Experiments with the Qhue python module.
If you haven't already, then pip install qhue
before starting.
Some of these examples may assume you have a recent bridge with recent software.
If you're viewing this with my sample output, I've truncated some of it for readability. I have a lot of lights!
In [49]:
# Put in the IP address of your Hue bridge here
BRIDGE_IP='192.168.0.45'
from qhue import Bridge, QhueException, create_new_username
In [54]:
# If you have a username set up on your bridge, enter it here
# otherwise leave it as None and you'll be prompted to create one.
# e.g.:
# username='zeZomfNu-y-p1PLM9oeYTiXbtqsxn-q1-7RNLI4B'
username=None
if username is None:
username = create_new_username(BRIDGE_IP)
print("New user: {} . Put this in the username variable above.".format(username))
Let's get the numbers and names of the lights:
In [55]:
bridge = Bridge(BRIDGE_IP, username)
lights = bridge.lights()
for num, info in lights.items():
print("{:16} {}".format(info['name'], num))
Let's try interactively changing a light. You could make this a lot more sophisticated:
In [56]:
from ipywidgets import interact, interactive, fixed
import ipywidgets as widgets
def setlight(lightid='14', on=True, ct=128, bri=128):
bridge.lights[lightid].state(on=on)
if on:
bridge.lights[lightid].state(bri=bri, ct=ct)
light_list = interact(setlight,
lightid = widgets.Dropdown(
options={ lights[i]['name']:i for i in lights },
value='14',
description='Light:',
),
on = widgets.Checkbox(value=True, description='On/off'),
bri = widgets.IntSlider(min=0,max=255,value=128, description='Bright:'),
ct = widgets.IntSlider(min=0,max=255,value=128, description='Colour:'))
The YAML format is a nice way to view the sometimes large amount of structured information which comes back from the bridge.
If you haven't got the Python yaml module, pip install PyYAML
.
In [57]:
import yaml
print("{} lights:\n".format(len(lights)))
print(yaml.safe_dump(lights, indent=4))
In [58]:
print(yaml.safe_dump(bridge.lights['3'](), indent=4))
Let's look at the scenes defined in the bridge, and their IDs. Some of these may be created manually, and others by the Hue app or other software.
Version 1-type scenes just refer to the lights - each light is told: "Set the value you have stored for this scene".
Version 2 scenes have more details stored in the hub, which is generally more useful.
In [59]:
scenes = bridge.scenes()
print("{} scenes:\n".format(len(scenes)))
print(yaml.safe_dump(scenes, indent=4))
Details of a particular scene from the list:
In [60]:
print(yaml.safe_dump(bridge.scenes['wVXtOrFmdnySqUz']()))
Let's list scenes with IDs, last updated time, and the lights affected:
In [61]:
for sid, info in scenes.items():
print("\n{:16} {:20} {}".format( sid, info['name'], info['lastupdated']))
for li in info['lights']:
print("{:40}- {}".format('', lights[li]['name']))
Tidying things up; let's delete a scene:
In [62]:
# Uncomment and edit this if you actually want to run it!
# print(bridge.scenes['cd06c70f7-on-0'](http_method='delete'))
Show the details of the scenes that affect a particular light:
In [63]:
lightname = 'Sitting room 1'
# How's this for a nice use of python iterators?
light_id = next(i for i,info in lights.items() if info['name'] == lightname)
print("Light {} - {}".format(light_id, lightname))
for line in ["{} : {:20} {}".format(sid, info['name'], info['lastupdated']) for sid, info in scenes.items() if light_id in info['lights']]:
print(line)
Let's look at groups:
In [64]:
print(yaml.safe_dump(bridge.groups(), indent=4))
The current Hue software creates 'rooms', which are groups with a type value set to Room:
In [65]:
groups = bridge.groups()
rooms = [(gid, info['name']) for gid, info in groups.items() if info.get('type') == 'Room' ]
for room_id, info in rooms:
print("{:3} : {}".format(room_id, info))
Sensors are mostly switches, but a few other things come under the same category in the bridge. There's a 'daylight' sensor, implemented in software, for example, and various bits of state can also be stored here so they can be used in rule conditions later.
In [66]:
sensors = bridge.sensors()
summary = [(info['name'], i, info['type']) for i,info in sensors.items()]
# Sort by name
# Python 2: summary.sort(lambda a,b: cmp(a[0], b[0]))
# Python 3:
summary.sort(key = lambda a: a[0])
for n,i,t in summary:
print("{:30} {:>3} {}".format(n,i,t))
#print(bridge.sensors[i]())
Here's a more complete list:
In [67]:
print(yaml.safe_dump(bridge.sensors(), indent=4))
In [68]:
rules = bridge.rules()
print(yaml.safe_dump(rules, indent=4))
Show the rules triggered by the Sitting Room switch.
For Tap switches, buttons 1,2,3,4 are represented by the values 34,16,17,18 respectively.
In [69]:
switch = '10' # sitting room
print("Switch {} -- {}\n".format(switch, sensors[switch]['name']))
# State changes on the switch will look like this:
state_string = "/sensors/{}/state/".format(switch)
# Look through the rules for once which contain this
# string in their conditions:
for rid, info in rules.items():
this_switch = False
matching_conditions = [c for c in info['conditions'] if state_string in c['address']]
if len(matching_conditions) > 0:
print("{:3} {:20}".format(rid, info['name']))
for c in info['conditions']:
print(" ? condition {}".format(c))
for a in info['actions']:
# If the action involves applying a scene, get its name
scene_name = ""
if 'scene' in a['body']:
scene_name = scenes[a['body']['scene']]['name']
print(" - action address {} body {!s:29s} {} ".format( a['address'], a['body'], scene_name))
Let's see what is actually done by one of these scenes:
In [70]:
scene='3owQUn01W7nVsxR' # 'Evening' scene button 10.4
s = bridge.scenes[scene]()
print(yaml.safe_dump(s, indent=4))
In [ ]: