multiple events in paho mqtt with python - python-3.x

#!/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.

Related

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

How to Subscribe on Multiple topic using PAHO-MQTT on python

I am trying to subscribe on three different topics using single subscriber client. But with the below mentioned code I am able to get data from only one server.
Please suggest ant modification in my code that can be implemented to get the desired data from the different publisher clients.
# Define Variables
MQTT_BROKER = "10.97.143.44"
MQTT_PORT = 11883
MQTT_TOPIC = [("Server1/kpi1"),("Server2/kpi2"),("Server3/kpi3")
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to broker")
global Connected #Use global variable
Connected = True #Signal connection
else:
print("Connection failed")
def on_message(client, userdata, message):
data = message.payload
receive=data.decode("utf-8")
m_decode = json.loads(receive)
#print(m_decode)
#print (m_decode['Server_name'])
print ("Message received: " + str(m_decode))
Connected = False #global variable for the state of the connection
client = mqttClient.Client("Python") #create new instance
client.on_connect= on_connect #attach function to callback
client.on_message= on_message #attach function to callback
client.connect(MQTT_BROKER,MQTT_PORT) #connect to broker
client.loop_start() #start the loop
while Connected != True: #Wait for connection
time.sleep(0.1)
client.subscribe(MQTT_TOPIC)
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print ("exiting")
List item
client.disconnect()
client.loop_stop()
Your MQTT_TOPIC array should contain QOS levels as well as topic names.
From the doc:
String and integer tuple
e.g. subscribe(("my/topic", 1))
topic
a tuple of (topic, qos). Both topic and qos must be present in
the tuple.
qos
not used.
e.g.
MQTT_TOPIC = [("Server1/kpi1",0),("Server2/kpi2",0),("Server3/kpi3",0)]

Add several individual threads to MQTT Python code

this is my code and I need add,
(1) loop(thread1) which can publish data when receive specific data by UART(ser.read())
(2) loop(thread2) which can run report_temp_humidity() with timed delay
so I put thread for test but this runs only one time, not loop.
Is this cause by "mqttclient.loop_forever()" at the end of line?
Need some help on this.
import paho.mqtt.client as mqtt
import Adafruit_DHT
import Adafruit_BBIO.UART as UART
import serial
import threading
import time
# DHT-11 Temperature & Humidity
sensor = Adafruit_DHT.DHT11
sensor_pin = 'P8_11'
# UART
UART.setup("UART1")
ser = serial.Serial(port = "/dev/ttyO1", baudrate=9600)
ser.close()
ser.open()
# Define event callbacks
def on_connect(self, client, userdata, rc):
if rc == 0:
print("Connected successfully.")
else:
print("Connection failed. rc= "+str(rc))
def on_publish(client, userdata, mid):
print("Message "+str(mid)+" published.")
def on_subscribe(client, userdata, mid, granted_qos):
print("Subscribe with mid "+str(mid)+" received.")
def on_message(client, userdata, msg):
print("Message received on topic "+msg.topic+" with QoS "+str(msg.qos)+"and payload "+msg.payload)
if msg.payload == "check_status":
report_temp_humidity()
if msg.payload == "motor_run!":
print "Send command to RF"
ser.write("11.1111[S]")
# Define my function prototypes
def report_temp_humidity():
hum, temp = Adafruit_DHT.read_retry(sensor, sensor_pin)
mqttclient.publish("/my_topic1/", "Temperature "+ str(temp) + "`C", qos=0)
mqttclient.publish("/my_topic1/", "Humidity " + str(hum) + "%", qos=0)
# Define thread(loop) test
def loop_test(delay):
print(loop!)
time.sleep(1)  
t1 = threading.Thread(target=loop_test, args=('1,',))
t1.start()
mqttclient = mqtt.Client()
# Assign event callbacks
mqttclient.on_connect = on_connect
mqttclient.on_publish = on_publish
mqttclient.on_subscribe = on_subscribe
mqttclient.on_message = on_message
# Connect
mqttclient.username_pw_set("dioty_user", "1234567")
mqttclient.connect("mqtt.dioty.co", 1883)
# Start subscription
mqttclient.subscribe("/my_topic1/")
# Publish a message
mqttclient.publish("/my_topic1/", "Hello World Message!")
# Loop
mqttclient.loop_forever()
This has nothing to do with the MQTT library.
Your thread t1 will run the loop_test function, which only has 2 statements in it. It will run these (once) then exit, there is nothing to tell it to continue to do anything else.
If you want that thread to continue to run for ever then you will need to include a loop statement of some sort (e.g. while True).

how to get data from a variable in Def to use it outside and remains updated?

Im trying to make a small 3 connected robots. They have to send and receive sensor data from each other and take an action to make the reads tends to zero again .
Iam trying to exchange the angle of the movements to let the other one follow him . Iam using the MQTT and it works very well .
But when i try to get the data from def on_message to use it in the next while the variable isn't global .
the code as follow :
############### MQTT section ##################
# when connecting to mqtt do this;
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(sub_topic)
# when receiving a mqtt message do this;
def on_message(client, userdata, msg):
masterangel = int(msg.payload)
print ( masterangel )
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(Broker, 1883, 60)
client.loop_start()
# Start the Program
psm.screen.termPrintAt(1, "Press Go to stop program")
while(not doExit):
oldAngel = Angel
Angel = gyro.readValue()
Angelshow = "Current Angel ="+" "+str (Angel)
if ( oldAngel != Angel):
psm.screen.termPrintAt(5, Angelshow)
if (Angel < masterangel) :
psm.BBM1.setSpeedSync(20)
psm.BAM1.floatSync()
elif (masterangel < Angel ) :
psm.BAM1.setSpeedSync(20)
psm.BBM1.floatSync()
client.publish(pub_topic, "test")
now has anyone an Idea how can i use the variable "masterangel" in the while loop ?
by the way the print order of works fine .
print ( masterangel )
thank you in Advance and i appreciate your Help
You need to initialise the variable outside the scope of the onMessage function and then mark it as a global variable in the onMessage functions.
Take a look at the python global keyword.
############### MQTT section ##################
# when connecting to mqtt do this;
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(sub_topic)
# when receiving a mqtt message do this;
def on_message(client, userdata, msg):
# use global version not local
global masterangel
masterangel = int(msg.payload)
print ( masterangel )
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(Broker, 1883, 60)
client.loop_start()
# initialise variable to starting value
masterangel = 0
# Start the Program
psm.screen.termPrintAt(1, "Press Go to stop program")
while(not doExit):
oldAngel = Angel
Angel = gyro.readValue()
Angelshow = "Current Angel ="+" "+str (Angel)
if ( oldAngel != Angel):
psm.screen.termPrintAt(5, Angelshow)
if (Angel < masterangel) :
psm.BBM1.setSpeedSync(20)
psm.BAM1.floatSync()
elif (masterangel < Angel ) :
psm.BAM1.setSpeedSync(20)
psm.BBM1.floatSync()
client.publish(pub_topic, "test")
To avoid the problems that may come with scope of variables later on (i.e. mixing local variables with global variables), instead of using the global keyword, take advantage of the return statement.
In other words, return allows you to actually use the arguments you pass into the return function and store it into another variable, whereas print() just prints to the screen.
############### MQTT section ##################
# when connecting to mqtt do this;
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(sub_topic)
# when receiving a mqtt message do this;
def on_message(client, userdata, msg):
masterangel = int(msg.payload)
return (masterangel) # Use return() instead of print ()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(Broker, 1883, 60)
client.loop_start()
# Start the Program
psm.screen.termPrintAt(1, "Press Go to stop program")
#Assign the value of masterangel being returned by calling the on_message
#function and storing it into its own variable.
new_var = on_message() # This stores the returned value of masterangel
while(not doExit):
oldAngel = Angel
Angel = gyro.readValue()
Angelshow = "Current Angel ="+" "+str (Angel)
if ( oldAngel != Angel):
psm.screen.termPrintAt(5, Angelshow)
if (Angel < new_var) :
psm.BBM1.setSpeedSync(20)
psm.BAM1.floatSync()
elif (new_var < Angel ) :
psm.BAM1.setSpeedSync(20)
psm.BBM1.floatSync()
client.publish(pub_topic, "test")

Resources