Запускать 2 цикла одновременно, чтобы вызывать функции друг от друга?
У меня есть 2 цикла, которые мне нужно запустить, один для прослушивания голосовых команд, а другой для того, чтобы оставаться на связи с брокером MQTT и прослушивать / публиковать темы MQTT, отправляя сообщения при выполнении голосовой команды. Проблема в том, что я не уверен, что лучше всего это настроить. Как бы я настроил оба этих режима, чтобы MQTT ожидал голосовой команды для выполнения функций / с чего бы я начал исследовать решение? Классы? Многопоточность? Не совсем уверен, с чего начать.
Также - примечание стороны - это распознавание голоса (карманный сфинкс) абсолютно ужасно. Он включается / выключается, возможно, в 5% случаев, каждый раз получая все виды случайных ответов. Бонус, если вы можете указать мне правильное направление, чтобы исправить это, используя более точный модуль или, возможно, более точную кодировку pocketsphinx (я уже подписался на ключ Google Cloud-Speech API, но еще не получил его),
Вот код
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()
2 ответа
paho.mqtt.client.loop_start()
запускает поток для обработки своего сетевого цикла для вас. Просто позвоните один раз, и все будет хорошо.
По предложению hardillb, я исследовал многопоточность и нашел несколько вопросов, которые решили проблему с классами. Ответы, которые я использовал, чтобы прийти к решению, находятся здесь:
Запуск бесконечных циклов с использованием потоков в Python
Проблема с потоком при подписке на MQTT в Python с использованием Paho MQTT
Ниже приведен законченный код, работающий как положено. Он запускает голосовой модуль и Mqtt-клиента, ждет да / нет (это единственные согласованные слова, которые я мог бы заставить распознавать голосовой модуль...) и включает / выключает мой светодиод Aruidno, когда он получает соответствующие команды. Для тех, кто заинтересован, я включу и код Arduino. IP-адрес 192.168.1.2 указывает на мой Raspberry Pi, на котором работает брокер Mosquitto для работы с темами MQTT.
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:
#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();
}