Skip to content

Instantly share code, notes, and snippets.

@bglnelissen
Last active October 1, 2020 05:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bglnelissen/0e13796852a29cd0b4840ce67a743e3a to your computer and use it in GitHub Desktop.
Save bglnelissen/0e13796852a29cd0b4840ce67a743e3a to your computer and use it in GitHub Desktop.
mqtt and Homekit for Shelly Dimmer

This flow can control the Shelly Dimmer and sets the user interface accordingly.

The flow does multiple things:

  1. It sets the values using Homekit or Node-RED UI and send the mqtt commands.
  2. It listens to the mqtt commands and set the switches and dimmer values in the Home app & Node-RED UI accordingly.
  3. It prevents an infinite loop which seems to be a feature of homekit-service.
  4. You can use the software slider / dimmer.
  5. You can use your light switch (hardware or in the user interface) to change the dimmer level to 4 presets values by doing a on/off/on sequence within 2 seconds.

This flow has some custom javascript because that is my preferred way to handle the message (msg) flow. As you will see, I prefer to set the msg.topic within my function node.

The device in this example is called hanglamp (which is Dutch for ceiling light or hanging lamp). Personally I use a text editor to rename the device in the JSON file to give it a new name. I guess using an inject node could also work.

Let me know if you have improvements.

Have fun,

Bas Nelissen

[
{
"id": "7a868da3.b1a744",
"type": "ui_slider",
"z": "4d2d578e.6cea28",
"name": "hanglamp slider",
"label": "",
"tooltip": "",
"group": "efa9c015.d79758",
"order": 2,
"width": 4,
"height": 1,
"passthru": false,
"outs": "end",
"topic": "shellies/hanglamp/light/0/set",
"min": "0",
"max": "100",
"step": "5",
"x": 1060,
"y": 920,
"wires": [
[
"83e1023e.62b47"
]
]
},
{
"id": "83e1023e.62b47",
"type": "function",
"z": "4d2d578e.6cea28",
"name": "brightness2mqtt",
"func": "brightness = msg.payload;\nmsg.payloadold = msg.payload;\n// set the brightness, turn the light on\nmsg.payload = {\n \"turn\": \"on\",\n \"brightness\": + brightness\n};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 1280,
"y": 920,
"wires": [
[
"ffafc6ee.6ee4d8"
]
]
},
{
"id": "ef232119.ab0b48",
"type": "mqtt in",
"z": "4d2d578e.6cea28",
"name": "hanglamp",
"topic": "shellies/hanglamp/light/0/status",
"qos": "0",
"datatype": "auto",
"broker": "707b233c.d0ad2c",
"x": 170,
"y": 860,
"wires": [
[
"a8896a13.25a638"
]
]
},
{
"id": "d79687d2.b1629",
"type": "function",
"z": "4d2d578e.6cea28",
"name": "prep switch",
"func": "lightOn = msg.payload.ison;\nif (lightOn){\n msg.payload = 'on';\n}else{\n msg.payload = 'off';\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 850,
"y": 860,
"wires": [
[
"e754c3c8.e50cf"
]
]
},
{
"id": "a8896a13.25a638",
"type": "json",
"z": "4d2d578e.6cea28",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 310,
"y": 860,
"wires": [
[
"46614d53.ed2fb4"
]
]
},
{
"id": "b50a4b62.45e34",
"type": "mqtt out",
"z": "4d2d578e.6cea28",
"name": "",
"topic": "",
"qos": "",
"retain": "",
"broker": "707b233c.d0ad2c",
"x": 1450,
"y": 860,
"wires": []
},
{
"id": "ffafc6ee.6ee4d8",
"type": "mqtt out",
"z": "4d2d578e.6cea28",
"name": "",
"topic": "",
"qos": "",
"retain": "",
"broker": "707b233c.d0ad2c",
"x": 1450,
"y": 920,
"wires": []
},
{
"id": "cb558f65.bcf9b",
"type": "homekit-service",
"z": "4d2d578e.6cea28",
"isParent": true,
"bridge": "93e1fd.7adf2e",
"parentService": "",
"name": "hanglamp",
"serviceName": "Lightbulb",
"topic": "",
"filter": false,
"manufacturer": "Default Manufacturer",
"model": "Default Model",
"serialNo": "Default Serial Number",
"cameraConfigVideoProcessor": "ffmpeg",
"cameraConfigSource": "",
"cameraConfigStillImageSource": "",
"cameraConfigMaxStreams": 2,
"cameraConfigMaxWidth": 1280,
"cameraConfigMaxHeight": 720,
"cameraConfigMaxFPS": 10,
"cameraConfigMaxBitrate": 300,
"cameraConfigVideoCodec": "libx264",
"cameraConfigAudioCodec": "libfdk_aac",
"cameraConfigAudio": false,
"cameraConfigPacketSize": 1316,
"cameraConfigVerticalFlip": false,
"cameraConfigHorizontalFlip": false,
"cameraConfigMapVideo": "0:0",
"cameraConfigMapAudio": "0:1",
"cameraConfigVideoFilter": "scale=1280:720",
"cameraConfigAdditionalCommandLine": "-tune zerolatency",
"cameraConfigDebug": false,
"cameraConfigSnapshotOutput": "disabled",
"cameraConfigInterfaceName": "",
"characteristicProperties": "{ \"Brightness\":true }",
"x": 1040,
"y": 980,
"wires": [
[
"385ad340.901afc"
],
[]
]
},
{
"id": "e20da7d6.c777e8",
"type": "function",
"z": "4d2d578e.6cea28",
"name": "prep homekit",
"func": "// set variables known by Homekit\nmsg.prev = msg.payload;\n\nif(msg.prev.ison){\n msg.prev.on = 1;\n}else{\n msg.prev.on = 0;\n}\n\nmsg.payload = {\n \"On\": + msg.prev.on,\n \"Brightness\": + msg.prev.brightness\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 850,
"y": 980,
"wires": [
[
"cb558f65.bcf9b"
]
]
},
{
"id": "e754c3c8.e50cf",
"type": "ui_switch",
"z": "4d2d578e.6cea28",
"name": "",
"label": "hanglamp",
"tooltip": "",
"group": "efa9c015.d79758",
"order": 1,
"width": 2,
"height": 1,
"passthru": false,
"decouple": "true",
"topic": "shellies/hanglamp/light/0/command",
"style": "",
"onvalue": "on",
"onvalueType": "str",
"onicon": "",
"oncolor": "",
"offvalue": "off",
"offvalueType": "str",
"officon": "",
"offcolor": "",
"x": 1040,
"y": 860,
"wires": [
[
"b50a4b62.45e34"
]
]
},
{
"id": "48cb8aa0.e6cfbc",
"type": "mqtt out",
"z": "4d2d578e.6cea28",
"name": "",
"topic": "",
"qos": "",
"retain": "",
"broker": "707b233c.d0ad2c",
"x": 1450,
"y": 980,
"wires": []
},
{
"id": "385ad340.901afc",
"type": "function",
"z": "4d2d578e.6cea28",
"name": "home2mqtt",
"func": "// the message from homekit is either the brightness, or if it is on.\n// when the brightness changes also put the light on\n// when on/off changes, do not change the brightness\n// for anything else just turn it off as a default exit case (which should never happen)\n\nmsg.payloadold = msg.payload;\nmsg.topic = 'shellies/hanglamp/light/0/set';\n\n// set the brightness if it exists\nbrightness = msg.payload.Brightness||false;\n\n\nstatus = msg.payload.On\n\nif(brightness){\n msg.payload = {\n \"turn\": \"on\",\n \"brightness\": + brightness\n }\n}else if(status){\n msg.payload = {\n \"turn\": \"on\"\n }\n}else{\n msg.payload = {\n \"turn\": \"off\"\n }\n}\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 1290,
"y": 980,
"wires": [
[
"48cb8aa0.e6cfbc"
]
]
},
{
"id": "46614d53.ed2fb4",
"type": "function",
"z": "4d2d578e.6cea28",
"name": "loop detection and auto dimmer",
"func": "// B. Nelissen\n// Loop detection and dimmer preperation\n\n// timeouts\nlet msLoopDetection = 100;\nlet msWithinDimming = 2000;\nlet currentTime=Math.round(Date.now());\n\n// setting variables\nlet previousTime=context.get('time') || 0;\nlet previousIson=context.get('ison') || false;\nlet timeDifference=currentTime-previousTime;\n\n// catch loop and exit\nif (msLoopDetection > timeDifference) return;\n\n// dimmer function\nfunction changeBrightness(brightness) {\n var step0 = 5;\n var step1 = 30;\n var step2 = 55;\n var step3 = 100;\n if (!(brightness >= 0 && brightness <= 100)) {\n node.warn('Invalid brightness, set to 42')\n brightness=step1;\n }\n switch (true) {\n case (brightness < step0):\n brightness=step0;\n break;\n case (brightness < step1):\n brightness=step1;\n break;\n case (brightness < step2):\n brightness=step2;\n break;\n case (brightness < step3):\n brightness=step3;\n break;\n default: // when 100\n brightness=step0;\n }\n return brightness;\n}\n\n// dimmer when state goes from OFF to ON\nif(msg.payload.ison && (msg.payload.ison !== previousIson)){\n switch (true) {\n case (msLoopDetection > timeDifference): // loops should be catched already\n msg = null;\n break;\n case (msWithinDimming > timeDifference): // dimmer\n msg.payload.brightness = changeBrightness(msg.payload.brightness)\n break; \n default: //do nothing\n break;\n }\n}\n\ncontext.set('time',currentTime);\ncontext.set('ison',msg.payload.ison);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 530,
"y": 860,
"wires": [
[
"d79687d2.b1629",
"e20da7d6.c777e8",
"fb1435fa.0a159"
]
]
},
{
"id": "fb1435fa.0a159",
"type": "change",
"z": "4d2d578e.6cea28",
"name": "prep brightness",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.brightness",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 860,
"y": 920,
"wires": [
[
"7a868da3.b1a744"
]
]
},
{
"id": "c7c574bf.0c3698",
"type": "inject",
"z": "4d2d578e.6cea28",
"name": "",
"topic": "shellies/hanglamp/light/0/command",
"payload": "on",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 170,
"y": 980,
"wires": [
[
"6406408e.e87808"
]
]
},
{
"id": "61f2fe69.492a88",
"type": "inject",
"z": "4d2d578e.6cea28",
"name": "",
"topic": "shellies/hanglamp/light/0/command",
"payload": "off",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": "1",
"x": 170,
"y": 920,
"wires": [
[
"7455ea6e.a48244"
]
]
},
{
"id": "7455ea6e.a48244",
"type": "mqtt out",
"z": "4d2d578e.6cea28",
"name": "",
"topic": "",
"qos": "",
"retain": "",
"broker": "707b233c.d0ad2c",
"x": 470,
"y": 920,
"wires": []
},
{
"id": "6406408e.e87808",
"type": "mqtt out",
"z": "4d2d578e.6cea28",
"name": "",
"topic": "",
"qos": "",
"retain": "",
"broker": "707b233c.d0ad2c",
"x": 470,
"y": 980,
"wires": []
},
{
"id": "efa9c015.d79758",
"type": "ui_group",
"z": "",
"name": "Woonkamer",
"tab": "f529ddcc.a47f8",
"order": 1,
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "707b233c.d0ad2c",
"type": "mqtt-broker",
"z": "",
"name": "serverPi",
"broker": "localhost",
"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": "93e1fd.7adf2e",
"type": "homekit-bridge",
"z": "",
"bridgeName": "server Home",
"pinCode": "111-11-111",
"port": "",
"allowInsecureRequest": false,
"manufacturer": "server",
"model": "Model",
"serialNo": "Serial Number",
"customMdnsConfig": false,
"mdnsMulticast": true,
"mdnsInterface": "",
"mdnsPort": "",
"mdnsIp": "",
"mdnsTtl": "",
"mdnsLoopback": true,
"mdnsReuseAddr": true,
"allowMessagePassthrough": true
},
{
"id": "f529ddcc.a47f8",
"type": "ui_tab",
"z": "",
"name": "Lichten",
"icon": "dashboard",
"order": 1,
"disabled": false,
"hidden": false
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment