I need to build a network with multiple publishers, one broker, and one subscriber.
Issue:
I have a working code with one to one option (one pub - one sub). However, when I run more publishers the subscriber receives messages only from the last connected publisher and I have no idea why it is happening.
More information: Broker (mosquitto) is working in a docker container, each publisher is a separate script and the target is to run multiple docker containers with one publisher in each container, but now I need to work around the communication issue.
Does anyone have any clues or ideas on how to debug or solved this?
This is the publisher script:
import time
import paho.mqtt.client as mqtt
import datetime
import random
import json
import logging
from multiprocessing import Process
CLEAN_SESSION = False
def on_connect(client, userdata, flags, rc):
logging.info(f"New connection {client}, {rc}")
def sensor(client_id):
localhost = '172.17.0.2'
port = 1883
timeout = 60
topic = "/mia/sensor"
client_id = f"sensor_{client_id}"
def check_sensor():
time.sleep(1)
rand = random.randint(0, 10)
if rand > 5:
current_time = datetime.datetime.now()
current_time = current_time.strftime('%Y-%m-%d %H:%M:%S')
return {"time": current_time, "signal": 1, "id": client_id}
else:
return 0
client = mqtt.Client(client_id, clean_session=CLEAN_SESSION)
client.on_connect = on_connect
client.connect(localhost, port, timeout)
while True:
check_info = check_sensor()
if check_info:
message_payload = json.dumps(check_info)
logging.info(message_payload)
client.publish(topic, message_payload, qos=2)
client.loop()
client.disconnect()
if __name__ == "__main__":
p = Process(target=sensor, args=(1,))
p.start()
print("new publisher created!")
This is the subscriber script:
import paho.mqtt.client as mqtt
import paho.mqtt.subscribe as sub
import json
import logging
localhost = '172.17.0.2'
port = 1883
timeout = 60
topic = "/mia/sensor"
def on_connect(client, userdata, flags, rc):
logging.info(f"New connection {client}, {rc}")
client.subscribe(topic, qos=2)
def on_message(client, userdata, msg):
data = json.loads(msg.payload.decode('utf-8'))
logging.debug(f"new message from {client} - {data}")
print(data)
client = mqtt.Client("python", clean_session=False)
client.on_connect = on_connect
client.on_message = on_message
client.connect_async(localhost, port, timeout)
client.loop_forever()
Thanks in advance
Your client_id needs to be unique. Check that.
Related
I have written two programs - Publisher and Subscriber.
However, I don't see that subscriber is getting subscribed to the topic.
Also, the subscriber isn't receiving any messages/payload.
I am unsure on how to fix this?
I have verified the endpoints and certificates and it seems to be fine.
Publisher code -
import paho.mqtt.client as mqtt
import ssl
import time
# Define variables
MQTT_PORT = 8883
MQTT_KEEPALIVE_INTERVAL = 45
MQTT_TOPIC = "driveLedTopic"
MQTT_HOST = "a3p01azi7xqox0-ats.iot.us-east-2.amazonaws.com"
CA_ROOT_CERT_FILE = "root-CA.crt"
THING_CERT_FILE = "MyFirstThing.cert.pem"
THING_PRIVATE_KEY = "MyFirstThing.private.key"
# Define on_publish event function
def on_publish(client, userdata, mid):
print "Message Published..."
#Initiate MQTT client
mqttc = mqtt.Client()
# Regiser publish callback function
mqttc.on_publish = on_publish
# Configure TLS Set
mqttc.tls_set(CA_ROOT_CERT_FILE, certfile=THING_CERT_FILE,
keyfile=THING_PRIVATE_KEY, cert_reqs=ssl.CERT_REQUIRED,
tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
# Connect with MQTT Broker
mqttc.connect(MQTT_HOST, MQTT_PORT, MQTT_KEEPALIVE_INTERVAL)
mqttc.loop_start()
counter = 0
while True:
print("Publish Message")
mqttc.publish(MQTT_TOPIC, "Hello User ", qos=1)
time.sleep(10)
mqttc.disconnect()
Subscriber code -
import paho.mqtt.client as mqtt
import ssl
# Define Variables
MQTT_PORT = 8883
MQTT_KEEPALIVE_INTERVAL = 45
MQTT_TOPIC = "driveLedTopic"
MQTT_HOST = "a3p01azi7xqox0-ats.iot.us-east-2.amazonaws.com"
CA_ROOT_CERT_FILE = "root-CA.crt"
THING_CERT_FILE = "MyFirstThing.cert.pem"
THING_PRIVATE_KEY = "MyFirstThing.private.key"
# Define on connect event function
# We shall subscribe to our Topic in this function
def on_connect(mosq, obj, rc):
mqttc.subscribe(MQTT_TOPIC, 0)
# Define on_message event function.
# This function will be invoked every time,
# a new message arrives for the subscribed topic
def on_message(mosq, obj, msg):
print("Topic: " + str(msg.topic))
print("QoS: " + str(msg.qos))
print("Payload: " + str(msg.payoad))
def on_subscribe(mosq, obj, mid, granted_qos):
print("Subscribed to Topic: ")
# Initiate MQTT Client
mqttc = mqtt.Client()
# Assign event callbacks
mqttc.on_message = on_message
mqttc.on_connect = on_connect
mqttc.on_subscribe = on_subscribe
# Configure TLS Set
mqttc.tls_set(CA_ROOT_CERT_FILE, certfile=THING_CERT_FILE,
keyfile=THING_PRIVATE_KEY, cert_reqs=ssl.CERT_REQUIRED,
tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
# Connect with MQTT Broker
mqttc.connect(MQTT_HOST, MQTT_PORT, MQTT_KEEPALIVE_INTERVAL)
# Continue Monitoring the incoming messages for subscribed topic
mqttc.loop_forever()
I am trying to publish single message to MQTT and disconnect with following code. But it works sometime, sometime doesn't work as expected. I want to listen for a topic for if the switch1 os on then turn off, of its of then turn on based on the received data and disconnect.
#!/usr/bin/env python2.7
import json
import time
import os
import paho.mqtt.client as mqtt
mqtt_host = os.getenv('HOST', 'xxxx')
mqtt_port = os.getenv('PORT', 1883)
mqtt_username = os.getenv('USERNAME', 'xxxx')
mqtt_password = os.getenv('PASSWORD', 'xxxx')
mqtt_subacribe_topic = os.getenv('SUBSCRIBE_TOPIC', 'xxxx')
mqtt_publish_topic = os.getenv('PUBLISH_TOPIC', 'xxxx')
sleep_time = os.getenv('SLEEP_TIME', 15)
CLIENT_ID = "lambda"
SWITCH1_ON = { "SWITCH1": "on" }
SWITCH1_OFF = { "SWITCH1": "off" }
def on_publish(client, userdata, mid):
print ("Message Published...")
client.disconnect()
def on_subscribe(client, userdata, mid, granted_qos):
print("Subscribed: " + str(message.topic) + " " + str(mid) + " " + str(granted_qos))
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to broker")
client.subscribe(mqtt_subacribe_topic)
else:
print("Connection failed")
def on_message(client, userdata, msg):
payload = json.loads(msg.payload)
if payload.get('switch1') == 1:
client.publish(mqtt_publish_topic,json.dumps(SWITCH1_ON))
elif payload.get('switch1') == 0:
client.publish(mqtt_publish_topic,json.dumps(SWITCH1_OFF))
def main():
client = mqtt.Client(CLIENT_ID)
client.username_pw_set(mqtt_username, password=mqtt_password)
# Register publish callback function
client.on_publish = on_publish
client.on_connect = on_connect
client.on_message = on_message
# Connect with MQTT Broker
client.connect(mqtt_host, port=mqtt_port)
# Loop forever
client.loop_start()
time.sleep(sleep_time)
client.loop_stop()
client.disconnect()
if __name__ == "__main__":
main()
Based on hardillb's answer I tried :
#!/usr/bin/env python2.7
import json
import time
import os
import paho.mqtt.subscribe as subscribe
import paho.mqtt.publish as publish
mqtt_host = os.getenv('HOST', 'xxx.cloudmqtt.com')
mqtt_port = os.getenv('PORT', 1883)
mqtt_username = os.getenv('USERNAME', 'xxx')
mqtt_password = os.getenv('PASSWORD', 'xxx')
mqtt_subacribe_topic = os.getenv('SUBSCRIBE_TOPIC', 'xxx')
mqtt_publish_topic = os.getenv('PUBLISH_TOPIC', 'xxx')
sleep_time = os.getenv('SLEEP_TIME', 14)
CLIENT_ID = "lambda"
SWITCH1_ON = { "SWITCH1": "on" }
SWITCH1_OFF = { "SWITCH1": "off" }
auth = {'username':mqtt_username, 'password':mqtt_password}
def on_message(client, userdata, msg):
payload = json.loads(msg.payload)
print(payload)
if payload.get('switch1') == 1:
publish.single(mqtt_publish_topic,json.dumps(SWITCH1_ON),hostname=mqtt_host,auth=auth)
print "Turning switch1 ON"
elif payload.get('switch1') == 0:
publish.single(mqtt_publish_topic,json.dumps(SWITCH1_OFF),hostname=mqtt_host,auth=auth)
print "Turning switch1 OFF"
def main():
subscribe.callback(on_message, mqtt_subacribe_topic,hostname=mqtt_host,auth=auth)
if __name__ == "__main__":
main()
But script is keep running, I have to kill it to stop. Is it possible to just subscribed to a topic and once first message is received, process it, publish to another topic and end the execution.
If you just want to publish a single message then the Paho client has a built in method to do this. You can find the doc here
import paho.mqtt.publish as publish
publish.single("paho/test/single", "payload", hostname="iot.eclipse.org")
There is an equivalent method for also subscribing to a topic and receiving a single message.
I managed to publish on several topics and read one of them. What I need to do is to listen and read to all published topics and get messages. This is the code I use:
Publish messages to 3 topics :
#!/usr/bin/env python3
import paho.mqtt.client as mqtt
client = mqtt.Client()
client.connect("localhost",1883,60)
client.publish("topic/1", "400 | 350 | 320 | 410");
client.publish("topic/2", "200 | 350 | 420 | 110");
client.publish("topic/3", "200 | 350 | 420 | 110");
client.disconnect();
Subscribe and read messages for 1 topic
#!/usr/bin/env python3
import paho.mqtt.client as mqttClient
import time
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):
print "Message received : " + message.payload
Connected = False
broker_address= "localhost"
port = 1883
client = mqttClient.Client("Python")
client.on_connect= on_connect
client.on_message= on_message
client.connect(broker_address, port=port)
client.loop_start()
while Connected != True:
time.sleep(0.1)
client.subscribe("topic/2")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print "exiting"
client.disconnect()
client.loop_stop()
You can call the client.subscribe() function multiple times to subscribe to multiple topics.
Also you should move the calls to subscribe to the on_connect callback to remove the need for the first loop.
#!/usr/bin/env python3
import paho.mqtt.client as mqttClient
import time
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to broker")
client.subscribe("topic/1")
client.subscribe("topic/2")
client.subscribe("topic/3")
client.subscribe("topic/4")
else:
print("Connection failed")
def on_message(client, userdata, message):
print("Message received : " + str(message.payload) + " on " + message.topic)
broker_address= "localhost"
port = 1883
client = mqttClient.Client("Python")
client.on_connect= on_connect
client.on_message= on_message
client.connect(broker_address, port=port)
client.loop_start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("exiting")
client.disconnect()
client.loop_stop()
EDIT:
You can also subscribe to multiple topics in one go with the following syntax
client.subscribe([("topic/1", 0), ("topic/2", 0), ("topic/3", 0),("topic/4", 0)])
I am trying to publish JSON data on MQTT broker topic. this is the source code, I tried-
import paho.mqtt.client as mqtt
import json
# Define Variables
MQTT_HOST = "localhost"
MQTT_PORT = 1883
MQTT_KEEPALIVE_INTERVAL = 45
MQTT_TOPIC = "irisPayload"
MQTT_MSG=json.dumps({"sepalLength": "6.4","sepalWidth": "3.2","petalLength": "4.5","petalWidth": "1.5"});
# Define on_publish event function
def on_publish(client, userdata, mid):
print "Message Published..."
# Initiate MQTT Client
mqttc = mqtt.Client()
# Register publish callback function
mqttc.on_publish = on_publish
# Connect with MQTT Broker
mqttc.connect(MQTT_HOST, MQTT_PORT, MQTT_KEEPALIVE_INTERVAL)
# Publish message to MQTT Broker
mqttc.publish(MQTT_TOPIC,MQTT_MSG)
# Disconnect from MQTT_Broker
mqttc.disconnect()
I just want to publish JSON data without payload={jsondata}format, how to remove payload as it comes every time when I am publishing my data on particular topic?
In the log it shows msg like this--- [payload={ "sepalLength": "6.4", "sepalWidth": "3.2", "petalLength": "4.5", "petalWidth": "1.5" }]
I add some modification for your code, then you can publish json as string, then receive string and convert to json.
Sample code:
import paho.mqtt.client as mqtt
import json
# Define Variables
MQTT_HOST = "localhost"
MQTT_PORT = 1883
MQTT_KEEPALIVE_INTERVAL = 45
MQTT_TOPIC = "irisPayload"
MQTT_MSG=json.dumps({"sepalLength": "6.4","sepalWidth": "3.2","petalLength": "4.5","petalWidth": "1.5"});
# Define on_publish event function
def on_publish(client, userdata, mid):
print "Message Published..."
def on_connect(client, userdata, flags, rc):
client.subscribe(MQTT_TOPIC)
client.publish(MQTT_TOPIC, MQTT_MSG)
def on_message(client, userdata, msg):
print(msg.topic)
print(msg.payload) # <- do you mean this payload = {...} ?
payload = json.loads(msg.payload) # you can use json.loads to convert string to json
print(payload['sepalWidth']) # then you can check the value
client.disconnect() # Got message then disconnect
# Initiate MQTT Client
mqttc = mqtt.Client()
# Register publish callback function
mqttc.on_publish = on_publish
mqttc.on_connect = on_connect
mqttc.on_message = on_message
# Connect with MQTT Broker
mqttc.connect(MQTT_HOST, MQTT_PORT, MQTT_KEEPALIVE_INTERVAL)
# Loop forever
mqttc.loop_forever()
data = {"sepalLength": "6.4","sepalWidth": "3.2","petalLength": "4.5","petalWidth": "1.5"}
print json.dumps(data)
prints:
{"sepalLength": "6.4","sepalWidth": "3.2","petalLength":
"4.5","petalWidth": "1.5"}
not:
payload={"sepalLength": "6.4","sepalWidth": "3.2","petalLength":
"4.5","petalWidth": "1.5"}
you have somewhere else a manipulated string that is describing that payload
adding that unwanted key to the msg
I'm using MQTT since a while to monitor some channels I subscribed. Now I want to implement to send a message as reaction to a state. I got it running with the code below, where I just react in the on_message callback (code 1 at the end). But this code uses
loop_forever()
in the main code which is blocking.
What I would like to do is to just send a single message to MQTT. When I try the following (with all different loop-functions), nothing is received by the MQTT server:
import paho.mqtt.client as mqtt
if __name__ == "__main__":
mqtt_client = mqtt.Client()
mqtt_client.connect("192.168.178.204", 1883, 60)
mqtt_client.username_pw_set(username="test", password="test")
mqtt_client.publish(topic='TEST', payload='CCCCCCCCC', retain=False)
mqtt_client.loop_write()
# mqtt_client.loop()
# mqtt_client.loop_start()
mqtt_client.disconnect()
How can I send a message to MQTT which does not block the process?
Code 1:
import paho.mqtt.client as mqtt
def on_connect(client, userdata, rc):
topic_list = [("TEST_MS", 1)]
if rc == 0:
print("Successful connected and subscribed to: {}".format(topic_list))
client.subscribe(topic_list)
def on_message(client, userdata, msg):
print(msg.payload)
client.publish(topic='TEST_MS2', payload=msg.payload, retain=False)
def on_publish(client, userdata, mid):
print("message published")
def on_subscribe(mosq, obj, mid, granted_qos):
print("Subscribed: " + str(mid) + " " + str(granted_qos))
if __name__ == "__main__":
mqtt_client = mqtt.Client()
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
mqtt_client.on_publish = on_publish
mqtt_client.on_subscribe = on_subscribe
mqtt_client.connect("192.168.178.204", 1883, 60)
mqtt_client.username_pw_set(username="test", password="test")
# mqtt_client.publish(topic='TEST_MS', payload='CCCCCCCCC', retain=False)
mqtt_client.loop_forever()
mqtt_client.disconnect()
If you want to send just a single message and then exit use the API specifically for that. Docs here
import paho.mqtt.publish as publish
publish.single("paho/test/single", "payload", hostname="iot.eclipse.org")