track firmware versions

This commit is contained in:
Robin Appelman 2022-02-13 17:00:50 +01:00
commit d6acb68602
4 changed files with 26 additions and 12 deletions

View file

@ -100,6 +100,7 @@ pub struct DeviceState {
pub co2: Option<f32>,
pub pms_state: Option<PMSState>,
pub last_seen: Instant,
pub firmware: String,
}
impl Default for DeviceState {
@ -117,6 +118,7 @@ impl Default for DeviceState {
co2: Default::default(),
pms_state: Default::default(),
last_seen: Instant::now(),
firmware: Default::default(),
}
}
}
@ -188,6 +190,10 @@ impl DeviceState {
self.gas_total = Some(gas);
}
if let Some(version) = json["StatusFWR"]["Version"].as_str() {
self.firmware = version.into();
}
if json["PMS5003"].is_object() {
let pms = self.pms_state.get_or_insert(PMSState::default());
pms.update(&json["PMS5003"]);
@ -338,6 +344,14 @@ pub fn format_device_state<W: Write>(
format_pms_state(&mut writer, device, state, pms)?;
}
if !state.firmware.is_empty() {
writeln!(
writer,
"tasmota_version{{tasmota_id=\"{}\", name=\"{}\"}} {}",
device.hostname, state.name, state.firmware
)?;
}
Ok(())
}

View file

@ -78,13 +78,13 @@ async fn mqtt_loop(
}
}
async fn command(client: &AsyncClient, device: &Device, command: &str) -> Result<()> {
async fn command(client: &AsyncClient, device: &Device, command: &str, body: &str) -> Result<()> {
client
.publish(
device.get_topic("cmnd", command),
QoS::AtMostOnce,
false,
"",
body,
)
.await?;
Ok(())
@ -109,23 +109,19 @@ async fn mqtt_client<S: Stream<Item = Result<Publish>>>(
// on discovery, ask the device for it's power state and name
let send_client = client.clone();
spawn(async move {
if let Err(e) = command(&send_client, &device, "POWER").await {
if let Err(e) = command(&send_client, &device, "POWER", "").await {
eprintln!("Failed to ask for power state: {:#}", e);
}
if let Err(e) = command(&send_client, &device, "DeviceName").await {
if let Err(e) = command(&send_client, &device, "DeviceName", "").await {
eprintln!("Failed to ask for device name: {:#}", e);
}
if let Err(e) = command(&send_client, &device, "Status", "2").await {
eprintln!("Failed to ask for firmware state: {:#}", e);
}
});
}
Topic::Power(_) => {}
Topic::Result(device) => {
let payload = std::str::from_utf8(message.payload.as_ref()).unwrap_or_default();
if let Ok(json) = json::parse(payload) {
let mut device_states = device_states.lock().unwrap();
device_states.update(device, json);
}
}
Topic::Sensor(device) => {
Topic::Result(device) | Topic::Sensor(device) | Topic::Status(device) => {
let payload = std::str::from_utf8(message.payload.as_ref()).unwrap_or_default();
if let Ok(json) = json::parse(payload) {
let mut device_states = device_states.lock().unwrap();

View file

@ -11,6 +11,7 @@ pub async fn mqtt_stream(
client.subscribe("stat/+/POWER", QoS::AtMostOnce).await?;
client.subscribe("tele/+/SENSOR", QoS::AtMostOnce).await?;
client.subscribe("stat/+/RESULT", QoS::AtMostOnce).await?;
client.subscribe("stat/+/STATUS2", QoS::AtMostOnce).await?;
let stream = event_loop_to_stream(event_loop).filter_map(|event| match event {
Ok(Event::Incoming(Packet::Publish(message))) => Some(Ok(message)),

View file

@ -8,6 +8,7 @@ pub enum Topic {
Sensor(Device),
Result(Device),
Other(String),
Status(Device),
}
impl From<&str> for Topic {
@ -25,6 +26,8 @@ impl From<&str> for Topic {
("stat", "POWER") => Topic::Power(device),
("tele", "SENSOR") => Topic::Sensor(device),
("stat", "RESULT") => Topic::Result(device),
("stat", "STATUS") => Topic::Status(device),
("stat", "STATUS2") => Topic::Status(device),
_ => Topic::Other(raw.to_string()),
}
} else {