Fix zigbee attribute writes and configuration

This commit is contained in:
Stephan Hadinger 2022-09-18 19:23:59 +02:00
parent 3a356263ba
commit e94baa84cf
3 changed files with 26 additions and 17 deletions

View File

@ -278,10 +278,12 @@ uint8_t toPercentageCR2032(uint32_t voltage) {
// Adds to buf: // Adds to buf:
// - n bytes: value (typically between 1 and 4 bytes, or bigger for strings) // - n bytes: value (typically between 1 and 4 bytes, or bigger for strings)
// returns number of bytes of attribute, or <0 if error // returns number of bytes of attribute, or <0 if error
// If the value is `NAN`, the value encoded is the "zigbee invalid value"
int32_t encodeSingleAttribute(SBuffer &buf, double val_d, const char *val_str, uint8_t attrtype) { int32_t encodeSingleAttribute(SBuffer &buf, double val_d, const char *val_str, uint8_t attrtype) {
uint32_t len = Z_getDatatypeLen(attrtype); // pre-compute length, overloaded for variable length attributes uint32_t len = Z_getDatatypeLen(attrtype); // pre-compute length, overloaded for variable length attributes
uint32_t u32 = val_d; bool nan = isnan(val_d);
int32_t i32 = val_d; uint32_t u32 = nan ? 0xFFFFFFFF : roundf(val_d);
int32_t i32 = roundf(val_d);
float f32 = val_d; float f32 = val_d;
switch (attrtype) { switch (attrtype) {
@ -315,13 +317,13 @@ int32_t encodeSingleAttribute(SBuffer &buf, double val_d, const char *val_str, u
// signed 8 // signed 8
case Zint8: // int8 case Zint8: // int8
buf.add8(i32); buf.add8(nan ? 0x80 : i32);
break; break;
case Zint16: // int16 case Zint16: // int16
buf.add16(i32); buf.add16(nan ? 0x8000 : i32);
break; break;
case Zint32: // int32 case Zint32: // int32
buf.add32(i32); buf.add32(nan ? 0x80000000 : i32);
break; break;
case Zsingle: // float case Zsingle: // float

View File

@ -1594,7 +1594,7 @@ void Z_AutoConfigReportingForCluster(uint16_t shortaddr, uint16_t groupaddr, uin
buf.add16(min_interval); buf.add16(min_interval);
buf.add16(max_interval); buf.add16(max_interval);
if (!Z_isDiscreteDataType(attr_matched.zigbee_type)) { // report_change is only valid for non-discrete data types (numbers) if (!Z_isDiscreteDataType(attr_matched.zigbee_type)) { // report_change is only valid for non-discrete data types (numbers)
ZbApplyMultiplier(report_change, attr_matched.multiplier, attr_matched.divider, attr_matched.base); ZbApplyMultiplierForWrites(report_change, attr_matched.multiplier, attr_matched.divider, attr_matched.base);
// encode value // encode value
int32_t res = encodeSingleAttribute(buf, report_change, "", attr_matched.zigbee_type); int32_t res = encodeSingleAttribute(buf, report_change, "", attr_matched.zigbee_type);
if (res < 0) { if (res < 0) {

View File

@ -219,18 +219,20 @@ void zigbeeZCLSendCmd(class ZCLFrame &zcl) {
// Definitive doc for Tuya protocol: // Definitive doc for Tuya protocol:
// https://developer.tuya.com/en/docs/iot-device-dev/tuya-zigbee-universal-docking-access-standard?id=K9ik6zvofpzql#subtitle-6-Private%20cluster // https://developer.tuya.com/en/docs/iot-device-dev/tuya-zigbee-universal-docking-access-standard?id=K9ik6zvofpzql#subtitle-6-Private%20cluster
// Special encoding for multiplier:
// Special encoding for multiplier when sending writes or reportable attributes,
// I.e. multipliers and dividers are inversed
// multiplier == 0: ignore // multiplier == 0: ignore
// multiplier == 1: ignore // multiplier == 1: ignore
void ZbApplyMultiplier(double &val_d, int8_t multiplier, int8_t divider, int8_t base) { void ZbApplyMultiplierForWrites(double &val_d, int8_t multiplier, int8_t divider, int8_t base) {
if (0 != base) {
val_d = val_d - base;
}
if ((0 != multiplier) && (1 != multiplier)) { if ((0 != multiplier) && (1 != multiplier)) {
val_d = val_d * multiplier; val_d = val_d / multiplier;
} }
if ((0 != divider) && (1 != divider)) { if ((0 != divider) && (1 != divider)) {
val_d = val_d / divider; val_d = val_d * divider;
}
if (0 != base) {
val_d = val_d + base;
} }
} }
@ -243,7 +245,7 @@ bool ZbTuyaWrite(SBuffer & buf, const Z_attribute & attr) {
if (attr.key_is_str || attr.key_is_cmd) { return false; } // couldn't find attr if so skip if (attr.key_is_str || attr.key_is_cmd) { return false; } // couldn't find attr if so skip
if (attr.isNum()) { if (attr.isNum()) {
ZbApplyMultiplier(val_d, attr.attr_multiplier, attr.attr_divider, 0); ZbApplyMultiplierForWrites(val_d, attr.attr_multiplier, attr.attr_divider, 0);
} }
uint32_t u32 = val_d; uint32_t u32 = val_d;
int32_t i32 = val_d; int32_t i32 = val_d;
@ -302,7 +304,7 @@ bool ZbAppendWriteBuf(SBuffer & buf, const Z_attribute & attr, bool prepend_stat
if (attr.key_is_str && attr.key_is_cmd) { return false; } // couldn't find attr if so skip if (attr.key_is_str && attr.key_is_cmd) { return false; } // couldn't find attr if so skip
if (attr.isNum()) { if (attr.isNum()) {
ZbApplyMultiplier(val_d, attr.attr_multiplier, attr.attr_divider, 0); ZbApplyMultiplierForWrites(val_d, attr.attr_multiplier, attr.attr_divider, 0);
} }
// push the value in the buffer // push the value in the buffer
@ -419,9 +421,14 @@ void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZCLFrame & zcl)
// read ReportableChange // read ReportableChange
JsonParserToken val_attr_rc = attr_config[PSTR("ReportableChange")]; JsonParserToken val_attr_rc = attr_config[PSTR("ReportableChange")];
if (val_attr_rc) { if (val_attr_rc) {
val_d = val_attr_rc.getFloat(); // If value is `null` then we send 0xFFFF for invalid value
val_str = val_attr_rc.getStr(); val_str = val_attr_rc.getStr();
ZbApplyMultiplier(val_d, attr.attr_multiplier, attr.attr_divider, 0); if (!val_attr_rc.isNull()) {
val_d = val_attr_rc.getFloat();
ZbApplyMultiplierForWrites(val_d, attr.attr_multiplier, attr.attr_divider, 0);
} else {
val_d = NAN;
}
} }
// read TimeoutPeriod // read TimeoutPeriod