From da5037ed3bee7090c950fa124933f9e5e9794d5b Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Wed, 16 Mar 2016 14:49:03 +0100 Subject: [PATCH 01/37] [fxbox/openzwave-adapter] initial commit --- components/openzwave-adapter/.gitignore | 4 ++++ components/openzwave-adapter/Cargo.toml | 7 +++++++ components/openzwave-adapter/src/lib.rs | 8 ++++++++ 3 files changed, 19 insertions(+) create mode 100644 components/openzwave-adapter/.gitignore create mode 100644 components/openzwave-adapter/Cargo.toml create mode 100644 components/openzwave-adapter/src/lib.rs diff --git a/components/openzwave-adapter/.gitignore b/components/openzwave-adapter/.gitignore new file mode 100644 index 00000000..4ddfaa57 --- /dev/null +++ b/components/openzwave-adapter/.gitignore @@ -0,0 +1,4 @@ +target +Cargo.lock +.*.sw* +.cargo diff --git a/components/openzwave-adapter/Cargo.toml b/components/openzwave-adapter/Cargo.toml new file mode 100644 index 00000000..7bb9c6e7 --- /dev/null +++ b/components/openzwave-adapter/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "openzwave-adapter" +version = "0.1.0" +authors = ["Julien Wajsberg "] + +[dependencies] +"openzwave" = { git = "https://github.com/fxbox/openzwave-rust" } diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs new file mode 100644 index 00000000..ec0205ab --- /dev/null +++ b/components/openzwave-adapter/src/lib.rs @@ -0,0 +1,8 @@ +extern crate openzwave; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + } +} From 6c179c0e743aac8185b4a2b2d4771af28c0d5c13 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Wed, 16 Mar 2016 18:40:45 +0100 Subject: [PATCH 02/37] [fxbox/openzwave-adapter] some first code --- components/openzwave-adapter/Cargo.toml | 3 ++ components/openzwave-adapter/src/lib.rs | 44 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/components/openzwave-adapter/Cargo.toml b/components/openzwave-adapter/Cargo.toml index 7bb9c6e7..73105707 100644 --- a/components/openzwave-adapter/Cargo.toml +++ b/components/openzwave-adapter/Cargo.toml @@ -5,3 +5,6 @@ authors = ["Julien Wajsberg "] [dependencies] "openzwave" = { git = "https://github.com/fxbox/openzwave-rust" } +"foxbox_adapters" = { git = "https://github.com/fxbox/adapters" } +"foxbox_taxonomy" = { git = "https://github.com/fxbox/taxonomy", rev = "cb77821" } +transformable_channels = "^0.1" diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index ec0205ab..09b6ac4c 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -1,4 +1,48 @@ extern crate openzwave; +extern crate foxbox_adapters as adapters; +extern crate foxbox_taxonomy as taxonomy; +extern crate transformable_channels; + +use taxonomy::util::Id as TaxId; +use taxonomy::services::{ AdapterId, Getter, Setter }; +use taxonomy::values::{ Value, Range }; +use taxonomy::api::{ ResultMap, Error as TaxError }; +use adapters::adapter::{ AdapterWatchGuard, WatchEvent }; +use transformable_channels::mpsc::ExtSender; + +struct OpenzwaveAdapter { + version: [u32; 4] +} + +impl adapters::adapter::Adapter for OpenzwaveAdapter { + fn id(&self) -> TaxId { + unimplemented!() + } + + fn name(&self) -> &str { + unimplemented!() + } + + fn vendor(&self) -> &str { + unimplemented!() + } + + fn version(&self) -> &[u32; 4] { + &self.version + } + + fn fetch_values(&self, set: Vec>) -> ResultMap, Option, TaxError> { + unimplemented!() + } + + fn send_values(&self, values: Vec<(TaxId, Value)>) -> ResultMap, (), TaxError> { + unimplemented!() + } + + fn register_watch(&self, values: Vec<(TaxId, Option)>, cb: Box>) -> ResultMap, Box, TaxError> { + unimplemented!() + } +} #[cfg(test)] mod tests { From a41445c991557928b4caa148201da4ad765927d5 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Wed, 16 Mar 2016 19:32:13 +0100 Subject: [PATCH 03/37] [fxbox/openzwave-adapter] implementing init --- components/openzwave-adapter/src/lib.rs | 26 +++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 09b6ac4c..6bba29bb 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -7,11 +7,29 @@ use taxonomy::util::Id as TaxId; use taxonomy::services::{ AdapterId, Getter, Setter }; use taxonomy::values::{ Value, Range }; use taxonomy::api::{ ResultMap, Error as TaxError }; -use adapters::adapter::{ AdapterWatchGuard, WatchEvent }; +use adapters::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent }; use transformable_channels::mpsc::ExtSender; struct OpenzwaveAdapter { - version: [u32; 4] + name: String, + vendor: String, + version: [u32; 4], + manager: Box +} + +impl OpenzwaveAdapter { + fn init (manager: &T) -> Result<(), TaxError> { + let adapter = Box::new(OpenzwaveAdapter { + name: String::from("OpenZwave Adapter"), + vendor: String::from("Mozilla"), + version: [1, 0, 0, 0], + manager: Box::new(manager.clone()) + }); + + try!(manager.add_adapter(adapter)); + + Ok(()) + } } impl adapters::adapter::Adapter for OpenzwaveAdapter { @@ -20,11 +38,11 @@ impl adapters::adapter::Adapter for OpenzwaveAdapter { } fn name(&self) -> &str { - unimplemented!() + &self.name } fn vendor(&self) -> &str { - unimplemented!() + &self.vendor } fn version(&self) -> &[u32; 4] { From 95851366c283e006b6309046549fcde0a646f889 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Thu, 17 Mar 2016 18:23:20 +0100 Subject: [PATCH 04/37] [fxbox/openzwave-adapter] add the id impl --- components/openzwave-adapter/src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 6bba29bb..8e6f5d57 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -11,6 +11,7 @@ use adapters::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent }; use transformable_channels::mpsc::ExtSender; struct OpenzwaveAdapter { + id: TaxId, name: String, vendor: String, version: [u32; 4], @@ -19,8 +20,10 @@ struct OpenzwaveAdapter { impl OpenzwaveAdapter { fn init (manager: &T) -> Result<(), TaxError> { + let name = String::from("OpenZwave Adapter"); let adapter = Box::new(OpenzwaveAdapter { - name: String::from("OpenZwave Adapter"), + id: TaxId::new(name.clone()), // replace with &name once we update to latest taxonomy + name: name, vendor: String::from("Mozilla"), version: [1, 0, 0, 0], manager: Box::new(manager.clone()) @@ -34,7 +37,7 @@ impl OpenzwaveAdapter { impl adapters::adapter::Adapter for OpenzwaveAdapter { fn id(&self) -> TaxId { - unimplemented!() + self.id.clone() } fn name(&self) -> &str { From b606cbd00c220468882714717811d9aee7503ed6 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Thu, 24 Mar 2016 11:31:49 -0700 Subject: [PATCH 05/37] [fxbox/openzwave-adapter] first adapter work --- components/openzwave-adapter/Cargo.toml | 5 +- components/openzwave-adapter/src/lib.rs | 71 ++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/components/openzwave-adapter/Cargo.toml b/components/openzwave-adapter/Cargo.toml index 73105707..f9660dad 100644 --- a/components/openzwave-adapter/Cargo.toml +++ b/components/openzwave-adapter/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" authors = ["Julien Wajsberg "] [dependencies] -"openzwave" = { git = "https://github.com/fxbox/openzwave-rust" } -"foxbox_adapters" = { git = "https://github.com/fxbox/adapters" } -"foxbox_taxonomy" = { git = "https://github.com/fxbox/taxonomy", rev = "cb77821" } +openzwave-stateful = { git = "https://github.com/fxbox/openzwave-stateful-rust" } +foxbox_taxonomy = { git = "https://github.com/fxbox/taxonomy.git", rev = "6840677" } transformable_channels = "^0.1" diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 8e6f5d57..6b6f69e8 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -1,5 +1,4 @@ -extern crate openzwave; -extern crate foxbox_adapters as adapters; +extern crate openzwave_stateful as openzwave; extern crate foxbox_taxonomy as taxonomy; extern crate transformable_channels; @@ -7,10 +6,60 @@ use taxonomy::util::Id as TaxId; use taxonomy::services::{ AdapterId, Getter, Setter }; use taxonomy::values::{ Value, Range }; use taxonomy::api::{ ResultMap, Error as TaxError }; -use adapters::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent }; +use taxonomy::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent }; use transformable_channels::mpsc::ExtSender; -struct OpenzwaveAdapter { +use openzwave::InitOptions; +use openzwave::{ ValueGenre, ValueID }; + +use std::error; +use std::fmt; +use std::collections::HashMap; + +#[derive(Debug)] +pub enum OpenzwaveError { + RegisteringError(TaxError), + UnknownError +} + +impl From for OpenzwaveError { + fn from(err: TaxError) -> Self { + OpenzwaveError::RegisteringError(err) + } +} + +impl From<()> for OpenzwaveError { + fn from(_: ()) -> Self { + OpenzwaveError::UnknownError + } +} + +impl fmt::Display for OpenzwaveError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + OpenzwaveError::RegisteringError(ref err) => write!(f, "IO error: {}", err), + OpenzwaveError::UnknownError => write!(f, "Unknown error"), + } + } +} + +impl error::Error for OpenzwaveError { + fn description(&self) -> &str { + match *self { + OpenzwaveError::RegisteringError(ref err) => err.description(), + OpenzwaveError::UnknownError => "Unknown error", + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + OpenzwaveError::RegisteringError(ref err) => Some(err), + OpenzwaveError::UnknownError => None, + } + } +} + +pub struct OpenzwaveAdapter { id: TaxId, name: String, vendor: String, @@ -19,10 +68,10 @@ struct OpenzwaveAdapter { } impl OpenzwaveAdapter { - fn init (manager: &T) -> Result<(), TaxError> { + pub fn init (manager: &T) -> Result<(), OpenzwaveError> { let name = String::from("OpenZwave Adapter"); let adapter = Box::new(OpenzwaveAdapter { - id: TaxId::new(name.clone()), // replace with &name once we update to latest taxonomy + id: TaxId::new(&name), name: name, vendor: String::from("Mozilla"), version: [1, 0, 0, 0], @@ -31,11 +80,17 @@ impl OpenzwaveAdapter { try!(manager.add_adapter(adapter)); + let options = InitOptions { + device: None // TODO we should expose this as a Value + }; + + let ozw = try!(openzwave::init(&options)); + Ok(()) } } -impl adapters::adapter::Adapter for OpenzwaveAdapter { +impl taxonomy::adapter::Adapter for OpenzwaveAdapter { fn id(&self) -> TaxId { self.id.clone() } @@ -56,7 +111,7 @@ impl adapters::adapter::Adapter for OpenzwaveAdapter { unimplemented!() } - fn send_values(&self, values: Vec<(TaxId, Value)>) -> ResultMap, (), TaxError> { + fn send_values(&self, values: HashMap, Value>) -> ResultMap, (), TaxError> { unimplemented!() } From cd76e0f134b2186ac8bae31feeb28f06a95bb38f Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Thu, 24 Mar 2016 16:43:08 -0700 Subject: [PATCH 06/37] [fxbox/openzwave-adapter] starting implementation of handling notifications --- components/openzwave-adapter/src/lib.rs | 80 +++++++++++++++++++++---- 1 file changed, 67 insertions(+), 13 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 6b6f69e8..4cd97173 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -3,18 +3,22 @@ extern crate foxbox_taxonomy as taxonomy; extern crate transformable_channels; use taxonomy::util::Id as TaxId; -use taxonomy::services::{ AdapterId, Getter, Setter }; +use taxonomy::services::{ Setter, Getter, AdapterId, ServiceId, Service, Channel, ChannelKind }; use taxonomy::values::{ Value, Range }; use taxonomy::api::{ ResultMap, Error as TaxError }; use taxonomy::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent }; use transformable_channels::mpsc::ExtSender; -use openzwave::InitOptions; +use openzwave::{ InitOptions, ZWaveManager, ZWaveNotification }; use openzwave::{ ValueGenre, ValueID }; +use openzwave::{ Controller }; use std::error; use std::fmt; -use std::collections::HashMap; +use std::thread; +use std::sync::mpsc; +use std::sync::RwLock; +use std::collections::{ HashMap, HashSet }; #[derive(Debug)] pub enum OpenzwaveError { @@ -64,30 +68,78 @@ pub struct OpenzwaveAdapter { name: String, vendor: String, version: [u32; 4], - manager: Box + ozw: ZWaveManager, } impl OpenzwaveAdapter { - pub fn init (manager: &T) -> Result<(), OpenzwaveError> { + pub fn init (box_manager: &T) -> Result<(), OpenzwaveError> { + let options = InitOptions { + device: None // TODO we should expose this as a Value + }; + + let (ozw, rx) = try!(openzwave::init(&options)); + let name = String::from("OpenZwave Adapter"); let adapter = Box::new(OpenzwaveAdapter { id: TaxId::new(&name), name: name, vendor: String::from("Mozilla"), version: [1, 0, 0, 0], - manager: Box::new(manager.clone()) + ozw: ozw, }); - try!(manager.add_adapter(adapter)); - - let options = InitOptions { - device: None // TODO we should expose this as a Value - }; - - let ozw = try!(openzwave::init(&options)); + adapter.spawn_notification_thread(rx, box_manager); + try!(box_manager.add_adapter(adapter)); Ok(()) } + + fn spawn_notification_thread(&self, rx: mpsc::Receiver, box_manager: &T) { + let adapter_id = self.id.clone(); + let box_manager = box_manager.clone(); + + thread::spawn(move || { + let mut controller_map: Vec<(TaxId, Controller)> = Vec::new(); + + for notification in rx { + match notification { + ZWaveNotification::ControllerReady(controller) => { + let service = format!("OpenZWave/{}", controller.get_home_id()); + let service_id = TaxId::new(&service); + controller_map.push((service_id.clone(), controller)); + + box_manager.add_service(Service::empty(service_id.clone(), adapter_id.clone())); + } + ZWaveNotification::NodeNew(node) => {} + ZWaveNotification::NodeAdded(node) => {} + ZWaveNotification::NodeRemoved(node) => {} + ZWaveNotification::ValueAdded(value) => { + let value_id = format!("OpenZWave/{}", value.get_id()); + let controller_pair = controller_map.iter().find(|&&(_, controller)| controller == value.get_controller()); + if controller_pair.is_none() { continue; } + let ref controller_id = controller_pair.unwrap().0; + + if value.is_read_only() { + box_manager.add_getter(Channel { + id: TaxId::new(&value_id), + service: controller_id.clone(), + adapter: adapter_id.clone(), + last_seen: None, + tags: HashSet::new(), + mechanism: Getter { + kind: ChannelKind::Ready, + updated: None + } + }); + } + } + ZWaveNotification::ValueChanged(value) => {} + ZWaveNotification::ValueRemoved(value) => {} + ZWaveNotification::Generic(string) => {} + } + } + }); + } } impl taxonomy::adapter::Adapter for OpenzwaveAdapter { @@ -108,6 +160,8 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { } fn fetch_values(&self, set: Vec>) -> ResultMap, Option, TaxError> { + let state = self.ozw.get_state(); + unimplemented!() } From 1c952947879c598e5709c1a4e720308c40d7e181 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Thu, 24 Mar 2016 17:38:43 -0700 Subject: [PATCH 07/37] [fxbox/openzwave-adapter] values are defined --- components/openzwave-adapter/src/lib.rs | 74 ++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 4cd97173..d1b112f2 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -10,7 +10,7 @@ use taxonomy::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent }; use transformable_channels::mpsc::ExtSender; use openzwave::{ InitOptions, ZWaveManager, ZWaveNotification }; -use openzwave::{ ValueGenre, ValueID }; +use openzwave::{ CommandClass, ValueGenre, ValueID }; use openzwave::{ Controller }; use std::error; @@ -63,6 +63,34 @@ impl error::Error for OpenzwaveError { } } +struct IdMap { + map: Vec<(TaxId, Type)> +} + +impl IdMap where Type: Eq { + fn new() -> Self { + IdMap { + map: Vec::new() + } + } + + fn push(&mut self, id: TaxId, ozw_object: Type) { + self.map.push((id, ozw_object)) + } + + fn find_tax_id(&mut self, ozw_object: Type) -> Option<&TaxId> { + let find_result = self.map.iter().find(|&&(_, ref controller)| controller == &ozw_object); + find_result.map(|&(ref id, _)| id) + } +} + +fn kind_from_value(value: ValueID) -> Option { + value.get_command_class().map(|cc| match cc { + CommandClass::SensorBinary => ChannelKind::OpenClosed, + _ => ChannelKind::Ready // TODO + }) +} + pub struct OpenzwaveAdapter { id: TaxId, name: String, @@ -99,14 +127,16 @@ impl OpenzwaveAdapter { let box_manager = box_manager.clone(); thread::spawn(move || { - let mut controller_map: Vec<(TaxId, Controller)> = Vec::new(); + let mut controller_map: IdMap = IdMap::new(); + let mut getter_map: IdMap = IdMap::new(); + let mut setter_map: IdMap = IdMap::new(); for notification in rx { match notification { ZWaveNotification::ControllerReady(controller) => { let service = format!("OpenZWave/{}", controller.get_home_id()); let service_id = TaxId::new(&service); - controller_map.push((service_id.clone(), controller)); + controller_map.push(service_id.clone(), controller); box_manager.add_service(Service::empty(service_id.clone(), adapter_id.clone())); } @@ -114,20 +144,46 @@ impl OpenzwaveAdapter { ZWaveNotification::NodeAdded(node) => {} ZWaveNotification::NodeRemoved(node) => {} ZWaveNotification::ValueAdded(value) => { + if value.get_genre() != ValueGenre::ValueGenre_User { continue } + let value_id = format!("OpenZWave/{}", value.get_id()); - let controller_pair = controller_map.iter().find(|&&(_, controller)| controller == value.get_controller()); - if controller_pair.is_none() { continue; } - let ref controller_id = controller_pair.unwrap().0; - if value.is_read_only() { + let controller_id = controller_map.find_tax_id(value.get_controller()); + if controller_id.is_none() { continue } + let controller_id = controller_id.unwrap(); + + let has_getter = !value.is_write_only(); + let has_setter = !value.is_read_only(); + + let kind = kind_from_value(value); + if kind.is_none() { continue } + let kind = kind.unwrap(); + + if has_getter { + let getter_id = TaxId::new(&value_id); box_manager.add_getter(Channel { - id: TaxId::new(&value_id), + id: getter_id.clone(), service: controller_id.clone(), adapter: adapter_id.clone(), last_seen: None, tags: HashSet::new(), mechanism: Getter { - kind: ChannelKind::Ready, + kind: kind.clone(), + updated: None + } + }); + } + + if has_setter { + let setter_id = TaxId::new(&value_id); + box_manager.add_setter(Channel { + id: setter_id.clone(), + service: controller_id.clone(), + adapter: adapter_id.clone(), + last_seen: None, + tags: HashSet::new(), + mechanism: Setter { + kind: kind, updated: None } }); From ff0a8b6d58d34b1c1abaf4539ff6638769314f5b Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Fri, 25 Mar 2016 10:18:46 -0700 Subject: [PATCH 08/37] [fxbox/openzwave-adapter] fetch_values implementation --- components/openzwave-adapter/src/lib.rs | 71 ++++++++++++++++++------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index d1b112f2..ea00bffa 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -4,20 +4,20 @@ extern crate transformable_channels; use taxonomy::util::Id as TaxId; use taxonomy::services::{ Setter, Getter, AdapterId, ServiceId, Service, Channel, ChannelKind }; -use taxonomy::values::{ Value, Range }; -use taxonomy::api::{ ResultMap, Error as TaxError }; +use taxonomy::values::*; +use taxonomy::api::{ ResultMap, Error as TaxError, InternalError }; use taxonomy::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent }; use transformable_channels::mpsc::ExtSender; use openzwave::{ InitOptions, ZWaveManager, ZWaveNotification }; -use openzwave::{ CommandClass, ValueGenre, ValueID }; +use openzwave::{ CommandClass, ValueGenre, ValueType, ValueID }; use openzwave::{ Controller }; use std::error; use std::fmt; use std::thread; use std::sync::mpsc; -use std::sync::RwLock; +use std::sync::{ Arc, RwLock }; use std::collections::{ HashMap, HashSet }; #[derive(Debug)] @@ -63,24 +63,34 @@ impl error::Error for OpenzwaveError { } } +#[derive(Debug, Clone)] struct IdMap { - map: Vec<(TaxId, Type)> + map: Arc, Type)>>> } -impl IdMap where Type: Eq { +impl IdMap where Type: Eq + Clone, Kind: Clone { fn new() -> Self { IdMap { - map: Vec::new() + map: Arc::new(RwLock::new(Vec::new())) } } - fn push(&mut self, id: TaxId, ozw_object: Type) { - self.map.push((id, ozw_object)) + fn push(&mut self, id: TaxId, ozw_object: Type) -> Result<(), ()> { + let mut guard = try!(self.map.write().or(Err(()))); + guard.push((id, ozw_object)); + Ok(()) + } + + fn find_tax_id_from_ozw(&self, needle: &Type) -> Result>, ()> { + let guard = try!(self.map.read().or(Err(()))); + let find_result = guard.iter().find(|&&(_, ref controller)| controller == needle); + Ok(find_result.map(|&(ref id, _)| id.clone())) } - fn find_tax_id(&mut self, ozw_object: Type) -> Option<&TaxId> { - let find_result = self.map.iter().find(|&&(_, ref controller)| controller == &ozw_object); - find_result.map(|&(ref id, _)| id) + fn find_ozw_from_tax_id(&self, needle: &TaxId) -> Result, ()> { + let guard = try!(self.map.read().or(Err(()))); + let find_result = guard.iter().find(|&&(ref id, _)| id == needle); + Ok(find_result.map(|&(_, ref ozw_object)| ozw_object.clone())) } } @@ -97,6 +107,9 @@ pub struct OpenzwaveAdapter { vendor: String, version: [u32; 4], ozw: ZWaveManager, + controller_map: IdMap, + getter_map: IdMap, + setter_map: IdMap, } impl OpenzwaveAdapter { @@ -114,6 +127,9 @@ impl OpenzwaveAdapter { vendor: String::from("Mozilla"), version: [1, 0, 0, 0], ozw: ozw, + controller_map: IdMap::new(), + getter_map: IdMap::new(), + setter_map: IdMap::new(), }); adapter.spawn_notification_thread(rx, box_manager); @@ -125,12 +141,11 @@ impl OpenzwaveAdapter { fn spawn_notification_thread(&self, rx: mpsc::Receiver, box_manager: &T) { let adapter_id = self.id.clone(); let box_manager = box_manager.clone(); + let mut controller_map = self.controller_map.clone(); + let mut getter_map = self.getter_map.clone(); + let mut setter_map = self.setter_map.clone(); thread::spawn(move || { - let mut controller_map: IdMap = IdMap::new(); - let mut getter_map: IdMap = IdMap::new(); - let mut setter_map: IdMap = IdMap::new(); - for notification in rx { match notification { ZWaveNotification::ControllerReady(controller) => { @@ -148,7 +163,7 @@ impl OpenzwaveAdapter { let value_id = format!("OpenZWave/{}", value.get_id()); - let controller_id = controller_map.find_tax_id(value.get_controller()); + let controller_id = controller_map.find_tax_id_from_ozw(&value.get_controller()).unwrap(); if controller_id.is_none() { continue } let controller_id = controller_id.unwrap(); @@ -161,6 +176,7 @@ impl OpenzwaveAdapter { if has_getter { let getter_id = TaxId::new(&value_id); + getter_map.push(getter_id.clone(), value); box_manager.add_getter(Channel { id: getter_id.clone(), service: controller_id.clone(), @@ -176,6 +192,7 @@ impl OpenzwaveAdapter { if has_setter { let setter_id = TaxId::new(&value_id); + setter_map.push(setter_id.clone(), value); box_manager.add_setter(Channel { id: setter_id.clone(), service: controller_id.clone(), @@ -216,9 +233,23 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { } fn fetch_values(&self, set: Vec>) -> ResultMap, Option, TaxError> { - let state = self.ozw.get_state(); - - unimplemented!() + set.iter().map(|id| { + let ozw_value: Option = self.getter_map.find_ozw_from_tax_id(id).unwrap(); + + let ozw_value: Option> = ozw_value.map(|ozw_value: ValueID| { + let result: Option = match ozw_value.get_type() { + ValueType::ValueType_Bool => ozw_value.as_bool().map( + |bool| Value::OpenClosed( + if bool { OpenClosed::Open } else { OpenClosed::Closed } + ) + ).ok(), + _ => Some(Value::Unit) + }; + result + }); + let value_result: Result, TaxError> = ozw_value.ok_or(TaxError::InternalError(InternalError::NoSuchGetter(id.clone()))); + (id.clone(), value_result) + }).collect() } fn send_values(&self, values: HashMap, Value>) -> ResultMap, (), TaxError> { From 284ddfa298117075d5f64913dadeb39d81562d94 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Wed, 30 Mar 2016 14:29:14 +0200 Subject: [PATCH 09/37] [fxbox/openzwave-adapter] Some non-working implementation --- components/openzwave-adapter/src/lib.rs | 62 ++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index ea00bffa..5f8d6624 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -17,7 +17,7 @@ use std::error; use std::fmt; use std::thread; use std::sync::mpsc; -use std::sync::{ Arc, RwLock }; +use std::sync::{ Arc, Mutex, RwLock, Weak }; use std::collections::{ HashMap, HashSet }; #[derive(Debug)] @@ -94,6 +94,38 @@ impl IdMap where Type: Eq + Clone, Kind: Clone { } } +type WatchersMap = HashMap>>>; +struct Watchers { + current_index: usize, + map: Arc> +} + +impl Watchers { + fn new() -> Self { + Watchers { + current_index: 0, + map: Arc::new(Mutex::new(HashMap::new())), + } + } + + fn push(&mut self, watcher: Arc>>) -> WatcherGuard { + let index = self.current_index; + self.current_index += 1; + { + let mut map = self.map.lock(); + map.push(index, watcher); + } + WatcherGuard { + key: index, + map: self.map.clone().downgrade() + } + } + + fn get(&self, index: usize) -> Option<&ExtSender> { + self.map.borrow().get(index) + } +} + fn kind_from_value(value: ValueID) -> Option { value.get_command_class().map(|cc| match cc { CommandClass::SensorBinary => ChannelKind::OpenClosed, @@ -101,6 +133,22 @@ fn kind_from_value(value: ValueID) -> Option { }) } +struct WatcherGuard { + key: usize, + map: Weak>, +} + +impl Drop for WatcherGuard { + fn drop(&mut self) { + let map = self.map.upgrade(); + if map.is_none() { return } + let map = map.unwrap().lock(); + map.remove(self.key); + } +} + +impl AdapterWatchGuard for WatcherGuard {} + pub struct OpenzwaveAdapter { id: TaxId, name: String, @@ -110,6 +158,7 @@ pub struct OpenzwaveAdapter { controller_map: IdMap, getter_map: IdMap, setter_map: IdMap, + watchers: Arc>, } impl OpenzwaveAdapter { @@ -130,6 +179,7 @@ impl OpenzwaveAdapter { controller_map: IdMap::new(), getter_map: IdMap::new(), setter_map: IdMap::new(), + watchers: Arc::new(Mutex::new(Watchers::new())), }); adapter.spawn_notification_thread(rx, box_manager); @@ -257,7 +307,15 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { } fn register_watch(&self, values: Vec<(TaxId, Option)>, cb: Box>) -> ResultMap, Box, TaxError> { - unimplemented!() + let cb = Arc::new(cb); + values.iter().map(|id| { + let watch_guard = { + let mut watchers = self.watchers.lock(); + watchers.push(cb.clone()) + }; + let value_result: Result, TaxError> = Ok(watch_guard); + (id.clone(), value_result) + }).collect() } } From 218f199277b9de45acf269b0ad8bdd2d39ef6e79 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Wed, 30 Mar 2016 17:19:30 +0200 Subject: [PATCH 10/37] [fxbox/openzwave-adapter] first version with register_watch that builds --- components/openzwave-adapter/src/lib.rs | 51 ++++++++++++++++--------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 5f8d6624..fdb8b29e 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -94,10 +94,12 @@ impl IdMap where Type: Eq + Clone, Kind: Clone { } } -type WatchersMap = HashMap>>>; +type SyncExtSender = Mutex>>; +type WatchersMap = HashMap>; struct Watchers { current_index: usize, - map: Arc> + map: Arc>, + getter_map: HashMap, Vec>>, } impl Watchers { @@ -105,24 +107,37 @@ impl Watchers { Watchers { current_index: 0, map: Arc::new(Mutex::new(HashMap::new())), + getter_map: HashMap::new(), } } - fn push(&mut self, watcher: Arc>>) -> WatcherGuard { + fn push(&mut self, tax_id: TaxId, watcher: Arc) -> WatcherGuard { let index = self.current_index; self.current_index += 1; { - let mut map = self.map.lock(); - map.push(index, watcher); + let mut map = self.map.lock().unwrap(); + map.insert(index, watcher.clone()); } + + let entry = self.getter_map.entry(tax_id).or_insert(Vec::new()); + entry.push(Arc::downgrade(&watcher)); + WatcherGuard { key: index, - map: self.map.clone().downgrade() + map: self.map.clone() } } - fn get(&self, index: usize) -> Option<&ExtSender> { - self.map.borrow().get(index) + fn get(&self, index: usize) -> Option> { + let map = self.map.lock().unwrap(); + map.get(&index).cloned() + } + + fn get_from_tax_id(&self, tax_id: &TaxId) -> Option>> { + self.getter_map.get(tax_id).and_then(|vec| { + let vec: Vec<_> = vec.iter().filter_map(|weak_sender| weak_sender.upgrade()).collect(); + if vec.len() == 0 { None } else { Some(vec) } + }) } } @@ -135,15 +150,13 @@ fn kind_from_value(value: ValueID) -> Option { struct WatcherGuard { key: usize, - map: Weak>, + map: Arc>, } impl Drop for WatcherGuard { fn drop(&mut self) { - let map = self.map.upgrade(); - if map.is_none() { return } - let map = map.unwrap().lock(); - map.remove(self.key); + let mut map = self.map.lock().unwrap(); + map.remove(&self.key); } } @@ -170,7 +183,7 @@ impl OpenzwaveAdapter { let (ozw, rx) = try!(openzwave::init(&options)); let name = String::from("OpenZwave Adapter"); - let adapter = Box::new(OpenzwaveAdapter { + let adapter = Arc::new(OpenzwaveAdapter { id: TaxId::new(&name), name: name, vendor: String::from("Mozilla"), @@ -307,13 +320,13 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { } fn register_watch(&self, values: Vec<(TaxId, Option)>, cb: Box>) -> ResultMap, Box, TaxError> { - let cb = Arc::new(cb); - values.iter().map(|id| { + let cb = Arc::new(Mutex::new(cb)); // Mutex is necessary because cb is not Sync. + values.iter().map(|&(ref id, _)| { let watch_guard = { - let mut watchers = self.watchers.lock(); - watchers.push(cb.clone()) + let mut watchers = self.watchers.lock().unwrap(); + watchers.push(id.clone(), cb.clone()) }; - let value_result: Result, TaxError> = Ok(watch_guard); + let value_result: Result, TaxError> = Ok(Box::new(watch_guard)); (id.clone(), value_result) }).collect() } From 8ffa5cd74eff91a664fb57bf2c8333e757a90f9c Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Wed, 30 Mar 2016 17:58:22 +0200 Subject: [PATCH 11/37] [fxbox/openzwave-adapter] Actually implementing the watcher --- components/openzwave-adapter/src/lib.rs | 40 +++++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index fdb8b29e..55e53f24 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -148,6 +148,12 @@ fn kind_from_value(value: ValueID) -> Option { }) } +fn to_open_closed(val: bool) -> Value { + Value::OpenClosed( + if val { OpenClosed::Open } else { OpenClosed::Closed } + ) +} + struct WatcherGuard { key: usize, map: Arc>, @@ -207,6 +213,7 @@ impl OpenzwaveAdapter { let mut controller_map = self.controller_map.clone(); let mut getter_map = self.getter_map.clone(); let mut setter_map = self.setter_map.clone(); + let watchers = self.watchers.clone(); thread::spawn(move || { for notification in rx { @@ -269,7 +276,31 @@ impl OpenzwaveAdapter { }); } } - ZWaveNotification::ValueChanged(value) => {} + ZWaveNotification::ValueChanged(value) => { + match value.get_type() { + ValueType::ValueType_Bool => {}, + _ => continue // ignore non-bool vals for now + }; + + let tax_id = match getter_map.find_tax_id_from_ozw(&value) { + Ok(Some(tax_id)) => tax_id, + _ => continue + }; + + let watchers = watchers.lock().unwrap(); + + let watchers = match watchers.get_from_tax_id(&tax_id) { + Some(watchers) => watchers, + _ => continue + }; + + for sender in &watchers { + let sender = sender.lock().unwrap(); + sender.send( + WatchEvent::Enter { id: tax_id.clone(), value: to_open_closed(value.as_bool().unwrap()) } + ); + } + } ZWaveNotification::ValueRemoved(value) => {} ZWaveNotification::Generic(string) => {} } @@ -301,11 +332,7 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { let ozw_value: Option> = ozw_value.map(|ozw_value: ValueID| { let result: Option = match ozw_value.get_type() { - ValueType::ValueType_Bool => ozw_value.as_bool().map( - |bool| Value::OpenClosed( - if bool { OpenClosed::Open } else { OpenClosed::Closed } - ) - ).ok(), + ValueType::ValueType_Bool => ozw_value.as_bool().map(to_open_closed).ok(), _ => Some(Value::Unit) }; result @@ -338,3 +365,4 @@ mod tests { fn it_works() { } } + From b9710fd82b2e18a2d1dcfe4679b5247169af3780 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Wed, 30 Mar 2016 19:47:52 +0200 Subject: [PATCH 12/37] [fxbox/openzwave-adapter] bumping taxonomy version --- components/openzwave-adapter/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/openzwave-adapter/Cargo.toml b/components/openzwave-adapter/Cargo.toml index f9660dad..33ceefca 100644 --- a/components/openzwave-adapter/Cargo.toml +++ b/components/openzwave-adapter/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Julien Wajsberg "] [dependencies] openzwave-stateful = { git = "https://github.com/fxbox/openzwave-stateful-rust" } -foxbox_taxonomy = { git = "https://github.com/fxbox/taxonomy.git", rev = "6840677" } +foxbox_taxonomy = { git = "https://github.com/fxbox/taxonomy.git", rev = "aa03b11" } transformable_channels = "^0.1" From cd4e23fa0b9e5cad010027d7556d7ca25576ed24 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Thu, 31 Mar 2016 10:00:59 +0200 Subject: [PATCH 13/37] [fxbox/openzwave-adapter] expose the adapter with a simpler name --- components/openzwave-adapter/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 55e53f24..9fd483ca 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -20,6 +20,8 @@ use std::sync::mpsc; use std::sync::{ Arc, Mutex, RwLock, Weak }; use std::collections::{ HashMap, HashSet }; +pub use self::OpenzwaveAdapter as Adapter; + #[derive(Debug)] pub enum OpenzwaveError { RegisteringError(TaxError), From 1f2bc9773b3923567ce5c26315981a22bd79ff01 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Thu, 31 Mar 2016 14:56:51 +0200 Subject: [PATCH 14/37] [fxbox/openzwave-adapter] Send a value when the watch is registered + various other small changes --- components/openzwave-adapter/src/lib.rs | 56 +++++++++++++++++-------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 9fd483ca..3a855990 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -150,10 +150,14 @@ fn kind_from_value(value: ValueID) -> Option { }) } -fn to_open_closed(val: bool) -> Value { - Value::OpenClosed( - if val { OpenClosed::Open } else { OpenClosed::Closed } - ) +fn to_open_closed(value: &ValueID) -> Option { + debug_assert_eq!(value.get_type(), ValueType::ValueType_Bool); + + value.as_bool().ok().map(|val| { + Value::OpenClosed( + if val { OpenClosed::Open } else { OpenClosed::Closed } + ) + }) } struct WatcherGuard { @@ -298,9 +302,11 @@ impl OpenzwaveAdapter { for sender in &watchers { let sender = sender.lock().unwrap(); - sender.send( - WatchEvent::Enter { id: tax_id.clone(), value: to_open_closed(value.as_bool().unwrap()) } - ); + if let Some(value) = to_open_closed(&value) { + sender.send( + WatchEvent::Enter { id: tax_id.clone(), value: value } + ); + } } } ZWaveNotification::ValueRemoved(value) => {} @@ -328,19 +334,21 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { &self.version } - fn fetch_values(&self, set: Vec>) -> ResultMap, Option, TaxError> { - set.iter().map(|id| { - let ozw_value: Option = self.getter_map.find_ozw_from_tax_id(id).unwrap(); + fn fetch_values(&self, mut set: Vec>) -> ResultMap, Option, TaxError> { + set.drain(..).map(|id| { + let ozw_value: Option = self.getter_map.find_ozw_from_tax_id(&id).unwrap(); //FIXME no unwrap let ozw_value: Option> = ozw_value.map(|ozw_value: ValueID| { + if !ozw_value.is_set() { return None } + let result: Option = match ozw_value.get_type() { - ValueType::ValueType_Bool => ozw_value.as_bool().map(to_open_closed).ok(), + ValueType::ValueType_Bool => to_open_closed(&ozw_value), _ => Some(Value::Unit) }; result }); let value_result: Result, TaxError> = ozw_value.ok_or(TaxError::InternalError(InternalError::NoSuchGetter(id.clone()))); - (id.clone(), value_result) + (id, value_result) }).collect() } @@ -348,15 +356,29 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { unimplemented!() } - fn register_watch(&self, values: Vec<(TaxId, Option)>, cb: Box>) -> ResultMap, Box, TaxError> { - let cb = Arc::new(Mutex::new(cb)); // Mutex is necessary because cb is not Sync. - values.iter().map(|&(ref id, _)| { + fn register_watch(&self, mut values: Vec<(TaxId, Option)>, sender: Box>) -> ResultMap, Box, TaxError> { + let sender = Arc::new(Mutex::new(sender)); // Mutex is necessary because cb is not Sync. + values.drain(..).map(|(id, _)| { let watch_guard = { let mut watchers = self.watchers.lock().unwrap(); - watchers.push(id.clone(), cb.clone()) + watchers.push(id.clone(), sender.clone()) }; let value_result: Result, TaxError> = Ok(Box::new(watch_guard)); - (id.clone(), value_result) + + // if there is a set value already, let's send it. + let ozw_value: Option = self.getter_map.find_ozw_from_tax_id(&id).unwrap(); // FIXME no unwrap + if let Some(value) = ozw_value { + if value.is_set() && value.get_type() == ValueType::ValueType_Bool { + if let Some(value) = to_open_closed(&value) { + let sender = sender.lock().unwrap(); + sender.send( + WatchEvent::Enter { id: id.clone(), value: value } + ); + } + } + } + + (id, value_result) }).collect() } } From eefe670ec218ad1d1375cda314709f71f635e6f6 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Fri, 1 Apr 2016 17:18:15 +0200 Subject: [PATCH 15/37] [fxbox/openzwave-adapter] upgrade to newer taxonomy --- components/openzwave-adapter/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/openzwave-adapter/Cargo.toml b/components/openzwave-adapter/Cargo.toml index 33ceefca..0a0703e5 100644 --- a/components/openzwave-adapter/Cargo.toml +++ b/components/openzwave-adapter/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Julien Wajsberg "] [dependencies] openzwave-stateful = { git = "https://github.com/fxbox/openzwave-stateful-rust" } -foxbox_taxonomy = { git = "https://github.com/fxbox/taxonomy.git", rev = "aa03b11" } +foxbox_taxonomy = { git = "https://github.com/fxbox/taxonomy.git", rev = "8cad391" } transformable_channels = "^0.1" From 15de62c1086c33beac61a25f31982536df41f673 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Fri, 1 Apr 2016 17:53:09 +0200 Subject: [PATCH 16/37] [fxbox/openzwave-adapter] improved error handling --- components/openzwave-adapter/src/lib.rs | 38 ++++++++++++++++--------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 3a855990..1d2094d3 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -23,44 +23,54 @@ use std::collections::{ HashMap, HashSet }; pub use self::OpenzwaveAdapter as Adapter; #[derive(Debug)] -pub enum OpenzwaveError { - RegisteringError(TaxError), +pub enum Error { + TaxonomyError(TaxError), + OpenzwaveError(openzwave::Error), UnknownError } -impl From for OpenzwaveError { +impl From for Error { fn from(err: TaxError) -> Self { - OpenzwaveError::RegisteringError(err) + Error::TaxonomyError(err) } } -impl From<()> for OpenzwaveError { +impl From<()> for Error { fn from(_: ()) -> Self { - OpenzwaveError::UnknownError + Error::UnknownError } } -impl fmt::Display for OpenzwaveError { +impl From for Error { + fn from(error: openzwave::Error) -> Self { + Error::OpenzwaveError(error) + } +} + +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - OpenzwaveError::RegisteringError(ref err) => write!(f, "IO error: {}", err), - OpenzwaveError::UnknownError => write!(f, "Unknown error"), + Error::TaxonomyError(ref err) => write!(f, "{}: {}", error::Error::description(self), err), + Error::OpenzwaveError(ref err) => write!(f, "{}: {}", error::Error::description(self), err), + Error::UnknownError => write!(f, "{}", error::Error::description(self)), } } } -impl error::Error for OpenzwaveError { +impl error::Error for Error { fn description(&self) -> &str { match *self { - OpenzwaveError::RegisteringError(ref err) => err.description(), - OpenzwaveError::UnknownError => "Unknown error", + Error::TaxonomyError(_) => "Taxonomy Error", + Error::OpenzwaveError(_) => "Openzwave Error", + Error::UnknownError => "Unknown error", } } fn cause(&self) -> Option<&error::Error> { match *self { - OpenzwaveError::RegisteringError(ref err) => Some(err), - OpenzwaveError::UnknownError => None, + Error::TaxonomyError(ref err) => Some(err), + Error::OpenzwaveError(ref err) => Some(err), + Error::UnknownError => None, } } } From 71eaa0527b546635f69a138ae42a2b0370564cac Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Fri, 1 Apr 2016 17:53:45 +0200 Subject: [PATCH 17/37] [fxbox/openzwave-adapter] adapt to latest foxbox code --- components/openzwave-adapter/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 1d2094d3..33b5800e 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -197,7 +197,7 @@ pub struct OpenzwaveAdapter { } impl OpenzwaveAdapter { - pub fn init (box_manager: &T) -> Result<(), OpenzwaveError> { + pub fn init (box_manager: &Arc) -> Result<(), Error> { let options = InitOptions { device: None // TODO we should expose this as a Value }; @@ -223,7 +223,7 @@ impl OpenzwaveAdapter { Ok(()) } - fn spawn_notification_thread(&self, rx: mpsc::Receiver, box_manager: &T) { + fn spawn_notification_thread(&self, rx: mpsc::Receiver, box_manager: &Arc) { let adapter_id = self.id.clone(); let box_manager = box_manager.clone(); let mut controller_map = self.controller_map.clone(); From 0683847299da78587994a68dd0536eaf88328aac Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Fri, 1 Apr 2016 18:40:21 +0200 Subject: [PATCH 18/37] [fxbox/openzwave-adapter] expose the "no device found" error in a nicer way --- components/openzwave-adapter/src/lib.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 33b5800e..926566e8 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -25,6 +25,7 @@ pub use self::OpenzwaveAdapter as Adapter; #[derive(Debug)] pub enum Error { TaxonomyError(TaxError), + NoDeviceFound(openzwave::Error), OpenzwaveError(openzwave::Error), UnknownError } @@ -43,7 +44,10 @@ impl From<()> for Error { impl From for Error { fn from(error: openzwave::Error) -> Self { - Error::OpenzwaveError(error) + match error { + openzwave::Error::NoDeviceFound => Error::NoDeviceFound(error), + _ => Error::OpenzwaveError(error) + } } } @@ -52,7 +56,7 @@ impl fmt::Display for Error { match *self { Error::TaxonomyError(ref err) => write!(f, "{}: {}", error::Error::description(self), err), Error::OpenzwaveError(ref err) => write!(f, "{}: {}", error::Error::description(self), err), - Error::UnknownError => write!(f, "{}", error::Error::description(self)), + Error::NoDeviceFound(_) | Error::UnknownError => write!(f, "{}", error::Error::description(self)), } } } @@ -62,6 +66,7 @@ impl error::Error for Error { match *self { Error::TaxonomyError(_) => "Taxonomy Error", Error::OpenzwaveError(_) => "Openzwave Error", + Error::NoDeviceFound(_) => "No Device Found", Error::UnknownError => "Unknown error", } } @@ -70,6 +75,7 @@ impl error::Error for Error { match *self { Error::TaxonomyError(ref err) => Some(err), Error::OpenzwaveError(ref err) => Some(err), + Error::NoDeviceFound(ref err) => Some(err), Error::UnknownError => None, } } From b4cc0fd84e5065cab4bb2e7768e5ee9ed311947f Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Fri, 1 Apr 2016 19:44:23 +0200 Subject: [PATCH 19/37] [fxbox/openzwave-adapter] Specify config paths to openzwave::init --- components/openzwave-adapter/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 926566e8..1b484e6e 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -205,7 +205,9 @@ pub struct OpenzwaveAdapter { impl OpenzwaveAdapter { pub fn init (box_manager: &Arc) -> Result<(), Error> { let options = InitOptions { - device: None // TODO we should expose this as a Value + device: None, // TODO we should expose this as a Value + config_path: "./config/openzwave/".to_string(), + user_path: "./config/openzwave/".to_string(), }; let (ozw, rx) = try!(openzwave::init(&options)); From 235d52061cd19aaca3e56e5b58d429d852dc9e63 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Mon, 4 Apr 2016 16:02:35 +0200 Subject: [PATCH 20/37] [fxbox/openzwave-adapter] do not expose the DeviceNotFound error to the caller anymore --- components/openzwave-adapter/Cargo.toml | 1 + components/openzwave-adapter/src/lib.rs | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/components/openzwave-adapter/Cargo.toml b/components/openzwave-adapter/Cargo.toml index 0a0703e5..b1707c26 100644 --- a/components/openzwave-adapter/Cargo.toml +++ b/components/openzwave-adapter/Cargo.toml @@ -7,3 +7,4 @@ authors = ["Julien Wajsberg "] openzwave-stateful = { git = "https://github.com/fxbox/openzwave-stateful-rust" } foxbox_taxonomy = { git = "https://github.com/fxbox/taxonomy.git", rev = "8cad391" } transformable_channels = "^0.1" +log = "^0.3" diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 1b484e6e..1b4fc8d8 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -1,6 +1,8 @@ extern crate openzwave_stateful as openzwave; extern crate foxbox_taxonomy as taxonomy; extern crate transformable_channels; +#[macro_use] +extern crate log; use taxonomy::util::Id as TaxId; use taxonomy::services::{ Setter, Getter, AdapterId, ServiceId, Service, Channel, ChannelKind }; @@ -25,7 +27,6 @@ pub use self::OpenzwaveAdapter as Adapter; #[derive(Debug)] pub enum Error { TaxonomyError(TaxError), - NoDeviceFound(openzwave::Error), OpenzwaveError(openzwave::Error), UnknownError } @@ -44,10 +45,7 @@ impl From<()> for Error { impl From for Error { fn from(error: openzwave::Error) -> Self { - match error { - openzwave::Error::NoDeviceFound => Error::NoDeviceFound(error), - _ => Error::OpenzwaveError(error) - } + Error::OpenzwaveError(error) } } @@ -56,7 +54,7 @@ impl fmt::Display for Error { match *self { Error::TaxonomyError(ref err) => write!(f, "{}: {}", error::Error::description(self), err), Error::OpenzwaveError(ref err) => write!(f, "{}: {}", error::Error::description(self), err), - Error::NoDeviceFound(_) | Error::UnknownError => write!(f, "{}", error::Error::description(self)), + Error::UnknownError => write!(f, "{}", error::Error::description(self)), } } } @@ -66,7 +64,6 @@ impl error::Error for Error { match *self { Error::TaxonomyError(_) => "Taxonomy Error", Error::OpenzwaveError(_) => "Openzwave Error", - Error::NoDeviceFound(_) => "No Device Found", Error::UnknownError => "Unknown error", } } @@ -75,7 +72,6 @@ impl error::Error for Error { match *self { Error::TaxonomyError(ref err) => Some(err), Error::OpenzwaveError(ref err) => Some(err), - Error::NoDeviceFound(ref err) => Some(err), Error::UnknownError => None, } } @@ -210,7 +206,15 @@ impl OpenzwaveAdapter { user_path: "./config/openzwave/".to_string(), }; - let (ozw, rx) = try!(openzwave::init(&options)); + let (ozw, rx) = try!(match openzwave::init(&options) { + Err(openzwave::Error::NoDeviceFound) => { + // early return: we should not impair foxbox startup for this error. + // TODO concept of FatalError vs IgnoreableError + error!("No ZWave device has been found."); + return Ok(()); + } + result => result + }); let name = String::from("OpenZwave Adapter"); let adapter = Arc::new(OpenzwaveAdapter { From 8210bbab7ed63dbc2dfd337bc4e7c353dc42b124 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Mon, 4 Apr 2016 16:16:51 +0200 Subject: [PATCH 21/37] [fxbox/openzwave-adapter] Output a log when the openzwave adapter started --- components/openzwave-adapter/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 1b4fc8d8..5d040e8d 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -232,6 +232,8 @@ impl OpenzwaveAdapter { adapter.spawn_notification_thread(rx, box_manager); try!(box_manager.add_adapter(adapter)); + info!("Started Openzwave adapter."); + Ok(()) } From 187e7f7934b755e417b35e923b09af0f315589af Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Mon, 4 Apr 2016 16:09:36 +0200 Subject: [PATCH 22/37] [fxbox/openzwave-adapter] add some more information to the id so that we know which channel is what --- components/openzwave-adapter/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 5d040e8d..4ddea569 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -261,7 +261,7 @@ impl OpenzwaveAdapter { ZWaveNotification::ValueAdded(value) => { if value.get_genre() != ValueGenre::ValueGenre_User { continue } - let value_id = format!("OpenZWave/{}", value.get_id()); + let value_id = format!("OpenZWave/{} ({})", value.get_id(), value.get_label()); let controller_id = controller_map.find_tax_id_from_ozw(&value.get_controller()).unwrap(); if controller_id.is_none() { continue } From 197b172111595c3fee0de0f7f104dcf46c23d5b1 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Thu, 31 Mar 2016 16:23:29 +0200 Subject: [PATCH 23/37] [fxbox/openzwave-adapter] adapt to latest taxonomy --- components/openzwave-adapter/Cargo.toml | 2 +- components/openzwave-adapter/src/lib.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/openzwave-adapter/Cargo.toml b/components/openzwave-adapter/Cargo.toml index b1707c26..2699f6c7 100644 --- a/components/openzwave-adapter/Cargo.toml +++ b/components/openzwave-adapter/Cargo.toml @@ -5,6 +5,6 @@ authors = ["Julien Wajsberg "] [dependencies] openzwave-stateful = { git = "https://github.com/fxbox/openzwave-stateful-rust" } -foxbox_taxonomy = { git = "https://github.com/fxbox/taxonomy.git", rev = "8cad391" } +foxbox_taxonomy = { git = "https://github.com/fxbox/taxonomy.git", rev = "c222794d238072920857fea55e55d522ae75c192" } transformable_channels = "^0.1" log = "^0.3" diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 4ddea569..ffcd0690 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -7,7 +7,7 @@ extern crate log; use taxonomy::util::Id as TaxId; use taxonomy::services::{ Setter, Getter, AdapterId, ServiceId, Service, Channel, ChannelKind }; use taxonomy::values::*; -use taxonomy::api::{ ResultMap, Error as TaxError, InternalError }; +use taxonomy::api::{ ResultMap, Error as TaxError, InternalError, User }; use taxonomy::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent }; use transformable_channels::mpsc::ExtSender; @@ -358,7 +358,7 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { &self.version } - fn fetch_values(&self, mut set: Vec>) -> ResultMap, Option, TaxError> { + fn fetch_values(&self, mut set: Vec>, _: User) -> ResultMap, Option, TaxError> { set.drain(..).map(|id| { let ozw_value: Option = self.getter_map.find_ozw_from_tax_id(&id).unwrap(); //FIXME no unwrap @@ -376,7 +376,7 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { }).collect() } - fn send_values(&self, values: HashMap, Value>) -> ResultMap, (), TaxError> { + fn send_values(&self, values: HashMap, Value>, _: User) -> ResultMap, (), TaxError> { unimplemented!() } From 90b9a0fbdefdccd5b28acdaddbde2ffece5763f9 Mon Sep 17 00:00:00 2001 From: David Rajchenbach-Teller Date: Thu, 7 Apr 2016 18:37:21 +0200 Subject: [PATCH 24/37] [fxbox/openzwave-adapter] Unpinning Taxonomy --- components/openzwave-adapter/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/openzwave-adapter/Cargo.toml b/components/openzwave-adapter/Cargo.toml index 2699f6c7..e56d9ae0 100644 --- a/components/openzwave-adapter/Cargo.toml +++ b/components/openzwave-adapter/Cargo.toml @@ -5,6 +5,6 @@ authors = ["Julien Wajsberg "] [dependencies] openzwave-stateful = { git = "https://github.com/fxbox/openzwave-stateful-rust" } -foxbox_taxonomy = { git = "https://github.com/fxbox/taxonomy.git", rev = "c222794d238072920857fea55e55d522ae75c192" } +foxbox_taxonomy = { git = "https://github.com/fxbox/taxonomy.git" } transformable_channels = "^0.1" log = "^0.3" From 7828425e2858c21903526a76425537cf7e89de22 Mon Sep 17 00:00:00 2001 From: David Rajchenbach-Teller Date: Thu, 7 Apr 2016 18:45:54 +0200 Subject: [PATCH 25/37] [fxbox/openzwave-adapter] Warning when a notification is not handled --- components/openzwave-adapter/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index ffcd0690..9a9300ab 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -335,6 +335,7 @@ impl OpenzwaveAdapter { } ZWaveNotification::ValueRemoved(value) => {} ZWaveNotification::Generic(string) => {} + other => { warn!("Notification not handled {:?}", other)} } } }); From bb003480700f812fbbaee00620f49d73c07d776e Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Thu, 7 Apr 2016 19:53:16 +0200 Subject: [PATCH 26/37] [fxbox/openzwave-adapter] use references instead of owned objects --- components/openzwave-adapter/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 9a9300ab..60e7fbba 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -202,8 +202,8 @@ impl OpenzwaveAdapter { pub fn init (box_manager: &Arc) -> Result<(), Error> { let options = InitOptions { device: None, // TODO we should expose this as a Value - config_path: "./config/openzwave/".to_string(), - user_path: "./config/openzwave/".to_string(), + config_path: "./config/openzwave/", + user_path: "./config/openzwave/", }; let (ozw, rx) = try!(match openzwave::init(&options) { From 2cc545b5635015f33d5cb58c3ee0d481cf7544ea Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Thu, 7 Apr 2016 19:50:16 +0200 Subject: [PATCH 27/37] [fxbox/openzwave-adapter] Take profile from parameters and use the default configuration path --- components/openzwave-adapter/src/lib.rs | 40 +++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 60e7fbba..4a55f629 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -11,12 +11,14 @@ use taxonomy::api::{ ResultMap, Error as TaxError, InternalError, User }; use taxonomy::adapter::{ AdapterManagerHandle, AdapterWatchGuard, WatchEvent }; use transformable_channels::mpsc::ExtSender; -use openzwave::{ InitOptions, ZWaveManager, ZWaveNotification }; +use openzwave::{ ConfigPath, InitOptions, ZWaveManager, ZWaveNotification }; use openzwave::{ CommandClass, ValueGenre, ValueType, ValueID }; use openzwave::{ Controller }; use std::error; use std::fmt; +use std::{ fs, io }; +use std::path::Path; use std::thread; use std::sync::mpsc; use std::sync::{ Arc, Mutex, RwLock, Weak }; @@ -27,6 +29,7 @@ pub use self::OpenzwaveAdapter as Adapter; #[derive(Debug)] pub enum Error { TaxonomyError(TaxError), + IOError(io::Error), OpenzwaveError(openzwave::Error), UnknownError } @@ -49,11 +52,18 @@ impl From for Error { } } +impl From for Error { + fn from(error: io::Error) -> Self { + Error::IOError(error) + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::TaxonomyError(ref err) => write!(f, "{}: {}", error::Error::description(self), err), Error::OpenzwaveError(ref err) => write!(f, "{}: {}", error::Error::description(self), err), + Error::IOError(ref err) => write!(f, "{}: {}", error::Error::description(self), err), Error::UnknownError => write!(f, "{}", error::Error::description(self)), } } @@ -64,6 +74,7 @@ impl error::Error for Error { match *self { Error::TaxonomyError(_) => "Taxonomy Error", Error::OpenzwaveError(_) => "Openzwave Error", + Error::IOError(_) => "I/O Error", Error::UnknownError => "Unknown error", } } @@ -72,6 +83,7 @@ impl error::Error for Error { match *self { Error::TaxonomyError(ref err) => Some(err), Error::OpenzwaveError(ref err) => Some(err), + Error::IOError(ref err) => Some(err), Error::UnknownError => None, } } @@ -198,12 +210,30 @@ pub struct OpenzwaveAdapter { watchers: Arc>, } +fn ensure_directory + ?Sized>(directory: &T) -> Result<(), Error> { + let path = directory.as_ref(); + if path.exists() && !path.is_dir() { + return Err( + Error::IOError(io::Error::new(io::ErrorKind::AlreadyExists, format!("The file {} already exists and isn't a directory.", path.display()))) + ); + } + + if !path.exists() { + try!(fs::create_dir(path)); + } + + Ok(()) +} + impl OpenzwaveAdapter { - pub fn init (box_manager: &Arc) -> Result<(), Error> { + pub fn init (box_manager: &Arc, user_path: &str) -> Result<(), Error> { + + try!(ensure_directory(user_path)); + let options = InitOptions { device: None, // TODO we should expose this as a Value - config_path: "./config/openzwave/", - user_path: "./config/openzwave/", + config_path: ConfigPath::Default, // This is where the default system configuraton is, usually contains the device information. + user_path: user_path, // This is where we can override the system configuration, and where the network layout and logs are stored. }; let (ozw, rx) = try!(match openzwave::init(&options) { @@ -335,7 +365,7 @@ impl OpenzwaveAdapter { } ZWaveNotification::ValueRemoved(value) => {} ZWaveNotification::Generic(string) => {} - other => { warn!("Notification not handled {:?}", other)} + _ => {} } } }); From 82d66ca8e6b09560a069e9a37050b71a25899646 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Mon, 11 Apr 2016 19:44:18 +0200 Subject: [PATCH 28/37] [fxbox/openzwave-adapter] Consume Ranges and send Exit events and adapt to the new taxonomy API --- components/openzwave-adapter/src/lib.rs | 114 +++++++++++++++++++----- 1 file changed, 94 insertions(+), 20 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 4a55f629..232a78b8 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -120,12 +120,39 @@ impl IdMap where Type: Eq + Clone, Kind: Clone { } } -type SyncExtSender = Mutex>>; -type WatchersMap = HashMap>; +#[derive(Debug, Copy, Clone, PartialEq)] +enum SendDirection { + Enter, + Exit, +} + +trait RangeChecker { + fn should_send(&self, &Value, SendDirection) -> bool; +} + +impl RangeChecker for Option { + fn should_send(&self, value: &Value, direction: SendDirection) -> bool { + match *self { + None => direction == SendDirection::Enter, // no range means we send only Enter events + Some(ref range) => range.contains(value) + } + } +} + +impl RangeChecker for Range { + fn should_send(&self, value: &Value, _: SendDirection) -> bool { + self.contains(value) + } +} + +type SyncSender = Mutex>>; +type WatchersMap = HashMap>; +type RangedWeakSender = (Option, Weak); +type RangedSyncSender = (Option, Arc); struct Watchers { current_index: usize, map: Arc>, - getter_map: HashMap, Vec>>, + getter_map: HashMap, Vec>, } impl Watchers { @@ -137,7 +164,7 @@ impl Watchers { } } - fn push(&mut self, tax_id: TaxId, watcher: Arc) -> WatcherGuard { + fn push(&mut self, tax_id: TaxId, range: Option, watcher: Arc) -> WatcherGuard { let index = self.current_index; self.current_index += 1; { @@ -146,7 +173,7 @@ impl Watchers { } let entry = self.getter_map.entry(tax_id).or_insert(Vec::new()); - entry.push(Arc::downgrade(&watcher)); + entry.push((range, Arc::downgrade(&watcher))); WatcherGuard { key: index, @@ -154,14 +181,17 @@ impl Watchers { } } - fn get(&self, index: usize) -> Option> { + fn get(&self, index: usize) -> Option> { let map = self.map.lock().unwrap(); map.get(&index).cloned() } - fn get_from_tax_id(&self, tax_id: &TaxId) -> Option>> { + fn get_from_tax_id(&self, tax_id: &TaxId) -> Option> { self.getter_map.get(tax_id).and_then(|vec| { - let vec: Vec<_> = vec.iter().filter_map(|weak_sender| weak_sender.upgrade()).collect(); + let vec: Vec<_> = vec.iter().filter_map(|&(ref range, ref weak_sender)| { + let range = range.clone(); + weak_sender.upgrade().map(|sender| (range, sender)) + }).collect(); if vec.len() == 0 { None } else { Some(vec) } }) } @@ -198,6 +228,8 @@ impl Drop for WatcherGuard { impl AdapterWatchGuard for WatcherGuard {} +type ValueCache = HashMap, Value>; + pub struct OpenzwaveAdapter { id: TaxId, name: String, @@ -208,6 +240,7 @@ pub struct OpenzwaveAdapter { getter_map: IdMap, setter_map: IdMap, watchers: Arc>, + value_cache: Arc>, } fn ensure_directory + ?Sized>(directory: &T) -> Result<(), Error> { @@ -257,6 +290,7 @@ impl OpenzwaveAdapter { getter_map: IdMap::new(), setter_map: IdMap::new(), watchers: Arc::new(Mutex::new(Watchers::new())), + value_cache: Arc::new(Mutex::new(HashMap::new())), }); adapter.spawn_notification_thread(rx, box_manager); @@ -274,9 +308,11 @@ impl OpenzwaveAdapter { let mut getter_map = self.getter_map.clone(); let mut setter_map = self.setter_map.clone(); let watchers = self.watchers.clone(); + let value_cache = self.value_cache.clone(); thread::spawn(move || { for notification in rx { + //debug!("Received notification {:?}", notification); match notification { ZWaveNotification::ControllerReady(controller) => { let service = format!("OpenZWave/{}", controller.get_home_id()); @@ -347,6 +383,11 @@ impl OpenzwaveAdapter { _ => continue }; + let value = match to_open_closed(&value) { + Some(value) => value, + _ => continue + }; + let watchers = watchers.lock().unwrap(); let watchers = match watchers.get_from_tax_id(&tax_id) { @@ -354,11 +395,38 @@ impl OpenzwaveAdapter { _ => continue }; - for sender in &watchers { - let sender = sender.lock().unwrap(); - if let Some(value) = to_open_closed(&value) { + let previous_value = { + let mut cache = value_cache.lock().unwrap(); + let previous = cache.get(&tax_id).cloned(); + cache.insert(tax_id.clone(), value.clone()); + previous + }; + + for &(ref range, ref sender) in &watchers { + debug!("Openzwave::Adapter::ValueChanged iterate over watcher {:?} {:?}", tax_id, range); + + let should_send_value = range.should_send(&value, SendDirection::Enter); + + if let Some(ref previous_value) = previous_value { + let should_send_previous = range.should_send(previous_value, SendDirection::Exit); + // If the new and the old values are both in the same range, we + // need to send nothing. + if should_send_value && should_send_previous { continue } + + if should_send_previous { + debug!("Openzwave::Adapter::ValueChanged Sending event Exit {:?} {:?}", tax_id, value); + let sender = sender.lock().unwrap(); + sender.send( + WatchEvent::Exit { id: tax_id.clone(), value: value.clone() } + ); + } + } + + if should_send_value { + debug!("Openzwave::Adapter::ValueChanged Sending event Enter {:?} {:?}", tax_id, value); + let sender = sender.lock().unwrap(); sender.send( - WatchEvent::Enter { id: tax_id.clone(), value: value } + WatchEvent::Enter { id: tax_id.clone(), value: value.clone() } ); } } @@ -411,12 +479,14 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { unimplemented!() } - fn register_watch(&self, mut values: Vec<(TaxId, Option)>, sender: Box>) -> ResultMap, Box, TaxError> { - let sender = Arc::new(Mutex::new(sender)); // Mutex is necessary because cb is not Sync. - values.drain(..).map(|(id, _)| { + fn register_watch(&self, mut values: Vec<(TaxId, Option, Box>)>) -> Vec<(TaxId, Result, TaxError>)> { + debug!("Openzwave::Adapter::register_watch Should register some watchers"); + values.drain(..).map(|(id, range, sender)| { + let sender = Arc::new(Mutex::new(sender)); // Mutex is necessary because cb is not Sync. + debug!("Openzwave::Adapter::register_watch Should register a watcher for {:?} {:?}", id, range); let watch_guard = { let mut watchers = self.watchers.lock().unwrap(); - watchers.push(id.clone(), sender.clone()) + watchers.push(id.clone(), range.clone(), sender.clone()) }; let value_result: Result, TaxError> = Ok(Box::new(watch_guard)); @@ -425,10 +495,14 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { if let Some(value) = ozw_value { if value.is_set() && value.get_type() == ValueType::ValueType_Bool { if let Some(value) = to_open_closed(&value) { - let sender = sender.lock().unwrap(); - sender.send( - WatchEvent::Enter { id: id.clone(), value: value } - ); + self.value_cache.lock().unwrap().insert(id.clone(), value.clone()); + if range.should_send(&value, SendDirection::Enter) { + debug!("Openzwave::Adapter::register_watch Sending event Enter {:?} {:?}", id, value); + let sender = sender.lock().unwrap(); + sender.send( + WatchEvent::Enter { id: id.clone(), value: value } + ); + } } } } From 12aa30c435a105e07f0da12de4ecb2b1445528d8 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Fri, 8 Apr 2016 15:45:37 -0700 Subject: [PATCH 29/37] [fxbox/openzwave-adapter] Change home-id and value-id to be hex This also puts the home-id into the getter id since the valueids are only unique within the controller. --- components/openzwave-adapter/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 232a78b8..88f3b32e 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -315,7 +315,7 @@ impl OpenzwaveAdapter { //debug!("Received notification {:?}", notification); match notification { ZWaveNotification::ControllerReady(controller) => { - let service = format!("OpenZWave/{}", controller.get_home_id()); + let service = format!("OpenZWave-{:08x}", controller.get_home_id()); let service_id = TaxId::new(&service); controller_map.push(service_id.clone(), controller); @@ -327,7 +327,7 @@ impl OpenzwaveAdapter { ZWaveNotification::ValueAdded(value) => { if value.get_genre() != ValueGenre::ValueGenre_User { continue } - let value_id = format!("OpenZWave/{} ({})", value.get_id(), value.get_label()); + let value_id = format!("OpenZWave-{:08x}-{:016x} ({})", value.get_home_id(), value.get_id(), value.get_label()); let controller_id = controller_map.find_tax_id_from_ozw(&value.get_controller()).unwrap(); if controller_id.is_none() { continue } From e5ecd9ef83ae89735edb3cba78f349a5c9fb99c7 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Sun, 10 Apr 2016 21:50:21 -0700 Subject: [PATCH 30/37] [fxbox/openzwave-adapter] Add support for simple setters (boolean type) --- components/openzwave-adapter/src/lib.rs | 122 +++++++++++++++--------- 1 file changed, 79 insertions(+), 43 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 88f3b32e..f5c68c9e 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -197,21 +197,55 @@ impl Watchers { } } -fn kind_from_value(value: ValueID) -> Option { - value.get_command_class().map(|cc| match cc { - CommandClass::SensorBinary => ChannelKind::OpenClosed, - _ => ChannelKind::Ready // TODO - }) +fn tax_kind_from_ozw_vid(vid: &ValueID) -> Option { + match (vid.get_type(), vid.get_command_class(), vid.get_index()) { + (ValueType::ValueType_Bool, Some(CommandClass::DoorLock), 0) => Some(ChannelKind::DoorLocked), + (ValueType::ValueType_Bool, Some(CommandClass::SensorBinary), _) => Some(ChannelKind::OpenClosed), + // (ValueType::ValueType_Bool, Some(_)) => Some(ChannelKind::OnOff), TODO Find a proper type + // Unrecognized command class or type - we don't know what to do with it. + _ => None + } +} + +fn ozw_vid_as_tax_value(vid: &ValueID) -> Option { + if vid.get_command_class().is_none() { + return None; + } + + match vid.get_type() { + ValueType::ValueType_Bool => { + if let Ok(value) = vid.as_bool() { + match tax_kind_from_ozw_vid(vid) { + // Some(ChannelKind::OnOff) => Some(Value::OnOff(if value {OnOff::On} else {OnOff::Off})), // TODO support switches + Some(ChannelKind::OpenClosed) => Some(Value::OpenClosed(if value {OpenClosed::Open} else {OpenClosed::Closed})), + Some(ChannelKind::DoorLocked) => Some(Value::DoorLocked(if value {DoorLocked::Locked} else {DoorLocked::Unlocked})), + _ => None, + } + } else { + None + } + }, + _ => None, // TODO: Support more ValueType's + } } -fn to_open_closed(value: &ValueID) -> Option { - debug_assert_eq!(value.get_type(), ValueType::ValueType_Bool); +fn set_ozw_vid_from_tax_value(vid: &ValueID, value: Value) -> Result<(), TaxError> { + if vid.get_command_class().is_none() { + return Err(TaxError::InternalError(InternalError::GenericError(format!("Unknown command class: {}", vid.get_command_class_id())))); + } - value.as_bool().ok().map(|val| { - Value::OpenClosed( - if val { OpenClosed::Open } else { OpenClosed::Closed } - ) - }) + match vid.get_type() { + ValueType::ValueType_Bool => { + match value { + //Value::OnOff(onOff) => { vid.set_bool(onOff == OnOff::On); } // TODO support switches + Value::OpenClosed(open_closed) => { vid.set_bool(open_closed == OpenClosed::Open); } + Value::DoorLocked(locked_unlocked) => { vid.set_bool(locked_unlocked == DoorLocked::Locked); } + _ => { return Err(TaxError::InternalError(InternalError::GenericError(format!("Unsupported value type: {:?}", value)))); } + } + } + _ => { return Err(TaxError::InternalError(InternalError::GenericError(format!("Unsupported OZW type: {:?}", vid.get_type())))); } + }; + Ok(()) } struct WatcherGuard { @@ -324,25 +358,25 @@ impl OpenzwaveAdapter { ZWaveNotification::NodeNew(node) => {} ZWaveNotification::NodeAdded(node) => {} ZWaveNotification::NodeRemoved(node) => {} - ZWaveNotification::ValueAdded(value) => { - if value.get_genre() != ValueGenre::ValueGenre_User { continue } + ZWaveNotification::ValueAdded(vid) => { + if vid.get_genre() != ValueGenre::ValueGenre_User { continue } - let value_id = format!("OpenZWave-{:08x}-{:016x} ({})", value.get_home_id(), value.get_id(), value.get_label()); + let value_id = format!("OpenZWave-{:08x}-{:016x} ({})", vid.get_home_id(), vid.get_id(), vid.get_label()); - let controller_id = controller_map.find_tax_id_from_ozw(&value.get_controller()).unwrap(); + let controller_id = controller_map.find_tax_id_from_ozw(&vid.get_controller()).unwrap(); if controller_id.is_none() { continue } let controller_id = controller_id.unwrap(); - let has_getter = !value.is_write_only(); - let has_setter = !value.is_read_only(); + let has_getter = !vid.is_write_only(); + let has_setter = !vid.is_read_only(); - let kind = kind_from_value(value); + let kind = tax_kind_from_ozw_vid(&vid); if kind.is_none() { continue } let kind = kind.unwrap(); if has_getter { let getter_id = TaxId::new(&value_id); - getter_map.push(getter_id.clone(), value); + getter_map.push(getter_id.clone(), vid); box_manager.add_getter(Channel { id: getter_id.clone(), service: controller_id.clone(), @@ -358,7 +392,7 @@ impl OpenzwaveAdapter { if has_setter { let setter_id = TaxId::new(&value_id); - setter_map.push(setter_id.clone(), value); + setter_map.push(setter_id.clone(), vid); box_manager.add_setter(Channel { id: setter_id.clone(), service: controller_id.clone(), @@ -372,18 +406,18 @@ impl OpenzwaveAdapter { }); } } - ZWaveNotification::ValueChanged(value) => { - match value.get_type() { + ZWaveNotification::ValueChanged(vid) => { + match vid.get_type() { ValueType::ValueType_Bool => {}, _ => continue // ignore non-bool vals for now }; - let tax_id = match getter_map.find_tax_id_from_ozw(&value) { + let tax_id = match getter_map.find_tax_id_from_ozw(&vid) { Ok(Some(tax_id)) => tax_id, _ => continue }; - let value = match to_open_closed(&value) { + let tax_value = match ozw_vid_as_tax_value(&vid) { Some(value) => value, _ => continue }; @@ -398,14 +432,14 @@ impl OpenzwaveAdapter { let previous_value = { let mut cache = value_cache.lock().unwrap(); let previous = cache.get(&tax_id).cloned(); - cache.insert(tax_id.clone(), value.clone()); + cache.insert(tax_id.clone(), tax_value.clone()); previous }; for &(ref range, ref sender) in &watchers { debug!("Openzwave::Adapter::ValueChanged iterate over watcher {:?} {:?}", tax_id, range); - let should_send_value = range.should_send(&value, SendDirection::Enter); + let should_send_value = range.should_send(&tax_value, SendDirection::Enter); if let Some(ref previous_value) = previous_value { let should_send_previous = range.should_send(previous_value, SendDirection::Exit); @@ -414,19 +448,19 @@ impl OpenzwaveAdapter { if should_send_value && should_send_previous { continue } if should_send_previous { - debug!("Openzwave::Adapter::ValueChanged Sending event Exit {:?} {:?}", tax_id, value); + debug!("Openzwave::Adapter::ValueChanged Sending event Exit {:?} {:?}", tax_id, tax_value); let sender = sender.lock().unwrap(); sender.send( - WatchEvent::Exit { id: tax_id.clone(), value: value.clone() } + WatchEvent::Exit { id: tax_id.clone(), value: tax_value.clone() } ); } } if should_send_value { - debug!("Openzwave::Adapter::ValueChanged Sending event Enter {:?} {:?}", tax_id, value); + debug!("Openzwave::Adapter::ValueChanged Sending event Enter {:?} {:?}", tax_id, tax_value); let sender = sender.lock().unwrap(); sender.send( - WatchEvent::Enter { id: tax_id.clone(), value: value.clone() } + WatchEvent::Enter { id: tax_id.clone(), value: tax_value.clone() } ); } } @@ -459,24 +493,26 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { fn fetch_values(&self, mut set: Vec>, _: User) -> ResultMap, Option, TaxError> { set.drain(..).map(|id| { - let ozw_value: Option = self.getter_map.find_ozw_from_tax_id(&id).unwrap(); //FIXME no unwrap + let ozw_vid = self.getter_map.find_ozw_from_tax_id(&id).unwrap(); - let ozw_value: Option> = ozw_value.map(|ozw_value: ValueID| { - if !ozw_value.is_set() { return None } + let tax_value: Option> = ozw_vid.map(|ozw_vid: ValueID| { + if !ozw_vid.is_set() { return None } - let result: Option = match ozw_value.get_type() { - ValueType::ValueType_Bool => to_open_closed(&ozw_value), - _ => Some(Value::Unit) - }; - result + ozw_vid_as_tax_value(&ozw_vid) }); - let value_result: Result, TaxError> = ozw_value.ok_or(TaxError::InternalError(InternalError::NoSuchGetter(id.clone()))); + let value_result: Result, TaxError> = tax_value.ok_or(TaxError::InternalError(InternalError::NoSuchGetter(id.clone()))); (id, value_result) }).collect() } - fn send_values(&self, values: HashMap, Value>, _: User) -> ResultMap, (), TaxError> { - unimplemented!() + fn send_values(&self, mut values: HashMap, Value>, _: User) -> ResultMap, (), TaxError> { + values.drain().map(|(id, value)| { + if let Some(ozw_vid) = self.setter_map.find_ozw_from_tax_id(&id).unwrap() { + (id, set_ozw_vid_from_tax_value(&ozw_vid, value)) + } else { + (id.clone(), Err(TaxError::InternalError(InternalError::NoSuchSetter(id)))) + } + }).collect() } fn register_watch(&self, mut values: Vec<(TaxId, Option, Box>)>) -> Vec<(TaxId, Result, TaxError>)> { @@ -494,7 +530,7 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { let ozw_value: Option = self.getter_map.find_ozw_from_tax_id(&id).unwrap(); // FIXME no unwrap if let Some(value) = ozw_value { if value.is_set() && value.get_type() == ValueType::ValueType_Bool { - if let Some(value) = to_open_closed(&value) { + if let Some(value) = ozw_vid_as_tax_value(&value) { self.value_cache.lock().unwrap().insert(id.clone(), value.clone()); if range.should_send(&value, SendDirection::Enter) { debug!("Openzwave::Adapter::register_watch Sending event Enter {:?} {:?}", id, value); From eee11dca35cf86bd2fbfc4a1804c74d3f7b2e1f3 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Wed, 13 Apr 2016 13:23:26 +0200 Subject: [PATCH 31/37] [fxbox/openzwave-adapter] Removes warnings about "unused" variables --- components/openzwave-adapter/src/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index f5c68c9e..69291d2f 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -348,17 +348,17 @@ impl OpenzwaveAdapter { for notification in rx { //debug!("Received notification {:?}", notification); match notification { - ZWaveNotification::ControllerReady(controller) => { + ZWaveNotification::ControllerReady(controller) => { let service = format!("OpenZWave-{:08x}", controller.get_home_id()); let service_id = TaxId::new(&service); controller_map.push(service_id.clone(), controller); box_manager.add_service(Service::empty(service_id.clone(), adapter_id.clone())); } - ZWaveNotification::NodeNew(node) => {} - ZWaveNotification::NodeAdded(node) => {} - ZWaveNotification::NodeRemoved(node) => {} - ZWaveNotification::ValueAdded(vid) => { + ZWaveNotification::NodeNew(_node) => {} + ZWaveNotification::NodeAdded(_node) => {} + ZWaveNotification::NodeRemoved(_node) => {} + ZWaveNotification::ValueAdded(vid) => { if vid.get_genre() != ValueGenre::ValueGenre_User { continue } let value_id = format!("OpenZWave-{:08x}-{:016x} ({})", vid.get_home_id(), vid.get_id(), vid.get_label()); @@ -406,7 +406,7 @@ impl OpenzwaveAdapter { }); } } - ZWaveNotification::ValueChanged(vid) => { + ZWaveNotification::ValueChanged(vid) => { match vid.get_type() { ValueType::ValueType_Bool => {}, _ => continue // ignore non-bool vals for now @@ -465,8 +465,8 @@ impl OpenzwaveAdapter { } } } - ZWaveNotification::ValueRemoved(value) => {} - ZWaveNotification::Generic(string) => {} + ZWaveNotification::ValueRemoved(_value) => {} + ZWaveNotification::Generic(_string) => {} _ => {} } } From 7b5439c8dfa65028cdd88b90c58b29dbd6334241 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Wed, 13 Apr 2016 12:20:30 +0200 Subject: [PATCH 32/37] [fxbox/openzwave-adapter] Add nodes as services --- components/openzwave-adapter/src/lib.rs | 43 ++++++++++++++++--------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 69291d2f..1457880d 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -13,7 +13,7 @@ use transformable_channels::mpsc::ExtSender; use openzwave::{ ConfigPath, InitOptions, ZWaveManager, ZWaveNotification }; use openzwave::{ CommandClass, ValueGenre, ValueType, ValueID }; -use openzwave::{ Controller }; +use openzwave::{ Node }; use std::error; use std::fmt; @@ -109,7 +109,7 @@ impl IdMap where Type: Eq + Clone, Kind: Clone { fn find_tax_id_from_ozw(&self, needle: &Type) -> Result>, ()> { let guard = try!(self.map.read().or(Err(()))); - let find_result = guard.iter().find(|&&(_, ref controller)| controller == needle); + let find_result = guard.iter().find(|&&(_, ref item)| item == needle); Ok(find_result.map(|&(ref id, _)| id.clone())) } @@ -270,7 +270,7 @@ pub struct OpenzwaveAdapter { vendor: String, version: [u32; 4], ozw: ZWaveManager, - controller_map: IdMap, + node_map: IdMap, getter_map: IdMap, setter_map: IdMap, watchers: Arc>, @@ -320,7 +320,7 @@ impl OpenzwaveAdapter { vendor: String::from("Mozilla"), version: [1, 0, 0, 0], ozw: ozw, - controller_map: IdMap::new(), + node_map: IdMap::new(), getter_map: IdMap::new(), setter_map: IdMap::new(), watchers: Arc::new(Mutex::new(Watchers::new())), @@ -338,7 +338,7 @@ impl OpenzwaveAdapter { fn spawn_notification_thread(&self, rx: mpsc::Receiver, box_manager: &Arc) { let adapter_id = self.id.clone(); let box_manager = box_manager.clone(); - let mut controller_map = self.controller_map.clone(); + let mut node_map = self.node_map.clone(); let mut getter_map = self.getter_map.clone(); let mut setter_map = self.setter_map.clone(); let watchers = self.watchers.clone(); @@ -348,24 +348,35 @@ impl OpenzwaveAdapter { for notification in rx { //debug!("Received notification {:?}", notification); match notification { - ZWaveNotification::ControllerReady(controller) => { - let service = format!("OpenZWave-{:08x}", controller.get_home_id()); + ZWaveNotification::ControllerReady(_controller) => {} + ZWaveNotification::NodeNew(_node) => {} + ZWaveNotification::NodeAdded(node) => { + let service = format!("OpenZWave-{:08x}-{:02x}", node.get_home_id(), node.get_id()); let service_id = TaxId::new(&service); - controller_map.push(service_id.clone(), controller); + node_map.push(service_id.clone(), node); + + let mut service = Service::empty(service_id.clone(), adapter_id.clone()); + service.properties.insert(String::from("name"), node.get_name()); + service.properties.insert(String::from("product_name"), node.get_product_name()); + service.properties.insert(String::from("manufacturer_name"), node.get_manufacturer_name()); + service.properties.insert(String::from("location"), node.get_location()); - box_manager.add_service(Service::empty(service_id.clone(), adapter_id.clone())); + box_manager.add_service(service); + } + ZWaveNotification::NodeNaming(_node) => { + // unfortunately we can't change a service' properties :( + // https://github.com/fxbox/taxonomy/issues/97 + // When it's done we can move the properties change from above to here. } - ZWaveNotification::NodeNew(_node) => {} - ZWaveNotification::NodeAdded(_node) => {} ZWaveNotification::NodeRemoved(_node) => {} ZWaveNotification::ValueAdded(vid) => { if vid.get_genre() != ValueGenre::ValueGenre_User { continue } let value_id = format!("OpenZWave-{:08x}-{:016x} ({})", vid.get_home_id(), vid.get_id(), vid.get_label()); - let controller_id = controller_map.find_tax_id_from_ozw(&vid.get_controller()).unwrap(); - if controller_id.is_none() { continue } - let controller_id = controller_id.unwrap(); + let node_id = node_map.find_tax_id_from_ozw(&vid.get_node()).unwrap(); + if node_id.is_none() { continue } + let node_id = node_id.unwrap(); let has_getter = !vid.is_write_only(); let has_setter = !vid.is_read_only(); @@ -379,7 +390,7 @@ impl OpenzwaveAdapter { getter_map.push(getter_id.clone(), vid); box_manager.add_getter(Channel { id: getter_id.clone(), - service: controller_id.clone(), + service: node_id.clone(), adapter: adapter_id.clone(), last_seen: None, tags: HashSet::new(), @@ -395,7 +406,7 @@ impl OpenzwaveAdapter { setter_map.push(setter_id.clone(), vid); box_manager.add_setter(Channel { id: setter_id.clone(), - service: controller_id.clone(), + service: node_id.clone(), adapter: adapter_id.clone(), last_seen: None, tags: HashSet::new(), From aa9a98756dd8f156a9a8ad472fca41589fd7df90 Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Wed, 13 Apr 2016 21:13:31 +0200 Subject: [PATCH 33/37] [fxbox/openzwave-adapter] Save the network configuration at some right times (fixes #20) --- components/openzwave-adapter/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index 1457880d..b511d93e 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -477,6 +477,10 @@ impl OpenzwaveAdapter { } } ZWaveNotification::ValueRemoved(_value) => {} + ZWaveNotification::AwakeNodesQueried(ref controller) | ZWaveNotification::AllNodesQueried(ref controller) => { + debug!("Openzwave::Adapter writing the network config."); + controller.write_config(); + } ZWaveNotification::Generic(_string) => {} _ => {} } @@ -557,6 +561,11 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { (id, value_result) }).collect() } + + fn stop(&self) { + info!("Openzwave::Adapter::stop Stopping the Openzwave adapter: writing the network config."); + self.ozw.write_configs(); + } } #[cfg(test)] From fa6dc70afbfba7e854bcd1b79e012de41fee3abe Mon Sep 17 00:00:00 2001 From: Christiane Ruetten Date: Thu, 14 Apr 2016 14:10:45 +0200 Subject: [PATCH 34/37] [fxbox/openzwave-adapter] Turning error into info when no ZWave found --- components/openzwave-adapter/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index b511d93e..aa117149 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -307,7 +307,7 @@ impl OpenzwaveAdapter { Err(openzwave::Error::NoDeviceFound) => { // early return: we should not impair foxbox startup for this error. // TODO concept of FatalError vs IgnoreableError - error!("No ZWave device has been found."); + info!("No ZWave device has been found."); return Ok(()); } result => result From c8124fa72816c97d1192fd5e679e12408720e53a Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Fri, 15 Apr 2016 19:06:22 +0200 Subject: [PATCH 35/37] [fxbox/openzwave-adapter] Gobble the new CannotReadDevice error from openzwave-stateful-rust printing a log, and tidied the log messages --- components/openzwave-adapter/src/lib.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index aa117149..208a8f3d 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -306,8 +306,13 @@ impl OpenzwaveAdapter { let (ozw, rx) = try!(match openzwave::init(&options) { Err(openzwave::Error::NoDeviceFound) => { // early return: we should not impair foxbox startup for this error. - // TODO concept of FatalError vs IgnoreableError - info!("No ZWave device has been found."); + // TODO manage errors at adapter start: https://github.com/fxbox/RFC/issues/14 + info!("[OpenzwaveAdapter] No ZWave device has been found."); + return Ok(()); + }, + Err(openzwave::Error::CannotReadDevice(device, cause)) => { + // early return for the same reason as above. + error!("[OpenzwaveAdapter] Could not read the device {}: {}.", device, cause); return Ok(()); } result => result @@ -330,7 +335,7 @@ impl OpenzwaveAdapter { adapter.spawn_notification_thread(rx, box_manager); try!(box_manager.add_adapter(adapter)); - info!("Started Openzwave adapter."); + info!("[OpenzwaveAdapter] Started."); Ok(()) } @@ -448,7 +453,7 @@ impl OpenzwaveAdapter { }; for &(ref range, ref sender) in &watchers { - debug!("Openzwave::Adapter::ValueChanged iterate over watcher {:?} {:?}", tax_id, range); + debug!("[OpenzwaveAdapter::ValueChanged] Iterating over watcher {:?} {:?}", tax_id, range); let should_send_value = range.should_send(&tax_value, SendDirection::Enter); @@ -468,7 +473,7 @@ impl OpenzwaveAdapter { } if should_send_value { - debug!("Openzwave::Adapter::ValueChanged Sending event Enter {:?} {:?}", tax_id, tax_value); + debug!("[OpenzwaveAdapter::ValueChanged] Sending event Enter {:?} {:?}", tax_id, tax_value); let sender = sender.lock().unwrap(); sender.send( WatchEvent::Enter { id: tax_id.clone(), value: tax_value.clone() } @@ -478,7 +483,7 @@ impl OpenzwaveAdapter { } ZWaveNotification::ValueRemoved(_value) => {} ZWaveNotification::AwakeNodesQueried(ref controller) | ZWaveNotification::AllNodesQueried(ref controller) => { - debug!("Openzwave::Adapter writing the network config."); + debug!("[OpenzwaveAdapter] Writing the network config."); controller.write_config(); } ZWaveNotification::Generic(_string) => {} @@ -531,10 +536,10 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { } fn register_watch(&self, mut values: Vec<(TaxId, Option, Box>)>) -> Vec<(TaxId, Result, TaxError>)> { - debug!("Openzwave::Adapter::register_watch Should register some watchers"); + debug!("[OpenzwaveAdapter::register_watch] Should register some watchers"); values.drain(..).map(|(id, range, sender)| { let sender = Arc::new(Mutex::new(sender)); // Mutex is necessary because cb is not Sync. - debug!("Openzwave::Adapter::register_watch Should register a watcher for {:?} {:?}", id, range); + debug!("[OpenzwaveAdapter::register_watch] Should register a watcher for {:?} {:?}", id, range); let watch_guard = { let mut watchers = self.watchers.lock().unwrap(); watchers.push(id.clone(), range.clone(), sender.clone()) @@ -548,7 +553,7 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { if let Some(value) = ozw_vid_as_tax_value(&value) { self.value_cache.lock().unwrap().insert(id.clone(), value.clone()); if range.should_send(&value, SendDirection::Enter) { - debug!("Openzwave::Adapter::register_watch Sending event Enter {:?} {:?}", id, value); + debug!("[OpenzwaveAdapter::register_watch] Sending event Enter {:?} {:?}", id, value); let sender = sender.lock().unwrap(); sender.send( WatchEvent::Enter { id: id.clone(), value: value } @@ -563,7 +568,7 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { } fn stop(&self) { - info!("Openzwave::Adapter::stop Stopping the Openzwave adapter: writing the network config."); + info!("[OpenzwaveAdapter::stop] Stopping the Openzwave adapter: writing the network config."); self.ozw.write_configs(); } } From 64e1b817ee43d9ee3440e5ac99a8bde4a64ee233 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Fri, 15 Apr 2016 14:44:06 -0700 Subject: [PATCH 36/37] [fxbox/openzwave-adapter] Allow foxbox to provide a device to open. --- components/openzwave-adapter/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index f5c68c9e..78df9582 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -293,12 +293,12 @@ fn ensure_directory + ?Sized>(directory: &T) -> Result<(), Error> } impl OpenzwaveAdapter { - pub fn init (box_manager: &Arc, user_path: &str) -> Result<(), Error> { + pub fn init (box_manager: &Arc, user_path: &str, device: Option) -> Result<(), Error> { try!(ensure_directory(user_path)); let options = InitOptions { - device: None, // TODO we should expose this as a Value + device: device, config_path: ConfigPath::Default, // This is where the default system configuraton is, usually contains the device information. user_path: user_path, // This is where we can override the system configuration, and where the network layout and logs are stored. }; From acce7e99452190ed88bd361510fbb73e145caf0b Mon Sep 17 00:00:00 2001 From: Julien Wajsberg Date: Tue, 19 Apr 2016 15:30:57 +0200 Subject: [PATCH 37/37] [fxbox/openzwave-adapter] Rename SendDirection to EventType (fixes #12) --- components/openzwave-adapter/src/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/openzwave-adapter/src/lib.rs b/components/openzwave-adapter/src/lib.rs index b894ad21..007f139c 100644 --- a/components/openzwave-adapter/src/lib.rs +++ b/components/openzwave-adapter/src/lib.rs @@ -121,26 +121,26 @@ impl IdMap where Type: Eq + Clone, Kind: Clone { } #[derive(Debug, Copy, Clone, PartialEq)] -enum SendDirection { +enum EventType { Enter, Exit, } trait RangeChecker { - fn should_send(&self, &Value, SendDirection) -> bool; + fn should_send(&self, &Value, EventType) -> bool; } impl RangeChecker for Option { - fn should_send(&self, value: &Value, direction: SendDirection) -> bool { + fn should_send(&self, value: &Value, event_type: EventType) -> bool { match *self { - None => direction == SendDirection::Enter, // no range means we send only Enter events + None => event_type == EventType::Enter, // no range means we send only Enter events Some(ref range) => range.contains(value) } } } impl RangeChecker for Range { - fn should_send(&self, value: &Value, _: SendDirection) -> bool { + fn should_send(&self, value: &Value, _: EventType) -> bool { self.contains(value) } } @@ -455,10 +455,10 @@ impl OpenzwaveAdapter { for &(ref range, ref sender) in &watchers { debug!("[OpenzwaveAdapter::ValueChanged] Iterating over watcher {:?} {:?}", tax_id, range); - let should_send_value = range.should_send(&tax_value, SendDirection::Enter); + let should_send_value = range.should_send(&tax_value, EventType::Enter); if let Some(ref previous_value) = previous_value { - let should_send_previous = range.should_send(previous_value, SendDirection::Exit); + let should_send_previous = range.should_send(previous_value, EventType::Exit); // If the new and the old values are both in the same range, we // need to send nothing. if should_send_value && should_send_previous { continue } @@ -552,7 +552,7 @@ impl taxonomy::adapter::Adapter for OpenzwaveAdapter { if value.is_set() && value.get_type() == ValueType::ValueType_Bool { if let Some(value) = ozw_vid_as_tax_value(&value) { self.value_cache.lock().unwrap().insert(id.clone(), value.clone()); - if range.should_send(&value, SendDirection::Enter) { + if range.should_send(&value, EventType::Enter) { debug!("[OpenzwaveAdapter::register_watch] Sending event Enter {:?} {:?}", id, value); let sender = sender.lock().unwrap(); sender.send(