How to process many messages in parallel in mqtt - python-3.x

I want to receive messages from many sensors (in the code I've tried from two) and process these messages in parallel by sending a command to the lights at the same time if the two sensors return "1". So I've done that in a separate thread but it doesn't work. It stops sending to the bedroom once someone enters the kitchen!
from class_light import Light
from test_class import Mqtt
import paho.mqtt.client as mqtt
import sys
import threading
import time
from MongoDB import is_circadian_Light
Broker = "broker.mqttdashboard.com"
username = "growthtechnology"
password = "growthtechnology"
PortaBroker = 1883
KeepAliveBroker = 60
client_name = "Local"
topic_sub = "testtopic/1"
topic_pub = "testtopic/3"
light = Mqtt()
occupancy_sensor = [("testtopic/4", 0), ("testtopic/5", 0)]
tunable_light = Light("deviceID")
def on_connect(client, userdata, flags, rc):
print("Connection to the broker. Result : "+str(rc))
client.subscribe(topic_sub)
client.subscribe(occupancy_sensor)
def on_publish(client,userdata,result):
print("Message published")
def on_disconnect(client, userdata, rc):
if rc != 0:
print("Unexpected disconnection.")
try:
print("[STATUS] Inicializando MQTT...")
#inicializing MQTT:
client = mqtt.Client()
client.username_pw_set(username, password)
client.on_connect = on_connect
client.on_message = light.message()
client.on_disconnect = on_disconnect
client.on_publish = on_publish
client.connect(Broker, PortaBroker, KeepAliveBroker)
def publishing():
while True:
msg = light.messages # calling for the variable "messages" to get PUBLISH messages
print(msg)
time.sleep(3)
topic = light.topic
if msg == "1" and topic == "testtopic/4":
if is_circadian_Light("device2") == 1 :
client.publish("testtopic/Bedroom",tunable_light.circadianLight())
time.sleep(10)
def publishing_kitchen():
while True:
msg_kitchen = light.messages
topic = light.topic
if msg_kitchen == "1" and topic == "testtopic/5":
if is_circadian_Light("device2") == 1 :
client.publish("testtopic/Kitchen",tunable_light.circadianLight())
time.sleep(10)
#code to turn off lights after 1 min
pub = threading.Thread(target= publishing)
pub.start()
pub_k = threading.Thread(target= publishing_kitchen)
pub_k.start()
client.loop_forever()
except KeyboardInterrupt:
print ("\nCtrl+C pressionado, encerrando aplicacao e saindo...")
sys.exit(0)
This the class Mqtt that I have created:
import paho.mqtt.client as mqtt
import time
class Mqtt():
def __init__(self, messages = "", topic = "", topic_1 = ""):
self._messages = messages
self._topic = topic
#property
def messages(self):
return self._messages
#messages.setter
def messages(self, messages):
self._messages = messages
#property
def topic(self):
return self._topic
#topic.setter
def topic(self, topic):
self._topic = topic
def message(self):
def on_message(client, userdata, msg):
Message = str(msg.payload.decode("utf-8"))
self._messages = Message
if msg.topic == "testtopic/4":
self._topic = msg.topic
print("[Receiving msg] Topic:" +msg.topic+" / Message: "+Message)
return on_message

Related

Tello programming

Im trying to connect to my Tello drone with Spyder by socket but the dron dosen't send an answer back. It prints that the Tello drone refuses to enter command mode.
import socket
import threading
import time
import traceback
class Tello:
self.abort_flag = False
self.command_timeout = command_timeout
self.imperial = imperial
self.response = None
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.tello_address = (tello_ip, tello_port)
self.socket.bind((local_ip, local_port))
self.receive_thread = threading.Thread(target=self._receive_thread)
self.receive_thread.daemon=True
self.receive_thread.start()
if self.send_command('command') != 'OK':
raise RuntimeError('Tello rejected attempt to enter command mode')
def __del__(self):
self.socket.close()
def _receive_thread(self):
while True:
try:
self.response, ip = self.socket.recvfrom(256)
except Exception:
break
def send_command(self, command):
self.abort_flag = False
timer = threading.Timer(self.command_timeout, self.set_abort_flag)
self.socket.sendto(command.encode('utf-8'), self.tello_address)
timer.start()
while self.response is None:
if self.abort_flag is True:
raise RuntimeError('No response to command')
timer.cancel()
response = self.response.decode('utf-8')
self.response = None
return response
def set_abort_flag(self):
"""Sets self.abort_flag to True.
Used by the timer in Tello.send_command() to indicate to that a response
timeout has occurred.
"""
self.abort_flag = True

emit bradcast message in callback with flask socketIO

I have trouble using Flask socketio. Here is the code I use:
import json
import time
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
from engineio.async_drivers import gevent
from flask_cors import CORS
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, cors_allowed_origins="*")
import queue
queue_notification_thread = queue.Queue()
def callback_notification(data):
print("callback device {}".format(data))
notification_thread = threading.Thread(target=notification_job, args=(data))
notification_thread.start()
queue_notification_thread.put(notification_thread)
def notification_job(data):
print("callback device in notification job {}".format(data))
socketio.emit("notification", data, broadcast=True)
#socketio.on('request')
def handle_message(data):
Logger.instance().debug('received message: {}'.format(data))
try:
if data.__contains__('data'):
response_message = dict()
response_message['Devices'] = dict()
response_message['Devices']['event'] = 'MY_EVENT'
socketio.emit('notification', response_message, broadcast=True)
else:
Logger.instance().error('Can\'t parse data {}'.format(data))
except OSError as err:
print('Error: when process {} \n ValueError {}'.format(data, err))
#socketio.on_error_default # handles all namespaces without an explicit error handler
def default_error_handler(e):
print('An error occured:')
print(e)
if __name__ == '__main__':
serialReader = SerialReader()
serialReader.start_reading(callback_notification)
http_server = WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()
And the reader with call asynchronisly:
class SerialController:
serial_port: str
serial_device: serial.Serial
reading_thread: threading.Thread
device_name: str
def __init__(self, serial_port: str = "/dev/ttyACM0", baudrate=115200, read_timeout=0.2, device_name=''):
self.serial_port = serial_port
self.device_name = device_name
self.serial_device = serial.Serial(port=self.serial_port, baudrate=baudrate, timeout=0.2)
def start_reading(self, callback_function):
self.reading_callback = callback_function
# run the thread to
self.reading_thread = threading.Thread(target=self.read_job)
self.reading_thread.start()
def read_job(self):
available_data = 0
while True:
if self.serial_device.in_waiting > available_data:
available_data = self.serial_device.in_waiting
print('available_data {}'.format(available_data))
time.sleep(0.1)
else:
if available_data != 0:
data = self.serial_device.readall()
available_data = 0
if data != b'' and data != b'\n':
if self.reading_callback != None:
message = dict()
message["Reader"] = dict()
message["Reader"]["device"] = self.device_name
message["Reader"]["data"] = data
self.reading_callback(message)
time.sleep(1)
When I receive a message in #socketio.on('request') the bradcast emission work properly with no delay. When I use callback_notification called from my serial reader the breadcast emission have variable delay ( from 1seconde to 10 secondes).
On my server the message "callback device ..." is printed instantly but the client receive the message after few second.
I tried to the emission call in a thread like in the shown code but there is no improvment

How to read and publish to two different topics at the same time in mqtt

I have created a class Mqtt that contains the definitions of the functions of all the necessary callbacks, and I want to subscribe to two occupancy sensor (actually I have even more) using a single object of the class Mqtt, then based on the sensor that publishes "1", I need to send a PUBLISH message to turn the lights on. However, once I send "1" to testtopic/4 and then to testtopic/5, messages are sent at first t bedroom but then to the kitchen and no more to bedrooms. Here is the main code:
from class_mqtt import Mqtt
import paho.mqtt.client as mqtt
import sys
import threading
import time
from MongoDB import is_circadian_Light
Broker = "broker.mqttdashboard.com"
username = "growthtechnology"
password = "growthtechnology"
PortaBroker = 1883
KeepAliveBroker = 60
client_name = "Local"
light = Mqtt(topic_sub)
# I have two sensors
occupancy_sensor = Mqtt([("testtopic/4", 0), ("testtopic/5", 0)])
tunable_light = Light("deviceID")
# I used test as lights to subscribe and be sure to receive messages
test = Mqtt("testtopic/Kitchen")
try:
print("[STATUS] Initialising MQTT...")
#Initialising mqtt
client = mqtt.Client()
client.username_pw_set(username, password)
client.connect(Broker, PortaBroker, KeepAliveBroker)
# test
client.on_connect = test.connection()
client.on_message = test.message()
client.on_publish = test.publisher()
client.on_disconnect = test.disconnection()
# for lights
client.on_connect = light.connection()
client.on_message = light.message()
client.on_publish = light.publisher()
client.on_disconnect = light.disconnection()
#for sensor
client.on_connect = occupancy_sensor.connection()
client.on_message = occupancy_sensor.message()
client.on_disconnect = occupancy_sensor.disconnection()
def publishing():
client.publish("testtopic/5", 1)
while True:
msg = occupancy_sensor.messages # calling for the variable "messages" to get PUBLISH messages
topic = occupancy_sensor.topic
if msg == "1" and topic == "testtopic/4":
if is_circadian_Light("device2") == 1 :
client.publish("testtopic/Bedroom",tunable_light.circadianLight())
time.sleep(10)
# The problem here is that if someone enters the kitchen I can't send messages to lights in the bedroom
if msg == "1" and topic == "testtopic/5":
if is_circadian_Light("device2") == 1 :
client.publish("testtopic/Kitchen",tunable_light.circadianLight())
time.sleep(10)
pub = threading.Thread(target= publishing)
pub.start()
client.loop_forever()
except KeyboardInterrupt:
print ("\nCtrl+C pressionado, encerrando aplicacao e saindo...")
sys.exit(0)
Here is the on_message callback in the class Mqtt:
def message(self):
def on_message(client, userdata, msg):
Message = str(msg.payload.decode("utf-8"))
self._messages = Message
self._topic = msg.topic
print("[Receiving msg] Topic:" +msg.topic+" / Message: "+Message)
return on_message
I don't know if I need an object for every sensor so I can publish to multiple rooms at the same time, but if there are other solutions it will be better
You can only set the callback functions once for a single client.
You have set them all 3 times, only the last set will be used.
client.on_connect = occupancy_sensor.connection()
client.on_message = occupancy_sensor.message()
client.on_disconnect = occupancy_sensor.disconnection()

how to minimize the massive message delay paho mqtt

I have seven raspberry pi's as clients a and one raspberry pi as client b which are transferring messages between each other via mqtt. It's working well so far, but there is a massive delay of over 2s sometimes. Most of the times the the delay is arround 0,02-0,2s but sometimes there are some delay-peaks with over 2s of delay.
I think it appears as soon as client b gets too many messages at the same time from the a clients.
Has anybody of you guys an idea what's the reason for this and how I can solve this?
Thanks and stay healthy!
When the run() is called, client a publishes to client b
client a
from datetime import datetime
import time
import paho.mqtt.client as mqtt
class CarClient:
def __init__(self, id):
self.client = mqtt.Client(id)
self.client.connect("192.168.178.41", 1883, 60) # connect to broker
self.newSpeed = 0
self.holdSpeedTime = 5
self.speedDuration = 0
self.id = id
self.time_sent = 0
def on_connect(self, mqttc, obj, flags, rc):
print("connected" + str(rc))
def on_message(self, mqttc, obj, msg):
answerTuple = eval(msg.payload)
self.newSpeed = int(answerTuple[0])
self.holdSpeedTime = answerTuple[1]
self.client.unsubscribe("test_channel")
time_feedback = time.time()
delay = time_feedback - self.time_sent
print(str(delay))
def on_disconnect(self, mqttc, flags, rc):
print("disconnected" + str(rc))
def on_publish(self, mqttc, obj, mid):
print("Data published " + str(mid))
print("published")
def on_subscribe(self, mqttc, obj, mid, granted_qos):
print("Subscribed: " + str(mid) + " " + str(granted_qos))
def on_unsubscribe(self, mqttc, flags, rc):
print("unsubscribed" + str(rc))
def on_log(self, mqttc, obj, level, string):
print(string)
def run(self, carID, connectionPoint):
self.time_sent = time.time()
self.tuple = (carID, connectionPoint)
# assining functions to callback
self.client.on_disconnect = self.on_disconnect
self.client.on_connect = self.on_connect
self.client.on_message = self.on_message
# self.client.on_subscribe = self.on_subscribe
# self.client.on_unsubscribe = self.on_unsubscribe
self.client.loop_start()
self.client.subscribe(str(self.id), 0) # subscribe topic
self.client.publish("test_channel1", str(self.tuple))
time.sleep(1)
carFeedback = (self.newSpeed, self.holdSpeedTime)
self.newSpeed = 0
self.holdSpeedTime = 5
return carFeedback
client b
import paho.mqtt.client as mqtt
import time
crossingList = []
def on_subscribe(client, userdata, mid, granted_qos): # create function for callback
print("subscribed with qos", granted_qos, "\n")
def on_disconnect(client, userdata, rc=0):
print("disconnected")
def on_connect(client, userdata, flags, rc):
print("connected")
def on_message(client, userdata, message):
dataTuple = eval(message.payload) # message is a tuple of (carID, connectionPoint)
print(str(dataTuple))
addToList(dataTuple)
def on_publish(client, userdata, mid):
print("published")
def addToList(dataTuple):
carID = dataTuple[0]
connectionPoint = dataTuple[1]
crossingList.append((carID, connectionPoint))
def logic():
carID = crossingList.__getitem__(0)[0]
connectionPoint = crossingList.__getitem__(0)[1]
if connectionPoint == 600:
newSpeed = 400
holdTime = 5
client.publish( carID, str((newSpeed, holdTime)))
del crossingList[0]
else:
newSpeed = 500
holdTime = 3
client.publish(carID, str((newSpeed, holdTime)))
del crossingList[0]
client = mqtt.Client("Logic") # create client object
client.on_subscribe = on_subscribe # assign function to callback
client.on_disconnect = on_disconnect # assign function to callback
client.on_connect = on_connect # assign function to callback
client.on_message = on_message
client.connect("192.168.178.41", 1883, 60) # establish connection
time.sleep(0.1)
client.loop_start()
client.subscribe("test_channel1")
count = 1
while True: # runs forever break with CTRL+C
if len(crossingList) != 0:
logic()
else:
count = count + 1

multiple events in paho mqtt with python

#!/usr/bin/env python
import sys
from arduino.Arduino import Arduino
import paho.mqtt.client as mqtt
import serial
import time
pin = 13
broker_adress = "10.0.2.190"
sys.path.append("/home/hu/Schreibtisch/Arduino_BA_2.0/Probe_Programmierung/Python-Arduino-Proto-API-v2/arduino")
ser = serial.Serial('/dev/ttyACM0', 9600)
b = Arduino('/dev/ttyACM0')
b.output([pin])
b.setLow(pin)
gassensor_value = "no default_value"
sensor_value = [['/Deutschland/Osnabrueck/Coffee-bike-1/Sensor_1',gassensor_value]]
#########################################################################
# Callback_1 for relay
#on_connect1,on_disconnect1,on_subscribe1on_message_1
#########################################################################
def on_connect(mqttrelay, obj, flags, rc):
if rc != 0:
exit(rc)
else:
mqttrelay.subscribe("qos0/test", 0)
def on_disconnect(mqttrelay, obj, rc):
obj = rc
def on_subscribe(mqttrelay, obj, mid, granted_qos):
print(mqttrelay.subscribe("qos0/test", 0))
print("Waiting for the subscribed messages")
def on_message(mqttrelay,userdata, message):
a = str(message.payload.decode("utf-8"))
print(a)
if (a == "1" or a == "0"):
if (a == "1"):
b.setHigh(13)
time.sleep(10)
else:
b.setLow(13)
time.sleep(10)
else:
print("please publish the message 1 or 0")
#########################################################################
# Callback_2 for gassensor
# on_connect2,on_publish2
#########################################################################
def on_publish(mqttgassensor, obj, mid):
print("mid: " + str(mid))
def on_connect(mqttgassensor, userdata, flags, rc):
print("Connected with result code " + str(rc))
#create new instance to subscribe the sitution of relay
mqttrelay = mqtt.Client("relay_K_12", 1)
#create new instance to publish the situation of gassensor
mqttgassensor = mqtt.Cleint("gassensor",1)
#the events and callbacks of instance mqttrelais associate with each other:
mqttrelay.on_message = on_message
mqttrelay.on_connect = on_connect
mqttrelay.on_subscribe = on_subscribe
mqttrelay.on_disconnect = on_disconnect
mqttrelay.connect(broker_adress)
#the events and callbacks of instance gassensor associate with each other:
mqttgassensor.on_connect = on_connect
mqttgassensor.on_publish = on_publish
mqttgassensor.connect(broker_adress)
while True:
mqttrelay.loop_start()
time.sleeps(2)
mqttrelay.loop_stop()
print("relay 開始循環")
mqttgassensor.loop_start()
mqttgassensor.loop()
time.sleep(1)
sensor_value[0][1] = ser.readline()
if (sensor_value[0][1] != "no default_value" or sensor_value[0][1] != b''):
print(sensor_value[0])
mqttgassensor.publish("/Deutschland/Osnabrueck/Coffee-bike-1/Sensor_1", sensor_value[0][1])
mqttgassensor.loop_stop()
Hello, everyone. I want to accomplish two instances in this script.
Through the publish we can get the data from the gassensor. Because at the top of this script i have imported the serial modul with that we can accomplish the communication between the arduino and raspberry pi.
I want to use the subscribe to get the command(1 or 0) from the server. the number 1 can active the Relay and the 0 can deactive the relay.
I have tried to accomplish the two thoughts lonely and successfully. But the Combination gives me no reply.
You only need 1 instance of the MQTT client since there is only 1 broker. You can subscribe and publish to multiple topics from a single client.
You should connect this 1 instance and then start the network loop in the background with client.start_loop()
You can then run your own loop to read from the serial port.

Resources