Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Denenberg authored and Adam Denenberg committed Feb 24, 2019
1 parent b087a24 commit 31924f1
Show file tree
Hide file tree
Showing 10 changed files with 971 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

.idea
15 changes: 15 additions & 0 deletions Cargo.toml
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"
76 changes: 76 additions & 0 deletions src/api/device_control.rs
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(),
}
}
}
101 changes: 101 additions & 0 deletions src/api/device_status.rs
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(),
}
}
}
2 changes: 2 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod device_control;
pub mod device_status;
185 changes: 185 additions & 0 deletions src/device.rs
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",
}
}
}
Loading

0 comments on commit 31924f1

Please sign in to comment.