tl;dr: This code turns cursor position into color and brightness. X = hue, Y = brightness. Left click rotates X position from hue -> saturation -> locked. Right click to toggle brightness lock. Only works on Linux, should be easy to port. Use KDE Connect to control it from your phone.
Occasionally, I have been known to sleep. Sometimes when I sleep, I’ll wake up in the middle of the night and either have to turn on a light or risk running right into a wall. If I turn on a light I’m going to be instantly awake. A soft red glow would make it possible to see, without waking up. But hooking up a light switch or motion detector or some other fancy crap is too much effort.
So I made a solution with what I had, an Android phone and the Linux PC the LEDs are hooked up to. On my phone I have the KDE Connect app, which I can use as a remote control for my PC. I can play/pause/skip music, send/receive files, and most importantly control the mouse cursor.
I took advantage of that to make this script that grabs the mouse cursor, and sets all connected LED’s brightness and color based on the cursor position. When the script starts, X position of the cursor controls the hue, with Y position controlling brightness. Left clicking once swaps X position from hue to saturation. Clicking twice locks both hue and saturation and leaves brightness as the only control active, making it easy to just swipe up and down on the phone to adjust brightness. Right clicking toggles the brightness lock on and off.
Switching between modes and locking/unlocking the various thing saves and restores cursor position so that there aren’t any sharp changes in anything when switching from mode to mode. The cursor is disabled from clicking on other windows while the program is running to prevent you from accidentally clicking on something you didn’t mean to.
Keep in mind, this code depends on X to grab pointer location, so it will only work on Linux. It should be fairly easy to port to Windows for anyone interested, but you’d have to find an alternate way of controlling the cursor since KDE Connect is also Linux-only. You might just bring a wireless mouse to bed with you.
With all that in mind, here’s the code:
from Xlib import display, X
from blinkstick import blinkstick
from colorsys import hsv_to_rgb
from time import time, sleep
hue = 0
sat = 1
val = 0.5
mode = 0 # left click to switch control from hue/sat/none.
lock_brightness = False # right click to lock brightness.
disp = display.Display() # Get the X Display
screen = disp.screen() # Get the X Screen
root = screen.root # Get the root window
max_y = screen.height_in_pixels # Detect screen height
max_x = screen.width_in_pixels # And width
root.grab_pointer(1, X.ButtonPressMask, X.GrabModeAsync, X.GrabModeAsync, X.NONE, X.NONE, X.CurrentTime) # Grabs the cursor and watches for events.
sticks = blinkstick.find_all() # Find all connected blinksticks
start = time()
while True:
y = screen.root.query_pointer().root_y # Get X position of cursor
x = screen.root.query_pointer().root_x # Get Y position of cursor
if mode == 0: # If cursor controls hue
hue = x/max_x
elif mode == 1: # If cursor controls sat
sat = x/max_x
if not lock_brightness: # If cursor controls brightness
val = (max_y - y)/max_y
if disp.pending_events(): # If there are any mouse clicks waiting for us
new_x = x # Prepare for possible cursor position changes
new_y = y
while disp.pending_events(): # Loop through all mouse events
event = disp.next_event() # Get the current event
if event.detail == 1: # If it's a left click,
mode = (mode + 1) % 3 # rotate through modes.
if mode == 0: # If we're in hue mode now,
new_x = max_x*hue # Restore X mouse position
elif mode == 1: # If we're in satuation mode now,
new_x = max_x*sat # Do the same
elif event.detail == 3: # If this is a right click,
lock_brightness = not lock_brightness # toggle the brightness lock.
if not lock_brightness: # And if we unlocked it,
new_y = max_y*val # Restore Y mouse position
root.warp_pointer(int(new_x), int(new_y)) # Set the cursor to its new position
disp.sync() # And fire away
r, g, b = hsv_to_rgb(hue, sat, val) # Set RGB values
print(round(r, 2), round(g, 2), round(b, 2), end=" \r") # Print it out for fun
now = time()
if now-start < 0.02: # Make sure we gave the blinkstick enough of a break to catch up
sleep(0.02 - (now-start)) # I think that math works out.
for stick in sticks: # Loop over all blinksticks
count = stick.get_led_count() # Get LED count
if count == -1: # If this strip is a dumb single-color strip (Pro w/ LED adapter)
stick.set_color(0, 0, int(g*255), int(r*255), int(b*255)) # Use set_color instead
else: # If they're addressable,
stick.set_led_data(0, [int(g*255), int(r*255), int(b*255)]*count) # Then address them.
start = time()
And with that you should be able to control your blinkstick’s color and brightness from your phone.