hue-lib 0.6.0 → 0.7.0
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.
- data/README.md +9 -8
- data/hue-lib.gemspec +4 -3
- data/lib/hue/animations/candle.rb +54 -0
- data/lib/hue/animations/sunrise.rb +106 -0
- data/lib/hue/bridge.rb +23 -28
- data/lib/hue/bulb.rb +33 -332
- data/lib/hue/colors/color.rb +35 -0
- data/lib/hue/colors/color_temperature.rb +85 -0
- data/lib/hue/colors/hue_saturation.rb +104 -0
- data/lib/hue/colors/rgb.rb +102 -0
- data/lib/hue/colors/xy.rb +63 -0
- data/lib/hue/colors.rb +42 -0
- data/lib/hue.rb +29 -8
- data/spec/hue/bulb_spec.rb +25 -15
- data/spec/hue/colors/color_spec.rb +33 -0
- data/spec/hue/colors/color_temperature_spec.rb +106 -0
- data/spec/hue/colors/hue_saturation_spec.rb +91 -0
- data/spec/hue/colors/rgb_spec.rb +64 -0
- data/spec/hue/colors/xy_spec.rb +51 -0
- data/spec/hue/colors_spec.rb +92 -0
- data/spec/hue_spec.rb +8 -0
- metadata +20 -4
data/README.md
CHANGED
@@ -64,18 +64,19 @@ If you know the ID number of a particular lamp, you can access it directly.
|
|
64
64
|
>> b.on?
|
65
65
|
=> true
|
66
66
|
|
67
|
-
#
|
68
|
-
>> b.settings
|
69
|
-
=> {"ct"=>343, "on"=>true, "bri"=>240}
|
70
|
-
|
67
|
+
# brightness
|
71
68
|
>> b.brightness = 128
|
72
69
|
=> 128
|
73
70
|
|
74
|
-
|
75
|
-
|
71
|
+
# color
|
72
|
+
>> b.color = Hue::Colors::ColorTemperature.new(6500)
|
73
|
+
=> Temperature=6500°K (153 mired)
|
74
|
+
|
75
|
+
>> b.color = Hue::Colors::HueSaturation.new(10_000, 255)
|
76
|
+
=> Hue=10000, Saturation=255
|
76
77
|
|
77
|
-
>> b.
|
78
|
-
=>
|
78
|
+
>> b.color = Hue::Colors::XY.new(0.5, 0.5)
|
79
|
+
=> XY=[0.5, 0.5]
|
79
80
|
|
80
81
|
# blinking
|
81
82
|
>> b.blinking?
|
data/hue-lib.gemspec
CHANGED
@@ -3,12 +3,13 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "hue-lib"
|
6
|
-
s.version = '0.
|
6
|
+
s.version = '0.7.0'
|
7
7
|
s.authors = ["Birkir A. Barkarson", "Aaron Hurley"]
|
8
8
|
s.email = ["birkirb@stoicviking.net"]
|
9
9
|
s.homepage = "https://github.com/birkirb/hue-lib"
|
10
|
-
s.summary = %q{Ruby library for controlling
|
11
|
-
s.description =
|
10
|
+
s.summary = %q{Ruby library for controlling the Philips Hue system's lights and bridge.}
|
11
|
+
s.description = %q{Library allowing registration and invocation of a registered Philips Hue app.
|
12
|
+
Convinient objects allow executing commands on the bridge or individual bulbs.}
|
12
13
|
|
13
14
|
s.rubyforge_project = "hue-lib"
|
14
15
|
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Hue
|
2
|
+
module Animations
|
3
|
+
module Candle
|
4
|
+
|
5
|
+
public
|
6
|
+
|
7
|
+
def candle(repeat = 15)
|
8
|
+
# 0-65536 for hue, 182 per deg. Ideal 30-60 deg (5460-10920)
|
9
|
+
stash!
|
10
|
+
on if off?
|
11
|
+
|
12
|
+
repeat.times do
|
13
|
+
hue = ((rand * 3460) + 5460).to_i
|
14
|
+
sat = rand(64) + 170
|
15
|
+
bri = rand(32) + 16
|
16
|
+
|
17
|
+
delay = (rand * 0.35) + (@delay ||= 0)
|
18
|
+
update(hue: hue, sat: sat, bri: bri, transitiontime: (delay * 10).to_i)
|
19
|
+
sleep delay
|
20
|
+
end
|
21
|
+
restore!
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def options_with_colorstate
|
27
|
+
options.merge case state['colormode']
|
28
|
+
when 'ct'
|
29
|
+
{'ct' => state['ct']}
|
30
|
+
when 'xy'
|
31
|
+
{'xy' => state['xy']}
|
32
|
+
when 'hs'
|
33
|
+
{'hue' => state['hue'], 'sat' => state['sat']}
|
34
|
+
end.merge('on' => state['on'], 'bri' => state['bri'])
|
35
|
+
end
|
36
|
+
|
37
|
+
def restore!
|
38
|
+
if stash
|
39
|
+
update(@stash)
|
40
|
+
unstash!
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def stash!
|
45
|
+
@stash ||= options_with_colorstate
|
46
|
+
end
|
47
|
+
|
48
|
+
def unstash!
|
49
|
+
@stash = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Hue
|
2
|
+
module Animations
|
3
|
+
module Sunrise
|
4
|
+
|
5
|
+
SUN_STEPS = [ 1.5, 2, 3, 1, 4, 2.5 ]
|
6
|
+
SUN_TIMES = [ 3, 3, 3, 1, 2, 1]
|
7
|
+
|
8
|
+
public
|
9
|
+
|
10
|
+
# Experimental Sunrise/Sunset action
|
11
|
+
# this will transition from off and warm light to on and daytime light
|
12
|
+
# in a curve that mimics the actual sunrise.
|
13
|
+
|
14
|
+
def perform_sunrise(total_time_in_minutes = 18)
|
15
|
+
# total_time / 18 steps == time_per_step
|
16
|
+
# the multiplier should be 600 * time per step
|
17
|
+
minutes_per_step = total_time_in_minutes / 18.0
|
18
|
+
multiplier = (minutes_per_step * 60 * 10).to_i
|
19
|
+
|
20
|
+
perform_sun_transition total_time_in_minutes, sunrise_steps(multiplier)
|
21
|
+
end
|
22
|
+
|
23
|
+
def perform_sunrise(total_time_in_minutes = 18)
|
24
|
+
multiplier = sunrise_multiplier total_time_in_minutes
|
25
|
+
steps = sunrise_steps(multiplier)
|
26
|
+
if on?
|
27
|
+
puts "ON! #{steps[0][:bri]} :: #{brightness} :: #{brightness > steps[0][:bri]}"
|
28
|
+
while brightness >= steps[0][:bri]
|
29
|
+
steps.shift
|
30
|
+
end
|
31
|
+
end
|
32
|
+
steps.each_with_index do |step, i|
|
33
|
+
update step.merge(on: true)
|
34
|
+
sleep(step[:transitiontime] / 10.0)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def perform_sunset(total_time_in_minutes = 18)
|
39
|
+
multiplier = sunrise_multiplier total_time_in_minutes
|
40
|
+
steps = sunset_steps(multiplier)
|
41
|
+
if on?
|
42
|
+
puts "ON! #{steps[0][:bri]} :: #{brightness} :: #{brightness > steps[0][:bri]}"
|
43
|
+
while brightness <= steps[0][:bri]
|
44
|
+
steps.shift
|
45
|
+
end
|
46
|
+
end
|
47
|
+
steps.each_with_index do |step, i|
|
48
|
+
update step.merge(on: true)
|
49
|
+
sleep(step[:transitiontime] / 10.0)
|
50
|
+
end
|
51
|
+
off
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
|
57
|
+
def sunrise_multiplier(total_time_in_minutes)
|
58
|
+
# total_time / 18 steps == time_per_step
|
59
|
+
# the multiplier should be 600 * time per step
|
60
|
+
minutes_per_step = total_time_in_minutes / 18.0
|
61
|
+
(minutes_per_step * 60 * 10).to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
def sunrise_brightness
|
65
|
+
sun_bri_unit = 10
|
66
|
+
SUN_STEPS.inject([0]){|all, i| all << ((i * sun_bri_unit) + all[-1]).to_i } << 255
|
67
|
+
end
|
68
|
+
|
69
|
+
def sunrise_temps
|
70
|
+
sun_temp_unit = 16
|
71
|
+
SUN_STEPS.inject([500]){|all, i| all << (all[-1] - (i * sun_temp_unit)).to_i} << 200
|
72
|
+
end
|
73
|
+
|
74
|
+
def sunrise_times
|
75
|
+
[0, SUN_TIMES, 5].flatten
|
76
|
+
end
|
77
|
+
|
78
|
+
def sunset_times
|
79
|
+
[0, 5, SUN_TIMES.reverse].flatten
|
80
|
+
end
|
81
|
+
|
82
|
+
def sunrise_steps(multiplier = 600)
|
83
|
+
bri_steps = sunrise_brightness
|
84
|
+
tmp_steps = sunrise_temps
|
85
|
+
|
86
|
+
steps = []
|
87
|
+
sunrise_times.each_with_index do |t, i|
|
88
|
+
steps << {bri: bri_steps[i], ct: tmp_steps[i], transitiontime: (t * multiplier)}
|
89
|
+
end
|
90
|
+
steps
|
91
|
+
end
|
92
|
+
|
93
|
+
def sunset_steps(multiplier = 600)
|
94
|
+
bri_steps = sunrise_brightness.reverse
|
95
|
+
tmp_steps = sunrise_temps.reverse
|
96
|
+
|
97
|
+
steps = []
|
98
|
+
sunset_times.each_with_index do |t, i|
|
99
|
+
steps << {bri: bri_steps[i], ct: tmp_steps[i], transitiontime: (t * multiplier)}
|
100
|
+
end
|
101
|
+
steps
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/hue/bridge.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'socket'
|
2
2
|
require 'timeout'
|
3
|
+
require 'logger'
|
3
4
|
|
4
5
|
module Hue
|
5
6
|
class Bridge
|
@@ -73,50 +74,44 @@ module Hue
|
|
73
74
|
end
|
74
75
|
|
75
76
|
def index(url)
|
76
|
-
|
77
|
-
parse_and_check_response(Net::HTTP.new(url.host, url.port).start { |http| http.request(request) })
|
77
|
+
receive(Net::HTTP::Get, url)
|
78
78
|
end
|
79
79
|
|
80
80
|
def update(url, settings = {})
|
81
|
-
|
82
|
-
request.body = settings.to_json
|
83
|
-
parse_and_check_response(Net::HTTP.new(url.host, url.port).start { |http| http.request(request) })
|
81
|
+
receive(Net::HTTP::Put, url, settings.to_json)
|
84
82
|
end
|
85
83
|
|
86
84
|
def delete(url, settings = {})
|
87
|
-
|
88
|
-
request.body = settings.to_json
|
89
|
-
parse_and_check_response(Net::HTTP.new(url.host, url.port).start{ |http| http.request(request) })
|
85
|
+
receive(Net::HTTP::Delete, url, settings.to_json)
|
90
86
|
end
|
91
87
|
|
92
88
|
def create(url, settings = {})
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
89
|
+
receive(Net::HTTP::Post, url, settings.to_json)
|
90
|
+
end
|
91
|
+
|
92
|
+
def receive(request_class, url, payload = nil)
|
93
|
+
request = request_class.new(url.request_uri, initheader = {'Content-Type' =>'application/json'})
|
94
|
+
request.body = payload if payload
|
95
|
+
Hue.logger.info("Sending #{payload.to_s if payload} to #{url.to_s}")
|
96
|
+
response = nil
|
97
|
+
begin
|
98
|
+
response = Net::HTTP.new(url.host, url.port).start { |http| http.request(request) }
|
99
|
+
rescue => err
|
100
|
+
Hue.logger.error(err.message)
|
101
|
+
raise Hue::Error.new("Problem reaching bridge.", err)
|
102
|
+
end
|
97
103
|
|
98
|
-
|
99
|
-
|
104
|
+
if response && response.code.to_s != '200'
|
105
|
+
Hue.logger.info("Error with response #{response.code} #{response.message}")
|
106
|
+
raise Hue::Error.new("Unexpected response: #{response.code}, #{response.message}")
|
107
|
+
else
|
100
108
|
json = JSON.parse(response.body)
|
109
|
+
Hue.logger.info("Response #{response.code} #{response.message}: #{json}")
|
101
110
|
if json.is_a?(Array) && error = json.first['error']
|
102
111
|
raise Hue::API::Error.new(error)
|
103
112
|
else
|
104
113
|
json
|
105
114
|
end
|
106
|
-
else
|
107
|
-
raise Hue::Error.new("Unexpected response: #{response.code}, #{response.message}")
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def display(response = nil)
|
112
|
-
if response and response.code.to_s != '200'
|
113
|
-
# Output to logger
|
114
|
-
# puts "Response #{response.code} #{response.message}: #{JSON.parse(response.body).first}"
|
115
|
-
false
|
116
|
-
else
|
117
|
-
# Output to logger
|
118
|
-
# puts "Response #{response.code} #{response.message}: #{JSON.parse(response.body).first}"
|
119
|
-
true
|
120
115
|
end
|
121
116
|
end
|
122
117
|
|
data/lib/hue/bulb.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
+
require_relative 'animations/candle'
|
2
|
+
require_relative 'animations/sunrise'
|
3
|
+
|
1
4
|
module Hue
|
2
5
|
class Bulb
|
3
6
|
|
7
|
+
BRIGHTNESS_MAX = 255
|
8
|
+
|
9
|
+
include Animations::Candle
|
10
|
+
include Animations::Sunrise
|
11
|
+
|
4
12
|
public
|
5
13
|
|
6
14
|
attr_reader :id, :bridge
|
@@ -63,58 +71,39 @@ module Hue
|
|
63
71
|
alias :bri :brightness
|
64
72
|
|
65
73
|
def brightness=(bri)
|
66
|
-
|
74
|
+
if scale = Hue.percent_to_unit_interval(bri)
|
75
|
+
update(bri: (scale * BRIGHTNESS_MAX).round)
|
76
|
+
else
|
77
|
+
update(bri: bri.to_i)
|
78
|
+
end
|
67
79
|
brightness
|
68
80
|
end
|
69
81
|
|
70
82
|
alias :bri= :brightness=
|
71
83
|
|
72
|
-
def
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
HUE_MAX = 65536.0
|
77
|
-
HUE_DEGREES = 360
|
78
|
-
HUE_SCALE = HUE_MAX / HUE_DEGREES
|
79
|
-
|
80
|
-
def hue=(_hue)
|
81
|
-
_hue = (_hue * HUE_SCALE).to_i
|
82
|
-
update(hue: _hue)
|
83
|
-
hue
|
84
|
+
def brightness_in_unit_interval
|
85
|
+
brightness / BRIGHTNESS_MAX.to_f
|
84
86
|
end
|
85
87
|
|
86
|
-
def
|
87
|
-
|
88
|
+
def brightness_percent
|
89
|
+
(brightness_in_unit_interval * 100).round
|
88
90
|
end
|
89
91
|
|
90
|
-
|
91
|
-
|
92
|
-
def saturation=(_sat)
|
93
|
-
update(sat: _sat)
|
94
|
-
sat
|
92
|
+
def color_mode
|
93
|
+
self[:colormode]
|
95
94
|
end
|
96
95
|
|
97
|
-
alias :
|
96
|
+
alias :colormode :color_mode
|
98
97
|
|
99
|
-
def
|
100
|
-
|
98
|
+
def color
|
99
|
+
set_color
|
101
100
|
end
|
102
101
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
update(ct: [[_ct, 154].max, 500].min)
|
107
|
-
colortemp
|
102
|
+
def color=(col)
|
103
|
+
update(col.to_hash)
|
104
|
+
set_color
|
108
105
|
end
|
109
106
|
|
110
|
-
alias :ct= :color_temperature=
|
111
|
-
|
112
|
-
def color_mode
|
113
|
-
self[:colormode]
|
114
|
-
end
|
115
|
-
|
116
|
-
alias :colormode :color_mode
|
117
|
-
|
118
107
|
def blinking?
|
119
108
|
!solid?
|
120
109
|
end
|
@@ -146,312 +135,24 @@ module Hue
|
|
146
135
|
self.options[:transitiontime] = (time * 10).to_i
|
147
136
|
end
|
148
137
|
|
149
|
-
protected
|
150
|
-
|
151
|
-
def settings
|
152
|
-
options.merge case state['colormode']
|
153
|
-
when 'ct'
|
154
|
-
{'ct' => state['ct']}
|
155
|
-
when 'xy'
|
156
|
-
{'xy' => state['xy']}
|
157
|
-
when 'hs'
|
158
|
-
{'hue' => state['hue'], 'sat' => state['sat']}
|
159
|
-
end.merge('on' => state['on'], 'bri' => state['bri'])
|
160
|
-
end
|
161
|
-
|
162
|
-
def rgb
|
163
|
-
send %(#{colormode}_to_rgb)
|
164
|
-
end
|
165
|
-
|
166
|
-
def red
|
167
|
-
rgb[:red]
|
168
|
-
end
|
169
|
-
|
170
|
-
def green
|
171
|
-
rgb[:green]
|
172
|
-
end
|
173
|
-
|
174
|
-
def blue
|
175
|
-
rgb[:blue]
|
176
|
-
end
|
177
|
-
|
178
|
-
def red=(_red)
|
179
|
-
self.rgb = [_red, green, blue]
|
180
|
-
end
|
181
|
-
|
182
|
-
def green=(_green)
|
183
|
-
self.rgb = [red, _green, blue]
|
184
|
-
end
|
185
|
-
|
186
|
-
def blue=(_blue)
|
187
|
-
self.rgb = [red, green, _blue]
|
188
|
-
end
|
189
|
-
|
190
|
-
def kelvin
|
191
|
-
# convert colortemp setting to Kelvin
|
192
|
-
1000000 / self['ct']
|
193
|
-
end
|
194
|
-
|
195
|
-
def kelvin=(_temp)
|
196
|
-
self.colortemp = 1000000 / [_temp, 1].max
|
197
|
-
end
|
198
|
-
|
199
|
-
def ct_to_rgb
|
200
|
-
# using method described at
|
201
|
-
# http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
|
202
|
-
temp = kelvin / 100
|
203
|
-
|
204
|
-
red = temp <= 66 ? 255 : 329.698727446 * ((temp - 60) ** -0.1332047592)
|
205
|
-
|
206
|
-
green = if temp <= 66
|
207
|
-
99.4708025861 * Math.log(temp) - 161.1195681661
|
208
|
-
else
|
209
|
-
288.1221695283 * ((temp - 60) ** -0.0755148492)
|
210
|
-
end
|
211
|
-
|
212
|
-
blue = if temp >= 66
|
213
|
-
255
|
214
|
-
elsif temp <= 19
|
215
|
-
0
|
216
|
-
else
|
217
|
-
138.5177312231 * Math.log(temp - 10) - 305.0447927307
|
218
|
-
end
|
219
|
-
|
220
|
-
{ red: [[red, 0].max, 255].min.to_i,
|
221
|
-
green: [[green, 0].max, 255].min.to_i,
|
222
|
-
blue: [[blue, 0].max, 255].min.to_i
|
223
|
-
}
|
224
|
-
|
225
|
-
end
|
226
|
-
|
227
|
-
def xyz
|
228
|
-
vals = state['xy']
|
229
|
-
vals + [1 - vals.first - vals.last]
|
230
|
-
end
|
231
|
-
|
232
|
-
def xy_to_rgb
|
233
|
-
values = (RGB_MATRIX * Matrix[xyz].transpose).to_a.flatten.map{|x| [[x * 255, 0].max, 255].min.to_i}
|
234
|
-
{ red: values[0],
|
235
|
-
green: values[1],
|
236
|
-
blue: values[2]
|
237
|
-
}
|
238
|
-
end
|
239
|
-
|
240
|
-
def hue_in_degrees
|
241
|
-
self['hue'].to_f / HUE_SCALE
|
242
|
-
end
|
243
|
-
|
244
|
-
def hue_as_decimal
|
245
|
-
hue_in_degrees / HUE_DEGREES
|
246
|
-
end
|
247
|
-
|
248
|
-
def sat_as_decimal
|
249
|
-
self['sat'] / 255.0
|
250
|
-
end
|
251
|
-
|
252
|
-
def brightness_as_decimal
|
253
|
-
brightness / 255.0
|
254
|
-
end
|
255
|
-
|
256
|
-
def hs_to_rgb
|
257
|
-
h, s, v = hue_as_decimal, sat_as_decimal, brightness_as_decimal
|
258
|
-
if s == 0 #monochromatic
|
259
|
-
red = green = blue = v
|
260
|
-
else
|
261
|
-
|
262
|
-
v = 1.0 # We are setting the value to 1. Don't count brightness here
|
263
|
-
i = (h * 6).floor
|
264
|
-
f = h * 6 - i
|
265
|
-
p = v * (1 - s)
|
266
|
-
q = v * (1 - f * s)
|
267
|
-
t = v * (1 - (1 - f) * s)
|
268
|
-
|
269
|
-
case i % 6
|
270
|
-
when 0
|
271
|
-
red, green, blue = v, t, p
|
272
|
-
when 1
|
273
|
-
red, green, blue = q, v, p
|
274
|
-
when 2
|
275
|
-
red, green, blue = p, v, t
|
276
|
-
when 3
|
277
|
-
red, green, blue = p, q, v
|
278
|
-
when 4
|
279
|
-
red, green, blue = t, p, v
|
280
|
-
when 5
|
281
|
-
red, green, blue = v, p, q
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
{ red: [[red * 255, 0].max, 255].min.to_i,
|
286
|
-
green: [[green * 255, 0].max, 255].min.to_i,
|
287
|
-
blue: [[blue * 255, 0].max, 255].min.to_i
|
288
|
-
}
|
289
|
-
end
|
290
|
-
|
291
|
-
def rgb=(colors)
|
292
|
-
red, green, blue = colors[0] / 255.0, colors[1] / 255.0, colors[2] / 255.0
|
293
|
-
|
294
|
-
max = [red, green, blue].max
|
295
|
-
min = [red, green, blue].min
|
296
|
-
h, s, l = 0, 0, ((max + min) / 2 * 255)
|
297
|
-
|
298
|
-
d = max - min
|
299
|
-
s = max == 0 ? 0 : (d / max * 255)
|
300
|
-
|
301
|
-
h = case max
|
302
|
-
when min
|
303
|
-
0 # monochromatic
|
304
|
-
when red
|
305
|
-
(green - blue) / d + (green < blue ? 6 : 0)
|
306
|
-
when green
|
307
|
-
(blue - red) / d + 2
|
308
|
-
when blue
|
309
|
-
(red - green) / d + 4
|
310
|
-
end * 60 # / 6 * 360
|
311
|
-
|
312
|
-
h = (h * HUE_SCALE).to_i
|
313
|
-
update hue: h, sat: s.to_i#, bri: l.to_i
|
314
|
-
[h, s, 1.0]
|
315
|
-
end
|
316
|
-
|
317
|
-
def candle(repeat = 15)
|
318
|
-
# 0-65536 for hue, 182 per deg. Ideal 30-60 deg (5460-10920)
|
319
|
-
stash!
|
320
|
-
on if off?
|
321
|
-
|
322
|
-
repeat.times do
|
323
|
-
hue = ((rand * 3460) + 5460).to_i
|
324
|
-
sat = rand(64) + 170
|
325
|
-
bri = rand(32) + 16
|
326
|
-
|
327
|
-
delay = (rand * 0.35) + (@delay ||= 0)
|
328
|
-
update(hue: hue, sat: sat, bri: bri, transitiontime: (delay * 10).to_i)
|
329
|
-
sleep delay
|
330
|
-
end
|
331
|
-
restore!
|
332
|
-
end
|
333
|
-
|
334
138
|
private
|
335
139
|
|
336
|
-
def stash!
|
337
|
-
@stash ||= settings
|
338
|
-
end
|
339
|
-
|
340
|
-
def restore!
|
341
|
-
if stash
|
342
|
-
update(@stash)
|
343
|
-
unstash!
|
344
|
-
end
|
345
|
-
end
|
346
|
-
|
347
|
-
def unstash!
|
348
|
-
@stash = nil
|
349
|
-
end
|
350
|
-
|
351
140
|
def status
|
352
141
|
@status || refresh!
|
353
142
|
end
|
354
143
|
|
355
|
-
def
|
356
|
-
|
357
|
-
settings.each do |key, value|
|
358
|
-
@status['state'][key.to_s] = value # or refresh!
|
359
|
-
end
|
360
|
-
end
|
144
|
+
def set_color
|
145
|
+
@color = Colors.parse_state(state)
|
361
146
|
end
|
362
147
|
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
# the multiplier should be 600 * time per step
|
370
|
-
minutes_per_step = total_time_in_minutes / 18.0
|
371
|
-
multiplier = (minutes_per_step * 60 * 10).to_i
|
372
|
-
|
373
|
-
perform_sun_transition total_time_in_minutes, sunrise_steps(multiplier)
|
374
|
-
end
|
375
|
-
|
376
|
-
def perform_sunrise(total_time_in_minutes = 18)
|
377
|
-
multiplier = sunrise_multiplier total_time_in_minutes
|
378
|
-
steps = sunrise_steps(multiplier)
|
379
|
-
if on?
|
380
|
-
puts "ON! #{steps[0][:bri]} :: #{brightness} :: #{brightness > steps[0][:bri]}"
|
381
|
-
while brightness >= steps[0][:bri]
|
382
|
-
steps.shift
|
383
|
-
end
|
384
|
-
end
|
385
|
-
steps.each_with_index do |step, i|
|
386
|
-
update step.merge(on: true)
|
387
|
-
sleep(step[:transitiontime] / 10.0)
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
def perform_sunset(total_time_in_minutes = 18)
|
392
|
-
multiplier = sunrise_multiplier total_time_in_minutes
|
393
|
-
steps = sunset_steps(multiplier)
|
394
|
-
if on?
|
395
|
-
puts "ON! #{steps[0][:bri]} :: #{brightness} :: #{brightness > steps[0][:bri]}"
|
396
|
-
while brightness <= steps[0][:bri]
|
397
|
-
steps.shift
|
148
|
+
def update(settings = {})
|
149
|
+
if bridge.set_light_state(id, options.merge(settings))
|
150
|
+
if @status
|
151
|
+
settings.each do |key, value|
|
152
|
+
@status['state'][key.to_s] = value # or refresh!
|
153
|
+
end
|
398
154
|
end
|
399
155
|
end
|
400
|
-
steps.each_with_index do |step, i|
|
401
|
-
update step.merge(on: true)
|
402
|
-
sleep(step[:transitiontime] / 10.0)
|
403
|
-
end
|
404
|
-
off
|
405
|
-
end
|
406
|
-
|
407
|
-
SUN_STEPS = [ 1.5, 2, 3, 1, 4, 2.5 ]
|
408
|
-
SUN_TIMES = [ 3, 3, 3, 1, 2, 1]
|
409
|
-
|
410
|
-
def sunrise_multiplier(total_time_in_minutes)
|
411
|
-
# total_time / 18 steps == time_per_step
|
412
|
-
# the multiplier should be 600 * time per step
|
413
|
-
minutes_per_step = total_time_in_minutes / 18.0
|
414
|
-
(minutes_per_step * 60 * 10).to_i
|
415
|
-
end
|
416
|
-
|
417
|
-
def sunrise_brightness
|
418
|
-
sun_bri_unit = 10
|
419
|
-
SUN_STEPS.inject([0]){|all, i| all << ((i * sun_bri_unit) + all[-1]).to_i } << 255
|
420
|
-
end
|
421
|
-
|
422
|
-
def sunrise_temps
|
423
|
-
sun_temp_unit = 16
|
424
|
-
SUN_STEPS.inject([500]){|all, i| all << (all[-1] - (i * sun_temp_unit)).to_i} << 200
|
425
|
-
end
|
426
|
-
|
427
|
-
def sunrise_times
|
428
|
-
[0, SUN_TIMES, 5].flatten
|
429
|
-
end
|
430
|
-
|
431
|
-
def sunset_times
|
432
|
-
[0, 5, SUN_TIMES.reverse].flatten
|
433
|
-
end
|
434
|
-
|
435
|
-
def sunrise_steps(multiplier = 600)
|
436
|
-
bri_steps = sunrise_brightness
|
437
|
-
tmp_steps = sunrise_temps
|
438
|
-
|
439
|
-
steps = []
|
440
|
-
sunrise_times.each_with_index do |t, i|
|
441
|
-
steps << {bri: bri_steps[i], ct: tmp_steps[i], transitiontime: (t * multiplier)}
|
442
|
-
end
|
443
|
-
steps
|
444
|
-
end
|
445
|
-
|
446
|
-
def sunset_steps(multiplier = 600)
|
447
|
-
bri_steps = sunrise_brightness.reverse
|
448
|
-
tmp_steps = sunrise_temps.reverse
|
449
|
-
|
450
|
-
steps = []
|
451
|
-
sunset_times.each_with_index do |t, i|
|
452
|
-
steps << {bri: bri_steps[i], ct: tmp_steps[i], transitiontime: (t * multiplier)}
|
453
|
-
end
|
454
|
-
steps
|
455
156
|
end
|
456
157
|
|
457
158
|
end
|