lights 0.8.18 → 1.0.2

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,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MTUwNmZjMWQ4MzMyMjA2ODU1ZmJhMTVmNGY5ODJiNWFjZTU5ZjgyMQ==
5
- data.tar.gz: !binary |-
6
- MGQxNTExYWM5NjI1MzRlMzZlOGI1OTVlNjM2Y2YyNjlmOTEwMTFhMA==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- ZDg4MGE0MmIwNjdhNzljZmFjNmI2YWQ3ZTAyNTRkZDExYzg4MTZkZmY4N2Fi
10
- Y2ZlYWQ1Yjk4NmYzZDFiM2NlOGQzNDQ5MDgzYzE2NmM3OTE4MzAxMDQwZmZl
11
- N2I1N2M5NjA1YWY2MWM2MzQ0ZDFlNjFmNzM0MWNmZDhlMTY2ZTc=
12
- data.tar.gz: !binary |-
13
- Y2Q2OWVkMDI3ODAzMjI5NjUwYTI3MjU2YjY0MjY0NTE5YzEzNWE0MmZhODBj
14
- NDcwODRhYTc2MDQ3OWI3YzM4MWQ3ZTkyY2Q3ZDE1Y2ViODhiYjU2ZGM4MmQx
15
- OGE5NWU5N2Q2ZTFiNzE2MDNjNDAyMjgxYjljODUxMmQzMGNmNDA=
2
+ SHA256:
3
+ metadata.gz: a3bf9fc0031f505e57aeff2a521fa844f66da4d2d8f58cd72274bbe99ab16157
4
+ data.tar.gz: fd88ad10da1cdd5a82d7385e7e8eff031d13f2665ddc7db71e1f846ffb32dfa1
5
+ SHA512:
6
+ metadata.gz: f651502f6f3b129085fb3973acdff5f96bc7fe6a789148dc93c1412733c53756547586f433a9aa913eb459e1c8ead64549074106aec944f2b92edb6339e4631f
7
+ data.tar.gz: 8b732115636f705f482f1d6cd14f0af1c63fb0b6b88f0bcbec90ee9de2d30c143a965eddd0b786e9011fbf07e1933abe8d8c03f38470f950d58c9fe890c1faca
data/README.md CHANGED
@@ -16,7 +16,7 @@ Basic Usage
16
16
  ```ruby
17
17
  require 'lights'
18
18
  client = Lights.new( '192.168.x.x', 'username' )
19
- client.register_username
19
+ client.register
20
20
  client.request_bulb_list
21
21
  ```
22
22
  See [lights-examples](https://github.com/turnerba/lights-examples) for more usage examples.
@@ -26,11 +26,10 @@ CLI Quick Setup
26
26
 
27
27
  ```
28
28
  lights discover -s
29
- lights config -f --user <username>
30
29
  lights register
31
30
  lights list
32
- lights on -l all
33
- lights off -l all
31
+ lights on
32
+ lights off
34
33
  ```
35
34
 
36
35
  See [Sample Usage (Implemented)](https://github.com/turnerba/lights/wiki/Sample-Usage-(Implemented)) for more usage examples.
data/bin/lights CHANGED
@@ -18,18 +18,22 @@ class LightsCli
18
18
  def configured?
19
19
  @config["username"] && @config["bridge_ip"]
20
20
  end
21
+
22
+ def ip_configured?
23
+ @config["bridge_ip"]
24
+ end
21
25
 
22
26
  def config
23
27
  options = {}
24
28
  OptionParser.new do |opts|
25
- opts.on("-u", "--user <username>", String, "Username"){|url| options[:user]=url}
26
29
  opts.on("-i", "--ip <bridge ip>", String, "Bridge ip address"){|ip| options[:ip]=ip}
27
30
  opts.on("-f", "--force", "Force write to config file"){|f| options[:force]=f}
28
31
  opts.on("-l", "--list", "List saved configuration settings") {|l| options[:list]=l}
29
32
  end.parse!
30
33
 
31
- if !options[:user] && !options[:ip] && !options[:list]
32
- puts "Must specify username and/or bridge IP: --user <username> --ip <IP addr. of bridge>"
34
+ unless options[:ip] || options[:list]
35
+ puts "usage:"
36
+ puts " #{File.basename(__FILE__)} config (--ip <bridge IP> | --list)"
33
37
  exit 1
34
38
  end
35
39
 
@@ -52,7 +56,6 @@ class LightsCli
52
56
  end
53
57
  end
54
58
 
55
- @config["username"] = options[:user] || @config["username"]
56
59
  @config["bridge_ip"] = options[:ip] || @config["bridge_ip"]
57
60
 
58
61
  write_config
@@ -70,7 +73,8 @@ class LightsCli
70
73
  OptionParser.new do |opts|
71
74
  opts.on("-l", "--lights 1,2,...N", Array, "Which lights are in the scene"){|l| options[:lights]=l}
72
75
  opts.on("-n", "--name <name>", String, "Set scene name"){|n| options[:name]=n}
73
- opts.on("-i", "--id <id>", String, "Set scene ID"){|i| options[:id]=i}
76
+ opts.on("-r", "--recycle", "Can bridge recycle scene"){|r| options[:recycle]=r}
77
+ opts.on("-d", "--duration seconds", OptionParser::DecimalInteger, "Transition duration in seconds"){|d| options[:duration]=d}
74
78
  end.parse!
75
79
 
76
80
  if !options[:lights]
@@ -81,14 +85,12 @@ class LightsCli
81
85
  puts "Must specify scene name."
82
86
  exit 1
83
87
  end
84
- if !options[:id]
85
- puts "Must specify scene id."
86
- exit 1
87
- end
88
88
 
89
- s = Scene.new options[:id]
89
+ s = Scene.new
90
90
  s.name = options[:name]
91
91
  s.lights = options[:lights]
92
+ s.recycle = options[:recycle] || false
93
+ s.transition_time = options[:duration]
92
94
  hue.create_scene s
93
95
  when "group"
94
96
  OptionParser.new do |opts|
@@ -189,7 +191,14 @@ class LightsCli
189
191
 
190
192
  hue.delete_user id
191
193
  when "scene"
192
- STDERR.puts "Cannot delete scenes."
194
+ id = ARGV.shift
195
+
196
+ if !id
197
+ puts "Must specify scene id."
198
+ exit 1
199
+ end
200
+
201
+ hue.delete_scene id
193
202
  when nil
194
203
  STDERR.puts "Must specify a type to delete."
195
204
  else
@@ -213,8 +222,8 @@ class LightsCli
213
222
  when nil, "","lights"
214
223
  response = options[:new] ? hue.request_new_bulb_list : hue.request_bulb_list
215
224
  objects = BulbList.new(response)
216
- titles = ["ID","NAME"]
217
- methods = [:id,:name]
225
+ titles = ["ID","NAME","REACHABLE?"]
226
+ methods = [:id,:name,[:state,:reachable]]
218
227
  when "sensors"
219
228
  response = options[:new] ? hue.request_new_sensor_list : hue.request_sensor_list
220
229
  objects = SensorList.new(response)
@@ -228,8 +237,8 @@ class LightsCli
228
237
  when "scenes"
229
238
  response = hue.request_scene_list
230
239
  objects = SceneList.new(response)
231
- titles = ["ID","NAME","LIGHTS"]
232
- methods = [:id,:name,:lights]
240
+ titles = ["ID","NAME","LIGHTS","RECYCLE"]
241
+ methods = [:id,:name,:lights,:recycle]
233
242
  when "users"
234
243
  response = hue.request_config
235
244
  objects = UserList.new(response["whitelist"])
@@ -263,7 +272,9 @@ class LightsCli
263
272
 
264
273
  def register
265
274
  lights = Lights.new @config["bridge_ip"], @config["username"]
266
- response = lights.register_username
275
+ response = lights.register
276
+ @config["username"] = lights.username
277
+ write_config
267
278
  end
268
279
 
269
280
  def discover
@@ -447,12 +458,14 @@ begin
447
458
  cli.config
448
459
  elsif command == "discover"
449
460
  cli.discover
461
+ elsif !cli.ip_configured?
462
+ puts "Please run 'lights discover -s' or 'lights config --ip <IP>' before using."
463
+ elsif command == "register"
464
+ cli.register
450
465
  elsif !cli.configured?
451
- puts "Please run 'lights config' before using."
466
+ puts "Please run 'lights register' before using."
452
467
  elsif command == "list"
453
468
  cli.list
454
- elsif command == "register"
455
- cli.register
456
469
  elsif command == "on"
457
470
  cli.on
458
471
  elsif command == "off"
@@ -12,8 +12,8 @@ require 'lights/loggerconfig'
12
12
 
13
13
  class Lights
14
14
 
15
- attr_reader :bulbs
16
- def initialize(ip,username)
15
+ attr_reader :bulbs, :username
16
+ def initialize(ip,username=nil)
17
17
  @ip = ip
18
18
  @username = username
19
19
  @http = Net::HTTP.new(ip,80)
@@ -25,9 +25,9 @@ class Lights
25
25
  end
26
26
 
27
27
  def discover_hubs
28
- http = Net::HTTP.new("www.meethue.com",443)
28
+ http = Net::HTTP.new("discovery.meethue.com",443)
29
29
  http.use_ssl = true
30
- request = Net::HTTP::Get.new( "/api/nupnp" )
30
+ request = Net::HTTP::Get.new( "/" )
31
31
  response = http.request request
32
32
 
33
33
  case response.code.to_i
@@ -35,21 +35,28 @@ class Lights
35
35
  result = JSON.parse( response.body )
36
36
  result.each { |b| @bridges << Bridge.new(b) }
37
37
  else
38
+ @logger.fatal "Could not discover bridge. HTTP error #{response.code}"
39
+ @logger.fatal "Response: #{response.body}"
38
40
  raise "Unknown error"
39
41
  end
40
42
  @bridges
41
43
  end
42
44
 
43
- def register_username
44
- data = { "devicetype"=>"lights",
45
- "username"=>@username }
45
+ def register
46
+ data = { "devicetype"=>"lights" }
46
47
  response = @http.post "/api", data.to_json
47
48
  result = JSON.parse(response.body).first
48
49
  if result.has_key? "error"
49
50
  process_error result
51
+ elsif result["success"]
52
+ @username = result["success"]["username"]
50
53
  end
54
+ result
51
55
  end
52
56
 
57
+ # backwards compatibility
58
+ alias_method :register_username, :register
59
+
53
60
  def request_config
54
61
  get "config"
55
62
  end
@@ -134,7 +141,11 @@ class Lights
134
141
  end
135
142
 
136
143
  def create_scene( scene )
137
- put "scenes/#{scene.id}", scene
144
+ post "scenes/#{scene.id}", scene
145
+ end
146
+
147
+ def delete_scene( id )
148
+ delete "scenes/#{id}"
138
149
  end
139
150
 
140
151
  def delete_group( id )
@@ -165,6 +176,8 @@ private
165
176
  raise ParameterUnavailableException, result["error"]["description"]
166
177
  when 101
167
178
  raise BridgeConnectException
179
+ when 403
180
+ raise SceneLockedException, result["error"]["description"]
168
181
  else
169
182
  raise "Unknown Error: #{result["error"]["description"]}"
170
183
  end
@@ -172,6 +185,7 @@ private
172
185
 
173
186
  def get( path )
174
187
  @logger.debug "==> GET: #{path}"
188
+ raise UsernameException unless @username
175
189
  request = Net::HTTP::Get.new( "/api/#{@username}/#{path}" )
176
190
  response = @http.request request
177
191
  result = JSON.parse( response.body )
@@ -185,6 +199,7 @@ private
185
199
 
186
200
  def put( path, data={} )
187
201
  @logger.debug "==> PUT: #{path}"
202
+ raise UsernameException unless @username
188
203
  @logger.debug data.to_json
189
204
  response = @http.put( "/api/#{@username}/#{path}", data.to_json )
190
205
  result = JSON.parse( response.body )
@@ -198,6 +213,7 @@ private
198
213
 
199
214
  def post( path, data={} )
200
215
  @logger.debug "==> POST: #{path}"
216
+ raise UsernameException unless @username
201
217
  @logger.debug data.to_json
202
218
  response = @http.post( "/api/#{@username}/#{path}", data.to_json )
203
219
  result = JSON.parse( response.body )
@@ -211,6 +227,7 @@ private
211
227
 
212
228
  def delete( path )
213
229
  @logger.debug "==> DELETE: #{path}"
230
+ raise UsernameException unless @username
214
231
  request = Net::HTTP::Delete.new( "/api/#{@username}/#{path}" )
215
232
  response = @http.request request
216
233
  result = JSON.parse( response.body )
@@ -4,7 +4,6 @@ class Bridge < HObject
4
4
 
5
5
  attr_reader :id, :ip, :name, :mac
6
6
  def initialize(data = {})
7
- super
8
7
  @id = data["id"]
9
8
  @ip = data["internalipaddress"]
10
9
  @mac = data["macaddress"]
@@ -2,22 +2,29 @@ require 'lights/bulbstate'
2
2
  require 'lights/hobject'
3
3
 
4
4
  class Bulb < HObject
5
- attr_reader :id, :name, :type, :swversion, :state
5
+ attr_reader :id, :name, :type, :sw_version, :state,
6
+ :point_symbol, :model_id, :unique_id
7
+ attr_writer :name, :state
6
8
  def initialize(id,data = {})
7
- super(data)
8
9
  @id = id
9
10
  @name = data["name"]
10
11
  @type = data["type"]
11
- @swversion = data["swversion"]
12
+ @sw_version = data["swversion"]
13
+ @point_symbol = data["pointsymbol"]
14
+ @model_id = data["modelid"]
15
+ @unique_id = data["uniqueid"]
12
16
  @state = BulbState.new data["state"]
13
17
  end
14
18
 
15
19
  def data
16
- data = @data
20
+ data = {}
17
21
  data["name"] = @name if @name
18
22
  data["type"] = @type if @type
19
- data["swversion"] = @swversion if @swversion
20
- data["state"] = @state.data if !@state.data.empty?
23
+ data["swversion"] = @sw_version if @sw_version
24
+ data["state"] = @state.data unless @state.data.empty?
25
+ data["pointsymbol"] = @point_symbol if @point_symbol
26
+ data["modelid"] = @model_id if @model_id
27
+ data["uniqueid"] = @unique_id if @unique_id
21
28
  data
22
29
  end
23
30
  end
@@ -45,18 +45,21 @@ class BulbState < HObject
45
45
  :reachable, :transition_time
46
46
  def initialize( data = {} )
47
47
  data = {} if data == nil
48
- super
49
- @on = data["on"]
50
- set_bri data["bri"]
51
- set_hue data["hue"]
52
- set_sat data["sat"]
53
- set_xy data["xy"]
54
- set_ct data["ct"]
55
- set_alert data["alert"]
56
- set_effect data["effect"]
57
- set_color_mode data["colormode"]
58
48
  @reachable = data["reachable"]
59
- set_transition_time data["transitiontime"]
49
+
50
+ # bridge returns invaild values for state variables when reachable is false
51
+ unless @reachable == false
52
+ @on = data["on"]
53
+ set_bri data["bri"]
54
+ set_hue data["hue"]
55
+ set_sat data["sat"]
56
+ set_xy data["xy"]
57
+ set_ct data["ct"]
58
+ set_alert data["alert"]
59
+ set_effect data["effect"]
60
+ set_color_mode data["colormode"]
61
+ set_transition_time data["transitiontime"]
62
+ end
60
63
  end
61
64
 
62
65
  def color_mode=(value) set_color_mode(value) end
@@ -172,8 +175,8 @@ class BulbState < HObject
172
175
  end
173
176
 
174
177
  def data
175
- data = @data
176
- data["on"] = @on if (@on!=nil)
178
+ data = {}
179
+ data["on"] = @on unless @on.nil?
177
180
  data["bri"] = @bri if @bri
178
181
  data["hue"] = @hue if @hue
179
182
  data["sat"] = @sat if @sat
@@ -182,7 +185,7 @@ class BulbState < HObject
182
185
  data["alert"] = @alert if @alert
183
186
  data["effect"] = @effect if @effect
184
187
  data["colormode"] = @color_mode if @color_mode
185
- data["reachable"] = @reachable if @reachable
188
+ data["reachable"] = @reachable unless @reachable.nil?
186
189
  data["transitiontime"] = @transition_time if @transition_time
187
190
  data
188
191
  end
@@ -3,14 +3,13 @@ require 'lights/hobject'
3
3
  class Command < HObject
4
4
  attr_reader :address, :method, :body
5
5
  def initialize(data = {})
6
- super
7
6
  @address = data["address"]
8
7
  @body = data["body"]
9
8
  @method = data["method"]
10
9
  end
11
10
 
12
11
  def data
13
- data = @data
12
+ data = {}
14
13
  data["address"] = @address if @address
15
14
  data["body"] = @body if @body
16
15
  data["method"] = @method if @method
@@ -2,19 +2,58 @@ require 'lights/userlist'
2
2
  require 'lights/hobject'
3
3
 
4
4
  class HueConfig < HObject
5
- attr_reader :name, :swversion, :whitelist
5
+ attr_reader :name, :zigbee_channel, :mac, :dhcp,
6
+ :ip_address, :netmask, :gateway,
7
+ :proxy_address, :proxy_port, :utc,
8
+ :local_time, :time_zone, :whitelist,
9
+ :swversion, :api_version, :sw_update,
10
+ :link_button, :portal_services,
11
+ :portal_connection, :portal_state
6
12
  def initialize(data = {})
7
- super
8
13
  @name = data["name"]
9
- @swversion = data["swversion"]
14
+ @zigbee_channel = data["zigbeechannel"]
15
+ @mac = data["mac"]
16
+ @dhcp = data["dhcp"]
17
+ @ip_address = data["ipaddress"]
18
+ @netmask = data["netmask"]
19
+ @gateway = data["gateway"]
20
+ @proxy_address = data["proxyaddress"]
21
+ @proxy_port = data["proxyport"]
22
+ @utc = data["UTC"]
23
+ @local_time = data["localtime"]
24
+ @time_zone = data["timezone"]
10
25
  @whitelist = UserList.new(data["whitelist"])
26
+ @sw_version = data["swversion"]
27
+ @api_version = data["apiversion"]
28
+ @sw_update = data["swupdate"]
29
+ @link_button = data["linkbutton"]
30
+ @portal_services = data["portalservices"]
31
+ @portal_connection = data["portalconnection"]
32
+ @portal_state = data["portalstate"]
11
33
  end
12
34
 
13
35
  def data
14
- data = @data
36
+ data = {}
15
37
  data["name"] = @name if @name
16
- data["swversion"] = @swversion if @swversion
17
- data["whitelist"] = @whitelist.data if !@whitelist.data.empty?
38
+ data["zigbeechannel"] = @zigbee_channel if @zigbee_channel
39
+ data["mac"] = @mac if @mac
40
+ data["dhcp"] = @dhcp unless @dhcp.nil?
41
+ data["ipaddress"] = @ip_address if @ip_address
42
+ data["netmask"] = @netmask if @netmask
43
+ data["gateway"] = @gateway if @gateway
44
+ data["proxyaddress"] = @proxy_address if @proxy_address
45
+ data["proxyport"] = @proxy_port if @proxy_port
46
+ data["UTC"] = @utc if @utc
47
+ data["localtime"] = @local_time if @local_time
48
+ data["timezone"] = @time_zone if @time_zone
49
+ data["whitelist"] = @whitelist.data unless @whitelist.data.empty?
50
+ data["swversion"] = @sw_version if @sw_version
51
+ data["apiversion"] = @api_version if @api_version
52
+ data["swupdate"] = @sw_update unless @sw_update.nil?
53
+ data["linkbutton"] = @link_button unless @link_button.nil?
54
+ data["portalservices"] = @portal_services unless @portal_services.nil?
55
+ data["portalconnection"] = @portal_connection if @portal_connection
56
+ data["portalstate"] = @portal_state unless @portal_state.nil?
18
57
  data
19
58
  end
20
59
  end
@@ -11,7 +11,6 @@ class Datastore < HObject
11
11
  attr_reader :lights, :groups, :config, :rules,
12
12
  :scenes, :schedules, :sensors
13
13
  def initialize(data = {})
14
- super
15
14
  @lights = BulbList.new(data["lights"])
16
15
  @groups = GroupList.new(data["groups"])
17
16
  @config = HueConfig.new(data["config"])
@@ -32,7 +31,7 @@ class Datastore < HObject
32
31
  end
33
32
 
34
33
  def data
35
- data = @data
34
+ data = {}
36
35
  data["lights"] = @lights.data if !@lights.data.empty?
37
36
  data["groups"] = @groups.data if !@groups.data.empty?
38
37
  data["config"] = @config.data if !@config.data.empty?
@@ -12,7 +12,7 @@ end
12
12
 
13
13
  class BulbStateValueOutOfRangeException < Exception
14
14
  def initalize(msg = "Value out of range.")
15
- super(msg)
15
+ super
16
16
  end
17
17
  end
18
18
 
@@ -33,3 +33,9 @@ class ParameterUnavailableException < Exception
33
33
  super
34
34
  end
35
35
  end
36
+
37
+ class SceneLockedException < Exception
38
+ def initialize(msg = "Scene could not be removed, because it's locked.")
39
+ super
40
+ end
41
+ end
@@ -1,21 +1,22 @@
1
1
  require 'lights/hobject'
2
2
 
3
3
  class Group < HObject
4
- attr_reader :id, :data, :name, :lights, :action
4
+ attr_reader :id, :data, :name, :lights, :action, :type
5
5
  attr_writer :name, :lights, :action
6
6
  def initialize( id = nil, data = {} )
7
- super(data)
8
7
  @id = id
9
8
  @action = BulbState.new(data["action"])
10
9
  @name = data["name"]
11
10
  @lights = data["lights"]
11
+ @type = data["type"]
12
12
  end
13
13
 
14
14
  def data
15
- data = @data
15
+ data = {}
16
16
  data["name"] = @name if @name
17
17
  data["lights"] = @lights if @lights
18
- data["action"] = @action.data if @action.data != {}
18
+ data["type"] = @type if @type
19
+ data["action"] = @action.data unless @action.data.empty?
19
20
  data
20
21
  end
21
22
  end
@@ -1,6 +1,5 @@
1
1
  class HObject
2
- def initialize(data={})
3
- @data = data
2
+ def initialize(*args)
4
3
  end
5
4
 
6
5
  def to_json(options={})
@@ -9,12 +9,11 @@ class List < HObject
9
9
 
10
10
  attr_reader :list
11
11
  def initialize(data = {})
12
- super
13
12
  @list = []
14
13
  end
15
14
 
16
15
  def data
17
- data = @data
16
+ data = {}
18
17
  @list.each {|b| data[b.id] = b.data} if @list
19
18
  data
20
19
  end
@@ -1,16 +1,31 @@
1
1
  require 'lights/hobject'
2
2
 
3
3
  class Rule < HObject
4
- attr_reader :id, :data, :name
4
+ attr_reader :id, :name, :owner, :created,
5
+ :last_triggered, :times_triggered,
6
+ :status, :conditions, :actions
5
7
  def initialize( id = nil, data = {} )
6
- super(data)
7
8
  @id = id
8
9
  @name = data["name"]
10
+ @owner = data["owner"]
11
+ @created = data["created"]
12
+ @last_triggered = data["lasttriggered"]
13
+ @times_triggered = data["timestriggered"]
14
+ @status = data["status"]
15
+ @conditions = data["conditions"]
16
+ @actions = data["actions"]
9
17
  end
10
18
 
11
19
  def data
12
- data = @data
20
+ data = {}
13
21
  data["name"] = @name if @name
22
+ data["owner"] = @owner if @owner
23
+ data["created"] = @created if @created
24
+ data["lasttriggered"] = @last_triggered if @last_triggered
25
+ data["timestriggered"] = @times_triggered if @times_triggered
26
+ data["status"] = @status if @status
27
+ data["conditions"] = @conditions if @conditions
28
+ data["actions"] = @actions if @actions
14
29
  data
15
30
  end
16
31
  end
@@ -1,20 +1,23 @@
1
1
  require 'lights/hobject'
2
2
 
3
3
  class Scene < HObject
4
- attr_accessor :id, :name, :active, :lights
5
- def initialize(id,data = {})
6
- super(data)
4
+ attr_accessor :id, :name, :active, :lights, :recycle, :transition_time
5
+ def initialize(id = nil,data = {})
7
6
  @id = id
8
7
  @name = data["name"]
9
8
  @active = data["active"]
10
9
  @lights = data["lights"]
10
+ @recycle = data["recycle"]
11
+ @transition_time = data["transitiontime"]
11
12
  end
12
13
 
13
14
  def data
14
15
  data = {}
15
16
  data["name"] = @name if @name
16
- data["active"] = @active if @active
17
+ data["active"] = @active unless @active.nil?
17
18
  data["lights"] = @lights if @lights
19
+ data["recycle"] = @recycle unless @recycle.nil?
20
+ data["transitiontime"] = @transition_time if @transition_time
18
21
  data
19
22
  end
20
23
  end
@@ -2,13 +2,17 @@ require 'lights/command'
2
2
  require 'lights/hobject'
3
3
 
4
4
  class Schedule < HObject
5
- attr_reader :id, :name, :time, :status
5
+ attr_reader :id, :name, :time, :status,
6
+ :description, :local_time,
7
+ :created, :command
6
8
  def initialize(id,data = {})
7
- super(data)
8
9
  @id = id
9
10
  @name = data["name"]
10
11
  @time = data["time"]
11
12
  @status = data["status"]
13
+ @description = data["description"]
14
+ @local_time = data["localtime"]
15
+ @created = data["created"]
12
16
  @command = Command.new(data["command"])
13
17
  end
14
18
 
@@ -17,11 +21,14 @@ class Schedule < HObject
17
21
  end
18
22
 
19
23
  def data
20
- data = @data
24
+ data = {}
21
25
  data["name"] = @name if @name
22
26
  data["time"] = @time if @time
23
27
  data["status"] = @status if @status
24
- data["command"] = @command.data if !@command.data.empty?
28
+ data["description"] = @description if @description
29
+ data["localtime"] = @local_time if @local_time
30
+ data["created"] = @created if @created
31
+ data["command"] = @command.data unless @command.data.empty?
25
32
  data
26
33
  end
27
34
  end
@@ -1,35 +1,25 @@
1
1
  class SensorState < HObject
2
2
  attr_reader :last_updated
3
3
  def initialize(data)
4
- super
5
4
  @last_updated = data["lastupdated"]
5
+ @daylight = data["daylight"]
6
+ @button_event = data["buttonevent"]
6
7
  end
7
8
 
8
9
  def data
9
- data = @data
10
+ data = {}
10
11
  data["lastupdated"] = @last_updated if @last_updated
11
- data
12
- end
13
- end
14
-
15
- class TapState < SensorState
16
- attr_reader :button_event
17
- def initialize(data)
18
- super
19
- @button_event = data["button_event"]
20
- end
21
-
22
- def data
23
- data = @data
24
- data["button_event"] = @button_event if @button_event
12
+ data["daylight"] = @daylight unless @daylight.nil?
13
+ data["buttonevent"] = @button_event if @button_event
25
14
  data
26
15
  end
27
16
  end
28
17
 
29
18
  class Sensor < HObject
30
- attr_reader :id, :data, :name, :type, :model_id, :manufacturer_name, :unique_id, :sw_version, :state
19
+ attr_reader :id, :data, :name, :type, :model_id,
20
+ :manufacturer_name, :unique_id,
21
+ :sw_version, :state
31
22
  def initialize( id, data = {} )
32
- super(data)
33
23
  @id = id
34
24
  @name = data["name"]
35
25
  @type = data["type"]
@@ -37,19 +27,20 @@ class Sensor < HObject
37
27
  @manufacturer_name = data["manufacturername"]
38
28
  @unique_id = data["uniqueid"]
39
29
  @sw_version = data["swversion"]
30
+ @config = data["config"]
40
31
  @state = SensorState.new(data["state"])
41
- #@config = SensorConfig.new(data["config"])
42
32
  end
43
33
 
44
34
  def data
45
- data = @data
35
+ data = {}
46
36
  data["name"] = @name if @name
47
37
  data["type"] = @type if @type
48
38
  data["modelid"] = @model_id if @model_id
49
39
  data["manufacturername"] = @manufacturer_name if @manufacturer_name
50
40
  data["uniqueid"] = @unique_id if @unique_id
51
41
  data["swversion"] = @sw_version if @sw_version
52
- data["state"] = @state.data if @state.data if !@state.data.empty?
42
+ data["config"] = @config if @config
43
+ data["state"] = @state.data unless @state.data.empty?
53
44
  data
54
45
  end
55
46
  end
@@ -3,7 +3,6 @@ require 'lights/hobject'
3
3
  class User < HObject
4
4
  attr_reader :id, :name, :create_date, :last_use_date
5
5
  def initialize( id, data = {} )
6
- super(data)
7
6
  @id = id
8
7
  @name = data["name"]
9
8
  @create_date = data["create date"]
@@ -11,7 +10,7 @@ class User < HObject
11
10
  end
12
11
 
13
12
  def data
14
- data = @data
13
+ data = {}
15
14
  data["name"] = @name if @name
16
15
  data["create date"] = @create_date if @create_date
17
16
  data["last use date"] = @last_use_date if @last_use_date
@@ -1,3 +1,3 @@
1
1
  module LightsConst
2
- VERSION = "0.8.18"
2
+ VERSION = "1.0.2"
3
3
  end
@@ -2,6 +2,7 @@
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'lights/version'
5
+ require 'date'
5
6
 
6
7
  Gem::Specification.new do |s|
7
8
  s.name = 'lights'
@@ -12,14 +13,14 @@ Gem::Specification.new do |s|
12
13
  s.summary = "lights"
13
14
  s.homepage = 'http://rubygems.org/gems/lights'
14
15
  s.license = 'MIT'
15
- s.date = '2014-10-11'
16
+ s.date = Date.today.to_s
16
17
 
17
18
  s.files = `git ls-files`.split($/)
18
19
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
20
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
20
21
  s.require_paths = ["lib"]
21
22
 
22
- s.add_runtime_dependency "simpletable", "~> 0.3.1"
23
+ s.add_runtime_dependency "simpletable", "~> 0.3.2"
23
24
 
24
25
  s.add_development_dependency "bundler", "~> 1.3"
25
26
  s.add_development_dependency "rake"
@@ -7,6 +7,13 @@ describe Bulb do
7
7
  bulb.name.should eql "test name"
8
8
  end
9
9
 
10
+ it "properly set name parameter" do
11
+ data = { "name" => "test name" }
12
+ bulb = Bulb.new(1,data)
13
+ bulb.name = "new test name"
14
+ bulb.name.should eql "new test name"
15
+ end
16
+
10
17
  it "properly creates state object" do
11
18
  data = {
12
19
  "name" => "test name",
@@ -248,6 +248,16 @@ describe BulbState do
248
248
  expect { b.ct = BulbState::MIN_CT - 1 }.to raise_error
249
249
  end
250
250
 
251
+ it "should ignore out of range color temperature when 'reachable'= false" do
252
+ state = {
253
+ "reachable" => false,
254
+ "ct" => 0
255
+ }
256
+ b = BulbState.new state
257
+ b.data["ct"].should eq nil
258
+ b.data["reachable"].should eq false
259
+ end
260
+
251
261
  # EFFECT
252
262
  it "should properly set effect value in constructor" do
253
263
  data = { "effect" => BulbState::Effect::COLORLOOP }
@@ -2,15 +2,45 @@ require 'lights'
2
2
 
3
3
  describe Datastore do
4
4
  it "properly reconstructs sub objects" do
5
+ data = JSON.parse(DATASTORE_JSON)
6
+ ds = Datastore.new data
7
+ ds.data.should eql data
8
+ end
9
+
10
+ it "properly reconstructs light objects" do
5
11
  data = JSON.parse(DATASTORE_JSON)
6
12
  ds = Datastore.new data
7
13
  ds.lights.data.should eql data["lights"]
14
+ end
15
+ it "properly reconstructs group objects" do
16
+ data = JSON.parse(DATASTORE_JSON)
17
+ ds = Datastore.new data
8
18
  ds.groups.data.should eql data["groups"]
19
+ end
20
+ it "properly reconstructs rule objects" do
21
+ data = JSON.parse(DATASTORE_JSON)
22
+ ds = Datastore.new data
9
23
  ds.rules.data.should eql data["rules"]
24
+ end
25
+ it "properly reconstructs scene objects" do
26
+ data = JSON.parse(DATASTORE_JSON)
27
+ ds = Datastore.new data
10
28
  ds.scenes.data.should eql data["scenes"]
29
+ end
30
+ it "properly reconstructs schedule objects" do
31
+ data = JSON.parse(DATASTORE_JSON)
32
+ ds = Datastore.new data
11
33
  ds.schedules.data.should eql data["schedules"]
34
+ end
35
+ it "properly reconstructs sensor objects" do
36
+ data = JSON.parse(DATASTORE_JSON)
37
+ ds = Datastore.new data
12
38
  ds.sensors.data.should eql data["sensors"]
13
- ds.data.should eql data
39
+ end
40
+ it "properly reconstructs config object" do
41
+ data = JSON.parse(DATASTORE_JSON)
42
+ ds = Datastore.new data
43
+ ds.config.data.should eql data["config"]
14
44
  end
15
45
  end
16
46
 
@@ -19,7 +49,7 @@ DATASTORE_JSON = %Q{
19
49
  "lights": {
20
50
  "1": {
21
51
  "state": {
22
- "on": true,
52
+ "on": false,
23
53
  "bri": 254,
24
54
  "hue": 34495,
25
55
  "sat": 232,
@@ -227,7 +257,7 @@ DATASTORE_JSON = %Q{
227
257
  "name": "Philips hue",
228
258
  "zigbeechannel": 25,
229
259
  "mac": "00:11:22:33:44:55",
230
- "dhcp": true,
260
+ "dhcp": false,
231
261
  "ipaddress": "192.168.1.27",
232
262
  "netmask": "255.255.255.0",
233
263
  "gateway": "192.168.1.1",
@@ -269,7 +299,7 @@ DATASTORE_JSON = %Q{
269
299
  "notify": false
270
300
  },
271
301
  "linkbutton": false,
272
- "portalservices": true,
302
+ "portalservices": false,
273
303
  "portalconnection": "connected",
274
304
  "portalstate": {
275
305
  "signedon": true,
@@ -320,7 +350,7 @@ DATASTORE_JSON = %Q{
320
350
  "4",
321
351
  "5"
322
352
  ],
323
- "active": true
353
+ "active": false
324
354
  },
325
355
  "da01b1eaf-on-0": {
326
356
  "name": "Purple on 0",
@@ -2,22 +2,152 @@ require 'lights'
2
2
 
3
3
  describe Group do
4
4
  it "properly parses input parameters" do
5
- data = {
6
- "key1" => "value 1",
7
- "key2" => "value 2",
8
- }
5
+ data = JSON.parse(GROUPS_JSON)["1"]
9
6
  group = Group.new(1,data)
10
7
  group.id.should eql 1
11
- group.data.should eql data
8
+ group.name.should eql "Ceiling light"
9
+ group.type.should eql "LightGroup"
10
+ group.lights.should eql ["1","2","3","4"]
12
11
  end
13
12
 
14
13
  it "properly reconstucts object hash" do
15
- data = {
16
- "key1" => "value 1",
17
- "key2" => "value 2",
18
- }
14
+ data = JSON.parse(GROUPS_JSON)["1"]
19
15
  group = Group.new(1,data)
20
16
  group.id.should eql 1
21
17
  group.data.should eql data
22
18
  end
23
19
  end
20
+
21
+ GROUPS_JSON = %Q{
22
+ {
23
+ "1": {
24
+ "name": "Ceiling light",
25
+ "lights": [
26
+ "1",
27
+ "2",
28
+ "3",
29
+ "4"
30
+ ],
31
+ "type": "LightGroup",
32
+ "action": {
33
+ "on": true,
34
+ "bri": 254,
35
+ "hue": 56100,
36
+ "sat": 232,
37
+ "effect": "none",
38
+ "xy": [
39
+ 0.4119,
40
+ 0.1949
41
+ ],
42
+ "ct": 293,
43
+ "colormode": "xy"
44
+ }
45
+ },
46
+ "2": {
47
+ "name": "Lamp",
48
+ "lights": [
49
+ "5"
50
+ ],
51
+ "type": "LightGroup",
52
+ "action": {
53
+ "on": true,
54
+ "bri": 254,
55
+ "hue": 56100,
56
+ "sat": 232,
57
+ "effect": "none",
58
+ "xy": [
59
+ 0.4119,
60
+ 0.1949
61
+ ],
62
+ "ct": 293,
63
+ "colormode": "xy"
64
+ }
65
+ },
66
+ "3": {
67
+ "name": "HueCraft_Ambiance1",
68
+ "lights": [
69
+ "1",
70
+ "2"
71
+ ],
72
+ "type": "LightGroup",
73
+ "action": {
74
+ "on": true,
75
+ "bri": 254,
76
+ "hue": 56100,
77
+ "sat": 232,
78
+ "effect": "none",
79
+ "xy": [
80
+ 0.4119,
81
+ 0.1949
82
+ ],
83
+ "ct": 293,
84
+ "colormode": "xy"
85
+ }
86
+ },
87
+ "4": {
88
+ "name": "HueCraft_Ambiance2",
89
+ "lights": [
90
+ "3",
91
+ "4"
92
+ ],
93
+ "type": "LightGroup",
94
+ "action": {
95
+ "on": true,
96
+ "bri": 254,
97
+ "hue": 56100,
98
+ "sat": 232,
99
+ "effect": "none",
100
+ "xy": [
101
+ 0.4119,
102
+ 0.1949
103
+ ],
104
+ "ct": 293,
105
+ "colormode": "xy"
106
+ }
107
+ },
108
+ "5": {
109
+ "name": "HueCraft_Effect1",
110
+ "lights": [
111
+ "5"
112
+ ],
113
+ "type": "LightGroup",
114
+ "action": {
115
+ "on": true,
116
+ "bri": 254,
117
+ "hue": 56100,
118
+ "sat": 232,
119
+ "effect": "none",
120
+ "xy": [
121
+ 0.4119,
122
+ 0.1949
123
+ ],
124
+ "ct": 293,
125
+ "colormode": "xy"
126
+ }
127
+ },
128
+ "6": {
129
+ "name": "HueCraft_HueCraft",
130
+ "lights": [
131
+ "1",
132
+ "2",
133
+ "3",
134
+ "4",
135
+ "5"
136
+ ],
137
+ "type": "LightGroup",
138
+ "action": {
139
+ "on": true,
140
+ "bri": 254,
141
+ "hue": 56100,
142
+ "sat": 232,
143
+ "effect": "none",
144
+ "xy": [
145
+ 0.4119,
146
+ 0.1949
147
+ ],
148
+ "ct": 293,
149
+ "colormode": "xy"
150
+ }
151
+ }
152
+ }
153
+ }
@@ -4,8 +4,6 @@ describe Rule do
4
4
  it "properly reconstucts object hash" do
5
5
  data = {
6
6
  "name" => "test name",
7
- "key1" => "value 1",
8
- "key2" => "value 2",
9
7
  }
10
8
  rule = Rule.new(1,data)
11
9
  rule.id.should eql 1
metadata CHANGED
@@ -1,97 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lights
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.18
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brady Turner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-11 00:00:00.000000000 Z
11
+ date: 2020-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simpletable
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.1
19
+ version: 0.3.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.3.1
26
+ version: 0.3.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.3'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ! '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ! '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '2.6'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.6'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: cucumber
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ! '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ! '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: aruba
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ! '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ! '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  description: Client library and CLI for controlling Philips Hue lights.
@@ -101,7 +101,7 @@ executables:
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
- - .gitignore
104
+ - ".gitignore"
105
105
  - Gemfile
106
106
  - LICENSE.txt
107
107
  - README.md
@@ -154,17 +154,16 @@ require_paths:
154
154
  - lib
155
155
  required_ruby_version: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - ! '>='
157
+ - - ">="
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
160
  required_rubygems_version: !ruby/object:Gem::Requirement
161
161
  requirements:
162
- - - ! '>='
162
+ - - ">="
163
163
  - !ruby/object:Gem::Version
164
164
  version: '0'
165
165
  requirements: []
166
- rubyforge_project:
167
- rubygems_version: 2.0.6
166
+ rubygems_version: 3.0.6
168
167
  signing_key:
169
168
  specification_version: 4
170
169
  summary: lights