This commit is contained in:
Robin Appelman 2024-01-27 17:14:44 +01:00
commit 6a31d536bf
3 changed files with 22 additions and 5 deletions

View file

@ -8,7 +8,7 @@ rust-version = "1.70.0"
[dependencies] [dependencies]
rumqttc = { version = "0.23.0", features = ["use-rustls"] } rumqttc = { version = "0.23.0", features = ["use-rustls"] }
thiserror = "1.0.56" thiserror = "1.0.56"
tokio = { version = "1.35.1", features = ["rt-multi-thread", "sync"] } tokio = { version = "1.35.1", features = ["sync"] }
tracing = "0.1.40" tracing = "0.1.40"
async-stream = "0.3.5" async-stream = "0.3.5"
tokio-stream = { version = "0.1.14", features = ["sync"] } tokio-stream = { version = "0.1.14", features = ["sync"] }
@ -21,4 +21,5 @@ md-5 = "0.10.6"
[dev-dependencies] [dev-dependencies]
clap = { version = "4.4.18", features = ["derive"] } clap = { version = "4.4.18", features = ["derive"] }
tokio = { version = "1.35.1", features = ["rt-multi-thread", "macros"] }
hex_fmt = "0.3.0" hex_fmt = "0.3.0"

View file

@ -4,6 +4,7 @@ use crate::Result;
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
use md5::{Digest, Md5}; use md5::{Digest, Md5};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::debug;
#[derive(Serialize)] #[derive(Serialize)]
struct SendDownloadPayload<'a> { struct SendDownloadPayload<'a> {
@ -68,6 +69,7 @@ pub async fn download_config(
let msg = rx.recv().await.unwrap(); let msg = rx.recv().await.unwrap();
if let Ok(response) = serde_json::from_slice::<DownloadResponse>(msg.payload.as_ref()) { if let Ok(response) = serde_json::from_slice::<DownloadResponse>(msg.payload.as_ref()) {
debug!(message = ?response, "processing download status message");
if let Some(status) = response.file_download { if let Some(status) = response.file_download {
match status { match status {
"Started" => { "Started" => {
@ -111,6 +113,7 @@ pub async fn download_config(
continue; continue;
} }
} else { } else {
debug!(size = msg.payload.len(), "processing download chunk");
state.data.extend(msg.payload); state.data.extend(msg.payload);
} }

View file

@ -11,6 +11,7 @@ use rumqttc::MqttOptions;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::Deserialize; use serde::Deserialize;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::fmt::Debug;
use std::net::IpAddr; use std::net::IpAddr;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -20,6 +21,7 @@ use tokio::sync::broadcast::{channel, Sender};
use tokio::time::timeout; use tokio::time::timeout;
use tokio_stream::wrappers::BroadcastStream; use tokio_stream::wrappers::BroadcastStream;
use tokio_stream::{Stream, StreamExt}; use tokio_stream::{Stream, StreamExt};
use tracing::debug;
pub struct TasmotaClient { pub struct TasmotaClient {
mqtt: MqttHelper, mqtt: MqttHelper,
@ -58,6 +60,11 @@ impl TasmotaClient {
continue; continue;
}; };
debug!(
message = payload,
device = device,
"processing discovery message"
);
match payload { match payload {
"Online" => { "Online" => {
if edit_devices.lock().unwrap().insert(device.into()) { if edit_devices.lock().unwrap().insert(device.into()) {
@ -84,7 +91,7 @@ impl TasmotaClient {
/// Set the timeout used for one-show commands /// Set the timeout used for one-show commands
/// ///
/// The default timeout is 1 seccond /// The default timeout is 1 second
pub fn set_timeout(&mut self, timeout: Duration) { pub fn set_timeout(&mut self, timeout: Duration) {
self.timeout = timeout; self.timeout = timeout;
} }
@ -92,6 +99,7 @@ impl TasmotaClient {
/// Download the config backup from a device /// Download the config backup from a device
/// ///
/// The password is the mqtt password used by the device, which might be different from the mqtt password used by this client /// The password is the mqtt password used by the device, which might be different from the mqtt password used by this client
#[tracing::instrument(skip(self))]
pub async fn download_config(&self, client: &str, password: &str) -> Result<DownloadedFile> { pub async fn download_config(&self, client: &str, password: &str) -> Result<DownloadedFile> {
download_config(&self.mqtt, client, password).await download_config(&self.mqtt, client, password).await
} }
@ -116,7 +124,8 @@ impl TasmotaClient {
} }
/// Send a command that expect a single reply message /// Send a command that expect a single reply message
pub async fn command<T: DeserializeOwned>( #[tracing::instrument(skip(self))]
pub async fn command<T: DeserializeOwned + Debug>(
&self, &self,
device: &str, device: &str,
command: &str, command: &str,
@ -142,8 +151,10 @@ impl TasmotaClient {
.map_err(|_| Error::Timeout)? .map_err(|_| Error::Timeout)?
} }
/// Get the ip address for the device
#[tracing::instrument(skip(self))]
pub async fn device_ip(&self, device: &str) -> Result<IpAddr> { pub async fn device_ip(&self, device: &str) -> Result<IpAddr> {
#[derive(Deserialize)] #[derive(Deserialize, Debug)]
struct IpAddressResponse { struct IpAddressResponse {
#[serde(rename = "IPAddress1")] #[serde(rename = "IPAddress1")]
ip_address_1: String, ip_address_1: String,
@ -164,8 +175,10 @@ impl TasmotaClient {
Ok(ip) Ok(ip)
} }
/// Get the name for the device
#[tracing::instrument(skip(self))]
pub async fn device_name(&self, device: &str) -> Result<String> { pub async fn device_name(&self, device: &str) -> Result<String> {
#[derive(Deserialize)] #[derive(Deserialize, Debug)]
struct NameResponse { struct NameResponse {
#[serde(rename = "DeviceName")] #[serde(rename = "DeviceName")]
device_name: String, device_name: String,