How to configure the Philips Hue wall module to use push button (momentary) type wall switches [ZHA]

Ok guys, I had the same problem as most of you, but managed to make it working.

Why don’t you see the needed configuration…well you most likely have a newer model named RDM004. Apparently this is not supported yet.

Here are my steps to make it work.

  1. Open you favourite file editor. I use Studio Code Server;
  2. Make a new folder. In my case the folder is named “custom_zha_quirks”;
  3. Make a new file named MYFILE.PY
  4. Paste the following content into it:
"""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"},
    }
  1. Open configuration. yaml
  2. add the following lines:
zha:
  enable_quirks: true
  custom_quirks_path: /config/custom_zha_quirks
  1. remove the HUE module from you devices;
  2. Restart home assistant;
  3. Go back to devices. Right now alle names mentioned in this topic should be visible.
  4. follow the steps in this blog post: Make the Philips Hue wall switch module work with push button switches in Home Assistant — Rudd-O.com
  5. please note:
  • Select in Cluster: PhilipsBasicCluster << should be available now
  • Attributes: MODE (ID: 0x0034) << should be avaible now
  • Value: enter 2. This value enables a double rocker switch

  1. NOW WAIT
  2. if i’m correct one of the two switches is working, or at lease it should be. You can see it in the log of the device. Figure out which one is working.
  3. Now before you click “write attribute” you first click the button that is working. This wakes up the device. If you don’t do this, HA/Zigbee can’t communicate with the device.
  4. Within half a second after you clicked the button of the device to wake it up, you press write.

All done, you have two rocker type buttons working perfectly.

I’m using NODE RED, which makes it easy to separate the buttons based on action and ID.

2 Likes