diff --git a/code/nrf-connect/samples/zigbee/Kconfig b/code/nrf-connect/samples/zigbee/Kconfig index 1092ced..6fbb42a 100644 --- a/code/nrf-connect/samples/zigbee/Kconfig +++ b/code/nrf-connect/samples/zigbee/Kconfig @@ -7,7 +7,7 @@ config PRST_ZB_SLEEP_DURATION_SEC config PRST_ZB_PARENT_POLL_INTERVAL_SEC int "Interval for when b-parasite polls its parent for data in seconds." - default 60 + default 10 config PRST_ZB_BUILD_DATE string "Zigbee basic cluster build date attribute. Max 16 bytes." @@ -34,6 +34,9 @@ config PRST_ZB_FACTORY_RESET_VIA_RESET_PIN config PRST_ZB_FACTORY_RESET_VIA_SW1 bool "Resetting while pressing and holding SW1 for 5 seconds will factory reset the device. Only available on v2.0.0+ hardware revisions." +config PRST_ZB_FACTORY_RESET_DISABLED + bool "No factory reset procedure." + endchoice # PRST_ZB_FACTORY_RESET_METHOD config PRST_ZB_RESTART_WATCHDOG_TIMEOUT_SEC diff --git a/code/nrf-connect/samples/zigbee/prj.conf b/code/nrf-connect/samples/zigbee/prj.conf index e5d8f1b..5583e41 100644 --- a/code/nrf-connect/samples/zigbee/prj.conf +++ b/code/nrf-connect/samples/zigbee/prj.conf @@ -8,9 +8,6 @@ CONFIG_GPIO=y CONFIG_USE_SEGGER_RTT=y CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096 -CONFIG_PM=y -CONFIG_PM_DEVICE=y - CONFIG_NEWLIB_LIBC=y CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y @@ -39,8 +36,17 @@ CONFIG_NET_IPV6_RA_RDNSS=n CONFIG_NET_IP_ADDR_CHECK=n CONFIG_NET_UDP=n +## +## ZigBee Channel Selection +## # Get Zigbee to scan every channel. CONFIG_ZIGBEE_CHANNEL_SELECTION_MODE_MULTI=y +# By default only scans channel 11 (ZigBee2MQTT default) and 15 (ZHA default). +# Comment to scan all channels - this will make pairing consume more energy. +# CONFIG_ZIGBEE_CHANNEL_MASK=0x8800 + +# Uncomment to set a specific channel - this will make pairing more energy efficient. +# CONFIG_ZIGBEE_CHANNEL=11 # Enable API for powering down unused RAM parts. # https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.7.1/nrf/ug_zigbee_configuring.html#power-saving-during-sleep diff --git a/code/nrf-connect/samples/zigbee/src/debug_counters.c b/code/nrf-connect/samples/zigbee/src/debug_counters.c index ede174c..72f006a 100644 --- a/code/nrf-connect/samples/zigbee/src/debug_counters.c +++ b/code/nrf-connect/samples/zigbee/src/debug_counters.c @@ -65,6 +65,7 @@ int prst_debug_counters_increment(const char* counter_name) { if (written != sizeof(value)) { LOG_ERR("fs_write returned %d, expected %d", written, sizeof(value)); } + RET_IF_ERR(fs_sync(&file)); return fs_close(&file); } diff --git a/code/nrf-connect/samples/zigbee/src/factory_reset.c b/code/nrf-connect/samples/zigbee/src/factory_reset.c index 7ada82b..3495799 100644 --- a/code/nrf-connect/samples/zigbee/src/factory_reset.c +++ b/code/nrf-connect/samples/zigbee/src/factory_reset.c @@ -66,6 +66,10 @@ int prst_zb_factory_reset_check() { LOG_DBG("SW1 pressed. Scheduling timer"); k_timer_start(&sw1_factory_reset_check_timer, K_SECONDS(5), K_NO_WAIT); } -#endif return 0; +#elif CONFIG_PRST_ZB_FACTORY_RESET_DISABLED + return 0; +#else +#error "No factory reset method selected -- explicitly select CONFIG_PRST_ZB_FACTORY_RESET_DISABLED=y to disable it" +#endif // CONFIG_PRST_ZB_FACTORY_RESET_VIA_RESET_PIN } \ No newline at end of file diff --git a/code/nrf-connect/samples/zigbee/src/main.c b/code/nrf-connect/samples/zigbee/src/main.c index b1c1c42..20cbe9f 100644 --- a/code/nrf-connect/samples/zigbee/src/main.c +++ b/code/nrf-connect/samples/zigbee/src/main.c @@ -122,87 +122,26 @@ void identify_cb(zb_bufid_t bufid) { prst_led_flash(15); } -void zboss_signal_handler(zb_bufid_t bufid) { - // See zigbee_default_signal_handler() for all available signals. - zb_zdo_app_signal_hdr_t *sig_hndler = NULL; - zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, /*sg_p=*/&sig_hndler); - zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid); - switch (sig) { - case ZB_BDB_SIGNAL_STEERING: // New network. - case ZB_BDB_SIGNAL_DEVICE_REBOOT: { // Previously joined network. - LOG_DBG("Steering complete. Status: %d", status); - if (status == RET_OK) { - LOG_DBG("Steering successful. Status: %d", status); - prst_debug_counters_increment("steering_success"); - prst_led_flash(/*times=*/3); - k_timer_stop(&led_flashing_timer); - prst_restart_watchdog_stop(); - prst_led_off(); - } else { - LOG_DBG("Steering failed. Status: %d", status); - prst_debug_counters_increment("steering_failure"); - prst_led_flash(/*times=*/7); - prst_restart_watchdog_start(); - k_timer_stop(&led_flashing_timer); // Power saving - prst_led_off(); - } - } - case ZB_BDB_SIGNAL_DEVICE_FIRST_START: - joining_signal_received = true; - break; - case ZB_ZDO_SIGNAL_LEAVE: - if (status == RET_OK) { - k_timer_start(&led_flashing_timer, K_NO_WAIT, K_SECONDS(1)); - zb_zdo_signal_leave_params_t *leave_params = ZB_ZDO_SIGNAL_GET_PARAMS(sig_hndler, zb_zdo_signal_leave_params_t); - LOG_INF("Network left (leave type: %d)", leave_params->leave_type); - - /* Set joining_signal_received to false so broken rejoin procedure can be detected correctly. */ - if (leave_params->leave_type == ZB_NWK_LEAVE_TYPE_REJOIN) { - joining_signal_received = false; - } - } - case ZB_ZDO_SIGNAL_SKIP_STARTUP: { - stack_initialised = true; - LOG_DBG("Started zigbee stack and waiting for connection to network."); - k_timer_start(&led_flashing_timer, K_NO_WAIT, K_SECONDS(1)); - break; - } - case ZB_NLME_STATUS_INDICATION: { - zb_zdo_signal_nlme_status_indication_params_t *nlme_status_ind = - ZB_ZDO_SIGNAL_GET_PARAMS(sig_hndler, zb_zdo_signal_nlme_status_indication_params_t); - if (nlme_status_ind->nlme_status.status == ZB_NWK_COMMAND_STATUS_PARENT_LINK_FAILURE) { - /* Check for broken rejoin procedure and restart the device to recover. - This implements Nordic's suggested workaround for errata KRKNWK-12017, which effects - the recent nRF Connect SDK (v1.8.0 - v2.3.0 at time of writing). - For details see: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/known_issues.html?v=v2-3-0 - */ - if (stack_initialised && !joining_signal_received) { - prst_debug_counters_increment("krknwk_12017_reset"); - zb_reset(0); - } - } - break; - } - } - - ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid)); - if (bufid) { - zb_buf_free(bufid); - } -} - void update_sensors_cb(zb_uint8_t arg) { - LOG_INF("Updating sensors"); + LOG_DBG("Updating sensors"); - ZB_SCHEDULE_APP_ALARM(update_sensors_cb, - /*param=*/0, - ZB_TIME_ONE_SECOND * CONFIG_PRST_ZB_SLEEP_DURATION_SEC); + // Reschedule the same callback. + zb_ret_t ret = ZB_SCHEDULE_APP_ALARM( + update_sensors_cb, + /*param=*/0, + ZB_MILLISECONDS_TO_BEACON_INTERVAL(1000 * CONFIG_PRST_ZB_SLEEP_DURATION_SEC)); + if (ret != RET_OK) { + prst_debug_counters_increment("sens_cb_schedule_err"); + zb_reset(0); + } + prst_debug_counters_increment("sensors_read_before"); if (prst_sensors_read_all(&sensors)) { prst_debug_counters_increment("sensors_read_error"); LOG_ERR("Unable to read sensors"); return; } + prst_debug_counters_increment("sensors_read_after"); // Battery voltage in units of 100 mV. uint8_t batt_voltage = sensors.batt.adc_read.millivolts / 100; @@ -241,6 +180,81 @@ void update_sensors_cb(zb_uint8_t arg) { &log_lux); } +void zboss_signal_handler(zb_bufid_t bufid) { + // See zigbee_default_signal_handler() for all available signals. + zb_zdo_app_signal_hdr_t *sig_hndler = NULL; + zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, /*sg_p=*/&sig_hndler); + zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid); + switch (sig) { + case ZB_BDB_SIGNAL_STEERING: // New network. + case ZB_BDB_SIGNAL_DEVICE_REBOOT: { // Previously joined network. + LOG_DBG("Steering complete. Status: %d", status); + if (status == RET_OK) { + LOG_DBG("Steering successful. Status: %d", status); + k_timer_stop(&led_flashing_timer); + prst_led_off(); + prst_restart_watchdog_stop(); + // Update the long polling parent interval - needs to be done after joining. + zb_zdo_pim_set_long_poll_interval(1000 * CONFIG_PRST_ZB_PARENT_POLL_INTERVAL_SEC); + } else { + LOG_DBG("Steering failed. Status: %d", status); + prst_restart_watchdog_start(); + // Power saving. + k_timer_stop(&led_flashing_timer); + prst_led_off(); + } + joining_signal_received = true; + break; + } + case ZB_BDB_SIGNAL_DEVICE_FIRST_START: + joining_signal_received = true; + break; + case ZB_ZDO_SIGNAL_LEAVE: + if (status == RET_OK) { + k_timer_start(&led_flashing_timer, K_NO_WAIT, K_SECONDS(1)); + zb_zdo_signal_leave_params_t *leave_params = ZB_ZDO_SIGNAL_GET_PARAMS(sig_hndler, zb_zdo_signal_leave_params_t); + LOG_DBG("Network left (leave type: %d)", leave_params->leave_type); + + /* Set joining_signal_received to false so broken rejoin procedure can be detected correctly. */ + if (leave_params->leave_type == ZB_NWK_LEAVE_TYPE_REJOIN) { + joining_signal_received = false; + } + } + break; + case ZB_ZDO_SIGNAL_SKIP_STARTUP: { + stack_initialised = true; + LOG_DBG("Started zigbee stack and waiting for connection to network."); + k_timer_start(&led_flashing_timer, K_NO_WAIT, K_SECONDS(1)); + + // Kick off main sensor update task. + ZB_SCHEDULE_APP_ALARM(update_sensors_cb, + /*param=*/0, + ZB_MILLISECONDS_TO_BEACON_INTERVAL(1000)); + break; + } + case ZB_NLME_STATUS_INDICATION: { + zb_zdo_signal_nlme_status_indication_params_t *nlme_status_ind = + ZB_ZDO_SIGNAL_GET_PARAMS(sig_hndler, zb_zdo_signal_nlme_status_indication_params_t); + if (nlme_status_ind->nlme_status.status == ZB_NWK_COMMAND_STATUS_PARENT_LINK_FAILURE) { + /* Check for broken rejoin procedure and restart the device to recover. + This implements Nordic's suggested workaround for errata KRKNWK-12017, which effects + the recent nRF Connect SDK (v1.8.0 - v2.3.0 at time of writing). + For details see: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/known_issues.html?v=v2-3-0 + */ + if (stack_initialised && !joining_signal_received) { + zb_reset(0); + } + } + break; + } + } + + ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid)); + if (bufid) { + zb_buf_free(bufid); + } +} + void log_counter(const char *counter_name, prst_debug_counter_t value) { LOG_INF("- %s: %d", counter_name, value); } @@ -252,6 +266,9 @@ int main(void) { RET_IF_ERR(prst_flash_fs_init()); RET_IF_ERR(prst_debug_counters_init()); + // Initialize sensors - quickly put them into low power mode. + RET_IF_ERR(prst_sensors_read_all(&sensors)); + prst_debug_counters_increment("boot"); LOG_INF("Dumping debug counters:"); @@ -263,19 +280,14 @@ int main(void) { ZB_AF_REGISTER_DEVICE_CTX(&app_template_ctx); - update_sensors_cb(/*arg=*/0); - - zb_zdo_pim_set_long_poll_interval( - ZB_TIME_ONE_SECOND * CONFIG_PRST_ZB_PARENT_POLL_INTERVAL_SEC); - power_down_unused_ram(); - RET_IF_ERR(prst_led_flash(2)); k_msleep(100); ZB_AF_SET_IDENTIFY_NOTIFICATION_HANDLER(PRST_ZIGBEE_ENDPOINT, identify_cb); - zigbee_enable(); zigbee_configure_sleepy_behavior(/*enable=*/true); + power_down_unused_ram(); + zigbee_enable(); prst_debug_counters_increment("main_finish");