Prototype working
This commit is contained in:
parent
eec38c074c
commit
36a2eaab32
9
Cargo.lock
generated
9
Cargo.lock
generated
@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@ -1056,7 +1062,10 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
name = "weather_exporter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bme280",
|
||||
"byteorder",
|
||||
"embedded-hal",
|
||||
"linux-embedded-hal",
|
||||
"tokio",
|
||||
"warp",
|
||||
|
@ -9,5 +9,8 @@ description = "A Prometheus exporter for weather data."
|
||||
[dependencies]
|
||||
bme280 = "0.4.4"
|
||||
linux-embedded-hal = "0.4.0-alpha.2"
|
||||
embedded-hal = "1.0.0-alpha.7"
|
||||
tokio = { version = "1.23.0", features = ["macros", "rt"] }
|
||||
warp = "0.3.3"
|
||||
byteorder = "1.4.3"
|
||||
anyhow = "1.0.68"
|
||||
|
121
src/main.rs
121
src/main.rs
@ -1,23 +1,110 @@
|
||||
use bme280;
|
||||
use linux_embedded_hal::{I2cdev, Delay};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use bme280::{self, Measurements};
|
||||
use linux_embedded_hal::{I2cdev, Delay, I2CError};
|
||||
use embedded_hal::i2c::blocking::I2c;
|
||||
use byteorder::{LittleEndian, ByteOrder};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use anyhow::{Result, anyhow};
|
||||
use warp::Filter;
|
||||
|
||||
fn main() {
|
||||
struct LightSensor {
|
||||
addr: u8,
|
||||
reg: u8,
|
||||
bus: I2cdev,
|
||||
}
|
||||
|
||||
let loop_time = Duration::from_secs(5);
|
||||
impl LightSensor {
|
||||
fn new(bus: I2cdev, addr: u8, port: u8) -> Self {
|
||||
Self { bus, addr, reg: port + 0x10 }
|
||||
}
|
||||
|
||||
let i2c = I2cdev::new("/dev/i2c-1")
|
||||
.expect("Could not open i2c bus");
|
||||
|
||||
let mut sensor = bme280::i2c::BME280::new_primary(i2c);
|
||||
|
||||
sensor.init(&mut Delay).expect("Could not initialize BME280 sensor");
|
||||
|
||||
loop {
|
||||
let baro = sensor.measure(&mut Delay).expect("Could not perform measurement");
|
||||
println!("H {}%, P {} PA, T {}°C", baro.humidity, baro.pressure, baro.temperature);
|
||||
thread::sleep(loop_time);
|
||||
fn measure(&mut self) -> Result<u16, I2CError> {
|
||||
self.bus.write(self.addr, &[self.reg])?;
|
||||
//thread::sleep(Duration::from_millis(10));
|
||||
let mut buf = [0; 2];
|
||||
self.bus.write_read(self.addr, &[self.reg], &mut buf[..])?;
|
||||
Ok(LittleEndian::read_u16(&buf))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct Station {
|
||||
light: LightSensor,
|
||||
bme280: bme280::i2c::BME280<I2cdev>,
|
||||
}
|
||||
|
||||
impl Station {
|
||||
fn new() -> Result<Self> {
|
||||
|
||||
let i2c = I2cdev::new("/dev/i2c-1")
|
||||
.map_err(|e| anyhow!("Could not open i2c bus: {}", e))?;
|
||||
|
||||
// TODO properly share the device across the two consumers. Probably need to implement I2cdev for RefCell<impl I2cdev> or something
|
||||
// for now just open it twice :/
|
||||
let i2c2 = I2cdev::new("/dev/i2c-1")
|
||||
.map_err(|e| anyhow!("Could not open second i2c bus: {}", e))?;
|
||||
|
||||
let mut bme280 = bme280::i2c::BME280::new_primary(i2c);
|
||||
bme280.init(&mut Delay).expect("Could not initialize BME280 sensor");
|
||||
|
||||
let light = LightSensor::new(i2c2, 0x08, 0x00);
|
||||
|
||||
Ok(Self { light, bme280 })
|
||||
}
|
||||
|
||||
fn measure(&mut self) -> Result<(Measurements<I2CError>, u16)> {
|
||||
let baro = self.bme280.measure(&mut Delay)
|
||||
.map_err(|e| anyhow!("Cannot measure bme280: {:?}", e))?;
|
||||
let lux = self.light.measure()
|
||||
.map_err(|e| anyhow!("Cannot measure light: {:?}", e))?;
|
||||
Ok((baro, lux))
|
||||
}
|
||||
|
||||
pub fn scrape(&mut self) -> String {
|
||||
|
||||
let ( Measurements { temperature, pressure, humidity, .. }, lux) = match self.measure() {
|
||||
Err(e) => {
|
||||
return format!("# Error measuring: {:?}", e)
|
||||
},
|
||||
Ok(v) => v,
|
||||
};
|
||||
|
||||
let lux = lux as f64 / 1000f64;
|
||||
|
||||
eprintln!("Scraped data: T={temperature}°C P={pressure}Pa H={humidity}% L={lux}");
|
||||
|
||||
format!(
|
||||
"# HELP weather_temperature_celsius Temperature in °C
|
||||
# TYPE weather_temperature_celsius gauge
|
||||
weather_temperature_celsius {temperature}
|
||||
# HELP weather_humidity_percent Humidity percentage
|
||||
# TYPE weather_humidity_percent gauge
|
||||
weather_humidity_percent {humidity}
|
||||
# HELP weather_pressure_pascals Atmospheric pressure in Pascals
|
||||
# TYPE weather_pressure_pascals gauge
|
||||
weather_pressure_pascals {pressure}
|
||||
# HELP weather_illumination_relative Relative illumination as a fraction of the maximum
|
||||
# TYPE weather_illumination_relative gauge
|
||||
weather_illumination_relative {lux}
|
||||
")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[tokio::main(flavor="current_thread")]
|
||||
async fn main() -> Result<()> {
|
||||
|
||||
let home = format!("<html><body><h1>Weather Station v0.1</h1><ul><li><a href=\"https://git.xolus.net/max/weather_exporter\">source code</a></li><li><a href=\"/metrics\">metrics</a></li></ul></body></html>");
|
||||
let home: &'static str = Box::leak(home.into_boxed_str());
|
||||
|
||||
let station = Station::new()?;
|
||||
let station = Arc::new(Mutex::new(station));
|
||||
|
||||
let filter = warp::path!("metrics").map(move || station.lock().unwrap().scrape())
|
||||
.or(warp::path!().map(move || { warp::reply::html(home) }));
|
||||
|
||||
eprintln!("Starting web server.");
|
||||
Ok(warp::serve(filter).run(([0,0,0,0], 9073)).await)
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user