Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Device Support Request] Moes dimmer switches _TZE200_ip2akl4w & _TZE200_fjjbhx9d #1302

Closed
Daandeve opened this issue Jan 23, 2022 · 424 comments · Fixed by #1489
Closed

[Device Support Request] Moes dimmer switches _TZE200_ip2akl4w & _TZE200_fjjbhx9d #1302

Daandeve opened this issue Jan 23, 2022 · 424 comments · Fixed by #1489

Comments

@Daandeve
Copy link

Daandeve commented Jan 23, 2022

This is a Tuya device that has no entities and/or controls in home assistant and its a simple Zigbee Tuya dimmer. It should be very similar to many other devices like this.

1 Gang _TZE200_ip2akl4w

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZE200_ip2akl4w",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

2 Gang _TZE200_fjjbhx9d

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZE200_fjjbhx9d",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

Thanks in advance for the support.

@javicalle
Copy link
Collaborator

It seems that is like others Tuya dimmers but with the green power endpoint.
I believe that can be easily added.

For future reference do you have a link to the product to help visually identify it?

@javicalle
Copy link
Collaborator

The 2 gang will require the PR #1247 to be merged.
The 1 gang can be fixed with PR #1122, but it is a Work In Progress

@Daandeve are you able to test local quirks in your environment?

@Daandeve
Copy link
Author

It seems that is like others Tuya dimmers but with the green power endpoint. I believe that can be easily added.

For future reference do you have a link to the product to help visually identify it?

This is the product: https://nl.aliexpress.com/item/1005003619398730.html?gatewayAdapt=glo2nld&spm=a2g0o.9042311.0.0.130d4c4dGYyEsh
I have the 1 and 2 EU gang models

@Daandeve
Copy link
Author

Daandeve commented Jan 23, 2022

The 2 gang will require the PR #1247 to be merged. The 1 gang can be fixed with PR #1122, but it is a Work In Progress

@Daandeve are you able to test local quirks in your environment?

I would like to test it but I do not fully understand how I can test quirks.
Edit: I figured it out :)

@javicalle
Copy link
Collaborator

Depending on the environment there are different ways to do it.
Here are some examples of how to do it:

It is not too difficult, but it does require touching the insides of the installation and it is preferable to do it if you feel comfortable with those kind of modifications.

@Daandeve
Copy link
Author

Daandeve commented Jan 23, 2022

Thanks, but the device does not show entities and no errors in the logs. I only see this in the logs, I don't think it was there before.

[0x80c1:1:0xef00] Unknown cluster-specific command 1
[0x80c1:1:0xef00] Unknown cluster-specific command 36

I put the script in custom_zha_quirks/tuya/mcu/__init__.py
And in the home assistant config

zha:
  custom_quirks_path: /config/custom_zha_quirks/`

@javicalle
Copy link
Collaborator

javicalle commented Jan 23, 2022

Ok, let's try it.

You need to copy 2 file to the custom_zha_quirks:

Then you need to modify the ts0601_dimmer.py file:

  • add the new GreenPowerProxy import:
from zigpy.zcl.clusters.general import Basic, GreenPowerProxy, Groups, LevelControl, Ota, Scenes, Time
  • replace all the zhaquirks.tuya.mcu imports:
from custom_zha_quirks.tuya.mcu import (
    TuyaInWallLevelControl,
    TuyaLevelControlManufCluster,
    TuyaOnOff as TuyaOnOffMCU,
)
  • Add 2 new classes at the end of file:
class TuyaSingleSwitchDimmerGP(TuyaDimmerSwitch):
    """Tuya touch switch device."""

    signature = {
        MODELS_INFO: [
            ("_TZE200_3p5ydos3", "TS0601"),
            ("_TZE200_ip2akl4w", "TS0601"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.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: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaLevelControlManufCluster,
                    TuyaOnOffMCU,
                    TuyaInWallLevelControl,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }


class TuyaDoubleSwitchDimmerGP(TuyaDimmerSwitch):
    """Tuya double channel dimmer device."""

    signature = {
        MODELS_INFO: [
            ("_TZE200_fjjbhx9d", "TS0601"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaLevelControlManufCluster,
                    TuyaOnOffMCU,
                    TuyaInWallLevelControl,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    TuyaOnOffMCU,
                    TuyaInWallLevelControl,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }

Also, you can enable debug logs for custom_zha_quirks:

logger:
  default: warning
  logs:
    .../...
    custom_zha_quirks: debug

Delete the __pycache__ folder and restart HA.

@javicalle
Copy link
Collaborator

It seems that device also have the power_on_state and backlight_mode. Not implemented for dimmer yet.
This must be reviewed in order to support it.

@javicalle
Copy link
Collaborator

And probably also support minimum_level and maximum_level. It is not documented, but the photos from the link suggest it.

@Daandeve
Copy link
Author

I followed all steps but nothing is coming up, no logs and no entities. I tried to remove the zigbee device and add it again, but with no success..

@Daandeve
Copy link
Author

When I reconfigure the device the binding and reporting tables are empty.
image

@javicalle
Copy link
Collaborator

Do not have any logs when operate the device? Maybe you need to enable the zigpy logs.
Can you do a power cycle to the device? Usually this way, devices will broadcast their status.

@javicalle
Copy link
Collaborator

And the device signature? It is the quirk loaded?

@Daandeve
Copy link
Author

Daandeve commented Jan 23, 2022

This is what I get in the logs:

2022-01-24 00:00:21 DEBUG (MainThread) [zigpy.zcl] [0x80c1:1:0x0000] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=141 command_id=Command.Report_Attributes>
2022-01-24 00:00:21 DEBUG (MainThread) [zigpy.zcl] [0x80c1:1:0x0000] ZCL request 0x000a: [[Attribute(attrid=65503, value=<TypeValue type=CharacterString, value=���)e���)i���)i���)i���)i���)i���)i���)i���)i���)i���)i���)i>)]]
2022-01-24 00:00:21 DEBUG (MainThread) [zigpy.zcl] [0x80c1:1:0x0000] Attribute report received: 65503=���)e���)i���)i���)i���)i���)i���)i���)i���)i���)i���)i���)i

And

2022-01-24 00:02:28 DEBUG (MainThread) [zigpy.zcl] [0x80c1:1:0xef00] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=142 command_id=1>
2022-01-24 00:02:28 WARNING (MainThread) [zigpy.zcl] [0x80c1:1:0xef00] Unknown cluster-specific command 1
2022-01-24 00:02:28 DEBUG (MainThread) [zigpy.zcl] [0x80c1:1:0xef00] ZCL request 0x0001: b'\x00\xd1\x07\x01\x00\x01\x01'
2022-01-24 00:02:28 DEBUG (MainThread) [zigpy.zcl] [0x80c1:1:0xef00] No handler for cluster command 1

@Daandeve
Copy link
Author

And the device signature? It is the quirk loaded?

How can I see if the quirk is loaded correctly?

@javicalle
Copy link
Collaborator

How can I see if the quirk is loaded correctly?

From Configuration --> Integrations --> ZHA Devices --> select your device --> Zigbee device signature

It's the same info you put in the first comment.

@Daandeve
Copy link
Author

Daandeve commented Jan 23, 2022

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0051",
      "in_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0xef00"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZE200_fjjbhx9d",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

I don't think it is loaded

@javicalle
Copy link
Collaborator

I don't think it is loaded

No, it is not.

I believe that I have made a mess copying the files. Give me a second to review it.

@Daandeve
Copy link
Author

Daandeve commented Jan 23, 2022

I think I did it right, why is the init.py in the mcu folder?
image

@javicalle
Copy link
Collaborator

Then you hace to replace at ts0601_dimmer.py some imports:

from custom_zha_quirks.tuya.mcu import (
    TuyaInWallLevelControl,
    TuyaLevelControlManufCluster,
    TuyaOnOff as TuyaOnOffMCU,
)

I think the rest will be OK.

(I have updated the TuyaSingleSwitchDimmerGP signature part)

@Daandeve
Copy link
Author

I updated the files, without success. The quirk is not found in general.

2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Checking quirks for _TZE200_fjjbhx9d TS0601 (a4:c1:38:75:54:c8:df:96)
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Considering <class 'zhaquirks.xbee.xbee_io.XBeeSensor'>
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Fail because endpoint list mismatch: {232, 230} {1, 242}
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Considering <class 'zhaquirks.xbee.xbee3_io.XBee3Sensor'>
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Fail because endpoint list mismatch: {232, 230} {1, 242}
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Considering <class 'zhaquirks.smartthings.tag_v4.SmartThingsTagV4'>
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Fail because endpoint list mismatch: {1} {1, 242}
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Considering <class 'zhaquirks.smartthings.multi.SmartthingsMultiPurposeSensor'>
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Fail because endpoint list mismatch: {1} {1, 242}
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Considering <class 'zhaquirks.netvox.z308e3ed.Z308E3ED'>
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Fail because endpoint list mismatch: {1} {1, 242}
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Considering <class 'zhaquirks.gledopto.soposhgu10.SoposhGU10'>
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Fail because endpoint list mismatch: {11, 13} {1, 242}
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Considering <class 'bellows.zigbee.application.EZSPCoordinator'>
2022-01-24 00:40:53 DEBUG (MainThread) [zigpy.quirks.registry] Fail because endpoint list mismatch: {1} {1, 242}

@javicalle
Copy link
Collaborator

Just to be sure, are in HA the files placed in /config/custom_zha_quirks/tuya/...?

@javicalle
Copy link
Collaborator

javicalle commented Jan 23, 2022

No error logs in HA restart? no __pycache__ folder in custom_zha_quirks folder?

@Daandeve
Copy link
Author

Just to be sure, are in HA the files placed in /config/custom_zha_quirks/tuya/...?

Yes that is correct

@Daandeve
Copy link
Author

No error logs in HA restart? no __pycache__ folder in custom_zha_quirks folder?

No errors and no pycache

@javicalle
Copy link
Collaborator

No idea what could be going on...

Maybe you can try to put all the files at root level /config/custom_zha_quirks/. The import from ts0601_dimmer.py file would be replaced with:

from . import (
    TuyaInWallLevelControl,
    TuyaLevelControlManufCluster,
    TuyaOnOff as TuyaOnOffMCU,
)

The rest will be fine as is.

@javicalle
Copy link
Collaborator

Are you sure HA is restarting? Sometimes, if there is a validation and other error, the console doesn't tell you and it appears to have restarted, but it really hasn't.
(Sorry to ask, but I don't find a reason way it is not loading the quirk)

@Daandeve
Copy link
Author

Okay now it loads but I get
ImportError: attempted relative import with no known parent package

@Daandeve
Copy link
Author

Are you sure HA is restarting? Sometimes, if there is a validation and other error, the console doesn't tell you and it appears to have restarted, but it really hasn't. (Sorry to ask, but I don't find a reason way it is not loading the quirk)

I thought that was happening as well, but I restarted the full VM. So that is not the problem

@javicalle
Copy link
Collaborator

Okay now it loads but I get
ImportError: attempted relative import with no known parent package

Well, then put the __init__.py file at any place, for example in the original one /config/custom_zha_quirks/tuya/mcu/ and adapt the import accordly:

from custom_zha_quirks.tuya.mcu import (
    TuyaInWallLevelControl,
    TuyaLevelControlManufCluster,
    TuyaOnOff as TuyaOnOffMCU,
)

(not too diferent from previous situation 😅 )

@ToastySefac
Copy link

ToastySefac commented Apr 10, 2022

I have a Mercator Ikuu Light Dimmer (SSWD01) which identifies as a Tuya TS0601 Dimmer (_TZE200_swaamsoy). I've tried to follow along with the suggested quirk from this thread and add it to my system. Once added, I'm not seeing any usable HA controls.

Can I ask what might be an obvious question - How do I tell if the quirk is being read and used (other than the device working properly)?

I have the files in custom_zha_quirks and have referenced it in configuration.yaml.
config/custom_zha_quirks/ts0601_dimmer.py
config/custom_zha_quirks/tuya/mcu/__init__.py
config/configuration.yaml

zha:
  custom_quirks_path: /config/custom_zha_quirks/
{
"node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
"endpoints": {
"1": {
"profile_id": 260,
"device_type": "0x0104",
"in_clusters": [
"0x0000",
"0x0003",
"0x0004",
"0x0005",
"0x0006",
"0x0008",
"0x0300",
"0xef00"
],
"out_clusters": [
"0x000a",
"0x0019"
]
}
},
"manufacturer": "_TZE200_swaamsoy",
"model": "TS0601",
"class": "zigpy.device.Device"
}

@Tropaion
Copy link
Contributor

Can I ask what might be an obvious question - How do I tell if the quirk is being read and used (other than the device working properly)?

@ToastySefac You can see it in the device signature class, it should say something like ts0601_dimmer.TuyaSingleSwitchDimmerGP. zigpy.device.Device means there is no quirk applied.

Which quirk/file did you use? Your dimmer is a little bit different than mine, so you have to modify the quirk a bit, if you want I can help you with it.

@ToastySefac
Copy link

ToastySefac commented Apr 10, 2022

I've tried the main one as well as those in this thread, but the one I'm using now is from: (#1302 (comment))

I can't work out why it's not loading the quirk. I'm getting "class": "zigpy.device.Device" in the device signature. I have also been deleting the cached files as well.

if you want I can help you with it.

That would be great, thanks

@Tropaion
Copy link
Contributor

Tropaion commented Apr 10, 2022

@ToastySefac That's weird, there isn't a problem with the files/config you use and the paths are also correct.
Maybe a simple problem, did you reboot after deleting __pychache__?

@Tropaion
Copy link
Contributor

@javicalle BTW is there still something that stands in the way of a PR or will make one soon?

@javicalle
Copy link
Collaborator

javicalle commented Apr 10, 2022

@ToastySefac This seems to be a pretty weird device.
Tuya MCU devices do not normally expose 'normal' clusters and everything is managed through the Tuya cluster.
This device seems to expose both types: the normal clusters and the Tuya cluster, so the behavior cannot be predicted.

If you want to try, I think this class might work. A new class and the necessary imports have been added.

ts0601_dimmer.py

The full class content

"""Tuya based touch switch."""
# ---------------------------------------------------------------------------
# _TZE200_vm1gyrso:
# Add new code block
# 2022-04-07
# ---------------------------------------------------------------------------
from typing import Optional, Union

from zigpy.profiles import zha
from zigpy.quirks import CustomCluster
import zigpy.types as t
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import Basic, GreenPowerProxy, Groups, Identify, LevelControl, OnOff, Ota, Scenes, Time
from zigpy.zcl.clusters.lighting import Color

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.tuya import (
    TuyaDimmerSwitch,
    TuyaLevelControl,
    TuyaManufacturerClusterOnOff,
    TuyaManufacturerLevelControl,
    TuyaManufCluster,
    TuyaOnOff,
)

from custom_zha_quirks.tuya.mcu import (
    TuyaInWallLevelControl,
    TuyaLevelControlManufCluster,
    TuyaOnOff as TuyaOnOffMCU,
)

class NoManufacturerCluster(CustomCluster):
    """Forces the NO manufacturer id in command."""

    async def command(
        self,
        command_id: Union[foundation.GeneralCommand, 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("Setting the NO manufacturer id in command: %s", command_id)
        status = await super().command(
            command_id,
            *args,
            manufacturer=foundation.ZCLHeader.NO_MANUFACTURER_ID,
            expect_reply=expect_reply,
            tsn=tsn,
        )

        return foundation.GENERAL_COMMANDS[foundation.GeneralCommand.Default_Response].schema(command_id=command_id, status=status)
        
class TuyaOnOffNM(NoManufacturerCluster, TuyaOnOffMCU):
    """Tuya OnOff cluster with NoManufacturerID."""

    pass

class TuyaInWallLevelControlNM(NoManufacturerCluster, TuyaInWallLevelControl):
    """Tuya Level cluster for inwall dimmable device with NoManufacturerID."""

    pass

class TuyaSingleSwitchDimmer(TuyaDimmerSwitch):
    """Tuya touch switch device."""

    signature = {
        # "node_descriptor": "<NodeDescriptor byte1=1, byte2=64, mac_capability_flags=142, manufacturer_code=4098,
        # maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264,
        # maximum_outgoing_transfer_size=82, descriptor_capability_field=0>",
        # <SimpleDescriptor endpoint=1 profile=260 device_type=51 device_version=1 input_clusters=[0, 4, 5, 61184] output_clusters=[10, 25]>
        MODELS_INFO: [
            ("_TZE200_dfxkcots", "TS0601"),
            ("_TZE200_whpb9yts", "TS0601"),
            ("_TZE200_ebwgzdqq", "TS0601"),
            ("_TZE200_9i9dt8is", "TS0601"),
            ("_TZE200_swaamsoy", "TS0601"),
            ("_TZE200_0nauxa0p", "TS0601"),
            ("_TZE200_la2c2uo9", "TS0601"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    LevelControl.cluster_id,
                    TuyaManufacturerClusterOnOff,
                    TuyaOnOff,
                    TuyaManufacturerLevelControl,
                    TuyaLevelControl,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        }
    }


class TuyaSingleSwitchDimmerPlus(TuyaDimmerSwitch):
    """Tuya touch switch device."""

    signature = {
        # "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, 
        # reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, 
        # manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, 
        # descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, 
        # *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
        MODELS_INFO: [
            ("_TZE200_swaamsoy", "TS0601"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    LevelControl.cluster_id,
                    Color.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaOnOffMCU,
                    TuyaInWallLevelControl,
                    Color.cluster_id,
                    TuyaLevelControlManufCluster,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        }
    }


class TuyaDoubleSwitchDimmer(TuyaDimmerSwitch):
    """Tuya double channel dimmer device."""

    signature = {
        # "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0,
        #                     user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>,
        #                     mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>,
        #                     manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264,
        #                     maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True,
        #                     *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True,
        #                     *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)
        #   "endpoints": {
        #       "1": { "profile_id": 260, "device_type": "0x0051", "in_clusters": [ "0x0000", "0x0004", "0x0005", "0xef00" ], "out_clusters": [ "0x000a", "0x0019" ] }
        #   },
        #  "manufacturer": "_TZE200_e3oitdyu",
        #  "model": "TS0601",
        #  "class": "zigpy.device.Device"
        #  }
        MODELS_INFO: [
            ("_TZE200_e3oitdyu", "TS0601"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaLevelControlManufCluster,
                    TuyaOnOffMCU,
                    TuyaInWallLevelControl,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    TuyaOnOffMCU,
                    TuyaInWallLevelControl,
                ],
                OUTPUT_CLUSTERS: [],
            },
        }
    }

class TuyaSingleSwitchDimmerGP(TuyaDimmerSwitch):
    """Tuya touch switch device."""

    signature = {
        MODELS_INFO: [
            ("_TZE200_3p5ydos3", "TS0601"),
            ("_TZE200_ip2akl4w", "TS0601"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.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: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaLevelControlManufCluster,
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }


class TuyaDoubleSwitchDimmerGP(TuyaDimmerSwitch):
    """Tuya double channel dimmer device."""

    signature = {
        MODELS_INFO: [
            ("_TZE200_fjjbhx9d", "TS0601"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaLevelControlManufCluster,
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }


# ---------------------------------------------------------------------------
# _TZE200_vm1gyrso:
# Added this customer code block
# 2022-04-07
# ---------------------------------------------------------------------------
class TuyaTripleSwitchDimmerGPP(TuyaDimmerSwitch):
    """Tuya double channel dimmer device."""

    signature = {
        # "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, 
        #                     reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, 
        #                     mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, 
        #                     manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, 
        #                     maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, 
        #                     *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, 
        #                     *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, 
        #                     *is_security_capable=False)",
        # "endpoints": {
        #     "1": {"profile_id": 260, "device_type": "0x0051", "in_clusters": ["0x0000","0x0004","0x0005","0xef00"],"out_clusters": ["0x000a","0x0019"]},
        #     "242": {"profile_id": 41440,"device_type": "0x0061","in_clusters": [],"out_clusters": ["0x0021"]}
        # },
        # "manufacturer": "_TZE200_vm1gyrso",
        # "model": "TS0601",
        # "class": "zigpy.device.Device"

        MODELS_INFO: [
            ("_TZE200_vm1gyrso", "TS0601"),
        ],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaLevelControlManufCluster,
                    #TuyaOnOffMCU,
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    # TuyaOnOffMCU,
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [],
            },
            3: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    #TuyaOnOffMCU,
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }

@javicalle
Copy link
Collaborator

@javicalle BTW is there still something that stands in the way of a PR or will make one soon?

No, i'm working on it, but it's going to be hard to collect all the devices codes and quirks in this thread... 😅

@Tropaion
Copy link
Contributor

@javicalle Yeah, makes sense 😄 if I can help with something just say so^^

@ToastySefac
Copy link

@Tropaion I've restarted HA, as well as the entire VM.

If you want to try, I think this class might work. A new class and the necessary imports have been added.

@javicalle Thanks for looking into it. Here is the error log, but is that just indicative of it not loading the quirk at all?

2022-04-11 06:59:37 WARNING (MainThread) [zigpy.zcl] Unknown cluster 0xEF00
2022-04-11 06:59:37 WARNING (MainThread) [zigpy.zcl] [0x9E77:1:0xef00] Unknown cluster command 2 b'U\xf3\x06\x02\x00\x04\x00\x00\x00\x00'

@javicalle
Copy link
Collaborator

@ToastySefac there was a few errors in the code. I have updated it in the comment. Please replace with the new version and test.

Here is the error log, but is that just indicative of it not loading the quirk at all?

Not necessarily. That particular message can occur without it being an error in itself.
The device signature is what will tell you if the quirk has loaded successfully or not.

@ToastySefac
Copy link

ToastySefac commented Apr 10, 2022

I've used the new code with the following error:

2022-04-11 07:31:04 WARNING (MainThread) [zigpy.zcl] Unknown cluster 0xEF00
2022-04-11 07:31:10 WARNING (MainThread) [zigpy.zcl] [0x9E77:1:0xef00] Unknown cluster command 2 b'V\x14\x06\x02\x00\x04\x00\x00\x00\x00'
2022-04-11 07:31:10 WARNING (MainThread) [zigpy.zcl] [0x9E77:1:0xef00] Unknown cluster command 2 b'V\x14\x06\x02\x00\x04\x00\x00\x00\x00'
2022-04-11 07:31:10 WARNING (MainThread) [zigpy.zcl] [0x9E77:1:0xef00] Unknown cluster command 2 b'V\x14\x06\x02\x00\x04\x00\x00\x00\x00'
2022-04-11 07:31:17 WARNING (MainThread) [zigpy.zcl] [0x9E77:1:0xef00] Unknown cluster command 2 b'V\x15\x06\x02\x00\x04\x00\x00\x00\x00'
2022-04-11 07:31:17 WARNING (MainThread) [zigpy.zcl] [0x9E77:1:0xef00] Unknown cluster command 2 b'V\x15\x06\x02\x00\x04\x00\x00\x00\x00'

After reloading, my device signature still looks like this:

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4098, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0104",
      "in_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x0008",
        "0x0300",
        "0xef00"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZE200_swaamsoy",
  "model": "TS0601",
  "class": "zigpy.device.Device"
}

@Tropaion
Copy link
Contributor

@javicalle Since I have holidays the next few days, if it helps, I can collect the device signatures of the dimmers in the various issues and comments

@javicalle
Copy link
Collaborator

javicalle commented Apr 11, 2022

@Tropaion It would be really great if you could do that job.
In fact I think you are able to create the complete PR.

The class tuya.mcu.__init__.py has already been patched and you don't need to take it into account.
The rest is just to identify each MODEL_INFO with the signature and the type of device it is (single, double, triple...)
Finally note that the TuyaSingleSwitchDimmer class uses an 'older' implementation that is different from the rest. We can make the decision to also adapt it to the 'new' approach, although I don't think so I can't confirm that it is not a groundbreaking change.

Ummm, I have review the code and have two or three little tricks dificult to caught. Let me take care to the generic classes to me if you don't mind.

@javicalle
Copy link
Collaborator

@ToastySefac Although it may look similar, it seems to be a different device.
Please, in order not to continue expanding this thread that is becoming unmanageable, create a new ticket with your problem.
Add all possible information about it (signature, link to a store that helps identify the device, etc...)

Thanks in advanced.

@ToastySefac
Copy link

Ok, no problem. I have the ticket already open, which led me here:
#1463

Thanks

@Tropaion
Copy link
Contributor

Tropaion commented Apr 11, 2022

It would be really great if you could do that job.
In fact I think you are able to create the complete PR.

@javicalle I will try, but probably will take until tomorrow. I will notify you for a final check before PR 😄

Ummm, I have review the code and have two or three little tricks dificult to caught. Let me take care to the generic classes to me if you don't mind.

Would definitely be better 😄

@Tropaion
Copy link
Contributor

@javicalle I now searched through all issues and made a summary:

Devices from this Issue

Info: 1 Gang Dimmer with GP @Daandeve
Manufacturer: _TZE200_ip2akl4w
Class: TuyaSingleSwitchDimmerGP

Info: 2 Gang Dimmer with GP @Daandeve
Manufacturer: _TZE200_fjjbhx9d
Class: TuyaDoubleSwitchDimmerGP

Info: 1 Gang Dimmer with GP @Tropaion
Manufacturer: _TZE200_3p5ydos3
Class: TuyaSingleSwitchDimmerGP

Devices from other Issues

#1476
Manufacturer: _TZE200_1agwnems
Class: TuyaSingleSwitchDimmer

#1103
Manufacturer: _TZE200_3p5ydos3
Class: TuyaSingleSwitchDimmerGP

#730
Manufacturer: _TZE200_dfxkcots
Class: TuyaSingleSwitchDimmer

#1011
Manufacturer: _TZE200_la2c2uo9
Class: TuyaSingleSwitchDimmer

#1461
3-Gang Dimmer with GP: #1302 (comment)
Manufacturer: _TZE200_vm1gyrso
Class: TuyaTripleSwitchDimmerGP

About this device I'm not sure which class to use, I need your help:

#1463
Info: 1 Gang Dimmer
Manufacturer: _TZE200_swaamsoy

Device is already added to class TuyaSingleSwitchDimmer but the issue mentions another class needed for device, which one should I use?

Current ts0601_dimmer.py
"""Tuya based touch switch."""

from typing import Optional, Union

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

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.tuya import (
    TuyaDimmerSwitch,
    TuyaLevelControl,
    TuyaManufacturerClusterOnOff,
    TuyaManufacturerLevelControl,
    TuyaManufCluster,
    TuyaOnOff,
)
from zhaquirks.tuya.mcu import (
    TuyaInWallLevelControl,
    TuyaLevelControlManufCluster,
    TuyaOnOff as TuyaOnOffMCU,
)

class NoManufacturerCluster(CustomCluster):
    """Forces the NO manufacturer id in command."""

    async def command(
        self,
        command_id: Union[foundation.GeneralCommand, 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("Setting the NO manufacturer id in command: %s", command_id)
        status = await super().command(
            command_id,
            *args,
            manufacturer=foundation.ZCLHeader.NO_MANUFACTURER_ID,
            expect_reply=expect_reply,
            tsn=tsn,
        )

        return foundation.GENERAL_COMMANDS[foundation.GeneralCommand.Default_Response].schema(command_id=command_id, status=status)
        
class TuyaOnOffNM(NoManufacturerCluster, TuyaOnOffMCU):
    """Tuya OnOff cluster with NoManufacturerID."""

    pass

class TuyaInWallLevelControlNM(NoManufacturerCluster, TuyaInWallLevelControl):
    """Tuya Level cluster for inwall dimmable device with NoManufacturerID."""

    pass

# --- DEVICE SUMMARY ---
# TuyaSingleSwitchDimmer: 0x00, 0x04, 0x05, 0xEF00; 0x000A, 0x0019
# TuyaDoubleSwitchDimmer: 0x00, 0x04, 0x05, 0xEF00; 0x000A, 0x0019
# - Dimmer with Green Power Proxy: Endpoint=242 profile=41440 device_type=0x0061, output_clusters: 0x0021 -
# TuyaSingleSwitchDimmerGP: 0x00, 0x04, 0x05, 0xEF00; 0x000A, 0x0019
# TuyaDoubleSwitchDimmerGP: 0x00, 0x04, 0x05, 0xEF00; 0x000A, 0x0019
# TuyaTripleSwitchDimmerGP: 0x00, 0x04, 0x05, 0xEF00; 0x000A, 0x0019

class TuyaSingleSwitchDimmer(TuyaDimmerSwitch):
    """Tuya touch switch device."""

    signature = {
        MODELS_INFO: [
            ("_TZE200_dfxkcots", "TS0601"),
            ("_TZE200_whpb9yts", "TS0601"),
            ("_TZE200_ebwgzdqq", "TS0601"),
            ("_TZE200_9i9dt8is", "TS0601"),
            ("_TZE200_swaamsoy", "TS0601"),
            ("_TZE200_0nauxa0p", "TS0601"),
            ("_TZE200_la2c2uo9", "TS0601"),
            ("_TZE200_1agwnems", "TS0601"),
        ],
        ENDPOINTS: {
            # <SimpleDescriptor endpoint=1 profile=260 device_type=0x0051
            # device_version=1
            # input_clusters=[0, 4, 5, 61184]
            # output_clusters=[10, 25]>
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    LevelControl.cluster_id,
                    TuyaManufacturerClusterOnOff,
                    TuyaOnOff,
                    TuyaManufacturerLevelControl,
                    TuyaLevelControl,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        }
    }


class TuyaDoubleSwitchDimmer(TuyaDimmerSwitch):
    """Tuya double channel dimmer device."""

    signature = {
        MODELS_INFO: [
            ("_TZE200_e3oitdyu", "TS0601"),
        ],
        ENDPOINTS: {
            # <SimpleDescriptor endpoint=1 profile=260 device_type=0x0051
            # device_version=1
            # input_clusters=[0, 4, 5, 61184]
            # output_clusters=[10, 25]>
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaLevelControlManufCluster,
                    TuyaOnOffMCU,
                    TuyaInWallLevelControl,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    TuyaOnOffMCU,
                    TuyaInWallLevelControl,
                ],
                OUTPUT_CLUSTERS: [],
            },
        }
    }

class TuyaSingleSwitchDimmerGP(TuyaDimmerSwitch):
    """Tuya touch switch device."""

    signature = {
        MODELS_INFO: [
            ("_TZE200_3p5ydos3", "TS0601"),
            ("_TZE200_ip2akl4w", "TS0601"),
        ],
        ENDPOINTS: {
            # <SimpleDescriptor endpoint=1 profile=260 device_type=0x0100
            # device_version=1
            # input_clusters=[0, 4, 5, 61184]
            # output_clusters=[10, 25]>
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # input_clusters=[]
            # output_clusters=[33]
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaLevelControlManufCluster,
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }


class TuyaDoubleSwitchDimmerGP(TuyaDimmerSwitch):
    """Tuya double channel dimmer device."""

    signature = {
        MODELS_INFO: [
            ("_TZE200_fjjbhx9d", "TS0601"),
        ],
        ENDPOINTS: {
            # <SimpleDescriptor endpoint=1 profile=260 device_type=0x0100
            # device_version=1
            # input_clusters=[0, 4, 5, 61184]
            # output_clusters=[10, 25]>
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # input_clusters=[]
            # output_clusters=[33]
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaLevelControlManufCluster,
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }

class TuyaTripleSwitchDimmerGP(TuyaDimmerSwitch):
    """Tuya double channel dimmer device."""

    signature = {
        MODELS_INFO: [
            ("_TZE200_vm1gyrso", "TS0601"),
        ],
        ENDPOINTS: {
            # <SimpleDescriptor endpoint=1 profile=260 device_type=0x0100
            # device_version=1
            # input_clusters=[0, 4, 5, 61184]
            # output_clusters=[10, 25]>
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaManufCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # input_clusters=[]
            # output_clusters=[33]
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaLevelControlManufCluster,
                    #TuyaOnOffMCU,
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    # TuyaOnOffMCU,
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [],
            },
            3: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                INPUT_CLUSTERS: [
                    #TuyaOnOffMCU,
                    TuyaOnOffNM,
                    TuyaInWallLevelControlNM,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: 41440,
                DEVICE_TYPE: 97,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        }
    }

@javicalle
Copy link
Collaborator

javicalle commented Apr 13, 2022

@Tropaion explendit job!!!

Some comments (to myself mostly):

  • Device _TZE200_1agwnems not confirmed.
  • Class TuyaLevelControl quirk for move_to_level_with_on_off must also be considered (just for MCU devices):
  • DPs for 3 gang device must be added (class TuyaLevelControlManufCluster)
  • Device _TZE200_swaamsoy would need another definition (the TuyaSingleSwitchDimmerPlus in the issue). Not sure if I want to include it in the same PR. I will review it later.

I have created the PR #1489. In draft mode for now.

@javicalle
Copy link
Collaborator

Device is already added to class TuyaSingleSwitchDimmer but the issue mentions another class needed for device, which one should I use?

We can have the MODELS_INFO duplicated because in this case endpoints/cluster must also match.
So at the end we will have the same device in the 2 definitions. The definition search will match the correct one.

@Tropaion
Copy link
Contributor

@javicalle Looks good, now we shouldn't be far away from the goal.

We can have the MODELS_INFO duplicated because in this case endpoints/cluster must also match.
So at the end we will have the same device in the 2 definitions. The definition search will match the correct one.

I thought so, but the question is if both are needed.

BTW did you remove/change the commends I made? Do you prefer to write the whole device signature?

@javicalle
Copy link
Collaborator

I thought so, but the question is if both are needed.

Definitely yes. The 'original' one was added months ago (PR #1010) and probably was needed.
I have read other reports in which the device is repeated, perhaps because the manufacturer is careless or because they reuse the definitions of other devices.
We also have no way of knowing if all the definitions are being used and the risk of removing it is that something will be broken, so 🤷🏻‍♂️

BTW did you remove/change the commends I made? Do you prefer to write the whole device signature?

No. I like and prefer your way to comment.
Full signature sometimes don't match between diferent devices, but the 'translation' from cluster name to value is very usefull to me.
Also the DEVICE SUMMARY will give a fast view to the available definitions. Once again a good idea.

I hope to release the final version today.

@itsolon
Copy link

itsolon commented Apr 13, 2022 via email

@javicalle
Copy link
Collaborator

Question is: if you have finished your quirks and the device works which is true... How can users like me .. know when the local quick is not necessary anymore and remove it then afterwards?

Sort answer: when HA includes the version of the zha-device-handlers library that includes the PR
Long answer: look at this comment wich (more or less) answer your question (versions involved are diferent, but the process is the same).

@Tropaion
Copy link
Contributor

If we are at questioning @javicalle 😄 I also have one.
I still haven't found out what the use of Green Power Proxy Cluster is? For me it looks like a useless cluster...

@javicalle
Copy link
Collaborator

Meeeeeec, for Zigbee's specification questions I'm not your man.

I just put the pieces together.
Those who understand what each piece does are MattWestb and dmulcahey.

(I haven't found any direct use for this cluster, but either didn't search the answer).

@Daandeve
Copy link
Author

I can confirm than my 1 gang (_TZE200_ip2akl4w) & 2 gang (_TZE200_fjjbhx9d) switches are working perfectly with the new changes on home assistant 2022.4.2

@MattWestb
Copy link
Contributor

@Tropaion The Zigbee GPP is only one proxy server function for ZGPP devices (ZGP network frames) that use Zigbee Green power for sending commands. ZGP is not implanted in ZHA but some French devs have getting it working with Zigpy libs with some patches. Also the its one function that is autonomous in the device and the network mesh that we cant / dont need / shall not doing anything with it then its working (and is implanted) in the host system but i think in quirks we ska having it in the replace if its in the device signature so we can see that the device supporting it from ZHA GUI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants