Repository: zigpy/zha-device-handlers

Issue:
[Device Support Request] TS0211 by _TZ1800_ladpngdx - Lidl - Silvercrest Doorbell Klingel
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

After Pairing to ZHA (Raspi 4/ Conbee2) the device shows a Sensor 'Ias_zone' which is in state 'Closed' - after pushing the Doorbell- button this state changes to "Open" and stays in that state.

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

I want to use this doorbell as a push-button for an automation so i expect it to change back to the old state.

**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.EndDevice: 2>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>, manufacturer_code=4619, 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=True, *is_full_function_device=False, *is_mains_powered=False, *is_receiver_on_when_idle=False, *is_router=False, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0402",
      "in_clusters": [
        "0x0000",
        "0x0001",
        "0x0003",
        "0x0500",
        "0x0b05"
      ],
      "out_clusters": [
        "0x0019"
      ]
    }
  },
  "manufacturer": "_TZ1800_ladpngdx",
  "model": "TS0211",
  "class": "zigpy.device.Device"
}


Sent 'mgmt_permit_joining_req' to 84:18:26:00:00:0f:84:80: [<Status.SUCCESS: 0>]
Device 0x42d7 (84:2e:14:ff:fe:f8:09:83) joined the network
Device 84:2e:14:ff:fe:f8:09:83 changed id (0x42d7 => 0x42d7)
[0x42d7] Scheduling initialization
[0x42d7] Canceling old initialize call
Received frame on uninitialized device <Device model=None manuf=None nwk=0x42D7 ieee=84:2e:14:ff:fe:f8:09:83 is_initialized=False> from ep 0 to ep 0, cluster 19: b'\xf8\xd7B\x83\t\xf8\xfe\xff\x14.\x84\x80'
[0x42d7:zdo] ZDO request ZDOCmd.Device_annce: [0x42D7, 84:2e:14:ff:fe:f8:09:83, 128]
Tries remaining: 3
[0x42d7] Discovering endpoints
Tries remaining: 3
[0x42d7] Extending timeout for 0x71 request
Received frame on uninitialized device <Device model=None manuf=None nwk=0x42D7 ieee=84:2e:14:ff:fe:f8:09:83 is_initialized=False> from ep 0 to ep 0, cluster 6: b'C\xfd\xff\x04\x01\x00\x01\x00\x05'
[0x42d7:zdo] ZDO request ZDOCmd.Match_Desc_req: [0xFFFD, 260, [], [1280]]
Received frame on uninitialized device <Device model=None manuf=None nwk=0x42D7 ieee=84:2e:14:ff:fe:f8:09:83 is_initialized=False> from ep 0 to ep 0, cluster 32773: b'q\x00\xd7B\x01\x01'
[0x42d7] Discovered endpoints: [1]
[0x42d7] Initializing endpoints [<Endpoint id=1 in=[] out=[] status=<Status.NEW: 0>>]
[0x42d7:1] Discovering endpoint information
Tries remaining: 3
[0x42d7] Extending timeout for 0x74 request
Received frame on uninitialized device <Device model=None manuf=None nwk=0x42D7 ieee=84:2e:14:ff:fe:f8:09:83 is_initialized=False> from ep 0 to ep 0, cluster 32772: b't\x00\xd7B\x14\x01\x04\x01\x02\x04\x01\x05\x00\x00\x01\x00\x03\x00\x00\x05\x05\x0b\x01\x19\x00'
[0x42d7:1] Discovered endpoint information: SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=1026, device_version=1, input_clusters=[0, 1, 3, 1280, 2821], output_clusters=[25])
[0x42d7] Extending timeout for 0x76 request
[0x42d7:1:0x0000] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=118 command_id=Command.Read_Attributes_rsp>
[0x42d7] Read model 'TS0211' and manufacturer '_TZ1800_ladpngdx' from <Endpoint id=1 in=[basic:0x0000, power:0x0001, identify:0x0003, ias_zone:0x0500, diagnostic:0x0B05] out=[ota:0x0019] status=<Status.ZDO_INIT: 1>>
[0x42d7] Discovered basic device information for <Device model='TS0211' manuf='_TZ1800_ladpngdx' nwk=0x42D7 ieee=84:2e:14:ff:fe:f8:09:83 is_initialized=True>
Device is initialized <Device model='TS0211' manuf='_TZ1800_ladpngdx' nwk=0x42D7 ieee=84:2e:14:ff:fe:f8:09:83 is_initialized=True>
Checking quirks for _TZ1800_ladpngdx TS0211 (84:2e:14:ff:fe:f8:09:83)
Considering <class 'zhaquirks.xbee.xbee_io.XBeeSensor'>
Fail because endpoint list mismatch: {232, 230} {1}
Considering <class 'zhaquirks.xbee.xbee3_io.XBee3Sensor'>
Fail because endpoint list mismatch: {232, 230} {1}
Considering <class 'zhaquirks.smartthings.tag_v4.SmartThingsTagV4'>
Fail because device_type mismatch on at least one endpoint
Considering <class 'zhaquirks.smartthings.multi.SmartthingsMultiPurposeSensor'>
Fail because input cluster mismatch on at least one endpoint
Considering <class 'zhaquirks.netvox.z308e3ed.Z308E3ED'>
Fail because input cluster mismatch on at least one endpoint
Considering <class 'zhaquirks.gledopto.soposhgu10.SoposhGU10'>
Fail because endpoint list mismatch: {11, 13} {1}
Considering <class 'bellows.zigbee.application.EZSPCoordinator'>
Fail because device_type mismatch on at least one endpoint
device - 17111:84:2e:14:ff:fe:f8:09:83 entering async_device_initialized - is_new_join: True
device - 17111:84:2e:14:ff:fe:f8:09:83 has joined the ZHA zigbee network
[17111](TS0211): started configuration
[17111:ZDO](TS0211): 'async_configure' stage succeeded
Error handling '_save_attribute' event with (84:2e:14:ff:fe:f8:09:83, 1, 0, 4, '_TZ1800_ladpngdx') params: FOREIGN KEY constraint failed
[0x42d7] Extending timeout for 0x78 request
[0x42d7] Extending timeout for 0x7a request
[17111:1:0x0000]: finished channel configuration
[17111:1:0x0019]: finished channel configuration
Error handling '_save_attribute' event with (84:2e:14:ff:fe:f8:09:83, 1, 0, 5, 'TS0211') params: FOREIGN KEY constraint failed
[0x42d7:1:0x0500] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=120 command_id=Command.Read_Attributes_rsp>
[17111:1:0x0500]: started IASZoneChannel configuration
[0x42d7] Extending timeout for 0x7c request
[17111:1:0x0001]: bound 'power' cluster: Status.SUCCESS
[0x42d7] Extending timeout for 0x7e request
[17111:1:0x0500]: bound 'ias_zone' cluster: Status.SUCCESS
[0x42d7] Extending timeout for 0x80 request
[0x42d7:1:0x0001] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=126 command_id=Command.Configure_Reporting_rsp>
[17111:1:0x0001]: Successfully configured reporting for '{'battery_voltage': (3600, 10800, 1), 'battery_percentage_remaining': (3600, 10800, 1)}' on 'power' cluster: [ConfigureReportingResponseRecord(status=0)]
[17111:1:0x0001]: finished channel configuration
[0x42d7:1:0x0500] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=128 command_id=Command.Write_Attributes_rsp>
[17111:1:0x0500]: wrote cie_addr: 00:21:2e:ff:ff:07:56:52 to 'ias_zone' cluster: [WriteAttributesStatusRecord(status=<Status.SUCCESS: 0>)]
[17111:1:0x0500]: Sending pro-active IAS enroll response
[17111:1:0x0500]: finished IASZoneChannel configuration
[0x42d7] Extending timeout for 0x82 request
[17111:1:0x0500]: 'async_configure' stage succeeded
[17111:1:0x0001]: 'async_configure' stage succeeded
[17111:1:0x0000]: 'async_configure' stage succeeded
[17111:1:0x0019]: 'async_configure' stage succeeded
[17111](TS0211): completed configuration
[17111](TS0211): stored in registry: ZhaDeviceEntry(name='_TZ1800_ladpngdx TS0211', ieee='84:2e:14:ff:fe:f8:09:83', last_seen=1637571737.562357)
[0x42d7] Extending timeout for 0x84 request
[0x42d7:1:0x0003] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=132 command_id=Command.Default_Response>
[17111:1:0x0003]: executed 'trigger_effect' command with args: '(2, 0)' kwargs: '{}' result: [64, <Status.UNSUP_CLUSTER_COMMAND: 129>]
[17111](TS0211): started initialization
[17111:ZDO](TS0211): 'async_initialize' stage succeeded
[17111:1:0x0500]: initializing channel: from_cache: False
[0x42d7] Extending timeout for 0x86 request
[17111:1:0x0001]: initializing channel: from_cache: False
[0x42d7] Extending timeout for 0x88 request
[17111:1:0x0000]: initializing channel: from_cache: False
[17111:1:0x0000]: finished channel initialization
[17111:1:0x0019]: initializing channel: from_cache: False
[17111:1:0x0019]: finished channel initialization
[0x42d7:zdo] ZDO request ZDOCmd.NWK_addr_req: [00:21:2e:ff:ff:07:56:52, 0, 0]
[0x42d7:zdo] ZDO request ZDOCmd.NWK_addr_req: [00:21:2e:ff:ff:07:56:52, 0, 0]
[0x42d7:zdo] ZDO request ZDOCmd.NWK_addr_req: [00:21:2e:ff:ff:07:56:52, 0, 0]
[0x42d7:1:0x0500] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=134 command_id=Command.Read_Attributes_rsp>
[17111:1:0x0500]: finished channel initialization
[0x42d7:zdo] ZDO request ZDOCmd.NWK_addr_req: [00:21:2e:ff:ff:07:56:52, 0, 0]
[0x42d7:1:0x0001] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=136 command_id=Command.Read_Attributes_rsp>
[0x42d7] Extending timeout for 0x8e request
[0x42d7:1:0x0500] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=CLUSTER_COMMAND manufacturer_specific=False is_reply=True disable_default_response=False> manufacturer=None tsn=99 command_id=0>
[0x42d7:1:0x0500] ZCL request 0x0000: [<ZoneStatus.Supervision_reports|Tamper: 20>, <bitmap8.0: 0>, 0, 0]
[17111:1:0x0500]: Updated alarm state: ZoneStatus.0
[0x42d7:1:0x0001] ZCL deserialize: <ZCLHeader frame_control=<FrameControl frame_type=GLOBAL_COMMAND manufacturer_specific=False is_reply=True disable_default_response=True> manufacturer=None tsn=142 command_id=Command.Read_Attributes_rsp>
[17111:1:0x0001]: finished channel initialization
[17111:1:0x0500]: 'async_initialize' stage succeeded
[17111:1:0x0001]: 'async_initialize' stage succeeded
[17111:1:0x0000]: 'async_initialize' stage succeeded
[17111:1:0x0019]: 'async_initialize' stage succeeded
[17111](TS0211): power source: Battery or Unknown
[17111](TS0211): completed initialization

**Additional context**
Add any other context or screenshots about the feature request here.

Accidently i just found out that the Button on the (back under the lid) changes the State back to "Closed".
It seems to me as if the two buttons "doorbell" on front "and "Manipulation Detection/Open lid" are messed up in "one sensor".

![image](https://user-images.githubusercontent.com/86672383/142840279-dbef27b7-2b7f-4f13-84f8-a2dc4885d811.png)

Unfortunatly i am not able to reproduce that.

Thanks in advance - Michael


Discussion:
would appreciate that too. Button works fine in Deconz and Z2M but not in ZHA.
i am also interested in a solution.

Resolving patch:
diff --git a/zhaquirks/tuya/ts0211.py b/zhaquirks/tuya/ts0211.py
new file mode 100644
--- /dev/null
+++ b/zhaquirks/tuya/ts0211.py
@@ -0,0 +1,135 @@
+"""Tuya Doorbell."""
+
+from typing import Optional, Tuple, Union
+
+from zigpy.profiles import zha
+from zigpy.quirks import CustomDevice
+import zigpy.types as t
+from zigpy.zcl import foundation
+from zigpy.zcl.clusters.general import Basic, Identify, Ota, PowerConfiguration
+from zigpy.zcl.clusters.homeautomation import Diagnostic
+from zigpy.zcl.clusters.security import IasZone
+
+from zhaquirks.const import (
+    COMMAND_SINGLE,
+    DEVICE_TYPE,
+    ENDPOINTS,
+    INPUT_CLUSTERS,
+    MODEL,
+    OUTPUT_CLUSTERS,
+    PROFILE_ID,
+    ZHA_SEND_EVENT,
+)
+
+
+class IasZoneDoorbellCluster(IasZone):
+    """Custom IasZone cluster for the doorbell."""
+
+    cluster_id = IasZone.cluster_id
+
+    def handle_cluster_request(
+        self,
+        hdr: foundation.ZCLHeader,
+        args: Tuple[IasZone.ZoneStatus],
+        *,
+        dst_addressing: Optional[
+            Union[t.Addressing.Group, t.Addressing.IEEE, t.Addressing.NWK]
+        ] = None,
+    ) -> None:
+        """Handle cluster request."""
+        # args looks like [<ZoneStatus.Alarm_1: 1>, <bitmap8.0: 0>, 0, 0]
+        # we are only interested in 3 bits of the ZoneStatus item
+
+        # with thanks to
+        # https://github.com/Koenkk/zigbee-herdsman-converters/blob/26553bfa9d747c1a8b6322090429c04cf612c3c1/converters/fromZigbee.js#L2193-L2206
+
+        arg = args[0]
+        if arg & IasZone.ZoneStatus.Alarm_1:
+            self.listener_event(ZHA_SEND_EVENT, COMMAND_SINGLE, [])
+
+        # the doorbell also sets (arg & IasZone.ZoneStatus.Tamper) and
+        # (arg & IasZone.ZoneStatus.Battery) but those should eventually
+        # be handled by a more generic IasZone handling
+
+
+class TuyaDoorbell0211(CustomDevice):
+    """Tuya doorbell."""
+
+    # {
+    #   "node_descriptor": "NodeDescriptor(
+    #      logical_type=<LogicalType.EndDevice: 2>,
+    #      complex_descriptor_available=0,
+    #      user_descriptor_available=0,
+    #      reserved=0,
+    #      aps_flags=0,
+    #      frequency_band=<FrequencyBand.Freq2400MHz: 8>,
+    #      mac_capability_flags=<MACCapabilityFlags.AllocateAddress: 128>,
+    #      manufacturer_code=4619,
+    #      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=True,
+    #      *is_full_function_device=False,
+    #      *is_mains_powered=False,
+    #      *is_receiver_on_when_idle=False,
+    #      *is_router=False,
+    #      *is_security_capable=False)",
+    #   "endpoints": {
+    #     "1": {
+    #       "profile_id": 260,
+    #       "device_type": "0x0402",
+    #       "in_clusters": [
+    #         "0x0000",
+    #         "0x0001",
+    #         "0x0003",
+    #         "0x0500",
+    #         "0x0b05"
+    #       ],
+    #       "out_clusters": [
+    #         "0x0019"
+    #       ]
+    #     }
+    #   },
+    #   "manufacturer": "_TZ1800_ladpngdx",
+    #   "model": "TS0211",
+    #   "class": "zhaquirks.tuya.ts0211.TuyaDoorbell0211"
+    # }
+
+    signature = {
+        MODEL: "TS0211",
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    PowerConfiguration.cluster_id,
+                    Identify.cluster_id,
+                    IasZone.cluster_id,
+                    Diagnostic.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Ota.cluster_id],
+            },
+        },
+    }
+    replacement = {
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    PowerConfiguration.cluster_id,
+                    Identify.cluster_id,
+                    IasZoneDoorbellCluster,
+                    Diagnostic.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Ota.cluster_id],
+            },
+        },
+    }


Test patch: