[go: up one dir, main page]

Skip to content

Commit

Permalink
Added light codebase, settings, readme and misc
Browse files Browse the repository at this point in the history
  • Loading branch information
marko-k0 committed Apr 19, 2019
1 parent e689979 commit 334035c
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 40 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ description = "Rust library for Philips Hue lights API"
license = "MIT"

[dependencies]
config = "*"
clap = {version = "2.32", features = ["yaml"]}
reqwest = "*"
serde = { version = "1.0", features = ["derive"] }
Expand Down
68 changes: 61 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,71 @@
# Hue-rs ~ Philips Hue Rust Library and CLI
# Philips Hue Rust Library and CLI

## Description - let there be light!
**This is currently in development stage!**

...
## Hue-rs, let there be light!

Hue-rs is a *Rust* library that can be used for home automation on Philips Hue lights.
It offers a basic *CLI* with which you can control your lights from a terminal instead
of looking for your phone and making desired changes from official Philips Hue app.

## Installation and CLI use

...
```bash
$ cat <<EOF > ~/.huerc
debug = false
[hue]
ip = 192.168.0.1
username = <philips-hue-username>
EOF

$ hue help

hue 1.0
Marko Kosmerl <marko.kosmerl@gmail.com>
Philips Hue CLI

USAGE:
hue [FLAGS] [OPTIONS] <SUBCOMMAND>

FLAGS:
-h, --help Prints help information
-V, --version Prints version information
-v Sets the level of verbosity

OPTIONS:
-c, --config <FILE> Sets a custom config file

SUBCOMMANDS:
group Controls a group of lights
help Prints this message or the help of the given subcommand(s)
light Controls the lights
scene Controls a scene

$ hue light on 1
[{"success":{"/lights/1/state/on":true}}]
```

## Library use

```rust
extern crate hue-rs;

use hue-rs::*;
use hue-rs::lights::*;

## Library used
pub fn funhue) {
let client = Client::new();

...
let mut light = Light::get_light(&client, 1).unwrap();
let &mut light_state = light.state();
light_state.set_on(true);
light.update()
}
```

## Todo

...
- [ ] Tests
- [ ] Finalize *light*, *group* and *scene* API
- [ ] *Let there be light* voice recognition
2 changes: 1 addition & 1 deletion src/bin-cli.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: hue-rc
name: hue
version: "1.0"
author: Marko Kosmerl <marko.kosmerl@gmail.com>
about: Philips Hue CLI
Expand Down
21 changes: 6 additions & 15 deletions src/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,14 @@ fn main() {
}

fn run(matches: ArgMatches) -> Result<(), Box<Error>> {
let ref client = Client::new(
String::from("192.168.200.1"),
String::from("asdf"),
);
let ref client = Client::new();

match matches.subcommand() {
("light", Some(sub_m)) => return run_light(client, sub_m),
("group", Some(sub_m)) => return run_group(client, sub_m),
("scene", Some(sub_m)) => return run_scene(client, sub_m),
(_, _) => return Ok(()),
}

Ok(())
}

fn run_light(client: &Client, matches: &ArgMatches) -> Result<(), Box<Error>> {
Expand All @@ -52,15 +47,11 @@ fn run_light(client: &Client, matches: &ArgMatches) -> Result<(), Box<Error>> {
fn run_light_list(client: &Client) -> Result<(), Box<Error>> {
let light_list = Light::get_lights(&client);

//if let Ok(lights) = light_list {
// let light_list_yml = serde_yaml::to_string(&lights).unwrap();
// println!("{}", light_list_yml);
//} else if let Err(e) = light_list {
// format!("{}", e);
//}

for light in light_list.unwrap().values() {
light.test();
if let Ok(lights) = light_list {
let light_list_yml = serde_yaml::to_string(&lights).unwrap();
println!("{}", light_list_yml);
} else if let Err(e) = light_list {
//XXX:
}

Ok(())
Expand Down
5 changes: 5 additions & 0 deletions src/huerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
debug = false

[hue]
ip = 192.168.0.28
username = hue
19 changes: 9 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
use std::time::Duration;
pub mod lights;

extern crate config;
extern crate reqwest;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
extern crate custom_derive;
#[macro_use]
extern crate derive_builder;

type Res<T> = Result<T, Box<std::error::Error>>;
mod settings;
use settings::Settings;

#[derive(Debug)]
struct Config {
ip: String,
username: String,
}
type Res<T> = Result<T, Box<std::error::Error>>;

#[derive(Debug)]
pub struct Client {
config: Config,
settings: Settings,
client: reqwest::Client,
}

impl Client {
pub fn new(ip: String, username: String) -> Self {
pub fn new() -> Self {
Client {
config: Config { ip, username },
settings: Settings::new().unwrap(),
client: reqwest::Client::builder()
.timeout(Duration::from_secs(10))
.danger_accept_invalid_certs(true)
Expand All @@ -36,7 +35,7 @@ impl Client {
}

fn rest_call_url(&self, suffix: &str) -> String {
format!("https://{}/api/{}/{}", self.config.ip, self.config.username, suffix)
format!("https://{}/api/{}/{}", self.settings.ip(), self.settings.username(), suffix)
}

pub fn get(&self, call: &str) -> Result<String, reqwest::Error> {
Expand Down
52 changes: 45 additions & 7 deletions src/lights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,28 @@ impl LightState {
None => 0,
}
}
pub fn set_hue(&mut self, hue: u16) {
//XXX: only for color light
self.hue = Some(hue);
}
pub fn sat(&self) -> u8 {
match self.sat {
Some(s) => s,
None => 0,
}
}
pub fn set_sat(&mut self, sat: u8) {
//XXX: only for color light
self.sat = Some(sat);
}
pub fn alert(&self) -> &str {
&self.alert.as_ref().unwrap()
}
pub fn set_alert(&mut self, alert: &str) {
//XXX: only for color light
self.alert = Some(alert.to_owned())
}

}

#[derive(Serialize, Deserialize, Debug)]
Expand All @@ -81,6 +103,7 @@ pub struct Light<'a> {
swversion: String
}

/// API for operations on the lights.
impl<'a> Light<'a> {

pub fn get_lights(http_client: &'a Client) -> Res<BTreeMap<String,Light>> {
Expand All @@ -101,6 +124,7 @@ impl<'a> Light<'a> {
Ok(light)
}

//XXX: do we need this?
pub fn set_state(http_client: &'a Client, id: u8, state: &LightState) -> Res<String> {
let state_json = serde_json::to_string(state)?;
let response = http_client.put(&format!("lights/{}/state", id), state_json)?;
Expand All @@ -109,28 +133,42 @@ impl<'a> Light<'a> {

pub fn update(&self) -> Res<String> {
let state_json = serde_json::to_string(&self.state)?;
let response = self.client.unwrap().put(
&format!("lights/{}/state", self.id.unwrap()), state_json)?;
let response = self.client().put(
&format!("lights/{}/state", self.id()), state_json)?;
Ok(response)
}

pub fn rename(&mut self, name: &str) -> Res<&Self> {
let body = json!({"name": name});
self.client.unwrap().put(&format!("lights/{}", self.id.unwrap()), body.to_string())?;
self.client().put(&format!("lights/{}", self.id()), body.to_string())?;
self.name = name.to_owned();
Ok(self)
}

pub fn delete(self) -> Res<()> {
self.client.unwrap().delete(&format!("lights/{}", self.id.unwrap()))?;
self.client().delete(&format!("lights/{}", self.id()))?;
Ok(())
}

pub fn test(&self) {
let response = self.client.unwrap().get(&format!("lights/2")).unwrap();
println!("{}", response);
pub fn id(&self) -> u8 {
self.id.unwrap()
}

pub fn client(&self) -> &Client {
self.client.unwrap()
}

pub fn state(&mut self) -> &mut LightState {
&mut self.state
}

pub fn ty(&self) -> &str {
&self.ty
}

pub fn name(&self) -> &str {
&self.name
}
}


Expand Down
38 changes: 38 additions & 0 deletions src/settings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use config::{Config, ConfigError, File, Environment};

#[derive(Debug, Deserialize)]
struct Hue {
ip: String,
username: String,
}

/// Configuration holding Phiplips Hue API information and debug option.
#[derive(Debug, Deserialize)]
pub struct Settings {
debug: bool,
hue: Hue,
}

impl Settings {
/// Load configuration from environment or ~/.huerc configuration file.
///
/// Environment variables have a priority over configuration file.
pub fn new() -> Result<Self, ConfigError> {
let mut s = Config::new();

s.merge(File::with_name("~/.huerc").required(false));
s.merge(Environment::with_prefix("HUE"))?;

s.try_into()
}

/// Get IP address of Philips Hue bridge.
pub fn ip(&self) -> &str {
&self.hue.ip
}

/// Get username that is used to talk with the API.
pub fn username(&self) -> &str {
&self.hue.username
}
}

0 comments on commit 334035c

Please sign in to comment.