-1

I have 2 loops I need to run, one to listen for voice commands and the other to stay connected to an MQTT broker and listen for/post to an MQTT topic, posting when a voice command is issued. Problem is, I'm not sure of the best way to set this up. How would I set these up to both run, with MQTT waiting for a voice command to execute functions/where would I start researching the solution? Classes? Multithreading? Not real sure where to begin.

Also - side note - this voice recognition(pocketsphinx) is absolutely horrible. It picks up on/off maybe 5% of the time, giving all kinds of random response every other time. Bonus bro points if you can point me in the right direction to fix that by using a better module or possible coding pocketsphinx to be more accurate (I've already signed up for a Google Cloud-Speech API key but have not yet received it).

Here's the code

voice.py:

import pyaudio, os
import mqttPublisher
import speech_recognition as sr

def mainfunction(source):
    audio = r.listen(source)
    user = r.recognize_sphinx(audio)
    print(user)
    if user == 'on':
        mqttPublisher.led_on()
    elif user == 'off':
        mqttPublisher.led_off()

if __name__ == '__main__':
    r = sr.Recognizer()
    with sr.Microphone() as source:
        while 1:
            mainfunction(source)

mqttPublisher.py:

import paho.mqtt.client as mqtt

def led_on():
    mqttc.publish("IoT/LED", payload="1")
    print("LED is ON")

def led_off():
    mqttc.publish("IoT/LED", payload="2")
    print("LED is OFF")

def get_status():
    mqttc.publish("IoT/LED", payload="3")

def on_connect(client, userdata, flags, rc):
    mqttc.publish("IoT/LED", "connected")
    print("connected")

def on_subscribe(client, userdata, mid, granted_qos):
    mqttc.publish("IoT/LED", payload="3")
    print("subscribed")

def on_publish(client, userdata, mid):
    print("message published")

def on_message(client, userdata, message):
    print("message printed to topic")

def on_disconnect(client, userdata, rc):
    print("Client Disconnected")

mqttc = mqtt.Client()
mqttc.on_connect = on_connect
mqttc.on_subscribe = on_subscribe
mqttc.on_message = on_message
mqttc.on_publish = on_publish
mqttc.on_disconnect = on_disconnect

mqttc.connect("192.168.1.3", 1883)
mqttc.subscribe("IoT/LED", 1)

run = True
while run:
    mqttc.loop_start()
ralight
  • 11,033
  • 3
  • 49
  • 59
jshcrm
  • 97
  • 9

2 Answers2

1

paho.mqtt.client.loop_start() starts a thread to handle its network loop for you. Just call it once and you should be fine.

ralight
  • 11,033
  • 3
  • 49
  • 59
0

Per hardillb's suggestion, I researched threading and found some questions that solved the issue with classes. The answers I used to come to my solution are here:

Running infinite loops using threads in python

Thread issue while subscribing to MQTT in Python using Paho MQTT

Below is the completed code working as expected. It starts the voice module and Mqtt client, waits for yes/no (which are the only consistent words I could get the voice module to recognize...) and turns on/off my Aruidno LED when it receives the appropriate commands. For those that are interested, I will include the Arduino code as well. The IP address 192.168.1.2 points to my Raspberry Pi, which is running a Mosquitto broker to handle the MQTT topics.

voice.py:

import pyaudio, os
from mqttPublisher import MqttHandler
import speech_recognition as sr
from threading import Thread

class Amy(Thread):
    def mainfunction(self, source):
        audio = self.r.listen(source)
        user = self.r.recognize_sphinx(audio)
        print(user)
        if user == 'yes':
            mqtt.led_on()
        elif user == 'no':
            mqtt.led_off()
        elif user == 'get':
            mqtt.get_status()

    def __init__(self):
        Thread.__init__(self)
        self.daemon = True
        self.start()

    def run(self):
        self.r = sr.Recognizer()
        with sr.Microphone() as source:
            while True:
                self.mainfunction(source)

amy = Amy()
mqtt = MqttHandler()

amy
mqtt

while True:
    pass

mqttPublisher.py:

import paho.mqtt.client as mqtt
from threading import Thread

class MqttHandler(Thread):

    client = mqtt.Client()

    def __init__(self):
        Thread.__init__(self)
        self.daemon = True
        self.start()

        self.client.on_connect = self.on_connect
        self.client.on_subscribe = self.on_subscribe
        self.client.on_message = self.on_message
        self.client.on_publish = self.on_publish
        self.client.on_disconnect = self.on_disconnect
        self.client.led_on = self.led_on
        self.client.led_off = self.led_off
        self.client.get_status = self.get_status

        self.client.connect("192.168.1.2", 1883)
        self.client.subscribe("IoT/LED", 1)

    def run(self):
        while True:
            self.client.loop()

    def led_on(self):
        self.client.publish("IoT/LED", payload="1")
        print("LED is ON")

    def led_off(self):
        self.client.publish("IoT/LED", payload="2")
        print("LED is OFF")

    def get_status(self):
        self.client.publish("IoT/LED", payload="3")

    def on_connect(self, client, userdata, flags, rc):
        self.client.publish("IoT/LED", "connected")
        print("connected")

    def on_subscribe(self, client, userdata, mid, granted_qos):
        self.client.publish("IoT/LED", payload="3")
        print("subscribed")

    def on_publish(self, client, userdata, mid):
        print("message published")

    def on_message(self, client, userdata, message):
        print("message printed to topic")

    def on_disconnect(self, client, userdata, rc):
        print("Client Disconnected")

Arduino Code:

#include <PubSubClient.h>
#include <Ethernet.h>
#include <SPI.h>

byte mac[]    = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xEF };
byte ip[] = { 192, 168, 1, 6 };
byte localserver[] = { 192, 168, 1, 2 };

const char clientID[8] = "Arduino";
const char topicName[8] = "IoT/LED";
const char on[3] = "On";
const char off[4] = "Off";
const int led = 9;

int status;

EthernetClient ethClient;
PubSubClient client(localserver, 1883, callback, ethClient);

void callback(char* topic, byte* payload, unsigned int length) {
  int load = atoi ((const char*) payload);
  if (load != 0) {
    Serial.print("\n");
    Serial.print("Payload= ");
    Serial.println(load);
    switch(load) {
      case 1:
        digitalWrite(led, HIGH);
        client.publish(topicName, on);
        Serial.print("Light turned on");
        break;
      case 2:
        digitalWrite(led, LOW);
        client.publish(topicName, off);
        Serial.print("Light turned off");
        break;
      case 3:
        status = digitalRead(led);
        if (status == 0) {
          client.publish(topicName, off);
          Serial.print("Light status: ");
          Serial.println(off);
          break;
        }
        else if (status == 1) {
          client.publish(topicName, on);
          Serial.print("Light status: ");
          Serial.println(on);
          break;
        }
      default:
        break;
    }
  }
}

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  Ethernet.begin(mac, ip);

  if (!client.connected()) {
    Serial. print("Trying to connect...");
    client.connect(clientID);
  }
  if (client.connected()) {
    Serial.print("Connected");
    client.subscribe(topicName);
  }
}

void loop() {
  client.loop();
}
Community
  • 1
  • 1
jshcrm
  • 97
  • 9