dont set state to 0 if not in update and improve startup reliability

This commit is contained in:
Robin Appelman 2020-12-14 18:01:09 +01:00
commit c4c2a48179
2 changed files with 56 additions and 32 deletions

View file

@ -1,3 +1,5 @@
use json::JsonValue;
use std::convert::TryFrom;
use std::fmt::Write; use std::fmt::Write;
#[derive(Debug, Eq, PartialEq, Clone, Hash)] #[derive(Debug, Eq, PartialEq, Clone, Hash)]
@ -21,6 +23,32 @@ pub struct DeviceState {
pub power_today: Option<f32>, pub power_today: Option<f32>,
} }
impl DeviceState {
pub fn update(&mut self, json: JsonValue) {
if json["DeviceName"].is_string() && !json["DeviceName"].is_empty() {
self.name = json["DeviceName"].to_string();
}
if let Some(power) = json["ENERGY"]["Power"]
.as_number()
.and_then(|num| f32::try_from(num).ok())
{
self.power_watts = Some(power);
}
if let Some(yesterday) = json["ENERGY"]["Yesterday"]
.as_number()
.and_then(|num| f32::try_from(num).ok())
{
self.power_yesterday = Some(yesterday);
}
if let Some(today) = json["ENERGY"]["Today"]
.as_number()
.and_then(|num| f32::try_from(num).ok())
{
self.power_today = Some(today);
}
}
}
pub fn format_device_state<W: Write>( pub fn format_device_state<W: Write>(
mut writer: W, mut writer: W,
device: &Device, device: &Device,

View file

@ -11,7 +11,6 @@ use color_eyre::{eyre::WrapErr, Result};
use dashmap::DashMap; use dashmap::DashMap;
use pin_utils::pin_mut; use pin_utils::pin_mut;
use rumqttc::{MqttOptions, QoS}; use rumqttc::{MqttOptions, QoS};
use std::convert::TryFrom;
use std::sync::Arc; use std::sync::Arc;
use tokio::stream::StreamExt; use tokio::stream::StreamExt;
use tokio::time::Duration; use tokio::time::Duration;
@ -79,22 +78,31 @@ async fn mqtt_client(host: &str, port: u16, device_states: DeviceStates) -> Resu
match topic { match topic {
Topic::LWT(device) => { Topic::LWT(device) => {
// on discovery, ask the device for it's power state and name // on discovery, ask the device for it's power state and name
client let send_client = client.clone();
.publish( tokio::task::spawn(async move {
device.get_topic("cmnd", "POWER"), if let Err(e) = send_client
QoS::AtMostOnce, .publish(
false, device.get_topic("cmnd", "POWER"),
"", QoS::AtMostOnce,
) false,
.await?; "",
client )
.publish( .await
device.get_topic("cmnd", "DeviceName"), {
QoS::AtMostOnce, eprintln!("Failed to ask for power state: {:#}", e);
false, }
"", if let Err(e) = send_client
) .publish(
.await?; device.get_topic("cmnd", "DeviceName"),
QoS::AtMostOnce,
false,
"",
)
.await
{
eprintln!("Failed to ask for device name: {:#}", e);
}
});
} }
Topic::Power(device) => { Topic::Power(device) => {
let state = message.payload.as_ref() == b"ON"; let state = message.payload.as_ref() == b"ON";
@ -102,29 +110,17 @@ async fn mqtt_client(host: &str, port: u16, device_states: DeviceStates) -> Resu
} }
Topic::Result(device) => { Topic::Result(device) => {
let payload = std::str::from_utf8(message.payload.as_ref()).unwrap_or_default(); let payload = std::str::from_utf8(message.payload.as_ref()).unwrap_or_default();
dbg!(payload);
if let Ok(json) = json::parse(payload) { if let Ok(json) = json::parse(payload) {
let mut device_state = device_states.entry(device).or_default(); let mut device_state = device_states.entry(device).or_default();
if json["DeviceName"].is_string() { device_state.update(json);
let name = json["DeviceName"].to_string();
if !name.is_empty() {
device_state.name = name;
}
}
} }
} }
Topic::Sensor(device) => { Topic::Sensor(device) => {
let payload = std::str::from_utf8(message.payload.as_ref()).unwrap_or_default(); let payload = std::str::from_utf8(message.payload.as_ref()).unwrap_or_default();
if let Ok(json) = json::parse(payload) { if let Ok(json) = json::parse(payload) {
let mut device_state = device_states.entry(device).or_default(); let mut device_state = device_states.entry(device).or_default();
device_state.power_watts = json["ENERGY"]["Power"] device_state.update(json);
.as_number()
.map(|num| f32::try_from(num).unwrap_or_default());
device_state.power_yesterday = json["ENERGY"]["Yesterday"]
.as_number()
.map(|num| f32::try_from(num).unwrap_or_default());
device_state.power_today = json["ENERGY"]["Today"]
.as_number()
.map(|num| f32::try_from(num).unwrap_or_default());
} }
} }
_ => {} _ => {}