use crate::light::{Command, Light, Status, Update, Value}; use crossbeam_channel::RecvTimeoutError; use lifxi::http::prelude::*; use std::time::Duration; pub struct Lifx { client: Client, updates: crossbeam_channel::Sender, commands: crossbeam_channel::Receiver, lights: Vec, } impl Lifx { pub fn new( secret: S, updates: crossbeam_channel::Sender, commands: crossbeam_channel::Receiver, ) -> Self { Lifx { client: Client::new(secret), updates, commands, lights: vec![], } } pub fn get_lights(&self) -> Vec { self.client .select(Selector::All) .list() .send() .unwrap() .json() .unwrap() } pub fn listen(&mut self) { loop { match self.commands.recv_timeout(Duration::from_secs(1)) { Ok(command) => self.handle_command(command), Err(RecvTimeoutError::Disconnected) => return, Err(RecvTimeoutError::Timeout) => {} } self.update_lights(); } } fn update_lights(&mut self) { let new_lights = self.get_lights(); // find changes for new_light in &new_lights { if let Some(old_light) = self.lights.iter().find(|x| new_light.id == x.id) { self.find_diffs(old_light, new_light); } else { self.updates.send(Status::New(new_light.clone())).unwrap(); } } // find removed lamps self.lights .iter() .filter(|o| new_lights.iter().find(|n| n.id == o.id).is_none()) .for_each(|l| { self.updates.send(Status::Remove(l.label.clone())).unwrap(); }); self.lights = new_lights; } fn find_diffs(&self, old_light: &Light, new_light: &Light) { if old_light.power != new_light.power { self.updates .send(Status::Update(Update::new( &new_light.label, Value::Power(new_light.power.clone()), ))) .unwrap(); } if (old_light.brightness - new_light.brightness).abs() < 0.01 { self.updates .send(Status::Update(Update::new( &new_light.label, Value::Brightness(new_light.brightness), ))) .unwrap(); } } fn handle_command(&self, command: Command) { match command.command { Value::Power(val) => self.set_power(command.lampname, val == "on").unwrap(), Value::Brightness(val) => self.set_brightness(command.lampname, val).unwrap(), }; } fn set_power(&self, id: String, state: bool) -> Result<(), lifxi::http::Error> { self.client .select(Selector::Id(id)) .change_state() .power(state) .send() .and(Ok(())) } fn set_brightness(&self, id: String, brightness: f32) -> Result<(), lifxi::http::Error> { self.client .select(Selector::Id(id)) .change_state() .brightness(brightness) .send() .and(Ok(())) } }