Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 45 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,73 @@
# 🌦️ Rust Weather Station
# Rust Weather Station

<div align="center">
<img src=".github/assets/demo.jpg" width="60%" alt="Weather Station Demo" />
</div>

---
This repository contains the firmware for a solar-powered weather station based on an ESP32. The software is implemented entirely in Rust using the `esp-hal` hardware abstraction layer and the `embassy` async ecosystem. Sensor data is collected concurrently, published over MQTT, and the device returns to deep sleep to preserve the battery between sampling windows.

## 📌 About
## Hardware overview

This project is a weather station built with **Rust** and embedded hardware. It collects environmental data like **temperature**, **humidity**, **pressure**, **wind speed**, **wind direction**, and **rainfall**, and sends that data to an **MQTT** server for use in systems like **Home Assistant**.
The firmware targets the following hardware stack:

---
- ESP32 module serving as the main controller.
- AS5600 magnetic rotary sensor that tracks wind direction.
- DHT22 digital temperature and humidity sensor connected on a single data line.
- Anemometer and tipping-bucket rain gauge driven by hall-effect sensors.
- INA219 current and voltage monitor for battery telemetry.
- 18650 Li-ion battery with a CN3791-based charge controller and a 12 V solar panel.

## 🔧 Hardware Components
The enclosure, mast adapters, and sensor mounts are designed for 3D printing. STL files are available on Printables: [YAWS (Yet Another Weather Station)](https://www.printables.com/model/729382-yaws-yet-another-weather-station/files).

- **ESP32** – The main microcontroller running the code.
- **AS5600** – Magnetic rotary sensor for wind direction.
- **BME680** – Sensor for temperature, humidity, pressure, and gas.
- **Hall Effect Sensors** – Used in the anemometer and rain gauge.
- **18650 Li-ion Battery** – Power supply.
- **12V Solar Panel** – Charges the battery during the day.
- **CN3791 Solar Charger** – Manages charging and battery protection.
## Software architecture

---
### Async task layout

## 🌟 Features
The application runs under `esp-rtos` with the `embassy` executor:

- Publishes sensor data to an **MQTT** broker.
- Handles interrupts from wind and rain sensors using GPIO.
- Uses **deep sleep** to save power when idle.
- Supports multiple sensors over a shared I2C bus using Rust's embedded-hal tools.
- `wifi_task` brings up the Wi-Fi station interface and keeps the radio connected.
- `mqtt_task` drains a multi-producer queue and publishes each payload to the configured MQTT broker using the `rust-mqtt` client.
- `dht_task`, `anemo_task`, `as5600_task`, and `ina210_task` (INA219) sample their respective sensors and push structured readings onto the shared MQTT channel.
- Interrupt-driven peripherals (the anemometer and rain gauge) use debounce logic to ensure clean counts, while the AS5600 task averages multiple I2C readings to derive wind direction and cardinal labels.

---
Shared resources, such as the I2C bus, are coordinated through `embassy-embedded-hal` mutexes so multiple async tasks can safely communicate with their devices.

## 🛠️ Implementation Details
### Power management and scheduling

### 🔌 Sensor Integration
The main task supervises all worker tasks for a configurable active window, feeds the watchdog, and then disconnects nonessential peripherals before putting the ESP32 into deep sleep. Wakeups occur either on the deep-sleep timer or on the external interrupt used for the rain gauge, which allows single tips to be published immediately.

- **AS5600 (Wind Direction)**: Measures the position of a magnet to get the wind direction using I2C.
- **BME680 (Environmental Data)**: Reads temperature, humidity, pressure, and gas. Also I2C.
- Since Rust doesn't allow multiple mutable references, the [`embedded-hal-bus`](https://docs.rs/embedded-hal-bus/latest/embedded_hal_bus/) crate is used to safely share the I2C bus between devices.
## Configuration

### ⚡ Interrupts
Compile-time configuration values (Wi-Fi credentials, MQTT broker details, task durations, and channel sizes) are defined in `src/config.rs` through the `toml-cfg` macro. Provide a `cfg.toml` file in the project root with entries such as:

- **Anemometer & Rain Gauge**: Use magnets and hall sensors to trigger interrupts.
- When triggered, an interrupt sets a flag (`rotation_flag` or `rain_flag`), which is checked and handled later in the main loop.
- Interrupts must be manually re-enabled after they fire, due to how the API works.
```toml
[default]
ssid = "your-ssid"
wifi_pass = "your-password"
broker_ip = "192.168.1.10"
broker_port = 1883
mqtt_user = "station"
mqtt_pass = "secret"
topic = "weather_station"
```

### 📤 MQTT
Adjust `deep_sleep_dur_secs`, `main_task_dur_secs`, and `task_dur_secs` to control how long the station stays awake, how often readings are taken, and how frequently MQTT packets are sent.

- Data is published via functions like `publish_wifi_data()`, `publish_bme_data()`, etc.
- A separate thread manages the MQTT connection to keep it stable.
- Data is sent at regular intervals, and the ESP32 sleeps between cycles to save battery.
## Building and flashing

### 💤 Deep Sleep Mode
1. Install the ESP32 Rust toolchain specified in `rust-toolchain.toml` and ensure you have `cargo-espflash` available.
2. Connect the ESP32 over USB and place it into bootloader mode (usually by holding BOOT while pressing EN).
3. Build and flash the firmware:

- **Active (~1min)**: ESP32 wakes up, handles interrupts, checks if it’s time to send data.
- **Sleep (~20min)**: ESP32 goes into deep sleep to reduce power usage.

---
```bash
cargo espflash flash --release /dev/ttyUSB0
```

## 🧱 Resources
Replace the serial port path with the one that matches your workstation.

You can download the 3D printable parts (STL files) here:
👉 [Printables - YAWS (Yet Another Weather Station)](https://www.printables.com/model/729382-yaws-yet-another-weather-station/files)
After flashing, the station will connect to the configured Wi-Fi network, stream sensor values to the MQTT broker, and fall back to deep sleep between sampling intervals.

### 🔄 Thread-to-thread queue example
## Thread-to-thread queue example

Check `examples/dht_mqtt_queue.rs` for a minimal snippet that shows how a DHT sampling task can push readings into a FreeRTOS queue that a dedicated MQTT publisher drains using `esp-idf-svc` primitives.
For a smaller example demonstrating the same queueing pattern between tasks, see `examples/dht_mqtt_queue.rs`. It shows how a sensor sampling task can push readings into a FreeRTOS queue that an MQTT publisher drains using `esp-idf-svc` primitives.
Loading