From 5b25d9cc830edc13ca7dd801772a2eef9e3d5e72 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 11 Oct 2020 19:41:23 +0200 Subject: [PATCH] Zigbee support for Tuya Moes devices --- tasmota/support_static_buffer.ino | 13 + tasmota/xdrv_23_zigbee_5__constants.ino | 398 +++++++++++++----------- tasmota/xdrv_23_zigbee_5_converters.ino | 26 +- tasmota/xdrv_23_zigbee_6_commands.ino | 58 +++- 4 files changed, 314 insertions(+), 181 deletions(-) diff --git a/tasmota/support_static_buffer.ino b/tasmota/support_static_buffer.ino index 81deb083b..55d1a8097 100644 --- a/tasmota/support_static_buffer.ino +++ b/tasmota/support_static_buffer.ino @@ -148,6 +148,12 @@ public: } return 0; } + uint16_t get16BigEndian(const size_t offset) const { + if (offset < len() - 1) { + return _buf->buf[offset+1] | (_buf->buf[offset] << 8); + } + return 0; + } uint32_t get32(const size_t offset) const { if (offset < len() - 3) { return _buf->buf[offset] | (_buf->buf[offset+1] << 8) | @@ -155,6 +161,13 @@ public: } return 0; } + int32_t get32IBigEndian(const size_t offset) const { + if (offset < len() - 3) { + return _buf->buf[offset+3] | (_buf->buf[offset+2] << 8) | + (_buf->buf[offset+1] << 16) | (_buf->buf[offset] << 24); + } + return 0; + } uint64_t get64(const size_t offset) const { if (offset < len() - 7) { return (uint64_t)_buf->buf[offset] | ((uint64_t)_buf->buf[offset+1] << 8) | diff --git a/tasmota/xdrv_23_zigbee_5__constants.ino b/tasmota/xdrv_23_zigbee_5__constants.ino index bc2f0e4e0..f28ea0b5b 100644 --- a/tasmota/xdrv_23_zigbee_5__constants.ino +++ b/tasmota/xdrv_23_zigbee_5__constants.ino @@ -272,7 +272,7 @@ const char Z_strings[] PROGMEM = "ControlSequenceOfOperation" "\x00" "SystemMode" "\x00" "TRVMode" "\x00" - "SetValvePosition" "\x00" + "ValvePosition" "\x00" "EurotronicErrors" "\x00" "CurrentTemperatureSetPoint" "\x00" "ThSetpoint" "\x00" @@ -361,6 +361,26 @@ const char Z_strings[] PROGMEM = "PersistentMemoryWrites" "\x00" "LastMessageLQI" "\x00" "LastMessageRSSI" "\x00" + "TuyaScheduleWorkdays" "\x00" + "TuyaScheduleHolidays" "\x00" + "TuyaChildLock" "\x00" + "TuyaWindowDetection" "\x00" + "TuyaValveDetection" "\x00" + "TuyaAutoLock" "\x00" + "TuyaTempTarget" "\x00" + "TuyaBattery" "\x00" + "TuyaMinTemp" "\x00" + "TuyaMaxTemp" "\x00" + "TuyaBoostTime" "\x00" + "TuyaComfortTemp" "\x00" + "TuyaEcoTemp" "\x00" + "TuyaValvePosition" "\x00" + "TuyaAwayTemp" "\x00" + "TuyaAwayDays" "\x00" + "TuyaPreset" "\x00" + "TuyaFanMode" "\x00" + "TuyaForceMode" "\x00" + "TuyaWeekSelect" "\x00" "Identify" "\x00" "xxxx" "\x00" "IdentifyQuery" "\x00" @@ -651,184 +671,204 @@ enum Z_offsets { Zo_ControlSequenceOfOperation = 3427, Zo_SystemMode = 3454, Zo_TRVMode = 3465, - Zo_SetValvePosition = 3473, - Zo_EurotronicErrors = 3490, - Zo_CurrentTemperatureSetPoint = 3507, - 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, + Zo_ValvePosition = 3473, + Zo_EurotronicErrors = 3487, + Zo_CurrentTemperatureSetPoint = 3504, + Zo_ThSetpoint = 3531, + Zo_TempTarget = 3542, + Zo_Hue = 3553, + Zo_Sat = 3557, + Zo_RemainingTime = 3561, + Zo_X = 3575, + Zo_Y = 3577, + Zo_DriftCompensation = 3579, + Zo_CompensationText = 3597, + Zo_CT = 3614, + Zo_ColorMode = 3617, + Zo_NumberOfPrimaries = 3627, + Zo_Primary1X = 3645, + Zo_Primary1Y = 3655, + Zo_Primary1Intensity = 3665, + Zo_Primary2X = 3683, + Zo_Primary2Y = 3693, + Zo_Primary2Intensity = 3703, + Zo_Primary3X = 3721, + Zo_Primary3Y = 3731, + Zo_Primary3Intensity = 3741, + Zo_WhitePointX = 3759, + Zo_WhitePointY = 3771, + Zo_ColorPointRX = 3783, + Zo_ColorPointRY = 3796, + Zo_ColorPointRIntensity = 3809, + Zo_ColorPointGX = 3830, + Zo_ColorPointGY = 3843, + Zo_ColorPointGIntensity = 3856, + Zo_ColorPointBX = 3877, + Zo_ColorPointBY = 3890, + Zo_ColorPointBIntensity = 3903, + Zo_Illuminance = 3924, + Zo_IlluminanceMinMeasuredValue = 3936, + Zo_IlluminanceMaxMeasuredValue = 3964, + Zo_IlluminanceTolerance = 3992, + Zo_IlluminanceLightSensorType = 4013, + Zo_IlluminanceLevelStatus = 4040, + Zo_IlluminanceTargetLevel = 4063, + Zo_Temperature = 4086, + Zo_TemperatureMinMeasuredValue = 4098, + Zo_TemperatureMaxMeasuredValue = 4126, + Zo_TemperatureTolerance = 4154, + Zo_Pressure = 4175, + Zo_PressureMinMeasuredValue = 4184, + Zo_PressureMaxMeasuredValue = 4209, + Zo_PressureTolerance = 4234, + Zo_PressureScaledValue = 4252, + Zo_PressureMinScaledValue = 4272, + Zo_PressureMaxScaledValue = 4295, + Zo_PressureScaledTolerance = 4318, + Zo_PressureScale = 4342, + Zo_SeaPressure = 4356, + Zo_FlowRate = 4368, + Zo_FlowMinMeasuredValue = 4377, + Zo_FlowMaxMeasuredValue = 4398, + Zo_FlowTolerance = 4419, + Zo_Humidity = 4433, + Zo_HumidityMinMeasuredValue = 4442, + Zo_HumidityMaxMeasuredValue = 4467, + Zo_HumidityTolerance = 4492, + Zo_Occupancy = 4510, + Zo_OccupancySensorType = 4520, + Zo_ZoneState = 4540, + Zo_ZoneType = 4550, + Zo_ZoneStatus = 4559, + Zo_CurrentSummDelivered = 4570, + Zo_CompanyName = 4591, + Zo_MeterTypeID = 4603, + Zo_DataQualityID = 4615, + Zo_CustomerName = 4629, + Zo_Model = 4642, + Zo_PartNumber = 4648, + Zo_ProductRevision = 4659, + Zo_SoftwareRevision = 4675, + Zo_UtilityName = 4692, + Zo_POD = 4704, + Zo_AvailablePower = 4708, + Zo_PowerThreshold = 4723, + Zo_RMSVoltage = 4738, + Zo_RMSCurrent = 4749, + Zo_ActivePower = 4760, + Zo_NumberOfResets = 4772, + Zo_PersistentMemoryWrites = 4787, + Zo_LastMessageLQI = 4810, + Zo_LastMessageRSSI = 4825, + Zo_TuyaScheduleWorkdays = 4841, + Zo_TuyaScheduleHolidays = 4862, + Zo_TuyaChildLock = 4883, + Zo_TuyaWindowDetection = 4897, + Zo_TuyaValveDetection = 4917, + Zo_TuyaAutoLock = 4936, + Zo_TuyaTempTarget = 4949, + Zo_TuyaBattery = 4964, + Zo_TuyaMinTemp = 4976, + Zo_TuyaMaxTemp = 4988, + Zo_TuyaBoostTime = 5000, + Zo_TuyaComfortTemp = 5014, + Zo_TuyaEcoTemp = 5030, + Zo_TuyaValvePosition = 5042, + Zo_TuyaAwayTemp = 5060, + Zo_TuyaAwayDays = 5073, + Zo_TuyaPreset = 5086, + Zo_TuyaFanMode = 5097, + Zo_TuyaForceMode = 5109, + Zo_TuyaWeekSelect = 5123, + Zo_Identify = 5138, + Zo_xxxx = 5147, + Zo_IdentifyQuery = 5152, + Zo_AddGroup = 5166, + Zo_xxxx00 = 5175, + Zo_ViewGroup = 5182, + Zo_GetGroup = 5192, + Zo_01xxxx = 5201, + Zo_GetAllGroups = 5208, + Zo_00 = 5221, + Zo_RemoveGroup = 5224, + Zo_RemoveAllGroups = 5236, + Zo_ViewScene = 5252, + Zo_xxxxyy = 5262, + Zo_RemoveScene = 5269, + Zo_RemoveAllScenes = 5281, + Zo_RecallScene = 5297, + Zo_GetSceneMembership = 5309, + Zo_PowerOffEffect = 5328, + Zo_xxyy = 5343, + Zo_PowerOnRecall = 5348, + Zo_PowerOnTimer = 5362, + Zo_xxyyyyzzzz = 5375, + Zo_xx0A00 = 5386, + Zo_DimmerUp = 5393, + Zo_00190200 = 5402, + Zo_DimmerDown = 5411, + Zo_01190200 = 5422, + Zo_DimmerStop = 5431, + Zo_ResetAlarm = 5442, + Zo_xxyyyy = 5453, + Zo_ResetAllAlarms = 5460, + Zo_xx000A00 = 5475, + Zo_HueSat = 5484, + Zo_xxyy0A00 = 5491, + Zo_Color = 5500, + Zo_xxxxyyyy0A00 = 5506, + Zo_xxxx0A00 = 5519, + Zo_ShutterOpen = 5528, + Zo_ShutterClose = 5540, + Zo_ShutterStop = 5553, + Zo_ShutterLift = 5565, + Zo_xx = 5577, + Zo_ShutterTilt = 5580, + Zo_Shutter = 5592, + Zo_DimmerMove = 5600, + Zo_xx0A = 5611, + Zo_DimmerStepUp = 5616, + Zo_00xx0A00 = 5629, + Zo_DimmerStepDown = 5638, + Zo_01xx0A00 = 5653, + Zo_DimmerStep = 5662, + Zo_xx190A00 = 5673, + Zo_01 = 5682, + Zo_HueMove = 5685, + Zo_xx19 = 5693, + Zo_HueStepUp = 5698, + Zo_HueStepDown = 5708, + Zo_03xx0A00 = 5720, + Zo_HueStep = 5729, + Zo_SatMove = 5737, + Zo_SatStep = 5745, + Zo_xx190A = 5753, + Zo_ColorMove = 5760, + Zo_xxxxyyyy = 5770, + Zo_ColorStep = 5779, + Zo_ColorTempMoveUp = 5789, + Zo_01xxxx000000000000 = 5805, + Zo_ColorTempMoveDown = 5824, + Zo_03xxxx000000000000 = 5842, + Zo_ColorTempMoveStop = 5861, + Zo_00xxxx000000000000 = 5879, + Zo_ColorTempMove = 5898, + Zo_xxyyyy000000000000 = 5912, + Zo_ColorTempStepUp = 5931, + Zo_01xxxx0A0000000000 = 5947, + Zo_ColorTempStepDown = 5966, + Zo_03xxxx0A0000000000 = 5984, + Zo_ColorTempStep = 6003, + Zo_xxyyyy0A0000000000 = 6017, + Zo_ArrowClick = 6036, + Zo_ArrowHold = 6047, + Zo_ArrowRelease = 6057, + Zo_ZoneStatusChange = 6070, + Zo_xxxxyyzz = 6087, + Zo_xxyyzzzz = 6096, + Zo_AddScene = 6105, + Zo_xxyyyyzz = 6114, + Zo_StoreScene = 6123, }; diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index c2eaa891a..b57185e80 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -120,6 +120,7 @@ enum Cx_cluster_short { Cx0010, Cx0011, Cx0012, Cx0013, Cx0014, Cx001A, Cx0020, Cx0100, Cx0101, Cx0102, Cx0201, Cx0300, Cx0400, Cx0401, Cx0402, Cx0403, Cx0404, Cx0405, Cx0406, Cx0500, Cx0702, Cx0B01, Cx0B04, Cx0B05, + CxEF00, }; const uint16_t Cx_cluster[] PROGMEM = { @@ -128,6 +129,7 @@ const uint16_t Cx_cluster[] PROGMEM = { 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x001A, 0x0020, 0x0100, 0x0101, 0x0102, 0x0201, 0x0300, 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0500, 0x0702, 0x0B01, 0x0B04, 0x0B05, + 0xEF00, }; uint16_t CxToCluster(uint8_t cx) { @@ -453,7 +455,7 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = { { Zenum8, Cx0201, 0x001C, Z_(SystemMode), Cm1, 0 }, // below is Eurotronic specific { Zenum8, Cx0201, 0x4000, Z_(TRVMode), Cm1, 0 }, - { Zuint8, Cx0201, 0x4001, Z_(SetValvePosition), Cm1, 0 }, + { Zuint8, Cx0201, 0x4001, Z_(ValvePosition), 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 @@ -578,6 +580,28 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = { { Zuint8, Cx0B05, 0x011C, Z_(LastMessageLQI), Cm1, 0 }, { Zuint8, Cx0B05, 0x011D, Z_(LastMessageRSSI), Cm1, 0 }, + // Tuya Moes specific - 0xEF00 + { Zoctstr, CxEF00, 0x0070, Z_(TuyaScheduleWorkdays), Cm1, 0 }, + { Zoctstr, CxEF00, 0x0071, Z_(TuyaScheduleHolidays), Cm1, 0 }, + { Zuint8, CxEF00, 0x0107, Z_(TuyaChildLock), Cm1, 0 }, + { Zuint8, CxEF00, 0x0112, Z_(TuyaWindowDetection), Cm1, 0 }, + { Zuint8, CxEF00, 0x0114, Z_(TuyaValveDetection), Cm1, 0 }, + { Zuint8, CxEF00, 0x0174, Z_(TuyaAutoLock), Cm1, 0 }, + { Zint16, CxEF00, 0x0202, Z_(TuyaTempTarget), Cm_10, 0 }, + { Zint16, CxEF00, 0x0203, Z_(LocalTemperature), Cm_10, 0 }, // will be overwritten by actual LocalTemperature + { Zuint8, CxEF00, 0x0215, Z_(TuyaBattery), Cm1, 0 }, // TODO check equivalent? + { Zint32, CxEF00, 0x0266, Z_(TuyaMinTemp), Cm1, 0 }, + { Zint32, CxEF00, 0x0267, Z_(TuyaMaxTemp), Cm1, 0 }, + { Zint32, CxEF00, 0x0269, Z_(TuyaBoostTime), Cm1, 0 }, + { Zint32, CxEF00, 0x026B, Z_(TuyaComfortTemp), Cm1, 0 }, + { Zint32, CxEF00, 0x026C, Z_(TuyaEcoTemp), Cm1, 0 }, + { Zuint8, CxEF00, 0x026D, Z_(TuyaValvePosition), Cm1, 0 }, + { Zint32, CxEF00, 0x0272, Z_(TuyaAwayTemp), Cm1, 0 }, + { Zint32, CxEF00, 0x0275, Z_(TuyaAwayDays), Cm1, 0 }, + { Zuint8, CxEF00, 0x0404, Z_(TuyaPreset), Cm1, 0 }, + { Zuint8, CxEF00, 0x0405, Z_(TuyaFanMode), Cm1, 0 }, + { Zuint8, CxEF00, 0x046A, Z_(TuyaForceMode), Cm1, 0 }, + { Zuint8, CxEF00, 0x046F, Z_(TuyaWeekSelect), Cm1, 0 }, }; #pragma GCC diagnostic pop diff --git a/tasmota/xdrv_23_zigbee_6_commands.ino b/tasmota/xdrv_23_zigbee_6_commands.ino index 947e2ffe0..a859c507c 100644 --- a/tasmota/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/xdrv_23_zigbee_6_commands.ino @@ -134,6 +134,8 @@ const Z_CommandConverter Z_Commands[] PROGMEM = { { Z_(RemoveAllScenes),0x0005, 0x03, 0x82, Z_(xxyyyy) }, // xx = status, yyyy = group id { Z_(StoreScene), 0x0005, 0x04, 0x82, Z_(xxyyyyzz) }, // xx = status, yyyy = group id, zz = scene id { Z_(GetSceneMembership),0x0005, 0x06, 0x82,Z_(xxyyzzzz) }, // specific + // Tuya - Moes specific + { Z_(), 0xEF00, 0xFF, 0x83, Z_() }, // capture any command in 0xEF00 cluster }; /*********************************************************************************************\ @@ -330,7 +332,8 @@ void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster, // Format: "0004<00": "00" = "<": "" for commands to devices char attrid_str[12]; snprintf_P(attrid_str, sizeof(attrid_str), PSTR("%04X%c%02X"), cluster, direction ? '<' : '!', cmd); - attr_list.addAttribute(attrid_str).setBuf(payload, 0, payload.len()); + Z_attribute & attr_raw = attr_list.addAttribute(attrid_str); + attr_raw.setBuf(payload, 0, payload.len()); if (command_name) { // Now try to transform into a human readable format @@ -410,6 +413,11 @@ void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster, attr_list.addAttribute(PSTR("PowerOnTime"), true).setFloat(xyz.y / 10.0f); attr_list.addAttribute(PSTR("PowerOffWait"), true).setFloat(xyz.z / 10.0f); break; + case 0xEF000000 ... 0xEF0000FF: // any Tuya - Moes command + if (convertTuyaSpecificCluster(attr_list, cluster, cmd, direction, shortaddr, srcendpoint, payload)) { + attr_list.removeAttribute(&attr_raw); // remove raw command + } + break; } } else { // general case // do we send command with endpoint suffix @@ -438,6 +446,54 @@ void convertClusterSpecific(class Z_attribute_list &attr_list, uint16_t cluster, } } +// +// Tuya - MOES specifc cluster 0xEF00 +// See https://medium.com/@dzegarra/zigbee2mqtt-how-to-add-support-for-a-new-tuya-based-device-part-2-5492707e882d +// and https://github.com/Koenkk/zigbee-herdsman-converters/blob/9f503d47d3df6a99d133b78d2b52aa5c701ddddf/converters/fromZigbee.js#L339 +// +bool convertTuyaSpecificCluster(class Z_attribute_list &attr_list, uint16_t cluster, uint8_t cmd, bool direction, uint16_t shortaddr, uint8_t srcendpoint, const SBuffer &buf) { + // uint8_t status = buf.get8(0); + // uint8_t transid = buf.get8(1); + uint16_t dp = buf.get16(2); // decode dp as 16 bits little endian - which is not big endian as mentioned in documentation + // uint8_t fn = buf.get8(4); + uint8_t len = buf.get8(5); // len of payload + + if ((1 == cmd) || (2 == cmd)) { // attribute report or attribute response + // create a synthetic attribute with id 'dp' + Z_attribute & attr = attr_list.addAttribute(cluster, dp); + int32_t ival32 = -0x80000000; + if (1 == len) { + // 1 byte, convert as uint8_t + ival32 = buf.get8(6); + } else if (2 == len) { + ival32 = buf.get16BigEndian(6); + } else if (4 == len) { + // 4 bytes, convert as int32_t + ival32 = buf.get32IBigEndian(6); + } + if (ival32 != -0x80000000) { + // fix temperature coefficient + switch (dp) { + case 0x0202: + attr_list.addAttribute(0x0201, 0x0012).setInt(ival32 * 10); // OccupiedHeatingSetpoint + break; + case 0x0203: + attr_list.addAttribute(0x0201, 0x0000).setInt(ival32 * 10); // LocalTemperature + break; + case 0x026D: + attr_list.addAttribute(0x0201, 0x0008).setUInt(ival32); // PIHeatingDemand + break; + } + attr.setInt(ival32); + } else { + // add as raw buffer + attr.setBuf(buf, 6, len); + } + return true; // true = remove the original Tuya attribute + } + return false; +} + // Find the command details by command name // Only take commands outgoing, i.e. direction == 0 // If not found: