Repository: zigpy/zha-device-handlers

Issue:
[Device Support Request] Develco WISZB-120 door/windows sensor
**Is your feature request related to a problem? Please describe.**
This sensor is currently only working for the onboard temperature sensor. The contact sensor doesn't report state changes in HA. It is always `open`. Also, the battery sensor is not reporting any values at all, only `unknown`.

**Describe the solution you'd like**
Support for the sensor in ZHA.

**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.**
https://paste.ubuntu.com/p/ST3Y6k9fXf/



Discussion:
```
Node Descriptor: <Optional byte1=2 byte2=64 mac_capability_flags=0 manufacturer_code=4117 maximum_buffer_size=80 maximum_incoming_transfer_size=80 server_mask=0 maximum_outgoing_transfer_size=80 descriptor_capability_field=0>

<SimpleDescriptor endpoint=1 profile=49353 device_type=1 device_version=1 input_clusters=[3, 5, 6] output_clusters=[]>

<SimpleDescriptor endpoint=35 profile=260 device_type=1026 device_version=0 input_clusters=[0, 1, 3, 15, 32, 1280] output_clusters=[10, 25]>

<SimpleDescriptor endpoint=38 profile=260 device_type=770 device_version=0 input_clusters=[0, 3, 1026] output_clusters=[3]>


Manufacturer: Develco Products A/S
Model: WISZB-120
```


<https://github.com/Koenkk/zigbee2mqtt/issues/3012> device appears to have a firmware problem causing it to send an invalid payload on status change messages for the IAS Zone cluster
```
Failed to parse message (b'090d00350000') on cluster 1280, because Data is too short to contain 1 bytes
...
2020-03-30 18:15:07 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response: [32, 34, <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1, <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x4453>, 35, 260, 1280, b'\tI\x005\x00\x00\x00\xdc\x1a', 0, 175, 151, 20, 130, 16, 0, -75]
2020-03-30 18:15:07 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x4453>, ep: 35, profile: 0x0104, cluster_id: 0x0500, data: b'09490035000000dc1a'
2020-03-30 18:15:07 DEBUG (MainThread) [zigpy_deconz.api] APS data indication response: [29, 34, <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x0000>, 1, <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x4453>, 35, 260, 1280, b'\tI\x005\x00\x00', 0, 175, 143, 20, 130, 16, 0, -76]
2020-03-30 18:15:07 DEBUG (MainThread) [zigpy_deconz.api] 'aps_data_indication' response from <DeconzAddress address_mode=ADDRESS_MODE.NWK address=0x4453>, ep: 35, profile: 0x0104, cluster_id: 0x0500, data: b'094900350000'
```

as a test, modify `/usr/local/lib/python3.7/site-packages/zigpy/zcl/clusters/security.py` inside your homeassistant container and around line 80 modify schema for `"status_change_notification"` command:
```
    client_commands = {
        0x0000: (
            "status_change_notification",
            (ZoneStatus, t.bitmap8, t.Optional(t.uint8_t), t.Optional(t.uint16_t)),
            False,
        ),
```

the only change is to last two `t.uint8_t` and `t.uint16_t` making those optional. Just wanna to test if a quirk would work. 

Resolving patch:
diff --git a/zhaquirks/develco/__init_.py b/zhaquirks/develco/__init_.py
new file mode 100644
--- /dev/null
+++ b/zhaquirks/develco/__init_.py
@@ -0,0 +1,11 @@
+"""Quirks for Develco Products A/S."""
+from .. import PowerConfigurationCluster
+
+DEVELCO = "Develco Products A/S"
+
+
+class DevelcoPowerConfiguration(PowerConfigurationCluster):
+    """Common use power configuration cluster."""
+
+    MIN_VOLTS = 2.6  # old 2.1
+    MAX_VOLTS = 3.0  # old 3.2
diff --git a/zhaquirks/develco/open_close.py b/zhaquirks/develco/open_close.py
new file mode 100644
--- /dev/null
+++ b/zhaquirks/develco/open_close.py
@@ -0,0 +1,116 @@
+"""Door/Windows sensors."""
+
+from zigpy.profiles import zha
+import zigpy.types as t
+from zigpy.quirks import CustomDevice, CustomCluster
+from zigpy.zcl.clusters import general, measurement, security
+
+from . import DEVELCO, DevelcoPowerConfiguration
+from ..const import (
+    DEVICE_TYPE,
+    ENDPOINTS,
+    INPUT_CLUSTERS,
+    MODELS_INFO,
+    OUTPUT_CLUSTERS,
+    PROFILE_ID,
+)
+
+
+class DevelcoIASZone(CustomCluster, security.IasZone):
+    """IAS Zone."""
+
+    manufacturer_client_commands = {
+        0x0000: (
+            "status_change_notification",
+            (
+                security.IasZone.ZoneStatus,
+                t.bitmap8,
+                t.Optional(t.uint8_t),
+                t.Optional(t.uint16_t),
+            ),
+            False,
+        )
+    }
+
+
+class WISZB120(CustomDevice):
+    """Custom device representing door/windows sensors."""
+
+    signature = {
+        # <SimpleDescriptor endpoint=1 profile=49353 device_type=1 device_version=1
+        # input_clusters=[3, 5, 6] output_clusters=[]>
+        # <SimpleDescriptor endpoint=35 profile=260 device_type=1026 device_version=0
+        # input_clusters=[0, 1, 3, 15, 32, 1280] output_clusters=[10, 25]>
+        # <SimpleDescriptor endpoint=38 profile=260 device_type=770 device_version=0
+        # input_clusters=[0, 3, 1026] output_clusters=[3]>
+        MODELS_INFO: [(DEVELCO, "WISZB-120")],
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: 0xC0C9,
+                DEVICE_TYPE: 1,
+                INPUT_CLUSTERS: [
+                    general.Identify.cluster_id,
+                    general.Scenes.cluster_id,
+                    general.OnOff.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            35: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
+                INPUT_CLUSTERS: [
+                    general.Basic.cluster_id,
+                    general.PowerConfiguration.cluster_id,
+                    general.Identify.cluster_id,
+                    general.BinaryInput.cluster_id,
+                    general.PollControl.cluster_id,
+                    security.IasZone.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [general.Time, general.Ota.cluster_id],
+            },
+            38: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,
+                INPUT_CLUSTERS: [
+                    general.Basic.cluster_id,
+                    general.Identify.cluster_id,
+                    measurement.TemperatureMeasurement.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [general.Identify.cluster_id],
+            },
+        },
+    }
+
+    replacement = {
+        ENDPOINTS: {
+            1: {
+                INPUT_CLUSTERS: [
+                    general.Identify.cluster_id,
+                    general.Scenes.cluster_id,
+                    general.OnOff.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [],
+            },
+            35: {
+                INPUT_CLUSTERS: [
+                    general.Basic.cluster_id,
+                    DevelcoPowerConfiguration,
+                    general.Identify.cluster_id,
+                    general.BinaryInput.cluster_id,
+                    general.PollControl.cluster_id,
+                    DevelcoIASZone,
+                ],
+                OUTPUT_CLUSTERS: [general.Time, general.Ota.cluster_id],
+            },
+            38: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.TEMPERATURE_SENSOR,
+                INPUT_CLUSTERS: [
+                    general.Basic.cluster_id,
+                    general.Identify.cluster_id,
+                    measurement.TemperatureMeasurement.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [general.Identify.cluster_id],
+            },
+        }
+    }


Test patch: