From 839c0a1c57c6a05254acf68b454e82ca0bfd5662 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Mon, 10 Apr 2023 01:29:48 +0200 Subject: [PATCH] Applied clippy rules --- .cargo/config.toml | 2 + google-home/src/device.rs | 8 ++-- google-home/src/fullfillment.rs | 26 ++++++------- google-home/src/request/execute.rs | 2 +- google-home/src/response/execute.rs | 9 ++++- google-home/src/response/query.rs | 12 ++++++ src/config.rs | 14 +++---- src/debug_bridge.rs | 4 +- src/devices.rs | 2 +- src/devices/kasa_outlet.rs | 18 ++++----- src/devices/wake_on_lan.rs | 2 +- src/error.rs | 14 +++++-- src/hue_bridge.rs | 4 +- src/light_sensor.rs | 2 +- src/main.rs | 59 ++++++++++++++++++++++++++++- src/ntfy.rs | 8 +++- src/presence.rs | 6 +-- 17 files changed, 139 insertions(+), 53 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..2f05654 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "x86_64-unknown-linux-gnu" diff --git a/google-home/src/device.rs b/google-home/src/device.rs index 1841c41..f3346b6 100644 --- a/google-home/src/device.rs +++ b/google-home/src/device.rs @@ -23,7 +23,7 @@ pub trait GoogleHomeDevice: AsOnOff + AsScene { fn sync(&self) -> response::sync::Device { let name = self.get_device_name(); - let mut device = response::sync::Device::new(&self.get_id(), &name.name, self.get_device_type()); + let mut device = response::sync::Device::new(self.get_id(), &name.name, self.get_device_type()); device.name = name; device.will_report_state = self.will_report_state(); @@ -49,7 +49,7 @@ pub trait GoogleHomeDevice: AsOnOff + AsScene { device.traits = traits; - return device; + device } fn query(&self) -> response::query::Device { @@ -65,7 +65,7 @@ pub trait GoogleHomeDevice: AsOnOff + AsScene { .ok(); } - return device; + device } fn execute(&mut self, command: &CommandType) -> Result<(), ErrorCode> { @@ -84,7 +84,7 @@ pub trait GoogleHomeDevice: AsOnOff + AsScene { }, } - return Ok(()); + Ok(()) } } diff --git a/google-home/src/fullfillment.rs b/google-home/src/fullfillment.rs index 5799d7f..861e3b8 100644 --- a/google-home/src/fullfillment.rs +++ b/google-home/src/fullfillment.rs @@ -21,16 +21,16 @@ impl GoogleHome { Self { user_id: user_id.into() } } - pub fn handle_request(&self, request: Request, mut devices: &mut HashMap<&str, &mut dyn GoogleHomeDevice>) -> Result { + pub fn handle_request(&self, request: Request, devices: &mut HashMap<&str, &mut dyn GoogleHomeDevice>) -> Result { // TODO: What do we do if we actually get more then one thing in the input array, right now // we only respond to the first thing let payload = request .inputs .into_iter() .map(|input| match input { - Intent::Sync => ResponsePayload::Sync(self.sync(&devices)), - Intent::Query(payload) => ResponsePayload::Query(self.query(payload, &devices)), - Intent::Execute(payload) => ResponsePayload::Execute(self.execute(payload, &mut devices)), + Intent::Sync => ResponsePayload::Sync(self.sync(devices)), + Intent::Query(payload) => ResponsePayload::Query(self.query(payload, devices)), + Intent::Execute(payload) => ResponsePayload::Execute(self.execute(payload, devices)), }).next(); payload @@ -45,7 +45,7 @@ impl GoogleHome { .map(|(_, device)| device.sync()) .collect::>(); - return resp_payload; + resp_payload } fn query(&self, payload: request::query::Payload, devices: &HashMap<&str, &mut dyn GoogleHomeDevice>) -> query::Payload { @@ -63,10 +63,10 @@ impl GoogleHome { device }, |device| device.query()); - return (id, device); + (id, device) }).collect(); - return resp_payload; + resp_payload } @@ -100,9 +100,9 @@ impl GoogleHome { // TODO: We only get one error not all errors if let Err(err) = results { - return (id, Err(err)); + (id, Err(err)) } else { - return (id, Ok(true)); + (id, Ok(true)) } }) }).for_each(|(id, state)| { @@ -126,7 +126,7 @@ impl GoogleHome { } }); - return resp_payload; + resp_payload } } @@ -157,11 +157,11 @@ mod tests { name.add_default_name("Outlet"); name.add_nickname("Nightlight"); - return name; + name } fn get_id(&self) -> &str { - return &self.name; + &self.name } fn is_online(&self) -> bool { @@ -212,7 +212,7 @@ mod tests { } fn get_id(&self) -> &str { - return "living/party_mode"; + "living/party_mode" } fn is_online(&self) -> bool { diff --git a/google-home/src/request/execute.rs b/google-home/src/request/execute.rs index 92b1668..5245252 100644 --- a/google-home/src/request/execute.rs +++ b/google-home/src/request/execute.rs @@ -96,7 +96,7 @@ mod tests { assert_eq!(payload.commands[0].devices[1].id, "456"); assert_eq!(payload.commands[0].execution.len(), 1); match payload.commands[0].execution[0] { - CommandType::OnOff{on} => assert_eq!(on, true), + CommandType::OnOff{on} => assert!(on), _ => panic!("Expected OnOff") } }, diff --git a/google-home/src/response/execute.rs b/google-home/src/response/execute.rs index d517b29..0861781 100644 --- a/google-home/src/response/execute.rs +++ b/google-home/src/response/execute.rs @@ -24,6 +24,12 @@ impl Payload { } } +impl Default for Payload { + fn default() -> Self { + Self::new() + } +} + #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct Command { @@ -78,8 +84,7 @@ mod tests { fn serialize() { let mut execute_resp = Payload::new(); - let mut state = State::default(); - state.on = Some(true); + let state = State { on: Some(true) }; let mut command = Command::new(Status::Success); command.states = Some(States { online: true, diff --git a/google-home/src/response/query.rs b/google-home/src/response/query.rs index 51fcfba..00a4355 100644 --- a/google-home/src/response/query.rs +++ b/google-home/src/response/query.rs @@ -24,6 +24,12 @@ impl Payload { } } +impl Default for Payload { + fn default() -> Self { + Self::new() + } +} + #[derive(Debug, Serialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum Status { @@ -64,6 +70,12 @@ impl Device { } } +impl Default for Device { + fn default() -> Self { + Self::new() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/config.rs b/src/config.rs index 34359a8..a7bdc28 100644 --- a/src/config.rs +++ b/src/config.rs @@ -142,7 +142,7 @@ impl PresenceDeviceConfig { fn generate_topic(mut self, class: &str, identifier: &str, config: &Config) -> Result { if self.mqtt.is_none() { if !has_wildcards(&config.presence.topic) { - return Err(MissingWildcard::new(&config.presence.topic).into()); + return Err(MissingWildcard::new(&config.presence.topic)); } // TODO: This is not perfect, if the topic is some/+/thing/# this will fail @@ -243,17 +243,17 @@ impl Device { let device = match self { Device::IkeaOutlet { info, mqtt, outlet_type, timeout } => { trace!(id = identifier, "IkeaOutlet [{} in {:?}]", info.name, info.room); - IkeaOutlet::build(&identifier, info, mqtt, outlet_type, timeout, client).await + IkeaOutlet::build(identifier, info, mqtt, outlet_type, timeout, client).await .map(device_box)? }, Device::WakeOnLAN { info, mqtt, mac_address, broadcast_ip } => { trace!(id = identifier, "WakeOnLan [{} in {:?}]", info.name, info.room); - WakeOnLAN::build(&identifier, info, mqtt, mac_address, broadcast_ip, client).await + WakeOnLAN::build(identifier, info, mqtt, mac_address, broadcast_ip, client).await .map(device_box)? }, Device::KasaOutlet { ip } => { trace!(id = identifier, "KasaOutlet [{}]", identifier); - device_box(KasaOutlet::new(&identifier, ip)) + device_box(KasaOutlet::new(identifier, ip)) } Device::AudioSetup { mqtt, mixer, speakers } => { trace!(id = identifier, "AudioSetup [{}]", identifier); @@ -263,16 +263,16 @@ impl Device { let speakers_id = format!("{}.speakers", identifier); let speakers = (*speakers).create(&speakers_id, config, client.clone()).await?; - AudioSetup::build(&identifier, mqtt, mixer, speakers, client).await + AudioSetup::build(identifier, mqtt, mixer, speakers, client).await .map(device_box)? }, Device::ContactSensor { mqtt, presence } => { trace!(id = identifier, "ContactSensor [{}]", identifier); let presence = presence - .map(|p| p.generate_topic("contact", &identifier, &config)) + .map(|p| p.generate_topic("contact", identifier, config)) .transpose()?; - ContactSensor::build(&identifier, mqtt, presence, client).await + ContactSensor::build(identifier, mqtt, presence, client).await .map(device_box)? }, }; diff --git a/src/debug_bridge.rs b/src/debug_bridge.rs index b93d4c0..62b26ff 100644 --- a/src/debug_bridge.rs +++ b/src/debug_bridge.rs @@ -22,7 +22,7 @@ pub fn start(mut presence_rx: presence::Receiver, mut light_sensor_rx: light_sen loop { tokio::select! { res = presence_rx.changed() => { - if !res.is_ok() { + if res.is_err() { break; } @@ -30,7 +30,7 @@ pub fn start(mut presence_rx: presence::Receiver, mut light_sensor_rx: light_sen debug_bridge.on_presence(presence).await; } res = light_sensor_rx.changed() => { - if !res.is_ok() { + if res.is_err() { break; } diff --git a/src/devices.rs b/src/devices.rs index 0187392..ce50faa 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -126,7 +126,7 @@ pub fn start(mut mqtt_rx: mqtt::Receiver, mut presence_rx: presence::Receiver, m } }); - return DevicesHandle { tx }; + DevicesHandle { tx } } impl Devices { diff --git a/src/devices/kasa_outlet.rs b/src/devices/kasa_outlet.rs index 939d418..9773965 100644 --- a/src/devices/kasa_outlet.rs +++ b/src/devices/kasa_outlet.rs @@ -76,11 +76,11 @@ impl Request { encrypted.put_u32(data.len() as u32); for c in data { - key = key ^ c; + key ^= c; encrypted.put_u8(key); } - return encrypted.freeze(); + encrypted.freeze() } } @@ -157,7 +157,7 @@ impl Response { .map(|_| sysinfo.relay_state == 1); } - return Err(ResponseError::SysinfoNotFound); + Err(ResponseError::SysinfoNotFound) } fn check_set_relay_success(&self) -> Result<(), ResponseError> { @@ -165,13 +165,13 @@ impl Response { return set_relay_state.err_code.ok(); } - return Err(ResponseError::RelayStateNotFound); + Err(ResponseError::RelayStateNotFound) } fn decrypt(mut data: bytes::Bytes) -> Result { let mut key: u8 = 171; if data.len() < 4 { - return Err(ResponseError::ToShort.into()); + return Err(ResponseError::ToShort); } let length = data.get_u32(); @@ -189,10 +189,10 @@ impl Response { impl traits::OnOff for KasaOutlet { fn is_on(&self) -> Result { - let mut stream = TcpStream::connect(self.addr).or::(Err(DeviceError::DeviceOffline.into()))?; + let mut stream = TcpStream::connect(self.addr).or::(Err(DeviceError::DeviceOffline))?; let body = Request::get_sysinfo().encrypt(); - stream.write_all(&body).and(stream.flush()).or::(Err(DeviceError::TransientError.into()))?; + stream.write_all(&body).and(stream.flush()).or::(Err(DeviceError::TransientError))?; let mut received = Vec::new(); let mut rx_bytes = [0; 1024]; @@ -212,10 +212,10 @@ impl traits::OnOff for KasaOutlet { } fn set_on(&mut self, on: bool) -> Result<(), errors::ErrorCode> { - let mut stream = TcpStream::connect(self.addr).or::(Err(DeviceError::DeviceOffline.into()))?; + let mut stream = TcpStream::connect(self.addr).or::(Err(DeviceError::DeviceOffline))?; let body = Request::set_relay_state(on).encrypt(); - stream.write_all(&body).and(stream.flush()).or::(Err(DeviceError::TransientError.into()))?; + stream.write_all(&body).and(stream.flush()).or::(Err(DeviceError::TransientError))?; let mut received = Vec::new(); let mut rx_bytes = [0; 1024]; diff --git a/src/devices/wake_on_lan.rs b/src/devices/wake_on_lan.rs index c7ef321..25470b0 100644 --- a/src/devices/wake_on_lan.rs +++ b/src/devices/wake_on_lan.rs @@ -62,7 +62,7 @@ impl GoogleHomeDevice for WakeOnLAN { let mut name = device::Name::new(&self.info.name); name.add_default_name("Computer"); - return name; + name } fn get_id(&self) -> &str { diff --git a/src/error.rs b/src/error.rs index b52feec..3775c54 100644 --- a/src/error.rs +++ b/src/error.rs @@ -21,7 +21,7 @@ impl MissingEnv { } pub fn has_missing(self) -> result::Result<(), Self> { - if self.keys.len() > 0 { + if !self.keys.is_empty() { Err(self) } else { Ok(()) @@ -29,19 +29,25 @@ impl MissingEnv { } } +impl Default for MissingEnv { + fn default() -> Self { + Self::new() + } +} + impl fmt::Display for MissingEnv { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Missing environment variable")?; - if self.keys.len() == 0 { + if self.keys.is_empty() { unreachable!("This error should only be returned if there are actually missing environment variables"); } if self.keys.len() == 1 { write!(f, " '{}'", self.keys[0])?; } else { write!(f, "s '{}'", self.keys[0])?; - self.keys.iter().skip(1).map(|key| { + self.keys.iter().skip(1).try_for_each(|key| { write!(f, ", '{key}'") - }).collect::()?; + })?; } Ok(()) diff --git a/src/hue_bridge.rs b/src/hue_bridge.rs index dca99f6..867ade5 100644 --- a/src/hue_bridge.rs +++ b/src/hue_bridge.rs @@ -61,7 +61,7 @@ pub fn start(mut presence_rx: presence::Receiver, mut light_sensor_rx: light_sen loop { tokio::select! { res = presence_rx.changed() => { - if !res.is_ok() { + if res.is_err() { break; } @@ -69,7 +69,7 @@ pub fn start(mut presence_rx: presence::Receiver, mut light_sensor_rx: light_sen hue_bridge.on_presence(presence).await; } res = light_sensor_rx.changed() => { - if !res.is_ok() { + if res.is_err() { break; } diff --git a/src/light_sensor.rs b/src/light_sensor.rs index b47f356..1d0c4e1 100644 --- a/src/light_sensor.rs +++ b/src/light_sensor.rs @@ -24,7 +24,7 @@ struct LightSensor { impl LightSensor { fn new(mqtt: MqttDeviceConfig, min: isize, max: isize) -> Self { let (tx, is_dark) = watch::channel(false); - Self { is_dark: is_dark.clone(), mqtt, min, max, tx } + Self { is_dark, mqtt, min, max, tx } } } diff --git a/src/main.rs b/src/main.rs index 28b25f1..d37e0b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ #![feature(async_closure)] -use std::{process, time::Duration, collections::HashMap}; +use std::{ process, time::Duration, collections::HashMap }; use axum::{extract::FromRef, http::StatusCode, routing::post, Json, Router, response::IntoResponse}; @@ -14,6 +14,7 @@ use automation::{ }; use dotenvy::dotenv; use rumqttc::{AsyncClient, MqttOptions, Transport, matches}; +use tokio::task::JoinHandle; use tracing::{debug, error, info, metadata::LevelFilter}; use futures::future::join_all; @@ -92,6 +93,60 @@ async fn app() -> anyhow::Result<()> { debug_bridge::start(presence.clone(), light_sensor.clone(), config, client.clone()); } + // Super hacky implementation for the washing machine, just for testing + { + let mut handle = None::>; + let mut mqtt = mqtt.subscribe(); + client.subscribe("zigbee2mqtt/bathroom/washing", rumqttc::QoS::AtLeastOnce).await.unwrap(); + tokio::spawn(async move { + if let Some(ntfy) = ntfy { + loop { + let message = mqtt.recv().await.unwrap(); + + if !matches(&message.topic, "zigbee2mqtt/bathroom/washing") { + continue; + } + + let map: HashMap = serde_json::from_slice(&message.payload).unwrap(); + debug!("Test: {:?}", map); + + let strength = match map.get("strength").map(|value| value.as_i64().unwrap()) { + Some(s) => s, + None => continue, + }; + + if strength > 15 { + debug!("Strength over 15"); + + // Update of strength over 15 which means we are still running, cancel any + // running timer + if let Some(handle) = handle.take() { + handle.abort(); + } + + // Start a new timer, if the timer runs out we have not had an update of + // more then 15 in the last timeout period, assume we are done, notify user + let ntfy = ntfy.clone(); + handle = Some( + tokio::spawn(async move { + debug!("Starting timeout of 10 min for washing machine..."); + tokio::time::sleep(Duration::from_secs(10*60)).await; + debug!("Notifying user!"); + + let notification = ntfy::Notification::new() + .set_title("Laundy is done") + .set_message("Do not forget to hang it!") + .set_priority(ntfy::Priority::High); + + ntfy.send(notification).await.ok(); + }) + ); + } + } + } + }); + } + let devices = devices::start(mqtt.subscribe(), presence.clone(), light_sensor.clone()); join_all( config @@ -125,7 +180,7 @@ async fn app() -> anyhow::Result<()> { debug!(username = user.preferred_username, "{result:#?}"); - return (StatusCode::OK, Json(result)).into_response(); + (StatusCode::OK, Json(result)).into_response() }), ); diff --git a/src/ntfy.rs b/src/ntfy.rs index 18c2f1f..3baa89d 100644 --- a/src/ntfy.rs +++ b/src/ntfy.rs @@ -102,6 +102,12 @@ impl Notification { } } +impl Default for Notification { + fn default() -> Self { + Self::new() + } +} + impl Ntfy { fn new(base_url: &str, topic: &str, tx: Sender) -> Self { Self { base_url: base_url.to_owned(), topic: topic.to_owned(), tx } @@ -148,7 +154,7 @@ pub fn start(mut presence_rx: presence::Receiver, config: &NtfyConfig) -> Sender } }); - return tx; + tx } #[async_trait] diff --git a/src/presence.rs b/src/presence.rs index 5774ba0..9ed3f5f 100644 --- a/src/presence.rs +++ b/src/presence.rs @@ -25,11 +25,11 @@ struct Presence { impl Presence { fn build(mqtt: MqttDeviceConfig) -> Result { if !has_wildcards(&mqtt.topic) { - return Err(MissingWildcard::new(&mqtt.topic).into()); + return Err(MissingWildcard::new(&mqtt.topic)); } let (tx, overall_presence) = watch::channel(false); - Ok(Self { devices: HashMap::new(), overall_presence: overall_presence.clone(), mqtt, tx }) + Ok(Self { devices: HashMap::new(), overall_presence, mqtt, tx }) } } @@ -62,7 +62,7 @@ impl OnMqtt for Presence { let offset = self.mqtt.topic.find('+').or(self.mqtt.topic.find('#')).expect("Presence::new fails if it does not contain wildcards"); let device_name = &message.topic[offset..]; - if message.payload.len() == 0 { + if message.payload.is_empty() { // Remove the device from the map debug!("State of device [{device_name}] has been removed"); self.devices.remove(device_name);