Project Overview
Getting Started with Zigbee on the ESP32-C6: Build a real two-node Zigbee network from scratch — one ESP32-C6 as a smart light, a second as its wireless switch — using nothing but the Arduino IDE's built-in Zigbee examples. This is the same protocol behind millions of smart-home devices, running on a $10 board.
- Time: ~1 hour
- Skill level: Intermediate
- What you will build: A working Zigbee on/off light and a paired Zigbee switch — the foundation for sensors, scene controllers, and full smart-home devices.
Parts List
From ShillehTek
- ESP32-C6-N4 Pre-Soldered Development Board — you need two Zigbee-capable boards (one light, one switch); the Seeed XIAO ESP32-C6 works for either node
- Resistor Kit — for the LED's 220Ω current limiter
- 400-Point Breadboard
- Dupont Jumper Wires
- Optional: Tactile Button Kit if you want an external switch instead of the BOOT button
External
- An LED and two USB cables
Note: Zigbee runs on the 802.15.4 radio built into the ESP32-C6 — the same chip also does WiFi 6, BLE, and Thread. Zigbee's superpower is mesh networking: every powered device relays traffic, so networks get more reliable as they grow.
Step-by-Step Guide
Step 1 — Set Up the IDE for Zigbee
Goal: Get the ESP32 core and the right board settings.
What to do: Install the latest ESP32 core via Boards Manager (add Espressif's board manager URL under File → Preferences if you haven't). Select your board under Tools → Board → ESP32 Arduino → ESP32C6 Dev Module (or your specific C6 board). The Zigbee examples ship with the core — no extra libraries needed.
Expected result: IDE ready, with File → Examples → Zigbee available.
Step 2 — Wire and Flash the Light Node
Goal: Create a Zigbee on/off light device.
What to do: Wire GPIO4 → 220Ω resistor → LED → GND. Open File → Examples → Zigbee → Zigbee_On_Off_Light, and set two critical Tools options: Zigbee mode: Zigbee ED (end device) and Partition Scheme: Zigbee 4MB with spiffs. The sketch registers the LED as a light endpoint:
#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 = 4; // LED on GPIO4
uint8_t button = BOOT_PIN; // hold to factory-reset the node
ZigbeeLight zbLight = ZigbeeLight(ZIGBEE_LIGHT_ENDPOINT);
void setLED(bool value) {
digitalWrite(led, value);
}
void setup() {
Serial.begin(115200);
pinMode(led, OUTPUT);
pinMode(button, INPUT_PULLUP);
zbLight.onLightChange(setLED); // Zigbee commands drive the LED
Zigbee.addEndpoint(&zbLight);
Zigbee.begin(); // join the network
}
Expected result: The light node boots and searches for a Zigbee network to join.
Step 3 — Flash the Switch Node (the Coordinator)
Goal: Create the network and control the light.
What to do: On the second board, open File → Examples → Zigbee → Zigbee_On_Off_Switch. This node uses different settings: Zigbee mode: Zigbee ZCZR (coordinator/router), same Zigbee 4MB partition scheme. The coordinator forms the network that the light joins, and its BOOT button becomes the toggle:
#ifndef ZIGBEE_MODE_ZCZR
#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode"
#endif
#include "Zigbee.h"
#define SWITCH_ENDPOINT_NUMBER 5
#define GPIO_INPUT_IO_TOGGLE_SWITCH BOOT_PIN // or an external button
ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER);
void setup() {
Serial.begin(115200);
Zigbee.addEndpoint(&zbSwitch);
Zigbee.begin(ZIGBEE_COORDINATOR); // form the network
// button handling binds presses to on/off commands
// sent to the paired light endpoint
}
Expected result: The coordinator forms a network; the light node joins it automatically.
Step 4 — Pair and Test
Goal: Toggle an LED across the room with no WiFi involved.
What to do: Power both boards and watch the serial monitors: the coordinator opens the network, the light joins, and the switch binds to the light's endpoint. Press the switch board's BOOT button — the LED on the other board toggles. That's a genuine Zigbee command traveling over 802.15.4, exactly like a store-bought bulb and remote.
Expected result: Wireless on/off control between your two nodes.
Step 5 — Troubleshoot and Extend
Goal: Fix common snags, then go bigger.
What to do: If the nodes won't pair: confirm both radios initialized (serial output), keep them in range, and make sure both use the same channel. Compile errors almost always mean an outdated ESP32 core or the wrong Zigbee mode/partition selected. From here you can join the light to Home Assistant, SmartThings, or Alexa through a Zigbee gateway, add more lights and switches for a whole-room system, or swap the LED for a relay to switch real lamps.
Expected result: A debugged two-node network — and a roadmap to a full Zigbee smart home.
Conclusion
In one sitting you've stood up a complete Zigbee network: a coordinator forming the mesh, an end device joining it, and real on/off commands flowing between them. The ESP32-C6 makes the smart-home protocol hackable — sensors, scene controllers, and gateway-connected devices are all the same pattern with different endpoints.
Want the exact parts used in this build? Grab them from ShillehTek.com. If you want help customizing this project, check out our IoT consulting services.
Credits
All photos and images in this tutorial are credited to tech_nickk on Hackster.io. The original guide by tech_nickk (building on Zigbee example code by Espressif Systems and Jan Procházka) served as the reference for this ShillehTek version. We thank them for their excellent work in the maker community.


