Zigbee color bulb light show
The bulb goes full color: a color-dimmable light (real ZCL Color + Level clusters) joins the color-remote coordinator, which then walks it through a color wheel — a new hue every few seconds, no typing. Press the remote’s button to toggle the bulb; click the bulb for its live color. Both sketches are in the Code tab; every color command is a real 802.15.4 frame in the 📡 Sniffer.

How it works
The color bulb hides a C6 running ZigbeeColorDimmableLight firmware — real On/Off, Level, and Color ZCL clusters, like a Hue bulb. The remote DevKit is the coordinator: it binds the bulb, switches it on, and then walks a color wheel, sending a genuine ZCL color command every few seconds. The firmware’s RGB callback drives the internal WS2812, whose bit-banged frames the enclosure decodes into the glass color you see. The button on the remote sends a real Toggle.
What's on the bench
- 2× Battery
- Button
- ESP32-C6
- Zigbee Color Bulb
How it's wired
- Battery · pos→ESP32-C6 · vin
- Battery · neg→ESP32-C6 · gnd
- Button · a→ESP32-C6 · g9
- Button · b→ESP32-C6 · gnd2
- Battery · pos→Zigbee Color Bulb · vcc
- Battery · neg→Zigbee Color Bulb · gnd
The code
The exact Arduino C++ sketch(es) the bundled firmware was compiled from — shown in the simulator’s Code tab, where you can edit them and press Compile & upload to rebuild the board’s firmware.
Color remote (coordinator)
// Zigbee color remote — the coordinator for the color bulb. // // Forms the network, binds the color-dimmable light, then puts on a show // with no typing: every few seconds it walks the bulb through a color // wheel with genuine ZCL Color/Level commands. Pressing BOOT toggles the // bulb on/off. #include <Arduino.h> #ifndef ZIGBEE_MODE_ZCZR #error "Zigbee coordinator mode is not selected in Tools->Zigbee mode" #endif #include "Zigbee.h" #define SWITCH_ENDPOINT 5 uint8_t button = BOOT_PIN; ZigbeeColorDimmerSwitch zbRemote = ZigbeeColorDimmerSwitch(SWITCH_ENDPOINT); // A small color wheel the remote walks through. static const uint8_t WHEEL[][3] = { {255, 40, 20}, // warm red {255, 160, 0}, // amber {60, 255, 60}, // green {40, 120, 255}, // blue {200, 60, 255}, // violet {255, 255, 220}, // warm white }; void setup() { Serial.begin(115200); pinMode(button, INPUT_PULLUP); zbRemote.setManufacturerAndModel("Breadboard", "ColorRemote"); zbRemote.allowMultipleBinding(true); Zigbee.addEndpoint(&zbRemote); Zigbee.setRebootOpenNetwork(180); if (!Zigbee.begin(ZIGBEE_COORDINATOR)) { Serial.println("Zigbee failed to start!"); Serial.println("Rebooting..."); ESP.restart(); } Serial.println("Network formed and open. Waiting for the color bulb to bind"); while (!zbRemote.bound()) { Serial.print("."); delay(500); } Serial.println(); Serial.println("Bulb bound - starting the color show (press BOOT to toggle)."); delay(1000); zbRemote.lightOn(); zbRemote.setLightLevel(220); } void loop() { // BOOT toggles the bulb (debounced on release). if (digitalRead(button) == LOW) { delay(100); while (digitalRead(button) == LOW) { delay(50); } zbRemote.lightToggle(); Serial.println("TOGGLE sent"); } // Walk the color wheel while bound. static uint32_t lastStep = 0; static size_t idx = 0; if (millis() - lastStep >= 5000) { lastStep = millis(); const uint8_t *c = WHEEL[idx]; idx = (idx + 1) % (sizeof(WHEEL) / sizeof(WHEEL[0])); zbRemote.setLightColor(c[0], c[1], c[2]); Serial.printf("color -> rgb(%u,%u,%u)\r\n", c[0], c[1], c[2]); } delay(50); }
Color bulb (end device)
// Zigbee color bulb — a color-dimmable light end device (like a Hue bulb). // // The coordinator's ZCL On/Off, Level and Color commands land here; the // combined state drives the DevKit's WS2812 (RGB_BUILTIN), which the bulb // enclosure renders as the glass color. #include <Arduino.h> #ifndef ZIGBEE_MODE_ED #error "Zigbee end device mode is not selected in Tools->Zigbee mode" #endif #include "Zigbee.h" #define ZIGBEE_LIGHT_ENDPOINT 10 uint8_t led = RGB_BUILTIN; ZigbeeColorDimmableLight zbColorLight = ZigbeeColorDimmableLight(ZIGBEE_LIGHT_ENDPOINT); void setRGB(bool state, uint8_t red, uint8_t green, uint8_t blue, uint8_t level) { if (!state) { rgbLedWrite(led, 0, 0, 0); Serial.println("light OFF"); return; } // Scale the color by the level (ZCL level control), like a real bulb. uint8_t r = (uint16_t)red * level / 255; uint8_t g = (uint16_t)green * level / 255; uint8_t b = (uint16_t)blue * level / 255; rgbLedWrite(led, r, g, b); Serial.printf("light ON rgb(%u,%u,%u) level %u\r\n", red, green, blue, level); } void setup() { Serial.begin(115200); rgbLedWrite(led, 0, 0, 0); zbColorLight.setManufacturerAndModel("Breadboard", "ColorBulb"); zbColorLight.onLightChangeRgb(setRGB); Serial.println("Adding ZigbeeColorDimmableLight endpoint to Zigbee Core"); Zigbee.addEndpoint(&zbColorLight); if (!Zigbee.begin()) { Serial.println("Zigbee failed to start!"); Serial.println("Rebooting..."); ESP.restart(); } Serial.println("Connecting to network"); while (!Zigbee.connected()) { Serial.print("."); delay(100); } Serial.println(); Serial.println("Joined as a color bulb."); } void loop() { delay(100); }
Try this
- Let the bulb join and bind, then just watch: a new color every 5 seconds.
- Press the remote’s button to toggle the bulb off and on mid-show.
- Click the bulb: the Inspector shows the live color as hex.
- Open the 📡 Sniffer and match each color change to its ZCL frame.



