Converted google home traits to be async
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Dreaded_X 2023-08-11 03:46:44 +02:00
parent a67e47997b
commit 522fe27f11
Signed by: Dreaded_X
GPG Key ID: FA5F485356B0D2D4
8 changed files with 60 additions and 38 deletions

4
Cargo.lock generated
View File

@ -1682,11 +1682,11 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]] [[package]]
name = "wakey" name = "wakey"
version = "0.3.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/DreadedX/wakey#a982950203aa56a93a7ba7a63062eccdd24046c5"
checksum = "dedab5a691c0d33bcfb5c1ed6bb17265e531ed3392282eed9b20063a0f23e9f5"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"hex", "hex",
"tokio",
] ]
[[package]] [[package]]

View File

@ -39,5 +39,8 @@ console-subscriber = "0.1.8"
tracing-subscriber = "0.3.16" tracing-subscriber = "0.3.16"
serde-tuple-vec-map = "1.0.1" serde-tuple-vec-map = "1.0.1"
[patch.crates-io]
wakey = { git = "https://github.com/DreadedX/wakey" }
[profile.release] [profile.release]
lto = true lto = true

View File

@ -104,7 +104,11 @@ pub trait GoogleHomeDevice: AsGoogleHomeDevice + Sync + Send + 'static {
// OnOff // OnOff
if let Some(on_off) = As::<dyn OnOff>::cast(self) { if let Some(on_off) = As::<dyn OnOff>::cast(self) {
device.state.on = on_off.is_on().map_err(|err| device.set_error(err)).ok(); device.state.on = on_off
.is_on()
.await
.map_err(|err| device.set_error(err))
.ok();
} }
device device
@ -114,14 +118,14 @@ pub trait GoogleHomeDevice: AsGoogleHomeDevice + Sync + Send + 'static {
match command { match command {
CommandType::OnOff { on } => { CommandType::OnOff { on } => {
if let Some(on_off) = As::<dyn OnOff>::cast_mut(self) { if let Some(on_off) = As::<dyn OnOff>::cast_mut(self) {
on_off.set_on(*on)?; on_off.set_on(*on).await?;
} else { } else {
return Err(DeviceError::ActionNotAvailable.into()); return Err(DeviceError::ActionNotAvailable.into());
} }
} }
CommandType::ActivateScene { deactivate } => { CommandType::ActivateScene { deactivate } => {
if let Some(scene) = As::<dyn Scene>::cast(self) { if let Some(scene) = As::<dyn Scene>::cast(self) {
scene.set_active(!deactivate)?; scene.set_active(!deactivate).await?;
} else { } else {
return Err(DeviceError::ActionNotAvailable.into()); return Err(DeviceError::ActionNotAvailable.into());
} }

View File

@ -1,3 +1,4 @@
use async_trait::async_trait;
use serde::Serialize; use serde::Serialize;
use crate::errors::ErrorCode; use crate::errors::ErrorCode;
@ -10,6 +11,7 @@ pub enum Trait {
Scene, Scene,
} }
#[async_trait]
#[impl_cast::device_trait] #[impl_cast::device_trait]
pub trait OnOff { pub trait OnOff {
fn is_command_only(&self) -> Option<bool> { fn is_command_only(&self) -> Option<bool> {
@ -21,15 +23,16 @@ pub trait OnOff {
} }
// TODO: Implement correct error so we can handle them properly // TODO: Implement correct error so we can handle them properly
fn is_on(&self) -> Result<bool, ErrorCode>; async fn is_on(&self) -> Result<bool, ErrorCode>;
fn set_on(&mut self, on: bool) -> Result<(), ErrorCode>; async fn set_on(&mut self, on: bool) -> Result<(), ErrorCode>;
} }
#[async_trait]
#[impl_cast::device_trait] #[impl_cast::device_trait]
pub trait Scene { pub trait Scene {
fn is_scene_reversible(&self) -> Option<bool> { fn is_scene_reversible(&self) -> Option<bool> {
None None
} }
fn set_active(&self, activate: bool) -> Result<(), ErrorCode>; async fn set_active(&self, activate: bool) -> Result<(), ErrorCode>;
} }

View File

@ -87,21 +87,21 @@ impl OnMqtt for AudioSetup {
match action { match action {
RemoteAction::On => { RemoteAction::On => {
if self.mixer.is_on().unwrap() { if self.mixer.is_on().await.unwrap() {
self.speakers.set_on(false).unwrap(); self.speakers.set_on(false).await.unwrap();
self.mixer.set_on(false).unwrap(); self.mixer.set_on(false).await.unwrap();
} else { } else {
self.speakers.set_on(true).unwrap(); self.speakers.set_on(true).await.unwrap();
self.mixer.set_on(true).unwrap(); self.mixer.set_on(true).await.unwrap();
} }
}, },
RemoteAction::BrightnessMoveUp => { RemoteAction::BrightnessMoveUp => {
if !self.mixer.is_on().unwrap() { if !self.mixer.is_on().await.unwrap() {
self.mixer.set_on(true).unwrap(); self.mixer.set_on(true).await.unwrap();
} else if self.speakers.is_on().unwrap() { } else if self.speakers.is_on().await.unwrap() {
self.speakers.set_on(false).unwrap(); self.speakers.set_on(false).await.unwrap();
} else { } else {
self.speakers.set_on(true).unwrap(); self.speakers.set_on(true).await.unwrap();
} }
}, },
RemoteAction::BrightnessStop => { /* Ignore this action */ }, RemoteAction::BrightnessStop => { /* Ignore this action */ },
@ -116,8 +116,8 @@ impl OnPresence for AudioSetup {
// Turn off the audio setup when we leave the house // Turn off the audio setup when we leave the house
if !presence { if !presence {
debug!(id = self.identifier, "Turning devices off"); debug!(id = self.identifier, "Turning devices off");
self.speakers.set_on(false).unwrap(); self.speakers.set_on(false).await.unwrap();
self.mixer.set_on(false).unwrap(); self.mixer.set_on(false).await.unwrap();
} }
} }
} }

View File

@ -6,7 +6,6 @@ use google_home::{
types::Type, types::Type,
GoogleHomeDevice, GoogleHomeDevice,
}; };
use pollster::FutureExt as _;
use rumqttc::{AsyncClient, Publish}; use rumqttc::{AsyncClient, Publish};
use serde::Deserialize; use serde::Deserialize;
use std::time::Duration; use std::time::Duration;
@ -170,7 +169,7 @@ impl OnPresence for IkeaOutlet {
// Turn off the outlet when we leave the house (Not if it is a battery charger) // Turn off the outlet when we leave the house (Not if it is a battery charger)
if !presence && self.outlet_type != OutletType::Charger { if !presence && self.outlet_type != OutletType::Charger {
debug!(id = self.identifier, "Turning device off"); debug!(id = self.identifier, "Turning device off");
self.set_on(false).ok(); self.set_on(false).await.ok();
} }
} }
} }
@ -206,13 +205,14 @@ impl GoogleHomeDevice for IkeaOutlet {
} }
} }
#[async_trait]
impl traits::OnOff for IkeaOutlet { impl traits::OnOff for IkeaOutlet {
fn is_on(&self) -> Result<bool, ErrorCode> { async fn is_on(&self) -> Result<bool, ErrorCode> {
Ok(self.last_known_state) Ok(self.last_known_state)
} }
fn set_on(&mut self, on: bool) -> Result<(), ErrorCode> { async fn set_on(&mut self, on: bool) -> Result<(), ErrorCode> {
set_on(self.client.clone(), &self.mqtt.topic, on).block_on(); set_on(self.client.clone(), &self.mqtt.topic, on).await;
Ok(()) Ok(())
} }

View File

@ -1,9 +1,9 @@
use std::{ use std::{
io::{Read, Write}, net::{Ipv4Addr, SocketAddr},
net::{Ipv4Addr, SocketAddr, TcpStream},
str::Utf8Error, str::Utf8Error,
}; };
use async_trait::async_trait;
use bytes::{Buf, BufMut}; use bytes::{Buf, BufMut};
use google_home::{ use google_home::{
errors::{self, DeviceError}, errors::{self, DeviceError},
@ -12,6 +12,10 @@ use google_home::{
use rumqttc::AsyncClient; use rumqttc::AsyncClient;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::TcpStream,
};
use tracing::trace; use tracing::trace;
use crate::{config::CreateDevice, error::CreateDeviceError, event::EventChannel}; use crate::{config::CreateDevice, error::CreateDeviceError, event::EventChannel};
@ -215,15 +219,18 @@ impl Response {
} }
} }
#[async_trait]
impl traits::OnOff for KasaOutlet { impl traits::OnOff for KasaOutlet {
fn is_on(&self) -> Result<bool, errors::ErrorCode> { async fn is_on(&self) -> Result<bool, errors::ErrorCode> {
let mut stream = let mut stream = TcpStream::connect(self.addr)
TcpStream::connect(self.addr).or::<DeviceError>(Err(DeviceError::DeviceOffline))?; .await
.or::<DeviceError>(Err(DeviceError::DeviceOffline))?;
let body = Request::get_sysinfo().encrypt(); let body = Request::get_sysinfo().encrypt();
stream stream
.write_all(&body) .write_all(&body)
.and(stream.flush()) .await
.and(stream.flush().await)
.or::<DeviceError>(Err(DeviceError::TransientError))?; .or::<DeviceError>(Err(DeviceError::TransientError))?;
let mut received = Vec::new(); let mut received = Vec::new();
@ -231,6 +238,7 @@ impl traits::OnOff for KasaOutlet {
loop { loop {
let read = stream let read = stream
.read(&mut rx_bytes) .read(&mut rx_bytes)
.await
.or::<errors::ErrorCode>(Err(DeviceError::TransientError.into()))?; .or::<errors::ErrorCode>(Err(DeviceError::TransientError.into()))?;
received.extend_from_slice(&rx_bytes[..read]); received.extend_from_slice(&rx_bytes[..read]);
@ -247,20 +255,22 @@ impl traits::OnOff for KasaOutlet {
.or(Err(DeviceError::TransientError.into())) .or(Err(DeviceError::TransientError.into()))
} }
fn set_on(&mut self, on: bool) -> Result<(), errors::ErrorCode> { async fn set_on(&mut self, on: bool) -> Result<(), errors::ErrorCode> {
let mut stream = let mut stream = TcpStream::connect(self.addr)
TcpStream::connect(self.addr).or::<DeviceError>(Err(DeviceError::DeviceOffline))?; .await
.or::<DeviceError>(Err(DeviceError::DeviceOffline))?;
let body = Request::set_relay_state(on).encrypt(); let body = Request::set_relay_state(on).encrypt();
stream stream
.write_all(&body) .write_all(&body)
.and(stream.flush()) .await
.and(stream.flush().await)
.or::<DeviceError>(Err(DeviceError::TransientError))?; .or::<DeviceError>(Err(DeviceError::TransientError))?;
let mut received = Vec::new(); let mut received = Vec::new();
let mut rx_bytes = [0; 1024]; let mut rx_bytes = [0; 1024];
loop { loop {
let read = match stream.read(&mut rx_bytes) { let read = match stream.read(&mut rx_bytes).await {
Ok(read) => read, Ok(read) => read,
Err(_) => return Err(DeviceError::TransientError.into()), Err(_) => return Err(DeviceError::TransientError.into()),
}; };

View File

@ -95,7 +95,7 @@ impl OnMqtt for WakeOnLAN {
} }
}; };
self.set_active(activate).ok(); self.set_active(activate).await.ok();
} }
} }
@ -124,8 +124,9 @@ impl GoogleHomeDevice for WakeOnLAN {
} }
} }
#[async_trait]
impl traits::Scene for WakeOnLAN { impl traits::Scene for WakeOnLAN {
fn set_active(&self, activate: bool) -> Result<(), ErrorCode> { async fn set_active(&self, activate: bool) -> Result<(), ErrorCode> {
if activate { if activate {
debug!( debug!(
id = self.identifier, id = self.identifier,
@ -138,6 +139,7 @@ impl traits::Scene for WakeOnLAN {
})?; })?;
wol.send_magic_to((Ipv4Addr::new(0, 0, 0, 0), 0), (self.broadcast_ip, 9)) wol.send_magic_to((Ipv4Addr::new(0, 0, 0, 0), 0), (self.broadcast_ip, 9))
.await
.map_err(|err| { .map_err(|err| {
error!(id = self.identifier, "Failed to activate computer: {err}"); error!(id = self.identifier, "Failed to activate computer: {err}");
google_home::errors::DeviceError::TransientError.into() google_home::errors::DeviceError::TransientError.into()