Repository: zigpy/zha-device-handlers

Issue:
[Device Support Request] TS011F 4 plugs surge protector
**Is your feature request related to a problem? Please describe.**
I've just bought "Tuya Zigbee Smart Surge Protector, EU Outlet With 4 Plugs and 2 USB Port" [https://www.aliexpress.com/item/1005001867863311.html](url) 
![image](https://user-images.githubusercontent.com/26710811/139192468-c4961631-c082-4166-922a-67726b6c9b94.png)

It basically works in ZHA but doesn't give an ability to change behavior after power outage.

Before all my experiments I've checked device in Tuya Smart application with Tuya Zigbee gateway. There such behavior works as expected, it can be set to On, Off and Restore previous state. 

**Describe the solution you'd like**
I need an ability to change behavior after power outage.

**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=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": "0x010a",
      "in_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "out_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "2": {
      "profile_id": 260,
      "device_type": "0x010a",
      "in_clusters": [
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "out_clusters": []
    },
    "3": {
      "profile_id": 260,
      "device_type": "0x010a",
      "in_clusters": [
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "out_clusters": []
    },
    "4": {
      "profile_id": 260,
      "device_type": "0x010a",
      "in_clusters": [
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "out_clusters": []
    },
    "5": {
      "profile_id": 260,
      "device_type": "0x010a",
      "in_clusters": [
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0xe000",
        "0xe001"
      ],
      "out_clusters": []
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0061",
      "in_clusters": [],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZ3000_o005nuxx",
  "model": "TS011F",
  "class": "zigpy.device.Device"
}

```
**Additional context**
I use Home Assistant Core version core-2021.11.0b0 and zha-device-handlers version 0.0.63

I've added next class to zha-device-handlers/zhaquirks/tuya/ts011f_plug.py 

```
class Plug_4AC_2USB(CustomDevice):
    """Tuya 4 outlet + 2 USB surge protector with restore power state support."""

    signature = {
        MODEL: "TS011F",
        ENDPOINTS: {
            # <SimpleDescriptor endpoint=1 profile=260 device_type=266
            # 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_PLUG_IN_UNIT,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    TuyaClusterE000.cluster_id,
                    TuyaClusterE001.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            # <SimpleDescriptor endpoint=2 profile=260 device_type=266
            # device_version=1
            # input_clusters=[3, 4, 5, 6, 57344, 57345]
            # output_clusters=[]>
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
                INPUT_CLUSTERS: [
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    TuyaClusterE000.cluster_id,
                    TuyaClusterE001.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            },
            # <SimpleDescriptor endpoint=3 profile=260 device_type=266
            # device_version=1
            # input_clusters=[3, 4, 5, 6, 57344, 57345]
            # output_clusters=[]>
            3: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
                INPUT_CLUSTERS: [
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    TuyaClusterE000.cluster_id,
                    TuyaClusterE001.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            },
            # <SimpleDescriptor endpoint=4 profile=260 device_type=266
            # device_version=1
            # input_clusters=[3, 4, 5, 6, 57344, 57345]
            # output_clusters=[]>
            4: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
                INPUT_CLUSTERS: [
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    TuyaClusterE000.cluster_id,
                    TuyaClusterE001.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            },
            # <SimpleDescriptor endpoint=5 profile=260 device_type=266
            # device_version=1
            # input_clusters=[3, 4, 5, 6, 57344, 57345]
            # output_clusters=[]>
            5: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
                INPUT_CLUSTERS: [
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    TuyaClusterE000.cluster_id,
                    TuyaClusterE001.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            },
            # <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,
                    TuyaZBOnOffRestorePowerCluster,
                    TuyaClusterE000,
                    TuyaClusterE001,
                ],
                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: [
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaZBOnOffRestorePowerCluster,
                    TuyaClusterE000,
                    TuyaClusterE001,
                ],
                OUTPUT_CLUSTERS: [],
            },
            3: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
                INPUT_CLUSTERS: [
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaZBOnOffRestorePowerCluster,
                    TuyaClusterE000,
                    TuyaClusterE001,
                ],
                OUTPUT_CLUSTERS: [],
            },
            4: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
                INPUT_CLUSTERS: [
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaZBOnOffRestorePowerCluster,
                    TuyaClusterE000,
                    TuyaClusterE001,
                ],
                OUTPUT_CLUSTERS: [],
            },
            5: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
                INPUT_CLUSTERS: [
                    Identify.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaZBOnOffRestorePowerCluster,
                    TuyaClusterE000,
                    TuyaClusterE001,
                ],
                OUTPUT_CLUSTERS: [],
            },
        },
    }

```

Have placed the updated file into custom_quirks_path and HA has recognized the device.
After that I have access to an attribute power_on_state (id: 0x8002) of TuyaZBOnOffRestorePowerCluster.
Initial value of the attribute is TZBPowerOnState.LastState. All my attempts to set value other that 0 gives None as value of the attribute. If I set 0 as value of the attribute next get returns value TZBPowerOnState.LastState.

In the log I see next:
```
Logger: zigpy.zcl
Source: /usr/local/lib/python3.9/site-packages/zigpy/zcl/__init__.py:371
First occurred: 08:51:27 (5 occurrences)
Last logged: 08:52:01

[0x15c9:1:0x0006] invalid literal for int() with base 10: 'TZBPowerOnState.LastState'
[0x15c9:1:0x0006] invalid literal for int() with base 10: 'None'
```

What I may to do in order to resolve the issue?


Discussion:
Sorry, my mistake, attribute power_on_state (id: 0x8002) could be changed.

Maybe it has a sense to make PR with new class?
I have 2 of them but have not testing making the quirk for it but if its working is good making one PR for it.

I have making on PR for adding back light for switches but its not merged but is that working for the indicators or is they hard wired LEDs ?
https://github.com/zigpy/zha-device-handlers/pull/1105 (I have renaming the cluster !!)

I like testing it but i have little much dropped in (IKEA remotes OTA is updated and having problem with old bad updates that making the new rolling back),
Sorry i was wrong My is only 3 plugs  so i must doing one new class for it later :-(( 
I think it's better to put both 3 plugs and 4 plugs in one PR later.
I was looking little and the device is having 5 switch end points of 4 is the plugs. 
Is the EP 1 or 5 user for the surge protection or somthing else ?
Fifth one is for USB ports. USB ports could be controlled like the plug, but both USB ports together.
I have copy your quirk and deleted 2 EP and adding ZGPP in the replace and using the INIT from the adding extra attribute #1105 and i reading and setting the power start and also the back light but is not doing anything with the LEDs for the relay channels.
[ts011f_plug.zip](https://github.com/zigpy/zha-device-handlers/files/7435949/ts011f_plug.zip)



My 4 plugs + USB has backlight settings in Tuya Smart application but any option change nothing. Per plug LEDs always show plug state, main button lights if any of the plugs is on.
Its the most logic.
Its used by main powered switches that can having high intensity in the day and low i the night  and all of if like but interesting that tuya have reused the code then not using it in the device.
The power last state and back light is being merged in INIT and i have making one PR for the LIDL one.
Shall i making one PR for you power stripe 2 ?
Its only adding the new OnOff cluster and it shall working.
> Shall i making one PR for you power stripe 2 ?

Yes, make it please



Resolving patch:
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
@@ -214,3 +214,185 @@ class Plug_3AC_4USB(CustomDevice):
             },
         },
     }
+
+
+class Plug_4AC_2USB(CustomDevice):
+    """Tuya 4 outlet + 2 USB surge protector with restore power state support."""
+
+    signature = {
+        MODEL: "TS011F",
+        ENDPOINTS: {
+            # <SimpleDescriptor endpoint=1 profile=260 device_type=266
+            # 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_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    TuyaClusterE000.cluster_id,
+                    TuyaClusterE001.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            },
+            # <SimpleDescriptor endpoint=2 profile=260 device_type=266
+            # device_version=1
+            # input_clusters=[3, 4, 5, 6, 57344, 57345]
+            # output_clusters=[]>
+            2: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    TuyaClusterE000.cluster_id,
+                    TuyaClusterE001.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            # <SimpleDescriptor endpoint=3 profile=260 device_type=266
+            # device_version=1
+            # input_clusters=[3, 4, 5, 6, 57344, 57345]
+            # output_clusters=[]>
+            3: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    TuyaClusterE000.cluster_id,
+                    TuyaClusterE001.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            # <SimpleDescriptor endpoint=4 profile=260 device_type=266
+            # device_version=1
+            # input_clusters=[3, 4, 5, 6, 57344, 57345]
+            # output_clusters=[]>
+            4: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    TuyaClusterE000.cluster_id,
+                    TuyaClusterE001.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            # <SimpleDescriptor endpoint=5 profile=260 device_type=266
+            # device_version=1
+            # input_clusters=[3, 4, 5, 6, 57344, 57345]
+            # output_clusters=[]>
+            5: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    TuyaClusterE000.cluster_id,
+                    TuyaClusterE001.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            # <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,
+                    TuyaClusterE000,
+                    TuyaClusterE001,
+                ],
+                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: [
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaZBOnOffAttributeCluster,
+                    TuyaClusterE000,
+                    TuyaClusterE001,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            3: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaZBOnOffAttributeCluster,
+                    TuyaClusterE000,
+                    TuyaClusterE001,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            4: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaZBOnOffAttributeCluster,
+                    TuyaClusterE000,
+                    TuyaClusterE001,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            5: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_PLUG_IN_UNIT,
+                INPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    TuyaZBOnOffAttributeCluster,
+                    TuyaClusterE000,
+                    TuyaClusterE001,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            242: {
+                PROFILE_ID: 41440,
+                DEVICE_TYPE: 97,
+                INPUT_CLUSTERS: [],
+                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
+            },
+        },
+    }


Test patch: