diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fea8d1ff..a4d6d1e47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ All notable changes to this project will be documented in this file. - ESP32 platform update from 2024.07.11 to 2024.08.10 (#21893) - ESP32 Framework (Arduino Core) from v3.0.2 to v3.0.4 (#21893) - Refactored Analog driver to better support multiple channels +- Zigbee loads device data early before MCU startup ### Fixed - Berry `light.get` for separate RGB/CT (#21818) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1_headers.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1_headers.ino index a28afeae1..77c993a87 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1_headers.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1_headers.ino @@ -69,7 +69,7 @@ public: #endif // USE_ZIGBEE_EEPROM {} - bool active = true; // is Zigbee active for this device, i.e. GPIOs configured + bool active = false; // is Zigbee active for this device, i.e. GPIOs configured bool state_machine = false; // the state machine is running bool state_waiting = false; // the state machine is waiting for external event or timeout bool state_no_timeout = false; // the current wait loop does not generate a timeout but only continues running diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_0_statemachine.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_0_statemachine.ino index 204dc9406..bffd6d1c8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_0_statemachine.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_0_statemachine.ino @@ -425,7 +425,27 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT) ZI_ON_RECV_UNEXPECTED(&ZNP_Recv_Default) + + ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "Loading Zigbee data") + ZI_CALL(&Z_Prepare_Storage, 0) + ZI_CALL(&Z_Load_Devices, 0) + ZI_CALL(&Z_Load_Data, 0) + ZI_CALL(&Z_Set_Save_Data_Timer, 0) + ZI_CALL(&Z_ZbAutoload, 0) +#ifndef USE_ZIGBEE_DEBUG ZI_WAIT(15500) // wait for 15 seconds for Tasmota to stabilize +#else + ZI_WAIT(30000) // wait for cumulated 5 minutes + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) +#endif //ZI_MQTT_STATE(ZIGBEE_STATUS_BOOT, "Booting") ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "rebooting ZNP device") @@ -532,11 +552,6 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { // Correctly configured and running, enable all Tasmota features // ====================================================================== ZI_LABEL(ZIGBEE_LABEL_READY) - ZI_CALL(&Z_Prepare_Storage, 0) - ZI_CALL(&Z_Load_Devices, 0) - ZI_CALL(&Z_Load_Data, 0) - ZI_CALL(&Z_Set_Save_Data_Timer, 0) - ZI_CALL(&Z_ZbAutoload, 0) ZI_MQTT_STATE(ZIGBEE_STATUS_OK, kStarted) ZI_LOG(LOG_LEVEL_INFO, kZigbeeStarted) ZI_CALL(&Z_State_Ready, 1) // Now accept incoming messages @@ -881,7 +896,27 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT) ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT) ZI_ON_RECV_UNEXPECTED(&EZ_Recv_Default) + + ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "Loading Zigbee data") + ZI_CALL(&Z_Prepare_Storage, 0) + ZI_CALL(&Z_Load_Devices, 0) + ZI_CALL(&Z_Load_Data, 0) + ZI_CALL(&Z_Set_Save_Data_Timer, 0) + ZI_CALL(&Z_ZbAutoload, 0) +#ifndef USE_ZIGBEE_DEBUG ZI_WAIT(15500) // wait for 15 seconds for Tasmota to stabilize +#else + ZI_WAIT(30000) // wait for cumulated 5 minutes + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) + ZI_WAIT(30000) +#endif // Hardware reset ZI_LOG(LOG_LEVEL_INFO, kResettingDevice) // Log Debug: resetting EZSP device @@ -978,12 +1013,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_LOG(LOG_LEVEL_INFO, kZigbeeGroup0) ZI_SEND(ZBS_SET_MCAST_ENTRY) ZI_WAIT_RECV(2500, ZBR_SET_MCAST_ENTRY) - // ZI_LABEL(ZIGBEE_LABEL_READY) - ZI_CALL(&Z_Prepare_Storage, 0) - ZI_CALL(&Z_Load_Devices, 0) - ZI_CALL(&Z_Load_Data, 0) - ZI_CALL(&Z_Set_Save_Data_Timer, 0) - ZI_CALL(&Z_ZbAutoload, 0) + ZI_LABEL(ZIGBEE_LABEL_READY) ZI_MQTT_STATE(ZIGBEE_STATUS_OK, kStarted) ZI_LOG(LOG_LEVEL_INFO, kZigbeeStarted) ZI_CALL(&Z_State_Ready, 1) // Now accept incoming messages @@ -1088,6 +1118,7 @@ void ZigbeeStateMachine_Run(void) { } if (zigbee.pc < 0) { zigbee.state_machine = false; + zigbee.active = false; return; } @@ -1133,6 +1164,7 @@ void ZigbeeStateMachine_Run(void) { zigbee.state_machine = false; if (cur_d8) { AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Stopping (%d)"), cur_d8); + zigbee.active = false; } break; case ZGB_INSTR_CALL: diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino index 040a59d1a..c19edc77b 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino @@ -1172,8 +1172,6 @@ void CmndZbName(void) { // // Where can be: short_addr, long_addr, device_index, friendly_name - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - // check if parameters contain a comma ',' char *p = XdrvMailbox.data; char *device_id = strsep(&p, ","); // zigbee identifier @@ -1214,8 +1212,6 @@ void CmndZbModelId(void) { // // Where can be: short_addr, long_addr, device_index, friendly_name - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - // check if parameters contain a comma ',' char *p; strtok_r(XdrvMailbox.data, ",", &p); @@ -1241,8 +1237,6 @@ void CmndZbLight(void) { // // Where can be: short_addr, long_addr, device_index, friendly_name - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - // check if parameters contain a comma ',' char *p = XdrvMailbox.data; char *device_id = strsep(&p, ","); // zigbee identifier @@ -1287,8 +1281,6 @@ void CmndZbOccupancy(void) { // 0x8 = 120 s // Where can be: short_addr, long_addr, device_index, friendly_name - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - // check if parameters contain a comma ',' char *p; strtok_r(XdrvMailbox.data, ",", &p); @@ -1320,7 +1312,6 @@ void CmndZbOccupancy(void) { // Remove an old Zigbee device from the list of known devices, use ZigbeeStatus to know all registered devices // void CmndZbForget(void) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); // in case of short_addr, it must be already registered if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } @@ -1342,7 +1333,6 @@ void CmndZbInfo_inner(const Z_Device & device) { device.jsonPublishAttrList(PSTR(D_JSON_ZIGBEE_INFO), attr_list); // publish as ZbReceived } void CmndZbInfo(void) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } TrimSpace(XdrvMailbox.data); if (strlen(XdrvMailbox.data) == 0) { @@ -1369,7 +1359,6 @@ void CmndZbInfo(void) { // Save Zigbee information to flash // void CmndZbSave(void) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } switch (XdrvMailbox.payload) { case 2: // save only data hibernateAllData(); @@ -1578,7 +1567,6 @@ void CmndZbEmulation(void) { // ZbRestore [{"Device":"0x5ADF","Name":"Petite_Lampe","IEEEAddr":"0x90FD9FFFFE03B051","ModelId":"TRADFRI bulb E27 WS opal 980lm","Manufacturer":"IKEA of Sweden","Endpoints":["0x01","0xF2"]}] // ZbRestore {"Device":"0x5ADF","Name":"Petite_Lampe","IEEEAddr":"0x90FD9FFFFE03B051","ModelId":"TRADFRI bulb E27 WS opal 980lm","Manufacturer":"IKEA of Sweden","Endpoints":["0x01","0xF2"]} void CmndZbRestore(void) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } TrimSpace(XdrvMailbox.data); if (strlen(XdrvMailbox.data) == 0) { @@ -1795,34 +1783,31 @@ void ZigbeePermitJoinUpdate(void) { // 1.b. `ZbStatus Room` - Show single device shortaddr and name `{"ZbStatus1":[{"Device":"0x868E","Name":"Room"}]}` // 2. `ZbStatus2 Room` - Show detailed information of device `{"ZbStatus2":[{"Device":"0x868E","Name":"Room","IEEEAddr":"0x90FD9FFFFE03B051","ModelId":"TRADFRI bulb E27 WS opal 980lm","Manufacturer":"IKEA of Sweden","Endpoints":[1,242],"Config":["L01.2","O01"]}]}` void CmndZbStatus(void) { - if (ZigbeeSerial) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } - String dump; + TrimSpace(XdrvMailbox.data); + String dump; - if (0 == XdrvMailbox.index) { // Case 0 - dump = zigbee_devices.dumpCoordinator(); + if (0 == XdrvMailbox.index) { // Case 0 + dump = zigbee_devices.dumpCoordinator(); + } else { + Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); + if (XdrvMailbox.data_len > 0) { + if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } + // case 1.b and 2. + dump = zigbee_devices.dumpDevice(XdrvMailbox.index, device); } else { - Z_Device & device = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload); - if (XdrvMailbox.data_len > 0) { - if (!device.valid()) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } - // case 1.b and 2. - dump = zigbee_devices.dumpDevice(XdrvMailbox.index, device); - } else { - if (XdrvMailbox.index >= 2) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } - // case 1.a - dump = zigbee_devices.dumpDevice(XdrvMailbox.index, device_unk); - } + if (XdrvMailbox.index >= 2) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; } + // case 1.a + dump = zigbee_devices.dumpDevice(XdrvMailbox.index, device_unk); } - - Response_P(PSTR("{\"%s%d\":%s}"), XdrvMailbox.command, XdrvMailbox.index, dump.c_str()); } + + Response_P(PSTR("{\"%s%d\":%s}"), XdrvMailbox.command, XdrvMailbox.index, dump.c_str()); } // // Command `ZbData` // void CmndZbData(void) { - if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } TrimSpace(XdrvMailbox.data); if (strlen(XdrvMailbox.data) == 0) { @@ -1867,7 +1852,6 @@ void CmndZbConfig(void) { uint64_t zb_precfgkey_h = Settings->zb_precfgkey_h; int8_t zb_txradio_dbm = Settings->zb_txradio_dbm; - // if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } TrimSpace(XdrvMailbox.data); if (strlen(XdrvMailbox.data) > 0) { JsonParser parser(XdrvMailbox.data); @@ -2224,10 +2208,10 @@ void ZigbeeShow(bool json) if (json) { return; #ifdef USE_WEBSERVER - } else { + } else { UnishoxStrings msg(ZB_WEB); uint32_t zigbee_num = zigbee_devices.devicesSize(); - if (zigbee_num > 0) { + if ((zigbee_num > 0) && (!zigbee.init_phase)) { // don't displays devices on UI if still in initialization phase if (zigbee_num > 255) { zigbee_num = 255; } WSContentSend_P(msg[ZB_WEB_CSS], WebColor(COL_TEXT)); @@ -2426,7 +2410,7 @@ void ZigbeeShow(bool json) zigbee.major_rel, zigbee.minor_rel, zigbee.maint_rel, zigbee.revision); WSContentSend_P(HTTP_BTN_ZB_BUTTONS); - } else if (zigbee.state_machine) { // show buttons only if the state machine is still running. If not running anymore, it means aborted + } else { uint32_t grey = WebColor(COL_FORM); WSContentSend_P(HTTP_BTN_ZB_BUTTONS_DISABLED, grey, grey); } @@ -2485,6 +2469,9 @@ bool Xdrv23(uint32_t function) { if (TasmotaGlobal.gpio_optiona.enable_ccloader) { return false; } bool result = false; + if (!zigbee.active && (FUNC_PRE_INIT == function)) { + ZigbeeInit(); + } if (zigbee.active) { switch (function) { @@ -2521,9 +2508,6 @@ bool Xdrv23(uint32_t function) { WebServer_on(PSTR("/zbr"), ZigbeeMapRefresh, HTTP_GET); // add web handler for Zigbee map refresh break; #endif // USE_WEBSERVER - case FUNC_PRE_INIT: - ZigbeeInit(); - break; case FUNC_COMMAND: result = DecodeCommand(kZbCommands, ZigbeeCommand, kZbSynonyms); break; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_zigbee.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_zigbee.ino index e2c9d3fb8..b7d95d7c3 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_zigbee.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_zigbee.ino @@ -83,7 +83,7 @@ extern "C" { int zc_started(struct bvm *vm) { // return `nil` if `zigbee.active` is false (i.e. no GPIO configured) // or aborted, `zigbee.init_phase` is `true` but `zigbee.state_machine` is `false` - if (!zigbee.active || (!zigbee.state_machine && zigbee.init_phase)) { + if (!zigbee.active) { be_return_nil(vm); } be_pushbool(vm, !zigbee.init_phase); @@ -117,7 +117,7 @@ extern "C" { // implement item() and find() int zc_item_or_find(struct bvm *vm, bbool raise_if_unknown) { int32_t top = be_top(vm); // Get the number of arguments - if (zigbee.init_phase) { + if (!zigbee.active) { be_raise(vm, "internal_error", "zigbee not started"); } if (top >= 2 && (be_isint(vm, 2) || be_isstring(vm, 2))) { @@ -189,7 +189,7 @@ extern "C" { int zc_iter(bvm *vm); int zc_iter(bvm *vm) { - if (zigbee.init_phase) { + if (!zigbee.active) { be_raise(vm, "internal_error", "zigbee not started"); } be_pushntvclosure(vm, zc_iter_closure, 1);