hue 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Readme.markdown +2 -0
- data/Todo.markdown +0 -1
- data/lib/hue.rb +1 -0
- data/lib/hue/bridge.rb +104 -0
- data/lib/hue/client.rb +23 -16
- data/lib/hue/errors.rb +1 -0
- data/lib/hue/light.rb +59 -40
- data/lib/hue/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6a7f55311b35aa3cb7e2907ecad349632e102b7
|
4
|
+
data.tar.gz: 3201fe193181c257741f03f14a71b78b78ca3ecf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76884d923bbe4ee4084bd121caae4f0004cb25f0fcd8e0618f27acd5887c89350f412e4d765c2e0ac148c079e82f245261d0a8664eff2eb6dbb3a7a64d8f88b3
|
7
|
+
data.tar.gz: c86bbdea9bca5ec707791137c72836fae70f3a4fd9978eff41b472968391f2a32b14494bb9885fa943a8f636ac9d4e9a62de83d15bc24917fcdcdeae2829c150
|
data/Readme.markdown
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
Work with Philips Hue light bulbs from Ruby.
|
4
4
|
|
5
|
+
[![Code Climate](https://codeclimate.com/github/soffes/hue.png)](https://codeclimate.com/github/soffes/hue) [![Dependency Status](https://gemnasium.com/soffes/hue.png)](https://gemnasium.com/soffes/hue) [![Gem Version](https://badge.fury.io/rb/hue.png)](http://badge.fury.io/rb/hue)
|
6
|
+
|
5
7
|
## Installation
|
6
8
|
|
7
9
|
Add this line to your application's Gemfile:
|
data/Todo.markdown
CHANGED
data/lib/hue.rb
CHANGED
data/lib/hue/bridge.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
module Hue
|
2
|
+
class Bridge
|
3
|
+
# ID of the bridge.
|
4
|
+
attr_reader :id
|
5
|
+
|
6
|
+
# Name of the bridge. This is also its uPnP name, so will reflect the
|
7
|
+
# actual uPnP name after any conflicts have been resolved.
|
8
|
+
attr_accessor :name
|
9
|
+
|
10
|
+
# IP address of the bridge.
|
11
|
+
attr_reader :ip
|
12
|
+
|
13
|
+
# MAC address of the bridge.
|
14
|
+
attr_reader :mac_address
|
15
|
+
|
16
|
+
# IP Address of the proxy server being used.
|
17
|
+
attr_reader :proxy_address
|
18
|
+
|
19
|
+
# Port of the proxy being used by the bridge. If set to 0 then a proxy is
|
20
|
+
# not being used.
|
21
|
+
attr_reader :proxy_port
|
22
|
+
|
23
|
+
# Software version of the bridge.
|
24
|
+
attr_reader :software_version
|
25
|
+
|
26
|
+
# Contains information related to software updates.
|
27
|
+
attr_reader :software_update
|
28
|
+
|
29
|
+
# An array of whitelisted user IDs.
|
30
|
+
attr_reader :ip_whitelist
|
31
|
+
|
32
|
+
# Network mask of the bridge.
|
33
|
+
attr_reader :network_mask
|
34
|
+
|
35
|
+
# Gateway IP address of the bridge.
|
36
|
+
attr_reader :gateway
|
37
|
+
|
38
|
+
# Whether the IP address of the bridge is obtained with DHCP.
|
39
|
+
attr_reader :dhcp
|
40
|
+
|
41
|
+
def initialize(client, hash)
|
42
|
+
@client = client
|
43
|
+
unpack(hash)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Current time stored on the bridge.
|
47
|
+
def utc
|
48
|
+
json = get_configuration
|
49
|
+
DateTime.parse(json['utc'])
|
50
|
+
end
|
51
|
+
|
52
|
+
# Indicates whether the link button has been pressed within the last 30
|
53
|
+
# seconds.
|
54
|
+
def link_button_pressed?
|
55
|
+
json = get_configuration
|
56
|
+
json['linkbutton']
|
57
|
+
end
|
58
|
+
|
59
|
+
# This indicates whether the bridge is registered to synchronize data with a
|
60
|
+
# portal account.
|
61
|
+
def has_portal_services?
|
62
|
+
json = get_configuration
|
63
|
+
json['portalservices']
|
64
|
+
end
|
65
|
+
|
66
|
+
def refresh
|
67
|
+
json = get_configuration
|
68
|
+
unpack(json)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
KEYS_MAP = {
|
74
|
+
:id => :id,
|
75
|
+
:ip => :internalipaddress,
|
76
|
+
:name => :name,
|
77
|
+
:proxy_port => :proxyport,
|
78
|
+
:software_update => :swupdate,
|
79
|
+
:ip_whitelist => :whitelist,
|
80
|
+
:software_version => :swversion,
|
81
|
+
:proxy_address => :proxyaddress,
|
82
|
+
:mac_address => :macaddress,
|
83
|
+
:network_mask => :netmask,
|
84
|
+
:portal_services => :portalservices,
|
85
|
+
}
|
86
|
+
|
87
|
+
def unpack(hash)
|
88
|
+
puts hash
|
89
|
+
KEYS_MAP.each do |local_key, remote_key|
|
90
|
+
value = hash[remote_key.to_s]
|
91
|
+
next unless value
|
92
|
+
instance_variable_set("@#{local_key}", value)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def get_configuration
|
97
|
+
MultiJson.load(Net::HTTP.get(URI.parse("#{base_url}/config")))
|
98
|
+
end
|
99
|
+
|
100
|
+
def base_url
|
101
|
+
"http://#{ip}/api/#{@client.username}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/hue/client.rb
CHANGED
@@ -14,23 +14,29 @@ module Hue
|
|
14
14
|
validate_user
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
17
|
+
def bridge
|
18
18
|
# Pick the first one for now. In theory, they should all do the same thing.
|
19
|
-
|
20
|
-
raise
|
21
|
-
|
19
|
+
bridge = bridges.first
|
20
|
+
raise NoBridgeFound unless bridge
|
21
|
+
bridge
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
25
|
-
@
|
24
|
+
def bridges
|
25
|
+
@bridges ||= begin
|
26
|
+
bs = []
|
27
|
+
MultiJson.load(Net::HTTP.get(URI.parse('http://www.meethue.com/api/nupnp'))).each do |hash|
|
28
|
+
bs << Bridge.new(self, hash)
|
29
|
+
end
|
30
|
+
bs
|
31
|
+
end
|
26
32
|
end
|
27
33
|
|
28
34
|
def lights
|
29
35
|
@lights ||= begin
|
30
36
|
ls = []
|
31
|
-
json = MultiJson.load(Net::HTTP.get(URI.parse("http://#{
|
32
|
-
json.each do |key, value|
|
33
|
-
ls << Light.new(self, key, value
|
37
|
+
json = MultiJson.load(Net::HTTP.get(URI.parse("http://#{bridge.ip}/api/#{@username}")))
|
38
|
+
json['lights'].each do |key, value|
|
39
|
+
ls << Light.new(self, bridge, key, value)
|
34
40
|
end
|
35
41
|
ls
|
36
42
|
end
|
@@ -43,7 +49,12 @@ module Hue
|
|
43
49
|
private
|
44
50
|
|
45
51
|
def validate_user
|
46
|
-
response = MultiJson.load(Net::HTTP.get(URI.parse("http://#{
|
52
|
+
response = MultiJson.load(Net::HTTP.get(URI.parse("http://#{bridge.ip}/api/#{@username}")))
|
53
|
+
|
54
|
+
if response.is_a? Array
|
55
|
+
response = response.first
|
56
|
+
end
|
57
|
+
|
47
58
|
if error = response['error']
|
48
59
|
parse_error(error)
|
49
60
|
end
|
@@ -56,8 +67,8 @@ module Hue
|
|
56
67
|
username: @username
|
57
68
|
}
|
58
69
|
|
59
|
-
uri = URI.parse("http://#{
|
60
|
-
http = Net::HTTP.new(uri.
|
70
|
+
uri = URI.parse("http://#{bridge.ip}/api")
|
71
|
+
http = Net::HTTP.new(uri.host)
|
61
72
|
response = MultiJson.load(http.request_post(uri.path, MultiJson.dump(body)).body).first
|
62
73
|
|
63
74
|
if error = response['error']
|
@@ -66,10 +77,6 @@ module Hue
|
|
66
77
|
response['success']
|
67
78
|
end
|
68
79
|
|
69
|
-
def bridge_ip
|
70
|
-
base_station['internalipaddress']
|
71
|
-
end
|
72
|
-
|
73
80
|
def parse_error(error)
|
74
81
|
# Find error or return
|
75
82
|
klass = Hue::ERROR_MAP[error['type']]
|
data/lib/hue/errors.rb
CHANGED
data/lib/hue/light.rb
CHANGED
@@ -8,6 +8,9 @@ module Hue
|
|
8
8
|
# Unique identification number.
|
9
9
|
attr_reader :id
|
10
10
|
|
11
|
+
# Bridge the light is associated with
|
12
|
+
attr_reader :bridge
|
13
|
+
|
11
14
|
# A unique, editable name given to the light.
|
12
15
|
attr_accessor :name
|
13
16
|
|
@@ -78,15 +81,11 @@ module Hue
|
|
78
81
|
# Reserved for future functionality.
|
79
82
|
attr_reader :point_symbol
|
80
83
|
|
81
|
-
def initialize(client, id,
|
84
|
+
def initialize(client, bridge, id, hash)
|
82
85
|
@client = client
|
86
|
+
@bridge = bridge
|
83
87
|
@id = id
|
84
|
-
|
85
|
-
refresh
|
86
|
-
end
|
87
|
-
|
88
|
-
def [](index)
|
89
|
-
lights[index]
|
88
|
+
unpack(hash)
|
90
89
|
end
|
91
90
|
|
92
91
|
def name=(new_name)
|
@@ -99,7 +98,7 @@ module Hue
|
|
99
98
|
}
|
100
99
|
|
101
100
|
uri = URI.parse(base_url)
|
102
|
-
http = Net::HTTP.new(uri.
|
101
|
+
http = Net::HTTP.new(uri.host)
|
103
102
|
response = http.request_put(uri.path, MultiJson.dump(body))
|
104
103
|
response = MultiJson.load(response.body).first
|
105
104
|
if response['success']
|
@@ -133,28 +132,17 @@ module Hue
|
|
133
132
|
end
|
134
133
|
|
135
134
|
# @param transition The duration of the transition from the light’s current
|
136
|
-
# state to the new state. This is given as a multiple of 100ms and
|
137
|
-
# to 4 (400ms). For example, setting transistiontime:10 will
|
138
|
-
# transition last 1 second.
|
135
|
+
# state to the new state. This is given as a multiple of 100ms and
|
136
|
+
# defaults to 4 (400ms). For example, setting transistiontime:10 will
|
137
|
+
# make the transition last 1 second.
|
139
138
|
def set_state(attributes, transition = nil)
|
140
|
-
|
141
|
-
:brightness => :bri,
|
142
|
-
:saturation => :sat,
|
143
|
-
:color_temperature => :ct,
|
144
|
-
}
|
145
|
-
|
146
|
-
body = {}
|
147
|
-
attributes.each do |key, value|
|
148
|
-
new_key = map[key.to_sym]
|
149
|
-
key = new_key if new_key
|
150
|
-
body[key] = value
|
151
|
-
end
|
139
|
+
body = translate_keys(attributes)
|
152
140
|
|
153
141
|
# Add transition
|
154
142
|
body.merge!({:transitiontime => transition}) if transition
|
155
143
|
|
156
144
|
uri = URI.parse("#{base_url}/state")
|
157
|
-
http = Net::HTTP.new(uri.
|
145
|
+
http = Net::HTTP.new(uri.host)
|
158
146
|
response = http.request_put(uri.path, MultiJson.dump(body))
|
159
147
|
MultiJson.load(response.body)
|
160
148
|
end
|
@@ -162,28 +150,59 @@ module Hue
|
|
162
150
|
# Refresh the state of the lamp
|
163
151
|
def refresh
|
164
152
|
json = MultiJson.load(Net::HTTP.get(URI.parse(base_url)))
|
153
|
+
unpack(json)
|
154
|
+
end
|
165
155
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
156
|
+
private
|
157
|
+
|
158
|
+
KEYS_MAP = {
|
159
|
+
:state => :state,
|
160
|
+
:type => :type,
|
161
|
+
:name => :name,
|
162
|
+
:model => :modelid,
|
163
|
+
:software_version => :swversion,
|
164
|
+
:point_symbol => :pointsymbol
|
165
|
+
}
|
166
|
+
|
167
|
+
STATE_KEYS_MAP = {
|
168
|
+
:on => :on,
|
169
|
+
:brightness => :bri,
|
170
|
+
:hue => :hue,
|
171
|
+
:saturation => :sat,
|
172
|
+
:xy => :xy,
|
173
|
+
:color_temperature => :ct,
|
174
|
+
:alert => :alert,
|
175
|
+
:effect => :effect,
|
176
|
+
:color_mode => :colormode,
|
177
|
+
:reachable => :reachable,
|
178
|
+
}
|
179
|
+
|
180
|
+
def translate_keys(hash)
|
181
|
+
new_hash = {}
|
182
|
+
hash.each do |key, value|
|
183
|
+
new_key = KEYS_MAP[key.to_sym]
|
184
|
+
key = new_key if new_key
|
185
|
+
new_hash[key] = value
|
186
|
+
end
|
187
|
+
new_hash
|
188
|
+
end
|
189
|
+
|
190
|
+
def unpack(hash)
|
191
|
+
unpack_hash(hash, KEYS_MAP)
|
192
|
+
unpack_hash(@state, STATE_KEYS_MAP)
|
170
193
|
@x, @y = @state['xy']
|
171
|
-
@color_temperature = @state['ct']
|
172
|
-
@alert = @state['alert'].to_sym
|
173
|
-
@effect = @state['effect'].to_sym
|
174
|
-
@color_mode = @state['colormode']
|
175
|
-
@type = json['type']
|
176
|
-
@name = json['name']
|
177
|
-
@model = json['modelid']
|
178
|
-
@software_version = json['swversion']
|
179
|
-
@point_symbol = json['pointsymbol']
|
180
194
|
end
|
181
195
|
|
182
|
-
|
196
|
+
def unpack_hash(hash, map)
|
197
|
+
map.each do |local_key, remote_key|
|
198
|
+
value = hash[remote_key.to_s]
|
199
|
+
next unless value
|
200
|
+
instance_variable_set("@#{local_key}", value)
|
201
|
+
end
|
202
|
+
end
|
183
203
|
|
184
204
|
def base_url
|
185
|
-
|
186
|
-
"http://#{bridge_ip}/api/#{@client.username}/lights/#{id}"
|
205
|
+
"http://#{@bridge.ip}/api/#{@client.username}/lights/#{id}"
|
187
206
|
end
|
188
207
|
end
|
189
208
|
end
|
data/lib/hue/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Soffes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-03
|
11
|
+
date: 2013-06-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- bin/hue
|
57
57
|
- hue.gemspec
|
58
58
|
- lib/hue.rb
|
59
|
+
- lib/hue/bridge.rb
|
59
60
|
- lib/hue/cli.rb
|
60
61
|
- lib/hue/client.rb
|
61
62
|
- lib/hue/errors.rb
|
@@ -81,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
82
|
version: '0'
|
82
83
|
requirements: []
|
83
84
|
rubyforge_project:
|
84
|
-
rubygems_version: 2.0.
|
85
|
+
rubygems_version: 2.0.2
|
85
86
|
signing_key:
|
86
87
|
specification_version: 4
|
87
88
|
summary: Work with Philips Hue light bulbs from Ruby.
|