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.