%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D', 'background': '#ffffff', 'mainBkg': '#2C3E50', 'secondBkg': '#16A085', 'tertiaryBkg': '#E67E22'}}}%%
flowchart TD
subgraph Config[Configuration Station]
XCTU[XCTU Software] <--> USB[XBee Explorer USB]
USB <--> XCONF[XBee Modules<br/>Being Configured]
end
subgraph Coord[Coordinator Station]
ESP[ESP32 Board<br/>GPIO 16/17 UART] <--> XC[XBee S2C Coordinator<br/>PAN ID: 0x1234<br/>Channel: 25]
ESP -->|USB Serial<br/>115200 baud| MON[Serial Monitor]
end
subgraph ED1[End Device Station 1]
ARD1[Arduino Uno<br/>SoftwareSerial 10/11] <--> XE1[XBee End Device]
ARD1 --> DHT1[DHT22 Sensor<br/>Pin 2<br/>Temp & Humidity]
end
subgraph ED2[End Device Station 2]
ARD2[Arduino Uno<br/>SoftwareSerial 10/11] <--> XE2[XBee End Device]
ARD2 --> DHT2[DHT22 Sensor<br/>Pin 2<br/>Temp & Humidity]
end
XC <-.->|Zigbee Mesh<br/>2.4 GHz| XE1
XC <-.->|Zigbee Mesh<br/>2.4 GHz| XE2
style Config fill:#7F8C8D,stroke:#333
style Coord fill:#E67E22,stroke:#2C3E50
style ED1 fill:#16A085,stroke:#2C3E50
style ED2 fill:#16A085,stroke:#2C3E50
997 Zigbee Lab: ESP32 Temperature Monitoring Network
997.1 Learning Objectives
By the end of this chapter, you will be able to:
- Configure XBee Modules: Set up coordinator and end device roles using XCTU software
- Build a Sensor Network: Connect DHT22 sensors to Arduino end devices
- Implement API Mode Communication: Parse XBee API frames for reliable data transfer
- Create a Central Coordinator: Use ESP32 to receive and aggregate sensor data
- Monitor Network Health: Track RSSI, sensor counts, and alert on abnormal readings
What is this lab? A practical hands-on project building a Zigbee temperature and humidity monitoring network with real hardware.
When to use: - When learning Zigbee coordinator/end device communication - For understanding XBee API mode programming - Before deploying production sensor networks
Key Topics:
| Topic | Focus |
|---|---|
| XBee Configuration | XCTU software, API mode |
| Coordinator Role | ESP32 as central hub |
| End Device Role | Arduino with sensors |
| Data Aggregation | Parsing and displaying readings |
Prerequisites: - Zigbee Fundamentals - Basic Arduino/ESP32 programming - Understanding of serial communication
997.2 Prerequisites
Before starting this lab, ensure familiarity with:
- Zigbee Fundamentals and Architecture: Device roles, PAN formation, and network concepts
- Network Topologies Fundamentals: Star and mesh topology concepts
- Basic serial communication: UART, baud rates, and data framing
997.3 Hardware Requirements
To complete this lab, you will need:
- ESP32 Development Board
- XBee S2C module (configured as coordinator)
- 2x Arduino Uno + XBee modules (end devices)
- 2x DHT22 temperature/humidity sensors
- XBee Explorer USB adapter
- Jumper wires
- Breadboard
997.4 Part 1: Configure XBee Coordinator
Use XCTU software to configure the XBee module as a coordinator:
- Connect XBee to computer via USB adapter
- Open XCTU software
- Configure as Coordinator:
ID (PAN ID): 1234
CE (Coordinator Enable): 1
AP (API Mode): 2
BD (Baud Rate): 9600
- Click βWriteβ to save configuration
API mode 2 (AP=2) uses escaped characters for reliable binary data transfer. This prevents special bytes like 0x7E (start delimiter) from appearing in data payloads.
997.5 Part 2: ESP32 Coordinator Code
The ESP32 acts as the network coordinator, receiving data from all end devices:
#include <HardwareSerial.h>
// XBee connected to Serial2
#define XBEE_RX 16
#define XBEE_TX 17
HardwareSerial XBeeSerial(2);
struct SensorReading {
uint16_t nodeAddress;
float temperature;
float humidity;
unsigned long timestamp;
int rssi;
};
SensorReading sensorData[10];
int sensorCount = 0;
void setup() {
Serial.begin(115200);
XBeeSerial.begin(9600, SERIAL_8N1, XBEE_RX, XBEE_TX);
Serial.println("\n=== Zigbee Coordinator - Temperature Network ===");
Serial.println("Waiting for sensor data...\n");
delay(2000); // Wait for XBee initialization
}
void loop() {
// Check for incoming data from Zigbee network
if (XBeeSerial.available()) {
processZigbeePacket();
}
// Print network summary every 30 seconds
static unsigned long lastSummary = 0;
if (millis() - lastSummary > 30000) {
printNetworkSummary();
lastSummary = millis();
}
}
void processZigbeePacket() {
/**
* Process XBee API frame (API mode 2).
* Format: 7E [Length] [Frame Type] [Data] [Checksum]
*/
if (XBeeSerial.read() != 0x7E) return; // Start delimiter
// Read length (2 bytes)
uint16_t length = XBeeSerial.read() << 8;
length |= XBeeSerial.read();
uint8_t frameType = XBeeSerial.read();
if (frameType == 0x90) { // RX packet
// Read 64-bit source address
uint64_t sourceAddr64 = 0;
for (int i = 0; i < 8; i++) {
sourceAddr64 = (sourceAddr64 << 8) | XBeeSerial.read();
}
// Read 16-bit network address
uint16_t sourceAddr16 = XBeeSerial.read() << 8;
sourceAddr16 |= XBeeSerial.read();
// Skip receive options
XBeeSerial.read();
// Read RF data (temperature and humidity)
String data = "";
for (int i = 0; i < length - 12; i++) {
char c = XBeeSerial.read();
if (c != 0xFF) data += c;
}
// Skip checksum
XBeeSerial.read();
// Parse sensor data
parseSensorData(sourceAddr16, data);
}
}
void parseSensorData(uint16_t nodeAddr, String data) {
/**
* Parse sensor data format: "TEMP:22.5,HUMID:45.2,RSSI:-45"
*/
Serial.print("\n[Received] Node 0x");
Serial.print(nodeAddr, HEX);
Serial.print(": ");
Serial.println(data);
float temp = 0, humid = 0;
int rssi = 0;
// Extract temperature
int tempIdx = data.indexOf("TEMP:");
if (tempIdx >= 0) {
temp = data.substring(tempIdx + 5, data.indexOf(",", tempIdx)).toFloat();
}
// Extract humidity
int humidIdx = data.indexOf("HUMID:");
if (humidIdx >= 0) {
humid = data.substring(humidIdx + 6, data.indexOf(",", humidIdx)).toFloat();
}
// Extract RSSI
int rssiIdx = data.indexOf("RSSI:");
if (rssiIdx >= 0) {
rssi = data.substring(rssiIdx + 5).toInt();
}
// Store/update sensor reading
storeSensorReading(nodeAddr, temp, humid, rssi);
// Display formatted data
Serial.println("====================================");
Serial.print(" Temperature: ");
Serial.print(temp, 1);
Serial.println(" C");
Serial.print(" Humidity: ");
Serial.print(humid, 1);
Serial.println(" %");
Serial.print(" RSSI: ");
Serial.print(rssi);
Serial.println(" dBm");
Serial.println("====================================");
// Alert on abnormal readings
if (temp > 30.0) {
Serial.println("[ALERT] HIGH TEMPERATURE!");
}
if (temp < 10.0) {
Serial.println("[ALERT] LOW TEMPERATURE!");
}
if (humid > 70.0) {
Serial.println("[ALERT] HIGH HUMIDITY!");
}
}
void storeSensorReading(uint16_t nodeAddr, float temp, float humid, int rssi) {
/**
* Store sensor reading in memory
*/
// Find existing sensor or add new one
int idx = -1;
for (int i = 0; i < sensorCount; i++) {
if (sensorData[i].nodeAddress == nodeAddr) {
idx = i;
break;
}
}
if (idx == -1 && sensorCount < 10) {
idx = sensorCount++;
}
if (idx >= 0) {
sensorData[idx].nodeAddress = nodeAddr;
sensorData[idx].temperature = temp;
sensorData[idx].humidity = humid;
sensorData[idx].timestamp = millis();
sensorData[idx].rssi = rssi;
}
}
void printNetworkSummary() {
/**
* Print summary of all active sensors
*/
Serial.println("\n======================================================================");
Serial.println("NETWORK SUMMARY");
Serial.println("======================================================================");
Serial.print("Active Sensors: ");
Serial.println(sensorCount);
Serial.println("----------------------------------------------------------------------");
Serial.println("Node Temperature Humidity RSSI Last Update");
Serial.println("----------------------------------------------------------------------");
unsigned long now = millis();
for (int i = 0; i < sensorCount; i++) {
unsigned long age_sec = (now - sensorData[i].timestamp) / 1000;
Serial.print("0x");
Serial.print(sensorData[i].nodeAddress, HEX);
Serial.print(" ");
Serial.print(sensorData[i].temperature, 1);
Serial.print(" C ");
Serial.print(sensorData[i].humidity, 1);
Serial.print("% ");
Serial.print(sensorData[i].rssi);
Serial.print("dBm ");
Serial.print(age_sec);
Serial.println("s ago");
}
Serial.println("======================================================================\n");
}997.6 Part 3: Arduino End Device Code
Each end device reads sensors and transmits to the coordinator:
#include <SoftwareSerial.h>
#include <DHT.h>
#define DHTPIN 2
#define DHTTYPE DHT22
SoftwareSerial xbee(10, 11); // RX, TX
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
xbee.begin(9600);
dht.begin();
Serial.println("Zigbee End Device - Temperature Sensor");
// Wait for network join
delay(5000);
Serial.println("[OK] Joined Zigbee network");
}
void loop() {
// Read sensor
float temp = dht.readTemperature();
float humid = dht.readHumidity();
if (isnan(temp) || isnan(humid)) {
Serial.println("[ERROR] Failed to read sensor");
delay(10000);
return;
}
// Read RSSI (signal strength)
int rssi = getRSSI();
// Format and send data
String data = "TEMP:" + String(temp, 1) +
",HUMID:" + String(humid, 1) +
",RSSI:" + String(rssi);
xbee.print(data);
Serial.print("Sent: ");
Serial.println(data);
// Sleep for 10 seconds
delay(10000);
}
int getRSSI() {
// Query XBee for last RSSI (simplified)
// In real implementation, send AT command "ATDB"
return -random(40, 70); // Simulate RSSI between -40 and -70 dBm
}997.7 Expected Output
When the network is running, the coordinator displays:
=== Zigbee Coordinator - Temperature Network ===
Waiting for sensor data...
[Received] Node 0x1: TEMP:22.3,HUMID:45.8,RSSI:-52
====================================
Temperature: 22.3 C
Humidity: 45.8 %
RSSI: -52 dBm
====================================
[Received] Node 0x2: TEMP:23.1,HUMID:48.2,RSSI:-58
====================================
Temperature: 23.1 C
Humidity: 48.2 %
RSSI: -58 dBm
====================================
======================================================================
NETWORK SUMMARY
======================================================================
Active Sensors: 2
----------------------------------------------------------------------
Node Temperature Humidity RSSI Last Update
----------------------------------------------------------------------
0x1 22.3 C 45.8% -52dBm 5s ago
0x2 23.1 C 48.2% -58dBm 3s ago
======================================================================
997.8 Troubleshooting
| Problem | Solution |
|---|---|
| No data received | Verify PAN ID matches on all devices |
| Garbled data | Check baud rate settings (9600) |
| Only partial packets | Ensure API mode 2 on coordinator |
| Sensors not joining | Check coordinator CE=1 setting |
| Weak RSSI | Move devices closer or add routers |
997.9 Summary
This lab demonstrated building a practical Zigbee temperature monitoring network:
- XBee Configuration: Used XCTU to set up coordinator and end device roles with matching PAN ID
- API Mode Communication: Implemented frame parsing for reliable binary data transfer
- Sensor Integration: Connected DHT22 sensors to Arduino end devices
- Data Aggregation: ESP32 coordinator collects and displays readings from multiple sensors
- Network Monitoring: Tracked RSSI and timing for all connected devices
997.10 Whatβs Next
Continue with Zigbee Lab: Network Analyzer to learn how to visualize network topology and device health using Python and Zigbee2MQTT, or explore the Zigbee Mesh Simulator for hands-on routing experiments.
Prerequisites: - Zigbee Fundamentals and Architecture - Device roles and protocol stack
Next Steps: - Zigbee Lab: Network Analyzer - Python monitoring tools - Zigbee Lab: Mesh Simulator - Interactive Wokwi simulation
Reference: - Zigbee Comprehensive Review - Protocol deep dive