How-To-Tutorials · September 5, 2025

How to Implement a Zephyr Wi-Fi Logging System with MQTT for DHT22 Data

how-to-implement-a-zephyr-wi-fi-logging-system-with-mqtt-for-dht22-data.png

Introduction

Remote temperature monitoring is one of those "hello world" IoT projects that actually turns out to be useful. You wire up a DHT22, push readings over Wi-Fi to an MQTT broker, and suddenly you've got a system you can query from anywhere on your network. Zephyr RTOS (v3.7+) makes this surprisingly clean because its sensor API and networking stack are already designed to work together.

The approach here: read temperature from a DHT22 on an ESP32, connect to Wi-Fi, and publish the data to an MQTT topic at regular intervals. Simple concept, but the Zephyr configuration has a few quirks worth knowing about.

Prerequisites

  • Working knowledge of C programming
  • Some familiarity with Zephyr RTOS concepts (devicetree, Kconfig)
  • A DHT22 temperature/humidity sensor
  • An ESP32 development board (or another Zephyr-supported board with Wi-Fi)
  • An MQTT broker running on your network (Mosquitto is the go-to choice)
  • Zephyr SDK and west tool installed

Parts/Tools

  • DHT22 Temperature Sensor
  • ESP32 Development Board
  • Jumper wires
  • Computer with Zephyr SDK installed (v0.16+)
  • MQTT Broker (Mosquitto recommended)

Steps

  1. Set Up the Hardware

    1. Wire the DHT22 to the ESP32:
      • VCC to 3.3V
      • GND to Ground
      • DATA to a GPIO pin (e.g., GPIO 23)
    2. A 10k pull-up resistor between DATA and VCC is technically optional on some DHT22 breakout boards (they have one built in), but add one if you're getting flaky readings. The DHT22 protocol is timing-sensitive, and a weak pull-up causes intermittent failures that are annoying to debug.
    3. Make sure the ESP32 is powered and connected to your computer via USB.
  2. Configure the Zephyr Project

    1. Create a new Zephyr workspace. If you already have a Zephyr installation, you can skip the init/update steps:
    2. mkdir zephyr_wifi_logging
      cd zephyr_wifi_logging
      west init
      west update
    3. Create your application folder structure:
    4. mkdir -p app/src
      cd app
    5. Set up your CMakeLists.txt. Note that Zephyr v3.7+ uses find_package(Zephyr) instead of the older boilerplate include:
    6. cmake_minimum_required(VERSION 3.20)
      find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
      project(zephyr_wifi_logging)
      target_sources(app PRIVATE src/main.c)

      Watch out: the old boilerplate.cmake approach you might see in older tutorials is deprecated. Always use find_package(Zephyr) with current Zephyr versions.

  3. Write the Main Application Code

    1. Create src/main.c and include the headers you'll need:
    2. #include <zephyr/kernel.h>
      #include <zephyr/device.h>
      #include <zephyr/drivers/sensor.h>
      #include <zephyr/net/wifi_mgmt.h>
      #include <zephyr/net/mqtt.h>
      #include <zephyr/logging/log.h>
    3. Initialize the DHT22 sensor and MQTT client. Zephyr v3.7+ uses devicetree-based device access rather than string-based binding:
    4. const struct device *sensor = DEVICE_DT_GET_ONE(aosong_dht);
      
      int main(void) {
          if (!device_is_ready(sensor)) {
              LOG_ERR("DHT22 sensor not ready");
              return -1;
          }
          // Initialize MQTT client and connection parameters
      }

      Tip: device_get_binding() still works but is considered legacy. The devicetree macros give you compile-time checking, which catches wiring mistakes before you even flash.

    5. Implement the temperature reading function:
    6. float read_temperature(const struct device *sensor) {
          struct sensor_value temp;
          int ret = sensor_sample_fetch(sensor);
          if (ret != 0) {
              LOG_WRN("Failed to fetch sensor sample: %d", ret);
              return -999.0f;  // sentinel value
          }
          sensor_channel_get(sensor, SENSOR_CHAN_AMBIENT_TEMP, &temp);
          return sensor_value_to_float(&temp);
      }

      Always check the return value of sensor_sample_fetch(). The DHT22 needs about 2 seconds between reads, and calling it too fast returns errors silently if you don't check.

    7. Publish the temperature data to your MQTT broker:
    8. void publish_temperature(struct mqtt_client *client, float temperature) {
          char payload[32];
          snprintf(payload, sizeof(payload), "{\"temp\": %.1f}", temperature);
      
          struct mqtt_publish_param param = {
              .message.topic.qos = MQTT_QOS_1_AT_LEAST_ONCE,
              .message.topic.topic.utf8 = "sensor/dht22/temperature",
              .message.topic.topic.size = strlen("sensor/dht22/temperature"),
              .message.payload.data = payload,
              .message.payload.len = strlen(payload),
          };
          mqtt_publish(client, &param);
      }

      I prefer sending JSON payloads even for simple values. It costs almost nothing in bandwidth but makes the data much easier to parse on the receiving end.

  4. Configure Network Settings

    1. Add these to your prj.conf file:
    2. CONFIG_WIFI=y
      CONFIG_NET_L2_WIFI_MGMT=y
      CONFIG_MQTT_LIB=y
      CONFIG_SENSOR=y
      CONFIG_DHT=y
      CONFIG_LOG=y
    3. Wi-Fi credentials should go in a separate overlay or be set at build time rather than hardcoded in prj.conf. You can pass them as build arguments:
    4. west build -- -DCONFIG_WIFI_CREDENTIALS_STATIC_SSID="Your_SSID" \
                    -DCONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="Your_Password"
    5. Double-check your MQTT broker IP and port in the code. A common mistake is pointing at localhost instead of the actual broker IP on your network.
  5. Build and Flash the Application

    1. Build for the ESP32 target:
    2. west build -b esp32_devkitc_wroom app

      Note: the board name format changed in recent Zephyr versions. Use west boards | grep esp32 to find the exact name for your board variant.

    3. Flash to the ESP32:
    4. west flash
    5. Monitor the serial output to confirm Wi-Fi connects and MQTT publishes are going through:
    6. west espressif monitor

Troubleshooting

  • Sensor reads return errors or garbage values: The DHT22 is notoriously timing-sensitive. Make sure you're not reading faster than every 2 seconds. Also check that your pull-up resistor is in place and the wire run isn't too long (keep it under 1 meter for reliable readings).
  • Wi-Fi won't connect: Verify your SSID and password are correct (case-sensitive). Some ESP32 modules only support 2.4GHz networks, so make sure you're not trying to connect to a 5GHz band.
  • MQTT connection refused: Confirm the broker is running (systemctl status mosquitto on Linux) and that it's configured to accept connections from your network, not just localhost. Check the broker's listener config.
  • Build fails with missing symbols: You're probably missing a Kconfig option in prj.conf. The error messages from Zephyr builds can be cryptic, but they usually point to the missing config symbol if you read them carefully.

Conclusion

You now have a Zephyr-based temperature logger pushing DHT22 readings to MQTT over Wi-Fi. From here, the natural next steps are adding humidity data (the DHT22 already provides it), implementing a reconnection strategy for when Wi-Fi drops, or hooking up a subscriber on the other end to store readings in a database. You could also swap the DHT22 for a BME280 if you want faster, more accurate readings—the Zephyr sensor API makes that a mostly config-level change.