Skip to content

Commit

Permalink
Merge pull request #388 from cr/cr-huecolor
Browse files Browse the repository at this point in the history
Adding Color support for Philips Hue
  • Loading branch information
cr committed May 3, 2016
2 parents 94752f0 + 36098a1 commit fa8181b
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 77 deletions.
70 changes: 0 additions & 70 deletions docs/scripts/huedemo.sh

This file was deleted.

15 changes: 10 additions & 5 deletions src/adapters/philips_hue/hub_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,22 @@ impl HubApi {
structs::parse_json(&res).unwrap() // TODO no unwrap
}

#[allow(dead_code)]
pub fn set_light_color(&self, light_id: &str, hue: u32, sat: u32, val: u32, on: bool) {
pub fn set_light_power(&self, light_id: &str, on: bool) {
let url = format!("lights/{}/state", light_id);
let cmd = json!({ hue: hue, sat: sat, bri: val, on: on });
let cmd = json!({ on: on });
let _ = self.put(&url, &cmd);
}

pub fn set_light_power(&self, light_id: &str, on: bool) {
pub fn set_light_color(&self, light_id: &str, hsv: (u32, u32, u32)) {
let (hue, sat, val) = hsv;
let url = format!("lights/{}/state", light_id);
let cmd = json!({ on: on });
let cmd = json!({ hue: hue, sat: sat, bri: val });
let _ = self.put(&url, &cmd);
}

pub fn set_light_brightness(&self, light_id: &str, bri: u32) {
let url = format!("lights/{}/state", light_id);
let cmd = json!({ bri: bri });
let _ = self.put(&url, &cmd);
}
}
148 changes: 147 additions & 1 deletion src/adapters/philips_hue/lights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub struct Light {
pub get_available_id: Id<Getter>,
pub get_power_id: Id<Getter>,
pub set_power_id: Id<Setter>,
pub get_color_id: Id<Getter>,
pub set_color_id: Id<Setter>,
}

impl Light {
Expand All @@ -45,6 +47,8 @@ impl Light {
get_available_id: create_getter_id("available", &hub_id, &light_id),
get_power_id: create_getter_id("power", &hub_id, &light_id),
set_power_id: create_setter_id("power", &hub_id, &light_id),
get_color_id: create_getter_id("color", &hub_id, &light_id),
set_color_id: create_setter_id("color", &hub_id, &light_id),
}
}
pub fn start(&self) {
Expand All @@ -58,9 +62,12 @@ impl Light {
{
let adapter_id = create_adapter_id();
let status = self.api.lock().unwrap().get_light_status(&self.light_id);

if status.lighttype == "Extended color light" {
info!("New Philips Hue Extended Color Light service for light {} on bridge {}",

info!("New Philips Hue `Extended Color Light` service for light {} on bridge {}",
self.light_id, self.hub_id);

let mut service = Service::empty(self.service_id.clone(), adapter_id.clone());
service.properties.insert(CUSTOM_PROPERTY_MANUFACTURER.to_owned(),
status.manufacturername.to_owned());
Expand Down Expand Up @@ -119,6 +126,104 @@ impl Light {
},
}));

try!(manager.add_getter(Channel {
tags: HashSet::new(),
adapter: adapter_id.clone(),
id: self.get_color_id.clone(),
last_seen: None,
service: self.service_id.clone(),
mechanism: Getter {
kind: ChannelKind::Extension {
vendor: Id::new("[email protected]"),
adapter: Id::new("Philips Hue Adapter"),
kind: Id::new("Color"),
typ: Type::Color,
},
updated: None,
},
}));

try!(manager.add_setter(Channel {
tags: HashSet::new(),
adapter: adapter_id.clone(),
id: self.set_color_id.clone(),
last_seen: None,
service: self.service_id.clone(),
mechanism: Setter {
kind: ChannelKind::Extension {
vendor: Id::new("[email protected]"),
adapter: Id::new("Philips Hue Adapter"),
kind: Id::new("Color"),
typ: Type::Color,
},
updated: None,
},
}));

let mut services_lock = services.lock().unwrap();
services_lock.getters.insert(self.get_available_id.clone(), self.clone());
services_lock.getters.insert(self.get_power_id.clone(), self.clone());
services_lock.setters.insert(self.set_power_id.clone(), self.clone());
services_lock.getters.insert(self.get_color_id.clone(), self.clone());
services_lock.setters.insert(self.set_color_id.clone(), self.clone());

} else if status.lighttype == "Dimmable light" {
info!("New Philips Hue `Dimmable Light` service for light {} on bridge {}",
self.light_id, self.hub_id);
let mut service = Service::empty(self.service_id.clone(), adapter_id.clone());
service.properties.insert(CUSTOM_PROPERTY_MANUFACTURER.to_owned(),
status.manufacturername.to_owned());
service.properties.insert(CUSTOM_PROPERTY_MODEL.to_owned(),
status.modelid.to_owned());
service.properties.insert(CUSTOM_PROPERTY_NAME.to_owned(),
status.name.to_owned());
service.properties.insert(CUSTOM_PROPERTY_TYPE.to_owned(),
"Light/DimmerLight".to_owned());
service.tags.insert(tag_id!("type:Light/DimmerLight"));

try!(manager.add_service(service));

try!(manager.add_getter(Channel {
tags: HashSet::new(),
adapter: adapter_id.clone(),
id: self.get_available_id.clone(),
last_seen: None,
service: self.service_id.clone(),
mechanism: Getter {
kind: ChannelKind::Extension {
vendor: Id::new("[email protected]"),
adapter: Id::new("Philips Hue Adapter"),
kind: Id::new("available"),
typ: Type::OnOff,
},
updated: None,
},
}));

try!(manager.add_getter(Channel {
tags: HashSet::new(),
adapter: adapter_id.clone(),
id: self.get_power_id.clone(),
last_seen: None,
service: self.service_id.clone(),
mechanism: Getter {
kind: ChannelKind::LightOn,
updated: None,
},
}));

try!(manager.add_setter(Channel {
tags: HashSet::new(),
adapter: adapter_id.clone(),
id: self.set_power_id.clone(),
last_seen: None,
service: self.service_id.clone(),
mechanism: Setter {
kind: ChannelKind::LightOn,
updated: None,
},
}));

let mut services_lock = services.lock().unwrap();
services_lock.getters.insert(self.get_available_id.clone(), self.clone());
services_lock.getters.insert(self.get_power_id.clone(), self.clone());
Expand All @@ -145,4 +250,45 @@ impl Light {
self.api.lock().unwrap().set_light_power(&self.light_id, on);
}

#[allow(dead_code)]
pub fn get_brightness(&self) -> f64 {
// Hue API gives brightness value in [0, 254]
let ls = self.api.lock().unwrap().get_light_status(&self.light_id);
ls.state.bri as f64 / 254f64
}

#[allow(dead_code)]
pub fn set_brightness(&self, bri: f64) {
// Hue API takes brightness value in [0, 254]
let bri = bri.max(0f64).min(1f64); // [0,1]

// convert to value space used by Hue
let bri: u32 = (bri * 254f64) as u32;

self.api.lock().unwrap().set_light_brightness(&self.light_id, bri);
}

pub fn get_color(&self) -> (f64, f64, f64) {
// Hue API gives hue angle in [0, 65535], and sat and val in [0, 254]
let ls = self.api.lock().unwrap().get_light_status(&self.light_id);
let hue: f64 = ls.state.hue.unwrap_or(0) as f64 / 65536f64 * 360f64;
let sat: f64 = ls.state.sat.unwrap_or(0) as f64 / 254f64;
let val: f64 = ls.state.bri as f64 / 254f64;
(hue, sat, val)
}

pub fn set_color(&self, hsv: (f64, f64, f64)) {
// Hue API takes hue angle in [0, 65535], and sat and val in [0, 254]
let (hue, sat, val) = hsv;
let hue = ((hue % 360f64) + 360f64) % 360f64; // [0,360)
let sat = sat.max(0f64).min(1f64); // [0,1]
let val = val.max(0f64).min(1f64); // [0,1]

// convert to value space used by Hue
let hue: u32 = (hue * 65536f64 / 360f64) as u32;
let sat: u32 = (sat * 254f64) as u32;
let val: u32 = (val * 254f64) as u32;

self.api.lock().unwrap().set_light_color(&self.light_id, (hue, sat, val));
}
}
18 changes: 17 additions & 1 deletion src/adapters/philips_hue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub mod structs;
use foxbox_taxonomy::api::{ Error, InternalError, User };
use foxbox_taxonomy::manager::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::values::{ OnOff, Type, TypeError, Value };
use foxbox_taxonomy::values::{ Color, OnOff, Type, TypeError, Value };

use std::collections::HashMap;
use std::sync::{ Arc, Mutex };
Expand Down Expand Up @@ -250,6 +250,10 @@ impl<C: Controller> Adapter for PhilipsHueAdapter<C> {
return (id, Ok(Some(Value::OnOff(OnOff::Off))));
}
}
if id == light.get_color_id {
let (h, s, v) = light.get_color();
return (id, Ok(Some(Value::Color(Color::HSV(h, s, v)))));
}

(id.clone(), Err(Error::InternalError(InternalError::NoSuchGetter(id))))
}).collect()
Expand Down Expand Up @@ -277,6 +281,18 @@ impl<C: Controller> Adapter for PhilipsHueAdapter<C> {
}
return (id, Ok(()));
}
if id == light.set_color_id {
match value {
Value::Color(Color::HSV(h, s, v)) => { light.set_color((h, s, v)); },
_ => {
return (id, Err(Error::TypeError(TypeError {
got: value.get_type(),
expected: Type::Color
})));
}
}
return (id, Ok(()));
}

(id.clone(), Err(Error::InternalError(InternalError::NoSuchSetter(id))))
}).collect()
Expand Down
Loading

0 comments on commit fa8181b

Please sign in to comment.