Repository: zigpy/zha-device-handlers

Issue:
[BUG] NodOn on_off light switch seen as a dimmer
**Is your feature request related to a problem? Please describe.**
NodON SIN-4-2-20 light switch is quite well supported but ZHA offers dimming capability for it, while the module is only an on_off switch (confirmed with tech specs, and also tested with a dimming capable light, which didn't work).

The problem is that there is an in_cluster 0x0008 twice in its signature one for each relay.

**Describe the solution you'd like**
A quirck should be added for this device with a replacement, removing those 2 entries.

**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.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4747, 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": 260,
      "device_type": "0x0100",
      "in_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x0007",
        "0x0008",
        "0x1000",
        "0xfc57"
      ],
      "out_clusters": [
        "0x0003",
        "0x0006",
        "0x0019"
      ]
    },
    "2": {
      "profile_id": 260,
      "device_type": "0x0100",
      "in_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x0007",
        "0x0008"
      ],
      "out_clusters": [
        "0x0003",
        "0x0006"
      ]
    },
    "242": {
      "profile_id": 41440,
      "device_type": "0x0066",
      "in_clusters": [
        "0x0021"
      ],
      "out_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "NodOn",
  "model": "SIN-4-2-20",
  "class": "zigpy.device.Device"
}`

**Additional context**

![dimmer_nodon](https://user-images.githubusercontent.com/18574781/154046341-5cdc9b38-5a76-452b-8a73-aa819a409deb.PNG)

> {
>  "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.AllocateAddress|RxOnWhenIdle|MainsPowered|FullFunctionDevice: 142>, manufacturer_code=4747, 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": 260,
>      "device_type": "0x0100",
>      "in_clusters": [
>        "0x0000",
>        "0x0003",
>        "0x0004",
>        "0x0005",
>        "0x0006",
>        "0x0007",
>        "0x0008",     ### HERE ###
>        "0x1000",
>        "0xfc57"
>      ],
>      "out_clusters": [
>        "0x0003",
>        "0x0006",
>        "0x0019"
>      ]
>    },
>    "2": {
>      "profile_id": 260,
>      "device_type": "0x0100",
>      "in_clusters": [
>        "0x0000",
>        "0x0003",
>        "0x0004",
>        "0x0005",
>        "0x0006",
>        "0x0007",
>        "0x0008"    ### HERE ###
>      ],
>      "out_clusters": [
>        "0x0003",
>        "0x0006"
>      ]
>    },
>    "242": {
>      "profile_id": 41440,
>      "device_type": "0x0066",
>      "in_clusters": [
>        "0x0021"
>      ],
>      "out_clusters": [
>        "0x0021"
>      ]
>    }
>  },
>  "manufacturer": "NodOn",
>  "model": "SIN-4-2-20",
>  "class": "zigpy.device.Device"
>}

Here is the problem. I would have write it myself, had I been proficient enough in python, which isn't the case... I would need a bit of help ;) Thanks in advance !



Discussion:
I was looking on the quirk for IKEA outlet and the old ZLL was deleting the light level cluster so ZHA was not exposing the brightness. But the ZB3 is having it and no patching is dont and its not exposing the brightness is ZHA but its one  `ON_OFF_PLUG_IN_UNIT` and IKEA is sending move with on / off with there remotes so its way its need it (but not in ZHA).

Your device is one `ON_OFF_LIGHT` and ZHA shall **not** making any brightness slider but its doing it for 110% for you.

You can looking on https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/tuya/ts0501bs.py ther they is taking away the color cluster from one no color light.
Copy it and fixing the device signature and making the replace the same as signature but deleting the light level cluster.
It can being that you need defining more imports and also deleting things you dont need for getting it working but its one easy quirk for patching.

Configure local quirk https://github.com/zigpy/zha-device-handlers/discussions/693#discussioncomment-857274 and putting your new quirk in the new folder and restarting HA.
Thanks a lot for all this. I'll try to get the job done. You gave me more than I needed ;)
Hi @altmenorg, did you get the custom quirk working?
If so and it's still working on Home Assistant 2022.4.5, can you PR the changes or just send the quirk you're currently using here? (So that it can be integrated into Home Assistant itself)
Hi TheJulianJES. To be honnest I couldn't find time to work on the issue (crazy amount of work to do...).
I came here to finally start and read your message.
I have more available time these days, si I plan to work on it and hopefully get it to work in the next few days.
I'll let you know.
hi @TheJulianJES,

I finally was able to write the quirck. and it's working on 2022.6.6

Here is the quirck content, so you can integrate the code where it should be (I don't know about zigpy guidelines).



    """NodOn on/off switch two channels."""
    from zigpy.profiles import zha
    from zigpy.quirks import CustomDevice
    from zigpy.zcl.clusters.general import (
        Basic,
        GreenPowerProxy,
        Groups,
        Identify,
        LevelControl,
        OnOff,
        OnOffConfiguration,
        Ota,
        Scenes,
    )
    from zigpy.zcl.clusters.lightlink import LightLink
    
    from zhaquirks.const import (
        DEVICE_TYPE,
        ENDPOINTS,
        INPUT_CLUSTERS,
        MODELS_INFO,
        OUTPUT_CLUSTERS,
        PROFILE_ID,
    )

    class NodOnSIN4220(CustomDevice):
        """NodOn on/off switch two channels."""
    
        signature = {
            MODELS_INFO: [("NodOn", "SIN-4-2-20")],
            ENDPOINTS: {
                # <SimpleDescriptor endpoint=1 profile=260 device_type=256
                # input_clusters=[0, 3, 4, 5, 6, 7, 8, 4096, 64599]
                # output_clusters=[3, 6, 25]>
                1: {
                    PROFILE_ID: zha.PROFILE_ID,
                    DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                    INPUT_CLUSTERS: [
                        Basic.cluster_id,
                        Identify.cluster_id,
                        Groups.cluster_id,
                        Scenes.cluster_id,
                        OnOff.cluster_id,
                        OnOffConfiguration.cluster_id,
                        LevelControl.cluster_id,
                        LightLink.cluster_id,
                        64599,
                    ],
                    OUTPUT_CLUSTERS: [Identify.cluster_id, OnOff.cluster_id, Ota.cluster_id],
                },
                # <SimpleDescriptor endpoint=1 profile=260 device_type=256
                # input_clusters=[0, 3, 4, 5, 6, 7, 8]
                # output_clusters=[3, 6]>
                2: {
                    PROFILE_ID: zha.PROFILE_ID,
                    DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                    INPUT_CLUSTERS: [
                        Basic.cluster_id,
                        Identify.cluster_id,
                        Groups.cluster_id,
                        Scenes.cluster_id,
                        OnOff.cluster_id,
                        OnOffConfiguration.cluster_id,                  
                        LevelControl.cluster_id,
                    ],
                    OUTPUT_CLUSTERS: [Identify.cluster_id, OnOff.cluster_id],
                },            
                # <SimpleDescriptor endpoint=242 profile=41440 device_type=102
                # input_clusters=[33]
                # output_clusters=[33]
                242: {
                    PROFILE_ID: 41440,
                    DEVICE_TYPE: 102,
                    INPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
                    OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
                },
            },
        }
        replacement = {
            ENDPOINTS: {
                1: {
                    PROFILE_ID: zha.PROFILE_ID,
                    DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                    INPUT_CLUSTERS: [
                        Basic.cluster_id,
                        Identify.cluster_id,
                        Groups.cluster_id,
                        Scenes.cluster_id,
                        OnOff.cluster_id,
                        OnOffConfiguration.cluster_id,
                        LightLink.cluster_id,
                        64599,
                    ],
                    OUTPUT_CLUSTERS: [Identify.cluster_id, OnOff.cluster_id, Ota.cluster_id],
                },
                2: {
                    PROFILE_ID: zha.PROFILE_ID,
                    DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
                    INPUT_CLUSTERS: [
                        Basic.cluster_id,
                        Identify.cluster_id,
                        Groups.cluster_id,
                        Scenes.cluster_id,
                        OnOff.cluster_id,
                        OnOffConfiguration.cluster_id,
                    ],
                    OUTPUT_CLUSTERS: [Identify.cluster_id, OnOff.cluster_id],
                },
                242: {
                    PROFILE_ID: 41440,
                    DEVICE_TYPE: 102,
                    INPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
                    OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
                },
            },
        }

@TheJulianJES : just did the PR.
Thanks again for the help !

Resolving patch:
diff --git a/zhaquirks/nodon/sin-4-2-20.py b/zhaquirks/nodon/sin-4-2-20.py
new file mode 100644
--- /dev/null
+++ b/zhaquirks/nodon/sin-4-2-20.py
@@ -0,0 +1,125 @@
+"""NodOn on/off switch two channels."""
+from zigpy.profiles import zha
+from zigpy.quirks import CustomDevice
+from zigpy.zcl.clusters.general import (
+    Basic,
+    GreenPowerProxy,
+    Groups,
+    Identify,
+    LevelControl,
+    OnOff,
+    OnOffConfiguration,
+    Ota,
+    Scenes,
+)
+from zigpy.zcl.clusters.lightlink import LightLink
+
+from zhaquirks.const import (
+    DEVICE_TYPE,
+    ENDPOINTS,
+    INPUT_CLUSTERS,
+    MODELS_INFO,
+    OUTPUT_CLUSTERS,
+    PROFILE_ID,
+)
+
+
+class NodOnSIN4220(CustomDevice):
+    """NodOn on/off switch two channels."""
+
+    signature = {
+        MODELS_INFO: [("NodOn", "SIN-4-2-20")],
+        ENDPOINTS: {
+            # <SimpleDescriptor endpoint=1 profile=260 device_type=256
+            # input_clusters=[0, 3, 4, 5, 6, 7, 8, 4096, 64599]
+            # output_clusters=[3, 6, 25]>
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    OnOffConfiguration.cluster_id,
+                    LevelControl.cluster_id,
+                    LightLink.cluster_id,
+                    64599,
+                ],
+                OUTPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    OnOff.cluster_id,
+                    Ota.cluster_id,
+                ],
+            },
+            # <SimpleDescriptor endpoint=1 profile=260 device_type=256
+            # input_clusters=[0, 3, 4, 5, 6, 7, 8]
+            # output_clusters=[3, 6]>
+            2: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    OnOffConfiguration.cluster_id,
+                    LevelControl.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Identify.cluster_id, OnOff.cluster_id],
+            },
+            # <SimpleDescriptor endpoint=242 profile=41440 device_type=102
+            # input_clusters=[33]
+            # output_clusters=[33]
+            242: {
+                PROFILE_ID: 41440,
+                DEVICE_TYPE: 102,
+                INPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
+                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
+            },
+        },
+    }
+    replacement = {
+        ENDPOINTS: {
+            1: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    OnOffConfiguration.cluster_id,
+                    LightLink.cluster_id,
+                    64599,
+                ],
+                OUTPUT_CLUSTERS: [
+                    Identify.cluster_id,
+                    OnOff.cluster_id,
+                    Ota.cluster_id,
+                ],
+            },
+            2: {
+                PROFILE_ID: zha.PROFILE_ID,
+                DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
+                INPUT_CLUSTERS: [
+                    Basic.cluster_id,
+                    Identify.cluster_id,
+                    Groups.cluster_id,
+                    Scenes.cluster_id,
+                    OnOff.cluster_id,
+                    OnOffConfiguration.cluster_id,
+                ],
+                OUTPUT_CLUSTERS: [Identify.cluster_id, OnOff.cluster_id],
+            },
+            242: {
+                PROFILE_ID: 41440,
+                DEVICE_TYPE: 102,
+                INPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
+                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
+            },
+        },
+    }


Test patch: