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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user