Compare commits

..

1 Commits

Author SHA1 Message Date
8e13ae2c01
WIP: Working on trait macro
Some checks failed
Build and deploy / Build application (push) Successful in 7m19s
Check / Run checks (push) Successful in 3m35s
Build and deploy / Build container (push) Failing after 38s
Build and deploy / Deploy container (push) Has been skipped
2024-07-02 02:23:39 +02:00
18 changed files with 229 additions and 94 deletions

View File

@ -299,7 +299,7 @@ fn get_command_enum(traits: &Punctuated<Trait, Token![,]>) -> proc_macro2::Token
}); });
quote! { quote! {
#[derive(Debug, Clone, serde::Deserialize)] #[derive(Debug, serde::Deserialize)]
#[serde(tag = "command", content = "params", rename_all = "camelCase")] #[serde(tag = "command", content = "params", rename_all = "camelCase")]
pub enum Command { pub enum Command {
#(#items,)* #(#items,)*
@ -520,7 +520,7 @@ pub fn google_home_traits(item: TokenStream) -> TokenStream {
Some(quote! { Some(quote! {
Command::#command_name {#(#parameters,)*} => { Command::#command_name {#(#parameters,)*} => {
if let Some(t) = self.cast_mut() as Option<&mut dyn #ident> { if let Some(t) = self.cast() as Option<&dyn #ident> {
t.#f_name(#(#parameters,)*) #asyncness #errors; t.#f_name(#(#parameters,)*) #asyncness #errors;
serde_json::to_value(t.get_state().await?)? serde_json::to_value(t.get_state().await?)?
} else { } else {
@ -547,7 +547,7 @@ pub fn google_home_traits(item: TokenStream) -> TokenStream {
pub trait #fulfillment: Sync + Send { pub trait #fulfillment: Sync + Send {
async fn sync(&self) -> Result<(Vec<Trait>, serde_json::Value), Box<dyn ::std::error::Error>>; async fn sync(&self) -> Result<(Vec<Trait>, serde_json::Value), Box<dyn ::std::error::Error>>;
async fn query(&self) -> Result<serde_json::Value, Box<dyn ::std::error::Error>>; async fn query(&self) -> Result<serde_json::Value, Box<dyn ::std::error::Error>>;
async fn execute(&mut self, command: Command) -> Result<serde_json::Value, Box<dyn std::error::Error>>; async fn execute(&self, command: Command) -> Result<serde_json::Value, Box<dyn std::error::Error>>;
} }
#(#structs)* #(#structs)*
@ -575,7 +575,7 @@ pub fn google_home_traits(item: TokenStream) -> TokenStream {
Ok(state) Ok(state)
} }
async fn execute(&mut self, command: Command) -> Result<serde_json::Value, Box<dyn std::error::Error>> { async fn execute(&self, command: Command) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
let value = match command { let value = match command {
#(#execute)* #(#execute)*
}; };

View File

@ -0,0 +1,22 @@
use serde::Serialize;
use crate::traits::AvailableSpeeds;
#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Attributes {
#[serde(skip_serializing_if = "Option::is_none")]
pub command_only_on_off: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_only_on_off: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scene_reversible: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reversible: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub command_only_fan_speed: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub available_fan_speeds: Option<AvailableSpeeds>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_only_humidity_setting: Option<bool>,
}

View File

@ -1,13 +1,17 @@
use async_trait::async_trait; use async_trait::async_trait;
use automation_cast::Cast;
use serde::Serialize; use serde::Serialize;
use crate::errors::ErrorCode; use crate::errors::{DeviceError, ErrorCode};
use crate::request::execute::CommandType;
use crate::response; use crate::response;
use crate::traits::{Command, GoogleHomeDeviceFulfillment}; use crate::traits::{FanSpeed, HumiditySetting, OnOff, Scene, Trait};
use crate::types::Type; use crate::types::Type;
#[async_trait] #[async_trait]
pub trait GoogleHomeDevice: GoogleHomeDeviceFulfillment { pub trait GoogleHomeDevice:
Sync + Send + Cast<dyn OnOff> + Cast<dyn Scene> + Cast<dyn FanSpeed> + Cast<dyn HumiditySetting>
{
fn get_device_type(&self) -> Type; fn get_device_type(&self) -> Type;
fn get_device_name(&self) -> Name; fn get_device_name(&self) -> Name;
fn get_id(&self) -> String; fn get_id(&self) -> String;
@ -37,10 +41,35 @@ pub trait GoogleHomeDevice: GoogleHomeDeviceFulfillment {
} }
device.device_info = self.get_device_info(); device.device_info = self.get_device_info();
let (traits, attributes) = GoogleHomeDeviceFulfillment::sync(self).await.unwrap(); let mut traits = Vec::new();
// OnOff
if let Some(on_off) = self.cast() as Option<&dyn OnOff> {
traits.push(Trait::OnOff);
device.attributes.command_only_on_off = on_off.is_command_only();
device.attributes.query_only_on_off = on_off.is_query_only();
}
// Scene
if let Some(scene) = self.cast() as Option<&dyn Scene> {
traits.push(Trait::Scene);
device.attributes.scene_reversible = scene.is_scene_reversible();
}
// FanSpeed
if let Some(fan_speed) = self.cast() as Option<&dyn FanSpeed> {
traits.push(Trait::FanSpeed);
device.attributes.command_only_fan_speed = fan_speed.command_only_fan_speed();
device.attributes.available_fan_speeds = Some(fan_speed.available_speeds());
}
if let Some(humidity_setting) = self.cast() as Option<&dyn HumiditySetting> {
traits.push(Trait::HumiditySetting);
device.attributes.query_only_humidity_setting =
humidity_setting.query_only_humidity_setting();
}
device.traits = traits; device.traits = traits;
device.attributes = attributes;
device device
} }
@ -51,15 +80,50 @@ pub trait GoogleHomeDevice: GoogleHomeDeviceFulfillment {
device.set_offline(); device.set_offline();
} }
device.state = GoogleHomeDeviceFulfillment::query(self).await.unwrap(); // OnOff
if let Some(on_off) = self.cast() as Option<&dyn OnOff> {
device.state.on = on_off
.is_on()
.await
.map_err(|err| device.set_error(err))
.ok();
}
// FanSpeed
if let Some(fan_speed) = self.cast() as Option<&dyn FanSpeed> {
device.state.current_fan_speed_setting = Some(fan_speed.current_speed().await);
}
if let Some(humidity_setting) = self.cast() as Option<&dyn HumiditySetting> {
device.state.humidity_ambient_percent =
Some(humidity_setting.humidity_ambient_percent().await);
}
device device
} }
async fn execute(&mut self, command: Command) -> Result<(), ErrorCode> { async fn execute(&mut self, command: &CommandType) -> Result<(), ErrorCode> {
GoogleHomeDeviceFulfillment::execute(self, command.clone()) match command {
.await CommandType::OnOff { on } => {
.unwrap(); if let Some(t) = self.cast_mut() as Option<&mut dyn OnOff> {
t.set_on(*on).await?;
} else {
return Err(DeviceError::ActionNotAvailable.into());
}
}
CommandType::ActivateScene { deactivate } => {
if let Some(t) = self.cast_mut() as Option<&mut dyn Scene> {
t.set_active(!deactivate).await?;
} else {
return Err(DeviceError::ActionNotAvailable.into());
}
}
CommandType::SetFanSpeed { fan_speed } => {
if let Some(t) = self.cast_mut() as Option<&mut dyn FanSpeed> {
t.set_speed(fan_speed).await?;
}
}
}
Ok(()) Ok(())
} }

View File

@ -8,7 +8,7 @@ use tokio::sync::{Mutex, RwLock};
use crate::errors::{DeviceError, ErrorCode}; use crate::errors::{DeviceError, ErrorCode};
use crate::request::{self, Intent, Request}; use crate::request::{self, Intent, Request};
use crate::response::{self, execute, query, sync, Response, ResponsePayload}; use crate::response::{self, execute, query, sync, Response, ResponsePayload, State};
use crate::GoogleHomeDevice; use crate::GoogleHomeDevice;
#[derive(Debug)] #[derive(Debug)]
@ -66,7 +66,7 @@ impl GoogleHome {
let mut resp_payload = sync::Payload::new(&self.user_id); let mut resp_payload = sync::Payload::new(&self.user_id);
let f = devices.iter().map(|(_, device)| async move { let f = devices.iter().map(|(_, device)| async move {
if let Some(device) = device.read().await.as_ref().cast() { if let Some(device) = device.read().await.as_ref().cast() {
Some(GoogleHomeDevice::sync(device).await) Some(device.sync().await)
} else { } else {
None None
} }
@ -91,7 +91,7 @@ impl GoogleHome {
let device = if let Some(device) = devices.get(id.as_str()) let device = if let Some(device) = devices.get(id.as_str())
&& let Some(device) = device.read().await.as_ref().cast() && let Some(device) = device.read().await.as_ref().cast()
{ {
GoogleHomeDevice::query(device).await device.query().await
} else { } else {
let mut device = query::Device::new(); let mut device = query::Device::new();
device.set_offline(); device.set_offline();
@ -121,12 +121,12 @@ impl GoogleHome {
let mut success = response::execute::Command::new(execute::Status::Success); let mut success = response::execute::Command::new(execute::Status::Success);
success.states = Some(execute::States { success.states = Some(execute::States {
online: true, online: true,
state: Default::default(), state: State::default(),
}); });
let mut offline = response::execute::Command::new(execute::Status::Offline); let mut offline = response::execute::Command::new(execute::Status::Offline);
offline.states = Some(execute::States { offline.states = Some(execute::States {
online: false, online: false,
state: Default::default(), state: State::default(),
}); });
let mut errors: HashMap<ErrorCode, response::execute::Command> = HashMap::new(); let mut errors: HashMap<ErrorCode, response::execute::Command> = HashMap::new();
@ -147,8 +147,7 @@ impl GoogleHome {
// NOTE: We can not use .map here because async =( // NOTE: We can not use .map here because async =(
let mut results = Vec::new(); let mut results = Vec::new();
for cmd in &execution { for cmd in &execution {
results results.push(device.execute(cmd).await);
.push(GoogleHomeDevice::execute(device, cmd.clone()).await);
} }
// Convert vec of results to a result with a vec and the first // Convert vec of results to a result with a vec and the first

View File

@ -7,6 +7,7 @@ mod fulfillment;
mod request; mod request;
mod response; mod response;
mod attributes;
pub mod errors; pub mod errors;
pub mod traits; pub mod traits;
pub mod types; pub mod types;

View File

@ -1,7 +1,5 @@
use serde::Deserialize; use serde::Deserialize;
use crate::traits;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Payload { pub struct Payload {
@ -12,7 +10,7 @@ pub struct Payload {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Command { pub struct Command {
pub devices: Vec<Device>, pub devices: Vec<Device>,
pub execution: Vec<traits::Command>, pub execution: Vec<CommandType>,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@ -22,6 +20,20 @@ pub struct Device {
// customData // customData
} }
#[derive(Debug, Deserialize, Clone)]
#[serde(tag = "command", content = "params")]
pub enum CommandType {
#[serde(rename = "action.devices.commands.OnOff")]
OnOff { on: bool },
#[serde(rename = "action.devices.commands.ActivateScene")]
ActivateScene { deactivate: bool },
#[serde(
rename = "action.devices.commands.SetFanSpeed",
rename_all = "camelCase"
)]
SetFanSpeed { fan_speed: String },
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -62,7 +74,7 @@ mod tests {
assert_eq!(payload.commands[0].devices.len(), 0); assert_eq!(payload.commands[0].devices.len(), 0);
assert_eq!(payload.commands[0].execution.len(), 1); assert_eq!(payload.commands[0].execution.len(), 1);
match &payload.commands[0].execution[0] { match &payload.commands[0].execution[0] {
traits::Command::SetFanSpeed { fan_speed } => assert_eq!(fan_speed, "Test"), CommandType::SetFanSpeed { fan_speed } => assert_eq!(fan_speed, "Test"),
_ => panic!("Expected SetFanSpeed"), _ => panic!("Expected SetFanSpeed"),
} }
} }

View File

@ -27,3 +27,16 @@ pub enum ResponsePayload {
Query(query::Payload), Query(query::Payload),
Execute(execute::Payload), Execute(execute::Payload),
} }
#[derive(Debug, Default, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct State {
#[serde(skip_serializing_if = "Option::is_none")]
pub on: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub current_fan_speed_setting: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub humidity_ambient_percent: Option<isize>,
}

View File

@ -1,6 +1,7 @@
use serde::Serialize; use serde::Serialize;
use crate::errors::ErrorCode; use crate::errors::ErrorCode;
use crate::response::State;
#[derive(Debug, Serialize, Clone)] #[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
@ -71,7 +72,7 @@ pub struct States {
pub online: bool, pub online: bool,
#[serde(flatten)] #[serde(flatten)]
pub state: serde_json::Value, pub state: State,
} }
#[derive(Debug, Serialize, Clone)] #[derive(Debug, Serialize, Clone)]
@ -86,19 +87,19 @@ pub enum Status {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serde_json::json;
use super::*; use super::*;
use crate::errors::DeviceError; use crate::errors::DeviceError;
use crate::response::{Response, ResponsePayload}; use crate::response::{Response, ResponsePayload, State};
#[test] #[test]
fn serialize() { fn serialize() {
let mut execute_resp = Payload::new(); let mut execute_resp = Payload::new();
let state = json!({ let state = State {
"on": true, on: Some(true),
}); current_fan_speed_setting: None,
humidity_ambient_percent: None,
};
let mut command = Command::new(Status::Success); let mut command = Command::new(Status::Success);
command.states = Some(States { command.states = Some(States {
online: true, online: true,

View File

@ -3,6 +3,7 @@ use std::collections::HashMap;
use serde::Serialize; use serde::Serialize;
use crate::errors::ErrorCode; use crate::errors::ErrorCode;
use crate::response::State;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
@ -52,7 +53,7 @@ pub struct Device {
error_code: Option<ErrorCode>, error_code: Option<ErrorCode>,
#[serde(flatten)] #[serde(flatten)]
pub state: serde_json::Value, pub state: State,
} }
impl Device { impl Device {
@ -61,7 +62,7 @@ impl Device {
online: true, online: true,
status: Status::Success, status: Status::Success,
error_code: None, error_code: None,
state: Default::default(), state: State::default(),
} }
} }
@ -87,8 +88,6 @@ impl Default for Device {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serde_json::json;
use super::*; use super::*;
use crate::response::{Response, ResponsePayload}; use crate::response::{Response, ResponsePayload};
@ -97,15 +96,11 @@ mod tests {
let mut query_resp = Payload::new(); let mut query_resp = Payload::new();
let mut device = Device::new(); let mut device = Device::new();
device.state = json!({ device.state.on = Some(true);
"on": true,
});
query_resp.add_device("123", device); query_resp.add_device("123", device);
let mut device = Device::new(); let mut device = Device::new();
device.state = json!({ device.state.on = Some(false);
"on": true,
});
query_resp.add_device("456", device); query_resp.add_device("456", device);
let resp = Response::new( let resp = Response::new(

View File

@ -1,5 +1,6 @@
use serde::Serialize; use serde::Serialize;
use crate::attributes::Attributes;
use crate::device; use crate::device;
use crate::errors::ErrorCode; use crate::errors::ErrorCode;
use crate::traits::Trait; use crate::traits::Trait;
@ -46,7 +47,7 @@ pub struct Device {
pub room_hint: Option<String>, pub room_hint: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub device_info: Option<device::Info>, pub device_info: Option<device::Info>,
pub attributes: serde_json::Value, pub attributes: Attributes,
} }
impl Device { impl Device {
@ -60,7 +61,7 @@ impl Device {
notification_supported_by_agent: None, notification_supported_by_agent: None,
room_hint: None, room_hint: None,
device_info: None, device_info: None,
attributes: Default::default(), attributes: Attributes::default(),
} }
} }
} }

View File

@ -1,39 +1,42 @@
use automation_cast::Cast; use async_trait::async_trait;
use automation_macro::google_home_traits;
use serde::Serialize; use serde::Serialize;
use crate::errors::ErrorCode; use crate::errors::ErrorCode;
use crate::GoogleHomeDevice;
google_home_traits! { #[derive(Debug, Serialize)]
GoogleHomeDevice, pub enum Trait {
"action.devices.traits.OnOff" => trait OnOff { #[serde(rename = "action.devices.traits.OnOff")]
command_only_on_off: Option<bool>, OnOff,
query_only_on_off: Option<bool>, #[serde(rename = "action.devices.traits.Scene")]
async fn on(&self) -> Result<bool, ErrorCode>, Scene,
"action.devices.commands.OnOff" => async fn set_on(&mut self, on: bool) -> Result<(), ErrorCode>, #[serde(rename = "action.devices.traits.FanSpeed")]
}, FanSpeed,
"action.devices.traits.Scene" => trait Scene { #[serde(rename = "action.devices.traits.HumiditySetting")]
scene_reversible: Option<bool>, HumiditySetting,
"action.devices.commands.ActivateScene" => async fn set_active(&mut self, activate: bool) -> Result<(), ErrorCode>,
},
"action.devices.traits.FanSpeed" => trait FanSpeed {
reversible: Option<bool>,
command_only_fan_speed: Option<bool>,
available_fan_speeds: AvailableSpeeds,
fn current_fan_speed_setting(&self) -> Result<String, ErrorCode>,
// TODO: Figure out some syntax for optional command?
// Probably better to just force the user to always implement commands?
"action.devices.commands.SetFanSpeed" => async fn set_fan_speed(&mut self, fan_speed: String) -> Result<(), ErrorCode>,
},
"action.devices.traits.HumiditySetting" => trait HumiditySetting {
query_only_humidity_setting: Option<bool>,
fn humidity_ambient_percent(&self) -> Result<isize, ErrorCode>,
} }
#[async_trait]
pub trait OnOff: Sync + Send {
fn is_command_only(&self) -> Option<bool> {
None
}
fn is_query_only(&self) -> Option<bool> {
None
}
// TODO: Implement correct error so we can handle them properly
async fn is_on(&self) -> Result<bool, ErrorCode>;
async fn set_on(&mut self, on: bool) -> Result<(), ErrorCode>;
}
#[async_trait]
pub trait Scene: Sync + Send {
fn is_scene_reversible(&self) -> Option<bool> {
None
}
async fn set_active(&self, activate: bool) -> Result<(), ErrorCode>;
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
@ -53,3 +56,28 @@ pub struct AvailableSpeeds {
pub speeds: Vec<Speed>, pub speeds: Vec<Speed>,
pub ordered: bool, pub ordered: bool,
} }
#[async_trait]
pub trait FanSpeed: Sync + Send {
fn reversible(&self) -> Option<bool> {
None
}
fn command_only_fan_speed(&self) -> Option<bool> {
None
}
fn available_speeds(&self) -> AvailableSpeeds;
async fn current_speed(&self) -> String;
async fn set_speed(&self, speed: &str) -> Result<(), ErrorCode>;
}
#[async_trait]
pub trait HumiditySetting: Sync + Send {
// TODO: This implementation is not complete, I have only implemented what I need right now
fn query_only_humidity_setting(&self) -> Option<bool> {
None
}
async fn humidity_ambient_percent(&self) -> isize;
}

View File

@ -134,7 +134,7 @@ impl GoogleHomeDevice for AirFilter {
#[async_trait] #[async_trait]
impl OnOff for AirFilter { impl OnOff for AirFilter {
async fn on(&self) -> Result<bool, ErrorCode> { async fn is_on(&self) -> Result<bool, ErrorCode> {
Ok(self.last_known_state.state != AirFilterFanState::Off) Ok(self.last_known_state.state != AirFilterFanState::Off)
} }
@ -153,7 +153,7 @@ impl OnOff for AirFilter {
#[async_trait] #[async_trait]
impl FanSpeed for AirFilter { impl FanSpeed for AirFilter {
fn available_fan_speeds(&self) -> AvailableSpeeds { fn available_speeds(&self) -> AvailableSpeeds {
AvailableSpeeds { AvailableSpeeds {
speeds: vec![ speeds: vec![
Speed { Speed {
@ -189,7 +189,7 @@ impl FanSpeed for AirFilter {
} }
} }
fn current_fan_speed_setting(&self) -> Result<String, ErrorCode> { async fn current_speed(&self) -> String {
let speed = match self.last_known_state.state { let speed = match self.last_known_state.state {
AirFilterFanState::Off => "off", AirFilterFanState::Off => "off",
AirFilterFanState::Low => "low", AirFilterFanState::Low => "low",
@ -197,18 +197,17 @@ impl FanSpeed for AirFilter {
AirFilterFanState::High => "high", AirFilterFanState::High => "high",
}; };
Ok(speed.into()) speed.into()
} }
async fn set_fan_speed(&mut self, fan_speed: String) -> Result<(), ErrorCode> { async fn set_speed(&self, speed: &str) -> Result<(), ErrorCode> {
let fan_speed = fan_speed.as_str(); let state = if speed == "off" {
let state = if fan_speed == "off" {
AirFilterFanState::Off AirFilterFanState::Off
} else if fan_speed == "low" { } else if speed == "low" {
AirFilterFanState::Low AirFilterFanState::Low
} else if fan_speed == "medium" { } else if speed == "medium" {
AirFilterFanState::Medium AirFilterFanState::Medium
} else if fan_speed == "high" { } else if speed == "high" {
AirFilterFanState::High AirFilterFanState::High
} else { } else {
return Err(google_home::errors::DeviceError::TransientError.into()); return Err(google_home::errors::DeviceError::TransientError.into());
@ -226,7 +225,7 @@ impl HumiditySetting for AirFilter {
Some(true) Some(true)
} }
fn humidity_ambient_percent(&self) -> Result<isize, ErrorCode> { async fn humidity_ambient_percent(&self) -> isize {
Ok(self.last_known_state.humidity.round() as isize) self.last_known_state.humidity.round() as isize
} }
} }

View File

@ -92,7 +92,7 @@ impl OnMqtt for AudioSetup {
) { ) {
match action { match action {
RemoteAction::On => { RemoteAction::On => {
if mixer.on().await.unwrap() { if mixer.is_on().await.unwrap() {
speakers.set_on(false).await.unwrap(); speakers.set_on(false).await.unwrap();
mixer.set_on(false).await.unwrap(); mixer.set_on(false).await.unwrap();
} else { } else {
@ -101,9 +101,9 @@ impl OnMqtt for AudioSetup {
} }
}, },
RemoteAction::BrightnessMoveUp => { RemoteAction::BrightnessMoveUp => {
if !mixer.on().await.unwrap() { if !mixer.is_on().await.unwrap() {
mixer.set_on(true).await.unwrap(); mixer.set_on(true).await.unwrap();
} else if speakers.on().await.unwrap() { } else if speakers.is_on().await.unwrap() {
speakers.set_on(false).await.unwrap(); speakers.set_on(false).await.unwrap();
} else { } else {
speakers.set_on(true).await.unwrap(); speakers.set_on(true).await.unwrap();

View File

@ -155,7 +155,7 @@ impl OnMqtt for ContactSensor {
for (light, previous) in &mut trigger.devices { for (light, previous) in &mut trigger.devices {
let mut light = light.write().await; let mut light = light.write().await;
if let Some(light) = light.as_mut().cast_mut() as Option<&mut dyn OnOff> { if let Some(light) = light.as_mut().cast_mut() as Option<&mut dyn OnOff> {
*previous = light.on().await.unwrap(); *previous = light.is_on().await.unwrap();
light.set_on(true).await.ok(); light.set_on(true).await.ok();
} }
} }

View File

@ -152,7 +152,7 @@ impl OnOff for HueGroup {
Ok(()) Ok(())
} }
async fn on(&self) -> Result<bool, ErrorCode> { async fn is_on(&self) -> Result<bool, ErrorCode> {
let res = reqwest::Client::new() let res = reqwest::Client::new()
.get(self.url_get_state()) .get(self.url_get_state())
.send() .send()

View File

@ -205,7 +205,7 @@ impl GoogleHomeDevice for IkeaOutlet {
#[async_trait] #[async_trait]
impl traits::OnOff for IkeaOutlet { impl traits::OnOff for IkeaOutlet {
async fn on(&self) -> Result<bool, ErrorCode> { async fn is_on(&self) -> Result<bool, ErrorCode> {
Ok(self.last_known_state) Ok(self.last_known_state)
} }

View File

@ -207,7 +207,7 @@ impl Response {
#[async_trait] #[async_trait]
impl traits::OnOff for KasaOutlet { impl traits::OnOff for KasaOutlet {
async fn on(&self) -> Result<bool, errors::ErrorCode> { async fn is_on(&self) -> Result<bool, errors::ErrorCode> {
let mut stream = TcpStream::connect(self.config.addr) let mut stream = TcpStream::connect(self.config.addr)
.await .await
.or::<DeviceError>(Err(DeviceError::DeviceOffline))?; .or::<DeviceError>(Err(DeviceError::DeviceOffline))?;

View File

@ -103,7 +103,7 @@ impl GoogleHomeDevice for WakeOnLAN {
#[async_trait] #[async_trait]
impl traits::Scene for WakeOnLAN { impl traits::Scene for WakeOnLAN {
async fn set_active(&mut self, activate: bool) -> Result<(), ErrorCode> { async fn set_active(&self, activate: bool) -> Result<(), ErrorCode> {
if activate { if activate {
debug!( debug!(
id = Device::get_id(self), id = Device::get_id(self),