Code and Life

Programming, electronics and other cool tech stuff

Supported by

Supported by Picotech

Control Philips Hue Color (RGB) Lights With Python

I got tired of the fact, that Philips Hue application does not seem to have any easy way to set multiple lights to different colors (and possibly brightnesses) at once. Thankfully, there is a great "REST API" to query light and set status! Read on how to query your lights, set them, and do RBG to Philips Hue XY (or X, Y) colorspace conversion with Python!

Connecting and configuring your Philips Hue for API access

This is a prerequisite step. Find out your Hue Brige's IP and create a user (simple method of authentication). It's all covered in Get started.

Write down your IP and the username, and proceed to activate your user and test it according to instructions. Once you are done, you should be able to also open the lights list in your browser and see a lot of info:

https:///api//lights

Listing Your Connected Philips Hue Lights with Python

Alright, with the prerequisites done, let's do a simple test with Python, and query that same address parse the returned JSON, and pretty print it. You'll need Python 3.10+ for this:

import urllib.request
import ssl, json, pprint

context = ssl._create_unverified_context()

def get_json(url):
    """Do a HTTP GET request and return response parsed as JSON."""
    print(url)
    req = urllib.request.Request(url=url, method='GET')
    f = urllib.request.urlopen(req, context=context)
    print(f.status, f.reason)
    return json.loads(f.read())

# Replace these with your config
user = 'yourverylongusernamestring'
ip = '192.168.1.123'

data = get_json(f'https://{ip}/api/{user}/lights')

pp = pprint.PrettyPrinter(indent=4)   
pp.pprint(data)

for k in data: print(k, data[k]['name'])

Note the context = ... line where we create an unverified context — we've not that worried about the security in this one.

Turning Philips Hue Light On And Off With Python

Turning a light on or off is simply a matter of sending a PUT request to /api/{user}/lights/{id} with JSON request of {"on":true} for turning the light on, and {"on":false} for turning it off:

# Imports and user, ip set as in above example

def put(url, content):
    """Do a HTTP PUT request with given content as payload."""
    print(url, content)
    req = urllib.request.Request(url=url,
        data=content.encode('UTF-8'), method='PUT')
    f = urllib.request.urlopen(req, context=context)
    print(f.status, f.reason)

# Turn ON light 7
light = 7
put(f'https://{ip}/api/{user}/lights/{light}/state', '{"on":true}')

Getting and Setting Philips Hue to Given X/Y and Brightness

If you have color capable Hue lights, you can get their current color in X/Y format (based on the CIY 1931 color space, I think), and set them in a similar fashion.

# Get light 4 x, y, and brightness values
light = 4
data = get_json(f'https://{ip}/api/{user}/lights/{light}')
state = data['state']
print(state['xy'][0], state['xy'][1], state['bri'])

# Set light 4 to a greenish hue with 50 % brightness
light, x, y, b = 4, 0.4, 0.6, 127
put(f'https://{ip}/api/{user}/lights/{light}/state',
    '{"on":true,"xy":[%.4f,%.4f],"bri":%d}' % (x,y,b))

Note that the /api/{user}/lights/{light} will give more info than just the state, so we'll fetch the state section and then xy items and bri under that.

From Red, Green, Blue (RGB) Values to Philips Hue XY or "X, Y" format

This information took a bit googling, and was the reason I decided to write this article. The XY conversion is documented in Hue Developer pages (requires registration):

https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/

With Python, the formulas can be expressed in a pretty short form. Here's a function that takes RGB values and returns X and Y coordinates and brightness value:

def rgb2xyb(r,g,b):
    r = ((r+0.055)/1.055)**2.4 if r > 0.04045 else r/12.92
    g = ((g+0.055)/1.055)**2.4 if g > 0.04045 else g/12.92
    b = ((b+0.055)/1.055)**2.4 if b > 0.04045 else b/12.92

    X = r * 0.4124 + g * 0.3576 + b * 0.1805
    Y = r * 0.2126 + g * 0.7152 + b * 0.0722
    Z = r * 0.0193 + g * 0.1192 + b * 0.9505

    return X / (X + Y + Z), Y / (X + Y + Z), int(Y*254)

Note: I have converted the brightness value to integer in the range 0..254 as that is what the API expects the "bri" value to be.

Using this is pretty easy, let's set the light 4 to light pink:

light = 4
x,y,b = rgb2xyb(1.0, 0.6, 0.8)
put(f'https://{ip}/api/{user}/lights/{light}/state',
    '{"on":true,"xy":[%.4f,%.4f],"bri":%d}' % (x,y,b))

Wrapping it all together

I made a simple Python tool hue.py which includes all the above routines and some more. Here are a couple examples:

  1. List lights: python3 hue.py list
  2. Turn light 7 on: python3 hue.py on 7
  3. Turn lights 7 and 13 off: python3 hue.py off 7 13
  4. Set light 4 to green: python3 hue.py rgb 0 1 0 4
  5. Set light 4 to warm white: python3 hue.py ctb 400 200 4
  6. Dump X/Y and brightness for lights 5-7 to file.txt with: python3 hue.py getxyb 5 6 7 > file.txt
  7. Set lights from file.txt using python3 hue.py setxyb file.txt

Enjoy! Now if someone has a nifty way of passing a keyword from Alexa to a web service, let me know. I'm all set to use that keyword to fetch a setting file and apply it!