diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index e2310d951..7ba3f4237 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -760,8 +760,8 @@ // Auto-binding constants, see `Z_autoAttributeReporting` // Below are the threshold for attribute reporting - #define USE_ZIGBEE_AUTOBIND_BATTVOLTAGE 0.1 // V - #define USE_ZIGBEE_AUTOBIND_BATTPERCENT 1 // % + #define USE_ZIGBEE_AUTOBIND_BATTVOLTAGE 0.2 // V + #define USE_ZIGBEE_AUTOBIND_BATTPERCENT 5 // % #define USE_ZIGBEE_AUTOBIND_TEMPERATURE 0.5 // °C #define USE_ZIGBEE_AUTOBIND_HEATDEMAND 10 // % #define USE_ZIGBEE_AUTOBIND_PRESSURE 1 // hPA diff --git a/tasmota/xdrv_23_zigbee_1_headers.ino b/tasmota/xdrv_23_zigbee_1_headers.ino index 27f2dd895..46dc42a57 100644 --- a/tasmota/xdrv_23_zigbee_1_headers.ino +++ b/tasmota/xdrv_23_zigbee_1_headers.ino @@ -105,7 +105,11 @@ public: ZB_RecvMsgFunc recv_func = nullptr; // function to call when message is expected ZB_RecvMsgFunc recv_unexpected = nullptr; // function called when unexpected message is received +#ifdef USE_ZIGBEE_EZSP uint32_t permit_end_time = 0; // timestamp when permit join ends +#elif defined(USE_ZIGBEE_ZNP) + bool permit_end_time = false; // in ZNP mode it's only a boolean +#endif #ifdef USE_ZIGBEE_EZSP Eeprom24C512 eeprom; // takes only 1 bytes of RAM diff --git a/tasmota/xdrv_23_zigbee_2_devices.ino b/tasmota/xdrv_23_zigbee_2_devices.ino index 47247ddd5..3f7f916e0 100644 --- a/tasmota/xdrv_23_zigbee_2_devices.ino +++ b/tasmota/xdrv_23_zigbee_2_devices.ino @@ -965,6 +965,7 @@ public: Z_Device & devicesAt(size_t i) const; // Remove device from list + void clearDeviceRouterInfo(void); // reset all router flags, done just before ZbMap bool removeDevice(uint16_t shortaddr); // Mark data as 'dirty' and requiring to save in Flash diff --git a/tasmota/xdrv_23_zigbee_2a_devices_impl.ino b/tasmota/xdrv_23_zigbee_2a_devices_impl.ino index 55a98a748..b70a7edda 100644 --- a/tasmota/xdrv_23_zigbee_2a_devices_impl.ino +++ b/tasmota/xdrv_23_zigbee_2a_devices_impl.ino @@ -218,6 +218,15 @@ Z_Device & Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) { return device_unk; } +// Clear the router flag for each device, called at the beginning of ZbMap +void Z_Devices::clearDeviceRouterInfo(void) { + for (Z_Device & device : zigbee_devices._devices) { + if (device.valid()) { + device.setRouter(false); + } + } +} + // // Clear all endpoints // diff --git a/tasmota/xdrv_23_zigbee_7_5_map.ino b/tasmota/xdrv_23_zigbee_7_5_map.ino index c9013b665..f6a50e974 100644 --- a/tasmota/xdrv_23_zigbee_7_5_map.ino +++ b/tasmota/xdrv_23_zigbee_7_5_map.ino @@ -76,7 +76,7 @@ public: edges() {} - void reset(void) { edges.reset(); } + void reset(void) { edges.reset(); zigbee_devices.clearDeviceRouterInfo(); } Z_Mapper_Edge & findEdge(const Z_Mapper_Edge & edge2); bool addEdge(const Z_Mapper_Edge & edge2); diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index c85b1a7f0..3c3bf1e89 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -501,12 +501,15 @@ int32_t ZNP_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) { if (0xFF == duration) { status_code = ZIGBEE_STATUS_PERMITJOIN_OPEN_XX; message = PSTR("Enable Pairing mode until next boot"); + zigbee.permit_end_time = true; // In ZNP mode, declare permitjoin open } else if (duration > 0) { status_code = ZIGBEE_STATUS_PERMITJOIN_OPEN_60; message = PSTR("Enable Pairing mode for %d seconds"); + zigbee.permit_end_time = true; // In ZNP mode, declare permitjoin open } else { status_code = ZIGBEE_STATUS_PERMITJOIN_CLOSE; message = PSTR("Disable Pairing mode"); + zigbee.permit_end_time = false; // In ZNP mode, declare permitjoin closed } Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" "\"Status\":%d,\"Message\":\""), @@ -884,6 +887,14 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) { uint8_t capabilities = buf.get8(10); #endif + // record if we already knew the ieeeAddr for this device + // this will influence the decision whether we do auto-binding or not + const Z_Device & device_before = zigbee_devices.findShortAddr(nwkAddr); + bool ieee_already_known = false; + if (device_before.valid() && (device_before.longaddr != 0) && (device_before.longaddr == ieeeAddr)) { + ieee_already_known = true; + } + zigbee_devices.updateDevice(nwkAddr, ieeeAddr); // device is reachable zigbee_devices.deviceWasReached(nwkAddr); @@ -903,7 +914,10 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) { Z_Query_Bulb(nwkAddr, wait_ms); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - Z_SendActiveEpReq(nwkAddr); + // Continue the discovery process and auto-binding only if the device was unknown or if PermitJoin is ongoing + if (!ieee_already_known || zigbee.permit_end_time) { + Z_SendActiveEpReq(nwkAddr); + } return -1; }