Skip to content

Instantly share code, notes, and snippets.

@robertsLando
Last active May 6, 2023 08:58
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robertsLando/41ae75dbfbe6465d5cf40248e2500e0a to your computer and use it in GitHub Desktop.
Save robertsLando/41ae75dbfbe6465d5cf40248e2500e0a to your computer and use it in GitHub Desktop.
Z-Wave Control Panel with node-red-dashboard
[{"id":"c8fe91b8.daa3","type":"tab","label":"Flow 2"},{"id":"5b1e3f38.50856","type":"zwave-in","z":"c8fe91b8.daa3","name":"read_zwave","controller":"93bf10ea.1c4c3","x":194,"y":180,"wires":[["ee5ce307.9c417","c46bb234.40dcc"]]},{"id":"c46bb234.40dcc","type":"debug","z":"c8fe91b8.daa3","name":"","active":false,"console":"false","complete":"false","x":416,"y":74,"wires":[]},{"id":"ee5ce307.9c417","type":"switch","z":"c8fe91b8.daa3","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"zwave: driver ready","vt":"str"},{"t":"eq","v":"zwave: node added","vt":"str"},{"t":"eq","v":"zwave: value added","vt":"str"},{"t":"eq","v":"zwave: notification","vt":"str"},{"t":"eq","v":"zwave: value changed","vt":"str"},{"t":"eq","v":"zwave: node ready","vt":"str"},{"t":"eq","v":"zwave: scan complete","vt":"str"}],"checkall":"true","outputs":7,"x":455,"y":180,"wires":[["2bbed007.b1598"],["f439bf74.64e93"],["5dd0df27.0fddb"],["c1c7ad30.1fe2"],["1000fdaf.d177e2"],["592813f3.15708c"],["b9cbd4d9.694eb8"]]},{"id":"2bbed007.b1598","type":"function","z":"c8fe91b8.daa3","name":"init nodes","func":"flow.set(\"nodes\", []);\nflow.set(\"scanComplete\", false);\n\n","outputs":"0","noerr":0,"x":698,"y":77,"wires":[]},{"id":"f439bf74.64e93","type":"function","z":"c8fe91b8.daa3","name":"add node","func":"var nodes = flow.get(\"nodes\");\nmsg.payload.values = [];\nmsg.payload.ready = false;\n\nnodes.push(msg.payload);\n\n","outputs":"0","noerr":0,"x":697,"y":111,"wires":[]},{"id":"5dd0df27.0fddb","type":"function","z":"c8fe91b8.daa3","name":"add value to node","func":"var nodes = flow.get(\"nodes\");\n\nvar n = nodes.find(n => n.nodeid == msg.payload.nodeid);\n\nvar value = msg.payload.value;\n\nn.values.push(value);\n\n//optionally send enablepool \nif(value.label == \"Temperature\"){\n node.send({topic: \"enablePool\", payload: {\"args\": [value.nodeid, value.cmdclass]}});\n}\n\n\n","outputs":"1","noerr":0,"x":727,"y":147,"wires":[[]]},{"id":"c1c7ad30.1fe2","type":"function","z":"c8fe91b8.daa3","name":"notification","func":"var nodes = flow.get(\"nodes\");\nvar nodeid = msg.payload.nodeid;\nvar n = nodes.find(n => n.nodeid == nodeid);\n\nswitch (msg.payload.notification) {\n case 0:\n console.log('node%d: message complete', nodeid);\n break;\n case 1:\n console.log('node%d: timeout', nodeid);\n break;\n case 2:\n console.log('node%d: nop', nodeid);\n break;\n case 3:\n console.log('node%d: node awake', nodeid);\n break;\n case 4:\n console.log('node%d: node sleep', nodeid);\n break;\n case 5:\n console.log('node%d: node dead', nodeid);\n n.ready = false;\n node.send({topic: \"node_status\", nodeid: nodeid, payload: false});\n break;\n case 6:\n console.log('node%d: node alive', nodeid);\n n.ready = true;\n node.send({topic: \"node_status\", nodeid: nodeid, payload: true});\n break;\n }\n","outputs":1,"noerr":0,"x":705,"y":186,"wires":[[]]},{"id":"1000fdaf.d177e2","type":"function","z":"c8fe91b8.daa3","name":"value changed","func":"var nodes = flow.get(\"nodes\");\n\nvar node = nodes.find(n => n.nodeid == msg.payload.nodeid);\n\nvar value = node.values.find(v => v.value_id == msg.payload.value.value_id);\n\nvalue.value = msg.payload.value.value;\n\n\nmsg.payload = value;\nmsg.topic = \"value_changed\";\n\nreturn msg;","outputs":"1","noerr":0,"x":713,"y":227,"wires":[["3c7afb39.71dd74"]]},{"id":"592813f3.15708c","type":"function","z":"c8fe91b8.daa3","name":"node ready","func":"var nodes = flow.get(\"nodes\");\n\nvar n = nodes.find(n => n.nodeid == msg.payload.nodeid);\n\nn.ready = true;\nn.type = msg.payload.nodeinfo.type;\n\n/* NODEINFO\n{\"manufacturer\":\"Qubino\",\"manufacturerid\":\"0x0159\",\"product\":\"ZMNHKDx Flush Heat and Cool thermostat\",\"producttype\":\"0x0005\",\"productid\":\"0x0052\",\"type\":\"Thermostat HVAC\",\"name\":\"\",\"loc\":\"\"}\n*/","outputs":"0","noerr":0,"x":705,"y":266,"wires":[]},{"id":"b9cbd4d9.694eb8","type":"function","z":"c8fe91b8.daa3","name":"scan complete","func":"var nodes = flow.get(\"nodes\");\n\nflow.set(\"scanComplete\", true);\n\nreturn [{payload:{}, topic: \"writeConfig\"}, {payload: nodes, topic: \"init\"}];","outputs":"2","noerr":0,"x":714,"y":304,"wires":[[],[]]},{"id":"cd817b4e.3f49b8","type":"link in","z":"c8fe91b8.daa3","name":"zwaveWrite","links":["59251ba3.b3c2b4","bea6132.04aacf","177b2fe1.737a1"],"x":975,"y":480,"wires":[["47d342b5.7563cc"]]},{"id":"47d342b5.7563cc","type":"zwave-out","z":"c8fe91b8.daa3","name":"write","controller":"93bf10ea.1c4c3","x":1090,"y":480,"wires":[[]]},{"id":"d2183a6d.1b43e8","type":"ui_dropdown","z":"c8fe91b8.daa3","name":"","label":"Nodes","place":"Select a node","group":"91eff83b.4842a8","order":0,"width":0,"height":0,"passthru":false,"options":[{"label":"","value":"","type":"str"}],"payload":"","topic":"","x":340,"y":480,"wires":[["84c3d05.479453"]]},{"id":"59fc0fa2.398dc","type":"function","z":"c8fe91b8.daa3","name":"parse options","func":"var nodes = msg.payload;\nvar options = [];\n\nfor(var i=0;i<nodes.length; i++){\n var n = nodes[i];\n var tmp = {};\n var title = n.nodeid +\": \"+n.type;\n tmp[title] = n.nodeid;\n options.push(tmp);\n}\n\nmsg.options = options;\n\nreturn msg;","outputs":1,"noerr":0,"x":160,"y":480,"wires":[["d2183a6d.1b43e8"]]},{"id":"84c3d05.479453","type":"function","z":"c8fe91b8.daa3","name":"","func":"var n = flow.get(\"nodes\").find(n => n.nodeid == msg.payload);\n\nmsg.payload = n.values;\n\nmsg.topic = \"init\";\n\nreturn msg;","outputs":1,"noerr":0,"x":485,"y":480,"wires":[["a9ba8c06.0593c"]]},{"id":"a9ba8c06.0593c","type":"ui_template","z":"c8fe91b8.daa3","group":"d8a503ba.8c0ad","name":"config","order":0,"width":"20","height":"20","format":"<style>\nmd-tooltip .md-content {\n height: auto !important;\n max-width: 200px !important;\n font-size: 13px !important;\n}\n\nmd-tooltip {\n height: auto !important;\n max-width: 200px !important;\n font-size: 13px !important;\n overflow: visible !important;\n white-space: normal !important;\n}\n\nmd-tooltip ._md-content {\n height: auto !important;\n max-width: 200px !important;\n font-size: 13px !important;\n}\n</style>\n\n<div ng-repeat=\"v in values\">\n <label>\n {{v.label}}\n <md-tooltip ng-if=\"v.help\" md-direction=\"right\">{{v.help}}</md-tooltip>\n <select ng-if=\"v.values\" id=\"{{v.value_id}}\" ng-model=\"v.value\" ng-change=\"updateValue(v)\" ng-options=\"value as value for (key , value) in v.values\">\n </select>\n <div ng-if=\"!v.values\">\n <input type=\"text\" id=\"{{v.value_id}}\" ng-model=\"v.value\" ng-disabled=\"v.read_only\">\n <button ng-if=\"!v.read_only\" ng-click=\"updateValue(v)\">Submit</button>\n </div>\n </label>\n</div>\n\n<script>\n(function(scope) {\n \n scope.values = [];\n scope.send({topic:\"load\"});\n \n scope.updateValue = function(v){\n var newValue = $('#'+v.value_id).val();\n if(v.values) newValue = newValue.split(':')[1];\n var cmd = {};\n cmd.nodeid = v.node_id;\n cmd.cmdclass = v.class_id;\n cmd.instance = v.instance;\n cmd.cmdidx = v.index;\n cmd.value = newValue;\n v.value = \"\"; //to check updating\n scope.send({payload: cmd, topic: \"setValue\"});\n }\n \n scope.$watch('msg', function (msg) { \n if(msg){\n switch(msg.topic){\n case \"init\":\n if(scope.values.length == 0)\n scope.values = msg.payload;\n break;\n case \"value_changed\":\n var value = scope.values.find(n => n.value_id == msg.payload.value_id);\n if(value)\n value.value = msg.payload.value;\n break;\n }\n }\n }); \n\n})(scope);\n\n\n</script>\n","storeOutMessages":false,"fwdInMessages":false,"templateScope":"local","x":625,"y":480,"wires":[["30212724.e08828"]]},{"id":"30212724.e08828","type":"switch","z":"c8fe91b8.daa3","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"setValue","vt":"str"},{"t":"eq","v":"load","vt":"str"}],"checkall":"true","outputs":2,"x":767,"y":480,"wires":[["59251ba3.b3c2b4"],["85f1bb2a.ed8278"]]},{"id":"59251ba3.b3c2b4","type":"link out","z":"c8fe91b8.daa3","name":"writeConfig","links":["cd817b4e.3f49b8"],"x":876,"y":480,"wires":[]},{"id":"a7c360ff.c8e3","type":"link in","z":"c8fe91b8.daa3","name":"configs","links":["3c7afb39.71dd74"],"x":565,"y":420,"wires":[["a9ba8c06.0593c"]]},{"id":"85f1bb2a.ed8278","type":"change","z":"c8fe91b8.daa3","name":"load","rules":[{"t":"set","p":"payload","pt":"msg","to":"nodes","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":480,"y":560,"wires":[["59fc0fa2.398dc"]]},{"id":"3c7afb39.71dd74","type":"link out","z":"c8fe91b8.daa3","name":"value_changed","links":["a7c360ff.c8e3"],"x":857,"y":227,"wires":[]},{"id":"185c5e39.6f0d12","type":"inject","z":"c8fe91b8.daa3","name":"","topic":"","payload":"nodes","payloadType":"flow","repeat":"","crontab":"","once":false,"x":120,"y":280,"wires":[["589071d.12e7d9"]]},{"id":"589071d.12e7d9","type":"debug","z":"c8fe91b8.daa3","name":"","active":true,"console":"false","complete":"false","x":305,"y":280,"wires":[]},{"id":"8afcb2c1.c6946","type":"inject","z":"c8fe91b8.daa3","name":"healNetwork","topic":"healNetwork","payload":"{}","payloadType":"json","repeat":"","crontab":"","once":false,"x":132,"y":327,"wires":[["bea6132.04aacf"]]},{"id":"bea6132.04aacf","type":"link out","z":"c8fe91b8.daa3","name":"healNetwork","links":["cd817b4e.3f49b8"],"x":282,"y":327,"wires":[]},{"id":"171a9cd4.bb6a53","type":"inject","z":"c8fe91b8.daa3","name":"softReset","topic":"softReset","payload":"{}","payloadType":"json","repeat":"","crontab":"","once":false,"x":120,"y":371,"wires":[["177b2fe1.737a1"]]},{"id":"177b2fe1.737a1","type":"link out","z":"c8fe91b8.daa3","name":"softReset","links":["cd817b4e.3f49b8"],"x":281,"y":371,"wires":[]},{"id":"93bf10ea.1c4c3","type":"zwave-controller","z":"","port":"/dev/ttyACM0","driverattempts":"3","pollinterval":"10000","allowunreadyupdates":false,"logging":"full"},{"id":"91eff83b.4842a8","type":"ui_group","z":"","name":"Seleziona nodo","tab":"f990693c.63b0e8","disp":true,"width":"6"},{"id":"d8a503ba.8c0ad","type":"ui_group","z":"","name":"Config","tab":"f990693c.63b0e8","disp":true,"width":"20"},{"id":"f990693c.63b0e8","type":"ui_tab","z":"","name":"Configurazione","icon":"dashboard"}]
@robertsLando
Copy link
Author

If someone is interested in a zwave control panel nodeJS based that also works as zwave to MQTT gateway check my proejct: Zwave2MQTT

@HubertusH
Copy link

very nice flow! is it posible to show the parameter ID in the node's config? So we can found the right parameter from the tec. spec.
Thank you.

@robertsLando
Copy link
Author

robertsLando commented Apr 29, 2020 via email

@HubertusH
Copy link

HubertusH commented May 1, 2020 via email

@robertsLando
Copy link
Author

robertsLando commented May 1, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment