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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3c06483132e27c548f6636b9717d0fb1d7d3fb52
4
- data.tar.gz: 4fe57bd0ecb43a9a208adcb8cdef6b490b0f813e
3
+ metadata.gz: d6a7f55311b35aa3cb7e2907ecad349632e102b7
4
+ data.tar.gz: 3201fe193181c257741f03f14a71b78b78ca3ecf
5
5
  SHA512:
6
- metadata.gz: 79d882703ab4d35a2792e8b62711941cb8ff88b33a5a444c31f11c450fe1d5ef0e9f713d55dadbf36666155f63f312351f8220570e375c70c2399c5a4d0b2b13
7
- data.tar.gz: 2fa2d565f33b0a7464a906da5eebbae52f220baca044436f7c0f2e55009a461227cbe4d133bbf7226f0264fea1e3c428d9bbd10a23240115a1121415eea3ff0b
6
+ metadata.gz: 76884d923bbe4ee4084bd121caae4f0004cb25f0fcd8e0618f27acd5887c89350f412e4d765c2e0ac148c079e82f245261d0a8664eff2eb6dbb3a7a64d8f88b3
7
+ data.tar.gz: c86bbdea9bca5ec707791137c72836fae70f3a4fd9978eff41b472968391f2a32b14494bb9885fa943a8f636ac9d4e9a62de83d15bc24917fcdcdeae2829c150
@@ -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:
@@ -7,5 +7,4 @@
7
7
  * Effects
8
8
  * User management
9
9
  * Configuration
10
- * More efficient calls
11
10
  * Local UPNP
data/lib/hue.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'hue/version'
2
2
  require 'hue/errors'
3
3
  require 'hue/client'
4
+ require 'hue/bridge'
4
5
  require 'hue/light'
5
6
 
6
7
  module Hue
@@ -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
@@ -14,23 +14,29 @@ module Hue
14
14
  validate_user
15
15
  end
16
16
 
17
- def base_station
17
+ def bridge
18
18
  # Pick the first one for now. In theory, they should all do the same thing.
19
- base_station = base_stations.first
20
- raise NoBaseStationFound unless base_station
21
- base_station
19
+ bridge = bridges.first
20
+ raise NoBridgeFound unless bridge
21
+ bridge
22
22
  end
23
23
 
24
- def base_stations
25
- @base_stations ||= MultiJson.load(Net::HTTP.get(URI.parse('http://www.meethue.com/api/nupnp')))
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://#{bridge_ip}/api/#{@username}/lights")))
32
- json.each do |key, value|
33
- ls << Light.new(self, key, value['name'])
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://#{bridge_ip}/api/#{@username}")))
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://#{bridge_ip}/api")
60
- http = Net::HTTP.new(uri.hostname)
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']]
@@ -17,6 +17,7 @@ module Hue
17
17
 
18
18
  class InvalidUsername < Error; end
19
19
  class UnknownError < Error; end
20
+ class NoBridgeFound < Error; end
20
21
 
21
22
  # Status code to exception map
22
23
  ERROR_MAP = {
@@ -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, name)
84
+ def initialize(client, bridge, id, hash)
82
85
  @client = client
86
+ @bridge = bridge
83
87
  @id = id
84
- @name = name
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.hostname)
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 defaults
137
- # to 4 (400ms). For example, setting transistiontime:10 will make the
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
- map = {
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.hostname)
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
- @state = json['state']
167
- @brightness = @state['bri']
168
- @hue = @state['hue']
169
- @saturation = @state['sat']
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
- private
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
- bridge_ip = @client.base_station['internalipaddress']
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
@@ -1,3 +1,3 @@
1
1
  module Hue
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
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.0
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-21 00:00:00.000000000 Z
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.3
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.