Zigbee report unprocessed attributes

This commit is contained in:
Stephan Hadinger 2022-09-19 22:03:46 +02:00
parent af039838b6
commit eb65038b6c
9 changed files with 189 additions and 165 deletions

View File

@ -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

View File

@ -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

View File

@ -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
})
)
);

View File

@ -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;

View File

@ -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);
}

View File

@ -347,9 +347,9 @@ void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster,
// Format: "0001!06": "00" = "<cluster>!<cmd>": "<payload>" for commands to devices
// Format: "0004<00": "00" = "<cluster><<cmd>": "<payload>" 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

View File

@ -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

View File

@ -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));

View File

@ -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 },