Food delivery for the blood sucker – publishing temp/hum values read from DHT22 connected to NodeMCU v3 with MicroPython to Mosquitto MQTT server via WiFi

a.k.a. longest post title ever 😛

This is the Python code for a NodeMCU v3 running MicroPython 1.19.1. It will measure temperature and humidity at the connected DHT22 with breakout board every 30 seconds, connect to WiFi and publish to a MQTT server.
The first code block will be the necessary as simple and clear as possible. In the following code blocks there will be another version parallelizing methods, importing config values and sending the measured values in JSON format. Don’t forget to used your Wifi credentials and mqtt server IP.

import machine
import dht
import network
from time import sleep
from umqtt.simple import MQTTClient

sensor_id = 'Bedroom_TempHumSensor'
mqtt_server = '192.168.1.42'
wifi_ssid = 'YOUR_WIFI_SSID'
wifi_pwd = 'YOUR_WIFI_PASSWORD'
sensor_pin = 5
interval = 30


class IoTSensorTempHumSimple:

    def __init__(self):
        self.wifi = None
        self.sensor = dht.DHT22(machine.Pin(sensor_pin))

    def run_measure_loop(self):
        while(True):
            self.connect_to_wifi()
            self.read_sensor()
            self.publish()
            sleep(interval)
            
    def connect_to_wifi(self):
        self.wifi = network.WLAN(network.STA_IF)
        self.wifi.active(True)
        self.wifi.connect(wifi_ssid, wifi_pwd)
        while not self.wifi.isconnected():
            sleep(0.3)

    def read_sensor(self):
        self.sensor.measure()
        self.temp = self.sensor.temperature()
        self.hum = self.sensor.humidity()
        
    def publish(self):
        mqtt_client = MQTTClient(sensor_id, mqtt_server, keepalive=5)
        mqtt_client.connect()
        print(f"TEMP: {self.temp} | HUM: {self.hum}")
        mqtt_client.publish('/temphum', f'TEMP: {self.temp} | HUM: {self.hum}')


if __name__ == '__main__':
    IoTSensorTempHumSimple().run_measure_loop()

The following is the advanced version of the sensor code. Sensor, MQTT and WiFi configuration have been extracted and imported so that the code of the sensor doesn’t have to be changed if something changes or you use it on multiple devices – only the configuration.

To identify the device I used its MAC address – I have a small post about this on different devices with the same output format. As the MAC id and the Wifi only have to be initialized once, that part is now in the _init_ method. This unique and constant identifier serves as mqtt client id and can be used to map a name for it when dealing with the incoming mqtt messages e.g. in NodeRed. This is a software for managing and dealing / enriching data from a MQTT server. Completely free, intuitively to use and very powerful. So if you move a sensor from one room to another you won’t have to change the code on the device but only change its name in the web interface.

As the steps connecting to wifi and measuring can be parallelized, uasyncio is used. For the client identifier the MAC is extracted using binascii. To publish the values to my local MQTT server (running mosquitto on a Raspberry Pi 4), umqtt is used. The measured values can be sent as simple strings, but I also included examples to publish them separately and as JSON object. The multiple publish calls are here just to show different possibilities. You probably just want to use one of them.
Using the async module is more of a little showcase – as it doesn’t take long to wait for Wifi connection and DHT22 to measure, it won’t really save much time. But as I like it more that way I will use it on the device and you can have a look at it if want.

import uasyncio as asyncio
import machine
import network
from time import sleep
import dht
from umqtt.simple import MQTTClient
import ubinascii
import json
from config.wifi_credentials import WIFI_SSID, WIFI_PWD
from config.config import MQTT_SERVER, SENSOR_TOPIC, SENSOR_PIN, SENSOR_INTERVAL


class IoTSensorTempHum:

    def __init__(self):
        self.temp = None
        self.hum = None
        self.wifi = network.WLAN(network.STA_IF)
        self.mac = ubinascii.hexlify(self.wifi.config('mac'), ":").decode().upper()

    async def run_measure_loop(self) -> None:
        while(True):
            await asyncio.gather(self.connect_to_wifi(), self.read_sensor())
            await self.publish()
            sleep(SENSOR_INTERVAL)
            
    async def connect_to_wifi(self) -> None:
        if not self.wifi.active() and not self.wifi.isconnected():
            self.wifi.active(True)
            self.wifi.connect(WIFI_SSID, WIFI_PWD)
            while not self.wifi.isconnected():
                asyncio.sleep(0.3)

    async def read_sensor(self) -> None:
        sensor = dht.DHT22(machine.Pin(SENSOR_PIN))
        sensor.measure()
        self.temp = sensor.temperature()
        self.hum = sensor.humidity()

    async def publish(self) -> None:
        mqtt_client = MQTTClient(self.mac, MQTT_SERVER, keepalive=5)
        mqtt_client.connect()
        mqtt_client.publish(SENSOR_TOPIC, json.dumps({'temp': self.temp, 'hum': self.hum, 'id': self.mac}))


if __name__ == '__main__':
    asyncio.run(IoTSensorTempHum().run_measure_loop())
MQTT_SERVER = '192.168.188.45'
SENSOR_TOPIC = '/sensor/raw'
SENSOR_PIN = 5
INTERVAL = 30
WIFI_SSID = 'YOUR_WIFI_SSID'
WIFI_PWD = 'YOUR_WIFI_PASSWORD'

Similar Posts

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.