ESP32 MQTT: publish and subscribe in same script

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
ajocius
Posts: 52
Joined: Mon Feb 19, 2018 6:31 am

ESP32 MQTT: publish and subscribe in same script

Post by ajocius » Sun Feb 25, 2018 9:43 pm

Hi,

I am working on project where I can leave ESP32 in greenhouse to monitor sensors (temperature, soil moisture, etc), report (publish) to MQTT broker and also listen (subscribe) to commands (start valve to water plants, etc). It should publish data periodically (based on my defined schedule) or if some criteria is met (like window is closed, water valve is turned off). It should also continuesly listen to mqtt messages.

Currently I am on breadboard stage and testing various sensors, running small micropython scripts, trying to learn and understand. My set up is:
Respberry Pi 3 running Raspbian. I have Mosquitto server on it that acts as MQTT broker. Also have Node-Red that helps to visually see incomming mqtt messages and also create messages that are picked up by mqtt clients. Then I have ESP32 with micropython dowloaded from this website (umqtt.simple) and sensors that are connected to it via breadboard. I have been able to write (mostly copy/paste from web with some adjustments to fit local environment) scripts to read DHT22 sensor values (temp, humidity) and send it over to mqtt broker. This task runs in the loop until I interrupt. I have another script that subsribes to message and based on message it either turns on or off led light (imagine that is my water valve later on).

My attempt is to write one micropython code (or combine my existingworking codes into one) to do following tasks:
1. Read sensor data and publish msg1 (message1) to mqtt broker at certain interval;
2. Subscribe to msg2
3. If message says ON, turn led On.

I then plan to use Node-Red to listne to msg1 (contains temp and humidity) and if value exceeds certain number, then turn on led. Then I should be able to have led OFF under normal conditions, but if I blow to sensor, then led turns ON (as temp and humidity increases). If I manage that , then I should be able to run various scenarios in greenhouse (open watervalve for certain time if soil is dry, open windown if temp above x, close if below Y, etc).

So I managed to do publishing and subsribing separately, but not in one code, suspect something is wrong with my loop. Do you see what I am doing wrong? what should I change? Code below waits for message from broker after connecting to wifi, once received it executes code (turns led on or off) and publishes sensor values once, then I get error message pointing to line " client.wait_msg()"

Code: Select all

from time import sleep 
from umqtt.simple import MQTTClient
from machine import Pin
from dht import DHT22
import ubinascii
import machine
import micropython
import network, utime

#-----------Connect to WiFi
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect("******", "******")
tmo = 50
while not station.isconnected():
    utime.sleep_ms(100)
    tmo -= 1
    if tmo == 0:
        break
if tmo > 0:
    ifcfg = station.ifconfig()
    print("WiFi started, IP:", ifcfg[0])
    utime.sleep_ms(500)
#-----------------
led = Pin(13, Pin.OUT, value=1) # led on GPIO 13 
sensor = DHT22(Pin(15, Pin.IN, Pin.PULL_UP))   # DHT-22 on GPIO 15 (input with internal pull-up resistor)

def callback(topic, msg):
    global state
    print((topic, msg))
    if msg == b"on":
        led.value(1)
        state = 0
    elif msg == b"off":
        led.value(0)
        state = 1
    elif msg == b"toggle":
        # LED is inversed, so setting it to current state
        # value will make it toggle
        led.value(state)
        state = 1 - state	

broker_address = '*******'
client_id ='test1'
topic=b'led'
TOPIC2 = b'temp_humidity'
state=0

client = MQTTClient(client_id, broker_address, port=1883, user=b"*****", password=b"******")
client.set_callback(callback)
client.connect()
client.subscribe(b"led")

while True:
    if True:
        # Blocking wait for message
        client.wait_msg()
    else:
        # Non-blocking wait for message
        client.check_msg()
        # Then need to sleep to avoid 100% CPU usage (in a real
        # app other useful actions would be performed instead)
        time.sleep(1)
    try:
        sensor.measure()   # Poll sensor
        t = sensor.temperature()
        h = sensor.humidity()
        if isinstance(t, float) and isinstance(h, float):  # Confirm sensor results are numeric
            msg = (b'{0:3.1f},{1:3.1f}'.format(t, h))
            client.publish(TOPIC2, msg)  # Publish sensor data to MQTT topic
            print("Published", msg)
		
        else:
            print('Invalid sensor readings.')
    except OSError:
        print('Failed to read sensor.')
    sleep(4)
    client.disconnect()

User avatar
pythoncoder
Posts: 3509
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: ESP32 MQTT: publish and subscribe in same script

Post by pythoncoder » Mon Feb 26, 2018 8:22 am

It would help if you showed what error message occurs.

I think you should be using the nonblocking check_msg method here, otherwise publications won't occur until a subscription message has been received.
Peter Hinch

ajocius
Posts: 52
Joined: Mon Feb 19, 2018 6:31 am

Re: ESP32 MQTT: publish and subscribe in same script

Post by ajocius » Mon Feb 26, 2018 5:36 pm

have changed bottom part of the code with loop to the following and it now works without errors, except that it does not react to subscribed message immediately, seems like it waits until sleep mode is over ( i have sleep(4) in code). Ideally it would react the moment the message is sent, can that be done? In real life situation I might be reading temp every hour , so then it will sleep for 60 minutes and will not execute command that I send via mqtt broker?

Code: Select all

while True:
	client.check_msg()
	# Then need to sleep to avoid 100% CPU usage (in a real
	# app other useful actions would be performed instead)
	sleep(1)
	sensor.measure()   # Poll sensor
	t = sensor.temperature()
	h = sensor.humidity()
	if isinstance(t, float) and isinstance(h, float):  # Confirm sensor results are numeric
		msg = (b'{0:3.1f},{1:3.1f}'.format(t, h))
		client.publish(TOPIC2, msg)  # Publish sensor data to MQTT topic
		print("Published", msg)
		sleep(4)
	else:
		print('Invalid sensor readings.')

client.disconnect()

ajocius
Posts: 52
Joined: Mon Feb 19, 2018 6:31 am

Re: ESP32 MQTT: publish and subscribe in same script

Post by ajocius » Mon Feb 26, 2018 10:30 pm

Went for the different route. I will subscribe and publish messages using MP on ESP32, but all condition checking and action selection is probably easier to do in Node Red. Have already managed to put together flow in node.red that checks humidity value and turns led on when it reaches certain level.

ARTaylor
Posts: 29
Joined: Fri Mar 23, 2018 4:04 pm
Contact:

Re: ESP32 MQTT: publish and subscribe in same script

Post by ARTaylor » Fri Mar 23, 2018 4:27 pm

Great project! I'm working on a little environmental monitor based on the ESP32 to monitor ambient conditions in close proximity to seedlings grown in my lab. I have a Raspberry Pi Zero W doing watering routines.

Sorry to sideline the discussion, but I can't get the umqtt.simple module to work - I get "ImportError: no module named 'umqtt' back. I'm using the current ESP32 MicroPython build from the site - is the module included at the moment?

Edit: Ok I fixed it, just need to import the folder from MicroPython-lib - I'm new :D

Post Reply