Repository: zigpy/zha-device-handlers

Issue:
[Device Support Request] Tuya TS0001 relay
**Is your feature request related to a problem? Please describe.**
Just received Tuya TS0001 relay, 
![image](https://user-images.githubusercontent.com/26710811/139685824-328bdf97-37c5-4271-acf0-88210c79f963.png)
![image](https://user-images.githubusercontent.com/26710811/139685861-6ed599fb-47d6-4bcf-b096-4c50eea8bb72.png)
https://www.aliexpress.com/item/1005002482791975.html

It hasn't quirk, so works just basically.

In Tuya Smart application, it has power outage behavior and external switch type settings. The first setting is already implemented for plugs TS011F and TS0121, so it could implemented without problems. Switch type setting haven't been implemented yet.

Here is a screenshot from Tuya Smart application:
![image](https://user-images.githubusercontent.com/26710811/139689027-5e8389d8-9375-47dd-8037-61ca2b524a2d.png)

**Describe the solution you'd like**
The external switch type attribute could be added.

**Device signature - this can be acquired by removing the device from ZHA and pairing it again from the add devices screen. Be sure to add the entire content of the log panel after pairing the device to a code block below this line.**
```
{
  "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": "0x010a",
      "in_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZ3000_ark8nv4y",
  "model": "TS0001",
  "class": "ts011f_plug.Plug_0001"
}

```
**Additional context**
@MattWestb may be you know attribute id for external switch type?



Discussion:
I have making one PR for adding back light for some switches and also adding changing some switches sending light commands or clicks that all is on the on/off cluster but is not being merged.

I have funding that some tuya devices is using switch mode on cluster 0xE001 https://github.com/zigpy/zigpy/discussions/823#discussioncomment-1539469 but your devices is not having that.

So it can it have implanting it on the On/Off cluster but we dont knowing what attribute tuya is using or they is using it on the 0xE000 cluster but have hidden the cluster and must being added in the quirk for working or they have doing it in one other not known way.

Then you is having one tuya ZBGW and can controlling  the device it wold being great if you can sniffing it so we can see how they is doing it if you is having some device for doing sniffing (TI CC-2531 or one EM35X / EFR21MG with NCP firmware).
> I have funding that some tuya devices is using switch mode on cluster 0xE001 [zigpy/zigpy#823 (comment)](https://github.com/zigpy/zigpy/discussions/823#discussioncomment-1539469) but your devices is not having that.

No, mine device has 0xE001 cluster. It looks like 0xD030 attribute will make a trick, I'll check it.
I've posted wrong ZigBee information after applying my quick and dirty quirk. Here is raw information:

```
{
  "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": "0x0100",
      "in_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZ3000_ark8nv4y",
  "model": "TS0001",
  "class": "zigpy.device.Device"
}
```

OK i was missing  that then you was not having it in the replace in the quirk so that  is great !!

Try implanting it like its done with the power state and i think it will working OK.

My intention is getting it in tuya INI and then adding it to TS011F and TS0121 and also the TS001X quirk but i dont have any one for testing it and the devs have not merger it.

This is interesting !!!

And i think its needed on new quirk TS000X for your device :-)))
Then you is making the new 0xE001 you can doing some extra attributes like 0x03, 0x04 and so on and looking if you is getting response from the device and if the function is changed.
I've tried to make it in this way

```
class TuyaSwitchMode(t.enum8):
    """Tuya power on state enum."""

    Toggle = 0x00
    State = 0x01 
    Momentary = 0x02


class TuyaSwitchModeCluster(CustomCluster):
    """Tuya manufacturer specific cluster 57345."""

    name = "Tuya Manufacturer Specific"
    cluster_id = 0xE001
    ep_attribute = "tuya_is_pita_1"
    attributes.update({0xD030: ("switch_mode", TuyaSwitchMode)})

```


but received an error:

```
  File "/config/zhaquirks/ts011f_plug.py", line 52, in TuyaSwitchModeCluster
    attributes.update({0xD030: ("switch_mode", TuyaSwitchMode)})
NameError: name 'attributes' is not defined
```

where I have to take attributes?
`    attributes.update({0xD030: ("switch_mode", TuyaSwitchMode)})` 
Attribute must being imported or defined.

I looking how it was made in the first implementation before i was moving it to tuya INIT.
from the original implementation in the TS1021:
```
class PowerOnState(t.enum8):
    """Tuya power on state enum."""

    Off = 0x00
    On = 0x01
    LastState = 0x02


class OnOffRestorePowerCluster(CustomCluster, OnOff):
    """Tuya on off cluster with restore state."""

    attributes = OnOff.attributes.copy()
    attributes.update({0x8002: ("power_on_state", PowerOnState)})
```
that is not doing one new cluster but is updating the on/off cluster.
The TS130F is doing one new cluster and adding attributes like this:
```
class TuyaWithBacklightOnOffCluster(CustomCluster):
    """TuyaSmartCurtainOnOffCluster: fire events corresponding to press type."""

    cluster_id = OnOff.cluster_id

    LIGHT_MODE_1 = {0x8001: 0}
    LIGHT_MODE_2 = {0x8001: 1}
    LIGHT_MODE_3 = {0x8001: 2}

    attributes = {0x8001: ("backlight_mode", t.enum8)}
```
I think the latest is nor like you like to have and changing the cluster_id = `OnOff.cluster_id` to `cluster_id = 0xE001`

Good naming you can do later the most importent is you is getting the function working.
I can confirm - it works:

```
class TuyaSwitchMode(t.enum8):
    """Tuya switch mode enum."""

    Toggle = 0x00
    State = 0x01 
    Momentary = 0x02


class TuyaSwitchModeCluster(CustomCluster):
    """Tuya switch mode cluster 57345."""

    name = "Tuya Manufacturer Specific"
    cluster_id = 0xE001
    ep_attribute = "tuya_is_pita_1"
    attributes = {0xD030: ("switch_mode", TuyaSwitchMode)}
```
## GREAT  !!
Wot is the `ep_attribute = "tuya_is_pita_1"` doing ? 
I think its one cosmic description but i dont knowing, can you looking because i like have better names on things.

Then you have making it working and merger the PR i can moving it to the tuya INI and only using linking in your quirk but  you can doing it from the beginning if you like but i ts little trickier edeting the INIT then it must being done in the HA container.

Great work done !!
> Wot is the `ep_attribute = "tuya_is_pita_1"` doing ?

Have no idea. I just respect existing code and use the rule "don't touch anything"
BTW, in both ts011f_plug.py and ts0121_plug.py have wrong cluster numbers and wrong device_type in "# <SimpleDescriptor" comments. device_type must be 266. In input_clusters number 9 is needless. 
Its some quirks that is no fitting at all (i think the TS113F is one of them) and that is very bad then trying adding other devices with little different cluster settings.

Look little how other is made and copy it and changing the information its the best.

The profiles / device type you is can finding here: https://github.com/zigpy/zigpy/blob/dev/zigpy/profiles/zha.py

You must finding one good name for the "new made cluster" that all other devices can using in the future !!!

I was thinking putting somthing like this in tuya INIT:
```
class TuyaSwitchMode(t.enum8):
    """Tuya switch mode enum."""

    Toggle = 0x00
    State = 0x01 
    Momentary = 0x02


class TuyaZBSwitchModeCluster(CustomCluster):
    """Tuya switch mode cluster 57345."""

    name = "Tuya Switch Mode Cluster"
    cluster_id = 0xE001
    ep_attribute = "Tuya_Switch_Mode_Cluster"
    attributes = {0xD030: ("switch_mode", TuyaSwitchMode)}
```
But i dont knowing if its working OK with initiating the cluster.

@jacekk015 you is knowing how to do it right.

I like adding one new tuya cluster to INIT that can sending and receiving this attributes and its looks working OK in local quirks.
But i think it shall have some initiation for working OK.
Do you having some suggestions how to do it right ??

Thanks in advance !!!
There already is SwitchMode enum in INIT. I think it's better to name it ExternalSwitchType:

```
class ExternalSwitchType(t.enum8):
    """Tuya external switch type enum."""

    Toggle = 0x00
    State = 0x01 
    Momentary = 0x02


class TuyaZBExternalSwitchTypeCluster(CustomCluster):
    """Tuya External Switch Type Cluster"""

    name = "Tuya External Switch Type Cluster"
    cluster_id = 0xE001
    ep_attribute = "tuya_external_switch_type"
    attributes = {0xD030: ("external_switch_type", ExternalSwitchType)}
```
And maybe it's better to move constant 0xE001 to constants section, right before TUYA_CLUSTER_ID = 0xEF00
I think its very good not mixing the variables and getting strange collisions with the naming !!
Thanks for pointing it out and fixing it !!

I trying making all "noraml" tuya Zigbee with names so easy can see its tuya and Zigbee and not the DP devices things belonging.

I was thinking putting the  0xE001 early in the INIT after this:
https://github.com/zigpy/zha-device-handlers/blob/242d5f36b9d9bdd2ee3594e56fa4bac47c369de8/zhaquirks/tuya/__init__.py#L19-L23
In line 23:
```
TUYA_SWITCH_MODE_CLUSTER_ID = 0xE001
```
and in the new cluster:
```
    cluster_id = TUYA_SWITCH_MODE_CLUSTER_ID
```
Looks little long but i think its better doing as the original is being done.
Perhaps with external but then its being very long.
I think, anyway, it should be TYPE not MODE
More users have the same problem like you but 3 times more #1145 :-)
I have making some adding in INIT and moved both "PITA" clusters there:
```
# ---------------------------------------------------------
# Tuya Custom Cluster ID
# ---------------------------------------------------------
TUYA_CLUSTER_ID = 0xEF00
TUYA_CLUSTER_E000_ID = 0xE000
TUYA_CLUSTER_E001_ID = 0xE001
# ---------------------------------------------------------
```
And adding definitions for both:
```
# Tuya Zigbee Cluster 0xE000 Implementation
class TuyaZBE000Cluster(CustomCluster):
    """Tuya manufacturer specific cluster 57344."""

    name = "Tuya Manufacturer Specific"
    cluster_id = TUYA_CLUSTER_E000_ID
    ep_attribute = "tuya_is_pita_0"


# Tuya Zigbee Cluster 0xE001 Implementation
class ExternalSwitchType(t.enum8):
    """Tuya external switch type enum."""

    Toggle = 0x00
    State = 0x01
    Momentary = 0x02


class TuyaZBExternalSwitchTypeCluster(CustomCluster):
    """Tuya External Switch Type Cluster"""

    name = "Tuya External Switch Type Cluster"
    cluster_id = TUYA_CLUSTER_E001_ID
    ep_attribute = "tuya_external_switch_type"
    attributes = {0xD030: ("external_switch_type", ExternalSwitchType)}
```
The INIT is one updated version with renamed cluster so need also updating the ts011f_plug.py and ts0121_plug.py in the container or ZHA is not loading.

And one new `ts000x.py` with your relay plus the 3 gang in the new issue.

The TS011F Its loading in my test and production system and i can controlling the power restore state and back light (but not back light shown on the device like yours) but is not having switch mode implanted but other user have TS011F devices that having that.

Can you testing if i have making your device OK and its working and also taking one fast look on the 3 gang if its looks OK then i can testing it on the user.

Also more feedback on the copy and pace code is very welcome !!

[custom_zha_quirks.zip](https://github.com/zigpy/zha-device-handlers/files/7528530/custom_zha_quirks.zip)


> Can you testing if i have making your device OK and its working and also taking one fast look on the 3 gang if its looks OK then i can testing it on the user.

Unfortunately, I'm not able to check it. There is a problem with import. Statement:

`from zhaquirks.tuya import (`

causes error since in original zha-device-handlers/zhaquirks/tuya/\_\_init\_\_.py not defines such classes. I've tried to change import to 

`from . import (`

but the error is "ImportError: attempted relative import with no known parent package" in such case.


In witch quirk or is it in the INIT that is giving the error ?
I was getting somthing like that then copy the INIT to zhquirk and not zhaquirk/tuya.
But it was working OK in my production system.
The INIT must being copied into the HA container or its cant being imported of the quirks (both local and updated in the container).
I've tried it in custom_quirks. Ok, I'll try to work with HA container
TS011F and TS0121 must being patched for the new named (in the new INIT) of the power state cluster in the container. After that you can have copy of this in the custom folder (I was first deleting them in the container and its working 2).
Yes, my TS0001 works well with this code. Only one issue. 

Original device type is zha.DeviceType.ON_OFF_LIGHT. If we keep it in replacement section, there are two entities: 

![image](https://user-images.githubusercontent.com/26710811/141499095-19295492-8bff-4c8a-8e80-4ccc728d5339.png)

I've resolved it by changing it in replacement to zha.DeviceType.ON_OFF_PLUG_IN_UNIT:

```
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaZBOnOffAttributeCluster,
                    TuyaZBE000Cluster,
                    TuyaZBExternalSwitchTypeCluster,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
        },
    }

```

With this change, there is only one entity.


@MattWestb, is it possible to expose these attributes as entities with config category in ZHA?
I putting it in the replace and then testing the 3 gang on the new user :-))

ZHA is showing some attributes like battery voltage, type and number of batteries in the battery card (ZHA have starting saving all attributes in the device DB so the system is having them).
If like having more information you need doing one custom card in HA or making one extended function one in ZHA.
```
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaZBOnOffAttributeCluster,
                    TuyaZBE000Cluster,
                    TuyaZBExternalSwitchTypeCluster,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
        },
```
I think you can doing custom quirks that is exposed as switched and can sending attribute thru bus and getting its status from the bus like is made in tuya TRVs.
But it must being made as custom quirks then its never going in the main ZHA. then its braking the Zigbee standard.

Or you is implanting one nice device card for ZHA :-))

Resolving patch:
diff --git a/zhaquirks/tuya/__init__.py b/zhaquirks/tuya/__init__.py
--- a/zhaquirks/tuya/__init__.py
+++ b/zhaquirks/tuya/__init__.py
@@ -20,6 +20,8 @@
 # Tuya Custom Cluster ID
 # ---------------------------------------------------------
 TUYA_CLUSTER_ID = 0xEF00
+TUYA_CLUSTER_E000_ID = 0xE000
+TUYA_CLUSTER_E001_ID = 0xE001
 # ---------------------------------------------------------
 # Tuya Cluster Commands
 # ---------------------------------------------------------
@@ -844,6 +846,33 @@ class TuyaZBElectricalMeasurement(CustomCluster, ElectricalMeasurement):
     _CONSTANT_ATTRIBUTES = {AC_CURRENT_MULTIPLIER: 1, AC_CURRENT_DIVISOR: 1000}
 
 
+# Tuya Zigbee Cluster 0xE000 Implementation
+class TuyaZBE000Cluster(CustomCluster):
+    """Tuya manufacturer specific cluster 57344."""
+
+    name = "Tuya Manufacturer Specific"
+    cluster_id = TUYA_CLUSTER_E000_ID
+    ep_attribute = "tuya_is_pita_0"
+
+
+# Tuya Zigbee Cluster 0xE001 Implementation
+class ExternalSwitchType(t.enum8):
+    """Tuya external switch type enum."""
+
+    Toggle = 0x00
+    State = 0x01
+    Momentary = 0x02
+
+
+class TuyaZBExternalSwitchTypeCluster(CustomCluster):
+    """Tuya External Switch Type Cluster."""
+
+    name = "Tuya External Switch Type Cluster"
+    cluster_id = TUYA_CLUSTER_E001_ID
+    ep_attribute = "tuya_external_switch_type"
+    attributes = {0xD030: ("external_switch_type", ExternalSwitchType)}
+
+
 # Tuya Window Cover Implementation
 class TuyaManufacturerWindowCover(TuyaManufCluster):
     """Manufacturer Specific Cluster for cover device."""
diff --git a/zhaquirks/tuya/ts000x.py b/zhaquirks/tuya/ts000x.py
new file mode 100644
--- /dev/null
+++ b/zhaquirks/tuya/ts000x.py
@@ -0,0 +1,198 @@
+"""tuya TS000X Switches."""
+
+from zigpy.profiles import zha
+from zigpy.quirks import CustomDevice
+from zigpy.zcl.clusters.general import (
+    Basic,
+    GreenPowerProxy,
+    Groups,
+    Identify,
+    OnOff,
+    Ota,
+    Scenes,
+    Time,
+)
+
+from zhaquirks.const import (
+    DEVICE_TYPE,
+    ENDPOINTS,
+    INPUT_CLUSTERS,
+    MODEL,
+    OUTPUT_CLUSTERS,
+    PROFILE_ID,
+)
+from zhaquirks.tuya import (
+    TuyaZBE000Cluster,
+    TuyaZBExternalSwitchTypeCluster,
+    TuyaZBOnOffAttributeCluster,
+)
+
+
+class Switch_1G_GPP(CustomDevice):
+    """Tuya 1 gang switch module with restore power state support."""
+
+    signature = {
+        MODEL: "TS0001",
+        ENDPOINTS: {
+            # <SimpleDescriptor endpoint=1 profile=266 device_type=256
+            # device_version=1
+            # input_clusters=[0, 3, 4, 5, 6, 57344, 57345]
+            # output_clusters=[10, 25]>
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    TuyaZBE000Cluster.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            },
+            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
+            # device_version=1
+            # input_clusters=[]
+            # output_clusters=[33]>
+            242: {
+                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.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaZBOnOffAttributeCluster,
+                    TuyaZBE000Cluster,
+                    TuyaZBExternalSwitchTypeCluster,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            },
+        },
+    }
+
+
+class Switch_3G_GPP(CustomDevice):
+    """Tuya 3 gang switch module with restore power state support."""
+
+    signature = {
+        MODEL: "TS0003",
+        ENDPOINTS: {
+            # <SimpleDescriptor endpoint=1 profile=260 device_type=256
+            # device_version=1
+            # input_clusters=[0, 3, 4, 5, 6, 57344, 57345]
+            # output_clusters=[10, 25]>
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    TuyaZBE000Cluster.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            },
+            # <SimpleDescriptor endpoint=2 profile=260 device_type=256
+            # device_version=1
+            # input_clusters=[4, 5, 6, 57345]
+            # output_clusters=[]>
+            2: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
+                INPUT_CLUSTERS: [
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            # <SimpleDescriptor endpoint=3 profile=260 device_type=256
+            # device_version=1
+            # input_clusters=[4, 5, 6, 57345]
+            # output_clusters=[]>
+            3: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
+                INPUT_CLUSTERS: [
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
+            # device_version=0
+            # input_clusters=[]
+            # output_clusters=[33]>
+            242: {
+                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.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaZBOnOffAttributeCluster,
+                    TuyaZBE000Cluster,
+                    TuyaZBExternalSwitchTypeCluster,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            },
+            2: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaZBOnOffAttributeCluster,
+                    TuyaZBExternalSwitchTypeCluster,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            3: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaZBOnOffAttributeCluster,
+                    TuyaZBExternalSwitchTypeCluster,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            242: {
+                PROFILE_ID: 41440,
+                DEVICE_TYPE: 97,
+                INPUT_CLUSTERS: [],
+                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
+            },
+        },
+    }
diff --git a/zhaquirks/tuya/ts011f_plug.py b/zhaquirks/tuya/ts011f_plug.py
--- a/zhaquirks/tuya/ts011f_plug.py
+++ b/zhaquirks/tuya/ts011f_plug.py
@@ -1,7 +1,7 @@
 """TS011F plug."""
 
 from zigpy.profiles import zha
-from zigpy.quirks import CustomCluster, CustomDevice
+from zigpy.quirks import CustomDevice
 from zigpy.zcl.clusters.general import (
     Basic,
     GreenPowerProxy,
@@ -24,28 +24,14 @@
     PROFILE_ID,
 )
 from zhaquirks.tuya import (
+    TuyaZBE000Cluster,
     TuyaZBElectricalMeasurement,
+    TuyaZBExternalSwitchTypeCluster,
     TuyaZBMeteringCluster,
     TuyaZBOnOffAttributeCluster,
 )
 
 
-class TuyaClusterE000(CustomCluster):
-    """Tuya manufacturer specific cluster 57344."""
-
-    name = "Tuya Manufacturer Specific"
-    cluster_id = 0xE000
-    ep_attribute = "tuya_is_pita_0"
-
-
-class TuyaClusterE001(CustomCluster):
-    """Tuya manufacturer specific cluster 57345."""
-
-    name = "Tuya Manufacturer Specific"
-    cluster_id = 0xE001
-    ep_attribute = "tuya_is_pita_1"
-
-
 class Plug(CustomDevice):
     """Tuya plug with restore power state support."""
 
@@ -67,8 +53,8 @@ class Plug(CustomDevice):
                     OnOff.cluster_id,
                     Metering.cluster_id,
                     ElectricalMeasurement.cluster_id,
-                    TuyaClusterE000.cluster_id,
-                    TuyaClusterE001.cluster_id,
+                    TuyaZBE000Cluster.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
                 ],
                 OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
             },
@@ -97,8 +83,8 @@ class Plug(CustomDevice):
                     TuyaZBOnOffAttributeCluster,
                     TuyaZBMeteringCluster,
                     TuyaZBElectricalMeasurement,
-                    TuyaClusterE000,
-                    TuyaClusterE001,
+                    TuyaZBE000Cluster,
+                    TuyaZBExternalSwitchTypeCluster,
                 ],
                 OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
             },
@@ -235,8 +221,8 @@ class Plug_4AC_2USB(CustomDevice):
                     Groups.cluster_id,
                     Scenes.cluster_id,
                     OnOff.cluster_id,
-                    TuyaClusterE000.cluster_id,
-                    TuyaClusterE001.cluster_id,
+                    TuyaZBE000Cluster.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
                 ],
                 OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
             },
@@ -252,8 +238,8 @@ class Plug_4AC_2USB(CustomDevice):
                     Groups.cluster_id,
                     Scenes.cluster_id,
                     OnOff.cluster_id,
-                    TuyaClusterE000.cluster_id,
-                    TuyaClusterE001.cluster_id,
+                    TuyaZBE000Cluster.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
                 ],
                 OUTPUT_CLUSTERS: [],
             },
@@ -269,8 +255,8 @@ class Plug_4AC_2USB(CustomDevice):
                     Groups.cluster_id,
                     Scenes.cluster_id,
                     OnOff.cluster_id,
-                    TuyaClusterE000.cluster_id,
-                    TuyaClusterE001.cluster_id,
+                    TuyaZBE000Cluster.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
                 ],
                 OUTPUT_CLUSTERS: [],
             },
@@ -286,8 +272,8 @@ class Plug_4AC_2USB(CustomDevice):
                     Groups.cluster_id,
                     Scenes.cluster_id,
                     OnOff.cluster_id,
-                    TuyaClusterE000.cluster_id,
-                    TuyaClusterE001.cluster_id,
+                    TuyaZBE000Cluster.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
                 ],
                 OUTPUT_CLUSTERS: [],
             },
@@ -303,8 +289,8 @@ class Plug_4AC_2USB(CustomDevice):
                     Groups.cluster_id,
                     Scenes.cluster_id,
                     OnOff.cluster_id,
-                    TuyaClusterE000.cluster_id,
-                    TuyaClusterE001.cluster_id,
+                    TuyaZBE000Cluster.cluster_id,
+                    TuyaZBExternalSwitchTypeCluster.cluster_id,
                 ],
                 OUTPUT_CLUSTERS: [],
             },
@@ -331,8 +317,8 @@ class Plug_4AC_2USB(CustomDevice):
                     Groups.cluster_id,
                     Scenes.cluster_id,
                     TuyaZBOnOffAttributeCluster,
-                    TuyaClusterE000,
-                    TuyaClusterE001,
+                    TuyaZBE000Cluster,
+                    TuyaZBExternalSwitchTypeCluster,
                 ],
                 OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
             },
@@ -344,8 +330,8 @@ class Plug_4AC_2USB(CustomDevice):
                     Groups.cluster_id,
                     Scenes.cluster_id,
                     TuyaZBOnOffAttributeCluster,
-                    TuyaClusterE000,
-                    TuyaClusterE001,
+                    TuyaZBE000Cluster,
+                    TuyaZBExternalSwitchTypeCluster,
                 ],
                 OUTPUT_CLUSTERS: [],
             },
@@ -357,8 +343,8 @@ class Plug_4AC_2USB(CustomDevice):
                     Groups.cluster_id,
                     Scenes.cluster_id,
                     TuyaZBOnOffAttributeCluster,
-                    TuyaClusterE000,
-                    TuyaClusterE001,
+                    TuyaZBE000Cluster,
+                    TuyaZBExternalSwitchTypeCluster,
                 ],
                 OUTPUT_CLUSTERS: [],
             },
@@ -370,8 +356,8 @@ class Plug_4AC_2USB(CustomDevice):
                     Groups.cluster_id,
                     Scenes.cluster_id,
                     TuyaZBOnOffAttributeCluster,
-                    TuyaClusterE000,
-                    TuyaClusterE001,
+                    TuyaZBE000Cluster,
+                    TuyaZBExternalSwitchTypeCluster,
                 ],
                 OUTPUT_CLUSTERS: [],
             },
@@ -383,8 +369,8 @@ class Plug_4AC_2USB(CustomDevice):
                     Groups.cluster_id,
                     Scenes.cluster_id,
                     TuyaZBOnOffAttributeCluster,
-                    TuyaClusterE000,
-                    TuyaClusterE001,
+                    TuyaZBE000Cluster,
+                    TuyaZBExternalSwitchTypeCluster,
                 ],
                 OUTPUT_CLUSTERS: [],
             },


Test patch: