Add CircuitPython Code and Project Assets
In the embedded code element below, click on the Download Project Bundle button, and save the .zip archive file to your computer.
Then, uncompress the .zip file, it will unpack to a folder named PyPortal_Philips_Hue_Controller.
Copy the contents of the PyPortal_Philips_Hue_Controller directory to your PyPortal CIRCUITPY drive. Your CircuitPython code file needs to be named code.py to run on startup.
# SPDX-FileCopyrightText: 2019 Brent Rubell for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
PyPortal Philips Hue Lighting Controller
Brent Rubell for Adafruit Industries, 2019
"""
from os import getenv
import board
import displayio
from adafruit_bitmap_font import bitmap_font
from adafruit_button import Button
import adafruit_touchscreen
from digitalio import DigitalInOut
import busio
import neopixel
from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_wifimanager
# Import Philips Hue Bridge
from adafruit_hue import Bridge
# Get WiFi details, ensure these are setup in settings.toml
ssid = getenv("CIRCUITPY_WIFI_SSID")
password = getenv("CIRCUITPY_WIFI_PASSWORD")
if None in [ssid, password]:
raise RuntimeError(
"WiFi settings are kept in settings.toml, "
"please add them there. The settings file must contain "
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
"at a minimum."
)
# ESP32 SPI
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
# Attempt to load bridge username and IP address from settings.toml
try:
username = getenv("HUE_USERNAME")
bridge_ip = getenv("BRIDGE_IP")
my_bridge = Bridge(wifi, bridge_ip, username)
except:
# Perform first-time bridge setup
my_bridge = Bridge(wifi)
print('Finding bridge address...')
ip = my_bridge.discover_bridge()
print('Attempting to register username, press the link button on your Hue Bridge now!')
username = my_bridge.register_username()
print(f'ADD THESE VALUES TO settings.toml: \
\nBRIDGE_IP = "{ip}" \
\nHUE_USERNAME = "{username}"')
raise
# These pins are used as both analog and digital! XL, XR and YU must be analog
# and digital capable. YD just need to be digital
ts = adafruit_touchscreen.Touchscreen(board.TOUCH_XL, board.TOUCH_XR,
board.TOUCH_YD, board.TOUCH_YU,
calibration=((5200, 59000), (5800, 57000)),
size=(320, 240))
# Make the display context
button_group = displayio.Group()
board.DISPLAY.root_group = button_group
# preload the font
print('loading font...')
font = bitmap_font.load_font("/fonts/Arial-12.bdf")
glyphs = b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,.: '
font.load_glyphs(glyphs)
# button properties
BUTTON_WIDTH = 60
BUTTON_HEIGHT = 60
buttons = []
print('loading colors...')
# color conversions (RGB to Philips Hue-compatible HSB)
red = my_bridge.rgb_to_hsb([255, 0, 0])
white = my_bridge.rgb_to_hsb([255, 255, 255])
orange = my_bridge.rgb_to_hsb([255, 165, 0])
yellow = my_bridge.rgb_to_hsb([255, 255, 0])
green = my_bridge.rgb_to_hsb([0, 255, 0])
blue = my_bridge.rgb_to_hsb([0, 0, 255])
purple = my_bridge.rgb_to_hsb([128, 0, 128])
pink = my_bridge.rgb_to_hsb([255, 192, 203])
hue_hsb = {'red': red, 'white': white, 'orange': orange,
'yellow': yellow, 'green': green, 'blue': blue,
'purple': purple, 'pink': pink}
print('loading buttons...')
# button fill colors
button_colors = {'red':0xFF0000, 'white':0xFFFFFF,
'orange':0xFF9900, 'yellow':0xFFFF00,
'green':0x00FF00, 'blue':0x0000FF,
'purple':0x9900FF, 'pink': 0xFF00FF}
# list of color buttons and their properties
color_btn = [
{'name':'red', 'pos':(15, 80), 'color':button_colors['red']},
{'name':'white', 'pos':(85, 80), 'color':button_colors['white']},
{'name':'orange', 'pos':(155, 80), 'color':button_colors['orange']},
{'name':'yellow', 'pos':(225, 80), 'color':button_colors['yellow']},
{'name':'pink', 'pos':(15, 155), 'color':button_colors['pink']},
{'name':'green', 'pos':(85, 155), 'color':button_colors['green']},
{'name':'blue', 'pos':(155, 155), 'color':button_colors['blue']},
{'name':'purple', 'pos':(225, 155), 'color':button_colors['purple']}
]
# generate color buttons from color_btn list
for i in color_btn:
button = Button(x=i['pos'][0], y=i['pos'][1],
width=BUTTON_WIDTH, height=BUTTON_HEIGHT, name=i['name'],
fill_color=i['color'], style=Button.ROUNDRECT)
buttons.append(button)
# light property buttons and their properties
prop_btn = [
{'name':'onoff', 'pos':(15, 15), 'label':'on/off'},
{'name':'up', 'pos':(75, 15), 'label':'+'},
{'name':'down', 'pos':(135, 15), 'label':'-'},
{'name':'room', 'pos':(195, 15), 'label':'room'},
{'name':'lamp', 'pos':(255, 15), 'label':'lamp'}
]
# generate property buttons from prop_btn list
for i in prop_btn:
button = Button(name=i['name'], x=i['pos'][0], y=i['pos'][1],
width=55, height=40, label=i['label'],
label_font=font, style=Button.SHADOWROUNDRECT)
buttons.append(button)
# add buttons to the group
for b in buttons:
button_group.append(b.group)
# Hue Light/Group Identifiers
hue_lights={'lamp': 1, 'livingroom': 2}
hue_selector = hue_lights['lamp']
# Default to 25% brightness
current_brightness = 25
while True:
touch = ts.touch_point
if touch:
for i, button in enumerate(buttons):
if button.contains(touch):
button.selected = True
if button.name == 'room':
hue_selector = hue_lights['livingroom']
print('Switching to ', hue_selector)
elif button.name == 'lamp':
hue_selector = hue_lights['lamp']
print('Switching to ', hue_selector)
elif button.name == 'onoff':
print('Toggling {0}...'.format(hue_selector))
my_bridge.toggle_light(int(hue_selector))
elif button.name == 'up':
current_brightness += 25
print('Setting {0} brightness to {1}'.format(hue_selector, current_brightness))
my_bridge.set_light(int(hue_selector), bri=current_brightness)
elif button.name == 'down':
current_brightness -= 25
print('Setting {0} brightness to {1}'.format(hue_selector, current_brightness))
my_bridge.set_light(int(hue_selector), bri=current_brightness)
else:
print('Setting {0} color to {1}'.format(hue_selector, button.name))
my_bridge.set_light(light_id=int(hue_selector),
hue=int(hue_hsb[button.name][0]),
sat=int(hue_hsb[button.name][1]),
bri=int(hue_hsb[button.name][2]))
button.selected = False
else:
button.selected = False
This is what the final contents of the CIRCUITPY drive will look like:
Make sure your board's lib folder has the following files and folders copied over.
- adafruit_hue
- simpleio
- adafruit_bitmap_font
- adafruit_bus_device
- adafruit_button
- adafruit_display_shapes
- adafruit_display_text
- adafruit_esp32spi
- adafruit_touchscreen
- neopixel
The Hue system is built around the Hue Bridge. To communicate with the bridge, you'll need to register a unique username (stored on the bridge) for the PyPortal. you'll also need the Bridge's IP address to communicate with it.
We've built the CircuitPython Hue library to automate the process of discovering and registering a username with the bridge - but, you'll still need to add these values to the settings.toml file. This is a one-time setup and does not need to be repeated.
This guide requires you to edit and interact with CircuitPython code. Mu is a simple code editor that works with the Adafruit CircuitPython boards. It's written in Python and works on Windows, MacOS, Linux and Raspberry Pi. The serial console is built right in so you get immediate feedback from your board's serial output!
Before proceeding, click the button below to install the Mu Editor. There are versions for PC, mac, and Linux.
First, if you have not already done so, set up a settings.toml file with your local WiFi information, as described in this guide here.
Next, open the Mu editor and open the file code.py.
For this next step, you will need to connect to the serial console using Mu or a different terminal program.
- Not sure how to connect to your PyPortal's REPL? Read this page here and come back to the guide once you're connected.
Once connected to the PyPortal, the REPL will display that the code is searching for the bridge address using the WiFi credentials entered previously into settings.toml:
code.py output: Finding bridge address...
If the bridge address was found, the code will attempt to register a random, unique username with the bridge:
Attempting to register username, press the link button on your Hue Bridge now!
When it prints this, you have exactly 120 seconds to press the link button on top of the Hue Bridge.
- We've found that you may need to press this button more than once during this period to ensure a username is successfully generated.
Once the button on top of the bridge is pressed, the code will print the bridge IP address and username to the REPL.
Modify the settings.toml file by adding BRIDGE_IP and HUE_USERNAME and save the file. Your settings.toml file should look similar to the sample below:
CIRCUITPY_WIFI_SSID = "your_wifi_ssid" CIRCUITPY_WIFI_PASSWORD = "your_wifi_password" BRIDGE_IP = "192.160.0.00" HUE_USERNAME = "UpsdCULBXvOtWXaqgeTpdAp26Np9hu43x5XjkaLX"
Setting up the PyPortal with the bridge is finished! You do not need to repeat this process again unless you misplace the randomly generated username string.
Page last edited April 14, 2025
Text editor powered by tinymce.