Repository: zigpy/zha-device-handlers

Issue:
[Device Support Request] Iris IL07_1 (GreatStar iMagic 1117-S) Motion Sensor not reporting battery status
**Is your feature request related to a problem? Please describe.**
I have a few Iris IL07_01 Motion/Temp/Humidity sensors and none of them report the battery level.

**Describe the solution you'd like**
I would like to be able to see what percentage the batteries have remaining.

**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(byte1=2, byte2=64, mac_capability_flags=128, manufacturer_code=4667, maximum_buffer_size=82, maximum_incoming_transfer_size=82, server_mask=11264, maximum_outgoing_transfer_size=82, descriptor_capability_field=0)",
  "endpoints": {
    "1": {
      "profile_id": 260,
      "device_type": "0x0402",
      "in_clusters": [
        "0x0000",
        "0x0001",
        "0x0003",
        "0x0020",
        "0x0402",
        "0x0405",
        "0x0500",
        "0x0b05",
        "0xfc01",
        "0xfc02"
      ],
      "out_clusters": [
        "0x0003",
        "0x0019"
      ]
    }
  },
  "manufacturer": "iMagic by GreatStar",
  "model": "1117-S",
  "class": "zigpy.device.Device"
}
````

**Additional context**
When going into manage cluster -> power configuration, none of the battery_percentage_remaining options report a number, they all display "none"


Discussion:

Resolving patch:
diff --git a/zhaquirks/centralite/motionandtemp.py b/zhaquirks/centralite/motionandtemp.py
new file mode 100644
--- /dev/null
+++ b/zhaquirks/centralite/motionandtemp.py
@@ -0,0 +1,150 @@
+"""Device handler for centralite 3450L."""
+# pylint disable=C0103
+from zigpy.profiles import zha
+from zigpy.quirks import CustomDevice
+from zigpy.zcl.clusters.general import (
+    Basic,
+    Identify,
+    OnOff,
+    OnOffConfiguration,
+    Ota,
+    PollControl,
+    PowerConfiguration,
+)
+
+from zhaquirks import PowerConfigurationCluster
+from zhaquirks.centralite import CENTRALITE
+from zhaquirks.const import (
+    BUTTON_1,
+    BUTTON_2,
+    BUTTON_3,
+    BUTTON_4,
+    COMMAND,
+    COMMAND_PRESS,
+    DEVICE_TYPE,
+    ENDPOINTS,
+    ENDPOINT_ID,
+    INPUT_CLUSTERS,
+    MODELS_INFO,
+    OUTPUT_CLUSTERS,
+    PROFILE_ID,
+    SHORT_PRESS,
+)
+
+DIAGNOSTICS_CLUSTER_ID = 0x0B05  # decimal = 2821
+
+
+class CustomPowerConfigurationCluster(PowerConfigurationCluster):
+    """Custom PowerConfigurationCluster."""
+
+    cluster_id = PowerConfiguration.cluster_id
+    MIN_VOLTS = 2.1
+    MAX_VOLTS = 3.0
+
+
+class CentraLite3450L(CustomDevice):
+    """Custom device representing centralite 3450L."""
+
+    signature = {
+        #  <SimpleDescriptor endpoint=1 profile=260 device_type=6
+        #  device_version=0
+        #  input_clusters=[0, 1, 3, 7, 20, b05]
+        #  output_clusters=[3, 6, 19]>
+        MODELS_INFO: [(CENTRALITE, "3450-L"), (CENTRALITE, "3450-L2")],
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    PowerConfiguration.cluster_id,
+                    Identify.cluster_id,
+                    OnOffConfiguration.cluster_id,
+                    PollControl.cluster_id,
+                    DIAGNOSTICS_CLUSTER_ID,
+                ],
+                OUTPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    OnOff.cluster_id,
+                    Ota.cluster_id,
+                ],
+            },
+            2: {
+                #  input_clusters=[7]
+                #  output_clusters=[6]>
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
+                INPUT_CLUSTERS: [OnOffConfiguration.cluster_id],
+                OUTPUT_CLUSTERS: [OnOff.cluster_id],
+            },
+            3: {
+                #  input_clusters=[7]
+                #  output_clusters=[6]>
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
+                INPUT_CLUSTERS: [OnOffConfiguration.cluster_id],
+                OUTPUT_CLUSTERS: [OnOff.cluster_id],
+            },
+            4: {
+                #  input_clusters=[7]
+                #  output_clusters=[6]>
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
+                INPUT_CLUSTERS: [OnOffConfiguration.cluster_id],
+                OUTPUT_CLUSTERS: [OnOff.cluster_id],
+            },
+        },
+    }
+
+    replacement = {
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    CustomPowerConfigurationCluster,
+                    Identify.cluster_id,
+                    OnOffConfiguration.cluster_id,
+                    PollControl.cluster_id,
+                    DIAGNOSTICS_CLUSTER_ID,
+                ],
+                OUTPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    OnOff.cluster_id,
+                    Ota.cluster_id,
+                ],
+            },
+            2: {
+                #  input_clusters=[7]
+                #  output_clusters=[6]>
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
+                INPUT_CLUSTERS: [OnOffConfiguration.cluster_id],
+                OUTPUT_CLUSTERS: [OnOff.cluster_id],
+            },
+            3: {
+                #  input_clusters=[7]
+                #  output_clusters=[6]>
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
+                INPUT_CLUSTERS: [OnOffConfiguration.cluster_id],
+                OUTPUT_CLUSTERS: [OnOff.cluster_id],
+            },
+            4: {
+                #  input_clusters=[7]
+                #  output_clusters=[6]>
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL,
+                INPUT_CLUSTERS: [OnOffConfiguration.cluster_id],
+                OUTPUT_CLUSTERS: [OnOff.cluster_id],
+            },
+        }
+    }
+
+    device_automation_triggers = {
+        (SHORT_PRESS, BUTTON_1): {COMMAND: COMMAND_PRESS, ENDPOINT_ID: 1},
+        (SHORT_PRESS, BUTTON_2): {COMMAND: COMMAND_PRESS, ENDPOINT_ID: 2},
+        (SHORT_PRESS, BUTTON_3): {COMMAND: COMMAND_PRESS, ENDPOINT_ID: 3},
+        (SHORT_PRESS, BUTTON_4): {COMMAND: COMMAND_PRESS, ENDPOINT_ID: 4},
+    }
diff --git a/zhaquirks/imagic/__init__.py b/zhaquirks/imagic/__init__.py
new file mode 100644
--- /dev/null
+++ b/zhaquirks/imagic/__init__.py
@@ -0,0 +1,3 @@
+"""Module for GreatStar quirks implementations."""
+
+IMAGIC = "iMagic by GreatStar"
diff --git a/zhaquirks/imagic/gs1117s.py b/zhaquirks/imagic/gs1117s.py
new file mode 100644
--- /dev/null
+++ b/zhaquirks/imagic/gs1117s.py
@@ -0,0 +1,79 @@
+"""Device handler for iMagic by Greatstar."""
+from zigpy.profiles import zha
+from zigpy.quirks import CustomDevice
+from zigpy.zcl.clusters.general import (
+    Basic,
+    Identify,
+    Ota,
+    PollControl,
+    PowerConfiguration,
+)
+from zigpy.zcl.clusters.homeautomation import Diagnostic
+from zigpy.zcl.clusters.measurement import TemperatureMeasurement, RelativeHumidity
+from zigpy.zcl.clusters.security import IasZone
+
+from zhaquirks import PowerConfigurationCluster
+
+from . import IMAGIC
+from ..const import (
+    DEVICE_TYPE,
+    ENDPOINTS,
+    INPUT_CLUSTERS,
+    MODELS_INFO,
+    OUTPUT_CLUSTERS,
+    PROFILE_ID,
+)
+
+MANUFACTURER_SPECIFIC_PROFILE_ID = 0xFC01
+MANUFACTURER_SPECIFIC_PROFILE_ID2 = 0xFC02
+
+
+class Greatstar(CustomDevice):
+    """Custom device representing iMagic by Greatstar motion sensors."""
+
+    signature = {
+        #  <SimpleDescriptor endpoint=1 profile=260 device_type=0x0402
+        #  device_version=0
+        #  input_clusters=["0x0000", "0x0001", "0x0003","0x0020","0x0402", "0x0405", "0x0500", "0x0b05","0xfc01","0xfc02"]
+        #  output_clusters=["0x0003","0x0019"]>
+        MODELS_INFO: [(IMAGIC, "1117-S")],
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    PowerConfiguration.cluster_id,
+                    Identify.cluster_id,
+                    PollControl.cluster_id,
+                    TemperatureMeasurement.cluster_id,
+                    RelativeHumidity.cluster_id,
+                    IasZone.cluster_id,
+                    Diagnostic.cluster_id,
+                    MANUFACTURER_SPECIFIC_PROFILE_ID,
+                    MANUFACTURER_SPECIFIC_PROFILE_ID2,
+                ],
+                OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
+            }
+        },
+    }
+
+    replacement = {
+        ENDPOINTS: {
+            1: {
+                INPUT_CLUSTERS: [
+                    Basic,
+                    PowerConfigurationCluster,
+                    Identify,
+                    PollControl,
+                    TemperatureMeasurement,
+                    RelativeHumidity,
+                    IasZone,
+                    Diagnostic,
+                    MANUFACTURER_SPECIFIC_PROFILE_ID,
+                    MANUFACTURER_SPECIFIC_PROFILE_ID2,
+                ],
+                OUTPUT_CLUSTERS: [Identify, Ota],
+            }
+        }
+    }


Test patch: