"""Tuya Dimmer TS110E Custom Quirk.""" from typing import Any, Final, Union from zigpy.profiles import zgp, 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 zigpy.zcl.foundation import ZCLAttributeDef 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.""" class ServerCommandDefs(LevelControl.ServerCommandDefs): """Server command definitions.""" moveToLevelTuya = foundation.ZCLCommandDef( # noqa: N815 id=TUYA_CUSTOM_LEVEL_COMMAND, schema={"payload": TuyaLevelPayload}, is_manufacturer_specific=False, ) class AttributeDefs(LevelControl.AttributeDefs): """Attribute definitions.""" manufacturer_current_level: Final = ZCLAttributeDef( id=TUYA_LEVEL_ATTRIBUTE, type=t.uint16_t ) bulb_type: Final = ZCLAttributeDef( id=TUYA_BULB_TYPE_ATTRIBUTE, type=TuyaBulbType ) manufacturer_min_level: Final = ZCLAttributeDef( id=TUYA_MIN_LEVEL_ATTRIBUTE, type=t.uint16_t ) manufacturer_max_level: Final = ZCLAttributeDef( id=TUYA_MAX_LEVEL_ATTRIBUTE, type=t.uint16_t ) 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.GeneralCommand, int, t.uint8_t], *args, manufacturer: Union[int, t.uint16_t] | None = None, expect_reply: bool = True, tsn: Union[int, t.uint8_t] | None = None, **kwargs: Any, ): if command_id in (0x0000, 0x0001, 0x0004): if kwargs and "level" in kwargs: level = kwargs["level"] elif args: level = args[0] else: level = 0 brightness = level * (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, **kwargs ) class DimmerSwitchWithNeutral1Gang(TuyaDimmerSwitch): """Tuya Dimmer Switch Module With Neutral 1 Gang.""" signature = { MODELS_INFO: [("_TZ3210_ngqk6jia", "TS110E")], ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, DEVICE_TYPE: zha.DeviceType.DIMMABLE_LIGHT, INPUT_CLUSTERS: [ Basic.cluster_id, # 0x0000 0x0003, # Identify (Ajouté) Groups.cluster_id, # 0x0004 Scenes.cluster_id, # 0x0005 OnOff.cluster_id, # 0x0006 LevelControl.cluster_id, # 0x0008 0x1000, # LightLink (Ajouté) TuyaZBExternalSwitchTypeCluster.cluster_id, # 0xe001 ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: zgp.PROFILE_ID, DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC, 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, 0x0003, Groups.cluster_id, Scenes.cluster_id, OnOff.cluster_id, F000LevelControlCluster, # Applique le traitement spécifique Tuya 0x1000, TuyaZBExternalSwitchTypeCluster, ], OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id], }, 242: { PROFILE_ID: zgp.PROFILE_ID, DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC, INPUT_CLUSTERS: [], OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id], }, }, }