Monitoring Air Quality with the SEN5x Rust Driver
Hauke Jung··4 min readOn this page (7 sections)
If you’ve worked with Sensirion’s SEN5x sensor modules, you know they pack an impressive amount of environmental sensing into a tiny package — particulate matter, VOC index, NOx index, humidity, and temperature, all over a single I2C bus. What’s been missing is a solid no_std Rust driver to talk to them. That’s why I built sen5x-rs.
What is the SEN5x?
The SEN5x is Sensirion’s environmental sensor node series. Depending on the variant, you get different measurement capabilities:
| Variant | PM1.0/2.5/4.0/10.0 | VOC Index | NOx Index | Humidity | Temperature |
|---|---|---|---|---|---|
| SEN50 | ✓ | — | — | — | — |
| SEN54 | ✓ | ✓ | — | ✓ | ✓ |
| SEN55 | ✓ | ✓ | ✓ | ✓ | ✓ |
The SEN55 is the most capable model, giving you a full picture of indoor air quality from a single sensor. All variants communicate over I2C at address 0x69.
The Driver
The sen5x crate provides a complete, type-safe interface for all three sensor variants. It’s built on embedded-hal 1.0, works in no_std environments, and comes with full async support via embedded-hal-async.
Add it to your project:
[dependencies]
sen5x = "0.2"
# For async support (e.g., with Embassy)
# sen5x = { version = "0.2", features = ["embedded-hal-async"] }
Features
- Blocking and async APIs — full feature parity between
Sen5xandSen5xAsync no_stdby default — runs on bare-metal microcontrollers without heap allocation- CRC validation — every I2C read is verified using Sensirion’s CRC8 checksum
- defmt support — opt-in embedded logging with the
defmtfeature - Command safety — the driver tracks measurement state internally and prevents invalid command sequences
Getting Started
Here’s a minimal example reading air quality data on a Raspberry Pi using linux-embedded-hal:
use ;
use Sen5x;
The sensor updates every second. After calling start_measurement(), poll data_ready() and read with measurement() when new data is available.
Async on Embedded — ESP32-C3 with Embassy
For microcontroller targets, the async driver is the way to go. Here’s how it looks on an ESP32-C3 using Embassy:
use ;
use Sen5xAsync;
async
The API is identical to the blocking version — just add .await. No separate learning curve.
Beyond Basic Measurements
The driver exposes the full SEN5x feature set, not just the basics:
Fan management — trigger manual cleaning cycles or configure the auto-cleaning interval:
sensor.start_fan_cleaning?;
// or
sensor.set_fan_auto_cleaning_interval?; // weekly
Temperature compensation — correct for self-heating or enclosure effects:
sensor.set_temperature_offset_simple?; // offset in °C
VOC/NOx algorithm tuning — adjust the on-chip gas index algorithm parameters for your specific environment.
Algorithm state backup — save and restore the VOC algorithm state across power cycles. This avoids the 12-hour learning phase after every reboot:
let state = sensor.voc_algorithm_state?;
// persist `state` to flash/EEPROM
// ... after reboot:
sensor.set_voc_algorithm_state?;
Error Handling
Errors are generic over the underlying I2C implementation, keeping the driver platform-agnostic:
Enable the thiserror feature for std::error::Error integration, or defmt for embedded-friendly formatting.
Links
- Crate: crates.io/crates/sen5x
- Source: github.com/hauju/sen5x-rs
- Docs: docs.rs/sen5x
- Datasheet: Sensirion SEN5x Datasheet
