automation_rs/src/hue_bridge.rs

101 lines
2.7 KiB
Rust

use std::net::SocketAddr;
use async_trait::async_trait;
use serde::Serialize;
use tracing::{warn, error, trace};
use crate::{config::{HueBridgeConfig, Flags}, presence::{OnPresence, self}, light_sensor::{OnDarkness, self}};
pub enum Flag {
Presence,
Darkness,
}
pub struct HueBridge {
addr: SocketAddr,
login: String,
flags: Flags,
}
#[derive(Debug, Serialize)]
struct FlagMessage {
flag: bool
}
impl HueBridge {
pub fn create(mut presence_rx: presence::Receiver, mut light_sensor_rx: light_sensor::Receiver, config: HueBridgeConfig) {
let mut hue_bridge = Self {
addr: (config.ip, 80).into(),
login: config.login,
flags: config.flags,
};
tokio::spawn(async move {
loop {
tokio::select! {
res = presence_rx.changed() => {
if !res.is_ok() {
break;
}
let presence = *presence_rx.borrow();
hue_bridge.on_presence(presence).await;
}
res = light_sensor_rx.changed() => {
if !res.is_ok() {
break;
}
let darkness = *light_sensor_rx.borrow();
hue_bridge.on_darkness(darkness).await;
}
}
}
unreachable!("Did not expect this");
});
}
pub async fn set_flag(&self, flag: Flag, value: bool) {
let flag = match flag {
Flag::Presence => self.flags.presence,
Flag::Darkness => self.flags.darkness,
};
let url = format!("http://{}/api/{}/sensors/{flag}/state", self.addr, self.login);
let res = reqwest::Client::new()
.put(url)
.json(&FlagMessage { flag: value })
.send()
.await;
match res {
Ok(res) => {
let status = res.status();
if !status.is_success() {
warn!(flag, "Status code is not success: {status}");
}
},
Err(err) => {
error!(flag, "Error: {err}");
}
}
}
}
#[async_trait]
impl OnPresence for HueBridge {
async fn on_presence(&mut self, presence: bool) {
trace!("Bridging presence to hue");
self.set_flag(Flag::Presence, presence).await;
}
}
#[async_trait]
impl OnDarkness for HueBridge {
async fn on_darkness(&mut self, dark: bool) {
trace!("Bridging darkness to hue");
self.set_flag(Flag::Darkness, dark).await;
}
}