ESP32 DHT11 and DHT22 with MicroPython: Read Temperature and Humidity
The DHT11 and DHT22 are low-cost digital temperature and relative-humidity sensors often used in beginner weather stations, room monitors, and microcontroller projects. An ESP32 running MicroPython can read either sensor and print measurements to the serial console, show them on a display, or send them to a web server or MQTT broker.
Although the sensors look similar, they are not identical. The DHT11 has a narrower measurement range and generally lower resolution and accuracy, while the DHT22 (also sold as AM2302) is typically preferred when a broader range or finer measurement resolution is needed. Both use a single-wire digital signaling protocol that is different from standard I2C or UART.
This guide covers wiring, MicroPython setup, sample code, measurement timing, error handling, calibration expectations, and troubleshooting. Check the datasheet for your exact sensor module and ESP32 board before wiring. Sensor modules vary: some include a pull-up resistor and regulator, while a bare sensor may require external components.
1. DHT11 vs DHT22
DHT11 is inexpensive and suitable for simple demonstrations where broad trends matter more than precision. Its supported temperature and humidity ranges are narrower than those of DHT22, and readings are usually less granular. DHT22 is commonly selected for indoor monitoring and projects that need better resolution and a wider operating range. Exact specifications vary by manufacturer, so use the datasheet for the purchased part rather than relying only on a generic listing.
Neither sensor should be treated as a laboratory reference instrument. Placement, airflow, self-heating from nearby electronics, condensation, enclosure design, and sensor aging can all affect measurements. A sensor located beside a warm ESP32 regulator may report a higher temperature than the room. A sensor sealed in a poorly ventilated enclosure may respond slowly to humidity changes.
Both sensors need time between measurement requests. They are not designed to produce reliable new data continuously at arbitrary speed. Follow the timing requirements in the datasheet and the MicroPython driver's documentation. For many common DHT libraries, waiting about two seconds between readings is a conservative beginner-friendly starting point.
2. Parts and wiring
You need an ESP32 development board, a DHT11 or DHT22 sensor or module, jumper wires, and a USB data cable. A solderless breadboard can help for a temporary low-voltage prototype. Confirm the pin labels on the actual module: common labels are VCC, DATA, and GND, but physical order is not universal.
For a typical three-pin module, connect VCC to a supply voltage explicitly supported by that module, GND to ESP32 GND, and DATA to a suitable ESP32 GPIO such as GPIO 4. Many breakout modules support 3.3 V operation, but do not assume all modules do. A bare sensor may require a pull-up resistor between DATA and the supply specified by its datasheet. Some modules already include this resistor.
Important logic-level rule: ESP32 GPIO pins are not 5 V tolerant. If a module is powered at 5 V and its DATA pull-up brings the line to 5 V, connecting DATA directly to an ESP32 pin can damage the board. Prefer a sensor module designed for 3.3 V logic or use an appropriate level-shifting arrangement. Never connect the sensor's data pin to a GPIO before confirming the module's voltage and pull-up circuit.
3. Prepare MicroPython
Install MicroPython firmware suitable for your exact ESP32 variant and connect to the board using Thonny or another serial terminal. Confirm that the REPL responds. MicroPython includes a DHT module on many standard builds, but availability can depend on the port and firmware version. In the REPL, try importing it:
import dht
from machine import Pin
If the import succeeds, the built-in driver is available. If it raises ImportError, confirm that you are connected to the board rather than running standard CPython on the computer, and check the firmware documentation for your target. Do not install a random third-party package simply because its name resembles the built-in module.
Use the board's filesystem view to save the application as main.py after testing it interactively. A script that runs when manually executed is not necessarily saved on the device or configured to run after reset. Begin with a simple one-shot reading before adding Wi-Fi, MQTT, displays, or other subsystems; this isolates wiring and driver issues.
4. Read a sensor using MicroPython
The following example uses GPIO 4 as DATA. Confirm that GPIO 4 is suitable on your specific ESP32 board and is not reserved by another connected component. Change DHT11 to DHT22 if you have that sensor.
from machine import Pin
import dht
import time
sensor = dht.DHT22(Pin(4)) # Use dht.DHT11(Pin(4)) for DHT11
while True:
try:
sensor.measure()
temperature_c = sensor.temperature()
humidity_pct = sensor.humidity()
print("Temperature: {:.1f} C".format(temperature_c))
print("Humidity: {:.1f} %".format(humidity_pct))
except OSError as exc:
print("DHT read failed:", exc)
time.sleep(2)
The driver typically returns temperature in degrees Celsius and relative humidity as a percentage. The try/except block catches communication errors so a single bad sample does not terminate the whole application. The two-second delay is important; reduce the sampling interval only if the exact sensor and driver documentation explicitly permits it.
If your sensor module uses a different data pin, change the GPIO number. GPIO numbering in MicroPython usually refers to the chip GPIO number, not necessarily the board's physical header position. Verify the pinout for your ESP32 development board before connecting hardware.
5. Understand measurement timing and invalid readings
DHT sensors use a timing-sensitive digital protocol. A read can fail if the wire is too long, the pull-up is incorrect, the power supply is unstable, the sensor is read too frequently, or another part of the circuit interferes with the signal. The driver may report an OSError when it cannot decode a valid response.
Do not assume that every printed value is physically meaningful just because it is numeric. Add reasonable plausibility checks based on the sensor's specified range and your environment. For example, a room-monitoring application might flag a sudden jump from normal room temperature to an impossible extreme as a suspect measurement rather than immediately publishing it as fact. Avoid silently replacing all errors with zero; zero humidity or zero temperature can look like a real reading and mislead downstream logic.
A simple validation pattern is to retain the last known good value and separately record when the last successful sample occurred. If no fresh reading has been obtained for a while, display a stale-data indicator. This is safer than making an old value look current. Keep sensor acquisition separate from network publishing so a Wi-Fi outage does not stop local readings.
6. Display readings with units and timestamps
A measurement is more useful when its units and freshness are clear. Temperature should be labelled in degrees Celsius or Fahrenheit, and humidity should be labelled as relative humidity in percent. If values are sent to another application, use consistent field names and include a timestamp or an explicit sample age where practical.
For example, a simple structured console message could be:
print("temp_c={}, humidity_pct={}".format(temperature_c, humidity_pct))
Structured output is easier to parse than an ambiguous string such as "24 60". If the project later publishes JSON, preserve numeric types and document the units. Do not call relative humidity simply "moisture": it describes the amount of water vapor relative to saturation at the current temperature, not soil moisture or the absolute mass of water in the air.
For a display, avoid refreshing too quickly or clearing the screen unnecessarily. Show the last successful reading and an error or stale marker when communication fails. This gives users useful context and prevents a sensor problem from being mistaken for a stable environmental condition.
7. Troubleshooting checklist
ImportError: no module named dht. Confirm the program is running on MicroPython firmware for the ESP32, not CPython on your computer. Check whether the port includes the DHT driver and follow its documentation.
Every reading raises OSError. Check DATA wiring, common ground, supply voltage, pull-up resistor, GPIO selection, and sensor timing. Verify that you selected DHT11 versus DHT22 correctly in the code.
Readings are intermittent. Shorten long jumper wires, improve connections, check power stability, and keep the recommended delay between measurements. A breadboard contact that appears connected may still be intermittent.
Values are implausible. Confirm the sensor model, units, and wiring. Move the sensor away from voltage regulators, USB chips, sunlight, fans, or heat-producing components. Allow time for the sensor to equilibrate.
It works in the REPL but not after reboot. Save the script on the device under the expected name, normally main.py, and check startup messages for exceptions.
Wi-Fi or MQTT breaks the sensor loop. Handle network errors separately and avoid unbounded blocking calls. Read the sensor on its own schedule and publish only when connectivity is available.
8. Sensor placement, accuracy, and calibration
Place the sensor where air can circulate around it and where the reading represents the environment you want to measure. Do not press the sensing element against a warm enclosure wall or place it directly over a regulator. Direct sunlight, radiant heat, condensation, dust, and airflow from a fan can change the result. A weather station exposed outdoors needs a suitable ventilated radiation shield and protection from rain; a sensor module alone is not a weatherproof enclosure.
The DHT11 and DHT22 have stated accuracy limits and response times. A reading such as 24.6 °C should not be interpreted as proof that the true temperature is exactly 24.6 °C. Resolution describes the increments a sensor reports, while accuracy describes how close the value is to the true quantity. These are different properties. Humidity readings also depend on temperature and environmental conditions.
If accuracy matters, compare the sensor against a trusted reference under stable conditions and document the difference. Do not apply an arbitrary offset simply because one reading disagrees with a different device; the devices may have different placement, response time, or tolerances. For critical environmental, medical, industrial, or safety decisions, choose a sensor and measurement process designed and validated for that purpose rather than relying on a hobby DHT module.
9. Extending the project with Wi-Fi or MQTT
After local readings work reliably, the ESP32 can send measurements to a web dashboard, MQTT broker, or home-automation system. Add networking as a separate layer: check whether the Wi-Fi interface is connected, then publish a valid sample. If the network is unavailable, keep the sensor loop responsive and retry later rather than resetting the entire board.
Use placeholder values in shared examples, such as YOUR_WIFI_NAME and YOUR_WIFI_PASSWORD. Keep actual credentials in local configuration and out of public repositories. If sending measurements to an MQTT broker, use a topic that clearly identifies the device and measurement, document the units, and define how subscribers should interpret missing or stale data. Do not publish an old reading as if it were newly sampled.
If the device controls an actuator based on temperature or humidity, do not rely on a single unvalidated reading. Define sensible thresholds, hysteresis, error behavior, and a safe output state for sensor failure. A DHT sensor is not a certified safety device. Any hazardous system requires independent safeguards appropriate to the risk.
10. Final test plan
- Confirm the ESP32 firmware and REPL work before connecting the sensor.
- Verify the sensor's exact model, pin labels, supply voltage, and data pull-up requirements.
- Use a known-safe GPIO and share ground between the sensor and board.
- Run a one-shot reading, then use a reasonable interval such as two seconds.
- Catch communication exceptions and avoid treating a failed sample as zero.
- Check whether readings are plausible and compare them with a reference under stable conditions.
- Improve placement and airflow before trying to compensate for a suspicious reading in software.
- Save the tested script to the board and confirm it runs after reset.
- Add Wi-Fi or MQTT only after local acquisition is reliable.
- Test network loss and sensor disconnection, and make stale or invalid data visible.
DHT11 and DHT22 sensors are useful for learning digital sensor interfaces and building basic monitoring projects. Reliable results depend on correct wiring, suitable power and logic levels, proper sample timing, careful placement, and honest handling of measurement uncertainty. Start with the simplest possible circuit, verify each layer, and only then expand the project into a connected weather station.