Skip to content

Commit ef1cc89

Browse files
committed
Implement Network Scanning
Implemented Zigbee network scanning (async) to mostly match WiFi scan APIs. Added Zigbee_Scan_Networks example
1 parent ec60ed4 commit ef1cc89

File tree

4 files changed

+195
-119
lines changed

4 files changed

+195
-119
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/**
16+
* @brief This example demonstrates Zigbee Network Scanning.
17+
*
18+
* The example demonstrates how to use ESP Zigbee stack to scan for Zigbee networks.
19+
*
20+
* Any Zigbee mode can be selected in Tools->Zigbee mode
21+
* with proper Zigbee partition scheme in Tools->Partition Scheme.
22+
*
23+
* Please check the README.md for instructions and more detailed description.
24+
*
25+
* Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/)
26+
*/
27+
28+
#if !defined(ZIGBEE_MODE_ED) && !defined(ZIGBEE_MODE_ZCZR)
29+
#error "Zigbee device mode is not selected in Tools->Zigbee mode"
30+
#endif
31+
32+
#include "Zigbee_core.h"
33+
34+
#ifdef ZIGBEE_MODE_ZCZR
35+
zigbee_role_t role = ZIGBEE_ROUTER; // or can be ZIGBEE_COORDINATOR, but it wont scan itself
36+
#else
37+
zigbee_role_t role = ZIGBEE_END_DEVICE;
38+
#endif
39+
40+
void printScannedNetworks(uint16_t networksFound) {
41+
if (networksFound == 0) {
42+
Serial.println("No networks found");
43+
} else {
44+
zigbee_scan_result_t *scan_result = Zigbee.getScanResult();
45+
Serial.println("\nScan done");
46+
Serial.print(networksFound);
47+
Serial.println(" networks found:");
48+
Serial.println("Nr | PAN ID | CH | Permit Joining | Router Capacity | End Device Capacity | Extended PAN ID");
49+
for (int i = 0; i < networksFound; ++i) {
50+
// Print all available info for each network found
51+
Serial.printf("%2d", i + 1);
52+
Serial.print(" | ");
53+
Serial.printf("0x%04hx", scan_result[i].short_pan_id);
54+
Serial.print(" | ");
55+
Serial.printf("%2ld", scan_result[i].logic_channel);
56+
Serial.print(" | ");
57+
Serial.printf("%-14.14s", scan_result[i].permit_joining ? "Yes" : "No");
58+
Serial.print(" | ");
59+
Serial.printf("%-15.15s", scan_result[i].router_capacity ? "Yes" : "No");
60+
Serial.print(" | ");
61+
Serial.printf("%-19.19s", scan_result[i].end_device_capacity ? "Yes" : "No");
62+
Serial.print(" | ");
63+
Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", scan_result[i].extended_pan_id[7], scan_result[i].extended_pan_id[6],
64+
scan_result[i].extended_pan_id[5], scan_result[i].extended_pan_id[4],
65+
scan_result[i].extended_pan_id[3], scan_result[i].extended_pan_id[2],
66+
scan_result[i].extended_pan_id[1], scan_result[i].extended_pan_id[0]);
67+
Serial.println();
68+
delay(10);
69+
}
70+
Serial.println("");
71+
// Delete the scan result to free memory for code below.
72+
Zigbee.scanDelete();
73+
}
74+
}
75+
76+
void setup() {
77+
Serial.begin(115200);
78+
79+
// Initialize Zigbee stack without any EPs just for scanning
80+
Zigbee.begin(role);
81+
82+
// Waint until Zigbee stack is ready
83+
while (!Zigbee.isStarted()) {
84+
delay(100);
85+
}
86+
87+
Serial.println("Setup done");
88+
// Start Zigbee Network Scan with default parameters (all channels, scan time 5)
89+
Zigbee.scanNetworks();
90+
}
91+
92+
void loop() {
93+
// check Zigbee Network Scan process
94+
int16_t ZigbeeScanStatus = Zigbee.scanComplete();
95+
if (ZigbeeScanStatus < 0) { // it is busy scanning or got an error
96+
if (ZigbeeScanStatus == ZB_SCAN_FAILED) {
97+
Serial.println("WiFi Scan has failed. Starting again.");
98+
Zigbee.scanNetworks();
99+
}
100+
// other option is status ZB_SCAN_RUNNING - just wait.
101+
} else { // Found Zero or more Wireless Networks
102+
printScannedNetworks(ZigbeeScanStatus);
103+
Zigbee.scanNetworks(); // start over...
104+
}
105+
106+
// Loop can do something else...
107+
delay(500);
108+
Serial.println("Loop running...");
109+
}

libraries/Zigbee/examples/Zigbee_simple/Zigbee_simple.ino

Lines changed: 0 additions & 93 deletions
This file was deleted.

libraries/Zigbee/src/Zigbee_core.cpp

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Zigbee_Core::Zigbee_Core() {
1010
_zb_ep_list = esp_zb_ep_list_create();
1111
_primary_channel_mask = ESP_ZB_TRANSCEIVER_ALL_CHANNELS_MASK;
1212
_open_network = 0;
13+
_scan_status = ZB_SCAN_FAILED;
14+
_started = false;
1315
}
1416
Zigbee_Core::~Zigbee_Core() {}
1517

@@ -91,19 +93,22 @@ bool Zigbee_Core::zigbeeInit(esp_zb_cfg_t *zb_cfg, bool erase_nvs) {
9193
esp_zb_init(zb_cfg);
9294

9395
// Register all Zigbee EPs in list
94-
log_d("Register all Zigbee EPs in list");
95-
err = esp_zb_device_register(_zb_ep_list);
96-
if (err != ESP_OK) {
97-
log_e("Failed to register Zigbee EPs");
98-
return false;
99-
}
100-
101-
//print the list of Zigbee EPs from ep_objects
102-
log_i("List of registered Zigbee EPs:");
103-
for (std::list<Zigbee_EP*>::iterator it = ep_objects.begin(); it != ep_objects.end(); ++it) {
104-
log_i("Device type: %s, Endpoint: %d, Device ID: 0x%04x", getDeviceTypeString((*it)->_device_id), (*it)->_endpoint, (*it)->_device_id);
96+
if(ep_objects.empty()) {
97+
log_w("No Zigbee EPs to register");
98+
} else {
99+
log_d("Register all Zigbee EPs in list");
100+
err = esp_zb_device_register(_zb_ep_list);
101+
if (err != ESP_OK) {
102+
log_e("Failed to register Zigbee EPs");
103+
return false;
104+
}
105+
106+
//print the list of Zigbee EPs from ep_objects
107+
log_i("List of registered Zigbee EPs:");
108+
for (std::list<Zigbee_EP*>::iterator it = ep_objects.begin(); it != ep_objects.end(); ++it) {
109+
log_i("Device type: %s, Endpoint: %d, Device ID: 0x%04x", getDeviceTypeString((*it)->_device_id), (*it)->_endpoint, (*it)->_device_id);
110+
}
105111
}
106-
107112
// Register Zigbee action handler
108113
esp_zb_core_action_handler_register(zb_action_handler);
109114
err = esp_zb_set_primary_network_channel_set(_primary_channel_mask);
@@ -159,7 +164,6 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
159164
//coordinator variables
160165
esp_zb_zdo_signal_device_annce_params_t *dev_annce_params = NULL;
161166

162-
log_d("Zigbee role: %d", Zigbee._role);
163167
//main switch
164168
switch (sig_type) {
165169
case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP: // Common
@@ -183,8 +187,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
183187

184188
} else {
185189
log_i("Device rebooted");
186-
187-
// Implement opening network for joining after reboot if set
190+
Zigbee._started = true;
188191
if ((zigbee_role_t)Zigbee._role == ZIGBEE_COORDINATOR && Zigbee._open_network > 0) {
189192
log_i("Openning network for joining for %d seconds", Zigbee._open_network);
190193
esp_zb_bdb_open_network(Zigbee._open_network);
@@ -213,6 +216,7 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
213216
}
214217
break;
215218
case ESP_ZB_BDB_SIGNAL_STEERING: // Router and End Device
219+
Zigbee._started = true;
216220
if ((zigbee_role_t)Zigbee._role == ZIGBEE_COORDINATOR) {
217221
if (err_status == ESP_OK) {
218222
log_i("Network steering started");
@@ -283,18 +287,56 @@ void Zigbee_Core::factoryReset() {
283287
esp_zb_factory_reset();
284288
}
285289

290+
bool Zigbee_Core::isStarted() {
291+
return _started;
292+
}
293+
294+
void Zigbee_Core::scanCompleteCallback(esp_zb_zdp_status_t zdo_status, uint8_t count, esp_zb_network_descriptor_t *nwk_descriptor){
295+
log_v("Zigbee network scan complete");
296+
if(zdo_status == ESP_ZB_ZDP_STATUS_SUCCESS) {
297+
log_v("Found %d networks", count);
298+
//print Zigbee networks
299+
for (int i = 0; i < count; i++) {
300+
log_v("Network %d: PAN ID: 0x%04hx, Permit Joining: %s, Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, Channel: %d, Router Capacity: %s, End Device Capacity: %s",
301+
i, nwk_descriptor[i].short_pan_id, nwk_descriptor[i].permit_joining ? "Yes" : "No", nwk_descriptor[i].extended_pan_id[7], nwk_descriptor[i].extended_pan_id[6], nwk_descriptor[i].extended_pan_id[5], nwk_descriptor[i].extended_pan_id[4], nwk_descriptor[i].extended_pan_id[3], nwk_descriptor[i].extended_pan_id[2], nwk_descriptor[i].extended_pan_id[1], nwk_descriptor[i].extended_pan_id[0], nwk_descriptor[i].logic_channel, nwk_descriptor[i].router_capacity ? "Yes" : "No", nwk_descriptor[i].end_device_capacity ? "Yes" : "No");
302+
}
303+
//save scan result and update scan status
304+
//copy network descriptor to _scan_result to keep the data after the callback
305+
Zigbee._scan_result = (esp_zb_network_descriptor_t *)malloc(count * sizeof(esp_zb_network_descriptor_t));
306+
memcpy(Zigbee._scan_result, nwk_descriptor, count * sizeof(esp_zb_network_descriptor_t));
307+
Zigbee._scan_status = count;
308+
} else {
309+
log_e("Failed to scan Zigbee network (status: 0x%x)", zdo_status);
310+
Zigbee._scan_status = ZB_SCAN_FAILED;
311+
Zigbee._scan_result = nullptr;
312+
}
313+
}
314+
315+
void Zigbee_Core::scanNetworks(u_int32_t channel_mask, u_int8_t scan_duration) {
316+
if(!_started) {
317+
log_e("Zigbee stack is not started, cannot scan networks");
318+
return;
319+
}
320+
log_v("Scanning Zigbee networks");
321+
esp_zb_zdo_active_scan_request(channel_mask, scan_duration, scanCompleteCallback);
322+
_scan_status = ZB_SCAN_RUNNING;
323+
}
324+
325+
int16_t Zigbee_Core::scanComplete(){
326+
return _scan_status;
327+
}
328+
329+
zigbee_scan_result_t* Zigbee_Core::getScanResult() {
330+
return _scan_result;
331+
}
286332

287-
// TODO: Implement scanning network
288-
// /**
289-
// * @brief Active scan available network.
290-
// *
291-
// * Network discovery service for scanning available network
292-
// *
293-
// * @param[in] channel_mask Valid channel mask is from 0x00000800 (only channel 11) to 0x07FFF800 (all channels from 11 to 26)
294-
// * @param[in] scan_duration Time to spend scanning each channel
295-
// * @param[in] user_cb A user callback to get the active scan result please refer to esp_zb_zdo_scan_complete_callback_t
296-
// */
297-
// void esp_zb_zdo_active_scan_request(uint32_t channel_mask, uint8_t scan_duration, esp_zb_zdo_scan_complete_callback_t user_cb);
333+
void Zigbee_Core::scanDelete() {
334+
if (_scan_result != nullptr) {
335+
free(_scan_result);
336+
_scan_result = nullptr;
337+
}
338+
_scan_status = ZB_SCAN_FAILED;
339+
}
298340

299341
// NOTE: Binding functions to not forget
300342
// void esp_zb_zdo_device_bind_req(esp_zb_zdo_bind_req_param_t *cmd_req, esp_zb_zdo_bind_callback_t user_cb, void *user_ctx)

0 commit comments

Comments
 (0)