Zigbee device profile phase 1

This commit is contained in:
Stephan Hadinger 2020-08-20 08:25:53 +02:00
parent f6128bdae3
commit 7102d6a279
5 changed files with 166 additions and 70 deletions

View File

@ -22,7 +22,7 @@
#include <vector> #include <vector>
#ifndef ZIGBEE_SAVE_DELAY_SECONDS #ifndef ZIGBEE_SAVE_DELAY_SECONDS
#define ZIGBEE_SAVE_DELAY_SECONDS 2; // wait for 2s before saving Zigbee info #define ZIGBEE_SAVE_DELAY_SECONDS 2 // wait for 2s before saving Zigbee info
#endif #endif
const uint16_t kZigbeeSaveDelaySeconds = ZIGBEE_SAVE_DELAY_SECONDS; // wait for x seconds const uint16_t kZigbeeSaveDelaySeconds = ZIGBEE_SAVE_DELAY_SECONDS; // wait for x seconds
@ -63,14 +63,25 @@ typedef struct Z_Device {
uint16_t shortaddr; // unique key if not null, or unspecified if null uint16_t shortaddr; // unique key if not null, or unspecified if null
uint8_t seqNumber; uint8_t seqNumber;
// Light information for Hue integration integration, last known values // Light information for Hue integration integration, last known values
int8_t bulbtype; // number of channel for the bulb: 0-5, or 0xFF if no Hue integration uint8_t zb_profile; // profile of the device
// high 4 bits is device type:
// 0x0. = bulb
// 0x1. = switch
// 0x2. = motion sensor
// 0x3. = other alarms
// 0xE. = reserved for extension
// 0xF. = unknown
// For Bulb (0x0.)
// 0x0N = number of channel for the bulb: 0-5
// 0x08 = the device is hidden from Alexa
// other status
uint8_t power; // power state (boolean), MSB (0x80) stands for reachable uint8_t power; // power state (boolean), MSB (0x80) stands for reachable
uint8_t colormode; // 0x00: Hue/Sat, 0x01: XY, 0x02: CT uint8_t colormode; // 0x00: Hue/Sat, 0x01: XY, 0x02: CT | 0xFF not set, default 0x01
uint8_t dimmer; // last Dimmer value: 0-254 uint8_t dimmer; // last Dimmer value: 0-254 | 0xFF not set, default 0x00
uint8_t sat; // last Sat: 0..254 uint8_t sat; // last Sat: 0..254 | 0xFF not set, default 0x00
uint16_t ct; // last CT: 153-500 uint16_t ct; // last CT: 153-500 | 0xFFFF not set, default 200
uint16_t hue; // last Hue: 0..359 uint16_t hue; // last Hue: 0..359 | 0xFFFF not set, default 0
uint16_t x, y; // last color [x,y] uint16_t x, y; // last color [x,y] | 0xFFFF not set, default 0
uint8_t linkquality; // lqi from last message, 0xFF means unknown uint8_t linkquality; // lqi from last message, 0xFF means unknown
uint8_t batterypercent; // battery percentage (0..100), 0xFF means unknwon uint8_t batterypercent; // battery percentage (0..100), 0xFF means unknwon
} Z_Device; } Z_Device;
@ -163,9 +174,15 @@ public:
String dump(uint32_t dump_mode, uint16_t status_shortaddr = 0) const; String dump(uint32_t dump_mode, uint16_t status_shortaddr = 0) const;
int32_t deviceRestore(const JsonObject &json); int32_t deviceRestore(const JsonObject &json);
// General Zigbee device profile support
void setZbProfile(uint16_t shortaddr, uint8_t zb_profile);
uint8_t getZbProfile(uint16_t shortaddr) const ;
// Hue support // Hue support
void setHueBulbtype(uint16_t shortaddr, int8_t bulbtype); void setHueBulbtype(uint16_t shortaddr, int8_t bulbtype);
int8_t getHueBulbtype(uint16_t shortaddr) const ; int8_t getHueBulbtype(uint16_t shortaddr) const ;
void hideHueBulb(uint16_t shortaddr, bool hidden);
bool isHueBulbHidden(uint16_t shortaddr) const ;
void updateHueState(uint16_t shortaddr, void updateHueState(uint16_t shortaddr,
const bool *power, const uint8_t *colormode, const bool *power, const uint8_t *colormode,
const uint8_t *dimmer, const uint8_t *sat, const uint8_t *dimmer, const uint8_t *sat,
@ -236,6 +253,8 @@ private:
void freeDeviceEntry(Z_Device *device); void freeDeviceEntry(Z_Device *device);
void setStringAttribute(char*& attr, const char * str); void setStringAttribute(char*& attr, const char * str);
void updateZbProfile(uint16_t shortaddr);
}; };
/*********************************************************************************************\ /*********************************************************************************************\
@ -294,14 +313,14 @@ Z_Device & Z_Devices::createDeviceEntry(uint16_t shortaddr, uint64_t longaddr) {
shortaddr, shortaddr,
0, // seqNumber 0, // seqNumber
// Hue support // Hue support
-1, // no Hue support 0xFF, // no Hue support
0x80, // power off + reachable 0x80, // power off + reachable
0, // colormode 0xFF, // colormode
0, // dimmer 0xFF, // dimmer
0, // sat 0xFF, // sat
200, // ct 0xFFFF, // ct
0, // hue 0xFFFF, // hue
0, 0, // x, y 0xFFFF, 0xFFFF, // x, y
0xFF, // lqi, 0xFF = unknown 0xFF, // lqi, 0xFF = unknown
0xFF // battery percentage x 2, 0xFF means unknown 0xFF // battery percentage x 2, 0xFF means unknown
}; };
@ -691,24 +710,99 @@ uint8_t Z_Devices::getNextSeqNumber(uint16_t shortaddr) {
} }
} }
// General Zigbee device profile support
// Hue support void Z_Devices::setZbProfile(uint16_t shortaddr, uint8_t zb_profile) {
void Z_Devices::setHueBulbtype(uint16_t shortaddr, int8_t bulbtype) {
Z_Device &device = getShortAddr(shortaddr); Z_Device &device = getShortAddr(shortaddr);
if (bulbtype != device.bulbtype) { if (zb_profile != device.zb_profile) {
device.bulbtype = bulbtype; device.zb_profile = zb_profile;
updateZbProfile(shortaddr);
dirty(); dirty();
} }
} }
int8_t Z_Devices::getHueBulbtype(uint16_t shortaddr) const {
// Do all the required action when a profile is changed
void Z_Devices::updateZbProfile(uint16_t shortaddr) {
Z_Device &device = getShortAddr(shortaddr);
uint8_t zb_profile = device.zb_profile;
if (0xFF == zb_profile) { return; }
switch (zb_profile & 0xF0) {
case 0x00: // bulb profile
{
uint32_t channels = zb_profile & 0x07;
// depending on the bulb type, the default parameters from unknown to credible defaults
if (0xFF == device.power) { device.power = 0; }
if (1 <= channels) {
if (0xFF == device.dimmer) { device.dimmer = 0; }
}
if (3 <= channels) {
if (0xFF == device.sat) { device.sat = 0; }
if (0xFFFF == device.hue) { device.hue = 0; }
if (0xFFFF == device.x) { device.x = 0; }
if (0xFFFF == device.y) { device.y = 0; }
if (0xFF == device.colormode) { device.colormode = 0; } // HueSat mode
}
if ((2 == channels) || (5 == channels)) {
if (0xFFFF == device.ct) { device.ct = 200; }
if (0xFF == device.colormode) { device.colormode = 2; } // CT mode
}
}
break;
}
}
// Returns the device profile or 0xFF if the device or profile is unknown
uint8_t Z_Devices::getZbProfile(uint16_t shortaddr) const {
int32_t found = findShortAddr(shortaddr); int32_t found = findShortAddr(shortaddr);
if (found >= 0) { if (found >= 0) {
return _devices[found]->bulbtype; return _devices[found]->zb_profile;
} else { } else {
return -1; // Hue not activated return 0xFF; // Hue not activated
} }
} }
// Hue support
void Z_Devices::setHueBulbtype(uint16_t shortaddr, int8_t bulbtype) {
uint8_t zb_profile = (0 > bulbtype) ? 0xFF : (bulbtype & 0x07);
setZbProfile(shortaddr, zb_profile);
}
int8_t Z_Devices::getHueBulbtype(uint16_t shortaddr) const {
uint8_t zb_profile = getZbProfile(shortaddr);
if (0x00 == (zb_profile & 0xF0)) {
return (zb_profile & 0x07);
} else {
// not a bulb
return -1;
}
}
void Z_Devices::hideHueBulb(uint16_t shortaddr, bool hidden) {
uint8_t hue_hidden_flag = hidden ? 0x08 : 0x00;
Z_Device &device = getShortAddr(shortaddr);
if (0x00 == (device.zb_profile & 0xF0)) {
// bulb type
// set bit 3 accordingly
if (hue_hidden_flag != (device.zb_profile & 0x08)) {
device.zb_profile = (device.zb_profile & 0xF7) | hue_hidden_flag;
dirty();
}
}
}
// true if device is not knwon or not a bulb - it wouldn't make sense to publish a non-bulb
bool Z_Devices::isHueBulbHidden(uint16_t shortaddr) const {
int32_t found = findShortAddr(shortaddr);
if (found >= 0) {
uint8_t zb_profile = _devices[found]->zb_profile;
if (0x00 == (zb_profile & 0xF0)) {
// bulb type
return (zb_profile & 0x08) ? true : false;
}
}
return true; // Fallback - Device is considered as hidden
}
// Hue support // Hue support
void Z_Devices::updateHueState(uint16_t shortaddr, void Z_Devices::updateHueState(uint16_t shortaddr,
const bool *power, const uint8_t *colormode, const bool *power, const uint8_t *colormode,
@ -1056,27 +1150,17 @@ String Z_Devices::dumpLightState(uint16_t shortaddr) const {
} }
// expose the last known status of the bulb, for Hue integration // expose the last known status of the bulb, for Hue integration
dev[F(D_JSON_ZIGBEE_LIGHT)] = device.bulbtype; // sign extend, 0xFF changed as -1 dev[F(D_JSON_ZIGBEE_LIGHT)] = getHueBulbtype(shortaddr); // sign extend, 0xFF changed as -1
if (0 <= device.bulbtype) { // dump all known values
// bulbtype is defined dev[F("Reachable")] = bitRead(device.power, 7); // TODO TODO
dev[F("Power")] = bitRead(device.power, 0); if (0xFF != device.power) { dev[F("Power")] = bitRead(device.power, 0); }
dev[F("Reachable")] = bitRead(device.power, 7); if (0xFF != device.dimmer) { dev[F("Dimmer")] = device.dimmer; }
if (1 <= device.bulbtype) { if (0xFF != device.colormode) { dev[F("Colormode")] = device.colormode; }
dev[F("Dimmer")] = device.dimmer; if (0xFFFF != device.ct) { dev[F("CT")] = device.ct; }
} if (0xFF != device.sat) { dev[F("Sat")] = device.sat; }
if (2 <= device.bulbtype) { if (0xFFFF != device.hue) { dev[F("Hue")] = device.hue; }
dev[F("Colormode")] = device.colormode; if (0xFFFF != device.x) { dev[F("X")] = device.x; }
} if (0xFFFF != device.y) { dev[F("Y")] = device.y; }
if ((2 == device.bulbtype) || (5 == device.bulbtype)) {
dev[F("CT")] = device.ct;
}
if (3 <= device.bulbtype) {
dev[F("Sat")] = device.sat;
dev[F("Hue")] = device.hue;
dev[F("X")] = device.x;
dev[F("Y")] = device.y;
}
}
} }
String payload = ""; String payload = "";
@ -1119,8 +1203,9 @@ String Z_Devices::dump(uint32_t dump_mode, uint16_t status_shortaddr) const {
if (device.modelId) { if (device.modelId) {
dev[F(D_JSON_MODEL D_JSON_ID)] = device.modelId; dev[F(D_JSON_MODEL D_JSON_ID)] = device.modelId;
} }
if (device.bulbtype >= 0) { int8_t bulbtype = getHueBulbtype(shortaddr);
dev[F(D_JSON_ZIGBEE_LIGHT)] = device.bulbtype; // sign extend, 0xFF changed as -1 if (bulbtype >= 0) {
dev[F(D_JSON_ZIGBEE_LIGHT)] = bulbtype; // sign extend, 0xFF changed as -1
} }
if (device.manufacturerId) { if (device.manufacturerId) {
dev[F("Manufacturer")] = device.manufacturerId; dev[F("Manufacturer")] = device.manufacturerId;

View File

@ -103,10 +103,10 @@ void ZigbeeHueStatus(String * response, uint16_t shortaddr) {
void ZigbeeCheckHue(String * response, bool &appending) { void ZigbeeCheckHue(String * response, bool &appending) {
uint32_t zigbee_num = zigbee_devices.devicesSize(); uint32_t zigbee_num = zigbee_devices.devicesSize();
for (uint32_t i = 0; i < zigbee_num; i++) { for (uint32_t i = 0; i < zigbee_num; i++) {
int8_t bulbtype = zigbee_devices.devicesAt(i).bulbtype; uint16_t shortaddr = zigbee_devices.devicesAt(i).shortaddr;
int8_t bulbtype = zigbee_devices.getHueBulbtype(shortaddr);
if (bulbtype >= 0) { if (bulbtype >= 0) {
uint16_t shortaddr = zigbee_devices.devicesAt(i).shortaddr;
// this bulb is advertized // this bulb is advertized
if (appending) { *response += ","; } if (appending) { *response += ","; }
*response += "\""; *response += "\"";
@ -122,7 +122,8 @@ void ZigbeeCheckHue(String * response, bool &appending) {
void ZigbeeHueGroups(String * lights) { void ZigbeeHueGroups(String * lights) {
uint32_t zigbee_num = zigbee_devices.devicesSize(); uint32_t zigbee_num = zigbee_devices.devicesSize();
for (uint32_t i = 0; i < zigbee_num; i++) { for (uint32_t i = 0; i < zigbee_num; i++) {
int8_t bulbtype = zigbee_devices.devicesAt(i).bulbtype; uint16_t shortaddr = zigbee_devices.devicesAt(i).shortaddr;
int8_t bulbtype = zigbee_devices.getHueBulbtype(shortaddr);
if (bulbtype >= 0) { if (bulbtype >= 0) {
*lights += ",\""; *lights += ",\"";

View File

@ -46,7 +46,7 @@
// str - FriendlyName (null terminated C string, 32 chars max) // str - FriendlyName (null terminated C string, 32 chars max)
// reserved for extensions // reserved for extensions
// -- V2 -- // -- V2 --
// int8_t - bulbtype // int8_t - zigbee profile of the device
// Memory footprint // Memory footprint
#ifdef ESP8266 #ifdef ESP8266
@ -126,8 +126,8 @@ class SBuffer hibernateDevice(const struct Z_Device &device) {
} }
buf.add8(0x00); // end of string marker buf.add8(0x00); // end of string marker
// Hue Bulbtype // Zigbee Profile
buf.add8(device.bulbtype); buf.add8(device.zb_profile);
// update overall length // update overall length
buf.set8(0, buf.len()); buf.set8(0, buf.len());
@ -225,7 +225,7 @@ void hydrateDevices(const SBuffer &buf) {
// Hue bulbtype - if present // Hue bulbtype - if present
if (d < dev_record_len) { if (d < dev_record_len) {
zigbee_devices.setHueBulbtype(shortaddr, buf_d.get8(d)); zigbee_devices.setZbProfile(shortaddr, buf_d.get8(d));
d++; d++;
} }

View File

@ -99,7 +99,7 @@ typedef struct Z_AttributeConverter {
uint8_t cluster_short; uint8_t cluster_short;
uint16_t attribute; uint16_t attribute;
const char * name; const char * name;
int16_t multiplier; // multiplier for numerical value, (if > 0 multiply by x, if <0 device by x) int8_t multiplier; // multiplier for numerical value, (if > 0 multiply by x, if <0 device by x)
uint8_t cb; // callback func from Z_ConvOperators uint8_t cb; // callback func from Z_ConvOperators
// Z_AttrConverter func; // Z_AttrConverter func;
} Z_AttributeConverter; } Z_AttributeConverter;
@ -142,10 +142,12 @@ enum Z_ConvOperators {
}; };
ZF(ZCLVersion) ZF(AppVersion) ZF(StackVersion) ZF(HWVersion) ZF(Manufacturer) ZF(ModelId) ZF(ZCLVersion) ZF(AppVersion) ZF(StackVersion) ZF(HWVersion) ZF(Manufacturer) ZF(ModelId)
ZF(DateCode) ZF(PowerSource) ZF(SWBuildID) ZF(Power) ZF(SwitchType) ZF(Dimmer) ZF(GenericDeviceClass) ZF(GenericDeviceType) ZF(ProductCode) ZF(ProductURL)
ZF(DateCode) ZF(PowerSource) ZF(SWBuildID) ZF(Power) ZF(SwitchType) ZF(Dimmer) ZF(DimmerOptions)
ZF(DimmerRemainingTime) ZF(OnOffTransitionTime) ZF(StartUpOnOff)
ZF(MainsVoltage) ZF(MainsFrequency) ZF(BatteryVoltage) ZF(BatteryPercentage) ZF(MainsVoltage) ZF(MainsFrequency) ZF(BatteryVoltage) ZF(BatteryPercentage)
ZF(CurrentTemperature) ZF(MinTempExperienced) ZF(MaxTempExperienced) ZF(OverTempTotalDwell) ZF(CurrentTemperature) ZF(MinTempExperienced) ZF(MaxTempExperienced) ZF(OverTempTotalDwell)
ZF(IdentifyTime) ZF(IdentifyTime) ZF(GroupNameSupport)
ZF(SceneCount) ZF(CurrentScene) ZF(CurrentGroup) ZF(SceneValid) ZF(SceneCount) ZF(CurrentScene) ZF(CurrentGroup) ZF(SceneValid)
ZF(AlarmCount) ZF(Time) ZF(TimeStatus) ZF(TimeZone) ZF(DstStart) ZF(DstEnd) ZF(AlarmCount) ZF(Time) ZF(TimeStatus) ZF(TimeZone) ZF(DstStart) ZF(DstEnd)
ZF(DstShift) ZF(StandardTime) ZF(LocalTime) ZF(LastSetTime) ZF(ValidUntilTime) ZF(TimeEpoch) ZF(DstShift) ZF(StandardTime) ZF(LocalTime) ZF(LastSetTime) ZF(ValidUntilTime) ZF(TimeEpoch)
@ -243,6 +245,10 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
{ Zstring, Cx0000, 0x0005, Z(ModelId), 1, Z_ModelKeep }, // record Model { Zstring, Cx0000, 0x0005, Z(ModelId), 1, Z_ModelKeep }, // record Model
{ Zstring, Cx0000, 0x0006, Z(DateCode), 1, Z_Nop }, { Zstring, Cx0000, 0x0006, Z(DateCode), 1, Z_Nop },
{ Zenum8, Cx0000, 0x0007, Z(PowerSource), 1, Z_Nop }, { Zenum8, Cx0000, 0x0007, Z(PowerSource), 1, Z_Nop },
{ Zenum8, Cx0000, 0x0008, Z(GenericDeviceClass), 1, Z_Nop },
{ Zenum8, Cx0000, 0x0009, Z(GenericDeviceType), 1, Z_Nop },
{ Zoctstr, Cx0000, 0x000A, Z(ProductCode), 1, Z_Nop },
{ Zstring, Cx0000, 0x000B, Z(ProductURL), 1, Z_Nop },
{ Zstring, Cx0000, 0x4000, Z(SWBuildID), 1, Z_Nop }, { Zstring, Cx0000, 0x4000, Z(SWBuildID), 1, Z_Nop },
// { Zunk, Cx0000, 0xFFFF, nullptr, 0, Z_Nop }, // Remove all other values // { Zunk, Cx0000, 0xFFFF, nullptr, 0, Z_Nop }, // Remove all other values
// Cmd 0x0A - Cluster 0x0000, attribute 0xFF01 - proprietary // Cmd 0x0A - Cluster 0x0000, attribute 0xFF01 - proprietary
@ -263,6 +269,9 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
// Identify cluster // Identify cluster
{ Zuint16, Cx0003, 0x0000, Z(IdentifyTime), 1, Z_Nop }, { Zuint16, Cx0003, 0x0000, Z(IdentifyTime), 1, Z_Nop },
// Groups cluster
{ Zmap8, Cx0004, 0x0000, Z(GroupNameSupport), 1, Z_Nop },
// Scenes cluster // Scenes cluster
{ Zuint8, Cx0005, 0x0000, Z(SceneCount), 1, Z_Nop }, { Zuint8, Cx0005, 0x0000, Z(SceneCount), 1, Z_Nop },
{ Zuint8, Cx0005, 0x0001, Z(CurrentScene), 1, Z_Nop }, { Zuint8, Cx0005, 0x0001, Z(CurrentScene), 1, Z_Nop },
@ -272,6 +281,7 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
// On/off cluster // On/off cluster
{ Zbool, Cx0006, 0x0000, Z(Power), 1, Z_Nop }, { Zbool, Cx0006, 0x0000, Z(Power), 1, Z_Nop },
{ Zenum8, Cx0006, 0x4003, Z(StartUpOnOff), 1, Z_Nop },
{ Zbool, Cx0006, 0x8000, Z(Power), 1, Z_Nop }, // See 7280 { Zbool, Cx0006, 0x8000, Z(Power), 1, Z_Nop }, // See 7280
// On/Off Switch Configuration cluster // On/Off Switch Configuration cluster
@ -279,12 +289,13 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
// Level Control cluster // Level Control cluster
{ Zuint8, Cx0008, 0x0000, Z(Dimmer), 1, Z_Nop }, { Zuint8, Cx0008, 0x0000, Z(Dimmer), 1, Z_Nop },
// { Zuint16, Cx0008, 0x0001, Z(RemainingTime", 1, Z_Nop }, { Zmap8, Cx0008, 0x000F, Z(DimmerOptions), 1, Z_Nop },
// { Zuint16, Cx0008, 0x0010, Z(OnOffTransitionTime", 1, Z_Nop }, { Zuint16, Cx0008, 0x0001, Z(DimmerRemainingTime), 1, Z_Nop },
// { Zuint8, Cx0008, 0x0011, Z(OnLevel", 1, Z_Nop }, { Zuint16, Cx0008, 0x0010, Z(OnOffTransitionTime), 1, Z_Nop },
// { Zuint16, Cx0008, 0x0012, Z(OnTransitionTime", 1, Z_Nop }, // { Zuint8, Cx0008, 0x0011, Z(OnLevel), 1, Z_Nop },
// { Zuint16, Cx0008, 0x0013, Z(OffTransitionTime", 1, Z_Nop }, // { Zuint16, Cx0008, 0x0012, Z(OnTransitionTime), 1, Z_Nop },
// { Zuint16, Cx0008, 0x0014, Z(DefaultMoveRate", 1, Z_Nop }, // { Zuint16, Cx0008, 0x0013, Z(OffTransitionTime), 1, Z_Nop },
// { Zuint16, Cx0008, 0x0014, Z(DefaultMoveRate), 1, Z_Nop },
// Alarms cluster // Alarms cluster
{ Zuint16, Cx0009, 0x0000, Z(AlarmCount), 1, Z_Nop }, { Zuint16, Cx0009, 0x0000, Z(AlarmCount), 1, Z_Nop },
@ -615,7 +626,7 @@ typedef union ZCLHeaderFrameControl_t {
// If not found: // If not found:
// - returns nullptr // - returns nullptr
const __FlashStringHelper* zigbeeFindAttributeByName(const char *command, const __FlashStringHelper* zigbeeFindAttributeByName(const char *command,
uint16_t *cluster, uint16_t *attribute, int16_t *multiplier, uint16_t *cluster, uint16_t *attribute, int8_t *multiplier,
uint8_t *cb) { uint8_t *cb) {
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) { for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i]; const Z_AttributeConverter *converter = &Z_PostProcess[i];
@ -623,7 +634,7 @@ const __FlashStringHelper* zigbeeFindAttributeByName(const char *command,
if (0 == strcasecmp_P(command, converter->name)) { if (0 == strcasecmp_P(command, converter->name)) {
if (cluster) { *cluster = CxToCluster(pgm_read_byte(&converter->cluster_short)); } if (cluster) { *cluster = CxToCluster(pgm_read_byte(&converter->cluster_short)); }
if (attribute) { *attribute = pgm_read_word(&converter->attribute); } if (attribute) { *attribute = pgm_read_word(&converter->attribute); }
if (multiplier) { *multiplier = pgm_read_word(&converter->multiplier); } if (multiplier) { *multiplier = pgm_read_byte(&converter->multiplier); }
if (cb) { *cb = pgm_read_byte(&converter->cb); } if (cb) { *cb = pgm_read_byte(&converter->cb); }
return (const __FlashStringHelper*) converter->name; return (const __FlashStringHelper*) converter->name;
} }
@ -1363,7 +1374,6 @@ int32_t Z_AqaraCubeFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObjec
// presentValue = x + 128 = 180º flip to side x on top // presentValue = x + 128 = 180º flip to side x on top
// presentValue = x + 256 = push/slide cube while side x is on top // presentValue = x + 256 = push/slide cube while side x is on top
// presentValue = x + 512 = double tap while side x is on top // presentValue = x + 512 = double tap while side x is on top
return 0; return 0;
} }
@ -1487,7 +1497,7 @@ int32_t Z_AqaraSensorFunc(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObj
// apply the transformation from the converter // apply the transformation from the converter
int32_t Z_ApplyConverter(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name, int32_t Z_ApplyConverter(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const String &new_name,
uint16_t cluster, uint16_t attr, int16_t multiplier, uint8_t cb) { uint16_t cluster, uint16_t attr, int8_t multiplier, uint8_t cb) {
// apply multiplier if needed // apply multiplier if needed
if (1 == multiplier) { // copy unchanged if (1 == multiplier) { // copy unchanged
json[new_name] = value; json[new_name] = value;
@ -1596,7 +1606,7 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
const Z_AttributeConverter *converter = &Z_PostProcess[i]; const Z_AttributeConverter *converter = &Z_PostProcess[i];
uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short)); uint16_t conv_cluster = CxToCluster(pgm_read_byte(&converter->cluster_short));
uint16_t conv_attribute = pgm_read_word(&converter->attribute); uint16_t conv_attribute = pgm_read_word(&converter->attribute);
int16_t conv_multiplier = pgm_read_word(&converter->multiplier); int8_t conv_multiplier = pgm_read_byte(&converter->multiplier);
uint8_t conv_cb = pgm_read_byte(&converter->cb); // callback id uint8_t conv_cb = pgm_read_byte(&converter->cb); // callback id
if ((conv_cluster == cluster) && if ((conv_cluster == cluster) &&

View File

@ -190,7 +190,7 @@ void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint,
// multiplier == 1: ignore // multiplier == 1: ignore
// multiplier > 0: divide by the multiplier // multiplier > 0: divide by the multiplier
// multiplier < 0: multiply by the -multiplier (positive) // multiplier < 0: multiply by the -multiplier (positive)
void ZbApplyMultiplier(double &val_d, int16_t multiplier) { void ZbApplyMultiplier(double &val_d, int8_t multiplier) {
if ((0 != multiplier) && (1 != multiplier)) { if ((0 != multiplier) && (1 != multiplier)) {
if (multiplier > 0) { // inverse of decoding if (multiplier > 0) { // inverse of decoding
val_d = val_d / multiplier; val_d = val_d / multiplier;
@ -217,7 +217,7 @@ void ZbSendReportWrite(const JsonObject &val_pubwrite, uint16_t device, uint16_t
uint16_t attr_id = 0xFFFF; uint16_t attr_id = 0xFFFF;
uint16_t cluster_id = 0xFFFF; uint16_t cluster_id = 0xFFFF;
uint8_t type_id = Znodata; uint8_t type_id = Znodata;
int16_t multiplier = 1; // multiplier to adjust the key value int8_t multiplier = 1; // multiplier to adjust the key value
double val_d = 0; // I try to avoid `double` but this type capture both float and (u)int32_t without prevision loss double val_d = 0; // I try to avoid `double` but this type capture both float and (u)int32_t without prevision loss
const char* val_str = ""; // variant as string const char* val_str = ""; // variant as string
@ -245,7 +245,7 @@ void ZbSendReportWrite(const JsonObject &val_pubwrite, uint16_t device, uint16_t
uint16_t local_attr_id = pgm_read_word(&converter->attribute); uint16_t local_attr_id = pgm_read_word(&converter->attribute);
uint16_t local_cluster_id = CxToCluster(pgm_read_byte(&converter->cluster_short)); uint16_t local_cluster_id = CxToCluster(pgm_read_byte(&converter->cluster_short));
uint8_t local_type_id = pgm_read_byte(&converter->type); uint8_t local_type_id = pgm_read_byte(&converter->type);
int16_t local_multiplier = pgm_read_word(&converter->multiplier); int8_t local_multiplier = pgm_read_byte(&converter->multiplier);
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Try cluster = 0x%04X, attr = 0x%04X, type_id = 0x%02X"), local_cluster_id, local_attr_id, local_type_id); // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Try cluster = 0x%04X, attr = 0x%04X, type_id = 0x%02X"), local_cluster_id, local_attr_id, local_type_id);
if (delimiter) { if (delimiter) {