new node-red-contrib-mysensors out
-
I have worked on the node-red modules for mysensors. And have now released version 1.0.2
It now have the possibility to encode into mysensors compatible mqtt topics, the mysdecenc is also split into two separate nodes now called encode / decode. The old mysdecenc is kept for now, for compatibility reasons, but it will be removed in the future.
Also thanks to @gn0st1c for a couple of pull requests, updating the sensor value list to mysensors 2.x, among other things
the nodes can as always be found here https://www.npmjs.com/package/node-red-contrib-mysensors / https://github.com/tbowmo/node-red-contrib-mysensors
-
As an example, of using the mysensors nodes, here is my current "main" flow, converting mysensors serial protocol to / from MQTT..
The goal is to switch domoticz to run with mqtt at some point in time, and then skip the domoticz <-> mqtt transformation steps. Or even skip domoticz completely, as I only use it for some automation scripts in LUA. All graphing etc. is handled by influxdb / grafana instead. But right now I am leaving domoticz untouched to keep the WAF as high as possible
[ { "id": "2257718.fdda88e", "type": "subflow", "name": "Energy meter", "info": "Converts input from arduino sketch, to a \nMysensors compatible protocol format, usable\nfor injecting into the message stream from\nnormal Mysensors nodes\n\nOutputs data as nodeId 99.", "in": [], "out": [ { "x": 1320, "y": 220, "wires": [ { "id": "11f1e54.721221b", "port": 0 }, { "id": "f9b89df5.06476", "port": 0 }, { "id": "1dcfb48.fe2304c", "port": 0 }, { "id": "f8477377.66ad", "port": 0 }, { "id": "985078ce.c384e8", "port": 0 } ] } ] }, { "id": "12db17ce.ed24e8", "type": "serial in", "z": "2257718.fdda88e", "name": "Meter input", "serial": "acfe3226.5301d", "x": 160, "y": 200, "wires": [ [ "e56f30b7.1a90d" ] ] }, { "id": "1dcfb48.fe2304c", "type": "mysencap", "z": "2257718.fdda88e", "name": "", "nodeid": "99", "childid": "1", "subtype": "17", "internal": "0", "ack": false, "msgtype": "1", "presentation": false, "presentationtype": "13", "presentationtext": "Watt", "fullpresentation": false, "firmwarename": "", "firmwareversion": "", "x": 620, "y": 160, "wires": [ [] ] }, { "id": "f9b89df5.06476", "type": "mysencap", "z": "2257718.fdda88e", "name": "V_KWH node 99", "nodeid": "99", "childid": "1", "subtype": "18", "internal": "0", "ack": false, "msgtype": "1", "presentation": true, "presentationtype": "13", "presentationtext": "Kwh", "fullpresentation": true, "firmwarename": "MeterNode", "firmwareversion": "0.1", "x": 570, "y": 200, "wires": [ [] ] }, { "id": "e56f30b7.1a90d", "type": "function", "z": "2257718.fdda88e", "name": "Split meter data", "func": "var m=msg.payload.split(';');\n// Filtering away unrealistic high usage above 50KW\nif (Number(m[0]) < 50000) {\n var msg1 = {payload:m[0]};\n var msg2 = {payload:m[1]/1000};\n var msg3 = {payload:m[1]};\n return [msg1, msg2, msg3];\n}\n", "outputs": "3", "noerr": 0, "x": 340, "y": 200, "wires": [ [ "1dcfb48.fe2304c" ], [ "f9b89df5.06476" ], [ "dfd92894.2026d8", "11f1e54.721221b" ] ] }, { "id": "dfd92894.2026d8", "type": "file", "z": "2257718.fdda88e", "name": "meter counter output to file", "filename": "/var/tmp/meascache.txt", "appendNewline": true, "createDir": false, "overwriteFile": "true", "x": 480, "y": 300, "wires": [] }, { "id": "11f1e54.721221b", "type": "mysencap", "z": "2257718.fdda88e", "name": "", "nodeid": "99", "childid": "10", "subtype": "24", "internal": 0, "ack": false, "msgtype": "1", "presentation": false, "presentationtype": 0, "presentationtext": "", "fullpresentation": false, "firmwarename": "", "firmwareversion": "", "x": 630, "y": 240, "wires": [ [ "985078ce.c384e8" ] ] }, { "id": "985078ce.c384e8", "type": "function", "z": "2257718.fdda88e", "name": "Watt/Hour calculator", "func": "/* Takes input on subType 24, calculates difference\n from last time, if around 60 seconds have passed\n since last report.\n It passes the value on as subType 17, and\n childSensorId 2 */\n \nif ((Number(msg.subType)===24) && (Number(msg.nodeId)===99)) {\n var uTime = Math.floor(Date.now()/60000);\n var lastTime = context.get('lastTime')||0;\n if (lastTime === 0) {\n context.set('lastTime', uTime);\n context.set('lastCount', Number(msg.payload));\n } else {\n if (uTime != lastTime) {\n lastCount = context.get('lastCount');\n currentCount = Number(msg.payload);\n context.set('lastTime', uTime);\n context.set('lastCount', currentCount)\n msg.subType = 17;\n msg.childSensorId = \"2\";\n msg.payload = currentCount - lastCount;\n return msg;\n }\n }\n}", "outputs": 1, "noerr": 0, "x": 920, "y": 280, "wires": [ [ "693564ba.928f4c" ] ] }, { "id": "f8477377.66ad", "type": "change", "z": "2257718.fdda88e", "name": "", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "payload[0].sum", "tot": "msg" }, { "t": "set", "p": "subType", "pt": "msg", "to": "25", "tot": "num" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1200, "y": 40, "wires": [ [] ] }, { "id": "693564ba.928f4c", "type": "function", "z": "2257718.fdda88e", "name": "create query", "func": "if (msg.nodeId == 99 & msg.subType==17) {\nvar d = new Date();\nd.setHours(0,0,0,0);\nmsg.time = (1 * d.getTime())/1000;\nmsg.time = d.toISOString(); //ISODateString(d);\nmsg.query = \"select sum(value) from electricity where node='99' and sensor='2' and time>'\"+msg.time+\"'\"; //+msg.time;\nreturn msg;\n}\n", "outputs": 1, "noerr": 0, "x": 850, "y": 40, "wires": [ [ "fe2ccdc0.ecce8" ] ] }, { "id": "fe2ccdc0.ecce8", "type": "influxdb in", "z": "2257718.fdda88e", "influxdb": "9d8c74dc.570ca8", "name": "influx lookup", "query": "", "rawOutput": false, "precision": "", "retentionPolicy": "", "x": 1030, "y": 40, "wires": [ [ "f8477377.66ad" ] ] }, { "id": "acfe3226.5301d", "type": "serial-port", "z": "", "serialport": "/dev/ttyUTILITY", "serialbaud": "115200", "databits": "8", "parity": "none", "stopbits": "1", "newline": "\\n", "bin": "false", "out": "char", "addchar": true }, { "id": "9d8c74dc.570ca8", "type": "influxdb", "z": "", "hostname": "influxdb", "port": "8086", "protocol": "http", "database": "utility", "name": "", "usetls": false, "tls": "" }, { "id": "9b272654.9ad688", "type": "subflow", "name": "Influx processing", "info": "", "in": [ { "x": 220, "y": 280, "wires": [ { "id": "55204322.aadfbc" } ] } ], "out": [ { "x": 580, "y": 240, "wires": [ { "id": "55204322.aadfbc", "port": 2 } ] } ] }, { "id": "55204322.aadfbc", "type": "function", "z": "9b272654.9ad688", "name": "Influx conditioner", "func": "msg_env = null;\nmsg_utility = null;\nmsg_debug = null;\nst = msg.subType;\nif (msg.messageType == 1 && (st === 0 || st == 1 || st == 2 || st == 4 || st == 17)) {\n var tags = {};var data = {}\n tags.node = msg.nodeId.toString();\n tags.sensor = msg.childSensorId.toString();\n data.value=parseFloat(msg.payload);\n switch (st) {\n case 0 : type = \"temperature\";break;\n case 1 : type = \"humidity\"; break;\n case 2 : type = \"status\"; break;\n case 4 : type = \"barometer\"; break;\n case 17: type = \"electricity\"; break;\n }\n msg.payload = [data, tags];\n msg.measurement = type;\n msg_debug = msg;\n if (msg.subType==17) \n msg_utility = msg;\n else \n msg_env = msg;\n} \nelse \n msg = null;\nreturn [msg_debug, msg_env, msg_utility];", "outputs": "3", "noerr": 0, "x": 410, "y": 280, "wires": [ [], [ "c042117a.3fbdf" ], [ "f6bdc7dc.77c758" ] ] }, { "id": "c042117a.3fbdf", "type": "influxdb out", "z": "9b272654.9ad688", "influxdb": "a2b7673f.603a98", "name": "", "measurement": "", "precision": "", "retentionPolicy": "", "x": 630, "y": 280, "wires": [] }, { "id": "f6bdc7dc.77c758", "type": "influxdb out", "z": "9b272654.9ad688", "influxdb": "c4892f23.817cc", "name": "Utility", "measurement": "", "precision": "", "retentionPolicy": "", "x": 610, "y": 320, "wires": [] }, { "id": "a2b7673f.603a98", "type": "influxdb", "z": "9b272654.9ad688", "hostname": "influxdb", "port": "8086", "protocol": "http", "database": "environment", "name": "environment", "usetls": false, "tls": "" }, { "id": "c4892f23.817cc", "type": "influxdb", "z": "9b272654.9ad688", "hostname": "influxdb", "port": "8086", "protocol": "http", "database": "utility", "name": "utility", "usetls": false, "tls": "" }, { "id": "4c13992e.b3ec68", "type": "subflow", "name": "Logging filter", "in": [ { "x": 105.5, "y": 240, "wires": [ { "id": "b57b1f3.f4a84e" } ] } ], "out": [ { "x": 600, "y": 260, "wires": [ { "id": "b57b1f3.f4a84e", "port": 1 } ] } ] }, { "id": "b57b1f3.f4a84e", "type": "function", "z": "4c13992e.b3ec68", "name": "Filter battery msg", "func": "var battMsg = null;\nvar debugMsg = null;\nvar sketchMsg = null;\nif (msg.messageType==3) {\n if (msg.subType===0)\n battMsg = msg;\n if (msg.subType==9)\n debugMsg = msg;\n if (msg.subType==11 || msg.subType==12)\n sketchMsg = msg;\n}\n\nreturn [battMsg, debugMsg, sketchMsg];", "outputs": "3", "noerr": 0, "x": 430, "y": 240, "wires": [ [ "d8b91167.2746f", "de0acbaf.dce4e8" ], [], [ "cdd7f2cc.7bf58" ] ] }, { "id": "38f9ab87.c70654", "type": "file", "z": "4c13992e.b3ec68", "name": "Battery log", "filename": "/var/tmp/battlog.txt", "appendNewline": false, "createDir": false, "overwriteFile": "false", "x": 1050, "y": 180, "wires": [] }, { "id": "1b4decbb.e4b213", "type": "function", "z": "4c13992e.b3ec68", "name": "inject date", "func": "var date = new Date();\nvar str = date.getFullYear() + \"-\" + (date.getMonth() + 1) + \"-\" + date.getDate() + \" \" + date.getHours() + \":\" + date.getMinutes() + \":\" + date.getSeconds();\nmsg.payload = str + \" - \" + msg.payload;\nreturn msg;", "outputs": 1, "noerr": 0, "x": 830, "y": 180, "wires": [ [ "38f9ab87.c70654" ] ] }, { "id": "d8b91167.2746f", "type": "function", "z": "4c13992e.b3ec68", "name": "Check batt level", "func": "var date = new Date();\nvar str = date.getFullYear() + \"-\" + (date.getMonth() + 1) + \"-\" + date.getDate() + \" \" + date.getHours() + \":\" + date.getMinutes() + \":\" + date.getSeconds();\nmsg.date = str;\nif (parseInt(msg.payload)<5)\nreturn msg;", "outputs": 1, "noerr": 0, "x": 660, "y": 220, "wires": [ [ "c44e1c28.3bb1e" ] ] }, { "id": "c44e1c28.3bb1e", "type": "template", "z": "4c13992e.b3ec68", "name": "BatLow message", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "{{date}} - Battery level is low on node {{nodeId}} : {{payload}} !", "x": 850, "y": 220, "wires": [ [ "e9231639.16dce8" ] ] }, { "id": "e9231639.16dce8", "type": "twitter out", "z": "4c13992e.b3ec68", "twitter": "", "name": "Tweet", "x": 1030, "y": 220, "wires": [] }, { "id": "b478903e.4b877", "type": "file", "z": "4c13992e.b3ec68", "name": "Presentation log", "filename": "/var/tmp/presentation.txt", "appendNewline": true, "createDir": false, "overwriteFile": "false", "x": 840, "y": 300, "wires": [] }, { "id": "de0acbaf.dce4e8", "type": "mysencode", "z": "4c13992e.b3ec68", "name": "", "mqtt": false, "x": 600, "y": 120, "wires": [ [ "1b4decbb.e4b213" ] ] }, { "id": "cdd7f2cc.7bf58", "type": "mysencode", "z": "4c13992e.b3ec68", "name": "", "mqtt": false, "x": 630, "y": 360, "wires": [ [ "b478903e.4b877" ] ] }, { "id": "bed2e35d.412d2", "type": "subflow", "name": "Domoticz conditioner", "info": "Inverts lockstate for domoticz, as domoticz has inverted the logic in their code, compared to mysensors", "in": [ { "x": 280, "y": 220, "wires": [ { "id": "177ebcf6.1ef483" } ] } ], "out": [ { "x": 1000, "y": 220, "wires": [ { "id": "133a4a4e.e07f06", "port": 0 } ] } ] }, { "id": "126152bf.ed9ead", "type": "function", "z": "bed2e35d.412d2", "name": "Invert lockstate for domoticz", "func": "if (msg.subType == 36) {\n if (msg.payload== \"1\") msg.payload=\"0\";\n else msg.payload=\"1\";\n}\nreturn msg;", "outputs": 1, "noerr": 0, "x": 640, "y": 220, "wires": [ [ "133a4a4e.e07f06" ] ] }, { "id": "177ebcf6.1ef483", "type": "mysdecode", "z": "bed2e35d.412d2", "name": "", "mqtt": false, "x": 400, "y": 280, "wires": [ [ "126152bf.ed9ead" ] ] }, { "id": "133a4a4e.e07f06", "type": "mysencode", "z": "bed2e35d.412d2", "name": "", "mqtt": false, "x": 860, "y": 340, "wires": [ [] ] }, { "id": "67deb464.98214c", "type": "tab", "label": "Mysensors", "disabled": false, "info": "" }, { "id": "5b8bba4c.a47444", "type": "serial in", "z": "67deb464.98214c", "name": "Mysensors NRF", "serial": "821a7286.7de59", "x": 200, "y": 280, "wires": [ [ "8cb827f.b90b8d8", "25982c9c.c32ed4" ] ] }, { "id": "47b5936e.b84a6c", "type": "serial out", "z": "67deb464.98214c", "name": "Mysensors NRF", "serial": "821a7286.7de59", "x": 1000, "y": 160, "wires": [] }, { "id": "4755dfb8.b8aa2", "type": "serial out", "z": "67deb464.98214c", "name": "Domoticz", "serial": "b5105521.4aefa8", "x": 1040, "y": 580, "wires": [] }, { "id": "44592b43.bba6d4", "type": "debug", "z": "67deb464.98214c", "name": "Energy meter output", "active": false, "console": "false", "complete": "true", "x": 720, "y": 340, "wires": [] }, { "id": "9e471178.61b8f", "type": "subflow:bed2e35d.412d2", "z": "67deb464.98214c", "name": "", "x": 420, "y": 680, "wires": [ [ "173aba02.e8c546", "19c64177.e1a11f" ] ] }, { "id": "9bdc2a5b.6423d8", "type": "subflow:bed2e35d.412d2", "z": "67deb464.98214c", "name": "Domoticz out", "x": 850, "y": 580, "wires": [ [ "4755dfb8.b8aa2", "7acdfaa3.794f44" ] ] }, { "id": "9ebb1391.6144f", "type": "debug", "z": "67deb464.98214c", "name": "gw debug", "active": false, "console": "false", "complete": "true", "x": 840, "y": 540, "wires": [] }, { "id": "49c6c17b.b6394", "type": "subflow:4c13992e.b3ec68", "z": "67deb464.98214c", "x": 630, "y": 540, "wires": [ [ "9ebb1391.6144f" ] ] }, { "id": "602db35f.9fd24c", "type": "serial in", "z": "67deb464.98214c", "name": "Domoticz (20)", "serial": "b5105521.4aefa8", "x": 190, "y": 680, "wires": [ [ "9e471178.61b8f" ] ] }, { "id": "173aba02.e8c546", "type": "debug", "z": "67deb464.98214c", "name": "Domoticz in", "active": false, "console": "false", "complete": "payload", "x": 630, "y": 640, "wires": [] }, { "id": "3ff64036.ae116", "type": "subflow:9b272654.9ad688", "z": "67deb464.98214c", "name": "InfluxDB", "x": 620, "y": 500, "wires": [ [ "aec232d3.2860b" ] ] }, { "id": "aec232d3.2860b", "type": "debug", "z": "67deb464.98214c", "name": "", "active": false, "console": "false", "complete": "true", "x": 830, "y": 500, "wires": [] }, { "id": "932ebb67.4968d8", "type": "debug", "z": "67deb464.98214c", "name": "msg_nrf", "active": false, "console": "false", "complete": "payload", "x": 980, "y": 120, "wires": [] }, { "id": "8cb827f.b90b8d8", "type": "debug", "z": "67deb464.98214c", "name": "NRF input", "active": false, "console": "false", "complete": "payload", "x": 420, "y": 240, "wires": [] }, { "id": "ea57b38e.eecb5", "type": "debug", "z": "67deb464.98214c", "name": "", "active": false, "console": "false", "complete": "true", "x": 670, "y": 260, "wires": [] }, { "id": "a3d33992.a66ae8", "type": "debug", "z": "67deb464.98214c", "name": "", "active": false, "console": "false", "complete": "true", "x": 670, "y": 120, "wires": [] }, { "id": "7acdfaa3.794f44", "type": "debug", "z": "67deb464.98214c", "name": "", "active": false, "console": "false", "complete": "false", "x": 1050, "y": 540, "wires": [] }, { "id": "cf80a3d0.be573", "type": "mqtt out", "z": "67deb464.98214c", "name": "mys-out", "topic": "", "qos": "2", "retain": "false", "broker": "4798f2b0.5d747c", "x": 980, "y": 300, "wires": [] }, { "id": "895c5ec3.769fc", "type": "mqtt in", "z": "67deb464.98214c", "name": "", "topic": "mys-out/#", "qos": "2", "broker": "4798f2b0.5d747c", "x": 180, "y": 160, "wires": [ [ "ed4c6e39.bacbd", "c11a5ff7.4e5f1" ] ] }, { "id": "7ec6243f.89990c", "type": "mqtt in", "z": "67deb464.98214c", "name": "", "topic": "mys-in/#", "qos": "2", "broker": "4798f2b0.5d747c", "x": 180, "y": 540, "wires": [ [ "f11a2832.07d9d8" ] ] }, { "id": "a4e0701b.c1765", "type": "debug", "z": "67deb464.98214c", "name": "MQTT out", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "x": 980, "y": 260, "wires": [] }, { "id": "ff440b2.89fc2f8", "type": "subflow:2257718.fdda88e", "z": "67deb464.98214c", "x": 430, "y": 320, "wires": [ [ "44592b43.bba6d4", "7535eff3.37e22" ] ] }, { "id": "25982c9c.c32ed4", "type": "mysdecode", "z": "67deb464.98214c", "name": "", "mqtt": false, "x": 450, "y": 280, "wires": [ [ "ea57b38e.eecb5", "7535eff3.37e22" ] ] }, { "id": "f11a2832.07d9d8", "type": "mysdecode", "z": "67deb464.98214c", "name": "", "mqtt": true, "x": 370, "y": 540, "wires": [ [ "3ff64036.ae116", "49c6c17b.b6394", "8d2cee61.71c6c" ] ] }, { "id": "8d2cee61.71c6c", "type": "mysencode", "z": "67deb464.98214c", "name": "", "mqtt": false, "x": 650, "y": 580, "wires": [ [ "9bdc2a5b.6423d8" ] ] }, { "id": "7535eff3.37e22", "type": "mysencode", "z": "67deb464.98214c", "name": "", "mqtt": true, "mqtttopic": "mys-in", "x": 730, "y": 300, "wires": [ [ "a4e0701b.c1765", "cf80a3d0.be573" ] ] }, { "id": "19c64177.e1a11f", "type": "mysdecode", "z": "67deb464.98214c", "name": "", "mqtt": false, "x": 650, "y": 680, "wires": [ [ "eaa9d1f0.25429" ] ] }, { "id": "ed4c6e39.bacbd", "type": "mysdecode", "z": "67deb464.98214c", "name": "", "mqtt": true, "x": 440, "y": 160, "wires": [ [ "a3d33992.a66ae8", "1d6e96fd.d27aa9" ] ] }, { "id": "1d6e96fd.d27aa9", "type": "mysencode", "z": "67deb464.98214c", "name": "", "mqtt": false, "x": 710, "y": 160, "wires": [ [ "932ebb67.4968d8", "47b5936e.b84a6c" ] ] }, { "id": "7e24cbb9.731f94", "type": "mqtt out", "z": "67deb464.98214c", "name": "", "topic": "", "qos": "2", "retain": "false", "broker": "4798f2b0.5d747c", "x": 1090, "y": 680, "wires": [] }, { "id": "eaa9d1f0.25429", "type": "mysencode", "z": "67deb464.98214c", "name": "", "mqtt": true, "mqtttopic": "mys-out", "x": 890, "y": 680, "wires": [ [ "7e24cbb9.731f94" ] ] }, { "id": "c11a5ff7.4e5f1", "type": "debug", "z": "67deb464.98214c", "name": "", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "topic", "x": 420, "y": 120, "wires": [] }, { "id": "290b0786.992e48", "type": "comment", "z": "67deb464.98214c", "name": "Mysensors Serial <-> MQTT transformation", "info": "", "x": 680, "y": 60, "wires": [] }, { "id": "49126190.1d732", "type": "comment", "z": "67deb464.98214c", "name": "Domoticz (mysensors) <-> MQTT transformation", "info": "", "x": 700, "y": 460, "wires": [] }, { "id": "821a7286.7de59", "type": "serial-port", "z": "", "serialport": "/dev/ttyNRF24", "serialbaud": "115200", "databits": "8", "parity": "none", "stopbits": "1", "newline": "\\n", "bin": "false", "out": "char", "addchar": true }, { "id": "b5105521.4aefa8", "type": "serial-port", "serialport": "/dev/ttyS80", "serialbaud": "115200", "databits": "8", "parity": "none", "stopbits": "1", "newline": "\\n", "bin": "false", "out": "char", "addchar": true }, { "id": "4798f2b0.5d747c", "type": "mqtt-broker", "z": "", "broker": "mosquitto", "port": "1883", "clientid": "nodered-mysensors", "usetls": false, "compatmode": true, "keepalive": "60", "cleansession": true, "willTopic": "", "willQos": "0", "willPayload": "", "birthTopic": "", "birthQos": "0", "birthPayload": "" } ]