Misc code for controlling LED strip lights
This code is provided as-is for anyone else hacking the sp6xxe controllers. It is not meant as a finished project.
Rather than build a custom controller, hacking a low-cost one seemed like a time saver. For as popular as these SP6xxE series controllers appear, the only obvious automation control project was from the UniLED project. While too heavyweight for my needs and missing some important control elements, credit to the author for making it work and detailing the protocol. The controller design is simple with a chunk of queriable parameter memory and commands to change parameters. Read parameter memory, send a command, look for visible result, read parameter memory again for changes, and repeat until the controller has given up its secrets.
An annyoing issue is querying parameter memory can be problematic due to bluetooth issues. A single-response query (0x02 0x01) returns 47 valid bytes followed by 50 corrupt likely due to a PDU overrun. A multi-response query (0x02 0x00) returns 7 notifications of 14/13 bytes (97 total) but causes a disconnect 10-20% of the time likely due to poor controller implementation that sleeps between notifications rather than waiting for delivery (and disconnects on buffer overrun). The amount of parameter memory returned varies based on configuration. 79 bytes appears typical and 80 after a 0x5c call. The 0x5c command configures 0..10 mode+effect pairs used by the remote control and adjusts the parameter memory size between 77 and 97. The parameter to 0x02 specifies the notification size with 29 bytes (9 header + 20 data) returning uncorrupted parameter memory in 4/5 notify messages.
Another quirky detail is how the sp630e handles rgbi intensity. The passed rgb is used as-is and intensity saved as a reference for subsequent rgb scaling. Passing 0:255:255:191 (rgb=cyan, intensity=75%) directly to the controller results in full-brightness cyan. A subsequent level=255 does nothing because green/blue are already 255. To compensate, the wrapper prescales the rgb values to match the passed intensity. So 0:255:255:75 (cyan @ 75% intensity) passes 0:191:191:191 to the controller. This allows subsequent set/inc/dec commands full intensity control while preserving the color. Though the controller uses 0-255 for intensity, the wrapper uses 0-100% to match my automation software.