Hue dimmer switch in Node-RED
March 30th, 2020
Introduction

Have you been looking for a way to connect your hue dimmer switch with home assistant look no further.

Functions of the flow is the following:

  1. Turn on/off lights on the normal on/off buttons.

  2. Increase light from off state.

  3. Increase and dim lights by holding down either of the brightness buttons. Releasing a button will stop the increasement/dimming.

  4. Single push brightness buttons for increasing and dimming in steps.

  5. All transitions wil increase and dim lights smoothly.

  6. When the light is on but not full brightness a single push on the on button will change the light to full brightness.

The flow is pretty simple due to all the functions of the hue switch are programmed into the function node.

Start with a "MQTT in" node of your switch and drag it directly to the function node.

When holding down the brightness buttons the function node will direct traffic down to the loop for a safety stop when the light reaches full or minimum brightness state.

Be aware that you should change your light source in the function node. The first line var entity = 'light.all_lights'; defines what light should be controlled. Change "light.all_lights" to your light.

The Code

See the code of the function node below.

var entity = 'light.all_lights';
var interval = 30;
const globalHomeAssistant = global.get('homeassistant');
var brightness = globalHomeAssistant.homeAssistant.states[entity].attributes.brightness || 0;
var state = globalHomeAssistant.homeAssistant.states[entity].state;
var delay = 500;
flow.set('press', false);
if (!msg.payload.hasOwnProperty('action')) msg.payload.action = "";
var newMsg = { payload: {} };
if ( msg.payload.action == "on-press" ) {
if ( state == "on" && brightness > 0 ) {
newMsg.payload = {
domain: 'light',
service: 'turn_on',
data: { entity_id: entity, brightness: 255, transition: 1 }
};
} else {
newMsg.payload = {
domain: 'light',
service: 'turn_on',
data: { entity_id: entity }
};
}
}
if ( msg.payload.action == "up-press" ) {
if (brightness < 255) {
newMsg.payload = {
domain: 'light',
service: 'turn_on',
data: { entity_id: entity, brightness: brightness + interval, transition: 1 }
};
} else { return null; }
}
if ( msg.payload.action == "down-press" ) {
if (brightness > 0) {
newMsg.payload = {
domain: 'light',
service: 'turn_on',
data: { entity_id: entity, brightness: brightness - interval, transition: 1 }
};
} else { return null; }
}
if ( msg.payload.action == "up-hold" ) {
flow.set('press', true);
if ( brightness < 255 ) {
newMsg.payload = {
domain: 'light',
service: 'turn_on',
data: { entity_id: entity, brightness: brightness + interval, transition: 1 }
};
} else {
flow.set('press', false);
return null
}
}
if ( msg.payload.action == "down-hold" ) {
flow.set('press', true);
if ( brightness > 0 ) {
newMsg.payload = {
domain: 'light',
service: 'turn_on',
data: { entity_id: entity, brightness: brightness - interval, transition: 1 }
};
} else {
flow.set('press', false);
return null
}
}
if ( msg.payload.action == "up-hold-release" ) {
flow.set('press', false)
return null;
}
if ( msg.payload.action == "down-hold-release" ) {
flow.set('press', false)
if ( brightness <= 0 ) {
newMsg.payload = {
domain: 'light',
service: 'turn_off',
data: { entity_id: entity }
};
} else {
return null;
}
}
if ( msg.payload.action == "off-press" ) {
newMsg.payload = {
domain: 'light',
service: 'turn_off',
data: { entity_id: entity }
};
}
if ( msg.payload.action === "" ) {
return null;
}
return [newMsg, msg]

Node Setup

The delay node sets a delay for 500 miliseconds. This is necessary due to the latency needed for the lights to receive commands.

The control node ensures to stop the loop when the function node changes 'press' to false.

As described above the call service node will receive inputs from the function node and should therefore be empty.

Node-RED full flow code

For inserting the full flow copy the code below and import it in Node-RED

[{"id":"9069f94d.ffe9b8","type":"function","z":"a07c8357.c7315","name":"Switch","func":"var entity = 'light.all_lights';\nvar interval = 30;\n/*\nfunction name(parameter1, parameter2, parameter3) {\n // code to be executed\n}\n*/\n\nconst globalHomeAssistant = global.get('homeassistant');\nvar brightness = globalHomeAssistant.homeAssistant.states[entity].attributes.brightness || 0;\nvar state = globalHomeAssistant.homeAssistant.states[entity].state;\nvar delay = 500;\nflow.set('press', false);\n\nif (!msg.payload.hasOwnProperty('action')) msg.payload.action = \"\";\nvar newMsg = { payload: {} };\n\nif ( msg.payload.action == \"on-press\" ) {\n if ( state == \"on\" && brightness > 0 ) {\n newMsg.payload = {\n domain: 'light',\n service: 'turn_on',\n data: { entity_id: entity, brightness: 255, transition: 1 }\n }; \n } else {\n newMsg.payload = {\n domain: 'light',\n service: 'turn_on',\n data: { entity_id: entity }\n };\n }\n}\n\nif ( msg.payload.action == \"up-press\" ) {\n if (brightness < 255) {\n newMsg.payload = {\n domain: 'light',\n service: 'turn_on',\n data: { entity_id: entity, brightness: brightness + interval, transition: 1 }\n };\n \n } else { return null; }\n}\n\nif ( msg.payload.action == \"down-press\" ) {\n if (brightness > 0) {\n newMsg.payload = {\n domain: 'light',\n service: 'turn_on',\n data: { entity_id: entity, brightness: brightness - interval, transition: 1 }\n };\n } else { return null; }\n}\n\nif ( msg.payload.action == \"up-hold\" ) {\n flow.set('press', true);\n if ( brightness < 255 ) {\n newMsg.payload = {\n domain: 'light',\n service: 'turn_on',\n data: { entity_id: entity, brightness: brightness + interval, transition: 1 }\n };\n } else { \n flow.set('press', false);\n return null\n }\n}\n\nif ( msg.payload.action == \"down-hold\" ) {\n flow.set('press', true);\n if ( brightness > 0 ) {\n newMsg.payload = {\n domain: 'light',\n service: 'turn_on',\n data: { entity_id: entity, brightness: brightness - interval, transition: 1 }\n };\n } else {\n flow.set('press', false);\n return null\n }\n}\n\nif ( msg.payload.action == \"up-hold-release\" ) {\n flow.set('press', false)\n return null;\n}\n\nif ( msg.payload.action == \"down-hold-release\" ) {\n flow.set('press', false)\n if ( brightness <= 0 ) {\n newMsg.payload = {\n domain: 'light',\n service: 'turn_off',\n data: { entity_id: entity }\n };\n } else {\n return null;\n }\n}\n\nif ( msg.payload.action == \"off-press\" ) {\n newMsg.payload = {\n domain: 'light',\n service: 'turn_off',\n data: { entity_id: entity }\n \n };\n}\n\nif ( msg.payload.action === \"\" ) {\n return null;\n}\n\nreturn [newMsg, msg]","outputs":2,"noerr":0,"x":550,"y":280,"wires":[["671b8bfa.fe1e3c"],["54473fa6.2c70c8"]]},{"id":"6e8e13da.ff21b4","type":"mqtt in","z":"a07c8357.c7315","name":"Main switch hallway","topic":"zigbee2mqtt/main_switch_hallway","qos":"0","datatype":"json","broker":"4bc5a1d3.d944b","x":290,"y":280,"wires":[["9069f94d.ffe9b8"]]},{"id":"95558611.6079f","type":"switch","z":"a07c8357.c7315","name":"Control","property":"press","propertyType":"flow","rules":[{"t":"eq","v":"true","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":620,"y":320,"wires":[["9069f94d.ffe9b8"]]},{"id":"54473fa6.2c70c8","type":"delay","z":"a07c8357.c7315","name":"Delay","pauseType":"delay","timeout":"500","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":470,"y":320,"wires":[["95558611.6079f"]]},{"id":"671b8bfa.fe1e3c","type":"api-call-service","z":"a07c8357.c7315","name":"Light","server":"f0d170ea.f39ad","version":1,"debugenabled":false,"service_domain":"","service":"","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":810,"y":280,"wires":[[]]},{"id":"4bc5a1d3.d944b","type":"mqtt-broker","z":"","name":"MQTT Server","broker":"192.168.1.63","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":""},{"id":"f0d170ea.f39ad","type":"server","z":"","name":"Home Assistant","addon":true}]