I am experimenting with mqtt with python paho mqtt library and a mqtt client mobile app with the test.mosquito.org server/broker.
This basic script works below connecting to the test.mosquitto server where I can publish a message from a mobile mqtt client app to this script and this script can also publish to the mobile app every 20 seconds a test message via the def publish(client): function.
import random
import time
from paho.mqtt import client as mqtt_client
broker = 'test.mosquitto.org'
port = 1883
# generate client ID with pub prefix randomly
client_id = "test_1"
topic_to_publish = f"laptop/publish"
topic_to_listen = f"mobile/publish"
topic_to_wildcard = f"testing/*"
username = ""
password = ""
def connect_mqtt():
def on_connect(client, userdata, flags, rc):
if rc == 0:
client.subscribe(topic_to_listen)
print(f"Connected to MQTT Broker on topic: {topic_to_wildcard}")
else:
print("Failed to connect, return code %d\n", rc)
client = mqtt_client.Client(client_id)
client.username_pw_set(username, password)
client.on_connect = on_connect
client.connect(broker, port)
client.on_connect = on_connect # Define callback function for successful connection
client.on_message = on_message # Define callback function for receipt of a message
return client
def publish(client):
msg_count = 0
while True:
time.sleep(20)
msg = f"hello from {client_id}: {msg_count}"
result = client.publish(topic_to_publish, msg)
# result: [0, 1]
status = result[0]
if status == 0:
print(f"Send {msg} to topic {topic_to_publish}")
else:
print(f"Failed to send message to topic {topic_to_publish}")
msg_count += 1
def on_message(client, userdata, msg): # The callback for when a PUBLISH message is received from the server.
print("Message received-> " + msg.topic + " " + str(msg.payload))
def run():
client = connect_mqtt()
client.loop_start()
publish(client)
if __name__ == '__main__':
run()
Can someone give me a tip on how to modify the def publish(client): function not to be a while loop that will fire off messages every 20 seconds but to only publish if the message from the mobile app received equals a string "zone temps"?
Am I on track at all removing the publish(client) from main run function as well as the while loop from def publish(client):? Thanks any tips greatly appreciated. What I am running into is I am missing something when I run this modified version there is no message exchange between at all.
def on_message(client, userdata, msg):
print("Message received-> " + msg.topic + " " + str(msg.payload))
if str(msg.payload) == "zone temps":
publish(client,"avg=72.1;min=66.4;max=78.8")
def run():
client = connect_mqtt()
client.loop_start()
if __name__ == '__main__':
run()
I m also beginner; but ill create a variable to is it publish or listening, like:
phoneAppListener = 0
and also
if str(msg.payload) == "zone temps":
when i print my payload it looks like:
b'payload'
firstly you need to split your payload like:
tempMsgHolder = str(msg.payload).split("'")
when you do this. tempMsgHolder[1] is your pure payload.
if tempMsgHolder[1] == "zone temps": phoneAppListener = 1
phoneAppListener value make the decision 0 is listen, 1 is publish. on your publish loop you set this
phoneAppListener == 1: publish your message
import random
import time
import threading
from paho.mqtt import client as mqtt_client
class moduleDatas:
broker = ('test.mosquitto.org')
port = (1883)
# generate client ID with pub prefix randomly
client_id = "test_1"
topic_to_publish = f"laptop/publish"
topic_to_listen = f"mobile/publish"
topic_to_wildcard = f"testing/*"
username = ""
password = ""
# Create clients object:
# You can create mqtt client obj using same pattern. Client has different on_msg or ex.
mqttClient_1 = mqtt_client.Client(moduleDatas.client_id) # You can create what ever you want to create a new thread
def mqttClientConnect():
mqttClient_1.connect(moduleDatas.broker[0], moduleDatas.port[0])
mqttClient_1.loop_start() # It creates daemon thread while your main thread running, this will handle your mqtt connection.
#mqttClient_1.connect_callback()
def on_connect(client, userdata, flags, rc):
if rc == 0:
print(f"Connected to MQTT Broker on topic: {moduleDatas.topic_to_wildcard}")
else:
print("Failed to connect, return code %d\n", rc)
#mqttClient_1.publish_callback()
def on_publish(client, userdata, mid):
print(mid) # If publish is success its return 1 || If mid = 1 publish success. || You can check your publish msg if it return failed try to send again or check your connection.
#mqttClient_1.message_callback()
def on_message(client, userdata, message):
temp_str = str(message.payload).split("'")
if temp_str[1] == "zone temps":
msg = "hello world" # <-- Your message here. Some func return or simple texts
mqttClient_1.publish(topic= moduleDatas.topic_to_publish, payload= msg, qos= 0)
def mqttClientSubscribe():
mqttClient_1.subscribe(moduleDatas.topic_to_listen)
def threadMqttClient1():
mqttClientConnect()
mqttClientSubscribe()
def buildThreads():
threads= []
t = threading.Thread(target=threadMqttClient1(), daemon= True)
threads.append(t)
# You can create on same pattern and append threads list.
for t in threads:
t.start()
while True: # this will your main thread, you can create an operation, ill go with just idling.
pass
if __name__ == "__main__":
buildThreads()
Related
I'm trying to Globalize the msg.topic with test and then use it in showdata function. But when I called the test variable inside my showdata function, it show me "name 'test' is not defined"Does anyone have any idea on this issue? Thanks in advance.
Views.py
from django.shortcuts import render
from paho.mqtt import client as mqtt_client
import random
broker = 'localhost'
port = 1883
topic = "Wind"
# generate client ID with pub prefix randomly
client_id = f'python-mqtt-{random.randint(0, 100)}'
# username = 'emqx'
# password = 'public'
def connect_mqtt() -> mqtt_client:
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to MQTT Broker!")
else:
print("Failed to connect, return code %d\n", rc)
client = mqtt_client.Client(client_id)
client.on_connect = on_connect
client.connect(broker, port)
return client
def subscribe(client: mqtt_client):
def on_message(client, userdata, msg, request):
print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")
global test
test = msg.topic
client.subscribe(topic)
client.on_message = on_message
def showdata(request):
context = test
return render(request, 'index.html', {'data': context})
def run():
client = connect_mqtt()
subscribe(client)
client.loop_forever()
if __name__ == '__main__':
run()
You have to declare the global variable in your upper scope like this:
broker = 'localhost'
port = 1883
topic = "Wind"
# generate client ID with pub prefix randomly
client_id = f'python-mqtt-{random.randint(0, 100)}'
# username = 'emqx'
# password = 'public'
test = None
Then you can use it in your function as expected.
I am using python Paho client.
I am using this in to my function.
my code is showing
import paho.mqtt.client as mqtt
import time, logging
broker = "127.0.0.1"
port = 1883
QOS = 0
CLEAN_SESSION = True
# error logging
# use DEBUG,INFO,WARNING
def on_subscribe(client, userdata, mid, granted_qos): # create function for callback
# print("subscribed with qos",granted_qos, "\n")
time.sleep(1)
print("sub acknowledge message id=" + str(mid))
pass
def on_disconnect(client, userdata, rc=0):
print("DisConnected result code " + str(rc))
def on_connect(client, userdata, flags, rc):
print("Connected flags" + str(flags) + "result code " + str(rc))
def on_message(client, userdata, message):
msg = str(message.payload.decode("utf-8"))
print("message received in mqtt_subscriber " + msg)
def on_publish(client, userdata, mid):
print("message published " + str(mid))
topic1 = "test"
client = mqtt.Client("RDAresp", False) # 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(broker, port) # establish connection
time.sleep(1)
client.loop_start()
client.subscribe("RemoteDoorAccess")
count = 1
while True: # runs forever break with CTRL+C
print("publishing on topic ", topic1)
msg = "message : RemoteDoorAccess_resp is published "
client.publish(topic1, msg)
count += 1
time.sleep(5)
and in views.py
def on_message(client, userdata, message):
msg = str(message.payload.decode("utf-8"))
print("message authority resp module " + msg)
def on_subscribe(client, userdata, mid, granted_qos): # create function for callback
print("subscribed with qos", granted_qos, "\n")
time.sleep(1)
pass
def on_disconnect(client, userdata, rc=0):
print("DisConnected result code " + str(rc))
def on_connect(client, userdata, flags, rc):
print("Connected flags" + str(flags) + "result code " + str(rc))
def on_publish(client, userdata, mid):
print("message published " + str(mid))
def mqttConnection():
topic = "RemoteDoorAccess"
client = mqtt.Client("RDA", False) # 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(broker, port) # establish connection
time.sleep(1)
client.subscribe("test")
time.sleep(1)
print("publishing on topic ", topic)
msg = "RemoteDoor Access published"
client.publish(topic, msg)
time.sleep(10)
#api_view(['GET'])
#permission_classes([])
def remotedooraccess_mobile(request):
mqttConnection()
return Response({msg: validation["FDP34"]}, status=status.HTTP_200_OK)
Here the topic 'test' is published but not subscribing.
please check views output
in my views.py on_message function is not called by the topic test.
how can I solve this.
I am totally stuck here.. in view.py subscribe function is not calling.
I am very new to mqtt.
please help
You need to start the client loop in your views.py code otherwise there is nothing to actually run your on_message() callback.
You should also move all your calls to client.subscribe() to into the on_connect callback and remove most of the calls to time.sleep()
Basically, I want my userdata to act as a global flag that gets read and updated between successive executions of the on_message() callback. I wrote and ran the following script:
import paho.mqtt.client as mqtt
MQTT_SERVER = "broker.hivemq.com"
MQTT_TOPIC = "IvanHu"
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(MQTT_TOPIC)
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
print(userdata, end = '')
print(" message received.")
userdata += 1
user_data_set(client_userdata)
client_userdata = 1
client = mqtt.Client(userdata=client_userdata)
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_SERVER, 1883, 60)
client.loop_forever()
I then published to the topic IvanHu 4 times. I expect the output of my python paho script to be the following:
Connected with result code 0
1 message received.
2 message received.
3 message received.
4 message received.
However, this was what I got instead:
Connected with result code 0
1 message received.
1 message received.
1 message received.
1 message received.
Evidently, the variable client_userdata never got updated in successive on_message() calls. What is the correct way to update this variable?
You have to give a initial value for userdata by client.user_data_set before connection, then you can update the userdata in on_message callback.
import paho.mqtt.client as mqtt
MQTT_SERVER = "broker.hivemq.com"
MQTT_TOPIC = "IvanHu"
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(MQTT_TOPIC)
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
print(userdata, end = '')
print(" message received.")
user_data_set(userdata + 1) # <-- Update userdata
client_userdata = 1
client = mqtt.Client(userdata=client_userdata)
client.on_connect = on_connect
client.on_message = on_message
client.user_data_set(1) # <-- Initialize
client.connect(MQTT_SERVER, 1883, 60)
client.loop_forever()
I couldn't figure out a way to satisfy my requirement using the userdata approach, but I was able to do so with the global variables approach. Here's the working script:
import paho.mqtt.client as mqtt
MQTT_SERVER = "broker.hivemq.com"
MQTT_TOPIC = "IvanHu"
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe(MQTT_TOPIC)
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
global client_userdata
print(client_userdata, end = '')
print(" message received.")
client_userdata += 1
client_userdata = 1
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_SERVER, 1883, 60)
client.loop_forever()
Output:
Connected with result code 0
1 message received.
2 message received.
3 message received.
4 message received.
You seem to have missed the bit in the docs that talks about updating the user_data object
It may be updated at a later point with the user_data_set() function.
Taken from the docs here
This means you need to pass the new value to set_userdata() so it should be as follows:
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
print(userdata, end = '')
print(" message received.")
userdata += 1
client.user_data_set(userdata)
I am currently trying to send a message via MQTT protocol which works. I am using a raspberry Pi and a vibration sensor as a means to trigger the sending of the message. At the start I would touch the sensor and it would send loads of messages at once which is what I dont want to happen. so I tried to make it sleep for 5 seconds after it detects vibration. But now it detects one vibration and then wont detect another one but doesnt stop the running of the file. the only way i can get it to detect the vibration again is to run the file again. here is the two ways I tried:
import time
from grove.gpio import GPIO
import paho.mqtt.client as mqttClient
class GrovePiezoVibrationSensor(GPIO):
def __init__(self, pin):
super(GrovePiezoVibrationSensor, self).__init__(pin, GPIO.IN)
self._on_detect = None
#property
def on_detect(self):
return self._on_detect
#on_detect.setter
def on_detect(self, callback):
if not callable(callback):
return
if self.on_event is None:
self.on_event = self._handle_event
self._on_detect = callback
def _handle_event(self, pin, value):
if value:
if callable(self._on_detect):
self._on_detect()
time.sleep(5000)
Grove = GrovePiezoVibrationSensor
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")
Connected = False #global variable for the state of the connection
broker_address= "hairdresser.cloudmqtt.com"
port = 15767
user = "kprpjfue"
password = "1fIq2_CIwHZj"
client = mqttClient.Client("Python") #create new instance
client.username_pw_set(user, password=password) #set username and password
client.on_connect= on_connect
client.loop_start()
client.connect(broker_address, port=port)
def main():
from grove.helper import SlotHelper
sh = SlotHelper(SlotHelper.GPIO)
pin = sh.argv2pin()
pir = GrovePiezoVibrationSensor(pin)
def callback():
print('Detected.')
value = 'detected'
client.publish("sensor/Temp", value)
pir.on_detect = callback
while True:
time.sleep(5000)
if __name__ == '__main__':
main()
while Connected != True: #Wait for connection
time.sleep(0.1)
import time
from grove.gpio import GPIO
import paho.mqtt.client as mqttClient
class GrovePiezoVibrationSensor(GPIO):
def __init__(self, pin):
super(GrovePiezoVibrationSensor, self).__init__(pin, GPIO.IN)
self._on_detect = None
#property
def on_detect(self):
return self._on_detect
#on_detect.setter
def on_detect(self, callback):
if not callable(callback):
return
if self.on_event is None:
self.on_event = self._handle_event
self._on_detect = callback
def _handle_event(self, pin, value):
if value:
if callable(self._on_detect):
self._on_detect()
time.sleep(5000)
Grove = GrovePiezoVibrationSensor
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")
Connected = False #global variable for the state of the connection
broker_address= "hairdresser.cloudmqtt.com"
port = 15767
user = "kprpjfue"
password = "1fIq2_CIwHZj"
client = mqttClient.Client("Python") #create new instance
client.username_pw_set(user, password=password) #set username and password
client.on_connect= on_connect
client.connect(broker_address, port=port)
def main():
from grove.helper import SlotHelper
sh = SlotHelper(SlotHelper.GPIO)
pin = sh.argv2pin()
pir = GrovePiezoVibrationSensor(pin)
def callback():
print('Detected.')
value = 'detected'
client.publish("sensor/Temp", value)
pir.on_detect = callback
while True:
time.sleep(5000)
client.loop()
if __name__ == '__main__':
main()
while Connected != True: #Wait for connection
time.sleep(0.1)
As you can see under the if callable in the handle event method I told I say time.sleep(5000). Am I putting this in the wrong place?
You have not started the MQTT client network loop so it will not be able receive messages or send a message large the the MTU.
You will also get disconnected after the keep alive period.
Add client.loop_start() before the call to client.connect()
or insert client.loop() after the time.sleep(5000) in the loop in main and it will be better to make it 1000 to the client loop runs at least once a second.
Adding sleeps in callbacks is normally a bad idea as it doesn't stop events from being triggered it just delays them, because they will just be queued up until the sleep times out.
You should set a flag on the first event just after sending the MQTT message which you can then expire using the While True loop in main. If a new event comes in while the flag is still set then you just don't send another MQTT message.
I am new to python. I'm trying to connect my client with the broker. But I am getting an error "global name 'mqttClient' is not defined".
Can anyone help me to what is wrong with my code.
Here is my code,
Test.py
#!/usr/bin/env python
import time, threading
import mqttConnector
class UtilsThread(object):
def __init__(self):
thread = threading.Thread(target=self.run, args=())
thread.daemon = True # Daemonize thread
thread.start() # Start the execution
class SubscribeToMQTTQueue(object):
def __init__(self):
thread = threading.Thread(target=self.run, args=())
thread.daemon = True # Daemonize thread
thread.start() # Start the execution
def run(self):
mqttConnector.main()
def connectAndPushData():
PUSH_DATA = "xxx"
mqttConnector.publish(PUSH_DATA)
def main():
SubscribeToMQTTQueue() # connects and subscribes to an MQTT Queue that receives MQTT commands from the server
LAST_TEMP = 25
try:
if LAST_TEMP > 0:
connectAndPushData()
time.sleep(5000)
except (KeyboardInterrupt, Exception) as e:
print "Exception in RaspberryAgentThread (either KeyboardInterrupt or Other)"
print ("STATS: " + str(e))
pass
if __name__ == "__main__":
main()
mqttConnector.py
#!/usr/bin/env python
import time
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("MQTT_LISTENER: Connected with result code " + str(rc))
def on_message(client, userdata, msg):
print 'MQTT_LISTENER: Message Received by Device'
def on_publish(client, userdata, mid):
print 'Temperature Data Published Succesfully'
def publish(msg):
# global mqttClient
mqttClient.publish(TOPIC_TO_PUBLISH, msg)
def main():
MQTT_IP = "IP"
MQTT_PORT = "port"
global TOPIC_TO_PUBLISH
TOPIC_TO_PUBLISH = "xxx/laptop-management/001/data"
global mqttClient
mqttClient = mqtt.Client()
mqttClient.on_connect = on_connect
mqttClient.on_message = on_message
mqttClient.on_publish = on_publish
while True:
try:
mqttClient.connect(MQTT_IP, MQTT_PORT, 180)
mqttClient.loop_forever()
except (KeyboardInterrupt, Exception) as e:
print "MQTT_LISTENER: Exception in MQTTServerThread (either KeyboardInterrupt or Other)"
print ("MQTT_LISTENER: " + str(e))
mqttClient.disconnect()
print "MQTT_LISTENER: " + time.asctime(), "Connection to Broker closed - %s:%s" % (MQTT_IP, MQTT_PORT)
if __name__ == '__main__':
main()
I'm getting this,
Exception in RaspberryAgentThread (either KeyboardInterrupt or Other)
STATS: global name 'mqttClient' is not defined
You have not defined mqttClient globally.
Make the following changes
import time
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("MQTT_LISTENER: Connected with result code " + str(rc))
def on_message(client, userdata, msg):
print 'MQTT_LISTENER: Message Received by Device'
def on_publish(client, userdata, mid):
print 'Temperature Data Published Succesfully'
def publish(msg):
global mqttClient
mqttClient.publish(TOPIC_TO_PUBLISH, msg)
def main():
MQTT_IP = "IP"
MQTT_PORT = "port"
global TOPIC_TO_PUBLISH
TOPIC_TO_PUBLISH = "xxx/laptop-management/001/data"
global mqttClient
mqttClient.on_connect = on_connect
mqttClient.on_message = on_message
mqttClient.on_publish = on_publish
while True:
try:
mqttClient.connect(MQTT_IP, MQTT_PORT, 180)
mqttClient.loop_forever()
except (KeyboardInterrupt, Exception) as e:
print "MQTT_LISTENER: Exception in MQTTServerThread (either KeyboardInterrupt or Other)"
print ("MQTT_LISTENER: " + str(e))
mqttClient.disconnect()
print "MQTT_LISTENER: " + time.asctime(), "Connection to Broker closed - %s:%s" % (MQTT_IP, MQTT_PORT)
mqttClient = mqtt.Client()
if __name__ == '__main__':
main()
Error is occurs due to using following line :
mqttClient.on_connect = on_connect
the correct format should be
mqtt.Client.on_connect = on_connect