espressif / esp-zigbee-sdk

Espressif Zigbee SDK
Apache License 2.0
178 stars 31 forks source link

How to know if the Zigbee coordinator and End device still with the range or the link between them is active (TZ-908) #352

Closed kgkask closed 4 months ago

kgkask commented 6 months ago

Question

how to detect Zigbee signal range & rejoin?

Additional context.

I am new to Zigbee and find it a bit hard to implement all features I am looking to. I am using two ESP32-H2 DevKitM-1 on Arduino IDE to send a string message from coordinator to end device. I can capture the acknowledgement to know if the ED received the message correctly, however when I check the connection range as I go far from the ED the ack slows down (which is expected) and suddenly the connection between the Coordinator and ED terminates.

So I want a way to make the ED rejoin the network once it senses the signal from the Coordinator, and a mechanism like the ack to notify me if there is surrounding Zigbee signal.

I am not sure if it's possible since it shares the 2.4GHz band with a lot of other technologies.

My initial guess is that it can be handled from "_esp_zb_app_signalhandler" in the coordinator side, however I could not achieve it. I managed to detect if the connection dropped by adding the "_ESP_ZB_NLME_STATUSINDICATION" case.

Sorry if the wording of my question is not clear.

Here is a copy of my _esp_zb_app_signalhandler implementation: void esp_zb_app_signal_handler(esp_zb_app_signal_t signal_struct) { uint32_t p_sg_p = signal_struct->p_app_signal; esp_err_t err_status = signal_struct->esp_err_status; esp_zb_app_signal_type_t sig_type = (esp_zb_app_signal_type_t)p_sg_p; esp_zb_zdo_signal_device_annce_params_t dev_annce_params = NULL; // keep it for trubleshotting it might be needed this part is from the original code //esp_zb_app_signal_type_t sig_type = *p_sg_p;

switch (sig_type) { case ESP_ZB_ZDO_SIGNAL_SKIP_STARTUP: log_i("Zigbee stack initialized"); esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_INITIALIZATION); break; case ESP_ZB_BDB_SIGNAL_DEVICE_FIRST_START: case ESP_ZB_BDB_SIGNAL_DEVICE_REBOOT: if (err_status == ESP_OK) { if (esp_zb_bdb_is_factory_new()) { log_i("Start network formation"); esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_FORMATION); } else { log_i("Failed to initialize Zigbee stack (status: %s)", esp_err_to_name(err_status)); } break; case ESP_ZB_BDB_SIGNAL_FORMATION: if (err_status == ESP_OK) { esp_zb_ieee_addr_t extended_pan_id; esp_zb_get_extended_pan_id(extended_pan_id); log_i( "Formed network successfully (Extended PAN ID: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: 0x%04hx, Channel:%d, Short Address: 0x%04hx)", extended_pan_id[7], extended_pan_id[6], extended_pan_id[5], extended_pan_id[4], extended_pan_id[3], extended_pan_id[2], extended_pan_id[1], extended_pan_id[0], esp_zb_get_pan_id(), esp_zb_get_current_channel(), esp_zb_get_short_address() ); neopixelWrite(LED_PIN, 0, 255, 0); // Green --> esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); } else { log_i("Restart network formation (status: %s)", esp_err_to_name(err_status)); esp_zb_scheduler_alarm((esp_zb_callback_t)bdb_start_top_level_commissioning_cb, ESP_ZB_BDB_MODE_NETWORK_FORMATION, 1000); } break; case ESP_ZB_BDB_SIGNAL_STEERING: if (err_status == ESP_OK) { log_i("Network steering started"); neopixelWrite(LED_PIN, 255, 255, 255); // white --> } break; case ESP_ZB_ZDO_SIGNAL_DEVICE_ANNCE: dev_annce_params = (esp_zb_zdo_signal_device_annce_params_t )esp_zb_app_signal_get_params(p_sg_p); log_i("New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->device_short_addr); esp_zb_zdo_match_desc_req_param_t cmd_req; cmd_req.dst_nwk_addr = dev_annce_params->device_short_addr; cmd_req.addr_of_interest = dev_annce_params->device_short_addr; esp_zb_zdo_find_on_off_light(&cmd_req, user_find_cb, NULL); break; case ESP_ZB_NWK_SIGNAL_PERMIT_JOIN_STATUS: if (err_status == ESP_OK) { if ((uint8_t )esp_zb_app_signal_get_params(p_sg_p)) { log_i("Network(0x%04hx) is open for %d seconds", esp_zb_get_pan_id(), (uint8_t )esp_zb_app_signal_get_params(p_sg_p)); } else { log_w("Network(0x%04hx) closed, devices joining not allowed.", esp_zb_get_pan_id()); } } break; case ESP_ZB_NLME_STATUS_INDICATION: log_i("%s, status: 0x%x", esp_zb_zdo_signal_to_string(sig_type), (uint8_t *)esp_zb_app_signal_get_params(p_sg_p)); neopixelWrite(LED_PIN, 255, 0, 0); // white --> break; default: log_i("ZDO signal: %s (0x%x), status: %s", esp_zb_zdo_signal_to_string(sig_type), sig_type, esp_err_to_name(err_status)); if (sig_type == ESP_ZB_NLME_STATUS_INDICATION){ esp_zb_bdb_start_top_level_commissioning(ESP_ZB_BDB_MODE_NETWORK_STEERING); neopixelWrite(LED_PIN, 255, 255, 255); // white --> } break; } } }

xieqinan commented 6 months ago

@kgkask ,

You can use esp_zb_nwk_get_next_neighbor() to get the neighbor information of the current device, but this information may be delayed. Alternatively, you can send a simple command such as esp_zb_zdo_ieee_addr_req() to detect the link state. If the link is not active, the ESP_ZB_NLME_STATUS_INDICATION signal will be triggered.

If the device rejoins the network, it will broadcast a device announcement command, and the ESP_ZB_ZDO_SIGNAL_DEVICE_ANNCE signal will be triggered.

kgkask commented 6 months ago

Thanks for quick answer,

I got it for the esp_zb_zdo_ieee_addr_req() however the I am not quite sure about the implementation for it. but for rejoin the ED does not attend to join the network unless I reset the coordinator.

xieqinan commented 6 months ago

@kgkask

but for rejoin the ED does not attend to join the network unless I reset the coordinator.

Could you please try rejoining multiple times and provide the rejoin failure log for me? By the way, could you also try using the official switch and light example?

kgkask commented 6 months ago

I used the example

@kgkask

but for rejoin the ED does not attend to join the network unless I reset the coordinator.

Could you please try rejoining multiple times and provide the rejoin failure log for me? By the way, could you also try using the official switch and light example?

I have used the example from the library but still, if I went out of the range for a longer period around 3 minutes or so, it does not rejoin the network again. I modified the example to toggle automatically every 2 seconds and moved away from the coordinator until I reach the range where the signal starts getting weak, and from there I tried the time duration. When I get back too quickly to the range of the signal it starts receiving, otherwise, if I spend much time outside, it stops communicating with the coordinator unless I restart it (ED).

Not sure how to record the log, however it shows the warning message for network steering: log_i("Network steering was not successful (status: %s)", esp_err_to_name(err_status));

xieqinan commented 6 months ago

@kgkask ,

The rejoin issue may be triggered by a low LQI value. The stack prevents devices with low LQI from joining the network. The minimum LQI value of joining is set to 32 by default. You can test this by using esp_zb_secur_network_min_join_lqi_set() to set the threshold for device joining.

kgkask commented 6 months ago

Okay thanks I will give it a try.

One thing I notice is the coordinator, if I send the message (by pushing the button), it reconnects to the ED. Maybe what I am looking for is against the operation principle for Zigbee since it's a low power communication protocol, but I want to know the connectivity state continuously and passively without initiating a message myself. I know in a normal case it happens using messages like ping, however, if the protocol already uses that I want to make benefit of it, to have an updated status of the link between the devices.

and really appreciate your contribution and suggestions <3 @xieqinan .

xieqinan commented 5 months ago

@kgkask ,

The esp-zigbee-sdk does not currently provide a ping-like command. If you want to continuously and passively monitor the connectivity state without initiating a message yourself, you can call esp_zb_nwk_get_next_neighbor() to inspect the neighbor table and achieve this purpose.