lifx-mqtt-bridge/src/lifx.rs
2019-01-20 10:02:44 +01:00

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(()))
}
}