简体   繁体   中英

Publish and subscribe both ways using MQTT Python

I currently have a Python program written on the Raspberry Pi 3 to read in humidity and temperature sensor data and publish this data to a topic. I can then receive this data using my laptop. Here is my code for reading sensor data and publishing it to a topic from my Raspberry Pi :

import RPi.GPIO as GPIO
import time
import json
import Adafruit_DHT as dht
import math
import paho.mqtt.publish as publish
import paho.mqtt.client as mqtt
# Creating the JSON Objects

dht22 = {}
arduino = {}
dht22Temp = []
dht22Hum = []
arduinoLED = []


dht22['temperature'] = dht22Temp
dht22['humidity'] = dht22Hum
dht22['sensor'] = 'DHT22'

arduino['blink'] = arduinoLED
arduino['actuator'] = 'arduinoLED'  

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

def main():
  # Main program block
  while True:

    h, t = dht.read_retry(dht.DHT22, 17) //Reading humidity and temp data from GPIO17
    t = round(t,2)
    h = round(h,2)

    if t > 25: 
      if len(arduinoLED) == 3:
        arduinoLED.pop(0)
        arduinoLED.append("true")
      else: 
        arduinoLED.append("true")
    else:
      if len(arduinoLED) == 3:
        arduinoLED.pop(0)
        arduinoLED.append("false")
      else: 
        arduinoLED.append("false")
    if len(dht22Temp) == 3:
      dht22Temp.pop(0)
      dht22Temp.append(t)
    else: 
      dht22Temp.append(t)
    if len(dht22Hum) == 3:
      dht22Hum.pop(0)
      dht22Hum.append(h)
    else: 
      dht22Hum.append(h)
    # lm35dzTemp.append(tempc) 


    # Publishing sensor information by JSON converting object to a string
    publish.single("topic/sensorTemperature", json.dumps(dht22), hostname = "test.mosquitto.org")
    publish.single("topic/sensorTemperature", json.dumps(arduino), hostname = "test.mosquitto.org")

    # Printing JSON objects
    print(dht22)
    print(arduino)
    time.sleep(2)

if __name__ == '__main__':

  try:
    main()
  except KeyboardInterrupt:
    pass
  finally:

    GPIO.cleanup()

Here is my code for subscribing and receiving data from my laptop:

import paho.mqtt.client as mqtt
import json

# This is the Subscriber
def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
    client.subscribe("topic/sensorTemperature")


def on_message(client, userdata, msg):
    print(json.loads(msg.payload)) #converting the string back to a JSON object

client = mqtt.Client()

client.on_connect = on_connect
client.on_message = on_message

client.connect("test.mosquitto.org", 1883, 60)

client.loop_forever()

What I want to do is now publish something from my laptop (perhaps in the same code as the subscriber, or in a separate file that will just publish a message to the same topic - "topic/sensorTemperature" ). But my question is: how do I also publish and subscribe to messages on my Raspberry Pi (in my first code that I published)? Since I am publishing messages in an infinite loop to my laptop, I will also need an infinite loop to subscribe to the same (or different topic) to receive messages. How do you run two of these loops at once? Will I need two different threads?

Thank you.

The easiest way is to start another Python process (similar to your laptop's script) on Raspberry in parallel, handling messages received from laptop.

But if you want to implement everything in one script, you can extend your second code fragment (processing messages) with implementation of first fragment (publishing sensors data).

Of course, you can't use loop_forever() in this case. When you call loop_forever(), it will never return until client calls disconnect(), so you can't process received messages (main thread is blocked). Paho client also has routines loop() and loop_start()/loop_stop() to control over network loop. Take a look on them:

1) Function loop() can take timeout as an argument. It will block until new message arrives or time is out. In first case - preform the processing of received message and calculate time until the next publish. Pass this time as parameter to loop() again. In second case, just publish data and call loop() with time until next publish (2 seconds in your example).

2) loop_start()/loop_stop() starts and stops background thread doing job of sending and receiving(and processing) data for you. Create client, register on_message() callback, connect/subscribe, and call loop_start() to start this thread. Main thread is free for you now - use it with logic of first fragment (loop with 2 seconds sleep).

As suggested by Sergey you can use loop_start to create a separate thread for receiving messages.

Here is how your main function will look like:

def main():
    # Create a new client for receiving messages
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.subscribe(topic)
    client.connect(mqttserver)
    client.loop_start()
    while True:
        #code for publishing
        pass

Simply put your code from subscribing script into publishing script before while True: and replace loop_forever() with loop_start() . Use loop_stop() when you script is exitting before GPIO.cleanup() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM