mirror of
https://codeberg.org/icewind/taspromto.git
synced 2026-08-02 12:14:45 +02:00
cleanup dsmr
This commit is contained in:
parent
16993948cf
commit
74463cc56e
5 changed files with 114 additions and 85 deletions
98
src/device/dsmr.rs
Normal file
98
src/device/dsmr.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
use std::{
|
||||||
|
fmt::{self, Display},
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum DsmrMessageType {
|
||||||
|
Water,
|
||||||
|
Gas,
|
||||||
|
Energy1,
|
||||||
|
Energy2,
|
||||||
|
Power,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DsmrState {
|
||||||
|
pub name: String,
|
||||||
|
pub power: Option<f32>,
|
||||||
|
pub power_total_tariff_1: Option<f32>,
|
||||||
|
pub power_total_tariff_2: Option<f32>,
|
||||||
|
pub gas_total: Option<f32>,
|
||||||
|
pub water_total: Option<f32>,
|
||||||
|
pub last_seen: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DsmrState {
|
||||||
|
pub fn new(name: String) -> Self {
|
||||||
|
DsmrState {
|
||||||
|
name,
|
||||||
|
power: None,
|
||||||
|
power_total_tariff_1: None,
|
||||||
|
power_total_tariff_2: None,
|
||||||
|
gas_total: None,
|
||||||
|
water_total: None,
|
||||||
|
last_seen: Instant::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_open_metrics(&self) -> impl Display + '_ {
|
||||||
|
DsmrFormatter { device: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DsmrFormatter<'a> {
|
||||||
|
device: &'a DsmrState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for DsmrFormatter<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let power_total = self.device.power_total_tariff_1.unwrap_or_default()
|
||||||
|
+ self.device.power_total_tariff_2.unwrap_or_default();
|
||||||
|
if power_total > 0.0 {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"power_total_kwh{{name=\"{}\"}} {}",
|
||||||
|
self.device.name, power_total
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(power) = self.device.power_total_tariff_1 {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"power_total_low_kwh{{name=\"{}\"}} {}",
|
||||||
|
self.device.name, power
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(power) = self.device.power_total_tariff_2 {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"power_total_high_kwh{{name=\"{}\"}} {}",
|
||||||
|
self.device.name, power
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(power) = self.device.power {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"power_watts{{name=\"{}\"}} {}",
|
||||||
|
self.device.name,
|
||||||
|
power * 1000.0
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(gas) = self.device.gas_total {
|
||||||
|
writeln!(f, "gas_total_m3{{name=\"{}\"}} {}", self.device.name, gas)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(water) = self.device.water_total {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"water_total_m3{{name=\"{}\"}} {}",
|
||||||
|
self.device.name, water
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ impl MiTempDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_prometheus(&self) -> impl Display + '_ {
|
pub fn format_open_metrics(&self) -> impl Display + '_ {
|
||||||
MitempFormatter { device: self }
|
MitempFormatter { device: self }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
|
mod dsmr;
|
||||||
mod mitemp;
|
mod mitemp;
|
||||||
mod rf;
|
mod rf;
|
||||||
|
|
||||||
use color_eyre::{Report, Result, eyre::WrapErr};
|
use color_eyre::{Report, Result, eyre::WrapErr};
|
||||||
|
pub use dsmr::{DsmrMessageType, DsmrState};
|
||||||
use jzon::JsonValue;
|
use jzon::JsonValue;
|
||||||
pub use mitemp::MiTempDevice;
|
pub use mitemp::MiTempDevice;
|
||||||
pub use rf::{RfDeviceId, TempState};
|
pub use rf::{RfDeviceId, TempState};
|
||||||
|
|
@ -75,7 +77,10 @@ impl DeviceStates {
|
||||||
|
|
||||||
pub fn update_dsmr(&mut self, device: Device, ty: DsmrMessageType, payload: &str) {
|
pub fn update_dsmr(&mut self, device: Device, ty: DsmrMessageType, payload: &str) {
|
||||||
if let Ok(value) = payload.parse() {
|
if let Ok(value) = payload.parse() {
|
||||||
let state = self.dsmr_devices.entry(device).or_default();
|
let state = self
|
||||||
|
.dsmr_devices
|
||||||
|
.entry(device)
|
||||||
|
.or_insert_with_key(|device| DsmrState::new(device.hostname.clone()));
|
||||||
match ty {
|
match ty {
|
||||||
DsmrMessageType::Water => state.water_total = Some(value),
|
DsmrMessageType::Water => state.water_total = Some(value),
|
||||||
DsmrMessageType::Gas => state.gas_total = Some(value),
|
DsmrMessageType::Gas => state.gas_total = Some(value),
|
||||||
|
|
@ -230,37 +235,6 @@ impl Default for DeviceState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum DsmrMessageType {
|
|
||||||
Water,
|
|
||||||
Gas,
|
|
||||||
Energy1,
|
|
||||||
Energy2,
|
|
||||||
Power,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DsmrState {
|
|
||||||
pub power: Option<f32>,
|
|
||||||
pub power_total_tariff_1: Option<f32>,
|
|
||||||
pub power_total_tariff_2: Option<f32>,
|
|
||||||
pub gas_total: Option<f32>,
|
|
||||||
pub water_total: Option<f32>,
|
|
||||||
pub last_seen: Instant,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for DsmrState {
|
|
||||||
fn default() -> Self {
|
|
||||||
DsmrState {
|
|
||||||
power: None,
|
|
||||||
power_total_tariff_1: None,
|
|
||||||
power_total_tariff_2: None,
|
|
||||||
gas_total: None,
|
|
||||||
water_total: None,
|
|
||||||
last_seen: Instant::now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeviceState {
|
impl DeviceState {
|
||||||
pub fn update(&mut self, json: JsonValue) {
|
pub fn update(&mut self, json: JsonValue) {
|
||||||
self.last_seen = Instant::now();
|
self.last_seen = Instant::now();
|
||||||
|
|
@ -422,52 +396,6 @@ pub fn format_device_state<W: Write>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_dsmr_state<W: Write>(mut writer: W, device: &str, state: &DsmrState) -> fmt::Result {
|
|
||||||
let power_total = state.power_total_tariff_1.unwrap_or_default()
|
|
||||||
+ state.power_total_tariff_2.unwrap_or_default();
|
|
||||||
if power_total > 0.0 {
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
"power_total_kwh{{name=\"{}\"}} {}",
|
|
||||||
device, power_total
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(power) = state.power_total_tariff_1 {
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
"power_total_low_kwh{{name=\"{}\"}} {}",
|
|
||||||
device, power
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(power) = state.power_total_tariff_2 {
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
"power_total_high_kwh{{name=\"{}\"}} {}",
|
|
||||||
device, power
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(power) = state.power {
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
"power_watts{{name=\"{}\"}} {}",
|
|
||||||
device,
|
|
||||||
power * 1000.0
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(gas) = state.gas_total {
|
|
||||||
writeln!(writer, "gas_total_m3{{name=\"{}\"}} {}", device, gas)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(water) = state.water_total {
|
|
||||||
writeln!(writer, "water_total_m3{{name=\"{}\"}} {}", device, water)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stores the 6 byte address used to identify Bluetooth devices.
|
/// Stores the 6 byte address used to identify Bluetooth devices.
|
||||||
#[derive(Copy, Clone, Hash, Eq, PartialEq, Default, Ord, PartialOrd)]
|
#[derive(Copy, Clone, Hash, Eq, PartialEq, Default, Ord, PartialOrd)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ impl TempState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_prometheus(&self) -> impl Display + '_ {
|
pub fn format_open_metrics(&self) -> impl Display + '_ {
|
||||||
TempFormatter { device: self }
|
TempFormatter { device: self }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
13
src/main.rs
13
src/main.rs
|
|
@ -4,7 +4,7 @@ mod mqtt;
|
||||||
mod topic;
|
mod topic;
|
||||||
|
|
||||||
use crate::config::{Config, ListenConfig};
|
use crate::config::{Config, ListenConfig};
|
||||||
use crate::device::{Device, DeviceStates, format_device_state, format_dsmr_state};
|
use crate::device::{Device, DeviceStates, format_device_state};
|
||||||
use crate::mqtt::mqtt_stream;
|
use crate::mqtt::mqtt_stream;
|
||||||
use crate::topic::Topic;
|
use crate::topic::Topic;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
@ -81,14 +81,17 @@ async fn serve(device_states: Arc<Mutex<DeviceStates>>, listen: ListenConfig) {
|
||||||
for (device, state) in state.devices() {
|
for (device, state) in state.devices() {
|
||||||
format_device_state(&mut response, device, state).unwrap();
|
format_device_state(&mut response, device, state).unwrap();
|
||||||
}
|
}
|
||||||
for (device, state) in state.dsmr_devices() {
|
for (_, state) in state.dsmr_devices() {
|
||||||
format_dsmr_state(&mut response, device.hostname.as_str(), state).unwrap();
|
write!(&mut response, "{}", state.format_open_metrics())
|
||||||
|
.expect("formatting failed");
|
||||||
}
|
}
|
||||||
for (_, state) in state.mi_temp() {
|
for (_, state) in state.mi_temp() {
|
||||||
write!(&mut response, "{}", state.format_prometheus()).expect("formatting failed");
|
write!(&mut response, "{}", state.format_open_metrics())
|
||||||
|
.expect("formatting failed");
|
||||||
}
|
}
|
||||||
for (_, state) in state.rf_temp() {
|
for (_, state) in state.rf_temp() {
|
||||||
write!(&mut response, "{}", state.format_prometheus()).expect("formatting failed");
|
write!(&mut response, "{}", state.format_open_metrics())
|
||||||
|
.expect("formatting failed");
|
||||||
}
|
}
|
||||||
response
|
response
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue