diff --git a/tasmota/xdrv_23_zigbee_2_devices.ino b/tasmota/xdrv_23_zigbee_2_devices.ino index 618954053..d46debf02 100644 --- a/tasmota/xdrv_23_zigbee_2_devices.ino +++ b/tasmota/xdrv_23_zigbee_2_devices.ino @@ -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,8 +158,8 @@ 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 uint8_t colormode; // 0x00: Hue/Sat, 0x01: XY, 0x02: CT | 0xFF not set, default 0x01 @@ -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 diff --git a/tasmota/xdrv_23_zigbee_2a_devices_impl.ino b/tasmota/xdrv_23_zigbee_2a_devices_impl.ino index 3b7afcf9b..9c25cde89 100644 --- a/tasmota/xdrv_23_zigbee_2a_devices_impl.ino +++ b/tasmota/xdrv_23_zigbee_2a_devices_impl.ino @@ -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(0)); + const Z_Data_Light & light = device.data.find(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(0)); } Z_attribute_list attr_list_root; diff --git a/tasmota/xdrv_23_zigbee_5__constants.ino b/tasmota/xdrv_23_zigbee_5__constants.ino index 7d35d7862..bc2f0e4e0 100644 --- a/tasmota/xdrv_23_zigbee_5__constants.ino +++ b/tasmota/xdrv_23_zigbee_5__constants.ino @@ -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, }; diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 60fd0dc77..50efc72dc 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -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; iname_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 diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index 04c7e3c5f..37ae06d30 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -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(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(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(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(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(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; }