Table of Contents

Lab 5. Zigbee

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.

Quick Specs

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 Protocol Stack

Addressing & Identity

Network Topologies

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.

Device Roles

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.

Network Formation, Joining & Commissioning

Formation (Coordinator):

  1. Choose channel(s) with minimal interference (avoid busy Wi‑Fi channels if possible).
  2. Set Extended PAN ID, PAN ID, security policy, and network key.
  3. Optionally open a permit‑join window to allow devices to join.

Joining (Routers/End Devices):

  1. Scan for beacons; choose a PAN (match channels/Extended PAN ID if preconfigured).
  2. Association request → parent assigns a 16‑bit short address.
  3. Secure key establishment (Trust Center link key / install code / default fallback depending on policy).

Security Overview

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.

Power & Sleep Behavior

ZCL: Clusters, Attributes, Commands

Groups, Scenes, and Binding

Zigbee End Device Example

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:

platformio.ini
[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.

partitions.csv
# 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.

Zigbee Router + End Device

In this next example we will simulate a Zigbee smart lightbulb controlled by a Zigbee light switch, using two ESP32-C6 Sparrow nodes.

Node 1: Zigbee End Device – Light Switch Profile

Node 2: Zigbee Router – Lightbulb Profile

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.

Platformio Project Setup

You will need to modify platformio.ini with this dual-environment file:

platformio.ini
; 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.

Click here to get the code for this example.