Applied clippy rules
This commit is contained in:
parent
7d5ce71e5b
commit
839c0a1c57
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[build]
|
||||
target = "x86_64-unknown-linux-gnu"
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Response, FullfillmentError> {
|
||||
pub fn handle_request(&self, request: Request, devices: &mut HashMap<&str, &mut dyn GoogleHomeDevice>) -> Result<Response, FullfillmentError> {
|
||||
// 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::<Vec<_>>();
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -142,7 +142,7 @@ impl PresenceDeviceConfig {
|
|||
fn generate_topic(mut self, class: &str, identifier: &str, config: &Config) -> Result<PresenceDeviceConfig, MissingWildcard> {
|
||||
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)?
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<Self, ResponseError> {
|
||||
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<bool, errors::ErrorCode> {
|
||||
let mut stream = TcpStream::connect(self.addr).or::<DeviceError>(Err(DeviceError::DeviceOffline.into()))?;
|
||||
let mut stream = TcpStream::connect(self.addr).or::<DeviceError>(Err(DeviceError::DeviceOffline))?;
|
||||
|
||||
let body = Request::get_sysinfo().encrypt();
|
||||
stream.write_all(&body).and(stream.flush()).or::<DeviceError>(Err(DeviceError::TransientError.into()))?;
|
||||
stream.write_all(&body).and(stream.flush()).or::<DeviceError>(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::<DeviceError>(Err(DeviceError::DeviceOffline.into()))?;
|
||||
let mut stream = TcpStream::connect(self.addr).or::<DeviceError>(Err(DeviceError::DeviceOffline))?;
|
||||
|
||||
let body = Request::set_relay_state(on).encrypt();
|
||||
stream.write_all(&body).and(stream.flush()).or::<DeviceError>(Err(DeviceError::TransientError.into()))?;
|
||||
stream.write_all(&body).and(stream.flush()).or::<DeviceError>(Err(DeviceError::TransientError))?;
|
||||
|
||||
let mut received = Vec::new();
|
||||
let mut rx_bytes = [0; 1024];
|
||||
|
|
|
@ -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 {
|
||||
|
|
14
src/error.rs
14
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::<fmt::Result>()?;
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
59
src/main.rs
59
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::<JoinHandle<()>>;
|
||||
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<String, serde_json::Value> = 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()
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -25,11 +25,11 @@ struct Presence {
|
|||
impl Presence {
|
||||
fn build(mqtt: MqttDeviceConfig) -> Result<Self, MissingWildcard> {
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user