hue 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.