I made my own controller!
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
# Exploring Christmas Lights
|
# Exploring Christmas Lights
|
||||||
|
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Table of Contents](#table-of-contents)
|
- [Table of Contents](#table-of-contents)
|
||||||
- [Holidays](#holidays)
|
- [Holidays](#holidays)
|
||||||
- [Exploring and Learning](#exploring-and-learning)
|
- [Exploring and Learning](#exploring-and-learning)
|
||||||
- [Summary](#summary)
|
- [Summary](#summary)
|
||||||
|
- [Taking over the lights](#taking-over-the-lights)
|
||||||
|
- [Hidden modes](#hidden-modes)
|
||||||
- [Code](#code)
|
- [Code](#code)
|
||||||
|
|
||||||
## Holidays
|
## Holidays
|
||||||
@@ -65,6 +67,7 @@ If I had to guess at this point, the first three bits would be for the pattern!
|
|||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
Here's a summary of the command format that I've found:
|
Here's a summary of the command format that I've found:
|
||||||
|
|
||||||
- "On" by default
|
- "On" by default
|
||||||
- Short "off" pulses separate bits
|
- Short "off" pulses separate bits
|
||||||
- Pulses are 105±5µs. `0` bit has 4965±5µs pause and `1` bit has 16998±6µs pause
|
- Pulses are 105±5µs. `0` bit has 4965±5µs pause and `1` bit has 16998±6µs pause
|
||||||
@@ -81,6 +84,7 @@ Here's a summary of the command format that I've found:
|
|||||||
- `11`: Firefly
|
- `11`: Firefly
|
||||||
|
|
||||||
Also some notes about the behaviour of some modes and commands that I observed:
|
Also some notes about the behaviour of some modes and commands that I observed:
|
||||||
|
|
||||||
- Even when LEDs are off, the signal is still fully in "on" position, it's up to the LED to show light or not
|
- Even when LEDs are off, the signal is still fully in "on" position, it's up to the LED to show light or not
|
||||||
- The Power Off button sends all zeros: `0 00 0 000`
|
- The Power Off button sends all zeros: `0 00 0 000`
|
||||||
- The Power On button flashes white/off three times with about 330ms flashes, then waits about 475ms then sets the current color and pattern
|
- The Power On button flashes white/off three times with about 330ms flashes, then waits about 475ms then sets the current color and pattern
|
||||||
@@ -90,6 +94,7 @@ Also some notes about the behaviour of some modes and commands that I observed:
|
|||||||
- In multi-color mode, when a light turns off and back on, it always switches colors
|
- In multi-color mode, when a light turns off and back on, it always switches colors
|
||||||
|
|
||||||
Some example commands:
|
Some example commands:
|
||||||
|
|
||||||
- Steady white: `0 00 0 111`
|
- Steady white: `0 00 0 111`
|
||||||
- Steady multi-color `0 00 1 000`
|
- Steady multi-color `0 00 1 000`
|
||||||
- Fade red: `0 01 0 001`
|
- Fade red: `0 01 0 001`
|
||||||
@@ -101,6 +106,70 @@ Some example commands:
|
|||||||
|
|
||||||
It was super fun to be able to figure out how the lights work. But to get back to my original goal, I wanted to be able to customize the patterns. I have less options than I thought I would since the patterns are hardcoded into the bulbs directly. But I can still customize switching between patterns and colors. At this time I don't have the skills or hardware to reproduce the MOSFET switching needed to drive the LEDs, but that is the next step in this project!
|
It was super fun to be able to figure out how the lights work. But to get back to my original goal, I wanted to be able to customize the patterns. I have less options than I thought I would since the patterns are hardcoded into the bulbs directly. But I can still customize switching between patterns and colors. At this time I don't have the skills or hardware to reproduce the MOSFET switching needed to drive the LEDs, but that is the next step in this project!
|
||||||
|
|
||||||
|
*(Update: I did get there! See [Taking over the lights](#taking-over-the-lights). Also that leading `0` was not quite what I thought. See [Hidden modes](#hidden-modes).)*
|
||||||
|
|
||||||
|
## Taking over the lights
|
||||||
|
|
||||||
|
Fast forward a few years and I finally came back to the "drive these myself" part. The original controller box unplugs from both the brick and the string, so I left that board alone and built a little replacement brain.
|
||||||
|
|
||||||
|
The power supply is labeled **29V 45W**. The string still wants that high voltage, and an ESP8266/ESP32 only wants 3.3V logic. So the setup is:
|
||||||
|
|
||||||
|
1. Keep the original 29V brick for the lights
|
||||||
|
2. A buck converter steps 29V down to 5V for a NodeMCU (or just use USB while tinkering, but share ground with the brick)
|
||||||
|
3. An N-channel logic-level MOSFET on the **low side** (string `L-`) does the same job the OEM high-side switch did: briefly cut power to encode bits
|
||||||
|
4. GPIO idle **HIGH** = lights powered; short **LOW** pulses = the protocol
|
||||||
|
|
||||||
|
I used a gate resistor (~150Ω) between the GPIO and the MOSFET gate, and a 10kΩ pulldown from gate to ground so the FET doesn't float on during boot. Source to ground / brick negative, drain to string `L-`, brick positive straight to string `L+`.
|
||||||
|
|
||||||
|
Once power toggling worked I ported the protocol from the earlier Arduino sketch onto the NodeMCU. Steady red, then a full pattern/color demo, and it worked! Watching the board LED and the string flip together never gets old.
|
||||||
|
|
||||||
|
I also poked at multi-color a bit. If you keep resending Steady Multi, most bulbs reshuffle pretty randomly, but some hang on one color for a while or flip between two colors before eventually wandering through everything. Re-sending Multi also includes those short power-off pulses in the frame, so the reshuffle might be "multi mode plus little power glitches" as much as "decoded the Multi bit again."
|
||||||
|
|
||||||
|
## Hidden modes
|
||||||
|
|
||||||
|
Remember how I said the first pattern bit was always `0` and there were only four patterns? That was true for everything the *phone app* sends. It was not true for what the bulbs actually understand.
|
||||||
|
|
||||||
|
I wrote a small sweeper that walked the 7-bit commands the app never uses, with toggle switches to step forward/back so I could stare at the string and fill in a table ([command-sweep.md](./command-sweep.md)). Turns out the format is better thought of as:
|
||||||
|
|
||||||
|
`PPP M BGR`
|
||||||
|
|
||||||
|
- **PPP** (3 bits): pattern. There are **eight**, not four!
|
||||||
|
- **M** (1 bit): solid color vs palette mode
|
||||||
|
- **BGR** (3 bits): either a normal color, or which palette when `M=1`
|
||||||
|
|
||||||
|
That "leading `0`" was just the high pattern bit. The app never set it, so I never saw patterns `100` through `111`.
|
||||||
|
|
||||||
|
### Patterns
|
||||||
|
|
||||||
|
| PPP | Name (what I'm calling it) | What it looks like |
|
||||||
|
| ----- | ---------------------------- | -------------------- |
|
||||||
|
| `000` | Steady | Solid color / palette |
|
||||||
|
| `001` | Fade | OEM Fade |
|
||||||
|
| `010` | Sparkle | OEM Sparkle (sparkles toward white) |
|
||||||
|
| `011` | Firefly | OEM Firefly |
|
||||||
|
| `100` | Twinkle | Mostly dark; random bulbs flash on in color |
|
||||||
|
| `101` | Fast Sparkle | Like Sparkle but faster |
|
||||||
|
| `110` | Anti-Sparkle | Base color on; sparkles turn bulbs *off* (black sparkles!) |
|
||||||
|
| `111` | Fast Twinkle | Faster Twinkle |
|
||||||
|
|
||||||
|
### Colors and palettes
|
||||||
|
|
||||||
|
When `M=0`, `BGR` is the same solid colors as before (Off, R, G, Y, B, M, C, W).
|
||||||
|
|
||||||
|
When `M=1`, those bits pick a **palette** instead of "red plus green equals yellow":
|
||||||
|
|
||||||
|
| BGR | Palette |
|
||||||
|
| ----- | --------- |
|
||||||
|
| `000` | Classic multi (random per bulb) |
|
||||||
|
| `001` | Christmas: red / white / green |
|
||||||
|
| `010` | July 4th: red / white / blue |
|
||||||
|
| `011` | Same as classic multi, as far as I can tell |
|
||||||
|
| `100` through `111` | Often just off, or weird pattern-dependent leftovers |
|
||||||
|
|
||||||
|
So yeah, the bulbs had Christmas and Fourth of July palettes sitting in there unused the whole time. Also a whole second set of sparkle-ish patterns. The Flip mode on the phone is still just software, but a lot of the "I wish I had more modes" problem was already solved in the silicon.
|
||||||
|
|
||||||
|
Full notes from the sweep are in [command-sweep.md](./command-sweep.md).
|
||||||
|
|
||||||
## Code
|
## Code
|
||||||
|
|
||||||
Even though I can't test it yet, I have gone ahead and written a sample program to produce the same signals to control the lights. I wrote it for the Arduino platform and it's available as [christmas-lights.c.ino](./christmas-lights.c.ino). View these signals in a similar way I can see they it matches pretty well with the official signals, although the Arduino is not as precise and there is more variance. The current program just loops through all the possible colors and patterns to replicate a "demo" mode.
|
The Arduino demo that walks the meaningful patterns and colors/palettes is [christmas-lights.c.ino](./christmas-lights.c.ino). It sends full 7-bit `PPP M BGR` frames (pattern in the top three bits). On ESP8266/ESP32 it defaults to `D1` for the MOSFET gate.
|
||||||
|
|||||||
+77
-38
@@ -1,42 +1,73 @@
|
|||||||
|
// Mr. Christmas powerline RGB protocol
|
||||||
|
// 7-bit command: PPP M BGR (MSB first)
|
||||||
|
//
|
||||||
|
// Idle HIGH = string powered; brief LOW pulses encode bits.
|
||||||
|
// Short pause ~= 0, long pause ~= 1.
|
||||||
|
|
||||||
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
|
const int command_pin = D1; // MOSFET gate
|
||||||
|
#else
|
||||||
|
const int command_pin = 8;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const int PULSE_DURATION = 100; // microseconds
|
||||||
|
const int SHORT_PAUSE = 4964; // bit 0
|
||||||
|
const int LONG_PAUSE = 16992; // bit 1
|
||||||
|
|
||||||
|
// 3bits: PPP
|
||||||
enum Pattern {
|
enum Pattern {
|
||||||
STEADY = 0,
|
STEADY = 0, // 000
|
||||||
FADE = 0x10,
|
FADE = 1, // 001
|
||||||
SPARKLE = 0x20,
|
SPARKLE = 2, // 010
|
||||||
FIREFLY= 0x30
|
FIREFLY = 3, // 011
|
||||||
|
TWINKLE = 4, // 100 - dark + colored flashes
|
||||||
|
FAST_SPARKLE = 5, // 101
|
||||||
|
ANTI_SPARKLE = 6, // 110 - black sparkles
|
||||||
|
FAST_TWINKLE = 7, // 111
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 4bits: MBGR
|
||||||
|
// M=0: BGR (solid colors)
|
||||||
|
// M=1: palette
|
||||||
enum Color {
|
enum Color {
|
||||||
OFF,
|
COLOR_OFF = 0, // 0000
|
||||||
RED,
|
RED = 1, // 0001
|
||||||
GREEN,
|
GREEN = 2, // 0010
|
||||||
YELLOW,
|
YELLOW = 3, // 0011
|
||||||
BLUE,
|
BLUE = 4, // 0100
|
||||||
MAGENTA,
|
MAGENTA = 5, // 0101
|
||||||
CYAN,
|
CYAN = 6, // 0110
|
||||||
WHITE,
|
WHITE = 7, // 0111
|
||||||
MULTICOLOR
|
MULTI = 8, // 1000 - multi-color
|
||||||
|
CHRISTMAS = 9, // 1001 - red/white/green
|
||||||
|
JULY4 = 10, // 1010 - red/white/blue
|
||||||
};
|
};
|
||||||
|
|
||||||
Pattern patterns[] = {STEADY, FADE, SPARKLE, FIREFLY};
|
Pattern patterns[] = {
|
||||||
Color colors[] = {RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, MULTICOLOR, OFF};
|
STEADY, FADE, SPARKLE, FIREFLY, TWINKLE, FAST_SPARKLE, ANTI_SPARKLE, FAST_TWINKLE,
|
||||||
|
};
|
||||||
|
const char *pattern_names[] = {
|
||||||
|
"Steady", "Fade", "Sparkle", "Firefly", "Twinkle", "FastSparkle", "AntiSparkle", "FastTwinkle",
|
||||||
|
};
|
||||||
|
|
||||||
int PULSE_DURATION = 100; // microseconds
|
Color colors[] = {
|
||||||
int SHORT_PAUSE = 4964; // microseconds
|
COLOR_OFF, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, MULTI, CHRISTMAS, JULY4,
|
||||||
int LONG_PAUSE = 16992; // miccroseconds
|
};
|
||||||
|
const char *color_names[] = {
|
||||||
// output pin to send the signals to
|
"Off", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White", "Multi", "Christmas", "July4",
|
||||||
int command_pin = 8;
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a single short pulse of "off".
|
* Send a single short pulse of "off".
|
||||||
*/
|
*/
|
||||||
void send_pulse() {
|
void send_pulse() {
|
||||||
|
noInterrupts();
|
||||||
digitalWrite(command_pin, LOW);
|
digitalWrite(command_pin, LOW);
|
||||||
delayMicroseconds(PULSE_DURATION);
|
delayMicroseconds(PULSE_DURATION);
|
||||||
digitalWrite(command_pin, HIGH);
|
digitalWrite(command_pin, HIGH);
|
||||||
|
interrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a single bit.
|
* Send a single bit.
|
||||||
*/
|
*/
|
||||||
@@ -45,45 +76,53 @@ void send_bit(bool b) {
|
|||||||
delayMicroseconds(b ? LONG_PAUSE : SHORT_PAUSE);
|
delayMicroseconds(b ? LONG_PAUSE : SHORT_PAUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a whole command. Commands start with a 0 bit then six bits of data.
|
* Send a whole 7-bit command (PPP M BGR), then an end pulse.
|
||||||
*/
|
*/
|
||||||
void send_command(int cmd) {
|
void send_command(int cmd) {
|
||||||
// start command
|
for (int mask = 0x40; mask > 0; mask >>= 1) {
|
||||||
send_bit(0);
|
send_bit(cmd & mask);
|
||||||
|
|
||||||
for (int i = 0x20; i > 0; i >>= 1) {
|
|
||||||
send_bit(cmd & i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// end command
|
|
||||||
send_pulse();
|
send_pulse();
|
||||||
|
|
||||||
// minimum time before sending another command
|
|
||||||
delayMicroseconds(LONG_PAUSE);
|
delayMicroseconds(LONG_PAUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a whole command based on a pattern and color.
|
* Send a whole command based on a pattern and color/palette.
|
||||||
*/
|
*/
|
||||||
void send_command(Pattern pattern, Color color) {
|
void send_command(Pattern pattern, Color color) {
|
||||||
send_command(pattern | color);
|
send_command((pattern << 4) | color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
pinMode(command_pin, OUTPUT);
|
pinMode(command_pin, OUTPUT);
|
||||||
digitalWrite(command_pin, HIGH);
|
digitalWrite(command_pin, HIGH);
|
||||||
|
Serial.begin(9600);
|
||||||
|
delay(500);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("Full demo");
|
||||||
|
delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
delay(1000);
|
// Demo: each pattern x colors/palettes.
|
||||||
|
for (unsigned p = 0; p < sizeof(patterns) / sizeof(patterns[0]); p++) {
|
||||||
|
for (unsigned c = 0; c < sizeof(colors) / sizeof(colors[0]); c++) {
|
||||||
|
if (colors[c] == COLOR_OFF && patterns[p] != FAST_SPARKLE) {
|
||||||
|
// Off is only meaningful with FastSparkle (dark + fast white sparkles).
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Sample "demo" mode where it cycles between all the colors of all the patterns
|
|
||||||
for (int p = 0; p < sizeof(patterns) / sizeof(Pattern); p++) {
|
|
||||||
for (int c = 0; c < sizeof(colors) / sizeof(Color); c++) {
|
|
||||||
send_command(patterns[p], colors[c]);
|
send_command(patterns[p], colors[c]);
|
||||||
|
Serial.print(pattern_names[p]);
|
||||||
|
Serial.print(" + ");
|
||||||
|
Serial.println(color_names[c]);
|
||||||
delay(10000);
|
delay(10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
send_command(STEADY, COLOR_OFF);
|
||||||
|
Serial.println("Off");
|
||||||
|
delay(5000);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
# 7-bit command sweep notes
|
||||||
|
|
||||||
|
## Revised protocol (after sweep)
|
||||||
|
|
||||||
|
Layout: `PPP M BGR` (7 bits, MSB first). Same pulse timing as before.
|
||||||
|
|
||||||
|
| Field | Bits | Meaning |
|
||||||
|
| ------- | ------ | --------- |
|
||||||
|
| PPP | 3 | Pattern (8 modes — not 4) |
|
||||||
|
| M | 1 | Palette / multi flag |
|
||||||
|
| BGR | 3 | Color or palette select |
|
||||||
|
|
||||||
|
The old write-up treated this as `0 PP M BGR` (leading bit always 0 + 2 pattern bits). The leading bit is actually **pattern bit 2**; the app simply never used patterns `100`–`111`.
|
||||||
|
|
||||||
|
### Patterns (`PPP`)
|
||||||
|
|
||||||
|
| PPP | Name (working) | Behavior |
|
||||||
|
| ----- | ---------------- | ---------- |
|
||||||
|
| `000` | Steady | Solid color / palette |
|
||||||
|
| `001` | Fade | Fade (OEM “Fade”) |
|
||||||
|
| `010` | Sparkle | Sparkle to white (OEM) |
|
||||||
|
| `011` | Firefly | Firefly (OEM) |
|
||||||
|
| `100` | Twinkle | Mostly off; random bulbs flash on in color (colored sparkles on dark) |
|
||||||
|
| `101` | Fast sparkle | Like Sparkle but faster |
|
||||||
|
| `110` | Anti-sparkle | Base color on; sparkles turn bulbs **off** (black sparkles) |
|
||||||
|
| `111` | Fast twinkle | Faster version of Twinkle (`100`) |
|
||||||
|
|
||||||
|
### Color / palette (`M` + `BGR`)
|
||||||
|
|
||||||
|
When `M=0`, `BGR` is a normal solid color (same as before):
|
||||||
|
|
||||||
|
| BGR | Color |
|
||||||
|
| ----- | ------- |
|
||||||
|
| `000` | Off |
|
||||||
|
| `001` | Red |
|
||||||
|
| `010` | Green |
|
||||||
|
| `011` | Yellow |
|
||||||
|
| `100` | Blue |
|
||||||
|
| `101` | Magenta |
|
||||||
|
| `110` | Cyan |
|
||||||
|
| `111` | White |
|
||||||
|
|
||||||
|
When `M=1`, `BGR` selects a **palette** (not a single RGB mix):
|
||||||
|
|
||||||
|
| BGR | Palette |
|
||||||
|
| ----- | --------- |
|
||||||
|
| `000` | Classic multi (per-bulb random across colors) |
|
||||||
|
| `001` | Christmas — red / white / green |
|
||||||
|
| `010` | July 4th — red / white / blue |
|
||||||
|
| `011` | Same as classic multi (indistinguishable from `000` in testing) |
|
||||||
|
| `100`–`111` | Often **off** or pattern-dependent (see tables; Fade/Firefly sometimes treat these as solid B/M/C/W) |
|
||||||
|
|
||||||
|
Palette behavior depends on pattern (e.g. Steady+Multi+`1xx` → off; Fade+Multi+`1xx` → solid colors; Sparkle+Multi+`1xx` → dark with white sparkles).
|
||||||
|
|
||||||
|
### OEM / app subset
|
||||||
|
|
||||||
|
The phone app only used `PPP` in `000`–`011` with either solid colors (`M=0`) or Multi (`M=1`, `BGR=000`). Hidden: palettes `001`/`010`/`011` and patterns `100`–`111`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Known (skipped by early sweep sketch)
|
||||||
|
|
||||||
|
- `PPP` `000`–`011`, `M=0`, any `BGR` → published Steady/Fade/Sparkle/Firefly × colors
|
||||||
|
- `PPP` `000`–`011`, `M=1`, `BGR=000` → Multi with those patterns
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sweep results
|
||||||
|
|
||||||
|
### A) Multi + nonzero BGR (`PPP` `000`–`011`, `M=1`, `BGR≠000`)
|
||||||
|
|
||||||
|
| Dec | Binary `PPP M BGR` | PPP | M | BGR | Observed |
|
||||||
|
| ----: | -------------------- | ----- | --- | ----- | ---------- |
|
||||||
|
| 9 | `000 1 001` | Steady | 1 | 001 | red/white/green |
|
||||||
|
| 10 | `000 1 010` | Steady | 1 | 010 | red/white/blue |
|
||||||
|
| 11 | `000 1 011` | Steady | 1 | 011 | classic multi (same as `000`) |
|
||||||
|
| 12 | `000 1 100` | Steady | 1 | 100 | off |
|
||||||
|
| 13 | `000 1 101` | Steady | 1 | 101 | off |
|
||||||
|
| 14 | `000 1 110` | Steady | 1 | 110 | off |
|
||||||
|
| 15 | `000 1 111` | Steady | 1 | 111 | off |
|
||||||
|
| 25 | `001 1 001` | Fade | 1 | 001 | red/white/green |
|
||||||
|
| 26 | `001 1 010` | Fade | 1 | 010 | red/white/blue |
|
||||||
|
| 27 | `001 1 011` | Fade | 1 | 011 | classic multi (same as `000`) |
|
||||||
|
| 28 | `001 1 100` | Fade | 1 | 100 | blue |
|
||||||
|
| 29 | `001 1 101` | Fade | 1 | 101 | magenta |
|
||||||
|
| 30 | `001 1 110` | Fade | 1 | 110 | cyan |
|
||||||
|
| 31 | `001 1 111` | Fade | 1 | 111 | white |
|
||||||
|
| 41 | `010 1 001` | Sparkle | 1 | 001 | red/white/green |
|
||||||
|
| 42 | `010 1 010` | Sparkle | 1 | 010 | red/white/blue |
|
||||||
|
| 43 | `010 1 011` | Sparkle | 1 | 011 | classic multi (same as `000`) |
|
||||||
|
| 44 | `010 1 100` | Sparkle | 1 | 100 | all off but still white sparkle |
|
||||||
|
| 45 | `010 1 101` | Sparkle | 1 | 101 | ditto |
|
||||||
|
| 46 | `010 1 110` | Sparkle | 1 | 110 | ditto |
|
||||||
|
| 47 | `010 1 111` | Sparkle | 1 | 111 | ditto |
|
||||||
|
| 57 | `011 1 001` | Firefly | 1 | 001 | red/white/green |
|
||||||
|
| 58 | `011 1 010` | Firefly | 1 | 010 | red/white/blue |
|
||||||
|
| 59 | `011 1 011` | Firefly | 1 | 011 | classic multi (same as `000`) |
|
||||||
|
| 60 | `011 1 100` | Firefly | 1 | 100 | blue |
|
||||||
|
| 61 | `011 1 101` | Firefly | 1 | 101 | magenta |
|
||||||
|
| 62 | `011 1 110` | Firefly | 1 | 110 | cyan |
|
||||||
|
| 63 | `011 1 111` | Firefly | 1 | 111 | white |
|
||||||
|
|
||||||
|
### B) Alternate patterns (`PPP` `100`–`111`)
|
||||||
|
|
||||||
|
| Dec | Binary `PPP M BGR` | PPP | M | BGR | Observed |
|
||||||
|
| ----: | -------------------- | ----- | --- | ----- | ---------- |
|
||||||
|
| 64 | `100 0 000` | Twinkle | 0 | 000 | off |
|
||||||
|
| 65 | `100 0 001` | Twinkle | 0 | 001 | all off but red sparkle |
|
||||||
|
| 66 | `100 0 010` | Twinkle | 0 | 010 | ditto but green sparkle |
|
||||||
|
| 67 | `100 0 011` | Twinkle | 0 | 011 | ditto but yellow |
|
||||||
|
| 68 | `100 0 100` | Twinkle | 0 | 100 | ditto blue |
|
||||||
|
| 69 | `100 0 101` | Twinkle | 0 | 101 | ditto magenta |
|
||||||
|
| 70 | `100 0 110` | Twinkle | 0 | 110 | ditto cyan |
|
||||||
|
| 71 | `100 0 111` | Twinkle | 0 | 111 | ditto white |
|
||||||
|
| 72 | `100 1 000` | Twinkle | 1 | 000 | ditto but the sparkles are multi |
|
||||||
|
| 73 | `100 1 001` | Twinkle | 1 | 001 | ditto but sparkles are red/white/green |
|
||||||
|
| 74 | `100 1 010` | Twinkle | 1 | 010 | ditto but red/white/blue |
|
||||||
|
| 75 | `100 1 011` | Twinkle | 1 | 011 | ditto classic multi (same as `000`) |
|
||||||
|
| 76 | `100 1 100` | Twinkle | 1 | 100 | off |
|
||||||
|
| 77 | `100 1 101` | Twinkle | 1 | 101 | off |
|
||||||
|
| 78 | `100 1 110` | Twinkle | 1 | 110 | off |
|
||||||
|
| 79 | `100 1 111` | Twinkle | 1 | 111 | off |
|
||||||
|
| 80 | `101 0 000` | Fast sparkle | 0 | 000 | all off but fast white sparkles |
|
||||||
|
| 81 | `101 0 001` | Fast sparkle | 0 | 001 | red and fast white sparkles |
|
||||||
|
| 82 | `101 0 010` | Fast sparkle | 0 | 010 | ditto green |
|
||||||
|
| 83 | `101 0 011` | Fast sparkle | 0 | 011 | ditto yellow |
|
||||||
|
| 84 | `101 0 100` | Fast sparkle | 0 | 100 | ditto blue |
|
||||||
|
| 85 | `101 0 101` | Fast sparkle | 0 | 101 | ditto magenta |
|
||||||
|
| 86 | `101 0 110` | Fast sparkle | 0 | 110 | ditto cyan |
|
||||||
|
| 87 | `101 0 111` | Fast sparkle | 0 | 111 | ditto but white (normal white is slightly dim and sparkles are brighter) |
|
||||||
|
| 88 | `101 1 000` | Fast sparkle | 1 | 000 | multi and fast sparkles |
|
||||||
|
| 89 | `101 1 001` | Fast sparkle | 1 | 001 | red/white/green and fast sparkles |
|
||||||
|
| 90 | `101 1 010` | Fast sparkle | 1 | 010 | ditto red/white/blue |
|
||||||
|
| 91 | `101 1 011` | Fast sparkle | 1 | 011 | classic multi and fast sparkles (same as `000`) |
|
||||||
|
| 92 | `101 1 100` | Fast sparkle | 1 | 100 | off and fast sparkles |
|
||||||
|
| 93 | `101 1 101` | Fast sparkle | 1 | 101 | ditto |
|
||||||
|
| 94 | `101 1 110` | Fast sparkle | 1 | 110 | ditto |
|
||||||
|
| 95 | `101 1 111` | Fast sparkle | 1 | 111 | ditto |
|
||||||
|
| 96 | `110 0 000` | Anti-sparkle | 0 | 000 | off |
|
||||||
|
| 97 | `110 0 001` | Anti-sparkle | 0 | 001 | red and anti-sparkles (black sparkles) |
|
||||||
|
| 98 | `110 0 010` | Anti-sparkle | 0 | 010 | ditto green |
|
||||||
|
| 99 | `110 0 011` | Anti-sparkle | 0 | 011 | ditto yellow |
|
||||||
|
| 100 | `110 0 100` | Anti-sparkle | 0 | 100 | ditto blue |
|
||||||
|
| 101 | `110 0 101` | Anti-sparkle | 0 | 101 | ditto magenta |
|
||||||
|
| 102 | `110 0 110` | Anti-sparkle | 0 | 110 | ditto cyan |
|
||||||
|
| 103 | `110 0 111` | Anti-sparkle | 0 | 111 | ditto white |
|
||||||
|
| 104 | `110 1 000` | Anti-sparkle | 1 | 000 | ditto multi |
|
||||||
|
| 105 | `110 1 001` | Anti-sparkle | 1 | 001 | ditto red/white/green |
|
||||||
|
| 106 | `110 1 010` | Anti-sparkle | 1 | 010 | ditto red/white/blue |
|
||||||
|
| 107 | `110 1 011` | Anti-sparkle | 1 | 011 | ditto classic multi (same as `000`) |
|
||||||
|
| 108 | `110 1 100` | Anti-sparkle | 1 | 100 | off |
|
||||||
|
| 109 | `110 1 101` | Anti-sparkle | 1 | 101 | off |
|
||||||
|
| 110 | `110 1 110` | Anti-sparkle | 1 | 110 | off |
|
||||||
|
| 111 | `110 1 111` | Anti-sparkle | 1 | 111 | off |
|
||||||
|
| 112 | `111 0 000` | Fast twinkle | 0 | 000 | off |
|
||||||
|
| 113 | `111 0 001` | Fast twinkle | 0 | 001 | all off but fast red sparkles |
|
||||||
|
| 114 | `111 0 010` | Fast twinkle | 0 | 010 | ditto green |
|
||||||
|
| 115 | `111 0 011` | Fast twinkle | 0 | 011 | ditto yellow |
|
||||||
|
| 116 | `111 0 100` | Fast twinkle | 0 | 100 | ditto blue |
|
||||||
|
| 117 | `111 0 101` | Fast twinkle | 0 | 101 | ditto magenta |
|
||||||
|
| 118 | `111 0 110` | Fast twinkle | 0 | 110 | ditto cyan |
|
||||||
|
| 119 | `111 0 111` | Fast twinkle | 0 | 111 | ditto white |
|
||||||
|
| 120 | `111 1 000` | Fast twinkle | 1 | 000 | ditto multi |
|
||||||
|
| 121 | `111 1 001` | Fast twinkle | 1 | 001 | ditto red/white/green |
|
||||||
|
| 122 | `111 1 010` | Fast twinkle | 1 | 010 | ditto red/white/blue |
|
||||||
|
| 123 | `111 1 011` | Fast twinkle | 1 | 011 | ditto classic multi (same as `000`) |
|
||||||
|
| 124 | `111 1 100` | Fast twinkle | 1 | 100 | off |
|
||||||
|
| 125 | `111 1 101` | Fast twinkle | 1 | 101 | off |
|
||||||
|
| 126 | `111 1 110` | Fast twinkle | 1 | 110 | off |
|
||||||
|
| 127 | `111 1 111` | Fast twinkle | 1 | 111 | off |
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
- **8 patterns**, not 4 — high bit selects the alternate set (twinkle / fast sparkle / anti-sparkle / fast twinkle).
|
||||||
|
- **`M=1` is palette mode**: `000`/`011` classic multi, `001` Christmas R/W/G, `010` July 4th R/W/B; `1xx` is pattern-dependent (often off).
|
||||||
|
- Fade/Firefly + Multi + `1xx` oddly map to solid B/M/C/W — possible alias or shared decode path.
|
||||||
|
- Names above (Twinkle, Fast sparkle, etc.) are working labels from observation, not OEM names.
|
||||||
Reference in New Issue
Block a user