Using the Philips Hue Tap Dial Switch with Node-RED

There’s a bunch of people who have posted blueprints to decode the various outputs of the Philips Hue Tap Dial Switch, but for those of who prefer Node-RED for our automations, I thought I’d share a really simple example of how to make this work.

In my case, I’m using a controller for my home theatre amp and TV.

I use ZHA, but first you need to capture the Zigbee event associated with your specific Tap Dial and then decode the ‘keys’. At a high level, it’s simple flow:

The ZHA Events node just listens for any Zigbee messages and the function node operates only on messages from a specific Tap Dial, identified via its MAC address, and then proceeds to map the various Tap Dial messages to some more user friendly messages:

var command = msg.payload.event.command;
var step_mode = msg.payload.event.params.step_mode;
var step_size = msg.payload.event.params.step_size;
var device = msg.payload.event.device_ieee;
var scene_id = msg.payload.event.params.scene_id

// Match specific device
if (device == "00:17:88:07:0d:53:52:dc") {

// Decode wheel
    if (command == "step_with_on_off") {

        msg.step_size = step_size;

        if (step_mode == 0) {
            msg.payload = "wheel_right";
            return [msg];
        }
        if (step_mode == 1) {
            msg.payload = "wheel_left";
            return [msg];
        }
    }

// Decode buttons
    if (command == "recall") {
        if (scene_id == 1) {
            msg.payload = "button_1";
            return [msg];
        }
        if (scene_id == 0) {
            msg.payload = "button_2";
            return [msg];
        }
        if (scene_id == 5) {
            msg.payload = "button_3";
            return [msg];
        }
        if (scene_id == 4) {
            msg.payload = "button_4";
            return [msg];
        }
    }

// Ignore anything else
    msg.payload = "unknown";
    return [msg];
}


The switch node then routes the messages based on which key has been pressed or the direction of the wheel:

While long-click does not appear to be supported, I did play around a little with the wheel output and measure how fast the wheel is being spun to engage a “turbo” mode to increase or decrease the volume on my amp faster. I did this using some Smooth and Trigger nodes.

As a side note, most of this was repurposed from something I set up to use one of the Ikea Tradfir 5-button controls, but the Philips has a way nicer design, feels great and doesn’t seem to have the battery issues of the Ikea control. A definite improvement!

3 Likes

Hi,

I have Home Assistant running ZHA for my Zigbee devices. I now have some Philips Hue Tap and Dials but want to use Node Red isntead of Blueprints.

Thanks for sharing the above info. Would you be able to share your full flow code to get me started?

Many thanks in advance.

Sure, here’s a simple example for controlling my Sonos media player:

[{"id":"74838286f6d294a1","type":"function","z":"363b155f867f60a4","name":"Philips Tap Dial","func":"var command = msg.payload.event.command;\nvar step_mode = msg.payload.event.params.step_mode;\nvar step_size = msg.payload.event.params.step_size;\nvar device = msg.payload.event.device_ieee;\nvar scene_id = msg.payload.event.params.scene_id\n\n// Match specific device\nif (device == \"00:17:99:01:d0:35:21:f0\") {\n\n// Decode wheel\n    if (command == \"step_with_on_off\") {\n\n        msg.step_size = step_size;\n\n        if (step_mode == 0) {\n            msg.payload = \"wheel_right\";\n            return [msg];\n        }\n        if (step_mode == 1) {\n            msg.payload = \"wheel_left\";\n            return [msg];\n        }\n    }\n\n// Decode buttons\n    if (command == \"recall\") {\n        if (scene_id == 1) {\n            msg.payload = \"button_1\";\n            return [msg];\n        }\n        if (scene_id == 0) {\n            msg.payload = \"button_2\";\n            return [msg];\n        }\n        if (scene_id == 5) {\n            msg.payload = \"button_3\";\n            return [msg];\n        }\n        if (scene_id == 4) {\n            msg.payload = \"button_4\";\n            return [msg];\n        }\n    }\n\n// Ignore anything else\n    msg.payload = \"unknown\";\n    return [msg];\n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":420,"y":340,"wires":[["959bccac696fa856"]]},{"id":"959bccac696fa856","type":"switch","z":"363b155f867f60a4","name":"Route on Keys","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"wheel_right","vt":"str"},{"t":"eq","v":"wheel_left","vt":"str"},{"t":"eq","v":"button_1","vt":"str"},{"t":"eq","v":"button_2","vt":"str"},{"t":"eq","v":"button_3","vt":"str"},{"t":"eq","v":"button_4","vt":"str"}],"checkall":"false","repair":false,"outputs":6,"x":640,"y":340,"wires":[["402a11688139dc6f"],["aabf4a0182959ad3"],["f44563f2dca0386b"],["398ee6fa56d803d3","14f88ed8c1f6d347"],["94d9d1c768419941","14f88ed8c1f6d347"],["081aca748b7d9720","14f88ed8c1f6d347"]],"info":"Decode all keys.\r\nLast option (!= unknown) is used to turn system option\r\nregardless of which key is pressed."},{"id":"6d92c191ab4c491a","type":"server-events","z":"363b155f867f60a4","name":"ZHA Events","server":"","version":2,"eventType":"zha_event","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"waitForRunning":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"$outputData(\"eventData\").event_type","valueType":"jsonata"},{"property":"event_type","propertyType":"msg","value":"$outputData(\"eventData\").event_type","valueType":"jsonata"}],"x":210,"y":340,"wires":[["74838286f6d294a1"]]},{"id":"402a11688139dc6f","type":"smooth","z":"363b155f867f60a4","name":"Smooth  Wheel","property":"step_size","action":"mean","count":"5","round":"","mult":"single","reduce":false,"x":900,"y":180,"wires":[["c5d456a0261f9415"]]},{"id":"c5d456a0261f9415","type":"switch","z":"363b155f867f60a4","name":"Rate","property":"step_size","propertyType":"msg","rules":[{"t":"btwn","v":"1","vt":"num","v2":"28","v2t":"num"},{"t":"gte","v":"29","vt":"num"}],"checkall":"false","repair":false,"outputs":2,"x":1110,"y":180,"wires":[["bfd395bf8ba90f68"],["7d176a16a10f2bbf"]]},{"id":"bfd395bf8ba90f68","type":"trigger","z":"363b155f867f60a4","name":"Turbo","op1":"1","op2":"1","op1type":"str","op2type":"str","duration":"150","extend":false,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":1310,"y":140,"wires":[["7d176a16a10f2bbf"]]},{"id":"5d029d886f41cfbb","type":"switch","z":"363b155f867f60a4","name":"Rate","property":"step_size","propertyType":"msg","rules":[{"t":"btwn","v":"0","vt":"num","v2":"28","v2t":"num"},{"t":"gte","v":"29","vt":"num"}],"checkall":"false","repair":false,"outputs":2,"x":1110,"y":240,"wires":[["8e8be3d75ae8c5ad"],["6e85b26c95bde590"]]},{"id":"8e8be3d75ae8c5ad","type":"trigger","z":"363b155f867f60a4","name":"Turbo","op1":"1","op2":"1","op1type":"str","op2type":"str","duration":"150","extend":false,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":1310,"y":220,"wires":[["6e85b26c95bde590"]]},{"id":"aabf4a0182959ad3","type":"smooth","z":"363b155f867f60a4","name":"Smooth  Wheel","property":"step_size","action":"mean","count":"5","round":"","mult":"single","reduce":false,"x":900,"y":240,"wires":[["5d029d886f41cfbb"]]},{"id":"7d176a16a10f2bbf","type":"api-call-service","z":"363b155f867f60a4","name":"Volume Up","server":"","version":5,"debugenabled":false,"domain":"media_player","service":"volume_up","areaId":[],"deviceId":["3e162fec8a7f41cd9fadaa9c8683ee4b"],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1530,"y":160,"wires":[[]]},{"id":"6e85b26c95bde590","type":"api-call-service","z":"363b155f867f60a4","name":"Volume Down","server":"","version":5,"debugenabled":false,"domain":"media_player","service":"volume_down","areaId":[],"deviceId":["3e162fec8a7f41cd9fadaa9c8683ee4b"],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1540,"y":240,"wires":[[]]},{"id":"52da02ce07399143","type":"api-call-service","z":"363b155f867f60a4","name":"Next Track","server":"","version":5,"debugenabled":false,"domain":"media_player","service":"media_next_track","areaId":[],"deviceId":["3e162fec8a7f41cd9fadaa9c8683ee4b"],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1130,"y":440,"wires":[[]]},{"id":"7b9b8d76ab95f84d","type":"api-call-service","z":"363b155f867f60a4","name":"Previous Track","server":"","version":5,"debugenabled":false,"domain":"media_player","service":"media_previous_track","areaId":[],"deviceId":["3e162fec8a7f41cd9fadaa9c8683ee4b"],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1140,"y":500,"wires":[[]]},{"id":"f44563f2dca0386b","type":"api-call-service","z":"363b155f867f60a4","name":"Sonos Play/Pause","server":"","version":5,"debugenabled":false,"domain":"media_player","service":"media_play_pause","areaId":[],"deviceId":["3e162fec8a7f41cd9fadaa9c8683ee4b"],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1150,"y":320,"wires":[[]]},{"id":"bed4d7451f47a1e5","type":"comment","z":"363b155f867f60a4","name":"Sonos - Philips Tapdial Remote","info":"Use this remote to control main floor Sonos.","x":250,"y":240,"wires":[]},{"id":"8ead401db89f55dc","type":"switch","z":"363b155f867f60a4","name":"Toggle Pergola","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":1140,"y":560,"wires":[[]]},{"id":"398ee6fa56d803d3","type":"timed-counter","z":"363b155f867f60a4","name":"Double Click?","timelimit":350,"timeunit":1,"withhold":true,"fixedtimeout":true,"pertopic":false,"x":900,"y":440,"wires":[["52da02ce07399143"]]},{"id":"94d9d1c768419941","type":"timed-counter","z":"363b155f867f60a4","name":"Double Click?","timelimit":350,"timeunit":1,"withhold":true,"fixedtimeout":true,"pertopic":false,"x":900,"y":500,"wires":[["7b9b8d76ab95f84d"]]},{"id":"081aca748b7d9720","type":"timed-counter","z":"363b155f867f60a4","name":"Double Click?","timelimit":350,"timeunit":1,"withhold":true,"fixedtimeout":true,"pertopic":false,"x":900,"y":560,"wires":[["8ead401db89f55dc"]]},{"id":"14f88ed8c1f6d347","type":"api-current-state","z":"363b155f867f60a4","name":"Sonos Idle?","server":"","version":3,"outputs":2,"halt_if":"idle","halt_if_type":"str","halt_if_compare":"is","entity_id":"media_player.living_room","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":890,"y":380,"wires":[["f44563f2dca0386b"],[]],"info":"Let any key start Sonos playing"}]

You would need to change the MAC address in the function node to match your Tapdial, and obviously the service calls to match your devices, but it gives you the general idea.

I’ve made a Node-RED enhancement for the Tap dial that adds double- and triple-click support to the thing.

Check it out!

3 Likes