A cookbook for a weather station β€” Part I

Have you ever wondered how to measure temperature and humidity?

I decided to explore it by building my own setup from sensor to display:

flowchart TD ESP["πŸ”Œ NodeMCU ESP8266"] -->|Digital Pin| DHT["🌑️ DHT22 Sensor"] ESP -->|Wi-Fi / MQTT Publish| MQTT["πŸ“‘ MQTT Broker"] subgraph "πŸ“ Raspberry Pi" direction TB MQTT Rust["πŸ¦€ Rust Logger"] DB["πŸ—„οΈ SQLite Database"] HA["🏠 Home Assistant"] end Rust -->|Subscribes to topic| MQTT Rust -->|Writes data to| DB HA -->|Reads data from| MQTT
Hardware stack
NodeMCU ESP8266 acts as the "brain" of the weather station - reads data from the sensor and forwards it via Wi-Fi
DHT22 measures temperature and humidity
Raspberry Pi hosts an MQTT client that receives weather data published via the NodeMCU ESP8266 over Wi-Fi, allowing the data to be stored, processed, and shared
Software stack
MQTT messaging protocol for IoT using a publish/subscribe system
Arduino / C++ NodeMCU ESP8266 runs Arduino/C++ code to read data from the sensor and publish to the MQTT topics
Home Assistant subscribes to the MQTT topics to receive and display the measurements
SQLite database to archive and store the weather station’s historical data on the Raspberry Pi
Rust implements a logger that saves incoming MQTT weather data into the SQLite database

Assembling the sensor

To connect a DHT22 temperature and humidity sensor to the NodeMCU ESP8266, wire the VCC pin of the DHT22 to the NodeMCU ESP8266’s 3.3V pin and the GND pin to a GND pin on the NodeMCU ESP8266. Then connect the Data pin to the digital pin (D2) on the NodeMCU ESP8266.

If you want a visual walkthrough, Arduino provides an official tutorial that covers this step-by-step.

Retrieving temperature and humidity values

The NodeMCU ESP8266 and DHT22 sensor work together: every 10 minutes, the device connects to Wi-Fi and syncs its clock with an NTP server to get the correct time:

cpp
#include <WiFiUdp.h>
#include <NTPClient.h>

...

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 60000);

...

timeClient.update();

The DHT22 library handles updating temperature and humidity values:

cpp
#include <DHT22.h>

...

#define pinDATA SDA

...

DHT22 dht22(pinDATA);

...

float humidity = dht22.getHumidity();
float temperature = dht22.getTemperature();

Publishing data to MQTT

Since NodeMCU ESP8266 has a Wi-Fi module, the measured values can be published to an MQTT client hosted on a Raspberry Pi.

The board first joins the Wi-Fi network:

cpp
#include <ESP8266WiFi.h>

...

WiFiClient espClient;

...

const char* ssid = "ssid";
const char* password = "password";

...

void setup_wifi() {
  delay(10);
  Serial.println("Connecting to WiFi ...");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected. IP: ");
  Serial.println(WiFi.localIP());
}

With the Wi-Fi connection available, the board can publish data to MQTT:

cpp
#include <PubSubClient.h>


...

PubSubClient client(espClient);

...

const int mqtt_port = 1883;
const char* mqtt_server = "mqtt_server";

...

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection ...");
    if (client.connect("NodeMCUClient")) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" retrying in 5 seconds");
      delay(5000);
    }
  }
}

...

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  timeClient.begin();
}

...

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  timeClient.update();

  ...

}

Sensor measurements are sent as json messages containing the metric, value, unit, timestamp, and published via MQTT to designated topics. Since the NodeMCU ESP8266 transmits every 10 minutes, the buffer time is sufficient to capture all measurements.

cpp
const char* mqtt_temperature_topic = "weather/indoor-sensor/temperature";
const char* mqtt_humidity_topic = "weather/indoor-sensor/humidity";

...

void loop() {
  // Check if readings are valid
  if (!isnan(humidity) && !isnan(temperature)) {
    unsigned long timestamp = timeClient.getEpochTime();

    // Prepare temperature payload as JSON
    String temperature_payload = "{\"metric\": \"temperature\", \"value\": " + String(temperature) + ", \"unit\": \"℃\", \"timestamp\": " + String((uint64_t)timestamp) + "}";

    // Prepare humidity payload as JSON
    String humidity_payload = "{\"metric\": \"humidity\", \"value\": " + String(humidity) + ", \"unit\": \"%\", \"timestamp\": " + String((uint64_t)timestamp) + "}";

    // Publish temperature
    client.publish(mqtt_temperature_topic, temperature_payload.c_str());
    Serial.println("Published temperature: " + temperature_payload);

    // Publish humidity
    client.publish(mqtt_humidity_topic, humidity_payload.c_str());
    Serial.println("Published humidity: " + humidity_payload);

  } else {
    Serial.println("Failed to read from DHT sensor");
  }

  delay(600000);

}

Syncing with Home Assistant

Once the data lands in MQTT, the measurements can be displayed in Home Assistant configuring MQTT Sensor.

Up next

In the next part, I’ll dive into my Rust-based logger and share how it works.

Stay tuned, Pyrsuers! 🐍

If you would like to check out the entire project, it is available in my weather-station repo.