Zigbee is a low‑power, low‑data‑rate wireless protocol for building sensor/actuator networks (home automation, smart energy, lighting, industrial monitoring). It sits on top of IEEE 802.15.4 radios and adds networking, security, and application profiles.
Topic | Value | Notes |
---|---|---|
Frequency bands | 2.4 GHz (worldwide); optional sub‑GHz 868/915 MHz | 2.4 GHz is by far the most common |
Channels (2.4 GHz) | 16 channels: 11–26 | 5 MHz spacing; avoid Wi‑Fi overlap when possible |
Data rate | 250 kbps @ 2.4 GHz | Lower at sub‑GHz: 20/40/100 kbps |
Modulation | O-QPSK (2.4 GHz) | DSSS spread spectrum |
Range | ~10–100 m typical indoors | Depends on power, antennas, environment |
Max nodes | ~65k per PAN | 16‑bit short addressing |
Topologies | Star, Tree, Mesh | Mesh is the headline feature |
Power model | Sleepy end devices supported | Polling via parents (routers/coordinator) |
Zigbee supports several types of network topologies, including star, tree, and mesh. Among these, mesh networks are the most notable. In a mesh topology, devices can relay messages through one another, greatly extending the range and reliability of communication without relying solely on a central hub.
Star networks are simpler and center around a single coordinator, which communicates directly with end devices. Tree networks provide a hierarchical structure, where routers can also act as intermediaries between devices and the coordinator, offering a balance between coverage and efficiency.
Zigbee networks consist of three primary device roles:
The combination of these roles allows for flexible network configurations that can adapt to various deployment scenarios, from simple home automation systems to large-scale industrial sensor grids.
Formation (Coordinator):
Joining (Routers/End Devices):
Zigbee applies security at two key protocol layers: the MAC (Medium Access Control) layer and the APS (Application Support) layer. At the MAC layer, security relies on a Network Key (NK), which is shared by all devices within the Personal Area Network (PAN) and is used to encrypt and authenticate network-level communications. For more fine-grained and secure interactions, the APS layer uses Link Keys (LK), which are unique to each pair of devices. These keys help secure application-level messages and are also used in communication with the Trust Center—a central authority, typically the coordinator, that manages authentication and key distribution across the network.
To establish secure links, Zigbee supports install codes, which are unique per-device secrets used to derive initial link keys. These are strongly preferred over using global default keys, which are vulnerable to compromise. For improved security, best practices include disabling the use of known default keys, using install codes or other out-of-band commissioning methods, limiting the duration that the network allows new device joins (known as the permit-join window), and scheduling regular updates to the Network Key. These measures help mitigate risks from eavesdropping, spoofing, and unauthorized device access.
In this example we will be setting up the ESP32-C6 Sparrow node to act as a Zigbee End Device, registering to the network and sending periodic temperature, humidity and pressure readings to the Coordinator. As a coordinator we will be using a Home Assistant Green gateway with a Connect ZBT-1 Zigbee Coordinator attached.
You will need to edit platformio.ini and add these compile flags and libraries:
[env:esp32-c6-sparrow] platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip board = esp32-c6-devkitm-1 framework = arduino ; use SPIFFS for on-board files ;board_build.filesystem = spiffs build_flags = -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 -D ESP32_C6_env -D ZIGBEE_MODE_ED ; (optional) more logs while bringing up Zigbee -D CORE_DEBUG_LEVEL=5 ; Use a partitions.csv that contains Zigbee NV partitions board_build.partitions = partitions.csv monitor_speed = 115200 lib_deps = adafruit/Adafruit BME680 Library@^2.0.3 adafruit/Adafruit Unified Sensor@^1.1.14 adafruit/Adafruit NeoPixel@^1.12.0
Also, in the project root (same level as platformio.ini) you will need to create a .csv file that specifies the Zigbee partitions for the ED.
# Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xE000, 0x2000, app0, app, ota_0, 0x10000, 0x140000, app1, app, ota_1, 0x150000, 0x140000, spiffs, data, spiffs, 0x290000, 0x15B000, zb_storage, data, fat, 0x3EB000, 0x4000, zb_fct, data, fat, 0x3EF000, 0x1000, coredump, data, coredump, 0x3F0000, 0x10000,
Then you can add the main.cpp contents.
Click here to get the code sample.
This code sets up a Zigbee End Device on ESP32-C6 Sparrow that periodically reads environmental data from a BME680 sensor (temperature, humidity, and pressure) and reports it via Zigbee using two custom endpoints. It also handles Zigbee identify mode with blinking the neopixel LED and allows factory reset by holding the BOOT button for 3 seconds.
The device registers itself on the Zigbee network with manufacturer and model identifiers, sets reporting intervals and tolerances for each sensor type, and reacts to identify commands by blinking its LED. If Zigbee fails to initialize or connect, it restarts the ESP32.
In this next example we will simulate a Zigbee smart lightbulb controlled by a Zigbee light switch, using two ESP32-C6 Sparrow nodes.
When the ED button is pressed it sends an On or Off Zigbee command to the bound router device. The router receives the command and toggles the NeoPixel accordingly. Zigbee binding or group addressing links the two.
You will need to modify platformio.ini with this dual-environment file:
; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; See https://docs.platformio.org/page/projectconf.html for details. [platformio] default_envs = sparrow-switch [env] platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip board = esp32-c6-devkitm-1 framework = arduino ; use SPIFFS for on-board files ;board_build.filesystem = spiffs build_flags = -D ARDUINO_USB_MODE=1 -D ARDUINO_USB_CDC_ON_BOOT=1 -D ESP32_C6_env ; (optional) more logs while bringing up Zigbee ;-D CORE_DEBUG_LEVEL=5 ; Use a partitions.csv that contains Zigbee NV partitions (see step 2) board_build.partitions = partitions.csv monitor_speed = 115200 [env:sparrow-switch] build_flags = ${env.build_flags} -D ZIGBEE_MODE_ED -D SPARROW_SWITCH -D CONFIG_ZB_ENABLED=1 -L$PLATFORMIO_PACKAGES_DIR/framework-arduinoespressif32-libs/esp32c6/lib -lesp_zb_api.ed -lzboss_stack.ed -lzboss_port.native -lzboss_port.remote [env:sparrow-light] build_flags = ${env.build_flags} -D ZIGBEE_MODE_ROUTER -D SPARROW_LIGHT -D CONFIG_ZB_ENABLED=1 -L$PLATFORMIO_PACKAGES_DIR/framework-arduinoespressif32-libs/esp32c6/lib -lesp_zb_api.zczr -lzboss_stack.zczr -lzboss_port.native -lzboss_port.remote lib_deps = adafruit/Adafruit NeoPixel@^1.12.0
When building and deploying on the two nodes, switch default_envs
between sparrow-switch
and sparrow-light
.
Keep the same partitions.csv file.
The main is a dual one, depending on which type of device you are building for from platformio.ini.