diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eef9439f..9d2890919 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to this project will be documented in this file. - IRremoteESP8266 library from v2.8.2 to v2.8.3 - Tasmota Core32 from 2.0.4.1 to 2.0.5 - IRremoteESP8266 library from v2.8.3 to v2.8.4 +- Zigbee report unprocessed attributes ### Fixed diff --git a/lib/libesp32/berry_tasmota/src/embedded/zigbee_zcl_attribute.be b/lib/libesp32/berry_tasmota/src/embedded/zigbee_zcl_attribute.be index 16325d176..e58c463d9 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/zigbee_zcl_attribute.be +++ b/lib/libesp32/berry_tasmota/src/embedded/zigbee_zcl_attribute.be @@ -34,8 +34,9 @@ class zcl_attribute : zcl_attribute_ntv var v = self._cmd return ((v != 0xFF) && self._iscmd) ? v : nil elif k == "direction" - var v = self._direction - return ((v != 0xFF) && self._iscmd) ? (v & 0x01) : nil + return self._direction + elif k == "cmd_general" + return self._cmd_general elif k == "val" var v = self._get_val() if isinstance(v, bytes) @@ -69,13 +70,13 @@ class zcl_attribute : zcl_attribute_ntv else self._cmd = v self._iscmd = 1 - if self._direction == 0xFF # default direction - self._direction = 0 - end + # if self._direction == 0xFF # default direction + # self._direction = 0 + # end end elif k == "direction" if v == nil - self._direction = 0xFF + self._direction = 0 else self._direction = v ? 0x01 : 0x00 self._iscmd = 1 @@ -117,7 +118,7 @@ class zcl_attribute : zcl_attribute_ntv s += "+" + str(self.key_suffix) end elif (self.cluster != nil) && (self.cmd != nil) && (self.direction != nil) - s = string.format("%04X%s%02X", self.cluster, self.direction ? "<" : "!" ,self.cmd) + s = string.format("%04X%s%02X", self.cluster, self.direction ? "?" : "!" ,self.cmd) if self.key_suffix > 1 s += "+" + str(self.key_suffix) end diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_attribute.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_attribute.h index bbe87c457..ebb0e438d 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_attribute.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_attribute.h @@ -80,7 +80,7 @@ be_local_closure(zcl_attribute_key_tostring, /* name */ /* K10 */ be_nested_str_weak(cmd), /* K11 */ be_nested_str_weak(direction), /* K12 */ be_nested_str_weak(_X2504X_X25s_X2502X), - /* K13 */ be_nested_str_weak(_X3C), + /* K13 */ be_nested_str_weak(_X3F), /* K14 */ be_nested_str_weak(_X21), }), be_str_weak(key_tostring), @@ -185,8 +185,8 @@ be_local_closure(zcl_attribute_setmember, /* name */ /* K6 */ be_nested_str_weak(cmd), /* K7 */ be_nested_str_weak(_cmd), /* K8 */ be_const_int(1), - /* K9 */ be_nested_str_weak(_direction), - /* K10 */ be_nested_str_weak(direction), + /* K9 */ be_nested_str_weak(direction), + /* K10 */ be_nested_str_weak(_direction), /* K11 */ be_nested_str_weak(val), /* K12 */ be_nested_str_weak(_set_val), /* K13 */ be_nested_str_weak(key), @@ -195,7 +195,7 @@ be_local_closure(zcl_attribute_setmember, /* name */ }), be_str_weak(setmember), &be_const_str_solidified, - ( &(const binstruction[72]) { /* code */ + ( &(const binstruction[66]) { /* code */ 0x1C0C0300, // 0000 EQ R3 R1 K0 0x780E0007, // 0001 JMPF R3 #000A 0x4C0C0000, // 0002 LDNIL R3 @@ -205,7 +205,7 @@ be_local_closure(zcl_attribute_setmember, /* name */ 0x90020203, // 0006 SETMBR R0 K1 R3 0x70020000, // 0007 JMP #0009 0x90020202, // 0008 SETMBR R0 K1 R2 - 0x7002003C, // 0009 JMP #0047 + 0x70020036, // 0009 JMP #0041 0x1C0C0302, // 000A EQ R3 R1 K2 0x780E0008, // 000B JMPF R3 #0015 0x4C0C0000, // 000C LDNIL R3 @@ -216,58 +216,52 @@ be_local_closure(zcl_attribute_setmember, /* name */ 0x70020001, // 0011 JMP #0014 0x90020602, // 0012 SETMBR R0 K3 R2 0x90020905, // 0013 SETMBR R0 K4 K5 - 0x70020031, // 0014 JMP #0047 + 0x7002002B, // 0014 JMP #0041 0x1C0C0306, // 0015 EQ R3 R1 K6 - 0x780E000D, // 0016 JMPF R3 #0025 + 0x780E0008, // 0016 JMPF R3 #0020 0x4C0C0000, // 0017 LDNIL R3 0x1C0C0403, // 0018 EQ R3 R2 R3 0x780E0002, // 0019 JMPF R3 #001D 0x540E00FE, // 001A LDINT R3 255 0x90020E03, // 001B SETMBR R0 K7 R3 - 0x70020006, // 001C JMP #0024 + 0x70020001, // 001C JMP #001F 0x90020E02, // 001D SETMBR R0 K7 R2 0x90020908, // 001E SETMBR R0 K4 K8 - 0x880C0109, // 001F GETMBR R3 R0 K9 - 0x541200FE, // 0020 LDINT R4 255 - 0x1C0C0604, // 0021 EQ R3 R3 R4 - 0x780E0000, // 0022 JMPF R3 #0024 - 0x90021305, // 0023 SETMBR R0 K9 K5 - 0x70020021, // 0024 JMP #0047 - 0x1C0C030A, // 0025 EQ R3 R1 K10 - 0x780E000C, // 0026 JMPF R3 #0034 - 0x4C0C0000, // 0027 LDNIL R3 - 0x1C0C0403, // 0028 EQ R3 R2 R3 - 0x780E0002, // 0029 JMPF R3 #002D - 0x540E00FE, // 002A LDINT R3 255 - 0x90021203, // 002B SETMBR R0 K9 R3 - 0x70020005, // 002C JMP #0033 - 0x780A0001, // 002D JMPF R2 #0030 - 0x580C0008, // 002E LDCONST R3 K8 - 0x70020000, // 002F JMP #0031 - 0x580C0005, // 0030 LDCONST R3 K5 - 0x90021203, // 0031 SETMBR R0 K9 R3 - 0x90020908, // 0032 SETMBR R0 K4 K8 - 0x70020012, // 0033 JMP #0047 - 0x1C0C030B, // 0034 EQ R3 R1 K11 + 0x70020020, // 001F JMP #0041 + 0x1C0C0309, // 0020 EQ R3 R1 K9 + 0x780E000B, // 0021 JMPF R3 #002E + 0x4C0C0000, // 0022 LDNIL R3 + 0x1C0C0403, // 0023 EQ R3 R2 R3 + 0x780E0001, // 0024 JMPF R3 #0027 + 0x90021505, // 0025 SETMBR R0 K10 K5 + 0x70020005, // 0026 JMP #002D + 0x780A0001, // 0027 JMPF R2 #002A + 0x580C0008, // 0028 LDCONST R3 K8 + 0x70020000, // 0029 JMP #002B + 0x580C0005, // 002A LDCONST R3 K5 + 0x90021403, // 002B SETMBR R0 K10 R3 + 0x90020908, // 002C SETMBR R0 K4 K8 + 0x70020012, // 002D JMP #0041 + 0x1C0C030B, // 002E EQ R3 R1 K11 + 0x780E0003, // 002F JMPF R3 #0034 + 0x8C0C010C, // 0030 GETMET R3 R0 K12 + 0x5C140400, // 0031 MOVE R5 R2 + 0x7C0C0400, // 0032 CALL R3 2 + 0x7002000C, // 0033 JMP #0041 + 0x1C0C030D, // 0034 EQ R3 R1 K13 0x780E0003, // 0035 JMPF R3 #003A - 0x8C0C010C, // 0036 GETMET R3 R0 K12 + 0x8C0C010E, // 0036 GETMET R3 R0 K14 0x5C140400, // 0037 MOVE R5 R2 0x7C0C0400, // 0038 CALL R3 2 - 0x7002000C, // 0039 JMP #0047 - 0x1C0C030D, // 003A EQ R3 R1 K13 - 0x780E0003, // 003B JMPF R3 #0040 - 0x8C0C010E, // 003C GETMET R3 R0 K14 - 0x5C140400, // 003D MOVE R5 R2 - 0x7C0C0400, // 003E CALL R3 2 - 0x70020006, // 003F JMP #0047 - 0x600C0003, // 0040 GETGBL R3 G3 - 0x5C100000, // 0041 MOVE R4 R0 - 0x7C0C0200, // 0042 CALL R3 1 - 0x8C0C070F, // 0043 GETMET R3 R3 K15 - 0x5C140200, // 0044 MOVE R5 R1 - 0x5C180400, // 0045 MOVE R6 R2 - 0x7C0C0600, // 0046 CALL R3 3 - 0x80000000, // 0047 RET 0 + 0x70020006, // 0039 JMP #0041 + 0x600C0003, // 003A GETGBL R3 G3 + 0x5C100000, // 003B MOVE R4 R0 + 0x7C0C0200, // 003C CALL R3 1 + 0x8C0C070F, // 003D GETMET R3 R3 K15 + 0x5C140200, // 003E MOVE R5 R1 + 0x5C180400, // 003F MOVE R6 R2 + 0x7C0C0600, // 0040 CALL R3 3 + 0x80000000, // 0041 RET 0 }) ) ); @@ -447,7 +441,7 @@ be_local_closure(zcl_attribute_member, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[16]) { /* constants */ + ( &(const bvalue[17]) { /* constants */ /* K0 */ be_nested_str_weak(cluster), /* K1 */ be_nested_str_weak(_cluster), /* K2 */ be_nested_str_weak(attr_id), @@ -457,17 +451,18 @@ be_local_closure(zcl_attribute_member, /* name */ /* K6 */ be_nested_str_weak(_cmd), /* K7 */ be_nested_str_weak(direction), /* K8 */ be_nested_str_weak(_direction), - /* K9 */ be_const_int(1), - /* K10 */ be_nested_str_weak(val), - /* K11 */ be_nested_str_weak(_get_val), - /* K12 */ be_nested_str_weak(tohex), - /* K13 */ be_nested_str_weak(key), - /* K14 */ be_nested_str_weak(_get_key), - /* K15 */ be_nested_str_weak(member), + /* K9 */ be_nested_str_weak(cmd_general), + /* K10 */ be_nested_str_weak(_cmd_general), + /* K11 */ be_nested_str_weak(val), + /* K12 */ be_nested_str_weak(_get_val), + /* K13 */ be_nested_str_weak(tohex), + /* K14 */ be_nested_str_weak(key), + /* K15 */ be_nested_str_weak(_get_key), + /* K16 */ be_nested_str_weak(member), }), be_str_weak(member), &be_const_str_solidified, - ( &(const binstruction[78]) { /* code */ + ( &(const binstruction[75]) { /* code */ 0x1C080300, // 0000 EQ R2 R1 K0 0x780A0008, // 0001 JMPF R2 #000B 0x88080101, // 0002 GETMBR R2 R0 K1 @@ -478,7 +473,7 @@ be_local_closure(zcl_attribute_member, /* name */ 0x70020000, // 0007 JMP #0009 0x4C0C0000, // 0008 LDNIL R3 0x80040600, // 0009 RET 1 R3 - 0x70020041, // 000A JMP #004D + 0x7002003E, // 000A JMP #004A 0x1C080302, // 000B EQ R2 R1 K2 0x780A000A, // 000C JMPF R2 #0018 0x88080103, // 000D GETMBR R2 R0 K3 @@ -491,7 +486,7 @@ be_local_closure(zcl_attribute_member, /* name */ 0x70020000, // 0014 JMP #0016 0x4C0C0000, // 0015 LDNIL R3 0x80040600, // 0016 RET 1 R3 - 0x70020034, // 0017 JMP #004D + 0x70020031, // 0017 JMP #004A 0x1C080305, // 0018 EQ R2 R1 K5 0x780A000A, // 0019 JMPF R2 #0025 0x88080106, // 001A GETMBR R2 R0 K6 @@ -504,48 +499,45 @@ be_local_closure(zcl_attribute_member, /* name */ 0x70020000, // 0021 JMP #0023 0x4C0C0000, // 0022 LDNIL R3 0x80040600, // 0023 RET 1 R3 - 0x70020027, // 0024 JMP #004D + 0x70020024, // 0024 JMP #004A 0x1C080307, // 0025 EQ R2 R1 K7 - 0x780A000A, // 0026 JMPF R2 #0032 + 0x780A0002, // 0026 JMPF R2 #002A 0x88080108, // 0027 GETMBR R2 R0 K8 - 0x540E00FE, // 0028 LDINT R3 255 - 0x200C0403, // 0029 NE R3 R2 R3 - 0x780E0003, // 002A JMPF R3 #002F - 0x880C0104, // 002B GETMBR R3 R0 K4 - 0x780E0001, // 002C JMPF R3 #002F - 0x2C0C0509, // 002D AND R3 R2 K9 - 0x70020000, // 002E JMP #0030 - 0x4C0C0000, // 002F LDNIL R3 - 0x80040600, // 0030 RET 1 R3 - 0x7002001A, // 0031 JMP #004D - 0x1C08030A, // 0032 EQ R2 R1 K10 - 0x780A000B, // 0033 JMPF R2 #0040 - 0x8C08010B, // 0034 GETMET R2 R0 K11 - 0x7C080200, // 0035 CALL R2 1 - 0x600C000F, // 0036 GETGBL R3 G15 - 0x5C100400, // 0037 MOVE R4 R2 - 0x60140015, // 0038 GETGBL R5 G21 - 0x7C0C0400, // 0039 CALL R3 2 - 0x780E0002, // 003A JMPF R3 #003E - 0x8C0C050C, // 003B GETMET R3 R2 K12 - 0x7C0C0200, // 003C CALL R3 1 - 0x5C080600, // 003D MOVE R2 R3 - 0x80040400, // 003E RET 1 R2 - 0x7002000C, // 003F JMP #004D - 0x1C08030D, // 0040 EQ R2 R1 K13 - 0x780A0003, // 0041 JMPF R2 #0046 - 0x8C08010E, // 0042 GETMET R2 R0 K14 - 0x7C080200, // 0043 CALL R2 1 - 0x80040400, // 0044 RET 1 R2 - 0x70020006, // 0045 JMP #004D - 0x60080003, // 0046 GETGBL R2 G3 - 0x5C0C0000, // 0047 MOVE R3 R0 - 0x7C080200, // 0048 CALL R2 1 - 0x8C08050F, // 0049 GETMET R2 R2 K15 - 0x5C100200, // 004A MOVE R4 R1 - 0x7C080400, // 004B CALL R2 2 - 0x80040400, // 004C RET 1 R2 - 0x80000000, // 004D RET 0 + 0x80040400, // 0028 RET 1 R2 + 0x7002001F, // 0029 JMP #004A + 0x1C080309, // 002A EQ R2 R1 K9 + 0x780A0002, // 002B JMPF R2 #002F + 0x8808010A, // 002C GETMBR R2 R0 K10 + 0x80040400, // 002D RET 1 R2 + 0x7002001A, // 002E JMP #004A + 0x1C08030B, // 002F EQ R2 R1 K11 + 0x780A000B, // 0030 JMPF R2 #003D + 0x8C08010C, // 0031 GETMET R2 R0 K12 + 0x7C080200, // 0032 CALL R2 1 + 0x600C000F, // 0033 GETGBL R3 G15 + 0x5C100400, // 0034 MOVE R4 R2 + 0x60140015, // 0035 GETGBL R5 G21 + 0x7C0C0400, // 0036 CALL R3 2 + 0x780E0002, // 0037 JMPF R3 #003B + 0x8C0C050D, // 0038 GETMET R3 R2 K13 + 0x7C0C0200, // 0039 CALL R3 1 + 0x5C080600, // 003A MOVE R2 R3 + 0x80040400, // 003B RET 1 R2 + 0x7002000C, // 003C JMP #004A + 0x1C08030E, // 003D EQ R2 R1 K14 + 0x780A0003, // 003E JMPF R2 #0043 + 0x8C08010F, // 003F GETMET R2 R0 K15 + 0x7C080200, // 0040 CALL R2 1 + 0x80040400, // 0041 RET 1 R2 + 0x70020006, // 0042 JMP #004A + 0x60080003, // 0043 GETGBL R2 G3 + 0x5C0C0000, // 0044 MOVE R3 R0 + 0x7C080200, // 0045 CALL R2 1 + 0x8C080510, // 0046 GETMET R2 R2 K16 + 0x5C100200, // 0047 MOVE R4 R1 + 0x7C080400, // 0048 CALL R2 2 + 0x80040400, // 0049 RET 1 R2 + 0x80000000, // 004A RET 0 }) ) ); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1z_libs.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1z_libs.ino index 335431b53..d81cabe5c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1z_libs.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1z_libs.ino @@ -107,7 +107,8 @@ public: bool key_is_pmem; // is the string in progmem, so we don't need to make a copy bool val_str_raw; // if val is String, it is raw JSON and should not be escaped bool key_is_cmd; // if command, cmd_id is the low 8 bits of attr_id. - // The high 8 bits are `0` command sent to device or `1` command received from device + // Bit #8 is `0` command sent to device or `1` command received from device + // Bit #9 is `0` command is cluster specific, or `1` general_command uint8_t key_suffix; // append a suffix to key (default is 1, explicitly output if >1) uint8_t attr_type; // [opt] type of the attribute, default to Zunk (0xFF) int8_t attr_multiplier; // [opt] multiplier for attribute, defaults to 0x01 (no change) @@ -161,7 +162,7 @@ public: void setKeyName(const char * _key, const char * _key2); void setKeyId(uint16_t cluster, uint16_t attr_id); - void setCmdId(uint16_t cluster, uint8_t cmd_id, bool direction); + void setCmdId(uint16_t cluster, uint8_t cmd_id, bool direction, bool cmd_general); // Setters void setNone(void); @@ -209,7 +210,7 @@ public: bool equalsKey(const Z_attribute & attr2, bool ignore_key_suffix = false) const; bool equalsId(uint16_t cluster, uint16_t attr_id, uint8_t suffix = 0) const; - bool equalsCmd(uint16_t cluster, uint8_t cmd_id, bool direction, uint8_t suffix = 0) const; + bool equalsCmd(uint16_t cluster, uint8_t cmd_id, bool direction, bool cmd_general, uint8_t suffix = 0) const; bool equalsKey(const char * name, uint8_t suffix = 0) const; bool equalsVal(const Z_attribute & attr2) const; bool equals(const Z_attribute & attr2) const; @@ -272,7 +273,7 @@ public: Z_attribute & addAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix = 0); // ZCL command - Z_attribute & addAttributeCmd(uint16_t cluster, uint8_t cmd_id, bool direction, uint8_t suffix = 0); + Z_attribute & addAttributeCmd(uint16_t cluster, uint8_t cmd_id, bool direction, bool cmd_general, uint8_t suffix = 0); // Add attribute to the list, given name Z_attribute & addAttribute(const char * name, bool pmem = false, uint8_t suffix = 0); @@ -293,15 +294,15 @@ public: // find if attribute with same key already exists, return null if not found const Z_attribute * findAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix = 0) const; - const Z_attribute * findAttributeCmd(uint16_t cluster, uint8_t cmd_id, bool direction, uint8_t suffix = 0) const; + const Z_attribute * findAttributeCmd(uint16_t cluster, uint8_t cmd_id, bool direction, bool cmd_general, uint8_t suffix = 0) const; const Z_attribute * findAttribute(const char * name, uint8_t suffix = 0) const; const Z_attribute * findAttribute(const Z_attribute &attr) const; // suffix always count here // non-const variants inline Z_attribute * findAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix = 0) { return (Z_attribute*) ((const Z_attribute_list*)this)->findAttribute(cluster, attr_id, suffix); } - inline Z_attribute * findAttributeCmd(uint16_t cluster, uint8_t cmd_id, bool direction, uint8_t suffix = 0) { - return (Z_attribute*) ((const Z_attribute_list*)this)->findAttributeCmd(cluster, cmd_id, direction, suffix); + inline Z_attribute * findAttributeCmd(uint16_t cluster, uint8_t cmd_id, bool direction, bool cmd_general, uint8_t suffix = 0) { + return (Z_attribute*) ((const Z_attribute_list*)this)->findAttributeCmd(cluster, cmd_id, direction, cmd_general, suffix); } inline Z_attribute * findAttribute(const char * name, uint8_t suffix = 0) { return (Z_attribute*) (((const Z_attribute_list*)this)->findAttribute(name, suffix)); @@ -317,7 +318,7 @@ public: // if suffix == 0, we don't care and find the first match Z_attribute & findOrCreateAttribute(uint16_t cluster, uint16_t attr_id, uint8_t suffix = 0); Z_attribute & findOrCreateAttribute(const char * name, uint8_t suffix = 0); - Z_attribute & findOrCreateCmd(uint16_t cluster, uint8_t cmd_id, bool direction, uint8_t suffix = 0); + Z_attribute & findOrCreateCmd(uint16_t cluster, uint8_t cmd_id, bool direction, bool cmd_general, uint8_t suffix = 0); // always care about suffix Z_attribute & findOrCreateAttribute(const Z_attribute &attr); // replace attribute with new value, suffix does care @@ -381,11 +382,11 @@ void Z_attribute::setKeyId(uint16_t _cluster, uint16_t _attr_id) { key_is_cmd = false; } -void Z_attribute::setCmdId(uint16_t _cluster, uint8_t _cmd_id, bool direction) { +void Z_attribute::setCmdId(uint16_t _cluster, uint8_t _cmd_id, bool direction, bool cmd_general) { freeKey(); key_is_str = false; cluster = _cluster; - attr_id = _cmd_id | (direction ? 0x100 : 0x000); + attr_id = _cmd_id | (direction ? 0x100 : 0x000) | (cmd_general ? 0x200 : 0x000); key_is_cmd = true; } @@ -570,9 +571,9 @@ bool Z_attribute::equalsId(uint16_t _cluster, uint16_t _attr_id, uint8_t suffix) return false; } -bool Z_attribute::equalsCmd(uint16_t _cluster, uint8_t _cmd_id, bool _direction, uint8_t suffix) const { +bool Z_attribute::equalsCmd(uint16_t _cluster, uint8_t _cmd_id, bool _direction, bool cmd_general, uint8_t suffix) const { if (!key_is_cmd ||key_is_str) { return false; } - uint16_t _attr_id = _cmd_id | (_direction ? 0x100 : 0x000); + uint16_t _attr_id = _cmd_id | (_direction ? 0x100 : 0x000) | (cmd_general ? 0x200 : 0x000); if ((this->cluster == _cluster) && (this->attr_id == _attr_id) && (!this->key_is_cmd)) { if (suffix) { if (key_suffix == suffix) { return true; } @@ -636,8 +637,10 @@ String Z_attribute::toString(bool prefix_comma) const { snprintf_P(attr_name, sizeof(attr_name), PSTR("%04X/%04X"), this->cluster, this->attr_id); } else { // cmd bool direction = (this->attr_id & 0x100); + bool cmd_general = (this->attr_id & 0x200); uint8_t cmd_id = this->attr_id & 0xFF; - snprintf_P(attr_name, sizeof(attr_name), PSTR("%04X%c%02X"), this->cluster, direction ? '<' : '!', cmd_id); + char cmd_char = cmd_general ? (direction ? '^' : '_') : (direction ? '?' : '!'); + snprintf_P(attr_name, sizeof(attr_name), PSTR("%04X%c%02X"), this->cluster, cmd_char, cmd_id); } res += attr_name; if (key_suffix > 1) { @@ -808,10 +811,10 @@ Z_attribute & Z_attribute_list::addAttribute(uint16_t cluster, uint16_t attr_id, } // add a cluster/cmd_id attribute at the end of the list -Z_attribute & Z_attribute_list::addAttributeCmd(uint16_t cluster, uint8_t cmd_id, bool direction, uint8_t suffix) { +Z_attribute & Z_attribute_list::addAttributeCmd(uint16_t cluster, uint8_t cmd_id, bool direction, bool cmd_general, uint8_t suffix) { Z_attribute & attr = addToLast(); attr.cluster = cluster; - attr.attr_id = cmd_id | (direction ? 0x100 : 0); + attr.attr_id = cmd_id | (direction ? 0x100 : 0) | (cmd_general ? 0x200 : 0x000); attr.key_is_cmd = true; if (!suffix) { attr.key_suffix = countAttribute(attr.cluster, attr.attr_id); } else { attr.key_suffix = suffix; } @@ -884,7 +887,7 @@ const Z_attribute * Z_attribute_list::findAttribute(const Z_attribute &attr) con } else if (!attr.key_is_cmd) { return findAttribute(attr.cluster, attr.attr_id, suffix); } else { - return findAttributeCmd(attr.cluster, attr.attr_id & 0xFF, attr.attr_id & 0x100 ? true : false, suffix); + return findAttributeCmd(attr.cluster, attr.attr_id & 0xFF, attr.attr_id & 0x100 ? true : false, attr.attr_id & 0x200 ? true : false, suffix); } } @@ -902,9 +905,9 @@ size_t Z_attribute_list::countAttribute(uint16_t cluster, uint16_t attr_id) cons return count; } -const Z_attribute * Z_attribute_list::findAttributeCmd(uint16_t cluster, uint8_t cmd_id, bool direction, uint8_t suffix) const { +const Z_attribute * Z_attribute_list::findAttributeCmd(uint16_t cluster, uint8_t cmd_id, bool direction, bool cmd_general, uint8_t suffix) const { for (const auto & attr : *this) { - if (attr.equalsCmd(cluster, cmd_id, direction, suffix)) { return &attr; } + if (attr.equalsCmd(cluster, cmd_id, direction, cmd_general, suffix)) { return &attr; } } return nullptr; } @@ -915,9 +918,9 @@ Z_attribute & Z_attribute_list::findOrCreateAttribute(uint16_t cluster, uint16_t return found ? *found : addAttribute(cluster, attr_id, suffix); } -Z_attribute & Z_attribute_list::findOrCreateCmd(uint16_t cluster, uint8_t cmd_id, bool direction, uint8_t suffix) { - Z_attribute * found = findAttributeCmd(cluster, cmd_id, direction, suffix); - return found ? *found : addAttributeCmd(cluster, cmd_id, direction, suffix); +Z_attribute & Z_attribute_list::findOrCreateCmd(uint16_t cluster, uint8_t cmd_id, bool direction, bool cmd_general, uint8_t suffix) { + Z_attribute * found = findAttributeCmd(cluster, cmd_id, direction, cmd_general, suffix); + return found ? *found : addAttributeCmd(cluster, cmd_id, direction, cmd_general, suffix); } const Z_attribute * Z_attribute_list::findAttribute(const char * name, uint8_t suffix) const { @@ -943,7 +946,7 @@ Z_attribute & Z_attribute_list::findOrCreateAttribute(const char * name, uint8_t Z_attribute & Z_attribute_list::findOrCreateAttribute(const Z_attribute &attr) { Z_attribute & ret = attr.key_is_str ? findOrCreateAttribute(attr.key, attr.key_suffix) : attr.key_is_cmd ? - findOrCreateCmd(attr.cluster, attr.attr_id & 0xFF, attr.attr_id & 0x100 ? true : false, attr.key_suffix) + findOrCreateCmd(attr.cluster, attr.attr_id & 0xFF, attr.attr_id & 0x100 ? true : false, attr.attr_id & 0x200 ? true : false, attr.key_suffix) : findOrCreateAttribute(attr.cluster, attr.attr_id, attr.key_suffix); ret.key_suffix = attr.key_suffix; return ret; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino index 4e13f6bf6..25c4c57a0 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino @@ -112,6 +112,7 @@ public: _linkquality(linkquality), _securityuse(securityuse), _seqnumber(seqnumber) { _frame_control.d8 = frame_control; + direction = _frame_control.b.direction; clusterSpecific = (_frame_control.b.frame_type != 0); needResponse = !_frame_control.b.disable_def_resp; payload.addBuffer(buf, buf_len); @@ -131,7 +132,7 @@ public: srcendpoint, dstendpoint, _wasbroadcast, _linkquality, _securityuse, _seqnumber, _frame_control, - _frame_control.b.frame_type, _frame_control.b.direction, _frame_control.b.disable_def_resp, + _frame_control.b.frame_type, direction, _frame_control.b.disable_def_resp, manuf, transactseq, cmd, &payload); if (Settings->flag3.tuya_serial_mqtt_publish) { @@ -165,9 +166,8 @@ public: return zcl_frame; } - bool isClusterSpecificCommand(void) { - return _frame_control.b.frame_type & 1; - } + bool isClusterSpecificCommand(void) const { return _frame_control.b.frame_type & 1; } + uint8_t getDirection(void) const { return direction; } // parsers for received messages void parseReportAttributes(Z_attribute_list& attr_list); @@ -1127,10 +1127,10 @@ void ZCLFrame::parseClusterSpecificCommand(Z_attribute_list& attr_list) { device.debounce_transact = transactseq; zigbee_devices.setTimer(shortaddr, 0 /* groupaddr */, USE_ZIGBEE_DEBOUNCE_COMMANDS, 0 /*clusterid*/, srcendpoint, Z_CAT_DEBOUNCE_CMD, 0, &Z_ResetDebounce); - convertClusterSpecific(attr_list, cluster, cmd, _frame_control.b.direction, shortaddr, srcendpoint, payload); + convertClusterSpecific(attr_list, cluster, cmd, direction, shortaddr, 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 (!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); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_6_commands.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_6_commands.ino index 925f2da9f..826864e97 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_6_commands.ino @@ -347,9 +347,9 @@ void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster, // Format: "0001!06": "00" = "!": "" for commands to devices // Format: "0004<00": "00" = "<": "" for commands to devices // char attrid_str[12]; - // snprintf_P(attrid_str, sizeof(attrid_str), PSTR("%04X%c%02X"), cluster, direction ? '<' : '!', cmd); + // snprintf_P(attrid_str, sizeof(attrid_str), PSTR("%04X%c%02X"), cluster, direction ? '?' : '!', cmd); // Z_attribute & attr_raw = attr_list.addAttribute(attrid_str); - Z_attribute & attr_raw = attr_list.addAttributeCmd(cluster, cmd, direction); + Z_attribute & attr_raw = attr_list.addAttributeCmd(cluster, cmd, direction, false /* cluster specific */); attr_raw.setBuf(payload, 0, payload.len()); // TODO Berry encode command diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino index b9ea16e69..3817bdbb5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino @@ -1698,36 +1698,56 @@ void Z_IncomingMessage(class ZCLFrame &zcl_received) { attr_list.group_id = groupid; } - if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_DEFAULT_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseResponse(); // Zigbee general "Default Response", publish ZbResponse message + // uint8_t cmdid = zcl_received.getCmdId(); + bool cmd_ignore = false; // ignore the command in later processing + + if (zcl_received.isClusterSpecificCommand()) { + // Cluster-specific command + zcl_received.parseClusterSpecificCommand(attr_list); + Z_Query_Battery(srcaddr); // do battery auto-probing when receiving commands } else { - // Build the ZbReceive list - if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_REPORT_ATTRIBUTES == zcl_received.getCmdId() || ZCL_WRITE_ATTRIBUTES == zcl_received.getCmdId())) { - zcl_received.parseReportAttributes(attr_list); // Zigbee report attributes from sensors + // General cluster command + switch (zcl_received.getCmdId()) { + case ZCL_DEFAULT_RESPONSE: + zcl_received.parseResponse(); // Zigbee general "Default Response", publish ZbResponse message + cmd_ignore = true; + break; + case ZCL_REPORT_ATTRIBUTES: + case ZCL_WRITE_ATTRIBUTES: + zcl_received.parseReportAttributes(attr_list); // Zigbee report attributes from sensors - // since we receive a sensor value, and the device is still awake, - // try to read the battery value - if (clusterid != 0x0001) { // avoid sending Battery probe if we already received info from cluster 0x0001 - Z_Query_Battery(srcaddr); - } - if (clusterid && (ZCL_REPORT_ATTRIBUTES == zcl_received.getCmdId())) { defer_attributes = true; } // don't defer system Cluster=0 messages or Write Attribute - } else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_READ_ATTRIBUTES_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseReadAttributesResponse(attr_list); - if (clusterid) { defer_attributes = true; } // don't defer system Cluster=0 messages - } else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_READ_ATTRIBUTES == zcl_received.getCmdId())) { - zcl_received.parseReadAttributes(srcaddr, attr_list); - // never defer read_attributes, so the auto-responder can send response back on a per cluster basis - } else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_READ_REPORTING_CONFIGURATION_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseReadConfigAttributes(srcaddr, attr_list); - } else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_CONFIGURE_REPORTING_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseConfigAttributes(srcaddr, attr_list); - } else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_WRITE_ATTRIBUTES_RESPONSE == zcl_received.getCmdId())) { - zcl_received.parseWriteAttributesResponse(attr_list); - } else if (zcl_received.isClusterSpecificCommand()) { - zcl_received.parseClusterSpecificCommand(attr_list); - Z_Query_Battery(srcaddr); // do battery auto-probing when receiving commands + // since we receive a sensor value, and the device is still awake, + // try to read the battery value + if (clusterid != 0x0001) { // avoid sending Battery probe if we already received info from cluster 0x0001 + Z_Query_Battery(srcaddr); + } + if (clusterid && zcl_received.getCmdId() == ZCL_REPORT_ATTRIBUTES) { defer_attributes = true; } // defer attributes reporting except for cluster 0x0000 or Write Attribute + break; + case ZCL_READ_ATTRIBUTES_RESPONSE: + zcl_received.parseReadAttributesResponse(attr_list); + if (clusterid) { defer_attributes = true; } // defer attributes reporting except for cluster 0x0000 + break; + case ZCL_READ_ATTRIBUTES: + zcl_received.parseReadAttributes(srcaddr, attr_list); + // never defer read_attributes, so the auto-responder can send response back on a per cluster basis + break; + case ZCL_READ_REPORTING_CONFIGURATION_RESPONSE: + zcl_received.parseReadConfigAttributes(srcaddr, attr_list); + break; + case ZCL_CONFIGURE_REPORTING_RESPONSE: + zcl_received.parseConfigAttributes(srcaddr, attr_list); + break; + case ZCL_WRITE_ATTRIBUTES_RESPONSE: + zcl_received.parseWriteAttributesResponse(attr_list); + break; + default: + attr_list.addAttributeCmd(clusterid, zcl_received.getCmdId(), zcl_received.getDirection(), true /* general command */).setBuf(zcl_received.payload, 0, zcl_received.payload.len()); + break; } + } + // unless attributes are ignored, post-process and publish them + if (!cmd_ignore) { AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZCL_RAW_RECEIVED ": {\"0x%04X\":{%s}}"), srcaddr, attr_list.toString(false, false).c_str()); // don't include battery #ifdef USE_BERRY 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 6e53e90ba..8c0cdb8b6 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino @@ -556,6 +556,11 @@ void ZbSendSend(class JsonParserToken val_cmd, ZCLFrame & zcl) { // Now parse the string to extract cluster, command, and payload // Parse 'cmd' in the form "AAAA_BB/CCCCCCCC" or "AAAA!BB/CCCCCCCC" // where AAAA is the cluster number, BB the command number, CCCC... the payload + // Possible delimiters: + // "AAAA_BB/...": general cluster, sent to device (direction == 0) + // "AAAA^BB/...": general cluster, recevied from device (direction == 1) + // "AAAA!BB/...": cluster specific, sent to device (direction == 0) + // "AAAA?BB/...": cluster specific, recevied from device (direction == 1) // First delimiter is '_' for a global command, or '!' for a cluster specific command const char * data = val_cmd.getStr(); uint16_t local_cluster_id = parseHex(&data, 4); @@ -569,8 +574,9 @@ void ZbSendSend(class JsonParserToken val_cmd, ZCLFrame & zcl) { } // delimiter - if (('_' == *data) || ('!' == *data)) { - if ('_' == *data) { zcl.clusterSpecific = false; } + if (('_' == *data) || ('^' == *data) || ('!' == *data) || ('?' == *data)) { + if ('_' == *data || '^' == *data) { zcl.clusterSpecific = false; } + if ('^' == *data || '?' == *data) { zcl.direction = true; } data++; } else { ResponseCmndChar_P(PSTR(D_ZIGBEE_WRONG_DELIMITER)); 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 2642ac280..de58aeb91 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_zigbee.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_zigbee.ino @@ -254,13 +254,14 @@ extern "C" { extern const be_ctypes_structure_t be_zigbee_zcl_attribute_struct = { sizeof(Z_attribute), /* size in bytes */ - 9, /* number of elements */ + 10, /* number of elements */ nullptr, - (const be_ctypes_structure_item_t[9]) { + (const be_ctypes_structure_item_t[10]) { { "_attr_id", offsetof(Z_attribute, attr_id), 0, 0, ctypes_u16, 0 }, { "_cluster", offsetof(Z_attribute, cluster), 0, 0, ctypes_u16, 0 }, { "_cmd", offsetof(Z_attribute, attr_id), 0, 0, ctypes_u8, 0 }, // low 8 bits of attr_id - { "_direction", offsetof(Z_attribute, attr_id) + 1, 0, 0, ctypes_u8, 0 }, // high 8 bits of attr_id + { "_cmd_general", offsetof(Z_attribute, attr_id) + 1, 1, 1, ctypes_u8, 0 }, // bit #1 of byte+1 + { "_direction", offsetof(Z_attribute, attr_id) + 1, 0, 1, ctypes_u8, 0 }, // bit #0 of byte+1 { "_iscmd", offsetof(Z_attribute, key_is_cmd), 0, 0, ctypes_u8, 0 }, { "attr_multiplier", offsetof(Z_attribute, attr_multiplier), 0, 0, ctypes_i8, 0 }, { "attr_divider", offsetof(Z_attribute, attr_divider), 0, 0, ctypes_i8, 0 },