Zigbee debounce duplicate commands (#10477)

* Zigbee debounce duplicate commands received from the same device within ``USE_ZIGBEE_DEBOUNCE_COMMANDS`` milliseconds

* Zigbee debounce duplicate commands received from the same device within ``USE_ZIGBEE_DEBOUNCE_COMMANDS`` milliseconds

Co-authored-by: Stephan Hadinger <stephan.hadinger@gmail.com>
This commit is contained in:
s-hadinger 2021-01-09 17:58:57 +01:00 committed by GitHub
parent 4217880946
commit 6a6454d8ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 7 deletions

View File

@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
- Support for time proportioned (``#define USE_TIMEPROP``) and optional PID (``#define USE_PID``) relay control (#10412)
- Support rotary encoder on Shelly Dimmer (#10407)
- Command ``SetOption43 1..100`` to control Rotary step (#10407)
- Zigbee debounce duplicate commands received from the same device within ``USE_ZIGBEE_DEBOUNCE_COMMANDS`` milliseconds
### Breaking Changed
- ESP32 switch from default SPIFFS to default LittleFS file system loosing current (zigbee) files

View File

@ -746,6 +746,7 @@
#define USE_ZIGBEE_TXRADIO_DBM 20 // Tx Radio power in dBm (only for EZSP, EFR32 can go up to 20 dBm)
#define USE_ZIGBEE_COALESCE_ATTR_TIMER 350 // timer to coalesce attribute values (in ms)
#define USE_ZIGBEE_DEBOUNCE_COMMANDS 200 // if commands are received from the same device/endpoint with same ZCL transaction number, discard packet in this time window (ms)
#define USE_ZIGBEE_MODELID "Tasmota Z2T" // reported "ModelId" (cluster 0000 / attribute 0005)
#define USE_ZIGBEE_MANUFACTURER "Tasmota" // reported "Manufacturer" (cluster 0000 / attribute 0004)
#define USE_ZBBRIDGE_TLS // TLS support for zbbridge

View File

@ -730,6 +730,11 @@ public:
uint8_t lqi; // lqi from last message, 0xFF means unknown
uint8_t batterypercent; // battery percentage (0..100), 0xFF means unknwon
uint16_t reserved_for_alignment;
// Debounce informmation when receiving commands
// If we receive the same ZCL transaction number from the same device and the same endpoint within 300ms
// then discard the second packet
uint8_t debounce_endpoint; // endpoint of the last received packet, or 0 if not active (expired)
uint8_t debounce_transact; // ZCL transaction number of the last packet
// END OF DEVICE WIDE DATA
// Constructor with all defaults
@ -750,7 +755,9 @@ public:
last_seen(0),
lqi(0xFF),
batterypercent(0xFF),
reserved_for_alignment(0xFFFF)
reserved_for_alignment(0xFFFF),
debounce_endpoint(0),
debounce_transact(0)
{ };
inline bool valid(void) const { return BAD_SHORTADDR != shortaddr; } // is the device known, valid and found?
@ -847,6 +854,7 @@ typedef enum Z_Def_Category {
Z_CAT_BIND, // send auto-binding to coordinator
Z_CAT_CONFIG_ATTR, // send a config attribute reporting request
Z_CAT_READ_ATTRIBUTE, // read a single attribute
Z_CAT_DEBOUNCE_CMD, // debounce incoming commands
Z_CAT_CIE_ATTRIBUTE, // write CIE address
Z_CAT_CIE_ENROLL, // enroll CIE zone
} Z_Def_Category;

View File

@ -1606,14 +1606,34 @@ void ZCLFrame::parseResponse(void) {
parseResponse_inner(cmd, true, status);
}
/*********************************************************************************************\
* Callbacks
\*********************************************************************************************/
// Reset the debounce marker
void Z_ResetDebounce(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uint8_t endpoint, uint32_t value) {
zigbee_devices.getShortAddr(shortaddr).debounce_endpoint = 0;
}
// Parse non-normalized attributes
void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) {
convertClusterSpecific(attr_list, _cluster_id, _cmd_id, _frame_control.b.direction, _srcaddr, _srcendpoint, _payload);
if (!Settings.flag5.zb_disable_autoquery) {
// read attributes unless disabled
if (!_frame_control.b.direction) { // only handle server->client (i.e. device->coordinator)
if (_wasbroadcast) { // only update for broadcast messages since we don't see unicast from device to device and we wouldn't know the target
sendHueUpdate(BAD_SHORTADDR, _groupaddr, _cluster_id);
// Check if debounce is active and if the packet is a duplicate
Z_Device & device = zigbee_devices.getShortAddr(_srcaddr);
if ((device.debounce_endpoint != 0) && (device.debounce_endpoint == _srcendpoint) && (device.debounce_transact == _transact_seq)) {
// this is a duplicate, drop the packet
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "Discarding duplicate command from 0x%04X, endpoint %d"), _srcaddr, _srcendpoint);
} else {
// reset the duplicate marker, parse the packet normally, and set a timer to reset the marker later (which will discard any existing timer for the same device/endpoint)
device.debounce_endpoint = _srcendpoint;
device.debounce_transact = _transact_seq;
zigbee_devices.setTimer(_srcaddr, 0 /* groupaddr */, USE_ZIGBEE_DEBOUNCE_COMMANDS, 0 /*clusterid*/, _srcendpoint, Z_CAT_DEBOUNCE_CMD, 0, &Z_ResetDebounce);
convertClusterSpecific(attr_list, _cluster_id, _cmd_id, _frame_control.b.direction, _srcaddr, _srcendpoint, _payload);
if (!Settings.flag5.zb_disable_autoquery) {
// read attributes unless disabled
if (!_frame_control.b.direction) { // only handle server->client (i.e. device->coordinator)
if (_wasbroadcast) { // only update for broadcast messages since we don't see unicast from device to device and we wouldn't know the target
sendHueUpdate(BAD_SHORTADDR, _groupaddr, _cluster_id);
}
}
}
}