mirror of
https://codeberg.org/icewind/taspromto.git
synced 2026-08-02 12:14:45 +02:00
cleanup tasmota formatting
This commit is contained in:
parent
74463cc56e
commit
7955380859
3 changed files with 398 additions and 373 deletions
|
|
@ -1,11 +1,13 @@
|
|||
mod dsmr;
|
||||
mod mitemp;
|
||||
mod rf;
|
||||
mod tasmota;
|
||||
|
||||
use color_eyre::{Report, Result, eyre::WrapErr};
|
||||
pub use dsmr::{DsmrMessageType, DsmrState};
|
||||
use jzon::JsonValue;
|
||||
pub use mitemp::MiTempDevice;
|
||||
use rf::parse_rf_payload;
|
||||
pub use rf::{RfDeviceId, TempState};
|
||||
use rumqttc::{AsyncClient, QoS};
|
||||
use serde::de::Error;
|
||||
|
|
@ -13,12 +15,11 @@ use serde::{Deserialize, Deserializer};
|
|||
use std::borrow::Cow;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{self, Debug, Display, Formatter, Write};
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
use std::time::Instant;
|
||||
pub use tasmota::DeviceState;
|
||||
use tokio::task::spawn;
|
||||
|
||||
use crate::device::rf::parse_rf_payload;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DeviceStates {
|
||||
pub mi_temp_names: BTreeMap<BDAddr, String>,
|
||||
|
|
@ -52,7 +53,10 @@ impl DeviceStates {
|
|||
}
|
||||
|
||||
pub fn update(&mut self, device: Device, json: JsonValue) {
|
||||
let device = self.devices.entry(device).or_default();
|
||||
let device = self
|
||||
.devices
|
||||
.entry(device)
|
||||
.or_insert_with_key(|device| DeviceState::new(device.hostname.clone()));
|
||||
|
||||
for (key, value) in json.entries() {
|
||||
if let Some(addr) = key.strip_prefix("MJ_HT_V1") {
|
||||
|
|
@ -196,206 +200,6 @@ impl Device {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeviceState {
|
||||
pub state: Option<bool>,
|
||||
pub name: String,
|
||||
pub power_watts: Option<f32>,
|
||||
pub power_yesterday: Option<f32>,
|
||||
pub power_today: Option<f32>,
|
||||
pub power_total: Option<f32>,
|
||||
pub power_total_low: Option<f32>,
|
||||
pub power_total_high: Option<f32>,
|
||||
pub gas_total: Option<f32>,
|
||||
pub co2: Option<f32>,
|
||||
pub pms_state: Option<PMSState>,
|
||||
pub last_seen: Instant,
|
||||
pub firmware: String,
|
||||
pub version: f32,
|
||||
}
|
||||
|
||||
impl Default for DeviceState {
|
||||
fn default() -> Self {
|
||||
DeviceState {
|
||||
state: Default::default(),
|
||||
name: Default::default(),
|
||||
power_watts: Default::default(),
|
||||
power_yesterday: Default::default(),
|
||||
power_today: Default::default(),
|
||||
power_total: Default::default(),
|
||||
power_total_low: Default::default(),
|
||||
power_total_high: Default::default(),
|
||||
gas_total: Default::default(),
|
||||
co2: Default::default(),
|
||||
pms_state: Default::default(),
|
||||
last_seen: Instant::now(),
|
||||
firmware: Default::default(),
|
||||
version: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceState {
|
||||
pub fn update(&mut self, json: JsonValue) {
|
||||
self.last_seen = Instant::now();
|
||||
|
||||
if json["DeviceName"].is_string() && !json["DeviceName"].is_empty() {
|
||||
self.name = json["DeviceName"].to_string();
|
||||
}
|
||||
if json["POWER"].is_string() && !json["POWER"].is_empty() {
|
||||
self.state = Some(json["POWER"] == "ON");
|
||||
}
|
||||
if let Some(power) = json["ENERGY"]["Power"].as_number().map(f32::from) {
|
||||
self.power_watts = Some(power);
|
||||
}
|
||||
if let Some(yesterday) = json["ENERGY"]["Yesterday"].as_number().map(f32::from) {
|
||||
self.power_yesterday = Some(yesterday);
|
||||
}
|
||||
if let Some(today) = json["ENERGY"]["Today"].as_number().map(f32::from) {
|
||||
self.power_today = Some(today);
|
||||
}
|
||||
if let Some(co2) = json["MHZ19B"]["CarbonDioxide"].as_number().map(f32::from) {
|
||||
if co2 > 1.0 {
|
||||
self.co2 = Some(co2);
|
||||
}
|
||||
}
|
||||
if let Some(power) = json["OBIS"]["Power"].as_number().map(f32::from) {
|
||||
self.power_watts = Some(power);
|
||||
}
|
||||
if let Some(total) = json["OBIS"]["Total"].as_number().map(f32::from) {
|
||||
self.power_total = Some(total);
|
||||
}
|
||||
if let Some(total) = json["OBIS"]["Total_high"].as_number().map(f32::from) {
|
||||
self.power_total_high = Some(total);
|
||||
}
|
||||
if let Some(total) = json["OBIS"]["Total_low"].as_number().map(f32::from) {
|
||||
self.power_total_low = Some(total);
|
||||
}
|
||||
if let Some(gas) = json["OBIS"]["Gas_total"].as_number().map(f32::from) {
|
||||
self.gas_total = Some(gas);
|
||||
}
|
||||
|
||||
if let Some(version) = json["StatusFWR"]["Version"].as_str() {
|
||||
self.firmware = version.into();
|
||||
if let Some(version) = version
|
||||
.rfind('.')
|
||||
.map(|index| &version[0..index])
|
||||
.and_then(|s| s.parse().ok())
|
||||
{
|
||||
self.version = version
|
||||
}
|
||||
}
|
||||
|
||||
if json["PMS5003"].is_object() {
|
||||
let pms = self.pms_state.get_or_insert(PMSState::default());
|
||||
pms.update(&json["PMS5003"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_device_state<W: Write>(
|
||||
mut writer: W,
|
||||
device: &Device,
|
||||
state: &DeviceState,
|
||||
) -> fmt::Result {
|
||||
if state.name.is_empty() {
|
||||
println!("{} has no name set, skipping", device.hostname);
|
||||
return Ok(());
|
||||
}
|
||||
writeln!(
|
||||
writer,
|
||||
"tasmota_online{{tasmota_id=\"{}\", name=\"{}\"}} 1",
|
||||
device.hostname, state.name
|
||||
)?;
|
||||
if let Some(switch_state) = state.state {
|
||||
writeln!(
|
||||
writer,
|
||||
"switch_state{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname,
|
||||
state.name,
|
||||
if switch_state { 1 } else { 0 }
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_watts) = state.power_watts {
|
||||
writeln!(
|
||||
writer,
|
||||
"power_watts{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, state.name, power_watts
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_yesterday) = state.power_yesterday {
|
||||
writeln!(
|
||||
writer,
|
||||
"power_yesterday_kwh{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, state.name, power_yesterday
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_today) = state.power_today {
|
||||
writeln!(
|
||||
writer,
|
||||
"power_today_kwh{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, state.name, power_today
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_total) = state.power_total {
|
||||
writeln!(
|
||||
writer,
|
||||
"power_total_kwh{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, state.name, power_total
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_total) = state.power_total_high {
|
||||
writeln!(
|
||||
writer,
|
||||
"power_total_high_kwh{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, state.name, power_total
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_total) = state.power_total_low {
|
||||
writeln!(
|
||||
writer,
|
||||
"power_total_low_kwh{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, state.name, power_total
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(gas_total) = state.gas_total {
|
||||
writeln!(
|
||||
writer,
|
||||
"gas_total_m3{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, state.name, gas_total
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(co2) = state.co2 {
|
||||
writeln!(
|
||||
writer,
|
||||
"sensor_co2{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, state.name, co2
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(pms) = state.pms_state.as_ref() {
|
||||
format_pms_state(&mut writer, device, state, pms)?;
|
||||
}
|
||||
|
||||
if !state.firmware.is_empty() {
|
||||
writeln!(
|
||||
writer,
|
||||
r#"tasmota_version{{tasmota_id="{}", name="{}", firmware="{}", version="{}"}} 1"#,
|
||||
device.hostname, state.name, state.firmware, state.version
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Stores the 6 byte address used to identify Bluetooth devices.
|
||||
#[derive(Copy, Clone, Hash, Eq, PartialEq, Default, Ord, PartialOrd)]
|
||||
#[repr(C)]
|
||||
|
|
@ -450,169 +254,3 @@ impl Debug for BDAddr {
|
|||
(self as &dyn Display).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
//"PMS5003":{"CF1":6,"CF2.5":8,"CF10":8,"PM1":6,"PM2.5":8,"PM10":8,"PB0.3":0,"PB0.5":0,"PB1":0,"PB2.5":0,"PB5":0,"PB10":0}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PMSState {
|
||||
cf1: u16,
|
||||
cf2_5: u16,
|
||||
cf10: u16,
|
||||
pm1: u16,
|
||||
pm2_5: u16,
|
||||
pm10: u16,
|
||||
pb0_3: u16,
|
||||
pb0_5: u16,
|
||||
pb1: u16,
|
||||
pb2_5: u16,
|
||||
pb5: u16,
|
||||
pb10: u16,
|
||||
}
|
||||
|
||||
impl PMSState {
|
||||
pub fn update(&mut self, json: &JsonValue) {
|
||||
if let Some(val) = json["CF1"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.cf1 = val;
|
||||
}
|
||||
if let Some(val) = json["CF2.5"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.cf2_5 = val;
|
||||
}
|
||||
if let Some(val) = json["CF10"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.cf10 = val;
|
||||
}
|
||||
if let Some(val) = json["PM1"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pm1 = val;
|
||||
}
|
||||
if let Some(val) = json["PM2.5"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pm2_5 = val;
|
||||
}
|
||||
if let Some(val) = json["PM10"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pm10 = val;
|
||||
}
|
||||
if let Some(val) = json["PB0.3"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb0_3 = val;
|
||||
}
|
||||
if let Some(val) = json["PB0.5"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb0_5 = val;
|
||||
}
|
||||
if let Some(val) = json["PB1"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb1 = val;
|
||||
}
|
||||
if let Some(val) = json["PB2.5"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb2_5 = val;
|
||||
}
|
||||
if let Some(val) = json["PB5"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb5 = val;
|
||||
}
|
||||
if let Some(val) = json["PB10"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb10 = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_pms_state<W: Write>(
|
||||
mut writer: W,
|
||||
device: &Device,
|
||||
device_state: &DeviceState,
|
||||
state: &PMSState,
|
||||
) -> fmt::Result {
|
||||
let name = &device_state.name;
|
||||
|
||||
writeln!(
|
||||
writer,
|
||||
"cf1{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.cf1
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"cf2_5{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.cf2_5
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"cf10{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.cf10
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"pm1{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.pm1
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"pm2_5{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.pm2_5
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"pm10{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.pm10
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"pb0_3{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.pb0_3
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"pb0_5{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.pb0_5
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"pb1{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.pb1
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"pb2_5{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.pb2_5
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"pb5{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.pb5
|
||||
)?;
|
||||
writeln!(
|
||||
writer,
|
||||
"pb10{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
device.hostname, name, state.pb10
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
386
src/device/tasmota.rs
Normal file
386
src/device/tasmota.rs
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
use std::{
|
||||
fmt::{self, Display},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use jzon::JsonValue;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeviceState {
|
||||
pub state: Option<bool>,
|
||||
pub name: String,
|
||||
pub hostname: String,
|
||||
pub power_watts: Option<f32>,
|
||||
pub power_yesterday: Option<f32>,
|
||||
pub power_today: Option<f32>,
|
||||
pub power_total: Option<f32>,
|
||||
pub power_total_low: Option<f32>,
|
||||
pub power_total_high: Option<f32>,
|
||||
pub gas_total: Option<f32>,
|
||||
pub co2: Option<f32>,
|
||||
pub pms_state: Option<PMSState>,
|
||||
pub last_seen: Instant,
|
||||
pub firmware: String,
|
||||
pub version: f32,
|
||||
}
|
||||
|
||||
impl DeviceState {
|
||||
pub fn new(hostname: String) -> Self {
|
||||
DeviceState {
|
||||
hostname,
|
||||
state: Default::default(),
|
||||
name: Default::default(),
|
||||
power_watts: Default::default(),
|
||||
power_yesterday: Default::default(),
|
||||
power_today: Default::default(),
|
||||
power_total: Default::default(),
|
||||
power_total_low: Default::default(),
|
||||
power_total_high: Default::default(),
|
||||
gas_total: Default::default(),
|
||||
co2: Default::default(),
|
||||
pms_state: Default::default(),
|
||||
last_seen: Instant::now(),
|
||||
firmware: Default::default(),
|
||||
version: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, json: JsonValue) {
|
||||
self.last_seen = Instant::now();
|
||||
|
||||
if json["DeviceName"].is_string() && !json["DeviceName"].is_empty() {
|
||||
self.name = json["DeviceName"].to_string();
|
||||
}
|
||||
if json["POWER"].is_string() && !json["POWER"].is_empty() {
|
||||
self.state = Some(json["POWER"] == "ON");
|
||||
}
|
||||
if let Some(power) = json["ENERGY"]["Power"].as_number().map(f32::from) {
|
||||
self.power_watts = Some(power);
|
||||
}
|
||||
if let Some(yesterday) = json["ENERGY"]["Yesterday"].as_number().map(f32::from) {
|
||||
self.power_yesterday = Some(yesterday);
|
||||
}
|
||||
if let Some(today) = json["ENERGY"]["Today"].as_number().map(f32::from) {
|
||||
self.power_today = Some(today);
|
||||
}
|
||||
if let Some(co2) = json["MHZ19B"]["CarbonDioxide"].as_number().map(f32::from) {
|
||||
if co2 > 1.0 {
|
||||
self.co2 = Some(co2);
|
||||
}
|
||||
}
|
||||
if let Some(power) = json["OBIS"]["Power"].as_number().map(f32::from) {
|
||||
self.power_watts = Some(power);
|
||||
}
|
||||
if let Some(total) = json["OBIS"]["Total"].as_number().map(f32::from) {
|
||||
self.power_total = Some(total);
|
||||
}
|
||||
if let Some(total) = json["OBIS"]["Total_high"].as_number().map(f32::from) {
|
||||
self.power_total_high = Some(total);
|
||||
}
|
||||
if let Some(total) = json["OBIS"]["Total_low"].as_number().map(f32::from) {
|
||||
self.power_total_low = Some(total);
|
||||
}
|
||||
if let Some(gas) = json["OBIS"]["Gas_total"].as_number().map(f32::from) {
|
||||
self.gas_total = Some(gas);
|
||||
}
|
||||
|
||||
if let Some(version) = json["StatusFWR"]["Version"].as_str() {
|
||||
self.firmware = version.into();
|
||||
if let Some(version) = version
|
||||
.rfind('.')
|
||||
.map(|index| &version[0..index])
|
||||
.and_then(|s| s.parse().ok())
|
||||
{
|
||||
self.version = version
|
||||
}
|
||||
}
|
||||
|
||||
if json["PMS5003"].is_object() {
|
||||
let pms = self.pms_state.get_or_insert(PMSState::default());
|
||||
pms.update(&json["PMS5003"]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_open_metrics(&self) -> impl Display + '_ {
|
||||
TasmotaFormatter { device: self }
|
||||
}
|
||||
}
|
||||
|
||||
struct TasmotaFormatter<'a> {
|
||||
device: &'a DeviceState,
|
||||
}
|
||||
|
||||
impl Display for TasmotaFormatter<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.device.name.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
writeln!(
|
||||
f,
|
||||
"tasmota_online{{tasmota_id=\"{}\", name=\"{}\"}} 1",
|
||||
self.device.hostname, self.device.name
|
||||
)?;
|
||||
if let Some(switch_state) = self.device.state {
|
||||
writeln!(
|
||||
f,
|
||||
"switch_state{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname,
|
||||
self.device.name,
|
||||
if switch_state { 1 } else { 0 }
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_watts) = self.device.power_watts {
|
||||
writeln!(
|
||||
f,
|
||||
"power_watts{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, self.device.name, power_watts
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_yesterday) = self.device.power_yesterday {
|
||||
writeln!(
|
||||
f,
|
||||
"power_yesterday_kwh{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, self.device.name, power_yesterday
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_today) = self.device.power_today {
|
||||
writeln!(
|
||||
f,
|
||||
"power_today_kwh{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, self.device.name, power_today
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_total) = self.device.power_total {
|
||||
writeln!(
|
||||
f,
|
||||
"power_total_kwh{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, self.device.name, power_total
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_total) = self.device.power_total_high {
|
||||
writeln!(
|
||||
f,
|
||||
"power_total_high_kwh{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, self.device.name, power_total
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(power_total) = self.device.power_total_low {
|
||||
writeln!(
|
||||
f,
|
||||
"power_total_low_kwh{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, self.device.name, power_total
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(gas_total) = self.device.gas_total {
|
||||
writeln!(
|
||||
f,
|
||||
"gas_total_m3{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, self.device.name, gas_total
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(co2) = self.device.co2 {
|
||||
writeln!(
|
||||
f,
|
||||
"sensor_co2{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, self.device.name, co2
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(pms) = self.device.pms_state.as_ref() {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
PmsFormatter {
|
||||
device: self.device,
|
||||
pms
|
||||
}
|
||||
)?;
|
||||
}
|
||||
|
||||
if !self.device.firmware.is_empty() {
|
||||
writeln!(
|
||||
f,
|
||||
r#"tasmota_version{{tasmota_id="{}", name="{}", firmware="{}", version="{}"}} 1"#,
|
||||
self.device.hostname, self.device.name, self.device.firmware, self.device.version
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//"PMS5003":{"CF1":6,"CF2.5":8,"CF10":8,"PM1":6,"PM2.5":8,"PM10":8,"PB0.3":0,"PB0.5":0,"PB1":0,"PB2.5":0,"PB5":0,"PB10":0}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PMSState {
|
||||
cf1: u16,
|
||||
cf2_5: u16,
|
||||
cf10: u16,
|
||||
pm1: u16,
|
||||
pm2_5: u16,
|
||||
pm10: u16,
|
||||
pb0_3: u16,
|
||||
pb0_5: u16,
|
||||
pb1: u16,
|
||||
pb2_5: u16,
|
||||
pb5: u16,
|
||||
pb10: u16,
|
||||
}
|
||||
|
||||
impl PMSState {
|
||||
pub fn update(&mut self, json: &JsonValue) {
|
||||
if let Some(val) = json["CF1"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.cf1 = val;
|
||||
}
|
||||
if let Some(val) = json["CF2.5"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.cf2_5 = val;
|
||||
}
|
||||
if let Some(val) = json["CF10"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.cf10 = val;
|
||||
}
|
||||
if let Some(val) = json["PM1"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pm1 = val;
|
||||
}
|
||||
if let Some(val) = json["PM2.5"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pm2_5 = val;
|
||||
}
|
||||
if let Some(val) = json["PM10"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pm10 = val;
|
||||
}
|
||||
if let Some(val) = json["PB0.3"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb0_3 = val;
|
||||
}
|
||||
if let Some(val) = json["PB0.5"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb0_5 = val;
|
||||
}
|
||||
if let Some(val) = json["PB1"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb1 = val;
|
||||
}
|
||||
if let Some(val) = json["PB2.5"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb2_5 = val;
|
||||
}
|
||||
if let Some(val) = json["PB5"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb5 = val;
|
||||
}
|
||||
if let Some(val) = json["PB10"]
|
||||
.as_number()
|
||||
.and_then(|num| u16::try_from(num).ok())
|
||||
{
|
||||
self.pb10 = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PmsFormatter<'a> {
|
||||
pms: &'a PMSState,
|
||||
device: &'a DeviceState,
|
||||
}
|
||||
|
||||
impl Display for PmsFormatter<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let name = &self.device.name;
|
||||
|
||||
writeln!(
|
||||
f,
|
||||
"cf1{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.cf1
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"cf2_5{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.cf2_5
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"cf10{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.cf10
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"pm1{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.pm1
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"pm2_5{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.pm2_5
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"pm10{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.pm10
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"pb0_3{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.pb0_3
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"pb0_5{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.pb0_5
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"pb1{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.pb1
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"pb2_5{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.pb2_5
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"pb5{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.pb5
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"pb10{{tasmota_id=\"{}\", name=\"{}\"}} {}",
|
||||
self.device.hostname, name, self.pms.pb10
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue