117 lines
3.3 KiB
Rust
117 lines
3.3 KiB
Rust
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<Status>,
|
|
commands: crossbeam_channel::Receiver<Command>,
|
|
lights: Vec<Light>,
|
|
}
|
|
|
|
impl Lifx {
|
|
pub fn new<S: ToString>(
|
|
secret: S,
|
|
updates: crossbeam_channel::Sender<Status>,
|
|
commands: crossbeam_channel::Receiver<Command>,
|
|
) -> Self {
|
|
Lifx {
|
|
client: Client::new(secret),
|
|
updates,
|
|
commands,
|
|
lights: vec![],
|
|
}
|
|
}
|
|
|
|
pub fn get_lights(&self) -> Vec<Light> {
|
|
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(()))
|
|
}
|
|
}
|