Skip to content

Instantly share code, notes, and snippets.

@swhitt
Last active January 16, 2024 19:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save swhitt/91f5402768261273e30e211e667ee006 to your computer and use it in GitHub Desktop.
Save swhitt/91f5402768261273e30e211e667ee006 to your computer and use it in GitHub Desktop.
Python script to light up the last LED on each string of Twinkly LED lights using the `xled` library.
#!/usr/bin/env python3
"""
This script was written to help me find the end light on each strand of my
Twinkly Christmas Lights. It's much easier to remove the lights from the tree
when you know where the end is. :)
Upon execution, the script automatically discovers all Twinkly devices on your
local network and illuminates the last LED of each strand with a random color.
Realtime mode on the devices has a duration of 60 seconds. The strands will
revert to the default lighting pattern once this has elapsed.
Make sure to `pip install xled` first.
"""
import xled
import struct
import io
import random
def make_custom_frame(num_leds, positions, colors):
"""
Creates a custom frame for a given number of LEDs.
Each LED is set to black (off) initially, and then specific LEDs
are set to the provided colors at the given positions.
:param num_leds: The total number of LEDs.
:param positions: A list of positions where LEDs should be turned on.
:param colors: A list of RGB color tuples corresponding to each position.
:return: A BytesIO object containing the binary data for the frame.
"""
frame = [b"\x00\x00\x00"] * num_leds # Initialize all LEDs to off (black)
for pos, color in zip(positions, colors):
if 0 <= pos < num_leds:
frame[pos] = struct.pack(">BBB", *color)
frame_data = io.BytesIO()
frame_data.write(b"".join(frame))
frame_data.seek(0)
return frame_data
def random_color():
"""
:return: A tuple representing a random choice of red, green, or blue.
"""
rgbl = [255, 0, 0]
random.shuffle(rgbl)
return tuple(rgbl)
def light_last_led_on_each_string(device):
"""
Lights up the last LED on each string of a given Twinkly device.
:param device: An xled Device object representing a Twinkly device.
"""
ctr = xled.ControlInterface(device.ip_address, device.hw_address)
ctr.set_mode("rt") # Set the device to real-time mode
num_leds = ctr.get_device_info()["number_of_led"]
led_config = ctr.get_led_config()["strings"]
positions_to_light = [
light_string["first_led_id"] + light_string["length"] - 1
for light_string in led_config
]
colors = [random_color() for _ in positions_to_light]
for i, (pos, color) in enumerate(zip(positions_to_light, colors)):
print(f"Lighting strand {i + 1} at index {pos} ({color})")
frame_data = make_custom_frame(num_leds, positions_to_light, colors)
ctr.set_rt_frame_socket(frame_data, 3)
if __name__ == "__main__":
timeout_seconds = 20
try:
for device in xled.discover.xdiscover(timeout=timeout_seconds):
print(f"Found device at {device.ip_address} ({device.hw_address})!")
light_last_led_on_each_string(device)
except xled.exceptions.DiscoverTimeout:
print(
f"Discovery timed out after {timeout_seconds} seconds with no further devices found."
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment