High-performance Rust library for decoding Ruuvi sensor BLE advertisements. Supports all major Ruuvi data formats with comprehensive validation and type safety.
- 🚀 High Performance: Optimized for minimal latency
- 🔒 Type Safe: Leverages Rust's type system for data integrity
- 📊 Complete Coverage: Supports Data Formats v5, v6, and E1
- 🧪 Thoroughly Tested: All official test vectors pass
- 🔧 Easy Integration: Simple API with comprehensive error handling
| Format | Status | Description |
|---|---|---|
| v5 (RAWv2) | ✅ Complete | Temperature, humidity, pressure, acceleration, battery |
| v6 | ✅ Complete | Adds PM2.5, CO2, VOC, NOX, luminosity |
| E1 | ✅ Complete | Extended format with PM1.0/2.5/4.0/10.0 |
Add this to your Cargo.toml:
[dependencies]
ruuvi-decoders = "0.2"use ruuvi_decoders::{decode, extract_ruuvi_from_ble};
// From a full BLE advertisement
let ble_data = "02010603031691FF990405159F7C025A8BC4A53C00FB00000000E7FEE7FE00E7FE";
let ruuvi_hex = extract_ruuvi_from_ble(ble_data).unwrap();
let decoded = decode(&ruuvi_hex).unwrap();
match decoded {
ruuvi_decoders::RuuviData::V5(data) => {
println!("Temperature: {}°C", data.temperature.unwrap());
println!("Humidity: {}%", data.humidity.unwrap());
println!("Pressure: {} Pa", data.pressure.unwrap());
println!("MAC: {}", data.mac_address);
},
// Handle v6 and E1 formats...
_ => println!("Other format"),
}use ruuvi_decoders::decode;
// Direct Ruuvi payload (without BLE wrapper)
let hex_data = "0512FC5394C37C0004FFFC040CAC364200CDCBB8334C884F";
let result = decode(hex_data).unwrap();
if let ruuvi_decoders::RuuviData::V5(data) = result {
assert_eq!(data.temperature, Some(24.3));
assert_eq!(data.humidity, Some(53.49));
assert_eq!(data.pressure, Some(100044.0));
}The most common format used by RuuviTag sensors:
use ruuvi_decoders::v5::decode;
let bytes = hex::decode("0512FC5394C37C0004FFFC040CAC364200CDCBB8334C884F").unwrap();
let data = decode(&bytes).unwrap();
println!("Sensor Data:");
println!(" MAC: {}", data.mac_address);
println!(" Temperature: {:.2}°C", data.temperature.unwrap_or(0.0));
println!(" Humidity: {:.2}%", data.humidity.unwrap_or(0.0));
println!(" Pressure: {:.0} Pa", data.pressure.unwrap_or(0.0));
println!(" Battery: {} mV", data.battery_voltage.unwrap_or(0));
println!(" TX Power: {} dBm", data.tx_power.unwrap_or(0));The library provides comprehensive error handling:
use ruuvi_decoders::{decode, DecodeError};
match decode("invalid_hex") {
Ok(data) => println!("Decoded: {:?}", data),
Err(DecodeError::InvalidHex(msg)) => eprintln!("Invalid hex: {}", msg),
Err(DecodeError::UnsupportedFormat(format)) => {
eprintln!("Unsupported format: 0x{:02X}", format)
},
Err(DecodeError::InvalidLength(msg)) => eprintln!("Wrong length: {}", msg),
Err(e) => eprintln!("Other error: {}", e),
}All data structures support serialization:
use ruuvi_decoders::decode;
let hex_data = "0512FC5394C37C0004FFFC040CAC364200CDCBB8334C884F";
let decoded = decode(hex_data).unwrap();
// Serialize to JSON
let json = serde_json::to_string(&decoded).unwrap();
println!("JSON: {}", json);
// Deserialize from JSON
let restored: ruuvi_decoders::RuuviData = serde_json::from_str(&json).unwrap();The library properly handles invalid/unavailable sensor readings:
use ruuvi_decoders::v5::decode;
// Test with invalid values (from official test vectors)
let invalid_data = hex::decode("058000FFFFFFFF800080008000FFFFFFFFFFFFFFFFFFFFFF").unwrap();
let result = decode(&invalid_data).unwrap();
// All sensor readings will be None for invalid data
assert_eq!(result.temperature, None);
assert_eq!(result.humidity, None);
assert_eq!(result.pressure, None);
assert_eq!(result.mac_address, "invalid");Ruuvi Decoders is optimized for high-throughput scenarios:
- Decoding: ~0.8μs per v5 message on modern hardware
- Memory: Zero heap allocations in decode path
- Throughput: >1M messages/second/core
Run benchmarks:
cargo benchSee the examples/ directory for complete examples:
basic_usage.rs- Simple decodingble_scanner.rs- BLE advertisement parsingerror_handling.rs- Comprehensive error handling
Run an example:
cargo run --example basic_usageThis library implements the official Ruuvi specifications:
All test vectors from the official documentation are included and pass.
git clone https://github.com/ruuvi/ruuvi-decoders
cd ruuvi-decoders
cargo build# Run all tests
cargo testContributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Ruuvi Innovations Ltd. for the sensor specifications
- ruuvitag-sensor Python library for inspiration
- RuuviTag Firmware - Official sensor firmware