Skip to content

Commit

Permalink
Add device support for TS110E Model QS-Zigbee-D02-TRIAC-LN (#1422)
Browse files Browse the repository at this point in the history
* Add device support for TS110E

This device uses a non-default set level command.
Tested in local docker environment.
Thanks to @javicalle this was possible.
Fix #1415

* Lint

* Lint

* Update ts110e.py

* Update ts110e.py

* Update ts110e.py

* Update ts110e.py
  • Loading branch information
jonnylangefeld committed Jul 8, 2022
1 parent d28409c commit 5bbe4e0
Showing 1 changed file with 178 additions and 0 deletions.
178 changes: 178 additions & 0 deletions zhaquirks/tuya/ts110e.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
"""Tuya Dimmer TS110E."""
from typing import Optional, Union

from zigpy.profiles import zha
import zigpy.types as t
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import (
Basic,
GreenPowerProxy,
Groups,
LevelControl,
OnOff,
Ota,
Scenes,
Time,
)

from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.tuya import (
NoManufacturerCluster,
TuyaDimmerSwitch,
TuyaZBExternalSwitchTypeCluster,
)

TUYA_LEVEL_ATTRIBUTE = 0xF000
TUYA_BULB_TYPE_ATTRIBUTE = 0xFC02
TUYA_MIN_LEVEL_ATTRIBUTE = 0xFC03
TUYA_MAX_LEVEL_ATTRIBUTE = 0xFC04
TUYA_CUSTOM_LEVEL_COMMAND = 0x00F0


class TuyaLevelPayload(t.Struct):
"""Tuya Level payload."""

level: t.uint16_t
transtime: t.uint16_t


class TuyaBulbType(t.enum8):
"""Tuya bulb type."""

LED = 0x00
INCANDESCENT = 0x01
HALOGEN = 0x02


class F000LevelControlCluster(NoManufacturerCluster, LevelControl):
"""LevelControlCluster that reports to attrid 0xF000."""

server_commands = LevelControl.server_commands.copy()
server_commands[TUYA_CUSTOM_LEVEL_COMMAND] = foundation.ZCLCommandDef(
"moveToLevelTuya",
(TuyaLevelPayload,),
is_manufacturer_specific=False,
)

attributes = LevelControl.attributes.copy()
attributes.update(
{
# 0xF000
TUYA_LEVEL_ATTRIBUTE: ("manufacturer_current_level", t.uint16_t),
# 0xFC02
TUYA_BULB_TYPE_ATTRIBUTE: ("bulb_type", TuyaBulbType),
# 0xFC03
TUYA_MIN_LEVEL_ATTRIBUTE: ("manufacturer_min_level", t.uint16_t),
# 0xFC04
TUYA_MAX_LEVEL_ATTRIBUTE: ("manufacturer_max_level", t.uint16_t),
}
)

# 0xF000 reported values are 10-1000, convert to 0-254
def _update_attribute(self, attrid, value):
if attrid == TUYA_LEVEL_ATTRIBUTE:
self.debug(
"Getting brightness %s",
value,
)
value = (value + 4 - 10) * 254 // (1000 - 10)
attrid = 0x0000

super()._update_attribute(attrid, value)

async def command(
self,
command_id: Union[foundation.Command, int, t.uint8_t],
*args,
manufacturer: Optional[Union[int, t.uint16_t]] = None,
expect_reply: bool = True,
tsn: Optional[Union[int, t.uint8_t]] = None,
):
"""Override the default Cluster command."""
self.debug(
"Sending Cluster Command. Cluster Command is %x, Arguments are %s",
command_id,
args,
)
# move_to_level, move, move_to_level_with_on_off
if command_id in (0x0000, 0x0001, 0x0004):
# convert dim values to 10-1000
brightness = args[0] * (1000 - 10) // 254 + 10
self.debug(
"Setting brightness to %s",
brightness,
)
return await super().command(
TUYA_CUSTOM_LEVEL_COMMAND,
TuyaLevelPayload(level=brightness, transtime=0),
manufacturer=manufacturer,
expect_reply=expect_reply,
tsn=tsn,
)

return super().command(command_id, *args, manufacturer, expect_reply, tsn)


class DimmerSwitchWithNeutral1Gang(TuyaDimmerSwitch):
"""Tuya Dimmer Switch Module With Neutral 1 Gang."""

signature = {
MODELS_INFO: [("_TZ3210_ngqk6jia", "TS110E")],
ENDPOINTS: {
# <SimpleDescriptor endpoint=1 profile=260 device_type=257
# input_clusters=[0, 4, 5, 6, 8, 57345]
# output_clusters=[10, 25]>
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
LevelControl.cluster_id,
TuyaZBExternalSwitchTypeCluster.cluster_id,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
242: {
# <SimpleDescriptor endpoint=242 profile=41440 device_type=97
# input_clusters=[]
# output_clusters=[33]
PROFILE_ID: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
replacement = {
ENDPOINTS: {
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.DIMMABLE_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
OnOff.cluster_id,
F000LevelControlCluster,
TuyaZBExternalSwitchTypeCluster,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
242: {
PROFILE_ID: 41440,
DEVICE_TYPE: 97,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}

0 comments on commit 5bbe4e0

Please sign in to comment.