Repository: zigpy/zha-device-handlers

Issue:
[Device Support Request] Aqara T2 Dual Relay (LLKZMK12LM / acn047) - Interlock support
### Problem description

I bought two Aqara T2's to control two roller shades. I thought I'd be able to toggle interlock mode (prevents both switches being on at the same time) through ZHA in Home Assistant, but so far I've been unable to find a way to do it even in the clusters/attributes under Manage Zigbee Device. I see no "interlock" attribute or anything that looks similar.

### Solution description

Interlock mode available for the Aqara T2 through ZHA in Home Assistant.

### Screenshots/Video

_No response_

### Device signature

<details><summary>Device signature</summary>

```json
{
  "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.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4447, 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": "0x0104",
      "device_type": "0x0000",
      "input_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x0012",
        "0x0702",
        "0x0b04",
        "0xfcc0"
      ],
      "output_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "2": {
      "profile_id": "0x0104",
      "device_type": "0x0000",
      "input_clusters": [
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x0012",
        "0xfcc0"
      ],
      "output_clusters": []
    },
    "21": {
      "profile_id": "0x0104",
      "device_type": "0x0000",
      "input_clusters": [
        "0x000c"
      ],
      "output_clusters": []
    }
  },
  "manufacturer": "Aqara",
  "model": "lumi.switch.acn047",
  "class": "zigpy.device.Device"
}
```

</details>


### Diagnostic information

<details><summary>Diagnostic information</summary>

```json
{
  "home_assistant": {
    "installation_type": "Home Assistant Container",
    "version": "2023.11.3",
    "dev": false,
    "hassio": false,
    "virtualenv": false,
    "python_version": "3.11.6",
    "docker": true,
    "arch": "x86_64",
    "timezone": "America/New_York",
    "os_name": "Linux",
    "os_version": "6.1.0-12-amd64",
    "run_as_root": true
  },
  "custom_components": {},
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "after_dependencies": [
      "onboarding",
      "usb"
    ],
    "codeowners": [
      "@dmulcahey",
      "@adminiuga",
      "@puddly"
    ],
    "config_flow": true,
    "dependencies": [
      "file_upload"
    ],
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "iot_class": "local_polling",
    "loggers": [
      "aiosqlite",
      "bellows",
      "crccheck",
      "pure_pcapy3",
      "zhaquirks",
      "zigpy",
      "zigpy_deconz",
      "zigpy_xbee",
      "zigpy_zigate",
      "zigpy_znp",
      "universal_silabs_flasher"
    ],
    "requirements": [
      "bellows==0.36.8",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.106",
      "zigpy-deconz==0.21.1",
      "zigpy==0.59.0",
      "zigpy-xbee==0.19.0",
      "zigpy-zigate==0.11.0",
      "zigpy-znp==0.11.6",
      "universal-silabs-flasher==0.0.14",
      "pyserial-asyncio-fast==0.11"
    ],
    "usb": [
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*2652*",
        "known_devices": [
          "slae.sh cc2652rb stick"
        ]
      },
      {
        "vid": "1A86",
        "pid": "55D4",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus v2"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*zigstar*",
        "known_devices": [
          "ZigStar Coordinators"
        ]
      },
      {
        "vid": "1CF1",
        "pid": "0030",
        "description": "*conbee*",
        "known_devices": [
          "Conbee II"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8A2A",
        "description": "*zigbee*",
        "known_devices": [
          "Nortek HUSBZB-1"
        ]
      },
      {
        "vid": "0403",
        "pid": "6015",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate+"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8B34",
        "description": "*bv 2010/10*",
        "known_devices": [
          "Bitron Video AV2010/10"
        ]
      }
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      },
      {
        "type": "_zigstar_gw._tcp.local.",
        "name": "*zigstar*"
      },
      {
        "type": "_uzg-01._tcp.local.",
        "name": "uzg-01*"
      },
      {
        "type": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      }
    ],
    "is_built_in": true
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 44333,
    "manufacturer": "Aqara",
    "model": "lumi.switch.acn047",
    "name": "Aqara lumi.switch.acn047",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "quirk_id": null,
    "manufacturer_code": 4447,
    "power_source": "Mains",
    "lqi": 208,
    "rssi": -48,
    "last_seen": "2023-12-02T16:31:24",
    "available": true,
    "device_type": "Router",
    "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.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4447, 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": {
        "21": {
          "profile_id": "0x0104",
          "device_type": "0x0000",
          "input_clusters": [
            "0x000c"
          ],
          "output_clusters": []
        },
        "2": {
          "profile_id": "0x0104",
          "device_type": "0x0000",
          "input_clusters": [
            "0x0003",
            "0x0004",
            "0x0005",
            "0x0006",
            "0x0012",
            "0xfcc0"
          ],
          "output_clusters": []
        },
        "1": {
          "profile_id": "0x0104",
          "device_type": "0x0000",
          "input_clusters": [
            "0x0000",
            "0x0003",
            "0x0004",
            "0x0005",
            "0x0006",
            "0x0012",
            "0x0702",
            "0x0b04",
            "0xfcc0"
          ],
          "output_clusters": [
            "0x000a",
            "0x0019"
          ]
        }
      },
      "manufacturer": "Aqara",
      "model": "lumi.switch.acn047"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "button.aqara_double_relay_1_identify",
        "name": "Aqara lumi.switch.acn047"
      },
      {
        "entity_id": "sensor.aqara_double_relay_1_power",
        "name": "Aqara lumi.switch.acn047"
      },
      {
        "entity_id": "sensor.aqara_double_relay_1_summation_delivered",
        "name": "Aqara lumi.switch.acn047"
      },
      {
        "entity_id": "switch.aqara_double_relay_1_switch",
        "name": "Aqara lumi.switch.acn047"
      },
      {
        "entity_id": "switch.aqara_double_relay_1_switch_2",
        "name": "Aqara lumi.switch.acn047"
      }
    ],
    "neighbors": [],
    "routes": [],
    "endpoint_names": [
      {
        "name": "ON_OFF_SWITCH"
      },
      {
        "name": "ON_OFF_SWITCH"
      },
      {
        "name": "ON_OFF_SWITCH"
      }
    ],
    "user_given_name": "Aqara Double Relay 1",
    "device_reg_id": "d7a0cd6d520fb635ba0ba7e88258281a",
    "area_id": null,
    "cluster_details": {
      "21": {
        "device_type": {
          "name": "ON_OFF_SWITCH",
          "id": 0
        },
        "profile_id": 260,
        "in_clusters": {
          "0x000c": {
            "endpoint_attribute": "analog_input",
            "attributes": {
              "0x0055": {
                "attribute_name": "present_value",
                "value": 0.0
              },
              "0x006f": {
                "attribute_name": "status_flags",
                "value": 0
              }
            },
            "unsupported_attributes": {
              "0x0100": {
                "attribute_name": "application_type"
              },
              "0x0041": {
                "attribute_name": "max_present_value"
              },
              "0x006a": {
                "attribute_name": "resolution"
              }
            }
          }
        },
        "out_clusters": {}
      },
      "2": {
        "device_type": {
          "name": "ON_OFF_SWITCH",
          "id": 0
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {
              "0xfffd": {
                "attribute_name": "cluster_revision",
                "value": 2
              }
            },
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0003": {
            "endpoint_attribute": "identify",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0012": {
            "endpoint_attribute": "multistate_input",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0006": {
            "endpoint_attribute": "on_off",
            "attributes": {
              "0x0000": {
                "attribute_name": "on_off",
                "value": 0
              }
            },
            "unsupported_attributes": {
              "0x4003": {
                "attribute_name": "start_up_on_off"
              }
            }
          },
          "0xfcc0": {
            "endpoint_attribute": "manufacturer_specific",
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {}
      },
      "1": {
        "device_type": {
          "name": "ON_OFF_SWITCH",
          "id": 0
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0b04": {
            "endpoint_attribute": "electrical_measurement",
            "attributes": {
              "0x0605": {
                "attribute_name": "ac_power_divisor",
                "value": 10
              },
              "0x0604": {
                "attribute_name": "ac_power_multiplier",
                "value": 1
              },
              "0x050b": {
                "attribute_name": "active_power",
                "value": 0
              },
              "0x0000": {
                "attribute_name": "measurement_type",
                "value": 1
              }
            },
            "unsupported_attributes": {
              "0x0300": {
                "attribute_name": "ac_frequency"
              },
              "0x0601": {
                "attribute_name": "ac_voltage_divisor"
              },
              "0x0302": {
                "attribute_name": "ac_frequency_max"
              },
              "0x0603": {
                "attribute_name": "ac_current_divisor"
              },
              "0x0602": {
                "attribute_name": "ac_current_multiplier"
              },
              "0x0505": {
                "attribute_name": "rms_voltage"
              },
              "0x0507": {
                "attribute_name": "rms_voltage_max"
              },
              "0x0508": {
                "attribute_name": "rms_current"
              },
              "0x0600": {
                "attribute_name": "ac_voltage_multiplier"
              },
              "0x050a": {
                "attribute_name": "rms_current_max"
              },
              "0x0403": {
                "attribute_name": "power_divisor"
              },
              "0x050d": {
                "attribute_name": "active_power_max"
              },
              "0x050f": {
                "attribute_name": "apparent_power"
              },
              "0x0401": {
                "attribute_name": "ac_frequency_divisor"
              },
              "0x0510": {
                "attribute_name": "power_factor"
              },
              "0x0400": {
                "attribute_name": "ac_frequency_multiplier"
              },
              "0x0402": {
                "attribute_name": "power_multiplier"
              }
            }
          },
          "0x0702": {
            "endpoint_attribute": "smartenergy_metering",
            "attributes": {
              "0x0000": {
                "attribute_name": "current_summ_delivered",
                "value": 0
              },
              "0x0302": {
                "attribute_name": "divisor",
                "value": 1000
              },
              "0x0306": {
                "attribute_name": "metering_device_type",
                "value": 0
              },
              "0x0301": {
                "attribute_name": "multiplier",
                "value": 1
              },
              "0x0303": {
                "attribute_name": "summation_formatting",
                "value": 159
              },
              "0x0300": {
                "attribute_name": "unit_of_measure",
                "value": 0
              }
            },
            "unsupported_attributes": {
              "0x0400": {
                "attribute_name": "instantaneous_demand"
              },
              "0x0100": {
                "attribute_name": "current_tier1_summ_delivered"
              },
              "0x0102": {
                "attribute_name": "current_tier2_summ_delivered"
              },
              "0x0104": {
                "attribute_name": "current_tier3_summ_delivered"
              },
              "0x0200": {
                "attribute_name": "status"
              },
              "0x0106": {
                "attribute_name": "current_tier4_summ_delivered"
              },
              "0x0108": {
                "attribute_name": "current_tier5_summ_delivered"
              },
              "0x0304": {
                "attribute_name": "demand_formatting"
              },
              "0x010a": {
                "attribute_name": "current_tier6_summ_delivered"
              }
            }
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {
              "0xfffd": {
                "attribute_name": "cluster_revision",
                "value": 2
              }
            },
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0003": {
            "endpoint_attribute": "identify",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0012": {
            "endpoint_attribute": "multistate_input",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0001": {
                "attribute_name": "app_version",
                "value": 27
              },
              "0x0006": {
                "attribute_name": "date_code",
                "value": "20230606"
              },
              "0x0010": {
                "attribute_name": "location_desc",
                "value": "\u9ed8\u8ba4\u623f\u95f4"
              },
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "Aqara"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "lumi.switch.acn047"
              },
              "0x000d": {
                "attribute_name": "serial_number",
                "value": ""
              },
              "0x0002": {
                "attribute_name": "stack_version",
                "value": 27
              },
              "0x0000": {
                "attribute_name": "zcl_version",
                "value": 3
              }
            },
            "unsupported_attributes": {
              "0x0012": {
                "attribute_name": "device_enabled"
              },
              "0x0008": {
                "attribute_name": "generic_device_class"
              },
              "0x0013": {
                "attribute_name": "alarm_mask"
              },
              "0xfffe": {
                "attribute_name": "reporting_status"
              }
            }
          },
          "0x0006": {
            "endpoint_attribute": "on_off",
            "attributes": {
              "0x0000": {
                "attribute_name": "on_off",
                "value": 0
              }
            },
            "unsupported_attributes": {
              "0x4000": {
                "attribute_name": "global_scene_control"
              },
              "0x4003": {
                "attribute_name": "start_up_on_off"
              }
            }
          },
          "0xfcc0": {
            "endpoint_attribute": "manufacturer_specific",
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}
```

</details>


### Logs

_No response_

### Custom quirk

_No response_

### Additional information

This is almost identical to #639 for another Aqara relay.

Interlock for the Aqara T2 is supported by Zigbee2MQTT: https://www.zigbee2mqtt.io/devices/LLKZMK12LM.html

There are a lot of other options supported by Z2M that would be nice to have in ZHA, so this would be a good time to add those while you're at it, though interlock is the only critical one that I need before I can safely install the T2.
I spent hours trying to set up Z2M on a separate system with another adapter so I could enable interlock before adding the T2 to my production network, but I just couldn't get Z2M to connect to the SkyConnect adapter. At best, I got a "Resource busy" error when there was no reason for it to be busy (new adapter never used before and no other processes accessing it).


Discussion:

Resolving patch:
diff --git a/zhaquirks/xiaomi/aqara/switch_acn047.py b/zhaquirks/xiaomi/aqara/switch_acn047.py
new file mode 100644
--- /dev/null
+++ b/zhaquirks/xiaomi/aqara/switch_acn047.py
@@ -0,0 +1,210 @@
+"""Aqara T2 relay device."""
+from zigpy import types as t
+from zigpy.profiles import zha
+from zigpy.quirks import CustomCluster
+from zigpy.zcl.clusters.general import (
+    AnalogInput,
+    Basic,
+    DeviceTemperature,
+    Groups,
+    Identify,
+    MultistateInput,
+    OnOff,
+    Ota,
+    Scenes,
+    Time,
+)
+from zigpy.zcl.clusters.homeautomation import ElectricalMeasurement
+from zigpy.zcl.clusters.smartenergy import Metering
+
+from zhaquirks.const import (
+    ATTR_ID,
+    COMMAND,
+    DEVICE_TYPE,
+    ENDPOINTS,
+    INPUT_CLUSTERS,
+    MODELS_INFO,
+    OUTPUT_CLUSTERS,
+    PRESS_TYPE,
+    PROFILE_ID,
+    SHORT_PRESS,
+    VALUE,
+    ZHA_SEND_EVENT,
+)
+from zhaquirks.xiaomi import (
+    AnalogInputCluster,
+    BasicCluster,
+    ElectricalMeasurementCluster,
+    MeteringCluster,
+    XiaomiAqaraE1Cluster,
+    XiaomiCustomDevice,
+)
+
+PRESS_TYPES = {1: "single"}
+SINGLE = "single"
+STATUS_TYPE_ATTR = 0x0055  # decimal = 85
+
+
+class MultistateInputCluster(CustomCluster, MultistateInput):
+    """Multistate input cluster."""
+
+    def __init__(self, *args, **kwargs):
+        """Init."""
+        self._current_state = None
+        super().__init__(*args, **kwargs)
+
+    def _update_attribute(self, attrid, value):
+        if attrid == STATUS_TYPE_ATTR:
+            self._current_state = PRESS_TYPES.get(value)
+            event_args = {
+                PRESS_TYPE: self._current_state,
+                ATTR_ID: attrid,
+                VALUE: value,
+            }
+            self.listener_event(ZHA_SEND_EVENT, self, self._current_state, event_args)
+            super()._update_attribute(0, self._current_state)
+        else:
+            super()._update_attribute(attrid, value)
+
+
+class OppleCluster(XiaomiAqaraE1Cluster):
+    """Opple cluster."""
+
+    class SwitchType(t.enum8):
+        """Switch type."""
+
+        Toggle = 0x01
+        Momentary = 0x02
+        NoSwitch = 0x03
+
+    class StartupOnOff(t.enum8):
+        """Startup mode."""
+
+        On = 0x00
+        Previous = 0x01
+        Off = 0x02
+        Toggle = 0x03
+
+    class DecoupledMode(t.enum8):
+        """Decoupled mode."""
+
+        Decoupled = 0x00
+        ControlRelay = 0x01
+
+    class SwitchMode(t.enum8):
+        """Switch Mode."""
+
+        Power = 0x00
+        Pulse = 0x01
+        Dry = 0x03
+
+    attributes = {
+        0x000A: ("switch_type", t.uint8_t, True),
+        0x0517: ("startup_on_off", t.uint8_t, True),
+        0x0200: ("decoupled_mode", t.uint8_t, True),
+        0x02D0: ("interlock", t.Bool, True),
+        0x0289: ("switch_mode", t.uint8_t, True),
+        0x00EB: ("pulse_length", t.uint16_t, True),
+    }
+
+
+class AqaraT2Relay(XiaomiCustomDevice):
+    """Aqara T2 in-wall relay device."""
+
+    signature = {
+        MODELS_INFO: [("Aqara", "lumi.switch.acn047")],
+        ENDPOINTS: {
+            # <SimpleDescriptor endpoint=1 profile=260 device_type=0
+            # device_version=1
+            # input_clusters=[0, 3, 4, 5, 6, 18, 1794, 2820, 64704]
+            # output_clusters=[10, 25]>
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Identify.cluster_id,
+                    Scenes.cluster_id,
+                    Groups.cluster_id,
+                    OnOff.cluster_id,
+                    MultistateInput.cluster_id,
+                    Metering.cluster_id,
+                    ElectricalMeasurement.cluster_id,
+                    OppleCluster.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            },
+            # <SimpleDescriptor endpoint=2 profile=260 device_type=0
+            # device_version=1
+            # input_clusters=[3, 4, 5, 6, 18, 64704]
+            # output_clusters=[]>
+            2: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
+                INPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    Scenes.cluster_id,
+                    Groups.cluster_id,
+                    OnOff.cluster_id,
+                    MultistateInput.cluster_id,
+                    OppleCluster.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            # <SimpleDescriptor endpoint=21 profile=260 device_type=0
+            # device_version=1
+            # input_clusters=[12]
+            # output_clusters=[]>
+            21: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
+                INPUT_CLUSTERS: [AnalogInput.cluster_id],
+                OUTPUT_CLUSTERS: [],
+            },
+        },
+    }
+
+    replacement = {
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
+                INPUT_CLUSTERS: [
+                    BasicCluster,
+                    Identify.cluster_id,
+                    Scenes.cluster_id,
+                    Groups.cluster_id,
+                    OnOff.cluster_id,
+                    MultistateInputCluster,
+                    DeviceTemperature.cluster_id,
+                    MeteringCluster,
+                    ElectricalMeasurementCluster,
+                    OppleCluster,
+                ],
+                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
+            },
+            2: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
+                INPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    Scenes.cluster_id,
+                    Groups.cluster_id,
+                    OnOff.cluster_id,
+                    MultistateInputCluster,
+                    OppleCluster,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            21: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_SWITCH,
+                INPUT_CLUSTERS: [AnalogInputCluster],
+                OUTPUT_CLUSTERS: [],
+            },
+        },
+    }
+
+    device_automation_triggers = {
+        (SHORT_PRESS, SHORT_PRESS): {COMMAND: SINGLE},
+    }


Test patch:
diff --git a/tests/test_xiaomi.py b/tests/test_xiaomi.py
--- a/tests/test_xiaomi.py
+++ b/tests/test_xiaomi.py
@@ -13,6 +13,7 @@
     AnalogInput,
     AnalogOutput,
     DeviceTemperature,
+    MultistateInput,
     MultistateOutput,
     OnOff,
     PowerConfiguration,
@@ -1608,6 +1609,31 @@ async def test_xiaomi_e1_roller_commands_1(zigpy_device_from_quirk, command, val
     assert multistate_cluster._write_attributes.call_args[0][0][0].value.value == value
 
 
+@pytest.mark.parametrize(
+    "quirk",
+    (zhaquirks.xiaomi.aqara.switch_acn047.AqaraT2Relay,),
+)
+async def test_aqara_t2_relay(zigpy_device_from_quirk, quirk):
+    """Test Aqara T2 relay."""
+
+    device = zigpy_device_from_quirk(quirk)
+    mi_cluster = device.endpoints[1].multistate_input
+    mi_listener = ClusterListener(mi_cluster)
+
+    mi_cluster.update_attribute(MultistateInput.AttributeDefs.present_value.id, 1)
+    assert len(mi_listener.attribute_updates) == 1
+    assert mi_listener.attribute_updates[0][0] == 0
+    assert mi_listener.attribute_updates[0][1] == "single"
+
+    mi_cluster.update_attribute(MultistateInput.AttributeDefs.state_text.id, "foo")
+    assert len(mi_listener.attribute_updates) == 2
+    assert (
+        mi_listener.attribute_updates[1][0]
+        == MultistateInput.AttributeDefs.state_text.id
+    )
+    assert mi_listener.attribute_updates[1][1] == "foo"
+
+
 @pytest.mark.parametrize(
     "command, value",
     [