zha-device-handlers icon indicating copy to clipboard operation
zha-device-handlers copied to clipboard

[Device Support Request] Add support for Philips Hue Wall Switch RDM004

Open VEBERArnaud opened this issue 1 year ago • 9 comments

Problem description

I am encountering an issue with one of my Philips Hue Wall Switches and would appreciate your assistance. Here are the details:

  • Device 1: Philips Hue Wall Switch Model RDM001

    • Status: Works perfectly, no issues.
  • Device 2: Philips Hue Wall Switch Model RDM004

    • Problem: This device is not identified as a Philips Hue Wall Switch within the system. Consequently, it does not operate as expected.

Solution description

Add support for Philips Hue Wall Switch Model RDM004

Screenshots/Video

Screenshots/Video

Philips Hue Wall Switch Model RDM001, working as expected RDM001

Philips Hue Wall Switch Model RDM004, not working RDM004

Device signature

Device signature
{
  "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=4107, maximum_buffer_size=82, maximum_incoming_transfer_size=128, server_mask=11264, maximum_outgoing_transfer_size=128, 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": "0x0104",
      "device_type": "0x0830",
      "input_clusters": [
        "0x0000",
        "0x0001",
        "0x0003",
        "0xfc00"
      ],
      "output_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0006",
        "0x0008",
        "0x0019"
      ]
    }
  },
  "manufacturer": "Signify Netherlands B.V.",
  "model": "RDM004",
  "class": "zigpy.device.Device"
}

Diagnostic information

Diagnostic information
{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2023.11.2",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.11.6",
    "docker": true,
    "arch": "aarch64",
    "timezone": "Europe/Paris",
    "os_name": "Linux",
    "os_version": "6.1.21-v8",
    "supervisor": "2023.11.3",
    "host_os": "Home Assistant OS 11.1",
    "docker_version": "24.0.6",
    "chassis": "embedded",
    "run_as_root": true
  },
  "custom_components": {
    "hacs": {
      "version": "1.33.0",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    }
  },
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "after_dependencies": [
      "onboarding",
      "usb"
    ],
    "codeowners": [
      "@dmulcahey",
      "@adminiuga",
      "@puddly"
    ],
    "config_flow": true,
    "dependencies": [
      "file_upload"
    ],
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "iot_class": "local_polling",
    "loggers": [
      "aiosqlite",
      "bellows",
      "crccheck",
      "pure_pcapy3",
      "zhaquirks",
      "zigpy",
      "zigpy_deconz",
      "zigpy_xbee",
      "zigpy_zigate",
      "zigpy_znp",
      "universal_silabs_flasher"
    ],
    "requirements": [
      "bellows==0.36.8",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.106",
      "zigpy-deconz==0.21.1",
      "zigpy==0.59.0",
      "zigpy-xbee==0.19.0",
      "zigpy-zigate==0.11.0",
      "zigpy-znp==0.11.6",
      "universal-silabs-flasher==0.0.14",
      "pyserial-asyncio-fast==0.11"
    ],
    "usb": [
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*2652*",
        "known_devices": [
          "slae.sh cc2652rb stick"
        ]
      },
      {
        "vid": "1A86",
        "pid": "55D4",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus v2"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*zigstar*",
        "known_devices": [
          "ZigStar Coordinators"
        ]
      },
      {
        "vid": "1CF1",
        "pid": "0030",
        "description": "*conbee*",
        "known_devices": [
          "Conbee II"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8A2A",
        "description": "*zigbee*",
        "known_devices": [
          "Nortek HUSBZB-1"
        ]
      },
      {
        "vid": "0403",
        "pid": "6015",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate+"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8B34",
        "description": "*bv 2010/10*",
        "known_devices": [
          "Bitron Video AV2010/10"
        ]
      }
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      },
      {
        "type": "_zigstar_gw._tcp.local.",
        "name": "*zigstar*"
      },
      {
        "type": "_uzg-01._tcp.local.",
        "name": "uzg-01*"
      },
      {
        "type": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      }
    ],
    "is_built_in": true
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 2733,
    "manufacturer": "Signify Netherlands B.V.",
    "model": "RDM004",
    "name": "Signify Netherlands B.V. RDM004",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "quirk_id": null,
    "manufacturer_code": 4107,
    "power_source": "Battery or Unknown",
    "lqi": 184,
    "rssi": -54,
    "last_seen": "2023-11-19T00:35:42",
    "available": true,
    "device_type": "EndDevice",
    "signature": {
      "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=4107, maximum_buffer_size=82, maximum_incoming_transfer_size=128, server_mask=11264, maximum_outgoing_transfer_size=128, 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": "0x0104",
          "device_type": "0x0830",
          "input_clusters": [
            "0x0000",
            "0x0001",
            "0x0003",
            "0xfc00"
          ],
          "output_clusters": [
            "0x0000",
            "0x0003",
            "0x0004",
            "0x0006",
            "0x0008",
            "0x0019"
          ]
        }
      },
      "manufacturer": "Signify Netherlands B.V.",
      "model": "RDM004"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "sensor.test_switch_battery",
        "name": "Signify Netherlands B.V. RDM004"
      },
      {
        "entity_id": "button.test_switch_identify",
        "name": "Signify Netherlands B.V. RDM004"
      }
    ],
    "neighbors": [],
    "routes": [],
    "endpoint_names": [
      {
        "name": "NON_COLOR_SCENE_CONTROLLER"
      }
    ],
    "user_given_name": "Test Switch",
    "device_reg_id": "5e45b4468f3122dc3e685d098fd61626",
    "area_id": null,
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "NON_COLOR_SCENE_CONTROLLER",
          "id": 2096
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "Signify Netherlands B.V."
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "RDM004"
              }
            },
            "unsupported_attributes": {}
          },
          "0x0001": {
            "endpoint_attribute": "power",
            "attributes": {
              "0x0021": {
                "attribute_name": "battery_percentage_remaining",
                "value": 200
              },
              "0x0020": {
                "attribute_name": "battery_voltage",
                "value": 31
              }
            },
            "unsupported_attributes": {
              "0x0033": {
                "attribute_name": "battery_quantity"
              },
              "0x0031": {
                "attribute_name": "battery_size"
              }
            }
          },
          "0x0003": {
            "endpoint_attribute": "identify",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0xfc00": {
            "endpoint_attribute": "manufacturer_specific",
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0003": {
            "endpoint_attribute": "identify",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0006": {
            "endpoint_attribute": "on_off",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0008": {
            "endpoint_attribute": "level",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}

Logs

Logs
[Paste the logs here]

Custom quirk

Custom quirk
[Paste your custom quirk here]

Additional information

No response

VEBERArnaud avatar Nov 18 '23 23:11 VEBERArnaud

got it working with the custom quirk

"""Signify RDM004 device."""
import logging
from typing import Any, List, Optional, Union

from zigpy.profiles import zha
from zigpy.quirks import CustomCluster, CustomDevice
import zigpy.types as t
from zigpy.zcl import foundation
from zigpy.zcl.clusters.general import (
    Basic,
    Groups,
    Identify,
    LevelControl,
    OnOff,
    Ota,
    PowerConfiguration,
)

from zhaquirks.const import (
    ARGS,
    BUTTON,
    COMMAND,
    COMMAND_ID,
    DEVICE_TYPE,
    DOUBLE_PRESS,
    ENDPOINTS,
    INPUT_CLUSTERS,
    LONG_PRESS,
    LONG_RELEASE,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PRESS_TYPE,
    PROFILE_ID,
    QUADRUPLE_PRESS,
    QUINTUPLE_PRESS,
    RIGHT,
    SHORT_PRESS,
    SHORT_RELEASE,
    TRIPLE_PRESS,
    TURN_ON,
    ZHA_SEND_EVENT,
)
from zhaquirks.philips import PHILIPS, SIGNIFY

DEVICE_SPECIFIC_UNKNOWN = 64512
_LOGGER = logging.getLogger(__name__)


class PhilipsBasicCluster(CustomCluster, Basic):
    """Philips Basic cluster."""

    attributes = Basic.attributes.copy()
    attributes.update(
        {
            0x0031: ("philips", t.bitmap16, True),
            0x0034: ("mode", t.enum8, True),
        }
    )

    attr_config = {0x0031: 0x000B, 0x0034: 0x02}

    async def bind(self):
        """Bind cluster."""
        result = await super().bind()
        await self.write_attributes(self.attr_config, manufacturer=0x100B)
        return result


class PhilipsRemoteCluster(CustomCluster):
    """Philips remote cluster."""

    cluster_id = 64512
    name = "PhilipsRemoteCluster"
    ep_attribute = "philips_remote_cluster"
    client_commands = {
        0x00: foundation.ZCLCommandDef(
            "notification",
            {
                "param1": t.uint8_t,
                "param2": t.uint24_t,
                "param3": t.uint8_t,
                "param4": t.uint8_t,
                "param5": t.uint8_t,
                "param6": t.uint8_t,
            },
            is_manufacturer_specific=True,
            direction=foundation.Direction.Server_to_Client,
        )
    }
    BUTTONS = {
        1: "left",
        2: "right",
    }
    PRESS_TYPES = {0: "press", 1: "hold", 2: "press_release", 3: "hold_release"}

    def handle_cluster_request(
        self,
        hdr: foundation.ZCLHeader,
        args: List[Any],
        *,
        dst_addressing: Optional[
            Union[t.Addressing.Group, t.Addressing.IEEE, t.Addressing.NWK]
        ] = None,
    ):
        """Handle the cluster command."""
        _LOGGER.debug(
            "PhilipsRemoteCluster - handle_cluster_request tsn: [%s] command id: %s - args: [%s]",
            hdr.tsn,
            hdr.command_id,
            args,
        )

        button = self.BUTTONS.get(args[0], args[0])
        press_type = self.PRESS_TYPES.get(args[2], args[2])

        event_args = {
            BUTTON: button,
            PRESS_TYPE: press_type,
            COMMAND_ID: hdr.command_id,
            ARGS: args,
        }

        action = f"{button}_{press_type}"
        self.listener_event(ZHA_SEND_EVENT, action, event_args)


class PhilipsROM004(CustomDevice):
    """Philips ROM004 device."""

    signature = {
        #  <SimpleDescriptor endpoint=1 profile=260 device_type=2080
        #  device_version=1
        #  input_clusters=[0, 1, 3, 64512]
        #  output_clusters=[3, 4, 6, 8, 25]>
        MODELS_INFO: [(PHILIPS, "RDM004"), (SIGNIFY, "RDM004")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.NON_COLOR_SCENE_CONTROLLER,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfiguration.cluster_id,
                    Identify.cluster_id,
                    DEVICE_SPECIFIC_UNKNOWN,
                ],
                OUTPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    OnOff.cluster_id,
                    LevelControl.cluster_id,
                    Ota.cluster_id,
                ],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.NON_COLOR_CONTROLLER,
                INPUT_CLUSTERS: [
                    PhilipsBasicCluster,
                    PowerConfiguration.cluster_id,
                    Identify.cluster_id,
                    PhilipsRemoteCluster,
                ],
                OUTPUT_CLUSTERS: [
                    Ota.cluster_id,
                    Identify.cluster_id,
                    Groups.cluster_id,
                    OnOff.cluster_id,
                    LevelControl.cluster_id,
                ],
            }
        }
    }

    device_automation_triggers = {
        (SHORT_PRESS, TURN_ON): {COMMAND: "left_press"},
        (LONG_PRESS, TURN_ON): {COMMAND: "left_hold"},
        (DOUBLE_PRESS, TURN_ON): {COMMAND: "left_double_press"},
        (TRIPLE_PRESS, TURN_ON): {COMMAND: "left_triple_press"},
        (QUADRUPLE_PRESS, TURN_ON): {COMMAND: "left_quadruple_press"},
        (QUINTUPLE_PRESS, TURN_ON): {COMMAND: "left_quintuple_press"},
        (SHORT_RELEASE, TURN_ON): {COMMAND: "left_short_release"},
        (LONG_RELEASE, TURN_ON): {COMMAND: "left_long_release"},
        (SHORT_PRESS, RIGHT): {COMMAND: "right_press"},
        (LONG_PRESS, RIGHT): {COMMAND: "right_hold"},
        (DOUBLE_PRESS, RIGHT): {COMMAND: "right_double_press"},
        (TRIPLE_PRESS, RIGHT): {COMMAND: "right_triple_press"},
        (QUADRUPLE_PRESS, RIGHT): {COMMAND: "right_quadruple_press"},
        (QUINTUPLE_PRESS, RIGHT): {COMMAND: "right_quintuple_press"},
        (SHORT_RELEASE, RIGHT): {COMMAND: "right_short_release"},
        (LONG_RELEASE, RIGHT): {COMMAND: "right_long_release"},
    }

VEBERArnaud avatar Nov 19 '23 01:11 VEBERArnaud

If the RDM004 is compatible with the old RDM001(?) then could just add as an additional signature to exising rdm001.py quirk:

https://github.com/zigpy/zha-device-handlers/blob/dev/zhaquirks/philips/rdm001.py

For reference also see this related zigbee-herdsman-converters discussion mentioning old 929003017102 and new 9290030171A:

https://github.com/Koenkk/zigbee-herdsman-converters/issues/6269

Hedda avatar Dec 05 '23 11:12 Hedda

agree with this ticket. Same behaviour at my instance with the RDM004 Philips / Signify. RDM001 works just fine. I don't see any button triggers with this device in HAOS.

Quirk seems to work. Thanks @VEBERArnaud !

dennisborger avatar Dec 28 '23 11:12 dennisborger

I hope this can be added to the ZHA-library soon. I don't get the custom quirk to work. Specific the second button on my RDM004 doesn't work. I should change the mode 3 - double push button type switch, but I can't find that option (0x0034) in ZHA.

Anyone already found the setting to change the mode? '0x0034' or 'mode' doesn't appear in my list of clusters and attributes.

KWOAD avatar Feb 22 '24 20:02 KWOAD

Quirk works for me, thanks! :)

s-mod avatar Feb 23 '24 18:02 s-mod

I got the same problem. Can anyone maby give me a short description where i can import that given code to?

swatmugga avatar Mar 09 '24 20:03 swatmugga

See here for detailed instructions on adding a custom quirk: https://community.home-assistant.io/t/how-to-configure-the-philips-hue-wall-module-to-use-push-button-momentary-type-wall-switches-zha/451125/27

davidgeiger avatar Mar 25 '24 17:03 davidgeiger