ESP32 MicroPython MQTT Sensor: Send DHT22 Data to Node-RED and Home Assistant
This guide builds a practical telemetry path: an ESP32 reads a DHT22 temperature-and-humidity sensor, publishes measurements over MQTT, and makes those readings available to Node-RED or Home Assistant. You will configure Wi-Fi and a broker, install a compatible MicroPython MQTT client, wire the sensor safely, publish structured messages, and test each layer independently. MQTT is a messaging protocol—not a sensor driver—so reliable results depend on validating the sensor, network, broker, topic names, and subscriber separately.
1. Understand the system
The ESP32 is the publisher. It samples the DHT22 and sends a message to a broker on a topic such as solderhub/lab/room1/climate. The broker receives the message and forwards it to clients subscribed to that topic. Node-RED can subscribe, parse the payload, display a dashboard, or route data to a database. Home Assistant can subscribe through its MQTT integration and expose readings as entities.
MQTT separates producers from consumers: the ESP32 does not need to know whether Node-RED, Home Assistant, or another client is listening. Keep topics stable and descriptive, and avoid publishing secrets or personally identifying information. This example uses JSON with explicit temperature_c, humidity_pct, and device fields so subscribers can validate and transform data consistently.
2. Parts, wiring, and sensor limits
You need an ESP32 development board, a DHT22/AM2302 sensor, jumper wires, a breadboard, USB data cable, and a computer running Thonny or another MicroPython workflow. Some DHT22 modules include a pull-up resistor; a bare four-pin sensor generally needs one between DATA and the sensor supply. Check the exact module's pinout—pin order differs between bare sensors and breakout boards.
For a common three-pin module, connect VCC to a supply supported by that module, GND to ESP32 GND, and DATA to a suitable GPIO such as GPIO 4. Many modules accept 3.3 V, which is a straightforward choice for ESP32 logic. Do not assume a module powered at 5 V has a 3.3 V-safe data output. ESP32 GPIOs are not 5 V tolerant. Verify the board pinout and avoid input-only, flash-connected, or boot-strapping pins where they complicate startup. Disconnect power before changing wiring.
3. Validate the DHT22 before adding MQTT
Install a MicroPython firmware build for your exact ESP32 board and confirm that machine, network, and dht are available. In Thonny, select the MicroPython interpreter and the correct serial port. Save the following as sensor_test.py and run it with the DATA line connected to GPIO 4:
import time
import dht
from machine import Pin
sensor = dht.DHT22(Pin(4))
while True:
try:
sensor.measure()
print("Temperature C:", sensor.temperature())
print("Humidity %:", sensor.humidity())
except OSError as exc:
print("DHT read failed:", exc)
time.sleep(3)
DHT22 sampling should not be excessively frequent; a two- to three-second interval is a reasonable starting point. If readings fail, check pin order, common ground, pull-up resistor, cable length, supply voltage, and the exact sensor type. Do not proceed to MQTT until local readings are repeatable. This isolates hardware problems from network problems.
4. Set up an MQTT broker
The broker must be reachable from the ESP32 over the same LAN or a properly routed network. For a local development setup, a broker such as Mosquitto can run on a computer or small server. MQTT Explorer is a client for inspecting topics; installing MQTT Explorer alone does not install or start a broker. Confirm the broker service is running, identify the host's LAN IP or DNS name, and verify the listener port. Port 1883 is commonly used for unencrypted MQTT on a trusted local network; port 8883 is commonly used for MQTT over TLS when configured.
Do not put localhost or 127.0.0.1 in the ESP32 configuration unless the broker is somehow running on the ESP32 itself—those addresses refer to the device making the connection. Use the computer's LAN address, for example the documentation-only placeholder 192.0.2.10 (replace it with your actual broker address). A firewall may need a narrowly scoped rule for the chosen port on a private network. Avoid exposing an unauthenticated broker directly to the public internet.
5. Install and verify the MQTT client
MicroPython firmware does not guarantee that an MQTT library is preinstalled. A commonly used lightweight client is umqtt.simple, but package availability and import paths vary by firmware and distribution. Install a compatible library to the ESP32 filesystem using a trusted source and keep its license and version information with your project. In Thonny, upload the module file to the device and test import umqtt.simple at the REPL before running the full program.
If the import fails, inspect the exact error: ImportError: no module named 'umqtt' usually means the module is missing or stored in the wrong directory; a syntax or compatibility error can mean the library targets a different MicroPython version. Avoid copying an arbitrary folder from an unrelated tutorial. Use a client implementation compatible with your installed firmware, and test connection with a simple one-topic publisher before adding sensor logic.
6. Configure Wi-Fi and publish JSON
Create main.py on the ESP32. Replace the clearly marked example values with your own Wi-Fi credentials and broker address; do not commit real credentials to a public repository or paste them into screenshots. The example reconnects Wi-Fi if needed, reads the sensor at a conservative interval, publishes a JSON payload, and handles common failures without crashing silently.
import time
import json
import network
import dht
from machine import Pin
from umqtt.simple import MQTTClient
WIFI_SSID = "YOUR_WIFI_NAME"
WIFI_PASSWORD = "YOUR_WIFI_PASSWORD"
MQTT_HOST = "192.0.2.10" # replace with your broker's LAN address
CLIENT_ID = b"esp32-climate-room1"
TOPIC = b"solderhub/lab/room1/climate"
sensor = dht.DHT22(Pin(4))
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
def connect_wifi():
if not wlan.isconnected():
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
deadline = time.time() + 20
while not wlan.isconnected() and time.time() < deadline:
time.sleep(1)
if not wlan.isconnected():
raise OSError("Wi-Fi connection timed out")
print("Wi-Fi connected:", wlan.ifconfig()[0])
def connect_mqtt():
client = MQTTClient(CLIENT_ID, MQTT_HOST, port=1883, keepalive=60)
client.connect()
print("MQTT connected")
return client
client = None
while True:
try:
connect_wifi()
if client is None:
client = connect_mqtt()
sensor.measure()
payload = {
"device": "esp32-room1",
"temperature_c": sensor.temperature(),
"humidity_pct": sensor.humidity(),
"uptime_s": time.ticks_ms() // 1000
}
client.publish(TOPIC, json.dumps(payload))
print("Published:", payload)
time.sleep(10)
except Exception as exc:
print("Telemetry error:", exc)
if client is not None:
try:
client.disconnect()
except Exception:
pass
client = None
time.sleep(5)
This is a learning baseline, not a hardened unattended deployment. A repeated connection failure will retry, but you should add backoff, a last-will message, and secure transport for production. Some umqtt.simple versions accept arguments differently; consult the installed module's documentation if the constructor differs. The broker address above is a documentation placeholder and will not connect until replaced.
7. Confirm messages with MQTT Explorer
Open MQTT Explorer on a computer that can reach the broker. Configure the same host and port as the ESP32, plus username/password if authentication is enabled. Connect and subscribe to solderhub/# or the exact topic solderhub/lab/room1/climate. Start the ESP32 program and check whether new messages arrive about every ten seconds. The payload should be valid JSON and include numeric temperature and humidity fields.
If the client reports “disconnected from server,” verify that a broker is actually installed and running, that the host is correct, and that the port and authentication settings match. Check the broker's logs and firewall. A successful MQTT Explorer connection does not prove that the ESP32 has the correct Wi-Fi credentials or route; test each client separately. Do not confuse a topic name with a server address: topics are paths within the broker, not network destinations.
8. Use Node-RED to process the readings
In Node-RED, add an MQTT-in node and configure it to connect to the broker. Set the topic to solderhub/lab/room1/climate, output as a parsed JSON object if the node supports that option, or pass the message through a JSON node. Wire it to a Debug node and deploy. The Debug sidebar should show msg.payload.temperature_c and msg.payload.humidity_pct as numbers. If the payload appears as a string, add a JSON parsing node before accessing properties.
For a dashboard, connect the parsed values to suitable chart or gauge widgets and label the units explicitly. Use a Change or Function node to separate the two measurements if required by your dashboard version. Node-RED node packages and dashboard implementations differ, so use the documentation for the installed version rather than assuming every tutorial's widget names are current. Add validation: ignore messages with missing fields or values outside plausible sensor ranges, and timestamp received messages so stale data is visible. A dashboard should show “no recent data” rather than presenting an old reading as live.
9. Integrate with Home Assistant
First configure the MQTT integration in Home Assistant and confirm that Home Assistant can connect to the same broker. The exact interface depends on your Home Assistant and broker setup. You can initially subscribe to the topic using the MQTT listen tool and inspect the raw JSON. This confirms the transport layer before creating entities.
For a maintained deployment, prefer Home Assistant's current MQTT discovery approach or explicitly configured MQTT sensor entities, following the documentation for your installed release. Discovery payload structure, unique IDs, state topics, and YAML configuration conventions can change; do not copy configuration blindly across versions. A sensor definition should point to solderhub/lab/room1/climate and extract temperature_c or humidity_pct from the JSON payload, with appropriate units and device classes. Ensure entity IDs are unique and avoid publishing discovery configuration repeatedly without a stable identifier. If Home Assistant cannot see the sensor, verify broker connectivity, exact topic spelling, JSON key names, and whether the integration expects a string payload or parsed template.
10. Reliability, security, and troubleshooting
Sensor read errors: check DATA wiring and pull-up, use a longer sampling interval, shorten long wires, and test with the standalone sensor script. Wi-Fi timeout: confirm the network name and password, signal strength, supported Wi-Fi band, and whether the access point isolates clients. ESP32 boards generally use 2.4 GHz Wi-Fi; a 5 GHz-only network will not work. MQTT connection refused: check broker service status, port, credentials, listener binding, and firewall. Connection succeeds but no messages appear: subscribe to the exact topic, check case sensitivity, and inspect broker logs. Node-RED sees a string: parse JSON before accessing keys. Home Assistant shows unavailable: verify state topic, payload format, and freshness.
For reliability, avoid a tight infinite retry loop. Use a delay that increases after repeated failures, periodically re-establish Wi-Fi and MQTT, and distinguish sensor errors from network errors. Add a last-will topic such as solderhub/lab/room1/status if your client supports it, publishing offline when the connection drops and online after a successful connection. For production, use broker authentication, per-device permissions, TLS where feasible, unique client IDs, and credentials stored outside source control. Plain MQTT on port 1883 is not encrypted by default. Never expose the broker publicly with anonymous access.
11. Test methodically and extend the project
Use this order when commissioning the system: (1) read the DHT22 locally; (2) connect the ESP32 to Wi-Fi and print its assigned IP; (3) connect a desktop MQTT client to the broker; (4) publish a simple test message; (5) run the sensor publisher; (6) confirm the JSON topic in MQTT Explorer; (7) consume it in Node-RED; and (8) configure Home Assistant last. This layered sequence makes failures easier to isolate. Keep a short record of firmware version, client library version, GPIO, broker host, topic, and test date—but never include passwords.
Possible improvements include publishing a retained availability state, adding a monotonically increasing sample counter, including a device firmware version, buffering a small number of readings during temporary outages, and sending data to a time-series database. Do not buffer indefinitely on a small microcontroller. If you publish at ten-second intervals, each sensor creates 8,640 messages per day; choose an interval based on the use case and broker capacity. Calibrate expectations: the DHT22 is a low-cost sensor, not a laboratory instrument, and placement, airflow, condensation, and self-heating affect measurements. Compare readings with a known reference if accuracy matters.
The finished system demonstrates a reusable IoT pattern: measure locally, publish a documented payload, validate it at the broker, and let downstream applications consume it independently. Once this path works, adding another sensor is usually a matter of validating its driver and extending the payload schema—not redesigning MQTT.