-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Adam Denenberg
authored and
Adam Denenberg
committed
Feb 24, 2019
1 parent
b087a24
commit 31924f1
Showing
10 changed files
with
971 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,5 @@ Cargo.lock | |
|
||
# These are backup files generated by rustfmt | ||
**/*.rs.bk | ||
|
||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "hsctl" | ||
version = "0.1.0" | ||
authors = ["denen99"] | ||
edition = "2018" | ||
|
||
[dependencies] | ||
reqwest = "0.9.5" | ||
base64 = "0.10.0" | ||
clap = "2.32.0" | ||
serde = "1.0" | ||
serde_derive = "1.0" | ||
serde_json = "1.0" | ||
prettytable-rs = "^0.8" | ||
dirs = "1.0.4" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
extern crate serde_json; | ||
|
||
use crate::device::*; | ||
|
||
#[derive(Deserialize, Debug, Clone)] | ||
pub struct DeviceControlJson { | ||
#[serde(rename = "Ref")] | ||
pub id: u32, | ||
#[serde(rename = "Label")] | ||
pub label: String, | ||
#[serde(rename = "ControlValue")] | ||
pub control_value: f32, | ||
#[serde(rename = "ControlType")] | ||
pub control_type: u32, | ||
} | ||
|
||
#[derive(Deserialize, Debug)] | ||
pub struct DeviceControlPairJson { | ||
#[serde(rename = "ControlPairs")] | ||
control_pairs: Vec<DeviceControlJson>, | ||
#[serde(rename = "ref")] | ||
pub id: u32, | ||
} | ||
|
||
#[derive(Deserialize, Debug)] | ||
pub struct DeviceControlResponse { | ||
#[serde(rename = "Devices")] | ||
pub devices: Vec<DeviceControlPairJson>, | ||
} | ||
|
||
impl DeviceControlResponse { | ||
pub fn find_by_id(&self, id: u32) -> Vec<DeviceControlJson> { | ||
self | ||
.devices | ||
.iter() | ||
.filter(|d| d.id == id) | ||
.map(|d| d.control_pairs.clone()) | ||
.flatten() | ||
.collect::<Vec<DeviceControlJson>>() | ||
} | ||
} | ||
|
||
impl DeviceControlJson { | ||
pub fn get_control_type_value(&self) -> DeviceControlTypeValue { | ||
match self.control_type { | ||
1 => DeviceControlTypeValue::NotSpecified, | ||
2 => DeviceControlTypeValue::Values, | ||
3 => DeviceControlTypeValue::SingleTextFromList, | ||
4 => DeviceControlTypeValue::ListTextFromList, | ||
5 => DeviceControlTypeValue::Button, | ||
6 => DeviceControlTypeValue::ValuesRange, | ||
7 => DeviceControlTypeValue::ValuesRangeSlider, | ||
8 => DeviceControlTypeValue::TextList, | ||
9 => DeviceControlTypeValue::TextBoxNumber, | ||
10 => DeviceControlTypeValue::TextBoxString, | ||
11 => DeviceControlTypeValue::RadioOption, | ||
12 => DeviceControlTypeValue::ButtonScript, | ||
13 => DeviceControlTypeValue::ColorPicker, | ||
_ => DeviceControlTypeValue::Values, | ||
} | ||
} | ||
|
||
// pub fn add_control_pairs_to_device(self, d: &mut Device) { | ||
// let d_ctrl = self.to_device_control(); | ||
// | ||
// d.control_pairs.push(d_ctrl); | ||
// } | ||
|
||
pub fn to_device_control(&self) -> DeviceControl { | ||
DeviceControl { | ||
label: self.label.clone(), | ||
control_value: self.control_value, | ||
control_type: self.get_control_type_value(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
extern crate serde_json; | ||
|
||
use crate::device::*; | ||
// HomeSeer JSON is an absolute cluster. Bizarre naming conventions | ||
// as well as inconsistent casing. So we need to do a lot of mapping | ||
// here to our snake case structs | ||
|
||
#[derive(Deserialize, Debug)] | ||
pub struct DeviceJson { | ||
#[serde(rename = "ref")] | ||
pub id: u32, | ||
pub name: String, | ||
pub location: String, | ||
pub location2: String, | ||
pub value: f32, | ||
pub status: String, | ||
pub device_type_string: String, | ||
#[serde(rename = "device_type")] | ||
pub device_type_info: DeviceTypeInfo, | ||
} | ||
|
||
#[derive(Deserialize, Debug)] | ||
pub struct DeviceResponse { | ||
#[serde(rename = "Devices")] | ||
pub devices: Vec<DeviceJson>, | ||
} | ||
|
||
#[derive(Deserialize, Debug)] | ||
pub struct DeviceTypeInfo { | ||
#[serde(rename = "Device_API")] | ||
pub device_api: u32, | ||
#[serde(rename = "Device_API_Description")] | ||
pub device_api_description: String, | ||
#[serde(rename = "Device_Type")] | ||
pub device_type: u32, | ||
#[serde(rename = "Device_Type_Description")] | ||
pub device_type_description: String, | ||
#[serde(rename = "Device_SubType")] | ||
pub device_sub_type: u32, | ||
#[serde(rename = "Device_SubType_Description")] | ||
pub device_sub_type_description: String, | ||
} | ||
|
||
impl DeviceJson { | ||
pub fn get_device_api_value(&self) -> DeviceApiValue { | ||
match self.device_type_info.device_api { | ||
0 => DeviceApiValue::NoAPI, | ||
4 => DeviceApiValue::Plugin, | ||
16 => DeviceApiValue::Thermostat, | ||
32 => DeviceApiValue::Media, | ||
8 => DeviceApiValue::Security, | ||
64 => DeviceApiValue::SourceSwitch, | ||
128 => DeviceApiValue::Script, | ||
_ => DeviceApiValue::UnKnown, | ||
} | ||
} | ||
|
||
pub fn get_device_type_value(&self) -> DeviceTypeValue { | ||
if self.device_type_info.device_type == 999 { | ||
return DeviceTypeValue::GenericRoot; | ||
} | ||
|
||
match self.get_device_api_value() { | ||
DeviceApiValue::NoAPI => match self.device_type_info.device_type { | ||
999 => DeviceTypeValue::GenericRoot, | ||
_ => DeviceTypeValue::Unknown, | ||
}, | ||
DeviceApiValue::Plugin => match self.device_type_info.device_type { | ||
999 => DeviceTypeValue::GenericRoot, | ||
99 => DeviceTypeValue::Root, | ||
_ => DeviceTypeValue::Unknown, | ||
}, | ||
DeviceApiValue::Media => DeviceTypeValue::Media(self.device_type_info.device_type), | ||
DeviceApiValue::Thermostat => { | ||
DeviceTypeValue::Thermostat(self.device_type_info.device_type) | ||
} | ||
DeviceApiValue::Script => DeviceTypeValue::Script(self.device_type_info.device_type), | ||
DeviceApiValue::Security => { | ||
DeviceTypeValue::Security(self.device_type_info.device_type) | ||
} | ||
DeviceApiValue::SourceSwitch => { | ||
DeviceTypeValue::SourceSwitch(self.device_type_info.device_type) | ||
} | ||
_ => DeviceTypeValue::GenericRoot, | ||
} | ||
} | ||
|
||
pub fn to_device(&self) -> Device { | ||
Device { | ||
device_api: self.get_device_api_value(), | ||
device_type: self.get_device_type_value(), | ||
id: self.id, | ||
location: self.location.clone(), | ||
location2: self.location2.clone(), | ||
name: self.name.clone(), | ||
status: self.status.clone(), | ||
value: self.value, | ||
control_pairs: Vec::new(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod device_control; | ||
pub mod device_status; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
#[derive(Serialize, Debug)] | ||
pub struct Device { | ||
pub id: u32, | ||
pub name: String, | ||
pub location2: String, | ||
pub location: String, | ||
pub value: f32, | ||
pub status: String, | ||
pub device_api: DeviceApiValue, | ||
pub device_type: DeviceTypeValue, | ||
pub control_pairs: Vec<DeviceControl>, | ||
} | ||
|
||
impl Device { | ||
pub fn add_control_pairs(&mut self, control_pairs: Vec<DeviceControl>) { | ||
control_pairs.iter().for_each(|cp| { | ||
let c = cp.clone(); | ||
self.control_pairs.push(c); | ||
}); | ||
} | ||
} | ||
|
||
#[derive(Serialize, Clone, Debug)] | ||
pub struct DeviceControl { | ||
pub label: String, | ||
pub control_value: f32, | ||
pub control_type: DeviceControlTypeValue, | ||
} | ||
|
||
#[derive(Serialize, Clone, Debug)] | ||
pub enum DeviceTypeValue { | ||
GenericRoot, | ||
Media(u32), | ||
Script(u32), | ||
Security(u32), | ||
SourceSwitch(u32), | ||
Thermostat(u32), | ||
Root, | ||
Unknown, | ||
} | ||
|
||
impl DeviceTypeValue { | ||
pub fn to_str(&self) -> &str { | ||
match self { | ||
DeviceTypeValue::GenericRoot => "Generic Root", | ||
DeviceTypeValue::Root => "Root", | ||
DeviceTypeValue::Media(x) => match x { | ||
1 => "Player Status", | ||
2 => "Player Status Additional", | ||
3 => "Player Control", | ||
4 => "Player Volume", | ||
5 => "Player Shuffle", | ||
6 => "Player Repeat", | ||
7 => "Music Genre", | ||
8 => "Music Album", | ||
9 => "Music Artist", | ||
10 => "Music Track", | ||
11 => "Music Playlist", | ||
12 => "Media Type", | ||
20 => "Music Selector Control", | ||
99 => "Root", | ||
_ => "Unknown Media Type", | ||
}, | ||
DeviceTypeValue::SourceSwitch(x) => match x { | ||
0 => "Invalid", | ||
1 => "System", | ||
10 => "Source", | ||
15 => "Source Extended", | ||
20 => "Zone", | ||
25 => "Zone Extended", | ||
99 => "Root", | ||
_ => "Unknown Source Switch Type", | ||
}, | ||
DeviceTypeValue::Thermostat(x) => match x { | ||
1 => "Operating State", | ||
2 => "Temperature", | ||
3 => "Mode_Set", | ||
4 => "Fan Mode Set", | ||
5 => "Fan Status", | ||
6 => "Setpoint", | ||
7 => "Runtime", | ||
8 => "Hold Mode", | ||
9 => "Operating Mode", | ||
10 => "Additional Temperature", | ||
11 => "Setback", | ||
12 => "Filter Remind", | ||
99 => "Root", | ||
_ => "Unknown Thermostat Type", | ||
}, | ||
DeviceTypeValue::Script(x) => match x { | ||
0 => "Disabled", | ||
1 => "Run On Any Change", | ||
2 => "Run On Value Change", | ||
3 => "Run On String Change", | ||
_ => "Unknown Script Type", | ||
}, | ||
DeviceTypeValue::Security(x) => match x { | ||
1 => "Alarm", | ||
10 => "Arming", | ||
20 => "Keypad", | ||
30 => "Zone Perimeter", | ||
31 => "Zone Perimeter Delay", | ||
32 => "Zone Interior", | ||
33 => "Zone Interior Delay", | ||
34 => "Zone Auxiliary", | ||
35 => "Zone Other", | ||
40 => "Zone Safety Smoke", | ||
41 => "Zone Safety CO", | ||
42 => "Zone Safety CO2", | ||
43 => "Zone Safety Other", | ||
50 => "Output Relay", | ||
51 => "Output Other", | ||
60 => "Communicator", | ||
70 => "Siren", | ||
99 => "Root", | ||
_ => "Unknown Security Type", | ||
}, | ||
_ => "Unknown", | ||
} | ||
} | ||
} | ||
|
||
#[derive(Serialize, Debug)] | ||
pub enum DeviceApiValue { | ||
NoAPI, | ||
Plugin, | ||
Thermostat, | ||
Media, | ||
Security, | ||
SourceSwitch, | ||
Script, | ||
UnKnown, | ||
} | ||
|
||
impl DeviceApiValue { | ||
pub fn to_str(&self) -> &str { | ||
match self { | ||
DeviceApiValue::NoAPI => "NO_API", | ||
DeviceApiValue::Plugin => "Plugin", | ||
DeviceApiValue::Thermostat => "Thermostat", | ||
DeviceApiValue::Media => "Media", | ||
DeviceApiValue::Security => "Security", | ||
DeviceApiValue::SourceSwitch => "SourceSwitch", | ||
DeviceApiValue::Script => "Script", | ||
_ => "Unknown", | ||
} | ||
} | ||
} | ||
|
||
#[derive(Serialize, Clone, Debug)] | ||
pub enum DeviceControlTypeValue { | ||
NotSpecified, | ||
Values, | ||
SingleTextFromList, | ||
ListTextFromList, | ||
Button, | ||
ValuesRange, | ||
ValuesRangeSlider, | ||
TextList, | ||
TextBoxNumber, | ||
TextBoxString, | ||
RadioOption, | ||
ButtonScript, | ||
ColorPicker, | ||
} | ||
|
||
impl DeviceControlTypeValue { | ||
pub fn to_str(&self) -> &str { | ||
match self { | ||
DeviceControlTypeValue::NotSpecified => "Not Specified", | ||
DeviceControlTypeValue::Values => "Values", | ||
DeviceControlTypeValue::SingleTextFromList => "Single Text From List", | ||
DeviceControlTypeValue::ListTextFromList => "List Text From List", | ||
DeviceControlTypeValue::Button => "Button", | ||
DeviceControlTypeValue::ValuesRange => "Values Range", | ||
DeviceControlTypeValue::ValuesRangeSlider => "ValuesRangeSlider", | ||
DeviceControlTypeValue::TextList => "TextList", | ||
DeviceControlTypeValue::TextBoxNumber => "TextBoxNumber", | ||
DeviceControlTypeValue::TextBoxString => "TextBoxString", | ||
DeviceControlTypeValue::RadioOption => "RadioOption", | ||
DeviceControlTypeValue::ButtonScript => "ButtonScript", | ||
DeviceControlTypeValue::ColorPicker => "Color Picker", | ||
} | ||
} | ||
} |
Oops, something went wrong.