-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathhue-flux.py
275 lines (205 loc) · 7.09 KB
/
hue-flux.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# Copyright 2015 Iavor Todorov
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import ssdp
import urllib.request
import xml.dom.minidom
import phue
import time
import math
import sun
def discover_and_connect_bridge():
ssdp_responses = ssdp.discover("device")
registered = False
help_printed = False
for response in ssdp_responses:
hub_ip = verify_hue_upnp(response.location)
if hub_ip:
print("Found hub at: %s" % hub_ip)
discover_start = time.time()
while not(registered and (time.time() - discover_start > 90)): # Time out in 90 seconds
try:
bridge = phue.Bridge(hub_ip)
registered = True
print("Conected to hub at: %s" % hub_ip)
return bridge
except phue.PhueRegistrationException:
registered = False
time.sleep(1)
if not help_printed:
print(
"Please press the button on the Hue bridge to connect this app.")
help_printed = True
print ("Hub discovery timed out.")
def verify_hue_upnp(url):
upnpxml = urllib.request.urlopen(url).read().decode()
dom = xml.dom.minidom.parseString(upnpxml)
baseurl = dom.getElementsByTagName("URLBase")[0].childNodes[0].data
hub_ip = urllib.request.urlparse(baseurl).netloc.split(":")[0]
hub_config = urllib.request.urlopen(
baseurl + "api/%20/config").read().decode()
if hub_config.find("hue") != -1:
return hub_ip
else:
return False
def find_lights_by_name(bridge, searchtext):
lights = bridge.get_light_objects()
computer_lights = []
# Find lights and initialize them
for light in lights:
if light.name.find(searchtext) != -1:
computer_lights.append(light)
light.transitiontime = 0
light.sat = 255
light.brightness = 255
return computer_lights
def turn_lights_on(lights):
for light in lights:
if not light.on:
light.on = True
light.brightness = 254
def turn_lights_off(lights):
for light in lights:
if light.on:
light.on = False
def set_lights_colortemp_k(lights, temp):
for light in lights:
light.colortemp_k = temp
def set_lights_xy(lights, x, y):
for light in lights:
light.xy = [x, y]
# print("Setting light to: %s, %s" % (x, y))
def frange(start, stop, step):
i = start
if start > stop:
while i > stop:
yield i
i += step
else:
while i < stop:
yield i
i += step
def fade_colortemp_k(lights, temp_from, temp_to, fadetime):
delay = (0.2)
# If the color temp steps work out to less than 1, increase the delay
# instead
if abs(temp_from - temp_to) < fadetime:
delay = fadetime / abs(temp_from - temp_to)
if temp_from > temp_to:
temp_to -= 1
step = -(round((temp_from - temp_to) / (fadetime / delay), 2))
else:
temp_to += 1
step = (round((temp_to - temp_from) / (fadetime / delay), 2))
print("Fading lights with %s sec delay and %s color step" % (delay, step))
for temp in frange(temp_from, temp_to, step):
x, y = RGB_to_xy(*colortemp_k_to_RGB(temp))
set_lights_xy(lights, x, y)
print("Setting lights to temp: %s" % temp)
time.sleep(delay)
# Taken from:
# http://www.developers.meethue.com/documentation/color-conversions-rgb-xy
def RGB_to_xy(red, green, blue):
red = red / 255
blue = blue / 255
green = green / 255
# Gamma correction
red = pow((red + 0.055) / (1.0 + 0.055),
2.4) if (red > 0.04045) else (red / 12.92)
green = pow((green + 0.055) / (1.0 + 0.055),
2.4) if (green > 0.04045) else (green / 12.92)
blue = pow((blue + 0.055) / (1.0 + 0.055),
2.4) if (blue > 0.04045) else (blue / 12.92)
x = red * 0.664511 + green * 0.154324 + blue * 0.162028
y = red * 0.313881 + green * 0.668433 + blue * 0.047685
z = red * 0.000088 + green * 0.072310 + blue * 0.986039
try:
cx = x / (x + y + z)
cy = y / (x + y + z)
except:
cx, cy = 0, 0
if cx > 0.675:
cx = 0.675
if cx < 0.167:
cx = 0.167
if cy > 0.518:
cy = 0.518
if cy < 0.04:
cy = 0.04
return round(cx, 3), round(cy, 3)
def colortemp_k_to_RGB(temp):
temp = temp / 100
if temp <= 66:
red = 255
else:
red = temp - 60
red = 329.698727446 * (red ** -0.1332047592)
red = 0 if red < 0 else red
red = 255 if red > 255 else red
if temp <= 66:
green = temp
green = 99.4708025861 * math.log(green) - 161.1195681661
green = 0 if green < 0 else green
green = 255 if green > 255 else green
else:
green = temp - 60
green = 288.1221695283 * (green ** -0.0755148492)
green = 0 if green < 0 else green
green = 255 if green > 255 else green
if temp >= 66:
blue = 255
else:
if temp <= 19:
blue = 0
else:
blue = temp - 10
blue = 138.5177312231 * math.log(blue) - 305.0447927307
blue = 0 if blue < 0 else blue
blue = 255 if blue > 255 else blue
return red, green, blue
def get_secs_to_hour(hour):
today = time.strftime("%x", time.localtime())
return time.mktime(time.strptime(today + hour, "%x%H:%M")) - time.time()
# MAIN PROGRAM #
# Change settings as desired
location = "95050" # Zip code or some other location string
bedtime = "21:00"
day_colortemp = 4000
sunset_colortemp = 3000
bedtime_colortemp = 1900
# String to use to search for lights to work with.
# For example, if your computer room lights are named "Computer 1",
# "Computer 2", etc
searchtext = "Computer"
# Don't touch things below here
print("Discovering Hue bridges...")
try:
bridge = phue.Bridge()
registered = True
print("Found previously connected bridge")
except:
bridge = discover_and_connect_bridge()
lights = find_lights_by_name(bridge, searchtext)
turn_lights_on(lights)
sunset_time = sun.get_sun(location)[1] # Sunset time in 24hr format
fadetime = get_secs_to_hour(sunset_time)
if fadetime > 0:
print("Local sunset is at: %s, in %s seconds" % (sunset_time, fadetime))
fade_colortemp_k(lights, day_colortemp, sunset_colortemp, fadetime)
fadetime = get_secs_to_hour(bedtime)
if fadetime > 0:
print("The sun has set. Bedtime is at: %s, in %s seconds" %
(bedtime, fadetime))
fade_colortemp_k(lights, sunset_colortemp, bedtime_colortemp, fadetime)
print("Sweet dreams!")