Repository: zigpy/zha-device-handlers

Issue:
[Device Support Request] OSRAM Switch-LIGHTIFY
**Is your feature request related to a problem? Please describe.**
This switch version is not yet supportet

**Describe the solution you'd like**
Complete device support
Primary buttons and secondary the battery (seems to report the voltage but HA says unknown)

**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://pastebin.com/ZTE1nkrr

**Additional context**
zha_event log pressing all buttons
https://pastebin.com/Lm7W210A



Discussion:
The device wasn’t removed. You need to press the remove device button on the device card in the ZHA config panel then press a button on the remote to wake it up. Wait about a minute then re-pair the device and attach the logs. The log should contain <SimpleDescriptor lines. If it doesn’t it wasn’t removed and re-paired correctly
I've waited 5min between removing and adding it again...
Will setup a VM and pair it there...then it should be ok
Did you wake the remote up when removing it? It’s a battery powered device. You have to ensure it isn’t sleeping or it won’t remove
ehm nope but I have reset the remote
Yeah that’s not gonna remove the data from zigpy. Pair it, remove it while waking it up to make sure that it’s removed for real. Then pair it.
After I successfully destroyed my ZHA I think I got it now right
Yep paste looks good. I’ll take a look in a bit.

Resolving patch:
diff --git a/zhaquirks/osram/lightifyx4.py b/zhaquirks/osram/lightifyx4.py
--- a/zhaquirks/osram/lightifyx4.py
+++ b/zhaquirks/osram/lightifyx4.py
@@ -1,4 +1,5 @@
 """Osram Lightify X4 device."""
+import copy
 import logging
 
 from zigpy.profiles import zha
@@ -48,55 +49,71 @@
 _LOGGER = logging.getLogger(__name__)
 
 
-class LightifyX4(CustomDevice):
-    """Osram Lightify X4 device."""
+class OsramButtonCluster(CustomCluster):
+    """OsramButtonCluster."""
 
-    class OsramButtonCluster(CustomCluster):
-        """OsramButtonCluster."""
+    cluster_id = OSRAM_CLUSTER
+    name = "OsramCluster"
+    ep_attribute = "osram_cluster"
+    attributes = {
+        0x000A: ("osram_1", t.uint8_t),
+        0x000B: ("osram_2", t.uint8_t),
+        0x000C: ("osram_3", t.uint16_t),
+        0x000D: ("osram_4", t.uint16_t),
+        0x0019: ("osram_5", t.uint8_t),
+        0x001A: ("osram_6", t.uint16_t),
+        0x001B: ("osram_7", t.uint16_t),
+        0x001C: ("osram_8", t.uint8_t),
+        0x001D: ("osram_9", t.uint16_t),
+        0x001E: ("osram_10", t.uint16_t),
+        0x002C: ("osram_11", t.uint16_t),
+        0x002D: ("osram_12", t.uint16_t),
+        0x002E: ("osram_13", t.uint16_t),
+        0x002F: ("osram_14", t.uint16_t),
+    }
+    server_commands = {}
+    client_commands = {}
+    attr_config = {
+        0x000A: 0x01,
+        0x000B: 0x00,
+        0x000C: 0xFFFF,
+        0x000D: 0xFFFF,
+        0x0019: 0x06,
+        0x001A: 0x0001,
+        0x001B: 0x0026,
+        0x001C: 0x07,
+        0x001D: 0xFFFF,
+        0x001E: 0xFFFF,
+        0x002C: 0xFFFF,
+        0x002D: 0xFFFF,
+        0x002E: 0xFFFF,
+        0x002F: 0xFFFF,
+    }
 
-        cluster_id = OSRAM_CLUSTER
-        name = "OsramCluster"
-        ep_attribute = "osram_cluster"
-        attributes = {
-            0x000A: ("osram_1", t.uint8_t),
-            0x000B: ("osram_2", t.uint8_t),
-            0x000C: ("osram_3", t.uint16_t),
-            0x000D: ("osram_4", t.uint16_t),
-            0x0019: ("osram_5", t.uint8_t),
-            0x001A: ("osram_6", t.uint16_t),
-            0x001B: ("osram_7", t.uint16_t),
-            0x001C: ("osram_8", t.uint8_t),
-            0x001D: ("osram_9", t.uint16_t),
-            0x001E: ("osram_10", t.uint16_t),
-            0x002C: ("osram_11", t.uint16_t),
-            0x002D: ("osram_12", t.uint16_t),
-            0x002E: ("osram_13", t.uint16_t),
-            0x002F: ("osram_14", t.uint16_t),
-        }
-        server_commands = {}
-        client_commands = {}
-        attr_config = {
-            0x000A: 0x01,
-            0x000B: 0x00,
-            0x000C: 0xFFFF,
-            0x000D: 0xFFFF,
-            0x0019: 0x06,
-            0x001A: 0x0001,
-            0x001B: 0x0026,
-            0x001C: 0x07,
-            0x001D: 0xFFFF,
-            0x001E: 0xFFFF,
-            0x002C: 0xFFFF,
-            0x002D: 0xFFFF,
-            0x002E: 0xFFFF,
-            0x002F: 0xFFFF,
-        }
+    async def bind(self):
+        """Bind cluster."""
+        result = await super().bind()
+        await self.write_attributes(self.attr_config, manufacturer=OSRAM_MFG_CODE)
+        return result
 
-        async def bind(self):
-            """Bind cluster."""
-            result = await super().bind()
-            await self.write_attributes(self.attr_config, manufacturer=OSRAM_MFG_CODE)
-            return result
+
+class LightifyX4(CustomDevice):
+    """Osram Lightify X4 device."""
+
+    SIGNATURE_ENDPOINT = {
+        PROFILE_ID: zha.PROFILE_ID,
+        DEVICE_TYPE: OSRAM_DEVICE,
+        INPUT_CLUSTERS: [Basic.cluster_id, LightLink.cluster_id, OSRAM_CLUSTER],
+        OUTPUT_CLUSTERS: [
+            Groups.cluster_id,
+            Identify.cluster_id,
+            Scenes.cluster_id,
+            OnOff.cluster_id,
+            Color.cluster_id,
+            LevelControl.cluster_id,
+            LightLink.cluster_id,
+        ],
+    }
 
     signature = {
         #  <SimpleDescriptor endpoint=1 profile=260 device_type=2064
@@ -130,95 +147,45 @@ async def bind(self):
             # device_version=2
             # input_clusters=[0, 4096, 64768]
             # output_clusters=[3, 4, 5, 6, 8, 768, 4096]>
-            2: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: OSRAM_DEVICE,
-                INPUT_CLUSTERS: [Basic.cluster_id, LightLink.cluster_id, OSRAM_CLUSTER],
-                OUTPUT_CLUSTERS: [
-                    Groups.cluster_id,
-                    Identify.cluster_id,
-                    Scenes.cluster_id,
-                    OnOff.cluster_id,
-                    Color.cluster_id,
-                    LevelControl.cluster_id,
-                    LightLink.cluster_id,
-                ],
-            },
+            2: copy.deepcopy(SIGNATURE_ENDPOINT),
             # <SimpleDescriptor endpoint=3 profile=260 device_type=2064
             # device_version=2
             # input_clusters=[0, 4096, 64768]
             # output_clusters=[3, 4, 5, 6, 8, 768, 4096]>
-            3: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: OSRAM_DEVICE,
-                INPUT_CLUSTERS: [Basic.cluster_id, LightLink.cluster_id, OSRAM_CLUSTER],
-                OUTPUT_CLUSTERS: [
-                    Groups.cluster_id,
-                    Identify.cluster_id,
-                    Scenes.cluster_id,
-                    OnOff.cluster_id,
-                    Color.cluster_id,
-                    LevelControl.cluster_id,
-                    LightLink.cluster_id,
-                ],
-            },
+            3: copy.deepcopy(SIGNATURE_ENDPOINT),
             # <SimpleDescriptor endpoint=4 profile=260 device_type=2064
             # device_version=2
             # input_clusters=[0, 4096, 64768]
             # output_clusters=[3, 4, 5, 6, 8, 768, 4096]>
-            4: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: OSRAM_DEVICE,
-                INPUT_CLUSTERS: [Basic.cluster_id, LightLink.cluster_id, OSRAM_CLUSTER],
-                OUTPUT_CLUSTERS: [
-                    Groups.cluster_id,
-                    Identify.cluster_id,
-                    Scenes.cluster_id,
-                    OnOff.cluster_id,
-                    Color.cluster_id,
-                    LevelControl.cluster_id,
-                    LightLink.cluster_id,
-                ],
-            },
+            4: copy.deepcopy(SIGNATURE_ENDPOINT),
             # <SimpleDescriptor endpoint=5 profile=260 device_type=2064
             # device_version=2
             # input_clusters=[0, 4096, 64768]
             # output_clusters=[3, 4, 5, 6, 8, 768, 4096]>
-            5: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: OSRAM_DEVICE,
-                INPUT_CLUSTERS: [Basic.cluster_id, LightLink.cluster_id, OSRAM_CLUSTER],
-                OUTPUT_CLUSTERS: [
-                    Groups.cluster_id,
-                    Identify.cluster_id,
-                    Scenes.cluster_id,
-                    OnOff.cluster_id,
-                    Color.cluster_id,
-                    LevelControl.cluster_id,
-                    LightLink.cluster_id,
-                ],
-            },
+            5: copy.deepcopy(SIGNATURE_ENDPOINT),
             # <SimpleDescriptor endpoint=6 profile=260 device_type=2064
             # device_version=2
             # input_clusters=[0, 4096, 64768]
             # output_clusters=[3, 4, 5, 6, 8, 768, 4096]>
-            6: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: OSRAM_DEVICE,
-                INPUT_CLUSTERS: [Basic.cluster_id, LightLink.cluster_id, OSRAM_CLUSTER],
-                OUTPUT_CLUSTERS: [
-                    Groups.cluster_id,
-                    Identify.cluster_id,
-                    Scenes.cluster_id,
-                    OnOff.cluster_id,
-                    Color.cluster_id,
-                    LevelControl.cluster_id,
-                    LightLink.cluster_id,
-                ],
-            },
+            6: copy.deepcopy(SIGNATURE_ENDPOINT),
         },
     }
 
+    REPLACEMENT_ENDPOINT = {
+        PROFILE_ID: zha.PROFILE_ID,
+        DEVICE_TYPE: OSRAM_DEVICE,
+        INPUT_CLUSTERS: [Basic.cluster_id, LightLink.cluster_id, OsramButtonCluster],
+        OUTPUT_CLUSTERS: [
+            Groups.cluster_id,
+            Identify.cluster_id,
+            Scenes.cluster_id,
+            OnOff.cluster_id,
+            Color.cluster_id,
+            LevelControl.cluster_id,
+            LightLink.cluster_id,
+        ],
+    }
+
     replacement = {
         ENDPOINTS: {
             1: {
@@ -242,88 +209,11 @@ async def bind(self):
                     LightLink.cluster_id,
                 ],
             },
-            2: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: OSRAM_DEVICE,
-                INPUT_CLUSTERS: [
-                    Basic.cluster_id,
-                    LightLink.cluster_id,
-                    OsramButtonCluster,
-                ],
-                OUTPUT_CLUSTERS: [
-                    Groups.cluster_id,
-                    Identify.cluster_id,
-                    Scenes.cluster_id,
-                    OnOff.cluster_id,
-                    Color.cluster_id,
-                    LevelControl.cluster_id,
-                    LightLink.cluster_id,
-                ],
-            },
-            3: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: OSRAM_DEVICE,
-                INPUT_CLUSTERS: [
-                    Basic.cluster_id,
-                    LightLink.cluster_id,
-                    OsramButtonCluster,
-                ],
-                OUTPUT_CLUSTERS: [
-                    Groups.cluster_id,
-                    Identify.cluster_id,
-                    Scenes.cluster_id,
-                    OnOff.cluster_id,
-                    Color.cluster_id,
-                    LevelControl.cluster_id,
-                    LightLink.cluster_id,
-                ],
-            },
-            4: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: OSRAM_DEVICE,
-                INPUT_CLUSTERS: [
-                    Basic.cluster_id,
-                    LightLink.cluster_id,
-                    OsramButtonCluster,
-                ],
-                OUTPUT_CLUSTERS: [
-                    Groups.cluster_id,
-                    Identify.cluster_id,
-                    Scenes.cluster_id,
-                    OnOff.cluster_id,
-                    Color.cluster_id,
-                    LevelControl.cluster_id,
-                    LightLink.cluster_id,
-                ],
-            },
-            5: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: OSRAM_DEVICE,
-                INPUT_CLUSTERS: [Basic.cluster_id, LightLink.cluster_id, OSRAM_CLUSTER],
-                OUTPUT_CLUSTERS: [
-                    Groups.cluster_id,
-                    Identify.cluster_id,
-                    Scenes.cluster_id,
-                    OnOff.cluster_id,
-                    Color.cluster_id,
-                    LevelControl.cluster_id,
-                    LightLink.cluster_id,
-                ],
-            },
-            6: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: OSRAM_DEVICE,
-                INPUT_CLUSTERS: [Basic.cluster_id, LightLink.cluster_id, OSRAM_CLUSTER],
-                OUTPUT_CLUSTERS: [
-                    Groups.cluster_id,
-                    Identify.cluster_id,
-                    Scenes.cluster_id,
-                    OnOff.cluster_id,
-                    Color.cluster_id,
-                    LevelControl.cluster_id,
-                    LightLink.cluster_id,
-                ],
-            },
+            2: copy.deepcopy(REPLACEMENT_ENDPOINT),
+            3: copy.deepcopy(REPLACEMENT_ENDPOINT),
+            4: copy.deepcopy(REPLACEMENT_ENDPOINT),
+            5: copy.deepcopy(REPLACEMENT_ENDPOINT),
+            6: copy.deepcopy(REPLACEMENT_ENDPOINT),
         }
     }
 
@@ -341,3 +231,86 @@ async def bind(self):
         (LONG_RELEASE, BUTTON_3): {COMMAND: COMMAND_STOP, ENDPOINT_ID: 3},
         (LONG_RELEASE, BUTTON_4): {COMMAND: COMMAND_STOP, ENDPOINT_ID: 4},
     }
+
+
+class LightifySwitch(CustomDevice):
+    """Osram Lightify Switch device."""
+
+    SIGNATURE_ENDPOINT = {
+        PROFILE_ID: zha.PROFILE_ID,
+        DEVICE_TYPE: OSRAM_DEVICE,
+        INPUT_CLUSTERS: [LightLink.cluster_id, OSRAM_CLUSTER],
+        OUTPUT_CLUSTERS: [
+            Groups.cluster_id,
+            Identify.cluster_id,
+            Scenes.cluster_id,
+            OnOff.cluster_id,
+            Color.cluster_id,
+            LevelControl.cluster_id,
+            LightLink.cluster_id,
+        ],
+    }
+
+    signature = {
+        #  <SimpleDescriptor endpoint=1 profile=260 device_type=2064
+        #  device_version=2
+        #  input_clusters=[0, 1, 32, 4096, 64768]
+        #  output_clusters=[3, 4, 5, 6, 8, 25, 768, 4096]>
+        MODELS_INFO: [(OSRAM, "Switch-LIGHTIFY")],
+        ENDPOINTS: {
+            1: copy.deepcopy(LightifyX4.signature[ENDPOINTS][1]),
+            # <SimpleDescriptor endpoint=2 profile=260 device_type=2064
+            # device_version=2
+            # input_clusters=[4096, 64768]
+            # output_clusters=[3, 4, 5, 6, 8, 768, 4096]>
+            2: copy.deepcopy(SIGNATURE_ENDPOINT),
+            # <SimpleDescriptor endpoint=3 profile=260 device_type=2064
+            # device_version=2
+            # input_clusters=[4096, 64768]
+            # output_clusters=[3, 4, 5, 6, 8, 768, 4096]>
+            3: copy.deepcopy(SIGNATURE_ENDPOINT),
+            # <SimpleDescriptor endpoint=4 profile=260 device_type=2064
+            # device_version=2
+            # input_clusters=[4096, 64768]
+            # output_clusters=[3, 4, 5, 6, 8, 768, 4096]>
+            4: copy.deepcopy(SIGNATURE_ENDPOINT),
+            # <SimpleDescriptor endpoint=5 profile=260 device_type=2064
+            # device_version=2
+            # input_clusters=[4096, 64768]
+            # output_clusters=[3, 4, 5, 6, 8, 768, 4096]>
+            5: copy.deepcopy(SIGNATURE_ENDPOINT),
+            # <SimpleDescriptor endpoint=6 profile=260 device_type=2064
+            # device_version=2
+            # input_clusters=[4096, 64768]
+            # output_clusters=[3, 4, 5, 6, 8, 768, 4096]>
+            6: copy.deepcopy(SIGNATURE_ENDPOINT),
+        },
+    }
+
+    REPLACEMENT_ENDPOINT = {
+        PROFILE_ID: zha.PROFILE_ID,
+        DEVICE_TYPE: OSRAM_DEVICE,
+        INPUT_CLUSTERS: [LightLink.cluster_id, OsramButtonCluster],
+        OUTPUT_CLUSTERS: [
+            Groups.cluster_id,
+            Identify.cluster_id,
+            Scenes.cluster_id,
+            OnOff.cluster_id,
+            Color.cluster_id,
+            LevelControl.cluster_id,
+            LightLink.cluster_id,
+        ],
+    }
+
+    replacement = {
+        ENDPOINTS: {
+            1: copy.deepcopy(LightifyX4.replacement[ENDPOINTS][1]),
+            2: copy.deepcopy(REPLACEMENT_ENDPOINT),
+            3: copy.deepcopy(REPLACEMENT_ENDPOINT),
+            4: copy.deepcopy(REPLACEMENT_ENDPOINT),
+            5: copy.deepcopy(REPLACEMENT_ENDPOINT),
+            6: copy.deepcopy(REPLACEMENT_ENDPOINT),
+        }
+    }
+
+    device_automation_triggers = copy.deepcopy(LightifyX4.device_automation_triggers)


Test patch: