An air quality monitoring sensor node based on the Raspberry Pi Pico 2W and Sensirion SEN66 sensor, written entirely in Rust using the Embassy framework.
- Real-time monitoring of air quality parameters using the Sensirion SEN66 sensor
- Displays readings on Waveshare 3.7" e-paper Pico display
- Optionally sends data to an MQTT broker for home automation integration
- Configurable sampling interval and configurable thresholds for visual indicators
- 3D printed case files available (STL files available in
case/
directory)
The sensor node provides monitoring of:
- Temperature (°C)
- Relative humidity (%)
- CO₂ concentration (ppm)
- VOC index
- Particulate matter (PM1.0, PM2.5, PM4.0, PM10)
- 1x Raspberry Pi Pico 2W
- 1x Sensirion SEN66 sensor
- 1x Waveshare 3.7" e-paper Pico display
- 1x USB-C socket 2-wire socket like this one (available from various sources, Amazon, ebay, etc.)
- 1x USB-A to USB-C cable
- 1x GHR-06V-S receptable for the SEN66 sensor (available e.g. from DigiKey)
- 4x jumper wires compatible with the GHR-06V-S receptable (available e.g. from DigiKey, I used the 2" wire length, which is tight in combination with the printed case, 6" is probably also okay, but you'll have to tuck the wires in the case)
- 3D printed case (STL files in
case/
folder) - 4x M2.5 x 5mm screws to connect the main case with the sensor mount.
- A programmer (e.g. Raspberry Pi Debug Probe, Raspberry Pi Pico (2/W), or any other SWD programmer compatible with the Raspberry Pi Pico)
- A separate 5V-to-3V3 converter for the SEN66, e.g., this or this
Warning
When using a USB-C socket as listed above, a USB-A to USB-C cable will be required for powering the sensor node, a USB-C to USB-C cable will not work due to the resistors for the USB-C power negotiation not being present in the cheap sockets.
Caution
Please note that the wiring shown was for prototyping only and the actual setup must include a separate 5V-to-3V3 converter for the SEN66 sensor, as described below.
One end of the SEN66 sensor is connected to the SEN66 via the GHR-06V-S receptacle, the other end is directly soldered to the Pico.
- SDA → GPIO 26
- SCL → GPIO 27
- VCC → 3.3V (from external 5V-to-3V3 converter)
- GND → GND
Caution
Per it's datasheet, the SEN66 draws up to 300mA (typ.) / 350 mA (max.), exceeding the Raspberry Pi Pico's 300 mA recommendation (quote from the datasheet: "it is recommended to keep the load on this pin under 300mA"). Therefore, it is necessary to use a separate 5V-to-3V3 converter for powering the SEN66 sensor.
As the Pico 2W is directly hooked up to the e-paper display, no additional wiring is required. The display is connected internally to the Pico 2W's GPIO pins.
The USB-C socket wires are also directly soldered to the Pico 2W, providing power to the board.
The case/
directory contains three STL files for the enclosure:
case_main.stl
- Main body of the casefront_cover.stl
- Front cover with display window (printed at 100.5% size to fit the display snugly in my case, adjust as needed)sensor_mount.stl
- Mount for the SEN66 sensor: after multiple iterations, this "open" design was deliberately chosen for the sensor to have as much thermal decoupling from the main case (and the Pico inside it) to minimize temperature influence on the sensor readings.
All three parts can be printed without support on a BambuLab A1 printer in less than 2 hours.
- Snap the USB-C socket into the main case part.
- Solder the wires onto the Pico 2W as described in the wiring section (for the power socket, the socket needs to be seated in the case at this point already!) and push the other end into the right slot of the sensor connector receptable.
- Mount the Pico 2W onto the display.
- Snap the SEN66 sensor into Sensor Mount part.
- Mount the Sensor Mount onto the main case part using the M2.5 screws.
- Pass the jumper wires through the hole in the main case part and connect them to the SEN66 sensor (use tweezers if needed).
- Push the display assembly into the main case part in the correct orientation. Due to the design of the case, the display should fit snugly and not require any additional screws.
- Snap the front cover onto the main case part to complete the assembly. The front cover should also fit snugly. If it does not fit snugly, try increasing the part size uniformly (e.g., by 0.5%) in the printing slicer until it fits well.
The project makes heavy use of the embedded no-std
rust ecosystem and uses (amongst others):
embassy-rs
for the async runtime and hardware abstraction,epd-waveshare
for addressing the e-paper display,embedded-graphics
,embedded-icon
, andu8g2-fonts
for rendering graphics and text on the display,sen66-rs
for the SEN66 sensor driver, andrust-mqtt
andserde-json-core
for the MQTT functionality.
probe-rs
is used for interacting with the Raspberry Pi Pico 2W.
The software is structured in several tasks:
- Sensor Task: Reads data from the SEN66 sensor at regular intervals
- Display Task: Updates the e-paper display with the latest sensor data
- MQTT Task: Sends data to a configured MQTT broker
- Wifi Background Task: Manages the WiFi connection (from embassy)
The tasks communicate using Embassy's pub/sub channels.
A custom panic handler is implemented to log panics to the display.
The system can be configured by copying the config.template.rs
file in the repository root directory to config.rs
(excluded from committing with .gitignore
) and modifying the values there:
// Example configuration
pub const WIFI_ENABLED: bool = true;
pub const WIFI_SSID: &str = "your-ssid";
pub const WIFI_PASSWORD: &str = "your-password";
pub const MQTT_BROKER_HOST: &str = "homeassistant";
pub const MQTT_BROKER_PORT: u16 = 1883;
pub const MQTT_TOPIC: &str = "homeassistant/sen66";
// Sensor thresholds
pub const CO2_THRESHOLD: u16 = 1000; // PPM
pub const TEMPERATURE_THRESHOLD: f32 = 25.0; // °C
pub const HUMIDITY_THRESHOLD: f32 = 60.0; // %
// ... other thresholds
The usage of the config.rs
file can then be tiggered by enabling the use-config-file
feature.
- Rust toolchain with
thumbv8m.main-none-eabihf
target installed probe-rs
installed- Pico 2W connected via Debug Probe or other SWD programmer
cyw43-firmware
binary blobs already flashed to the Pico 2W (available from here, see this example for instructions on how to flash) at the following addresses:0x10100000
for the firmware and0x10140000
for the CLM blob.
-
Clone the repository:
git clone https://github.com/ducktec/sen66-display.git cd sen66-display
-
Create your
config.rs
file from the template:cp config.template.rs config.rs
-
Edit
config.rs
with your WiFi and MQTT credentials -
Build the project:
cargo build --features use-config-file
[!WARNING] This might take a while, as the used
embedded-icon
crate during it's build will download the used icons (from the github source repos) and compile them into the suitable formats. This is a one-time operation, subsequent builds will be faster. -
Flash to the Pico 2W:
cargo run --features use-config-file
The device can be integrated with Home Assistant using MQTT auto-discovery. The sensor data is published to the configured MQTT topic in JSON format (including the NOx value which is not shown on the display):
{
"pm1": 1.9,
"pm2_5": 3.8,
"pm4": 5.2,
"pm10": 5.9,
"humidity": 43.34,
"temperature": 25.705,
"co2": 517,
"voc": 14,
"nox": 1
}
This project is licensed under MIT License (see LICENSE_MIT)