diff --git a/Cargo.lock b/Cargo.lock index da8ed39..e75ef65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ "serialport", "strum", "tokio", + "uom", ] [[package]] @@ -424,6 +425,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -825,12 +835,28 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "uom" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8362194c7a9845a7a7f3562173d6e1da3f24f7132018cb78fe77a5b4474187b2" +dependencies = [ + "num-traits", + "typenum", +] + [[package]] name = "want" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index 0721848..0618f7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,4 @@ log = "0.4.20" serialport = "4.2.2" strum = { version = "0.25.0", features = ["derive"] } tokio = { version = "1.34.0", features = ["full"] } +uom = "0.35.0" diff --git a/src/index.html b/src/index.html index 37d3aee..7aab2b2 100644 --- a/src/index.html +++ b/src/index.html @@ -11,33 +11,33 @@

Wasser

-

Temperatur: {0} °C

-

Temperatur Min: {1} °C

-

Temperatur Max: {2} °C

-

Solltemperatur Solar: {3} °C

-

Solltemperatur Netz: {4} °C

+

Temperatur: {}

+

Temperatur Min: {}

+

Temperatur Max: {}

+

Solltemperatur Solar: {}

+

Solltemperatur Netz: {}

Solar aktuell

-

Spannung: {5} V

-

Strom: {6} A

-

Leistung: {7} kW

+

Spannung: {}

+

Strom: {}

+

Leistung: {} ({})

Historie

-

Solarenergie Heute: {8} kWh

-

Solarenergie Gesamt: {9} kWh

-

Netzenergie Heute: {10} kWh

+

Solarenergie Heute: {} ({})

+

Solarenergie Gesamt: {} ({})

+

Netzenergie Heute: {} ({})

Zustand

-

Isolationsmessung: {11}

-

Gerätetemperatur: {12} °C

-

Status: {13}

-

DC Trenner: {14}

-

DC Relais: {15}

-

AC Relais: {16}

+

Isolationsmessung: {}

+

Gerätetemperatur: {}

+

Status: {}

+

DC Trenner: {}

+

DC Relais: {}

+

AC Relais: {}

Misc

-

Betriebstag: {17}

-

Firmware: {18}

-

Seriennummer: {19}

+

Betriebstag: {}

+

Firmware: {}

+

Seriennummer: {}

\ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 47b68b3..761dbc0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use anyhow::Context; use axum::{ http::StatusCode, @@ -6,8 +8,19 @@ use axum::{ Router, }; use strum::{EnumIter, IntoEnumIterator}; +use uom::{ + fmt::DisplayStyle::Abbreviation, + si::{ + electric_current::ampere, + electric_potential::volt, + energy::{kilowatt_hour, watt_hour}, + f32::*, + power::{kilowatt, watt}, + thermodynamic_temperature::degree_celsius, + }, +}; -#[derive(EnumIter, Debug)] +#[derive(EnumIter, PartialEq, Eq, Hash, Debug)] enum StatusTag { Dummy0, Firmware, @@ -41,28 +54,28 @@ enum StatusTag { Dummy13, } -#[derive(Default, Debug)] +#[derive(Debug)] struct Status<'a> { // Wasser - wassertemp: f32, - wassertemp_min: f32, - wassertemp_max: f32, - solltemp_solar: f32, - solltemp_netz: f32, + wassertemp: ThermodynamicTemperature, + wassertemp_min: ThermodynamicTemperature, + wassertemp_max: ThermodynamicTemperature, + solltemp_solar: ThermodynamicTemperature, + solltemp_netz: ThermodynamicTemperature, // Solar aktuell - solarspannung: f32, - solarstrom: f32, - solarleistung: f32, + solarspannung: ElectricPotential, + solarstrom: ElectricCurrent, + solarleistung: Power, // Historie - solarenergie_heute: f32, - solarenergie_gesamt: f32, - netzenergie_heute: f32, + solarenergie_heute: Energy, + solarenergie_gesamt: Energy, + netzenergie_heute: Energy, // Zustand iso_messung: u32, - geraetetemp: u32, + geraetetemp: ThermodynamicTemperature, status: u32, dc_trenner: bool, dc_relais: bool, @@ -111,64 +124,80 @@ async fn handler() -> Result, AppError> { let data = read_device().context("Could not retrieve device data")?; let data_string = std::str::from_utf8(&data).unwrap(); - let mut status = Status::default(); - for (value, tag) in data_string.split('\t').zip(StatusTag::iter()) { - match tag { - StatusTag::Firmware => status.firmware = value, - StatusTag::Betriebstag => status.betriebstag = str::parse(value).unwrap(), - StatusTag::Status => status.status = str::parse(value).unwrap(), - StatusTag::DcTrenner => status.dc_trenner = str::parse::(value).unwrap() != 0, - StatusTag::DcRelais => status.dc_relais = str::parse::(value).unwrap() != 0, - StatusTag::AcRelais => status.ac_relais = str::parse::(value).unwrap() != 0, - StatusTag::Wassertemp => status.wassertemp = str::parse::(value).unwrap() / 10.0, - StatusTag::WassertempMin => { - status.wassertemp_min = str::parse::(value).unwrap() / 10.0 - } - StatusTag::WassertempMax => { - status.wassertemp_max = str::parse::(value).unwrap() / 10.0 - } - StatusTag::SolltempSolar => { - status.solltemp_solar = str::parse::(value).unwrap() / 10.0 - } - StatusTag::SolltempNetz => { - status.solltemp_netz = str::parse::(value).unwrap() / 10.0 - } - StatusTag::GeraeteTemp => status.geraetetemp = str::parse(value).unwrap(), - StatusTag::IsoMessung => status.iso_messung = str::parse(value).unwrap(), - StatusTag::Solarspannung => status.solarspannung = str::parse::(value).unwrap(), - StatusTag::Solarstrom => status.solarstrom = str::parse::(value).unwrap(), - StatusTag::Solarleistung => { - status.solarleistung = str::parse::(value).unwrap() / 1000.0 - } - StatusTag::SolarenergieHeute => { - status.solarenergie_heute = str::parse::(value).unwrap() / 1000.0 - } - StatusTag::SolarenergieGesamt => { - status.solarenergie_gesamt = str::parse::(value).unwrap() / 1000.0 - } - StatusTag::NetzenergieHeute => { - status.netzenergie_heute = str::parse::(value).unwrap() / 1000.0 - } - StatusTag::Seriennummer => status.seriennummer = value, - _ => (), - } - } + let status_map = StatusTag::iter() + .zip(data_string.split('\t')) + .collect::>(); + + let status = Status { + wassertemp: ThermodynamicTemperature::new::( + status_map[&StatusTag::Wassertemp].parse::()? / 10.0, + ), + wassertemp_min: ThermodynamicTemperature::new::( + status_map[&StatusTag::WassertempMin].parse::()? / 10.0, + ), + wassertemp_max: ThermodynamicTemperature::new::( + status_map[&StatusTag::WassertempMax].parse::()? / 10.0, + ), + solltemp_solar: ThermodynamicTemperature::new::( + status_map[&StatusTag::SolltempSolar].parse::()? / 10.0, + ), + solltemp_netz: ThermodynamicTemperature::new::( + status_map[&StatusTag::SolltempNetz].parse::()? / 10.0, + ), + solarspannung: ElectricPotential::new::( + status_map[&StatusTag::Solarspannung].parse()?, + ), + solarstrom: ElectricCurrent::new::(status_map[&StatusTag::Solarstrom].parse()?), + solarleistung: Power::new::(status_map[&StatusTag::Solarleistung].parse()?), + solarenergie_heute: Energy::new::( + status_map[&StatusTag::SolarenergieHeute].parse()?, + ), + solarenergie_gesamt: Energy::new::( + status_map[&StatusTag::SolarenergieGesamt].parse()?, + ), + netzenergie_heute: Energy::new::( + status_map[&StatusTag::NetzenergieHeute].parse()?, + ), + iso_messung: status_map[&StatusTag::IsoMessung].parse()?, + geraetetemp: ThermodynamicTemperature::new::( + status_map[&StatusTag::GeraeteTemp].parse()?, + ), + status: status_map[&StatusTag::Status].parse()?, + dc_trenner: status_map[&StatusTag::DcTrenner].parse::()? != 0, + dc_relais: status_map[&StatusTag::DcRelais].parse::()? != 0, + ac_relais: status_map[&StatusTag::AcRelais].parse::()? != 0, + betriebstag: status_map[&StatusTag::Betriebstag].parse()?, + firmware: status_map[&StatusTag::Firmware], + seriennummer: status_map[&StatusTag::Seriennummer], + }; + + let w = Power::format_args(watt, Abbreviation); + let kw = Power::format_args(kilowatt, Abbreviation); + let wh = Energy::format_args(watt_hour, Abbreviation); + let kwh = Energy::format_args(kilowatt_hour, Abbreviation); + let v = ElectricPotential::format_args(volt, Abbreviation); + let a = ElectricCurrent::format_args(ampere, Abbreviation); + let c = ThermodynamicTemperature::format_args(degree_celsius, Abbreviation); Ok(Html(format!( include_str!("index.html"), - status.wassertemp, - status.wassertemp_min, - status.wassertemp_max, - status.solltemp_solar, - status.solltemp_netz, - status.solarspannung, - status.solarstrom, - status.solarleistung, - status.solarenergie_heute, - status.solarenergie_gesamt, - status.netzenergie_heute, + c.with(status.wassertemp), + c.with(status.wassertemp_min), + c.with(status.wassertemp_max), + c.with(status.solltemp_solar), + c.with(status.solltemp_netz), + v.with(status.solarspannung), + a.with(status.solarstrom), + kw.with(status.solarleistung), + w.with(status.solarleistung), + kwh.with(status.solarenergie_heute), + wh.with(status.solarenergie_heute), + kwh.with(status.solarenergie_gesamt), + wh.with(status.solarenergie_gesamt), + kwh.with(status.netzenergie_heute), + wh.with(status.netzenergie_heute), status.iso_messung, - status.geraetetemp, + c.with(status.geraetetemp), status.status, status.dc_trenner, status.dc_relais,