Merge pull request #9504 from s-hadinger/zigbee_oct_9

Zigbee code optimization
This commit is contained in:
s-hadinger 2020-10-09 19:33:09 +02:00 committed by GitHub
commit f3f8f52317
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 673 additions and 607 deletions

View File

@ -49,6 +49,8 @@ public:
inline uint8_t getEndpoint(void) const { return _endpoint; }
void toAttributes(Z_attribute_list & attr_list, Z_Data_Type type) const;
static const Z_Data_Type type = Z_Data_Type::Z_Unknown;
friend class Z_Data_Set;
@ -73,12 +75,11 @@ public:
_config = 1; // at least 1 OnOff
}
inline bool validPower(uint32_t relay = 0) const { return (_config > relay); } // power is declared
inline bool getPower(uint32_t relay = 0) const { return bitRead(_power, relay); }
void setPower(bool val, uint32_t relay = 0);
static void toAttributes(Z_attribute_list & attr_list, const Z_Data_OnOff & light);
void toAttributes(Z_attribute_list & attr_list, Z_Data_Type type) const;
static const Z_Data_Type type = Z_Data_Type::Z_OnOff;
};
@ -111,8 +112,6 @@ public:
inline void setMainsVoltage(uint16_t _mains_voltage) { mains_voltage = _mains_voltage; }
inline void setMainsPower(int16_t _mains_power) { mains_power = _mains_power; }
static void toAttributes(Z_attribute_list & attr_list, const Z_Data_Plug & light);
static const Z_Data_Type type = Z_Data_Type::Z_Plug;
// 4 bytes
uint16_t mains_voltage; // AC voltage
@ -159,7 +158,7 @@ public:
inline void setX(uint16_t _x) { x = _x; }
inline void setY(uint16_t _y) { y = _y; }
static void toAttributes(Z_attribute_list & attr_list, const Z_Data_Light & light);
void toAttributes(Z_attribute_list & attr_list, Z_Data_Type type) const;
static const Z_Data_Type type = Z_Data_Type::Z_Light;
// 12 bytes
@ -179,37 +178,35 @@ public:
Z_Data_Thermo(uint8_t endpoint = 0) :
Z_Data(Z_Data_Type::Z_Thermo, endpoint),
temperature(-0x8000),
pressure(0xFFFF),
pressure(-0x8000),
humidity(0xFFFF),
th_setpoint(0xFF),
temperature_target(-0x8000)
{}
inline bool validTemperature(void) const { return -0x8000 != temperature; }
inline bool validPressure(void) const { return 0xFFFF != pressure; }
inline bool validPressure(void) const { return -0x8000 != pressure; }
inline bool validHumidity(void) const { return 0xFFFF != humidity; }
inline bool validThSetpoint(void) const { return 0xFF != th_setpoint; }
inline bool validTempTarget(void) const { return -0x8000 != temperature_target; }
inline int16_t getTemperature(void) const { return temperature; }
inline uint16_t getPressure(void) const { return pressure; }
inline int16_t getPressure(void) const { return pressure; }
inline uint16_t getHumidity(void) const { return humidity; }
inline uint8_t getThSetpoint(void) const { return th_setpoint; }
inline int16_t getTempTarget(void) const { return temperature_target; }
inline void setTemperature(int16_t _temperature) { temperature = _temperature; }
inline void setPressure(uint16_t _pressure) { pressure = _pressure; }
inline void setPressure(int16_t _pressure) { pressure = _pressure; }
inline void setHumidity(uint16_t _humidity) { humidity = _humidity; }
inline void setThSetpoint(uint8_t _th_setpoint) { th_setpoint = _th_setpoint; }
inline void setTempTarget(int16_t _temperature_target){ temperature_target = _temperature_target; }
static void toAttributes(Z_attribute_list & attr_list, const Z_Data_Thermo & thermo);
static const Z_Data_Type type = Z_Data_Type::Z_Thermo;
// 8 bytes
// sensor data
int16_t temperature; // temperature in 1/10th of Celsius, 0x8000 if unknown
uint16_t pressure; // air pressure in hPa, 0xFFFF if unknown
int16_t pressure; // air pressure in hPa, 0xFFFF if unknown
uint16_t humidity; // humidity in percent, 0..100, 0xFF if unknown
// thermostat
uint8_t th_setpoint; // percentage of heat/cool in percent
@ -234,8 +231,6 @@ public:
inline void setZoneType(uint16_t _zone_type) { zone_type = _zone_type; }
static void toAttributes(Z_attribute_list & attr_list, const Z_Data_Alarm & alarm);
// 4 bytes
uint16_t zone_type; // mapped to the Zigbee standard
// 0x0000 Standard CIE
@ -335,49 +330,18 @@ const Z_Data & Z_Data_Set::find(Z_Data_Type type, uint8_t ep) const {
return *(Z_Data*)nullptr;
}
// Low-level
// Add light attributes, used by dumpLightState and by SbData
//
void Z_Data_Plug::toAttributes(Z_attribute_list & attr_list, const Z_Data_Plug & plug) {
if (&plug == nullptr) { return; }
// dump all known values
if (plug.validMainsVoltage()) { attr_list.addAttribute(PSTR("RMSVoltage")).setUInt(plug.getMainsVoltage()); }
if (plug.validMainsPower()) { attr_list.addAttribute(PSTR("ActivePower")).setInt(plug.getMainsPower()); }
void Z_Data_Light::toAttributes(Z_attribute_list & attr_list, Z_Data_Type type) const {
attr_list.addAttribute(PSTR(D_JSON_ZIGBEE_LIGHT)).setInt(getConfig()); // special case, since type is 0x00 we can assume getConfig() is good
Z_Data::toAttributes(attr_list, type);
}
void Z_Data_Light::toAttributes(Z_attribute_list & attr_list, const Z_Data_Light & light) {
if (&light == nullptr) { return; }
// expose the last known status of the bulb, for Hue integration
attr_list.addAttribute(PSTR(D_JSON_ZIGBEE_LIGHT)).setInt(light.getConfig()); // special case, since type is 0x00 we can assume getConfig() is good
// dump all known values
if (light.validDimmer()) { attr_list.addAttribute(PSTR("Dimmer")).setUInt(light.getDimmer()); }
if (light.validColormode()) { attr_list.addAttribute(PSTR("Colormode")).setUInt(light.getColorMode()); }
if (light.validCT()) { attr_list.addAttribute(PSTR("CT")).setUInt(light.getCT()); }
if (light.validSat()) { attr_list.addAttribute(PSTR("Sat")).setUInt(light.getSat()); }
if (light.validHue()) { attr_list.addAttribute(PSTR("Hue")).setUInt(light.getHue()); }
if (light.validX()) { attr_list.addAttribute(PSTR("X")).setUInt(light.getX()); }
if (light.validY()) { attr_list.addAttribute(PSTR("Y")).setUInt(light.getY()); }
void Z_Data_OnOff::toAttributes(Z_attribute_list & attr_list, Z_Data_Type type) const {
if (validPower()) { attr_list.addAttribute(PSTR("Power")).setUInt(getPower() ? 1 : 0); }
}
void Z_Data_OnOff::toAttributes(Z_attribute_list & attr_list, const Z_Data_OnOff & onoff) {
if (&onoff == nullptr) { return; }
if (onoff.validPower()) { attr_list.addAttribute(PSTR("Power")).setUInt(onoff.getPower() ? 1 : 0); }
}
void Z_Data_Thermo::toAttributes(Z_attribute_list & attr_list, const Z_Data_Thermo & thermo) {
if (&thermo == nullptr) { return; }
if (thermo.validTemperature()) { attr_list.addAttribute(PSTR("Temperature")).setInt(thermo.getTemperature()); }
if (thermo.validPressure()) { attr_list.addAttribute(PSTR("Pressure")).setUInt(thermo.getPressure()); }
if (thermo.validHumidity()) { attr_list.addAttribute(PSTR("Humidity")).setUInt(thermo.getHumidity()); }
if (thermo.validThSetpoint()) { attr_list.addAttribute(PSTR("ThSetpoint")).setUInt(thermo.getThSetpoint()); }
if (thermo.validTempTarget()) { attr_list.addAttribute(PSTR("TempTarget")).setInt(thermo.getTempTarget()); }
}
void Z_Data_Alarm::toAttributes(Z_attribute_list & attr_list, const Z_Data_Alarm & alarm) {
if (&alarm == nullptr) { return; }
if (alarm.validZoneType()) { attr_list.addAttribute(PSTR("ZoneType")).setUInt(alarm.getZoneType()); }
}
/*********************************************************************************************\
* Structures for Rules variables related to the last received message
@ -678,6 +642,4 @@ Z_Devices zigbee_devices = Z_Devices();
uint64_t localIEEEAddr = 0;
uint16_t localShortAddr = 0;
#endif // USE_ZIGBEE

View File

@ -626,7 +626,15 @@ String Z_Devices::dumpLightState(uint16_t shortaddr) const {
// dump all known values
attr_list.addAttribute(F("Reachable")).setBool(device.getReachable());
if (device.validPower()) { attr_list.addAttribute(F("Power")).setUInt(device.getPower()); }
Z_Data_Light::toAttributes(attr_list, device.data.find<Z_Data_Light>(0));
const Z_Data_Light & light = device.data.find<Z_Data_Light>(0);
if (&light != nullptr) {
light.toAttributes(attr_list, Z_Data_Light::type);
// Exception, we need to convert Hue to 0..360 instead of 0..254
if (light.validHue()) {
attr_list.findOrCreateAttribute(PSTR("Hue")).setUInt(light.getHue());
}
}
// Z_Data_Light::toAttributes(attr_list, device.data.find<Z_Data_Light>(0));
}
Z_attribute_list attr_list_root;

View File

@ -275,6 +275,8 @@ const char Z_strings[] PROGMEM =
"SetValvePosition" "\x00"
"EurotronicErrors" "\x00"
"CurrentTemperatureSetPoint" "\x00"
"ThSetpoint" "\x00"
"TempTarget" "\x00"
"Hue" "\x00"
"Sat" "\x00"
"RemainingTime" "\x00"
@ -652,179 +654,181 @@ enum Z_offsets {
Zo_SetValvePosition = 3473,
Zo_EurotronicErrors = 3490,
Zo_CurrentTemperatureSetPoint = 3507,
Zo_Hue = 3534,
Zo_Sat = 3538,
Zo_RemainingTime = 3542,
Zo_X = 3556,
Zo_Y = 3558,
Zo_DriftCompensation = 3560,
Zo_CompensationText = 3578,
Zo_CT = 3595,
Zo_ColorMode = 3598,
Zo_NumberOfPrimaries = 3608,
Zo_Primary1X = 3626,
Zo_Primary1Y = 3636,
Zo_Primary1Intensity = 3646,
Zo_Primary2X = 3664,
Zo_Primary2Y = 3674,
Zo_Primary2Intensity = 3684,
Zo_Primary3X = 3702,
Zo_Primary3Y = 3712,
Zo_Primary3Intensity = 3722,
Zo_WhitePointX = 3740,
Zo_WhitePointY = 3752,
Zo_ColorPointRX = 3764,
Zo_ColorPointRY = 3777,
Zo_ColorPointRIntensity = 3790,
Zo_ColorPointGX = 3811,
Zo_ColorPointGY = 3824,
Zo_ColorPointGIntensity = 3837,
Zo_ColorPointBX = 3858,
Zo_ColorPointBY = 3871,
Zo_ColorPointBIntensity = 3884,
Zo_Illuminance = 3905,
Zo_IlluminanceMinMeasuredValue = 3917,
Zo_IlluminanceMaxMeasuredValue = 3945,
Zo_IlluminanceTolerance = 3973,
Zo_IlluminanceLightSensorType = 3994,
Zo_IlluminanceLevelStatus = 4021,
Zo_IlluminanceTargetLevel = 4044,
Zo_Temperature = 4067,
Zo_TemperatureMinMeasuredValue = 4079,
Zo_TemperatureMaxMeasuredValue = 4107,
Zo_TemperatureTolerance = 4135,
Zo_Pressure = 4156,
Zo_PressureMinMeasuredValue = 4165,
Zo_PressureMaxMeasuredValue = 4190,
Zo_PressureTolerance = 4215,
Zo_PressureScaledValue = 4233,
Zo_PressureMinScaledValue = 4253,
Zo_PressureMaxScaledValue = 4276,
Zo_PressureScaledTolerance = 4299,
Zo_PressureScale = 4323,
Zo_SeaPressure = 4337,
Zo_FlowRate = 4349,
Zo_FlowMinMeasuredValue = 4358,
Zo_FlowMaxMeasuredValue = 4379,
Zo_FlowTolerance = 4400,
Zo_Humidity = 4414,
Zo_HumidityMinMeasuredValue = 4423,
Zo_HumidityMaxMeasuredValue = 4448,
Zo_HumidityTolerance = 4473,
Zo_Occupancy = 4491,
Zo_OccupancySensorType = 4501,
Zo_ZoneState = 4521,
Zo_ZoneType = 4531,
Zo_ZoneStatus = 4540,
Zo_CurrentSummDelivered = 4551,
Zo_CompanyName = 4572,
Zo_MeterTypeID = 4584,
Zo_DataQualityID = 4596,
Zo_CustomerName = 4610,
Zo_Model = 4623,
Zo_PartNumber = 4629,
Zo_ProductRevision = 4640,
Zo_SoftwareRevision = 4656,
Zo_UtilityName = 4673,
Zo_POD = 4685,
Zo_AvailablePower = 4689,
Zo_PowerThreshold = 4704,
Zo_RMSVoltage = 4719,
Zo_RMSCurrent = 4730,
Zo_ActivePower = 4741,
Zo_NumberOfResets = 4753,
Zo_PersistentMemoryWrites = 4768,
Zo_LastMessageLQI = 4791,
Zo_LastMessageRSSI = 4806,
Zo_Identify = 4822,
Zo_xxxx = 4831,
Zo_IdentifyQuery = 4836,
Zo_AddGroup = 4850,
Zo_xxxx00 = 4859,
Zo_ViewGroup = 4866,
Zo_GetGroup = 4876,
Zo_01xxxx = 4885,
Zo_GetAllGroups = 4892,
Zo_00 = 4905,
Zo_RemoveGroup = 4908,
Zo_RemoveAllGroups = 4920,
Zo_ViewScene = 4936,
Zo_xxxxyy = 4946,
Zo_RemoveScene = 4953,
Zo_RemoveAllScenes = 4965,
Zo_RecallScene = 4981,
Zo_GetSceneMembership = 4993,
Zo_PowerOffEffect = 5012,
Zo_xxyy = 5027,
Zo_PowerOnRecall = 5032,
Zo_PowerOnTimer = 5046,
Zo_xxyyyyzzzz = 5059,
Zo_xx0A00 = 5070,
Zo_DimmerUp = 5077,
Zo_00190200 = 5086,
Zo_DimmerDown = 5095,
Zo_01190200 = 5106,
Zo_DimmerStop = 5115,
Zo_ResetAlarm = 5126,
Zo_xxyyyy = 5137,
Zo_ResetAllAlarms = 5144,
Zo_xx000A00 = 5159,
Zo_HueSat = 5168,
Zo_xxyy0A00 = 5175,
Zo_Color = 5184,
Zo_xxxxyyyy0A00 = 5190,
Zo_xxxx0A00 = 5203,
Zo_ShutterOpen = 5212,
Zo_ShutterClose = 5224,
Zo_ShutterStop = 5237,
Zo_ShutterLift = 5249,
Zo_xx = 5261,
Zo_ShutterTilt = 5264,
Zo_Shutter = 5276,
Zo_DimmerMove = 5284,
Zo_xx0A = 5295,
Zo_DimmerStepUp = 5300,
Zo_00xx0A00 = 5313,
Zo_DimmerStepDown = 5322,
Zo_01xx0A00 = 5337,
Zo_DimmerStep = 5346,
Zo_xx190A00 = 5357,
Zo_01 = 5366,
Zo_HueMove = 5369,
Zo_xx19 = 5377,
Zo_HueStepUp = 5382,
Zo_HueStepDown = 5392,
Zo_03xx0A00 = 5404,
Zo_HueStep = 5413,
Zo_SatMove = 5421,
Zo_SatStep = 5429,
Zo_xx190A = 5437,
Zo_ColorMove = 5444,
Zo_xxxxyyyy = 5454,
Zo_ColorStep = 5463,
Zo_ColorTempMoveUp = 5473,
Zo_01xxxx000000000000 = 5489,
Zo_ColorTempMoveDown = 5508,
Zo_03xxxx000000000000 = 5526,
Zo_ColorTempMoveStop = 5545,
Zo_00xxxx000000000000 = 5563,
Zo_ColorTempMove = 5582,
Zo_xxyyyy000000000000 = 5596,
Zo_ColorTempStepUp = 5615,
Zo_01xxxx0A0000000000 = 5631,
Zo_ColorTempStepDown = 5650,
Zo_03xxxx0A0000000000 = 5668,
Zo_ColorTempStep = 5687,
Zo_xxyyyy0A0000000000 = 5701,
Zo_ArrowClick = 5720,
Zo_ArrowHold = 5731,
Zo_ArrowRelease = 5741,
Zo_ZoneStatusChange = 5754,
Zo_xxxxyyzz = 5771,
Zo_xxyyzzzz = 5780,
Zo_AddScene = 5789,
Zo_xxyyyyzz = 5798,
Zo_StoreScene = 5807,
Zo_ThSetpoint = 3534,
Zo_TempTarget = 3545,
Zo_Hue = 3556,
Zo_Sat = 3560,
Zo_RemainingTime = 3564,
Zo_X = 3578,
Zo_Y = 3580,
Zo_DriftCompensation = 3582,
Zo_CompensationText = 3600,
Zo_CT = 3617,
Zo_ColorMode = 3620,
Zo_NumberOfPrimaries = 3630,
Zo_Primary1X = 3648,
Zo_Primary1Y = 3658,
Zo_Primary1Intensity = 3668,
Zo_Primary2X = 3686,
Zo_Primary2Y = 3696,
Zo_Primary2Intensity = 3706,
Zo_Primary3X = 3724,
Zo_Primary3Y = 3734,
Zo_Primary3Intensity = 3744,
Zo_WhitePointX = 3762,
Zo_WhitePointY = 3774,
Zo_ColorPointRX = 3786,
Zo_ColorPointRY = 3799,
Zo_ColorPointRIntensity = 3812,
Zo_ColorPointGX = 3833,
Zo_ColorPointGY = 3846,
Zo_ColorPointGIntensity = 3859,
Zo_ColorPointBX = 3880,
Zo_ColorPointBY = 3893,
Zo_ColorPointBIntensity = 3906,
Zo_Illuminance = 3927,
Zo_IlluminanceMinMeasuredValue = 3939,
Zo_IlluminanceMaxMeasuredValue = 3967,
Zo_IlluminanceTolerance = 3995,
Zo_IlluminanceLightSensorType = 4016,
Zo_IlluminanceLevelStatus = 4043,
Zo_IlluminanceTargetLevel = 4066,
Zo_Temperature = 4089,
Zo_TemperatureMinMeasuredValue = 4101,
Zo_TemperatureMaxMeasuredValue = 4129,
Zo_TemperatureTolerance = 4157,
Zo_Pressure = 4178,
Zo_PressureMinMeasuredValue = 4187,
Zo_PressureMaxMeasuredValue = 4212,
Zo_PressureTolerance = 4237,
Zo_PressureScaledValue = 4255,
Zo_PressureMinScaledValue = 4275,
Zo_PressureMaxScaledValue = 4298,
Zo_PressureScaledTolerance = 4321,
Zo_PressureScale = 4345,
Zo_SeaPressure = 4359,
Zo_FlowRate = 4371,
Zo_FlowMinMeasuredValue = 4380,
Zo_FlowMaxMeasuredValue = 4401,
Zo_FlowTolerance = 4422,
Zo_Humidity = 4436,
Zo_HumidityMinMeasuredValue = 4445,
Zo_HumidityMaxMeasuredValue = 4470,
Zo_HumidityTolerance = 4495,
Zo_Occupancy = 4513,
Zo_OccupancySensorType = 4523,
Zo_ZoneState = 4543,
Zo_ZoneType = 4553,
Zo_ZoneStatus = 4562,
Zo_CurrentSummDelivered = 4573,
Zo_CompanyName = 4594,
Zo_MeterTypeID = 4606,
Zo_DataQualityID = 4618,
Zo_CustomerName = 4632,
Zo_Model = 4645,
Zo_PartNumber = 4651,
Zo_ProductRevision = 4662,
Zo_SoftwareRevision = 4678,
Zo_UtilityName = 4695,
Zo_POD = 4707,
Zo_AvailablePower = 4711,
Zo_PowerThreshold = 4726,
Zo_RMSVoltage = 4741,
Zo_RMSCurrent = 4752,
Zo_ActivePower = 4763,
Zo_NumberOfResets = 4775,
Zo_PersistentMemoryWrites = 4790,
Zo_LastMessageLQI = 4813,
Zo_LastMessageRSSI = 4828,
Zo_Identify = 4844,
Zo_xxxx = 4853,
Zo_IdentifyQuery = 4858,
Zo_AddGroup = 4872,
Zo_xxxx00 = 4881,
Zo_ViewGroup = 4888,
Zo_GetGroup = 4898,
Zo_01xxxx = 4907,
Zo_GetAllGroups = 4914,
Zo_00 = 4927,
Zo_RemoveGroup = 4930,
Zo_RemoveAllGroups = 4942,
Zo_ViewScene = 4958,
Zo_xxxxyy = 4968,
Zo_RemoveScene = 4975,
Zo_RemoveAllScenes = 4987,
Zo_RecallScene = 5003,
Zo_GetSceneMembership = 5015,
Zo_PowerOffEffect = 5034,
Zo_xxyy = 5049,
Zo_PowerOnRecall = 5054,
Zo_PowerOnTimer = 5068,
Zo_xxyyyyzzzz = 5081,
Zo_xx0A00 = 5092,
Zo_DimmerUp = 5099,
Zo_00190200 = 5108,
Zo_DimmerDown = 5117,
Zo_01190200 = 5128,
Zo_DimmerStop = 5137,
Zo_ResetAlarm = 5148,
Zo_xxyyyy = 5159,
Zo_ResetAllAlarms = 5166,
Zo_xx000A00 = 5181,
Zo_HueSat = 5190,
Zo_xxyy0A00 = 5197,
Zo_Color = 5206,
Zo_xxxxyyyy0A00 = 5212,
Zo_xxxx0A00 = 5225,
Zo_ShutterOpen = 5234,
Zo_ShutterClose = 5246,
Zo_ShutterStop = 5259,
Zo_ShutterLift = 5271,
Zo_xx = 5283,
Zo_ShutterTilt = 5286,
Zo_Shutter = 5298,
Zo_DimmerMove = 5306,
Zo_xx0A = 5317,
Zo_DimmerStepUp = 5322,
Zo_00xx0A00 = 5335,
Zo_DimmerStepDown = 5344,
Zo_01xx0A00 = 5359,
Zo_DimmerStep = 5368,
Zo_xx190A00 = 5379,
Zo_01 = 5388,
Zo_HueMove = 5391,
Zo_xx19 = 5399,
Zo_HueStepUp = 5404,
Zo_HueStepDown = 5414,
Zo_03xx0A00 = 5426,
Zo_HueStep = 5435,
Zo_SatMove = 5443,
Zo_SatStep = 5451,
Zo_xx190A = 5459,
Zo_ColorMove = 5466,
Zo_xxxxyyyy = 5476,
Zo_ColorStep = 5485,
Zo_ColorTempMoveUp = 5495,
Zo_01xxxx000000000000 = 5511,
Zo_ColorTempMoveDown = 5530,
Zo_03xxxx000000000000 = 5548,
Zo_ColorTempMoveStop = 5567,
Zo_00xxxx000000000000 = 5585,
Zo_ColorTempMove = 5604,
Zo_xxyyyy000000000000 = 5618,
Zo_ColorTempStepUp = 5637,
Zo_01xxxx0A0000000000 = 5653,
Zo_ColorTempStepDown = 5672,
Zo_03xxxx0A0000000000 = 5690,
Zo_ColorTempStep = 5709,
Zo_xxyyyy0A0000000000 = 5723,
Zo_ArrowClick = 5742,
Zo_ArrowHold = 5753,
Zo_ArrowRelease = 5763,
Zo_ZoneStatusChange = 5776,
Zo_xxxxyyzz = 5793,
Zo_xxyyzzzz = 5802,
Zo_AddScene = 5811,
Zo_xxyyyyzz = 5820,
Zo_StoreScene = 5829,
};

View File

@ -95,7 +95,9 @@ typedef struct Z_AttributeConverter {
uint8_t cluster_short;
uint16_t attribute;
uint16_t name_offset;
int8_t multiplier; // multiplier for numerical value, (if > 0 multiply by x, if <0 device by x)
uint8_t multiplier_idx; // multiplier index for numerical value, use CmToMultiplier(), (if > 0 multiply by x, if <0 device by x)
// the high 4 bits are used to encode flags
// currently: 0x80 = this parameter needs to be exported to ZbData
uint8_t mapping; // high 4 bits = type, low 4 bits = offset in bytes from header
// still room for a byte
} Z_AttributeConverter;
@ -105,6 +107,10 @@ typedef struct Z_AttributeConverter {
#define Z_CLASS(c) c // necessary to get a valid token without concatenation (which wouldn't work)
#define Z_MAPPING(c,a) (((((uint8_t)Z_CLASS(c)::type) & 0x0F) << 4) | Z_OFFSET(c,a))
// lines with this marker, will be used to export automatically data to `ZbData`
// at the condition Z_MAPPING() is also used
const uint8_t Z_EXPORT_DATA = 0x80;
// Cluster numbers are store in 8 bits format to save space,
// the following tables allows the conversion from 8 bits index Cx...
// to the 16 bits actual cluster number
@ -132,7 +138,7 @@ uint16_t CxToCluster(uint8_t cx) {
}
uint8_t ClusterToCx(uint16_t cluster) {
for (uint8_t i=0; i<ARRAY_SIZE(Cx_cluster); i++) {
for (uint32_t i=0; i<ARRAY_SIZE(Cx_cluster); i++) {
if (pgm_read_word(&Cx_cluster[i]) == cluster) {
return i;
}
@ -140,413 +146,437 @@ uint8_t ClusterToCx(uint16_t cluster) {
return 0xFF;
}
// Multiplier contains only a limited set of values, so instead of storing the value
// we store an index in a table, and reduce it to 4 bits
enum Cm_multiplier_nibble {
Cm0 = 0, Cm1 = 1, Cm2, Cm5, Cm10, Cm100,
// negative numbers
Cm_2, Cm_5, Cm_10, Cm_100
};
const int8_t Cm_multiplier[] PROGMEM = {
0, 1, 2, 5, 10, 100,
-2, -5, -10, -100,
};
int8_t CmToMultiplier(uint8_t cm) {
cm = cm & 0x0F; // get only low nibble
if (cm < ARRAY_SIZE(Cm_multiplier)) {
return pgm_read_byte(&Cm_multiplier[cm]);
}
return 1;
}
// list of post-processing directives
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof" // avoid warnings since we're using offsetof() in a risky way
const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
{ Zuint8, Cx0000, 0x0000, Z_(ZCLVersion), 1, 0 },
{ Zuint8, Cx0000, 0x0001, Z_(AppVersion), 1, 0 },
{ Zuint8, Cx0000, 0x0002, Z_(StackVersion), 1, 0 },
{ Zuint8, Cx0000, 0x0003, Z_(HWVersion), 1, 0 },
{ Zstring, Cx0000, 0x0004, Z_(Manufacturer), 1, 0 }, // record Manufacturer
{ Zstring, Cx0000, 0x0005, Z_(ModelId), 1, 0 }, // record Model
// { Zstring, Cx0000, 0x0004, Z_(Manufacturer), 1, Z_ManufKeep, 0 }, // record Manufacturer
// { Zstring, Cx0000, 0x0005, Z_(ModelId), 1, Z_ModelKeep, 0 }, // record Model
{ Zstring, Cx0000, 0x0006, Z_(DateCode), 1, 0 },
{ Zenum8, Cx0000, 0x0007, Z_(PowerSource), 1, 0 },
{ Zenum8, Cx0000, 0x0008, Z_(GenericDeviceClass), 1, 0 },
{ Zenum8, Cx0000, 0x0009, Z_(GenericDeviceType), 1, 0 },
{ Zoctstr, Cx0000, 0x000A, Z_(ProductCode), 1, 0 },
{ Zstring, Cx0000, 0x000B, Z_(ProductURL), 1, 0 },
{ Zstring, Cx0000, 0x4000, Z_(SWBuildID), 1, 0 },
// { Zunk, Cx0000, 0xFFFF, nullptr, 0, 0 }, // Remove all other values
{ Zuint8, Cx0000, 0x0000, Z_(ZCLVersion), Cm1, 0 },
{ Zuint8, Cx0000, 0x0001, Z_(AppVersion), Cm1, 0 },
{ Zuint8, Cx0000, 0x0002, Z_(StackVersion), Cm1, 0 },
{ Zuint8, Cx0000, 0x0003, Z_(HWVersion), Cm1, 0 },
{ Zstring, Cx0000, 0x0004, Z_(Manufacturer), Cm1, 0 }, // record Manufacturer
{ Zstring, Cx0000, 0x0005, Z_(ModelId), Cm1, 0 }, // record Model
// { Zstring, Cx0000, 0x0004, Z_(Manufacturer), Cm1, Z_ManufKeep, 0 }, // record Manufacturer
// { Zstring, Cx0000, 0x0005, Z_(ModelId), Cm1, Z_ModelKeep, 0 }, // record Model
{ Zstring, Cx0000, 0x0006, Z_(DateCode), Cm1, 0 },
{ Zenum8, Cx0000, 0x0007, Z_(PowerSource), Cm1, 0 },
{ Zenum8, Cx0000, 0x0008, Z_(GenericDeviceClass), Cm1, 0 },
{ Zenum8, Cx0000, 0x0009, Z_(GenericDeviceType), Cm1, 0 },
{ Zoctstr, Cx0000, 0x000A, Z_(ProductCode), Cm1, 0 },
{ Zstring, Cx0000, 0x000B, Z_(ProductURL), Cm1, 0 },
{ Zstring, Cx0000, 0x4000, Z_(SWBuildID), Cm1, 0 },
// { Zunk, Cx0000, 0xFFFF, nullptr, Cm0, 0 }, // Remove all other values
// Cmd 0x0A - Cluster 0x0000, attribute 0xFF01 - proprietary
{ Zmap8, Cx0000, 0xFF01, Z_(), 0, 0 },
{ Zmap8, Cx0000, 0xFF02, Z_(), 0, 0 },
// { Zmap8, Cx0000, 0xFF01, Z_(), 0, Z_AqaraSensor, 0 },
// { Zmap8, Cx0000, 0xFF02, Z_(), 0, Z_AqaraSensor2, 0 },
{ Zmap8, Cx0000, 0xFF01, Z_(), Cm0, 0 },
{ Zmap8, Cx0000, 0xFF02, Z_(), Cm0, 0 },
// { Zmap8, Cx0000, 0xFF01, Z_(), Cm0, Z_AqaraSensor, 0 },
// { Zmap8, Cx0000, 0xFF02, Z_(), Cm0, Z_AqaraSensor2, 0 },
// Power Configuration cluster
{ Zuint16, Cx0001, 0x0000, Z_(MainsVoltage), 1, 0 },
{ Zuint8, Cx0001, 0x0001, Z_(MainsFrequency), 1, 0 },
{ Zuint8, Cx0001, 0x0020, Z_(BatteryVoltage), -10, 0 }, // divide by 10
{ Zuint8, Cx0001, 0x0021, Z_(BatteryPercentage), -2, 0 }, // divide by 2
// { Zuint8, Cx0001, 0x0021, Z_(BatteryPercentage), -2, Z_BatteryPercentage, 0 }, // divide by 2
{ Zuint16, Cx0001, 0x0000, Z_(MainsVoltage), Cm1, 0 },
{ Zuint8, Cx0001, 0x0001, Z_(MainsFrequency), Cm1, 0 },
{ Zuint8, Cx0001, 0x0020, Z_(BatteryVoltage), Cm_10, 0 }, // divide by 10
{ Zuint8, Cx0001, 0x0021, Z_(BatteryPercentage), Cm_2, 0 }, // divide by 2
// { Zuint8, Cx0001, 0x0021, Z_(BatteryPercentage), Cm_2, Z_BatteryPercentage, 0 }, // divide by 2
// Device Temperature Configuration cluster
{ Zint16, Cx0002, 0x0000, Z_(CurrentTemperature), 1, 0 },
{ Zint16, Cx0002, 0x0001, Z_(MinTempExperienced), 1, 0 },
{ Zint16, Cx0002, 0x0002, Z_(MaxTempExperienced), 1, 0 },
{ Zuint16, Cx0002, 0x0003, Z_(OverTempTotalDwell), 1, 0 },
{ Zint16, Cx0002, 0x0000, Z_(CurrentTemperature), Cm1, 0 },
{ Zint16, Cx0002, 0x0001, Z_(MinTempExperienced), Cm1, 0 },
{ Zint16, Cx0002, 0x0002, Z_(MaxTempExperienced), Cm1, 0 },
{ Zuint16, Cx0002, 0x0003, Z_(OverTempTotalDwell), Cm1, 0 },
// Identify cluster
{ Zuint16, Cx0003, 0x0000, Z_(IdentifyTime), 1, 0 },
{ Zuint16, Cx0003, 0x0000, Z_(IdentifyTime), Cm1, 0 },
// Groups cluster
{ Zmap8, Cx0004, 0x0000, Z_(GroupNameSupport), 1, 0 },
{ Zmap8, Cx0004, 0x0000, Z_(GroupNameSupport), Cm1, 0 },
// Scenes cluster
{ Zuint8, Cx0005, 0x0000, Z_(SceneCount), 1, 0 },
{ Zuint8, Cx0005, 0x0001, Z_(CurrentScene), 1, 0 },
{ Zuint16, Cx0005, 0x0002, Z_(CurrentGroup), 1, 0 },
{ Zbool, Cx0005, 0x0003, Z_(SceneValid), 1, 0 },
//{ Zmap8, Cx0005, 0x0004, (NameSupport), 1, 0 },
{ Zuint8, Cx0005, 0x0000, Z_(SceneCount), Cm1, 0 },
{ Zuint8, Cx0005, 0x0001, Z_(CurrentScene), Cm1, 0 },
{ Zuint16, Cx0005, 0x0002, Z_(CurrentGroup), Cm1, 0 },
{ Zbool, Cx0005, 0x0003, Z_(SceneValid), Cm1, 0 },
//{ Zmap8, Cx0005, 0x0004, (NameSupport), Cm1, 0 },
// On/off cluster
{ Zbool, Cx0006, 0x0000, Z_(Power), 1, 0 },
{ Zenum8, Cx0006, 0x4003, Z_(StartUpOnOff), 1, 0 },
{ Zbool, Cx0006, 0x8000, Z_(Power), 1, 0 }, // See 7280
{ Zbool, Cx0006, 0x0000, Z_(Power), Cm1, 0 },
{ Zenum8, Cx0006, 0x4003, Z_(StartUpOnOff), Cm1, 0 },
{ Zbool, Cx0006, 0x8000, Z_(Power), Cm1, 0 }, // See 7280
// On/Off Switch Configuration cluster
{ Zenum8, Cx0007, 0x0000, Z_(SwitchType), 1, 0 },
{ Zenum8, Cx0007, 0x0000, Z_(SwitchType), Cm1, 0 },
// Level Control cluster
{ Zuint8, Cx0008, 0x0000, Z_(Dimmer), 1, Z_MAPPING(Z_Data_Light, dimmer) },
{ Zmap8, Cx0008, 0x000F, Z_(DimmerOptions), 1, 0 },
{ Zuint16, Cx0008, 0x0001, Z_(DimmerRemainingTime), 1, 0 },
{ Zuint16, Cx0008, 0x0010, Z_(OnOffTransitionTime), 1, 0 },
// { Zuint8, Cx0008, 0x0011, (OnLevel), 1, 0 },
// { Zuint16, Cx0008, 0x0012, (OnTransitionTime), 1, 0 },
// { Zuint16, Cx0008, 0x0013, (OffTransitionTime), 1, 0 },
// { Zuint16, Cx0008, 0x0014, (DefaultMoveRate), 1, 0 },
{ Zuint8, Cx0008, 0x0000, Z_(Dimmer), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Light, dimmer) },
{ Zmap8, Cx0008, 0x000F, Z_(DimmerOptions), Cm1, 0 },
{ Zuint16, Cx0008, 0x0001, Z_(DimmerRemainingTime), Cm1, 0 },
{ Zuint16, Cx0008, 0x0010, Z_(OnOffTransitionTime), Cm1, 0 },
// { Zuint8, Cx0008, 0x0011, (OnLevel), Cm1, 0 },
// { Zuint16, Cx0008, 0x0012, (OnTransitionTime), Cm1, 0 },
// { Zuint16, Cx0008, 0x0013, (OffTransitionTime), Cm1, 0 },
// { Zuint16, Cx0008, 0x0014, (DefaultMoveRate), Cm1, 0 },
// Alarms cluster
{ Zuint16, Cx0009, 0x0000, Z_(AlarmCount), 1, 0 },
{ Zuint16, Cx0009, 0x0000, Z_(AlarmCount), Cm1, 0 },
// Time cluster
{ ZUTC, Cx000A, 0x0000, Z_(Time), 1, 0 },
{ Zmap8, Cx000A, 0x0001, Z_(TimeStatus), 1, 0 },
{ Zint32, Cx000A, 0x0002, Z_(TimeZone), 1, 0 },
{ Zuint32, Cx000A, 0x0003, Z_(DstStart), 1, 0 },
{ Zuint32, Cx000A, 0x0004, Z_(DstEnd), 1, 0 },
{ Zint32, Cx000A, 0x0005, Z_(DstShift), 1, 0 },
{ Zuint32, Cx000A, 0x0006, Z_(StandardTime), 1, 0 },
{ Zuint32, Cx000A, 0x0007, Z_(LocalTime), 1, 0 },
{ ZUTC, Cx000A, 0x0008, Z_(LastSetTime), 1, 0 },
{ ZUTC, Cx000A, 0x0009, Z_(ValidUntilTime), 1, 0 },
{ ZUTC, Cx000A, 0xFF00, Z_(TimeEpoch), 1, 0 }, // Tasmota specific, epoch
{ ZUTC, Cx000A, 0x0000, Z_(Time), Cm1, 0 },
{ Zmap8, Cx000A, 0x0001, Z_(TimeStatus), Cm1, 0 },
{ Zint32, Cx000A, 0x0002, Z_(TimeZone), Cm1, 0 },
{ Zuint32, Cx000A, 0x0003, Z_(DstStart), Cm1, 0 },
{ Zuint32, Cx000A, 0x0004, Z_(DstEnd), Cm1, 0 },
{ Zint32, Cx000A, 0x0005, Z_(DstShift), Cm1, 0 },
{ Zuint32, Cx000A, 0x0006, Z_(StandardTime), Cm1, 0 },
{ Zuint32, Cx000A, 0x0007, Z_(LocalTime), Cm1, 0 },
{ ZUTC, Cx000A, 0x0008, Z_(LastSetTime), Cm1, 0 },
{ ZUTC, Cx000A, 0x0009, Z_(ValidUntilTime), Cm1, 0 },
{ ZUTC, Cx000A, 0xFF00, Z_(TimeEpoch), Cm1, 0 }, // Tasmota specific, epoch
// RSSI Location cluster
{ Zdata8, Cx000B, 0x0000, Z_(LocationType), 1, 0 },
{ Zenum8, Cx000B, 0x0001, Z_(LocationMethod), 1, 0 },
{ Zuint16, Cx000B, 0x0002, Z_(LocationAge), 1, 0 },
{ Zuint8, Cx000B, 0x0003, Z_(QualityMeasure), 1, 0 },
{ Zuint8, Cx000B, 0x0004, Z_(NumberOfDevices), 1, 0 },
{ Zdata8, Cx000B, 0x0000, Z_(LocationType), Cm1, 0 },
{ Zenum8, Cx000B, 0x0001, Z_(LocationMethod), Cm1, 0 },
{ Zuint16, Cx000B, 0x0002, Z_(LocationAge), Cm1, 0 },
{ Zuint8, Cx000B, 0x0003, Z_(QualityMeasure), Cm1, 0 },
{ Zuint8, Cx000B, 0x0004, Z_(NumberOfDevices), Cm1, 0 },
// Analog Input cluster
// { 0xFF, Cx000C, 0x0004, (AnalogInActiveText), 1, 0 },
{ Zstring, Cx000C, 0x001C, Z_(AnalogInDescription), 1, 0 },
// { 0xFF, Cx000C, 0x002E, (AnalogInInactiveText), 1, 0 },
{ Zsingle, Cx000C, 0x0041, Z_(AnalogInMaxValue), 1, 0 },
{ Zsingle, Cx000C, 0x0045, Z_(AnalogInMinValue), 1, 0 },
{ Zbool, Cx000C, 0x0051, Z_(AnalogInOutOfService), 1, 0 },
{ Zsingle, Cx000C, 0x0055, Z_(AqaraRotate), 1, 0 },
// { 0xFF, Cx000C, 0x0057, (AnalogInPriorityArray),1, 0 },
{ Zenum8, Cx000C, 0x0067, Z_(AnalogInReliability), 1, 0 },
// { 0xFF, Cx000C, 0x0068, (AnalogInRelinquishDefault),1, 0 },
{ Zsingle, Cx000C, 0x006A, Z_(AnalogInResolution), 1, 0 },
{ Zmap8, Cx000C, 0x006F, Z_(AnalogInStatusFlags), 1, 0 },
{ Zenum16, Cx000C, 0x0075, Z_(AnalogInEngineeringUnits),1, 0 },
{ Zuint32, Cx000C, 0x0100, Z_(AnalogInApplicationType),1, 0 },
{ Zuint16, Cx000C, 0xFF05, Z_(Aqara_FF05), 1, 0 },
// { 0xFF, Cx000C, 0x0004, (AnalogInActiveText), Cm1, 0 },
{ Zstring, Cx000C, 0x001C, Z_(AnalogInDescription), Cm1, 0 },
// { 0xFF, Cx000C, 0x002E, (AnalogInInactiveText), Cm1, 0 },
{ Zsingle, Cx000C, 0x0041, Z_(AnalogInMaxValue), Cm1, 0 },
{ Zsingle, Cx000C, 0x0045, Z_(AnalogInMinValue), Cm1, 0 },
{ Zbool, Cx000C, 0x0051, Z_(AnalogInOutOfService), Cm1, 0 },
{ Zsingle, Cx000C, 0x0055, Z_(AqaraRotate), Cm1, 0 },
// { 0xFF, Cx000C, 0x0057, (AnalogInPriorityArray),Cm1, 0 },
{ Zenum8, Cx000C, 0x0067, Z_(AnalogInReliability), Cm1, 0 },
// { 0xFF, Cx000C, 0x0068, (AnalogInRelinquishDefault),Cm1, 0 },
{ Zsingle, Cx000C, 0x006A, Z_(AnalogInResolution), Cm1, 0 },
{ Zmap8, Cx000C, 0x006F, Z_(AnalogInStatusFlags), Cm1, 0 },
{ Zenum16, Cx000C, 0x0075, Z_(AnalogInEngineeringUnits),Cm1, 0 },
{ Zuint32, Cx000C, 0x0100, Z_(AnalogInApplicationType),Cm1, 0 },
{ Zuint16, Cx000C, 0xFF05, Z_(Aqara_FF05), Cm1, 0 },
// Analog Output cluster
{ Zstring, Cx000D, 0x001C, Z_(AnalogOutDescription), 1, 0 },
{ Zsingle, Cx000D, 0x0041, Z_(AnalogOutMaxValue), 1, 0 },
{ Zsingle, Cx000D, 0x0045, Z_(AnalogOutMinValue), 1, 0 },
{ Zbool, Cx000D, 0x0051, Z_(AnalogOutOutOfService),1, 0 },
{ Zsingle, Cx000D, 0x0055, Z_(AnalogOutValue), 1, 0 },
// { Zunk, Cx000D, 0x0057, (AnalogOutPriorityArray),1, 0 },
{ Zenum8, Cx000D, 0x0067, Z_(AnalogOutReliability), 1, 0 },
{ Zsingle, Cx000D, 0x0068, Z_(AnalogOutRelinquishDefault),1, 0 },
{ Zsingle, Cx000D, 0x006A, Z_(AnalogOutResolution), 1, 0 },
{ Zmap8, Cx000D, 0x006F, Z_(AnalogOutStatusFlags), 1, 0 },
{ Zenum16, Cx000D, 0x0075, Z_(AnalogOutEngineeringUnits),1, 0 },
{ Zuint32, Cx000D, 0x0100, Z_(AnalogOutApplicationType),1, 0 },
{ Zstring, Cx000D, 0x001C, Z_(AnalogOutDescription), Cm1, 0 },
{ Zsingle, Cx000D, 0x0041, Z_(AnalogOutMaxValue), Cm1, 0 },
{ Zsingle, Cx000D, 0x0045, Z_(AnalogOutMinValue), Cm1, 0 },
{ Zbool, Cx000D, 0x0051, Z_(AnalogOutOutOfService),Cm1, 0 },
{ Zsingle, Cx000D, 0x0055, Z_(AnalogOutValue), Cm1, 0 },
// { Zunk, Cx000D, 0x0057, (AnalogOutPriorityArray),Cm1, 0 },
{ Zenum8, Cx000D, 0x0067, Z_(AnalogOutReliability), Cm1, 0 },
{ Zsingle, Cx000D, 0x0068, Z_(AnalogOutRelinquishDefault), Cm1, 0 },
{ Zsingle, Cx000D, 0x006A, Z_(AnalogOutResolution), Cm1, 0 },
{ Zmap8, Cx000D, 0x006F, Z_(AnalogOutStatusFlags), Cm1, 0 },
{ Zenum16, Cx000D, 0x0075, Z_(AnalogOutEngineeringUnits), Cm1, 0 },
{ Zuint32, Cx000D, 0x0100, Z_(AnalogOutApplicationType), Cm1, 0 },
// Analog Value cluster
{ Zstring, Cx000E, 0x001C, Z_(AnalogDescription), 1, 0 },
{ Zbool, Cx000E, 0x0051, Z_(AnalogOutOfService), 1, 0 },
{ Zsingle, Cx000E, 0x0055, Z_(AnalogValue), 1, 0 },
{ Zunk, Cx000E, 0x0057, Z_(AnalogPriorityArray), 1, 0 },
{ Zenum8, Cx000E, 0x0067, Z_(AnalogReliability), 1, 0 },
{ Zsingle, Cx000E, 0x0068, Z_(AnalogRelinquishDefault),1, 0 },
{ Zmap8, Cx000E, 0x006F, Z_(AnalogStatusFlags), 1, 0 },
{ Zenum16, Cx000E, 0x0075, Z_(AnalogEngineeringUnits),1, 0 },
{ Zuint32, Cx000E, 0x0100, Z_(AnalogApplicationType),1, 0 },
{ Zstring, Cx000E, 0x001C, Z_(AnalogDescription), Cm1, 0 },
{ Zbool, Cx000E, 0x0051, Z_(AnalogOutOfService), Cm1, 0 },
{ Zsingle, Cx000E, 0x0055, Z_(AnalogValue), Cm1, 0 },
{ Zunk, Cx000E, 0x0057, Z_(AnalogPriorityArray), Cm1, 0 },
{ Zenum8, Cx000E, 0x0067, Z_(AnalogReliability), Cm1, 0 },
{ Zsingle, Cx000E, 0x0068, Z_(AnalogRelinquishDefault),Cm1, 0 },
{ Zmap8, Cx000E, 0x006F, Z_(AnalogStatusFlags), Cm1, 0 },
{ Zenum16, Cx000E, 0x0075, Z_(AnalogEngineeringUnits),Cm1, 0 },
{ Zuint32, Cx000E, 0x0100, Z_(AnalogApplicationType),Cm1, 0 },
// Binary Input cluster
{ Zstring, Cx000F, 0x0004, Z_(BinaryInActiveText), 1, 0 },
{ Zstring, Cx000F, 0x001C, Z_(BinaryInDescription), 1, 0 },
{ Zstring, Cx000F, 0x002E, Z_(BinaryInInactiveText),1, 0 },
{ Zbool, Cx000F, 0x0051, Z_(BinaryInOutOfService),1, 0 },
{ Zenum8, Cx000F, 0x0054, Z_(BinaryInPolarity), 1, 0 },
{ Zstring, Cx000F, 0x0055, Z_(BinaryInValue), 1, 0 },
// { 0xFF, Cx000F, 0x0057, (BinaryInPriorityArray),1, 0 },
{ Zenum8, Cx000F, 0x0067, Z_(BinaryInReliability), 1, 0 },
{ Zmap8, Cx000F, 0x006F, Z_(BinaryInStatusFlags), 1, 0 },
{ Zuint32, Cx000F, 0x0100, Z_(BinaryInApplicationType),1, 0 },
{ Zstring, Cx000F, 0x0004, Z_(BinaryInActiveText), Cm1, 0 },
{ Zstring, Cx000F, 0x001C, Z_(BinaryInDescription), Cm1, 0 },
{ Zstring, Cx000F, 0x002E, Z_(BinaryInInactiveText),Cm1, 0 },
{ Zbool, Cx000F, 0x0051, Z_(BinaryInOutOfService),Cm1, 0 },
{ Zenum8, Cx000F, 0x0054, Z_(BinaryInPolarity), Cm1, 0 },
{ Zstring, Cx000F, 0x0055, Z_(BinaryInValue), Cm1, 0 },
// { 0xFF, Cx000F, 0x0057, (BinaryInPriorityArray),Cm1, 0 },
{ Zenum8, Cx000F, 0x0067, Z_(BinaryInReliability), Cm1, 0 },
{ Zmap8, Cx000F, 0x006F, Z_(BinaryInStatusFlags), Cm1, 0 },
{ Zuint32, Cx000F, 0x0100, Z_(BinaryInApplicationType),Cm1, 0 },
// Binary Output cluster
{ Zstring, Cx0010, 0x0004, Z_(BinaryOutActiveText), 1, 0 },
{ Zstring, Cx0010, 0x001C, Z_(BinaryOutDescription), 1, 0 },
{ Zstring, Cx0010, 0x002E, Z_(BinaryOutInactiveText),1, 0 },
{ Zuint32, Cx0010, 0x0042, Z_(BinaryOutMinimumOffTime),1, 0 },
{ Zuint32, Cx0010, 0x0043, Z_(BinaryOutMinimumOnTime),1, 0 },
{ Zbool, Cx0010, 0x0051, Z_(BinaryOutOutOfService),1, 0 },
{ Zenum8, Cx0010, 0x0054, Z_(BinaryOutPolarity), 1, 0 },
{ Zbool, Cx0010, 0x0055, Z_(BinaryOutValue), 1, 0 },
// { Zunk, Cx0010, 0x0057, (BinaryOutPriorityArray),1, 0 },
{ Zenum8, Cx0010, 0x0067, Z_(BinaryOutReliability), 1, 0 },
{ Zbool, Cx0010, 0x0068, Z_(BinaryOutRelinquishDefault),1, 0 },
{ Zmap8, Cx0010, 0x006F, Z_(BinaryOutStatusFlags), 1, 0 },
{ Zuint32, Cx0010, 0x0100, Z_(BinaryOutApplicationType),1, 0 },
{ Zstring, Cx0010, 0x0004, Z_(BinaryOutActiveText), Cm1, 0 },
{ Zstring, Cx0010, 0x001C, Z_(BinaryOutDescription), Cm1, 0 },
{ Zstring, Cx0010, 0x002E, Z_(BinaryOutInactiveText),Cm1, 0 },
{ Zuint32, Cx0010, 0x0042, Z_(BinaryOutMinimumOffTime),Cm1, 0 },
{ Zuint32, Cx0010, 0x0043, Z_(BinaryOutMinimumOnTime),Cm1, 0 },
{ Zbool, Cx0010, 0x0051, Z_(BinaryOutOutOfService),Cm1, 0 },
{ Zenum8, Cx0010, 0x0054, Z_(BinaryOutPolarity), Cm1, 0 },
{ Zbool, Cx0010, 0x0055, Z_(BinaryOutValue), Cm1, 0 },
// { Zunk, Cx0010, 0x0057, (BinaryOutPriorityArray),Cm1, 0 },
{ Zenum8, Cx0010, 0x0067, Z_(BinaryOutReliability), Cm1, 0 },
{ Zbool, Cx0010, 0x0068, Z_(BinaryOutRelinquishDefault),Cm1, 0 },
{ Zmap8, Cx0010, 0x006F, Z_(BinaryOutStatusFlags), Cm1, 0 },
{ Zuint32, Cx0010, 0x0100, Z_(BinaryOutApplicationType),Cm1, 0 },
// Binary Value cluster
{ Zstring, Cx0011, 0x0004, Z_(BinaryActiveText), 1, 0 },
{ Zstring, Cx0011, 0x001C, Z_(BinaryDescription), 1, 0 },
{ Zstring, Cx0011, 0x002E, Z_(BinaryInactiveText), 1, 0 },
{ Zuint32, Cx0011, 0x0042, Z_(BinaryMinimumOffTime), 1, 0 },
{ Zuint32, Cx0011, 0x0043, Z_(BinaryMinimumOnTime), 1, 0 },
{ Zbool, Cx0011, 0x0051, Z_(BinaryOutOfService), 1, 0 },
{ Zbool, Cx0011, 0x0055, Z_(BinaryValue), 1, 0 },
// { Zunk, Cx0011, 0x0057, (BinaryPriorityArray), 1, 0 },
{ Zenum8, Cx0011, 0x0067, Z_(BinaryReliability), 1, 0 },
{ Zbool, Cx0011, 0x0068, Z_(BinaryRelinquishDefault),1, 0 },
{ Zmap8, Cx0011, 0x006F, Z_(BinaryStatusFlags), 1, 0 },
{ Zuint32, Cx0011, 0x0100, Z_(BinaryApplicationType),1, 0 },
{ Zstring, Cx0011, 0x0004, Z_(BinaryActiveText), Cm1, 0 },
{ Zstring, Cx0011, 0x001C, Z_(BinaryDescription), Cm1, 0 },
{ Zstring, Cx0011, 0x002E, Z_(BinaryInactiveText), Cm1, 0 },
{ Zuint32, Cx0011, 0x0042, Z_(BinaryMinimumOffTime), Cm1, 0 },
{ Zuint32, Cx0011, 0x0043, Z_(BinaryMinimumOnTime), Cm1, 0 },
{ Zbool, Cx0011, 0x0051, Z_(BinaryOutOfService), Cm1, 0 },
{ Zbool, Cx0011, 0x0055, Z_(BinaryValue), Cm1, 0 },
// { Zunk, Cx0011, 0x0057, (BinaryPriorityArray), Cm1, 0 },
{ Zenum8, Cx0011, 0x0067, Z_(BinaryReliability), Cm1, 0 },
{ Zbool, Cx0011, 0x0068, Z_(BinaryRelinquishDefault),Cm1, 0 },
{ Zmap8, Cx0011, 0x006F, Z_(BinaryStatusFlags), Cm1, 0 },
{ Zuint32, Cx0011, 0x0100, Z_(BinaryApplicationType),Cm1, 0 },
// Multistate Input cluster
// { Zunk, Cx0012, 0x000E, (MultiInStateText), 1, 0 },
{ Zstring, Cx0012, 0x001C, Z_(MultiInDescription), 1, 0 },
{ Zuint16, Cx0012, 0x004A, Z_(MultiInNumberOfStates),1, 0 },
{ Zbool, Cx0012, 0x0051, Z_(MultiInOutOfService), 1, 0 },
{ Zuint16, Cx0012, 0x0055, Z_(MultiInValue), 1, 0 },
// { Zuint16, Cx0012, 0x0055, Z_(MultiInValue), 0, Z_AqaraCube, 0 },
// { Zuint16, Cx0012, 0x0055, Z_(MultiInValue), 0, Z_AqaraButton, 0 },
{ Zenum8, Cx0012, 0x0067, Z_(MultiInReliability), 1, 0 },
{ Zmap8, Cx0012, 0x006F, Z_(MultiInStatusFlags), 1, 0 },
{ Zuint32, Cx0012, 0x0100, Z_(MultiInApplicationType),1, 0 },
// { Zunk, Cx0012, 0x000E, (MultiInStateText), Cm1, 0 },
{ Zstring, Cx0012, 0x001C, Z_(MultiInDescription), Cm1, 0 },
{ Zuint16, Cx0012, 0x004A, Z_(MultiInNumberOfStates),Cm1, 0 },
{ Zbool, Cx0012, 0x0051, Z_(MultiInOutOfService), Cm1, 0 },
{ Zuint16, Cx0012, 0x0055, Z_(MultiInValue), Cm1, 0 },
// { Zuint16, Cx0012, 0x0055, Z_(MultiInValue), Cm0, Z_AqaraCube, 0 },
// { Zuint16, Cx0012, 0x0055, Z_(MultiInValue), Cm0, Z_AqaraButton, 0 },
{ Zenum8, Cx0012, 0x0067, Z_(MultiInReliability), Cm1, 0 },
{ Zmap8, Cx0012, 0x006F, Z_(MultiInStatusFlags), Cm1, 0 },
{ Zuint32, Cx0012, 0x0100, Z_(MultiInApplicationType),Cm1, 0 },
// Multistate output
// { Zunk, Cx0013, 0x000E, (MultiOutStateText), 1, 0 },
{ Zstring, Cx0013, 0x001C, Z_(MultiOutDescription), 1, 0 },
{ Zuint16, Cx0013, 0x004A, Z_(MultiOutNumberOfStates),1, 0 },
{ Zbool, Cx0013, 0x0051, Z_(MultiOutOutOfService), 1, 0 },
{ Zuint16, Cx0013, 0x0055, Z_(MultiOutValue), 1, 0 },
// { Zunk, Cx0013, 0x0057, (MultiOutPriorityArray),1, 0 },
{ Zenum8, Cx0013, 0x0067, Z_(MultiOutReliability), 1, 0 },
{ Zuint16, Cx0013, 0x0068, Z_(MultiOutRelinquishDefault),1, 0 },
{ Zmap8, Cx0013, 0x006F, Z_(MultiOutStatusFlags), 1, 0 },
{ Zuint32, Cx0013, 0x0100, Z_(MultiOutApplicationType),1, 0 },
// { Zunk, Cx0013, 0x000E, (MultiOutStateText), Cm1, 0 },
{ Zstring, Cx0013, 0x001C, Z_(MultiOutDescription), Cm1, 0 },
{ Zuint16, Cx0013, 0x004A, Z_(MultiOutNumberOfStates),Cm1, 0 },
{ Zbool, Cx0013, 0x0051, Z_(MultiOutOutOfService), Cm1, 0 },
{ Zuint16, Cx0013, 0x0055, Z_(MultiOutValue), Cm1, 0 },
// { Zunk, Cx0013, 0x0057, (MultiOutPriorityArray),Cm1, 0 },
{ Zenum8, Cx0013, 0x0067, Z_(MultiOutReliability), Cm1, 0 },
{ Zuint16, Cx0013, 0x0068, Z_(MultiOutRelinquishDefault),Cm1, 0 },
{ Zmap8, Cx0013, 0x006F, Z_(MultiOutStatusFlags), Cm1, 0 },
{ Zuint32, Cx0013, 0x0100, Z_(MultiOutApplicationType),Cm1, 0 },
// Multistate Value cluster
// { Zunk, Cx0014, 0x000E, (MultiStateText), 1, 0 },
{ Zstring, Cx0014, 0x001C, Z_(MultiDescription), 1, 0 },
{ Zuint16, Cx0014, 0x004A, Z_(MultiNumberOfStates), 1, 0 },
{ Zbool, Cx0014, 0x0051, Z_(MultiOutOfService), 1, 0 },
{ Zuint16, Cx0014, 0x0055, Z_(MultiValue), 1, 0 },
{ Zenum8, Cx0014, 0x0067, Z_(MultiReliability), 1, 0 },
{ Zuint16, Cx0014, 0x0068, Z_(MultiRelinquishDefault),1, 0 },
{ Zmap8, Cx0014, 0x006F, Z_(MultiStatusFlags), 1, 0 },
{ Zuint32, Cx0014, 0x0100, Z_(MultiApplicationType), 1, 0 },
// { Zunk, Cx0014, 0x000E, (MultiStateText), Cm1, 0 },
{ Zstring, Cx0014, 0x001C, Z_(MultiDescription), Cm1, 0 },
{ Zuint16, Cx0014, 0x004A, Z_(MultiNumberOfStates), Cm1, 0 },
{ Zbool, Cx0014, 0x0051, Z_(MultiOutOfService), Cm1, 0 },
{ Zuint16, Cx0014, 0x0055, Z_(MultiValue), Cm1, 0 },
{ Zenum8, Cx0014, 0x0067, Z_(MultiReliability), Cm1, 0 },
{ Zuint16, Cx0014, 0x0068, Z_(MultiRelinquishDefault),Cm1, 0 },
{ Zmap8, Cx0014, 0x006F, Z_(MultiStatusFlags), Cm1, 0 },
{ Zuint32, Cx0014, 0x0100, Z_(MultiApplicationType), Cm1, 0 },
// Power Profile cluster
{ Zuint8, Cx001A, 0x0000, Z_(TotalProfileNum), 1, 0 },
{ Zbool, Cx001A, 0x0001, Z_(MultipleScheduling), 1, 0 },
{ Zmap8, Cx001A, 0x0002, Z_(EnergyFormatting), 1, 0 },
{ Zbool, Cx001A, 0x0003, Z_(EnergyRemote), 1, 0 },
{ Zmap8, Cx001A, 0x0004, Z_(ScheduleMode), 1, 0 },
{ Zuint8, Cx001A, 0x0000, Z_(TotalProfileNum), Cm1, 0 },
{ Zbool, Cx001A, 0x0001, Z_(MultipleScheduling), Cm1, 0 },
{ Zmap8, Cx001A, 0x0002, Z_(EnergyFormatting), Cm1, 0 },
{ Zbool, Cx001A, 0x0003, Z_(EnergyRemote), Cm1, 0 },
{ Zmap8, Cx001A, 0x0004, Z_(ScheduleMode), Cm1, 0 },
// Poll Control cluster
{ Zuint32, Cx0020, 0x0000, Z_(CheckinInterval), 1, 0 },
{ Zuint32, Cx0020, 0x0001, Z_(LongPollInterval), 1, 0 },
{ Zuint16, Cx0020, 0x0002, Z_(ShortPollInterval), 1, 0 },
{ Zuint16, Cx0020, 0x0003, Z_(FastPollTimeout), 1, 0 },
{ Zuint32, Cx0020, 0x0004, Z_(CheckinIntervalMin), 1, 0 },
{ Zuint32, Cx0020, 0x0005, Z_(LongPollIntervalMin), 1, 0 },
{ Zuint16, Cx0020, 0x0006, Z_(FastPollTimeoutMax), 1, 0 },
{ Zuint32, Cx0020, 0x0000, Z_(CheckinInterval), Cm1, 0 },
{ Zuint32, Cx0020, 0x0001, Z_(LongPollInterval), Cm1, 0 },
{ Zuint16, Cx0020, 0x0002, Z_(ShortPollInterval), Cm1, 0 },
{ Zuint16, Cx0020, 0x0003, Z_(FastPollTimeout), Cm1, 0 },
{ Zuint32, Cx0020, 0x0004, Z_(CheckinIntervalMin), Cm1, 0 },
{ Zuint32, Cx0020, 0x0005, Z_(LongPollIntervalMin), Cm1, 0 },
{ Zuint16, Cx0020, 0x0006, Z_(FastPollTimeoutMax), Cm1, 0 },
// Shade Configuration cluster
{ Zuint16, Cx0100, 0x0000, Z_(PhysicalClosedLimit), 1, 0 },
{ Zuint8, Cx0100, 0x0001, Z_(MotorStepSize), 1, 0 },
{ Zmap8, Cx0100, 0x0002, Z_(Status), 1, 0 },
{ Zuint16, Cx0100, 0x0010, Z_(ClosedLimit), 1, 0 },
{ Zenum8, Cx0100, 0x0011, Z_(Mode), 1, 0 },
{ Zuint16, Cx0100, 0x0000, Z_(PhysicalClosedLimit), Cm1, 0 },
{ Zuint8, Cx0100, 0x0001, Z_(MotorStepSize), Cm1, 0 },
{ Zmap8, Cx0100, 0x0002, Z_(Status), Cm1, 0 },
{ Zuint16, Cx0100, 0x0010, Z_(ClosedLimit), Cm1, 0 },
{ Zenum8, Cx0100, 0x0011, Z_(Mode), Cm1, 0 },
// Door Lock cluster
{ Zenum8, Cx0101, 0x0000, Z_(LockState), 1, 0 },
{ Zenum8, Cx0101, 0x0001, Z_(LockType), 1, 0 },
{ Zbool, Cx0101, 0x0002, Z_(ActuatorEnabled), 1, 0 },
{ Zenum8, Cx0101, 0x0003, Z_(DoorState), 1, 0 },
{ Zuint32, Cx0101, 0x0004, Z_(DoorOpenEvents), 1, 0 },
{ Zuint32, Cx0101, 0x0005, Z_(DoorClosedEvents), 1, 0 },
{ Zuint16, Cx0101, 0x0006, Z_(OpenPeriod), 1, 0 },
{ Zenum8, Cx0101, 0x0000, Z_(LockState), Cm1, 0 },
{ Zenum8, Cx0101, 0x0001, Z_(LockType), Cm1, 0 },
{ Zbool, Cx0101, 0x0002, Z_(ActuatorEnabled), Cm1, 0 },
{ Zenum8, Cx0101, 0x0003, Z_(DoorState), Cm1, 0 },
{ Zuint32, Cx0101, 0x0004, Z_(DoorOpenEvents), Cm1, 0 },
{ Zuint32, Cx0101, 0x0005, Z_(DoorClosedEvents), Cm1, 0 },
{ Zuint16, Cx0101, 0x0006, Z_(OpenPeriod), Cm1, 0 },
// Aqara Lumi Vibration Sensor
{ Zuint16, Cx0101, 0x0055, Z_(AqaraVibrationMode), 1, 0 },
{ Zuint16, Cx0101, 0x0503, Z_(AqaraVibrationsOrAngle), 1, 0 },
{ Zuint32, Cx0101, 0x0505, Z_(AqaraVibration505), 1, 0 },
{ Zuint48, Cx0101, 0x0508, Z_(AqaraAccelerometer), 1, 0 },
{ Zuint16, Cx0101, 0x0055, Z_(AqaraVibrationMode), Cm1, 0 },
{ Zuint16, Cx0101, 0x0503, Z_(AqaraVibrationsOrAngle), Cm1, 0 },
{ Zuint32, Cx0101, 0x0505, Z_(AqaraVibration505), Cm1, 0 },
{ Zuint48, Cx0101, 0x0508, Z_(AqaraAccelerometer), Cm1, 0 },
// Window Covering cluster
{ Zenum8, Cx0102, 0x0000, Z_(WindowCoveringType), 1, 0 },
{ Zuint16, Cx0102, 0x0001, Z_(PhysicalClosedLimitLift),1, 0 },
{ Zuint16, Cx0102, 0x0002, Z_(PhysicalClosedLimitTilt),1, 0 },
{ Zuint16, Cx0102, 0x0003, Z_(CurrentPositionLift), 1, 0 },
{ Zuint16, Cx0102, 0x0004, Z_(CurrentPositionTilt), 1, 0 },
{ Zuint16, Cx0102, 0x0005, Z_(NumberofActuationsLift),1, 0 },
{ Zuint16, Cx0102, 0x0006, Z_(NumberofActuationsTilt),1, 0 },
{ Zmap8, Cx0102, 0x0007, Z_(ConfigStatus), 1, 0 },
{ Zuint8, Cx0102, 0x0008, Z_(CurrentPositionLiftPercentage),1, 0 },
{ Zuint8, Cx0102, 0x0009, Z_(CurrentPositionTiltPercentage),1, 0 },
{ Zuint16, Cx0102, 0x0010, Z_(InstalledOpenLimitLift),1, 0 },
{ Zuint16, Cx0102, 0x0011, Z_(InstalledClosedLimitLift),1, 0 },
{ Zuint16, Cx0102, 0x0012, Z_(InstalledOpenLimitTilt),1, 0 },
{ Zuint16, Cx0102, 0x0013, Z_(InstalledClosedLimitTilt),1, 0 },
{ Zuint16, Cx0102, 0x0014, Z_(VelocityLift), 1, 0 },
{ Zuint16, Cx0102, 0x0015, Z_(AccelerationTimeLift),1, 0 },
{ Zuint16, Cx0102, 0x0016, Z_(DecelerationTimeLift), 1, 0 },
{ Zmap8, Cx0102, 0x0017, Z_(Mode), 1, 0 },
{ Zoctstr, Cx0102, 0x0018, Z_(IntermediateSetpointsLift),1, 0 },
{ Zoctstr, Cx0102, 0x0019, Z_(IntermediateSetpointsTilt),1, 0 },
{ Zenum8, Cx0102, 0x0000, Z_(WindowCoveringType), Cm1, 0 },
{ Zuint16, Cx0102, 0x0001, Z_(PhysicalClosedLimitLift),Cm1, 0 },
{ Zuint16, Cx0102, 0x0002, Z_(PhysicalClosedLimitTilt),Cm1, 0 },
{ Zuint16, Cx0102, 0x0003, Z_(CurrentPositionLift), Cm1, 0 },
{ Zuint16, Cx0102, 0x0004, Z_(CurrentPositionTilt), Cm1, 0 },
{ Zuint16, Cx0102, 0x0005, Z_(NumberofActuationsLift),Cm1, 0 },
{ Zuint16, Cx0102, 0x0006, Z_(NumberofActuationsTilt),Cm1, 0 },
{ Zmap8, Cx0102, 0x0007, Z_(ConfigStatus), Cm1, 0 },
{ Zuint8, Cx0102, 0x0008, Z_(CurrentPositionLiftPercentage),Cm1, 0 },
{ Zuint8, Cx0102, 0x0009, Z_(CurrentPositionTiltPercentage),Cm1, 0 },
{ Zuint16, Cx0102, 0x0010, Z_(InstalledOpenLimitLift),Cm1, 0 },
{ Zuint16, Cx0102, 0x0011, Z_(InstalledClosedLimitLift),Cm1, 0 },
{ Zuint16, Cx0102, 0x0012, Z_(InstalledOpenLimitTilt),Cm1, 0 },
{ Zuint16, Cx0102, 0x0013, Z_(InstalledClosedLimitTilt),Cm1, 0 },
{ Zuint16, Cx0102, 0x0014, Z_(VelocityLift), Cm1, 0 },
{ Zuint16, Cx0102, 0x0015, Z_(AccelerationTimeLift),Cm1, 0 },
{ Zuint16, Cx0102, 0x0016, Z_(DecelerationTimeLift), Cm1, 0 },
{ Zmap8, Cx0102, 0x0017, Z_(Mode), Cm1, 0 },
{ Zoctstr, Cx0102, 0x0018, Z_(IntermediateSetpointsLift),Cm1, 0 },
{ Zoctstr, Cx0102, 0x0019, Z_(IntermediateSetpointsTilt),Cm1, 0 },
// Thermostat
{ Zint16, Cx0201, 0x0000, Z_(LocalTemperature), -100, Z_MAPPING(Z_Data_Thermo, temperature) },
{ Zint16, Cx0201, 0x0001, Z_(OutdoorTemperature),-100, 0 },
{ Zuint8, Cx0201, 0x0007, Z_(PICoolingDemand), 1, Z_MAPPING(Z_Data_Thermo, th_setpoint) },
{ Zuint8, Cx0201, 0x0008, Z_(PIHeatingDemand), 1, Z_MAPPING(Z_Data_Thermo, th_setpoint) },
{ Zint8, Cx0201, 0x0010, Z_(LocalTemperatureCalibration), -10, 0 },
{ Zint16, Cx0201, 0x0011, Z_(OccupiedCoolingSetpoint), -100, Z_MAPPING(Z_Data_Thermo, temperature_target) },
{ Zint16, Cx0201, 0x0012, Z_(OccupiedHeatingSetpoint), -100, Z_MAPPING(Z_Data_Thermo, temperature_target) },
{ Zint16, Cx0201, 0x0013, Z_(UnoccupiedCoolingSetpoint), -100, 0 },
{ Zint16, Cx0201, 0x0014, Z_(UnoccupiedHeatingSetpoint), -100, 0 },
{ Zmap8, Cx0201, 0x001A, Z_(RemoteSensing), 1, 0 },
{ Zenum8, Cx0201, 0x001B, Z_(ControlSequenceOfOperation), 1, 0 },
{ Zenum8, Cx0201, 0x001C, Z_(SystemMode), 1, 0 },
{ Zint16, Cx0201, 0x0000, Z_(LocalTemperature), Cm_100, Z_MAPPING(Z_Data_Thermo, temperature) },
{ Zint16, Cx0201, 0x0001, Z_(OutdoorTemperature),Cm_100, 0 },
{ Zuint8, Cx0201, 0x0007, Z_(PICoolingDemand), Cm1, Z_MAPPING(Z_Data_Thermo, th_setpoint) },
{ Zuint8, Cx0201, 0x0008, Z_(PIHeatingDemand), Cm1, Z_MAPPING(Z_Data_Thermo, th_setpoint) },
{ Zint8, Cx0201, 0x0010, Z_(LocalTemperatureCalibration), Cm_10, 0 },
{ Zint16, Cx0201, 0x0011, Z_(OccupiedCoolingSetpoint), Cm_100, Z_MAPPING(Z_Data_Thermo, temperature_target) },
{ Zint16, Cx0201, 0x0012, Z_(OccupiedHeatingSetpoint), Cm_100, Z_MAPPING(Z_Data_Thermo, temperature_target) },
{ Zint16, Cx0201, 0x0013, Z_(UnoccupiedCoolingSetpoint), Cm_100, 0 },
{ Zint16, Cx0201, 0x0014, Z_(UnoccupiedHeatingSetpoint), Cm_100, 0 },
{ Zmap8, Cx0201, 0x001A, Z_(RemoteSensing), Cm1, 0 },
{ Zenum8, Cx0201, 0x001B, Z_(ControlSequenceOfOperation), Cm1, 0 },
{ Zenum8, Cx0201, 0x001C, Z_(SystemMode), Cm1, 0 },
// below is Eurotronic specific
{ Zenum8, Cx0201, 0x4000, Z_(TRVMode), 1, 0 },
{ Zuint8, Cx0201, 0x4001, Z_(SetValvePosition), 1, 0 },
{ Zuint8, Cx0201, 0x4002, Z_(EurotronicErrors), 1, 0 },
{ Zint16, Cx0201, 0x4003, Z_(CurrentTemperatureSetPoint), -100, 0 },
{ Zenum8, Cx0201, 0x4000, Z_(TRVMode), Cm1, 0 },
{ Zuint8, Cx0201, 0x4001, Z_(SetValvePosition), Cm1, 0 },
{ Zuint8, Cx0201, 0x4002, Z_(EurotronicErrors), Cm1, 0 },
{ Zint16, Cx0201, 0x4003, Z_(CurrentTemperatureSetPoint), Cm_100, 0 },
// below are virtual attributes to simplify ZbData import/export
{ Zuint8, Cx0201, 0xFFF0, Z_(ThSetpoint), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Thermo, th_setpoint) },
{ Zint16, Cx0201, 0xFFF1, Z_(TempTarget), Cm_100 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Thermo, temperature_target) },
// Color Control cluster
{ Zuint8, Cx0300, 0x0000, Z_(Hue), 1, Z_MAPPING(Z_Data_Light, hue) },
{ Zuint8, Cx0300, 0x0001, Z_(Sat), 1, Z_MAPPING(Z_Data_Light, sat) },
{ Zuint16, Cx0300, 0x0002, Z_(RemainingTime), 1, 0 },
{ Zuint16, Cx0300, 0x0003, Z_(X), 1, Z_MAPPING(Z_Data_Light, x) },
{ Zuint16, Cx0300, 0x0004, Z_(Y), 1, Z_MAPPING(Z_Data_Light, y) },
{ Zenum8, Cx0300, 0x0005, Z_(DriftCompensation), 1, 0 },
{ Zstring, Cx0300, 0x0006, Z_(CompensationText), 1, 0 },
{ Zuint16, Cx0300, 0x0007, Z_(CT), 1, Z_MAPPING(Z_Data_Light, ct) },
{ Zenum8, Cx0300, 0x0008, Z_(ColorMode), 1, Z_MAPPING(Z_Data_Light, colormode) },
{ Zuint8, Cx0300, 0x0010, Z_(NumberOfPrimaries), 1, 0 },
{ Zuint16, Cx0300, 0x0011, Z_(Primary1X), 1, 0 },
{ Zuint16, Cx0300, 0x0012, Z_(Primary1Y), 1, 0 },
{ Zuint8, Cx0300, 0x0013, Z_(Primary1Intensity), 1, 0 },
{ Zuint16, Cx0300, 0x0015, Z_(Primary2X), 1, 0 },
{ Zuint16, Cx0300, 0x0016, Z_(Primary2Y), 1, 0 },
{ Zuint8, Cx0300, 0x0017, Z_(Primary2Intensity), 1, 0 },
{ Zuint16, Cx0300, 0x0019, Z_(Primary3X), 1, 0 },
{ Zuint16, Cx0300, 0x001A, Z_(Primary3Y), 1, 0 },
{ Zuint8, Cx0300, 0x001B, Z_(Primary3Intensity), 1, 0 },
{ Zuint16, Cx0300, 0x0030, Z_(WhitePointX), 1, 0 },
{ Zuint16, Cx0300, 0x0031, Z_(WhitePointY), 1, 0 },
{ Zuint16, Cx0300, 0x0032, Z_(ColorPointRX), 1, 0 },
{ Zuint16, Cx0300, 0x0033, Z_(ColorPointRY), 1, 0 },
{ Zuint8, Cx0300, 0x0034, Z_(ColorPointRIntensity), 1, 0 },
{ Zuint16, Cx0300, 0x0036, Z_(ColorPointGX), 1, 0 },
{ Zuint16, Cx0300, 0x0037, Z_(ColorPointGY), 1, 0 },
{ Zuint8, Cx0300, 0x0038, Z_(ColorPointGIntensity), 1, 0 },
{ Zuint16, Cx0300, 0x003A, Z_(ColorPointBX), 1, 0 },
{ Zuint16, Cx0300, 0x003B, Z_(ColorPointBY), 1, 0 },
{ Zuint8, Cx0300, 0x003C, Z_(ColorPointBIntensity), 1, 0 },
{ Zuint8, Cx0300, 0x0000, Z_(Hue), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Light, hue) },
{ Zuint8, Cx0300, 0x0001, Z_(Sat), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Light, sat) },
{ Zuint16, Cx0300, 0x0002, Z_(RemainingTime), Cm1, 0 },
{ Zuint16, Cx0300, 0x0003, Z_(X), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Light, x) },
{ Zuint16, Cx0300, 0x0004, Z_(Y), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Light, y) },
{ Zenum8, Cx0300, 0x0005, Z_(DriftCompensation), Cm1, 0 },
{ Zstring, Cx0300, 0x0006, Z_(CompensationText), Cm1, 0 },
{ Zuint16, Cx0300, 0x0007, Z_(CT), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Light, ct) },
{ Zenum8, Cx0300, 0x0008, Z_(ColorMode), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Light, colormode) },
{ Zuint8, Cx0300, 0x0010, Z_(NumberOfPrimaries), Cm1, 0 },
{ Zuint16, Cx0300, 0x0011, Z_(Primary1X), Cm1, 0 },
{ Zuint16, Cx0300, 0x0012, Z_(Primary1Y), Cm1, 0 },
{ Zuint8, Cx0300, 0x0013, Z_(Primary1Intensity), Cm1, 0 },
{ Zuint16, Cx0300, 0x0015, Z_(Primary2X), Cm1, 0 },
{ Zuint16, Cx0300, 0x0016, Z_(Primary2Y), Cm1, 0 },
{ Zuint8, Cx0300, 0x0017, Z_(Primary2Intensity), Cm1, 0 },
{ Zuint16, Cx0300, 0x0019, Z_(Primary3X), Cm1, 0 },
{ Zuint16, Cx0300, 0x001A, Z_(Primary3Y), Cm1, 0 },
{ Zuint8, Cx0300, 0x001B, Z_(Primary3Intensity), Cm1, 0 },
{ Zuint16, Cx0300, 0x0030, Z_(WhitePointX), Cm1, 0 },
{ Zuint16, Cx0300, 0x0031, Z_(WhitePointY), Cm1, 0 },
{ Zuint16, Cx0300, 0x0032, Z_(ColorPointRX), Cm1, 0 },
{ Zuint16, Cx0300, 0x0033, Z_(ColorPointRY), Cm1, 0 },
{ Zuint8, Cx0300, 0x0034, Z_(ColorPointRIntensity), Cm1, 0 },
{ Zuint16, Cx0300, 0x0036, Z_(ColorPointGX), Cm1, 0 },
{ Zuint16, Cx0300, 0x0037, Z_(ColorPointGY), Cm1, 0 },
{ Zuint8, Cx0300, 0x0038, Z_(ColorPointGIntensity), Cm1, 0 },
{ Zuint16, Cx0300, 0x003A, Z_(ColorPointBX), Cm1, 0 },
{ Zuint16, Cx0300, 0x003B, Z_(ColorPointBY), Cm1, 0 },
{ Zuint8, Cx0300, 0x003C, Z_(ColorPointBIntensity), Cm1, 0 },
// Illuminance Measurement cluster
{ Zuint16, Cx0400, 0x0000, Z_(Illuminance), 1, 0 }, // Illuminance (in Lux)
{ Zuint16, Cx0400, 0x0001, Z_(IlluminanceMinMeasuredValue), 1, 0 }, //
{ Zuint16, Cx0400, 0x0002, Z_(IlluminanceMaxMeasuredValue), 1, 0 }, //
{ Zuint16, Cx0400, 0x0003, Z_(IlluminanceTolerance), 1, 0 }, //
{ Zenum8, Cx0400, 0x0004, Z_(IlluminanceLightSensorType), 1, 0 }, //
{ Zunk, Cx0400, 0xFFFF, Z_(), 0, 0 }, // Remove all other values
{ Zuint16, Cx0400, 0x0000, Z_(Illuminance), Cm1, 0 }, // Illuminance (in Lux)
{ Zuint16, Cx0400, 0x0001, Z_(IlluminanceMinMeasuredValue), Cm1, 0 }, //
{ Zuint16, Cx0400, 0x0002, Z_(IlluminanceMaxMeasuredValue), Cm1, 0 }, //
{ Zuint16, Cx0400, 0x0003, Z_(IlluminanceTolerance), Cm1, 0 }, //
{ Zenum8, Cx0400, 0x0004, Z_(IlluminanceLightSensorType), Cm1, 0 }, //
{ Zunk, Cx0400, 0xFFFF, Z_(), Cm0, 0 }, // Remove all other values
// Illuminance Level Sensing cluster
{ Zenum8, Cx0401, 0x0000, Z_(IlluminanceLevelStatus), 1, 0 }, // Illuminance (in Lux)
{ Zenum8, Cx0401, 0x0001, Z_(IlluminanceLightSensorType), 1, 0 }, // LightSensorType
{ Zuint16, Cx0401, 0x0010, Z_(IlluminanceTargetLevel), 1, 0 }, //
{ Zunk, Cx0401, 0xFFFF, Z_(), 0, 0 }, // Remove all other values
{ Zenum8, Cx0401, 0x0000, Z_(IlluminanceLevelStatus), Cm1, 0 }, // Illuminance (in Lux)
{ Zenum8, Cx0401, 0x0001, Z_(IlluminanceLightSensorType), Cm1, 0 }, // LightSensorType
{ Zuint16, Cx0401, 0x0010, Z_(IlluminanceTargetLevel), Cm1, 0 }, //
{ Zunk, Cx0401, 0xFFFF, Z_(), Cm0, 0 }, // Remove all other values
// Temperature Measurement cluster
{ Zint16, Cx0402, 0x0000, Z_(Temperature), -100, Z_MAPPING(Z_Data_Thermo, temperature) },
{ Zint16, Cx0402, 0x0001, Z_(TemperatureMinMeasuredValue), -100, 0 }, //
{ Zint16, Cx0402, 0x0002, Z_(TemperatureMaxMeasuredValue), -100, 0 }, //
{ Zuint16, Cx0402, 0x0003, Z_(TemperatureTolerance), -100, 0 }, //
{ Zunk, Cx0402, 0xFFFF, Z_(), 0, 0 }, // Remove all other values
{ Zint16, Cx0402, 0x0000, Z_(Temperature), Cm_100 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Thermo, temperature) },
{ Zint16, Cx0402, 0x0001, Z_(TemperatureMinMeasuredValue), Cm_100, 0 }, //
{ Zint16, Cx0402, 0x0002, Z_(TemperatureMaxMeasuredValue), Cm_100, 0 }, //
{ Zuint16, Cx0402, 0x0003, Z_(TemperatureTolerance), Cm_100, 0 }, //
{ Zunk, Cx0402, 0xFFFF, Z_(), Cm0, 0 }, // Remove all other values
// Pressure Measurement cluster
{ Zint16, Cx0403, 0x0000, Z_(Pressure), 1, Z_MAPPING(Z_Data_Thermo, pressure) }, // Pressure
{ Zint16, Cx0403, 0x0001, Z_(PressureMinMeasuredValue), 1, 0 }, //
{ Zint16, Cx0403, 0x0002, Z_(PressureMaxMeasuredValue), 1, 0 }, //
{ Zuint16, Cx0403, 0x0003, Z_(PressureTolerance), 1, 0 }, //
{ Zint16, Cx0403, 0x0010, Z_(PressureScaledValue), 1, 0 }, //
{ Zint16, Cx0403, 0x0011, Z_(PressureMinScaledValue), 1, 0 }, //
{ Zint16, Cx0403, 0x0012, Z_(PressureMaxScaledValue), 1, 0 }, //
{ Zuint16, Cx0403, 0x0013, Z_(PressureScaledTolerance), 1, 0 }, //
{ Zint8, Cx0403, 0x0014, Z_(PressureScale), 1, 0 }, //
{ Zint16, Cx0403, 0xFF00, Z_(SeaPressure), 1, Z_MAPPING(Z_Data_Thermo, pressure) }, // Pressure at Sea Level, Tasmota specific
{ Zunk, Cx0403, 0xFFFF, Z_(), 0, 0 }, // Remove all other Pressure values
{ Zint16, Cx0403, 0x0000, Z_(Pressure), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Thermo, pressure) }, // Pressure
{ Zint16, Cx0403, 0x0001, Z_(PressureMinMeasuredValue), Cm1, 0 }, //
{ Zint16, Cx0403, 0x0002, Z_(PressureMaxMeasuredValue), Cm1, 0 }, //
{ Zuint16, Cx0403, 0x0003, Z_(PressureTolerance), Cm1, 0 }, //
{ Zint16, Cx0403, 0x0010, Z_(PressureScaledValue), Cm1, 0 }, //
{ Zint16, Cx0403, 0x0011, Z_(PressureMinScaledValue), Cm1, 0 }, //
{ Zint16, Cx0403, 0x0012, Z_(PressureMaxScaledValue), Cm1, 0 }, //
{ Zuint16, Cx0403, 0x0013, Z_(PressureScaledTolerance), Cm1, 0 }, //
{ Zint8, Cx0403, 0x0014, Z_(PressureScale), Cm1, 0 }, //
{ Zint16, Cx0403, 0xFFF0, Z_(SeaPressure), Cm1, Z_MAPPING(Z_Data_Thermo, pressure) }, // Pressure at Sea Level, Tasmota specific
{ Zunk, Cx0403, 0xFFFF, Z_(), Cm0, 0 }, // Remove all other Pressure values
// Flow Measurement cluster
{ Zuint16, Cx0404, 0x0000, Z_(FlowRate), -10, 0 }, // Flow (in m3/h)
{ Zuint16, Cx0404, 0x0001, Z_(FlowMinMeasuredValue), 1, 0 }, //
{ Zuint16, Cx0404, 0x0002, Z_(FlowMaxMeasuredValue), 1, 0 }, //
{ Zuint16, Cx0404, 0x0003, Z_(FlowTolerance), 1, 0 }, //
{ Zunk, Cx0404, 0xFFFF, Z_(), 0, 0 }, // Remove all other values
{ Zuint16, Cx0404, 0x0000, Z_(FlowRate), Cm_10, 0 }, // Flow (in m3/h)
{ Zuint16, Cx0404, 0x0001, Z_(FlowMinMeasuredValue), Cm1, 0 }, //
{ Zuint16, Cx0404, 0x0002, Z_(FlowMaxMeasuredValue), Cm1, 0 }, //
{ Zuint16, Cx0404, 0x0003, Z_(FlowTolerance), Cm1, 0 }, //
{ Zunk, Cx0404, 0xFFFF, Z_(), Cm0, 0 }, // Remove all other values
// Relative Humidity Measurement cluster
{ Zuint16, Cx0405, 0x0000, Z_(Humidity), -100, Z_MAPPING(Z_Data_Thermo, humidity) }, // Humidity
{ Zuint16, Cx0405, 0x0001, Z_(HumidityMinMeasuredValue), 1, 0 }, //
{ Zuint16, Cx0405, 0x0002, Z_(HumidityMaxMeasuredValue), 1, 0 }, //
{ Zuint16, Cx0405, 0x0003, Z_(HumidityTolerance), 1, 0 }, //
{ Zunk, Cx0405, 0xFFFF, Z_(), 0, 0 }, // Remove all other values
{ Zuint16, Cx0405, 0x0000, Z_(Humidity), Cm_100 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Thermo, humidity) }, // Humidity
{ Zuint16, Cx0405, 0x0001, Z_(HumidityMinMeasuredValue), Cm1, 0 }, //
{ Zuint16, Cx0405, 0x0002, Z_(HumidityMaxMeasuredValue), Cm1, 0 }, //
{ Zuint16, Cx0405, 0x0003, Z_(HumidityTolerance), Cm1, 0 }, //
{ Zunk, Cx0405, 0xFFFF, Z_(), Cm0, 0 }, // Remove all other values
// Occupancy Sensing cluster
{ Zmap8, Cx0406, 0x0000, Z_(Occupancy), 1, 0 }, // Occupancy (map8)
{ Zenum8, Cx0406, 0x0001, Z_(OccupancySensorType), 1, 0 }, // OccupancySensorType
{ Zunk, Cx0406, 0xFFFF, Z_(), 0, 0 }, // Remove all other values
{ Zmap8, Cx0406, 0x0000, Z_(Occupancy), Cm1, 0 }, // Occupancy (map8)
{ Zenum8, Cx0406, 0x0001, Z_(OccupancySensorType), Cm1, 0 }, // OccupancySensorType
{ Zunk, Cx0406, 0xFFFF, Z_(), Cm0, 0 }, // Remove all other values
// IAS Cluster (Intruder Alarm System)
{ Zenum8, Cx0500, 0x0000, Z_(ZoneState), 1, 0 }, // Occupancy (map8)
{ Zenum16, Cx0500, 0x0001, Z_(ZoneType), 1, 0 }, // Occupancy (map8)
{ Zmap16, Cx0500, 0x0002, Z_(ZoneStatus), 1, Z_MAPPING(Z_Data_Alarm, zone_type) }, // Occupancy (map8)
{ Zenum8, Cx0500, 0x0000, Z_(ZoneState), Cm1, 0 }, // Occupancy (map8)
{ Zenum16, Cx0500, 0x0001, Z_(ZoneType), Cm1, 0 }, // Occupancy (map8)
{ Zmap16, Cx0500, 0x0002, Z_(ZoneStatus), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Alarm, zone_type) }, // Occupancy (map8)
// Metering (Smart Energy) cluster
{ Zuint48, Cx0702, 0x0000, Z_(CurrentSummDelivered), 1, 0 },
{ Zuint48, Cx0702, 0x0000, Z_(CurrentSummDelivered), Cm1, 0 },
// Meter Identification cluster
{ Zstring, Cx0B01, 0x0000, Z_(CompanyName), 1, 0 },
{ Zuint16, Cx0B01, 0x0001, Z_(MeterTypeID), 1, 0 },
{ Zuint16, Cx0B01, 0x0004, Z_(DataQualityID), 1, 0 },
{ Zstring, Cx0B01, 0x0005, Z_(CustomerName), 1, 0 },
{ Zoctstr, Cx0B01, 0x0006, Z_(Model), 1, 0 },
{ Zoctstr, Cx0B01, 0x0007, Z_(PartNumber), 1, 0 },
{ Zoctstr, Cx0B01, 0x0008, Z_(ProductRevision), 1, 0 },
{ Zoctstr, Cx0B01, 0x000A, Z_(SoftwareRevision), 1, 0 },
{ Zstring, Cx0B01, 0x000B, Z_(UtilityName), 1, 0 },
{ Zstring, Cx0B01, 0x000C, Z_(POD), 1, 0 },
{ Zint24, Cx0B01, 0x000D, Z_(AvailablePower), 1, 0 },
{ Zint24, Cx0B01, 0x000E, Z_(PowerThreshold), 1, 0 },
{ Zstring, Cx0B01, 0x0000, Z_(CompanyName), Cm1, 0 },
{ Zuint16, Cx0B01, 0x0001, Z_(MeterTypeID), Cm1, 0 },
{ Zuint16, Cx0B01, 0x0004, Z_(DataQualityID), Cm1, 0 },
{ Zstring, Cx0B01, 0x0005, Z_(CustomerName), Cm1, 0 },
{ Zoctstr, Cx0B01, 0x0006, Z_(Model), Cm1, 0 },
{ Zoctstr, Cx0B01, 0x0007, Z_(PartNumber), Cm1, 0 },
{ Zoctstr, Cx0B01, 0x0008, Z_(ProductRevision), Cm1, 0 },
{ Zoctstr, Cx0B01, 0x000A, Z_(SoftwareRevision), Cm1, 0 },
{ Zstring, Cx0B01, 0x000B, Z_(UtilityName), Cm1, 0 },
{ Zstring, Cx0B01, 0x000C, Z_(POD), Cm1, 0 },
{ Zint24, Cx0B01, 0x000D, Z_(AvailablePower), Cm1, 0 },
{ Zint24, Cx0B01, 0x000E, Z_(PowerThreshold), Cm1, 0 },
// Electrical Measurement cluster
{ Zuint16, Cx0B04, 0x0505, Z_(RMSVoltage), 1, Z_MAPPING(Z_Data_Plug, mains_voltage) },
{ Zuint16, Cx0B04, 0x0508, Z_(RMSCurrent), 1, 0 },
{ Zint16, Cx0B04, 0x050B, Z_(ActivePower), 1, Z_MAPPING(Z_Data_Plug, mains_power) },
{ Zuint16, Cx0B04, 0x0505, Z_(RMSVoltage), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Plug, mains_voltage) },
{ Zuint16, Cx0B04, 0x0508, Z_(RMSCurrent), Cm1, 0 },
{ Zint16, Cx0B04, 0x050B, Z_(ActivePower), Cm1 + Z_EXPORT_DATA, Z_MAPPING(Z_Data_Plug, mains_power) },
// Diagnostics cluster
{ Zuint16, Cx0B05, 0x0000, Z_(NumberOfResets), 1, 0 },
{ Zuint16, Cx0B05, 0x0001, Z_(PersistentMemoryWrites),1, 0 },
{ Zuint8, Cx0B05, 0x011C, Z_(LastMessageLQI), 1, 0 },
{ Zuint8, Cx0B05, 0x011D, Z_(LastMessageRSSI), 1, 0 },
{ Zuint16, Cx0B05, 0x0000, Z_(NumberOfResets), Cm1, 0 },
{ Zuint16, Cx0B05, 0x0001, Z_(PersistentMemoryWrites),Cm1, 0 },
{ Zuint8, Cx0B05, 0x011C, Z_(LastMessageLQI), Cm1, 0 },
{ Zuint8, Cx0B05, 0x011D, Z_(LastMessageRSSI), Cm1, 0 },
};
#pragma GCC diagnostic pop
@ -562,20 +592,23 @@ typedef union ZCLHeaderFrameControl_t {
uint32_t d8; // raw 8 bits field
} ZCLHeaderFrameControl_t;
// Find the attribute details by attribute name
// If not found:
// - returns nullptr
const __FlashStringHelper* zigbeeFindAttributeByName(const char *command,
uint16_t *cluster, uint16_t *attribute, int8_t *multiplier) {
uint16_t *cluster, uint16_t *attribute, int8_t *multiplier,
uint8_t *zigbee_type = nullptr, Z_Data_Type *data_type = nullptr, uint8_t *map_offset = nullptr) {
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i];
if (0 == pgm_read_word(&converter->name_offset)) { continue; } // avoid strcasecmp_P() from crashing
if (0 == strcasecmp_P(command, Z_strings + pgm_read_word(&converter->name_offset))) {
if (cluster) { *cluster = CxToCluster(pgm_read_byte(&converter->cluster_short)); }
if (attribute) { *attribute = pgm_read_word(&converter->attribute); }
if (multiplier) { *multiplier = pgm_read_byte(&converter->multiplier); }
if (multiplier) { *multiplier = CmToMultiplier(pgm_read_byte(&converter->multiplier_idx)); }
if (zigbee_type) { *zigbee_type = pgm_read_byte(&converter->type); }
uint8_t conv_mapping = pgm_read_byte(&converter->mapping);
if (data_type) { *data_type = (Z_Data_Type) ((conv_mapping & 0xF0)>>4); }
if (map_offset) { *map_offset = (conv_mapping & 0x0F); }
return (const __FlashStringHelper*) (Z_strings + pgm_read_word(&converter->name_offset));
}
}
@ -593,7 +626,7 @@ const __FlashStringHelper* zigbeeFindAttributeById(uint16_t cluster, uint16_t at
uint16_t conv_attr_id = pgm_read_word(&converter->attribute);
if ((conv_cluster == cluster) && (conv_attr_id == attr_id)) {
if (multiplier) { *multiplier = pgm_read_byte(&converter->multiplier); }
if (multiplier) { *multiplier = CmToMultiplier(pgm_read_byte(&converter->multiplier_idx)); }
if (attr_type) { *attr_type = pgm_read_byte(&converter->type); }
return (const __FlashStringHelper*) (Z_strings + pgm_read_word(&converter->name_offset));
}
@ -1163,8 +1196,8 @@ void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) {
{
int16_t pressure = attr.getInt();
int16_t pressure_sealevel = (pressure / FastPrecisePow(1.0 - ((float)Settings.altitude / 44330.0f), 5.255f)) - 21.6f;
attr_list.addAttribute(0x0403, 0xFF00).setInt(pressure_sealevel);
// We create a synthetic attribute 0403/FF00 to indicate sea level
attr_list.addAttribute(0x0403, 0xFFF0).setInt(pressure_sealevel);
// We create a synthetic attribute 0403/FFF0 to indicate sea level
}
break;
}
@ -1319,7 +1352,7 @@ void ZCLFrame::parseReadConfigAttributes(Z_attribute_list& attr_list) {
if ((conv_cluster == _cluster_id) && (conv_attribute == attrid)) {
const char * attr_name = Z_strings + pgm_read_word(&converter->name_offset);
attr_2.addAttribute(attr_name, true).setBool(true);
multiplier = pgm_read_byte(&converter->multiplier);
multiplier = CmToMultiplier(pgm_read_byte(&converter->multiplier_idx));
break;
}
}
@ -1799,7 +1832,7 @@ bool Z_parseAttributeKey(class Z_attribute & attr) {
uint16_t local_attr_id = pgm_read_word(&converter->attribute);
uint16_t local_cluster_id = CxToCluster(pgm_read_byte(&converter->cluster_short));
uint8_t local_type_id = pgm_read_byte(&converter->type);
int8_t local_multiplier = pgm_read_byte(&converter->multiplier);
int8_t local_multiplier = CmToMultiplier(pgm_read_byte(&converter->multiplier_idx));
// 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 (!attr.key_is_str) {
@ -1823,4 +1856,47 @@ bool Z_parseAttributeKey(class Z_attribute & attr) {
return (Zunk != attr.attr_type) ? true : false;
}
// generic toAttributes() based on declaration in the attribute array
// can be overloaded for specific objects
// Input:
// the Json object to add attributes to
// the type of object (necessary since the type system is unaware of the actual sub-type)
void Z_Data::toAttributes(Z_attribute_list & attr_list, Z_Data_Type type) const {
// iterate through attributes to see which ones need to be exported
for (uint32_t i = 0; i < ARRAY_SIZE(Z_PostProcess); i++) {
const Z_AttributeConverter *converter = &Z_PostProcess[i];
uint8_t conv_export = pgm_read_byte(&converter->multiplier_idx) & Z_EXPORT_DATA;
uint8_t conv_mapping = pgm_read_byte(&converter->mapping);
Z_Data_Type map_type = (Z_Data_Type) ((conv_mapping & 0xF0)>>4);
uint8_t map_offset = (conv_mapping & 0x0F);
if ((conv_export != 0) && (map_type == type)) {
// we need to export this attribute
const char * conv_name = Z_strings + pgm_read_word(&converter->name_offset);
uint8_t zigbee_type = pgm_read_byte(&converter->type); // zigbee type to select right size 8/16/32 bits
uint8_t *attr_address = ((uint8_t*)this) + sizeof(Z_Data) + map_offset; // address of attribute in memory
int32_t data_size = 0;
int32_t ival32;
uint32_t uval32;
switch (zigbee_type) {
case Zenum8:
case Zuint8: uval32 = *(uint8_t*)attr_address; if (uval32 != 0xFF) data_size = 8; break;
case Zenum16:
case Zuint16: uval32 = *(uint16_t*)attr_address; if (uval32 != 0xFFFF) data_size = 16; break;
case Zuint32: uval32 = *(uint32_t*)attr_address; if (uval32 != 0xFFFFFFFF) data_size = 32; break;
case Zint8: ival32 = *(int8_t*)attr_address; if (ival32 != -0x80) data_size = -8; break;
case Zint16: ival32 = *(int16_t*)attr_address; if (ival32 != -0x8000) data_size = -16; break;
case Zint32: ival32 = *(int32_t*)attr_address; if (ival32 != -0x80000000) data_size = -32; break;
}
if (data_size != 0) {
Z_attribute & attr = attr_list.addAttribute(conv_name);
if (data_size > 0) { attr.setUInt(uval32); }
else { attr.setInt(ival32); }
}
}
}
}
#endif // USE_ZIGBEE

View File

@ -1219,9 +1219,10 @@ void CmndZbStatus(void) {
//
// Innder part of ZbData parsing
//
// {"L-02":{"Dimmer":10,"Sat":254}}
// {"L02":{"Dimmer":10,"Sat":254}}
bool parseDeviceInnerData(class Z_Device & device, JsonParserObject root) {
for (auto data_elt : root) {
// Parse key in format "L02":....
const char * data_type_str = data_elt.getStr();
Z_Data_Type data_type;
@ -1247,54 +1248,68 @@ bool parseDeviceInnerData(class Z_Device & device, JsonParserObject root) {
uint8_t endpoint = strtoul(&data_type_str[1], nullptr, 16); // hex base 16
JsonParserToken val;
// Import generic attributes first
Z_Data & data = device.data.getByType(data_type, endpoint);
// scan through attributes
for (auto attr : data_values) {
JsonParserToken attr_value = attr.getValue();
uint8_t conv_zigbee_type;
Z_Data_Type conv_data_type;
uint8_t conv_map_offset;
if (zigbeeFindAttributeByName(attr.getStr(), nullptr, nullptr, nullptr, &conv_zigbee_type, &conv_data_type, &conv_map_offset) != nullptr) {
// found an attribute matching the name, does is fit the type?
if (conv_data_type == data_type) {
// we got a match. Bear in mind that a zero value is not a valid 'data_type'
uint8_t *attr_address = ((uint8_t*)&data) + sizeof(Z_Data) + conv_map_offset;
uint32_t uval32 = attr_value.getUInt(); // call converter to uint only once
int32_t ival32 = attr_value.getInt(); // call converter to int only once
switch (conv_zigbee_type) {
case Zenum8:
case Zuint8: *(uint8_t*)attr_address = uval32; break;
case Zenum16:
case Zuint16: *(uint16_t*)attr_address = uval32; break;
case Zuint32: *(uint32_t*)attr_address = uval32; break;
case Zint8: *(int8_t*)attr_address = ival32; break;
case Zint16: *(int16_t*)attr_address = ival32; break;
case Zint32: *(int32_t*)attr_address = ival32; break;
}
} else if (conv_data_type != Z_Data_Type::Z_Unknown) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "attribute %s is wrong type %d (expected %d)"), attr.getStr(), (uint8_t)data_type, (uint8_t)conv_data_type);
}
}
}
// Import specific attributes that are not handled with the generic method
switch (data_type) {
case Z_Data_Type::Z_Plug:
{
Z_Data_Plug & plug = device.data.get<Z_Data_Plug>(endpoint);
if (val = data_values[PSTR("RMSVoltage")]) { plug.setMainsVoltage(val.getUInt()); }
if (val = data_values[PSTR("ActivePower")]) { plug.setMainsPower(val.getInt()); }
}
break;
case Z_Data_Type::Z_Light:
{
Z_Data_Light & light = device.data.get<Z_Data_Light>(endpoint);
if (val = data_values[PSTR("Light")]) { light.setConfig(val.getUInt()); }
if (val = data_values[PSTR("Dimmer")]) { light.setDimmer(val.getUInt()); }
if (val = data_values[PSTR("Colormode")]) { light.setColorMode(val.getUInt()); }
if (val = data_values[PSTR("CT")]) { light.setCT(val.getUInt()); }
if (val = data_values[PSTR("Sat")]) { light.setSat(val.getUInt()); }
if (val = data_values[PSTR("Hue")]) { light.setHue(val.getUInt()); }
if (val = data_values[PSTR("X")]) { light.setX(val.getUInt()); }
if (val = data_values[PSTR("Y")]) { light.setY(val.getUInt()); }
}
break;
// case Z_Data_Type::Z_Plug:
// {
// Z_Data_Plug & plug = (Z_Data_Plug&) data;
// }
// break;
// case Z_Data_Type::Z_Light:
// {
// Z_Data_Light & light = (Z_Data_Light&) data;
// }
// break;
case Z_Data_Type::Z_OnOff:
{
Z_Data_OnOff & onoff = device.data.get<Z_Data_OnOff>(endpoint);
Z_Data_OnOff & onoff = (Z_Data_OnOff&) data;
if (val = data_values[PSTR("Power")]) { onoff.setPower(val.getUInt() ? true : false); }
}
break;
case Z_Data_Type::Z_Thermo:
{
Z_Data_Thermo & thermo = device.data.get<Z_Data_Thermo>(endpoint);
if (val = data_values[PSTR("Temperature")]) { thermo.setTemperature(val.getInt()); }
if (val = data_values[PSTR("Pressure")]) { thermo.setPressure(val.getUInt()); }
if (val = data_values[PSTR("Humidity")]) { thermo.setHumidity(val.getUInt()); }
if (val = data_values[PSTR("ThSetpoint")]) { thermo.setThSetpoint(val.getUInt()); }
if (val = data_values[PSTR("TempTarget")]) { thermo.setTempTarget(val.getInt()); }
}
break;
case Z_Data_Type::Z_Alarm:
{
Z_Data_Alarm & alarm = device.data.get<Z_Data_Alarm>(endpoint);
if (val = data_values[PSTR("ZoneType")]) { alarm.setZoneType(val.getUInt()); }
}
break;
// case Z_Data_Type::Z_Thermo:
// {
// Z_Data_Thermo & thermo = (Z_Data_Thermo&) data;
// }
// break;
// case Z_Data_Type::Z_Alarm:
// {
// Z_Data_Alarm & alarm = (Z_Data_Alarm&) data;
// }
// break;
case Z_Data_Type::Z_Device:
{
if (val = data_values[PSTR(D_CMND_ZIGBEE_LINKQUALITY)]) { device.lqi = val.getUInt(); }
@ -1362,35 +1377,36 @@ void CmndZbData(void) {
// 'L' = Light
// 'P' = Power
//
switch (data_elt.getType()) {
Z_Data_Type data_type = data_elt.getType();
switch (data_type) {
case Z_Data_Type::Z_Plug:
{
key[0] = 'P';
Z_Data_Plug::toAttributes(inner_attr, (Z_Data_Plug&) data_elt);
((Z_Data_Plug&)data_elt).toAttributes(inner_attr, data_type);
}
break;
case Z_Data_Type::Z_Light:
{
key[0] = 'L';
Z_Data_Light::toAttributes(inner_attr, (Z_Data_Light&) data_elt);
((Z_Data_Light&)data_elt).toAttributes(inner_attr, data_type);
}
break;
case Z_Data_Type::Z_OnOff:
{
key[0] = 'O';
Z_Data_OnOff::toAttributes(inner_attr, (Z_Data_OnOff&) data_elt);
((Z_Data_OnOff&)data_elt).toAttributes(inner_attr, data_type);
}
break;
case Z_Data_Type::Z_Thermo:
{
key[0] = 'T';
Z_Data_Thermo::toAttributes(inner_attr, (Z_Data_Thermo&) data_elt);
((Z_Data_Thermo&)data_elt).toAttributes(inner_attr, data_type);
}
break;
case Z_Data_Type::Z_Alarm:
{
key[0] = 'A';
Z_Data_Alarm::toAttributes(inner_attr, (Z_Data_Alarm&) data_elt);
((Z_Data_Alarm&)data_elt).toAttributes(inner_attr, data_type);
}
break;
}