Obtain your LIFX Access Token
All requests to the LIFX bulbs require an access token. Obtaining one is simple!
Navigate to the LIFX account settings page, name your access token something unique, and click generate.
Then, copy this token to a file or somewhere safe - you will not be able to view it again when you navigate away from this page.
CircuitPython Library Installation
First make sure you are running the latest version of Adafruit CircuitPython for your board.
Next you'll need to install the necessary libraries to use the hardware--carefully follow the steps to find and install these libraries from Adafruit's CircuitPython library bundle matching your version of CircuitPython. PyPortal requires at least CircuitPython version 4.0.0.
Before continuing make sure your board's lib folder has the following files and folders copied over.
- adafruit_lifx
- adafruit_bitmap_font
- adafruit_bus_device
- adafruit_button
- adafruit_display_shapes
- adafruit_display_text
- adafruit_esp32spi
- adafruit_touchscreen
- neopixel
Add the LIFX Access Token you generated to to your settings.toml file:
CIRCUITPY_WIFI_SSID = "your_wifi_ssid" CIRCUITPY_WIFI_PASSWORD = "your_wifi_password" LIFX_TOKEN = "_your_really_long_lifx_token_"
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_lifx_controller.
Copy the contents of the pyportal_lifx_controller directory to your PyPortal CIRCUITPY drive.
# SPDX-FileCopyrightText: 2019 Brent Rubell for Adafruit Industries # # SPDX-License-Identifier: MIT """ PyPortal Smart Lighting Controller ------------------------------------------------------------- https://learn.adafruit.com/pyportal-smart-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 lifx library import adafruit_lifx # 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) # 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)) # Set this to your LIFX personal access token in settings.toml # (to obtain a token, visit: https://cloud.lifx.com/settings) lifx_token = getenv("LIFX_TOKEN") # Initialize the LIFX API Helper lifx = adafruit_lifx.LIFX(wifi, lifx_token) # Set these to your LIFX light selector (https://api.developer.lifx.com/docs/selectors) lifx_lights = ['label:Lamp', 'label:Bedroom'] # set default light properties current_light = lifx_lights[0] light_brightness = 1.0 # 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 = [] # button fill colors (from https://api.developer.lifx.com/docs/colors) button_colors = {'red':0xFF0000, 'white':0xFFFFFF, 'orange':0xFF9900, 'yellow':0xFFFF00, 'green':0x00FF00, 'blue':0x0000FF, 'purple':0x9900FF, 'pink': 0xFF00FF} print('loading buttons...') # 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':'lamp', 'pos':(195, 15), 'label':'lamp'}, {'name':'room', 'pos':(245, 15), 'label':'room'} ] # 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=40, 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) while True: touch = ts.touch_point if touch: for i, button in enumerate(buttons): if button.contains(touch): button.selected = True if button.name == 'lamp': current_light = lifx_lights[0] print('Switching to ', current_light) elif button.name == 'room': current_light = lifx_lights[1] print('Switching to ', current_light) elif button.name == 'onoff': print('Toggling {0}...'.format(current_light)) lifx.toggle_light(current_light) elif button.name == 'up': light_brightness += 0.25 print('Setting {0} brightness to {1}'.format(current_light, light_brightness)) lifx.set_brightness(current_light, light_brightness) elif button.name == 'down': light_brightness -= 0.25 print('Setting {0} brightness to {1}'.format(current_light, light_brightness)) lifx.set_brightness(current_light, light_brightness) else: print('Setting {0} color to {1}'.format(current_light, button.name)) lifx.set_color(current_light, 'on', button.name, light_brightness) button.selected = False else: button.selected = False
This is what the final contents of the CIRCUITPY drive will look like:

Setup Code
Before you can use the code, you'll need to modify the code.py file to add a label specifying which light you're controlling.
LIFX uses an identifier called a selector to identify the lights associated with your account. With a selector, you can use the light's unique identifier, location (bedroom, workbench, living room) or lighting groups. For simplicity, this guide assumes that you will be using a label as a selector.
To find the bulb's label:
Navigate to the LIFX app and select the light you'd like to control.
Tap the gear icon to reveal the detailed settings of the light.
The Name of the light is the light's label.
Next, modify the lifx_lights
variable within code.py to include the label from the App.
For example, if you're adding a new LIFX bulb called workbench, change the code from
lifx_lights = ['label:lamp', 'label:Main Room']
to
lifx_lights = ['label:lamp', 'label:workbench']
Be sure to include label:
before the name of your light.
For more information on using LIFX light selectors, check out their API documentation on this topic here.
From the Mu Editor, click the Serial button to open the REPL. You should see the REPL display the code's status as it loads the interface.
Select a light by tapping the name of the light you'd like to control. If none is selected, the code will default to the first light specified within the lifx_lights
list.
Tap the on/off button to toggle the power of the light you selected. Keep in mind that LIFX lights save state - if your light was previously set to red and turned off, it'll turn on with the same color.
- Buttons invert their color while they make a request to the LIFX API. Once the request is complete, the button changes back to its original color.
- If you're having issues with your light not responding: scroll down to the Diagnosing Errors section below.
Tapping a color button will set the light to the button's fill color with the brightness specified by the + or - buttons.
- Note: We used the color names for this guide to set different colors. The LIFX HTTP Remote Control API allows you to go beyond basic colors - you can set a bulb's color by specifying hue, saturation, brightness, kelvin or hex values.
Next up, we'll take a look at the code you loaded onto your PyPortal
Page last edited January 21, 2025
Text editor powered by tinymce.