Node-Red as Controller
-
...Will post a full working example when i have everything ready.
Any updates on this please?!
-
I managed to get the following configuration to run:
MySensors --> MySensorsEthernetGateway --> FHEM --> FHEM/MQTTDevice --> Mosquitto--> Node-Red
FHEM and Mosquitto are running an a raspberry.
Running Node-Red on IBM Bluemix in the cloud also succeeded to connect to my local mosquitto broker.
-
@vikasjee I am still working on my own system. Started to learn MongoDb and AngularJS so i am building my own frontend based on node-red as backend.
There is another guy at the node-red maillist that has made a simple "mobile-app" based on node-red with a pure javascript/jquery setup. Check it out here: https://github.com/industrialinternet/Node-red-flows-mobile-web-app
-
@Heinz said:
I managed to get the following configuration to run:
MySensors --> MySensorsEthernetGateway --> FHEM --> FHEM/MQTTDevice --> Mosquitto--> Node-Red
FHEM and Mosquitto are running an a raspberry.
Running Node-Red on IBM Bluemix in the cloud also succeeded to connect to my local mosquitto broker.@Heinz Do you have some code/work/instreuctions to share to get an insight?
-
@vikasjee
Everything is straight forward:- install FHEM on a rapsberry
- add the MYSENSORS gateway to fhem.cfg
define MYSENSOR_Gateway MYSENSORS 192.168.178.20:5003 attr MYSENSOR_Gateway autocreate 1 attr MYSENSOR_Gateway requestAck 1 attr MYSENSOR_Gateway stateFormat connection
- install mosquitto on the raspberry
- add the MQTT device to fhem.cfg (point to local MQTT broker)
define mqtt MQTT 127.0.0.1:1883
- publish sensor data (e.g. MQTT_CO2) from FHEM to MQTT
define MQTT_CO2 MQTT_BRIDGE MYSENSOR_MQ135_CO2 attr MQTT_CO2 IODev mqtt attr MQTT_CO2 publishState fhem/CO2 attr MQTT_CO2 stateFormat transmission-state
Whenever the CO2 value changes it is forwarded to the local mosquitto broker via topic fehm/CO2
Now you any client in the world that has access to the raspberry my subscribe this topic. You simply have to
know the IP address of the MQTT broker.- install Node-Red on the raspberry
- open the Node-Red window of the raspberry <IP>:1883
- drag the MQTT input node to the sheet
- configure the MQTT input node so that it uses the local broker and the topic from above
- drag a debug output node to the sheet
- connect both
- Deploy
--> The CO2 values are printed in the debug window.
The same can be done from within bluemix with the difference that node-red runs in the cloud accessing your local broker in the raspberry.
-
@Heinz Thanks a lot for the details. Actually i am looking out for a confirmation and method/way of using the nodejs controller code in NodeRED somehow (looking out for direct porting or with minimal effort) so that all the functions of a MySensor controller may be made available under NodeRED and hence a NodeRED Controller for MySensor...
This way we may port many other functionalities available as nodejs scripts into NodeRED controller...
Any way forward or a nudge into that direction will also help...
-
I also use node-red with a serial gateway attached. I created a flow that converts the serial payload to a mqtt type payload and it is picked up by openHAB. This also works the other way around. openHAB sents everything out via mqtt and node-red picks it up and parses it back into a serial formated payload which is picked up by the serial gateway. I also use node-red's Owntracks node to monitor my proximity and send updates to openHAB as an mqtt message and I also have a flow that monitors my phone and my wifes phone, if we are both home the outside lights get turned off at 22:00. node-red also sends twitter messages to me when my doors and windows are opened and no one is home.
I only use mqtt with with a combiniation if nfr radios via the serial gateway, like I mentioned above, and I also use ESP8266 modules running lua. So as not to send the wrong payload to the serial gateway, all topics that come from openHAB that are destined for the serial gateway start with RF24SN/out/... and on node-red I subscribe the RF24SN/out/#. This will capture all those message and they will get parsed to the serial format (Nodeid;clientid;message;...etc).
Everything that happens in node-red is passed to openHAB. I have a couple of relays and leds I control from openHAB. The leds use the MySensor LEDDimmer. Basically node-red acts as the middle man between the serial gateway and openHAB/mqtt.
Mike
-
@Fredrik-Carlsson said:
The only thing is that you must point the topic of the mqtt node directly to a child. Its not possible to just subscribe to topics higher in the hierarchy.
For example in MyMQTT app on Android i can just subscribe to topic MyMQTT and then i get messages from all nodes connected to the Gateway. This is not possible with the mqtt node in NodeRED. You must specifically point it.
You can capture all higher level topics by using the # symbal. As I mention above, my openHAB sents RF24SN/out/.... and on node-red I have an mqtt node that listens for RF24SN/out/#.
Mike
-
@Mike-Cayouette thanks, I will try that tomorrow!
-
Here is my setup:
- MyMQTT Client Gateway, OpenHAB, HomeMatic and node-red all connected to mosquitto
- OpenHab configured to expose the internal bus to mosquitto
- All glued together with node-red: the OpenHab Items have no mqtt binding, all messages are exchanged via the OpenHab internal bus.
- Messages from any sensors are transformed in node-red to the destination (topic and payload)
The advantage of this setup is:
- OpenHab is only the GUI and doesn't need to know anything about the sensors
- I can exchange any sensor/actuator without any change in OpenHab. I can even change from a netatmo device to a mysensor device or vice versa.
I was thinking about replacing the MyMQTT Client Gateway with a Serial Gateway and node-red, but the gateway is stable since weeks.... never touch a running system. This would solve my biggest concern with the MyMQTT Client Gateway: it doesn't support encryption....
-
The following node-red sample illustrates how the data sent by the serial gateway can be analysed.
The upper lane receives the data from COM-Port, splits the incomming message into single tokens and feeds the result into
a switch block.
The lower lane implements a http request which displays data for message type "set".
The result of this simple sniffer looks like:
On the top right I added a debug node to visualize the incomming data:
This should be a minimalistic sample to get a feeling for how much work it would take to implement a fully functional controller.
If the "presentation" messages would be fed into some no-sql database like mongoose, answering nodeid-requests shouldn't be a challenging task. In the end I think this could be done in 1-2 days.
-
if anybody wants to try it on his own here is the source which can be imported into node-red.
[{"id":"e2627000.52f61","type":"serial-port","serialport":"COM13","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"10","bin":"false","out":"time","addchar":true},{"id":"ae116278.ceadf","type":"serial in","name":"SerialGateway","serial":"e2627000.52f61","x":75.5,"y":170.3333511352539,"z":"6e87bdcb.1ab8d4","wires":[["421469f9.a974f8"]]},{"id":"421469f9.a974f8","type":"function","name":"split message","func":"var message = msg.payload;\nsplitMessage = message.split(\" \");\nif(splitMessage[0] == \"0;0;3;0;9;read:\")\n{\n msg.route = splitMessage[1].split(\"-\");\n \n var splitData = splitMessage[2].split(\"\\n\");\n var tokens = splitData[1].split(\";\")\n \n msg.rawData = tokens;\n if(tokens.length == 6)\n {\n msg.nodeId = tokens[0];\n msg.childSensorId = tokens[1];\n msg.messageType = tokens[2];\n msg.ack = tokens[3];\n msg.subType = tokens[4];\n msg.payload = tokens[5];\n }\n}\nelse\n{\n \n}\nreturn msg;","outputs":1,"valid":true,"x":260.5,"y":170.3333511352539,"z":"6e87bdcb.1ab8d4","wires":[["ea996599.33b75"]]},{"id":"ea996599.33b75","type":"switch","name":"switch message type","property":"messageType","rules":[{"t":"eq","v":"0"},{"t":"eq","v":"1"},{"t":"eq","v":"2"},{"t":"eq","v":"3"},{"t":"eq","v":"4"}],"checkall":"true","outputs":5,"x":461.49998474121094,"y":170.3333511352539,"z":"6e87bdcb.1ab8d4","wires":[["4bca8505.d463e4"],["cfb87963.3e2a8"],["7cd01fb.f71436"],["e722ad62.22ebd"],["9f4ff922.f54838"]]},{"id":"4bca8505.d463e4","type":"function","name":"presentation","func":"msg.topic = \"presentation\";\nreturn msg;","outputs":1,"valid":true,"x":681.5,"y":37.333335876464844,"z":"6e87bdcb.1ab8d4","wires":[[]]},{"id":"7cd01fb.f71436","type":"function","name":"req","func":"msg.topic = \"req\";\nreturn msg;","outputs":1,"valid":true,"x":698.3333129882812,"y":152.33334350585938,"z":"6e87bdcb.1ab8d4","wires":[[]]},{"id":"e722ad62.22ebd","type":"function","name":"internal","func":"msg.topic = \"internal\";\nreturn msg;","outputs":1,"valid":true,"x":693.3333129882812,"y":203.33334350585938,"z":"6e87bdcb.1ab8d4","wires":[[]]},{"id":"9f4ff922.f54838","type":"function","name":"stream","func":"msg.topic = \"stream\";\nreturn msg;","outputs":1,"valid":true,"x":692.3333129882812,"y":261.3333435058594,"z":"6e87bdcb.1ab8d4","wires":[[]]},{"id":"137f8a82.b7ce45","type":"debug","name":"debug","active":true,"console":"false","complete":"true","x":897.3333129882812,"y":101.33333587646484,"z":"6e87bdcb.1ab8d4","wires":[]},{"id":"ff056cd7.417e98","type":"http response","name":"http out","x":744,"y":444.3333740234375,"z":"6e87bdcb.1ab8d4","wires":[]},{"id":"74b70760.4f808","type":"http in","name":"","url":"/mysensorsdata","method":"get","x":151.00001525878906,"y":444.3333740234375,"z":"6e87bdcb.1ab8d4","wires":[["68713a54.5c30ec"]]},{"id":"e26e1fbf.606c8","type":"template","name":"html template","field":"","format":"html","template":"\nGateway <br />\nreceived at: {{data.timestamp}}<br />\nnode-id: {{data.nodeId}}<br />\nchild-SensorId: {{data.childSensorId}}<br />\nmessageType: {{data.messageType}}<br />\nsubType: {{data.subType}}<br />\npayload: {{data.payload}}\n","x":560.0000152587891,"y":445.33336663246155,"z":"6e87bdcb.1ab8d4","wires":[["ff056cd7.417e98"]]},{"id":"68713a54.5c30ec","type":"function","name":"message buffer","func":"context.data = context.data || new Object();\n\nswitch (msg.topic) {\n case \"set\":\n context.data.timestamp = new Date().toLocaleString();\n context.data.nodeId = msg.nodeId;\n context.data.childSensorId = msg.childSensorId;\n context.data.messageType = msg.messageType;\n context.data.subType = msg.subType;\n context.data.payload = msg.payload;\n msg = null;\n break;\n default:\n \tmsg.data = context.data;\n}\n\nreturn msg;","outputs":1,"valid":true,"x":393.00001525878906,"y":445.3333435058594,"z":"6e87bdcb.1ab8d4","wires":[["e26e1fbf.606c8"]]},{"id":"8f3083f8.2dc96","type":"http in","name":"","url":"/mysensors","method":"get","x":135.00001525878906,"y":507.3333740234375,"z":"6e87bdcb.1ab8d4","wires":[["92f9be8f.e42c68"]]},{"id":"92f9be8f.e42c68","type":"template","name":"Auto Update Script","field":"","template":"<script>\n setInterval(function(){\t\n\t var theUrl = \"http://localhost:1880/mysensorsdata\";\n\t var xmlHttp = new XMLHttpRequest();\n\t xmlHttp.open( \"GET\", theUrl, false );\n\t xmlHttp.send( null );\n\t document. getElementById('mysensorsdata')\n\t \t.innerHTML = xmlHttp.responseText;\n },1000);\n</script>\n<div id = 'mysensorsdata'>\n ... Loading ...\n</div>\n","x":410,"y":507.3333740234375,"z":"6e87bdcb.1ab8d4","wires":[["ff056cd7.417e98"]]},{"id":"cfb87963.3e2a8","type":"function","name":"set","func":"msg.topic = \"set\";\nreturn msg;","outputs":1,"valid":true,"x":696.5,"y":101.33333587646484,"z":"6e87bdcb.1ab8d4","wires":[["137f8a82.b7ce45","68713a54.5c30ec"]]}]
-
where are you storing the sensor data for presentation , stream. let me know which database you are using here? you can have another flows for sending the the request to sensor node via serial port. I tried it same some time back . may be i can share it here.
-
@Heinz ,
Thanks for the flow. kindly post how you have referenced mysensors library for the flow? Split function is spitting out an error as is.
OR Is it required at all?Function Error: TypeError: Cannot call method 'split' of undefined (line 8, col 31)
-
@Dheeraj right now I do not have a database attached as the flow is not finished. I plan to use redis or mongodb.
@vikasjee Indid not reference any mysensors lib in the flow. Split is standard javascript. I wonder why this should not work on your system.
-
@Dheeraj said:
where are you storing the sensor data for presentation , stream. let me know which database you are using here? you can have another flows for sending the the request to sensor node via serial port. I tried it same some time back . may be i can share it here.
@Dheeraj, Will you like to share your way out here?
-
I paused the project as I am working on my low power sensors. As soon as I continue I will post it here.
-
@vikasjee said:
Function Error: TypeError: Cannot call method 'split' of undefined (line 8, col 31)
You need to add an commit to the line 8 like
var tokens = splitData[1].split(";");
I'm getting data at : http://192.168.1.115:1880/mysensorsdata, but the http://192.168.1.115:1880/mysensors don't update.. there is an autoupdate in the flow but it don't work..
-
which browser did you take? Probably you should try another one.
-
I've used NodeRED for various tasks over the years and it still remains my favorite IOT interface. All the while I've tried at least 5 of the officially supported MS controllers out there and nothing has come close! At present I'm trying Home Assistant but am almost ready to give up and set up my own workflow with NodeRED. There's a blog post at https://crankylinuxuser.net/2015/10/01/idiot-crazy-ways-to-make-iot-simple-and-cheap/ that includes a great example of a MySensors+NodeRED flow along with a spot-on critique of mainstream automation services being marketed at present.
The only reason I havent just used NodeRED in the past is it would still require other components to truly make a unified home automation service. An ideal scenario IMHO would be something that uses NodeRED as a front-end with something more unified running it.
-
Here my approach:
[{"id":"ba386057.845d3","type":"mqtt-broker","broker":"192.168.92.4","port":"1883","clientid":"NodeRed"},{"id":"b5e4f17d.4a1b1","type":"function","name":"hanlde internal messages","func":"//msg.subTypeString = \"\";\n//msg.topic = \"internal respones\";\n\nif (msg.subTypeString == 'I_TIME')\n{\n var payload = parseInt(new Date().getTime()/1000);\n\tvar command = context.global.MYS.T_INTERNAL; \n\tvar acknowledge = 0; // no ack\n\tvar type = context.global.MYS.I_TIME; // I_TIME\n\tmsg.payload = encode(msg.nodeId, msg.childSensorId, command, acknowledge, type, payload);\n return msg;\n \n}\nelse if (msg.subTypeString == 'I_ID_REQUEST')\n{\n msg.topic = \"I_ID_RESPONSE\";\n msg.subTypeString = \"I_ID_RESPONSE\";\n // 255;255;3;0;4;8 for ID 8\n var command = context.global.MYS.T_INTERNAL;\n\tvar acknowledge = 0; // no ack\n\tvar type = context.global.MYS.I_ID_RESPONSE; // I_ID_RESPONSE\n\n\tif (context.global.mysnextid[msg.controller] === undefined) {\n\t payload = context.global.MYS.MIN_NODEID;\n\t} \n\telse\n\t{\n\t payload = context.global.mysnextid[msg.controller];\n\t}\n\t\n msg.payload = encode(msg.nodeId, msg.childSensorId, command, acknowledge, type, payload);\n return msg; \n} \nelse if (msg.subTypeString == 'I_INCLUSION_MODE')\n{\n // not yet implemented\n}\n\nreturn;\n\nfunction encode(destination, sensor, command, acknowledge, type, payload) {\n\tvar msg = destination.toString(10) + \";\" + sensor.toString(10) + \";\" + command.toString(10) + \";\" + acknowledge.toString(10) + \";\" + type.toString(10) + \";\";\n\tif (command == 4) {\n\t\tfor (var i = 0; i < payload.length; i++) {\n\t\t\tif (payload[i] < 16)\n\t\t\t\tmsg += \"0\";\n\t\t\tmsg += payload[i].toString(16);\n\t\t}\n\t} else {\n\t\tmsg += payload;\n\t}\n\tmsg += '\\n';\n\treturn msg.toString();\n}\n","outputs":1,"noerr":0,"x":1655.916648864746,"y":536.4166927337646,"z":"9592163f.6a6de8","wires":[["4d15a037.b2ea6","266b87b3.d99478"]]},{"id":"e6ce260d.1931d8","type":"switch","name":"switch message type","property":"messageType","rules":[{"t":"eq","v":"0"},{"t":"eq","v":"1"},{"t":"eq","v":"2"},{"t":"eq","v":"3"},{"t":"eq","v":"4"}],"checkall":"true","outputs":5,"x":1220.166648864746,"y":175.5000171661377,"z":"9592163f.6a6de8","wires":[["8c663d73.7399c"],["4a1e5f84.b5e1a"],["7753f9a2.88ac08"],["1e4aa61b.e1b55a"],["60a0dde4.9f5f24"]]},{"id":"8c663d73.7399c","type":"function","name":"presentation","func":"msg.subTypeString = context.global.MYS.SString(msg.subType);\n\nmsg.topic = context.global.MYS.TOPIC_PREFIX + '/' + msg.controller + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.subTypeString;\n\nreturn msg;","outputs":1,"noerr":0,"x":1449.916648864746,"y":38.2499885559082,"z":"9592163f.6a6de8","wires":[["df9e131d.2061f","4d15a037.b2ea6"]]},{"id":"7753f9a2.88ac08","type":"function","name":"req","func":"msg.topic = \"req\";\nreturn msg;","outputs":1,"noerr":0,"x":1445.5000228881836,"y":175.7500057220459,"z":"9592163f.6a6de8","wires":[["4d15a037.b2ea6"]]},{"id":"1e4aa61b.e1b55a","type":"function","name":"internal","func":"msg.subTypeString = context.global.MYS.IString(msg.subType);\n\nmsg.topic = context.global.MYS.TOPIC_PREFIX + '/' + msg.controller + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.subTypeString;\n\nreturn msg;","outputs":1,"noerr":0,"x":1449.5000228881836,"y":226.0000057220459,"z":"9592163f.6a6de8","wires":[["df9e131d.2061f","4d15a037.b2ea6","b5e4f17d.4a1b1"]]},{"id":"60a0dde4.9f5f24","type":"function","name":"stream","func":"msg.topic = \"stream\";\nreturn msg;","outputs":1,"x":1457.5000228881836,"y":321.0000057220459,"z":"9592163f.6a6de8","wires":[[]]},{"id":"4d15a037.b2ea6","type":"debug","name":"debug","active":true,"console":"false","complete":"true","x":1806.7500267028809,"y":235.00000667572021,"z":"9592163f.6a6de8","wires":[]},{"id":"4a1e5f84.b5e1a","type":"function","name":"set","func":"msg.subTypeString = context.global.MYS.VString(msg.subType);\n\nmsg.topic = context.global.MYS.TOPIC_PREFIX + '/' + msg.controller + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.subTypeString;\n\n\nreturn msg;","outputs":1,"noerr":0,"x":1453.166648864746,"y":100.50000381469727,"z":"9592163f.6a6de8","wires":[["4d15a037.b2ea6","df9e131d.2061f"]]},{"id":"fc54bb91.03ab48","type":"debug","name":"","active":false,"console":"false","complete":"true","x":1179.9166259765625,"y":34.66668891906738,"z":"9592163f.6a6de8","wires":[]},{"id":"6aa2d9f6.955d28","type":"function","name":"Split GW Message","func":"\n var tokens = msg.payload.split(\";\")\n \n msg.rawData = tokens;\n if(tokens.length >= 6)\n {\n msg.nodeId = tokens[0];\n msg.childSensorId = tokens[1];\n msg.messageType = tokens[2];\n msg.ack = tokens[3];\n msg.subType = tokens[4];\n msg.payload = tokens[5];\n for (j=6; j<tokens.length; j++) \n msg.payload = msg.payload + ';' + tokens[j];\n }\n\nreturn msg;","outputs":1,"noerr":0,"x":984.6666488647461,"y":173.66664505004883,"z":"9592163f.6a6de8","wires":[["e6ce260d.1931d8","fc54bb91.03ab48","e0e76d62.1f189"]]},{"id":"df9e131d.2061f","type":"mqtt out","name":"Publish to MQTT","topic":"","qos":"","retain":"","broker":"ba386057.845d3","x":1819.9166526794434,"y":174.1666603088379,"z":"9592163f.6a6de8","wires":[]},{"id":"5f03c10e.a0fc4","type":"tcp request","server":"192.168.92.13","port":"5003","out":"char","splitc":"\\n","name":"MySWifi ESP8266 GW AES 13","x":376.6666946411133,"y":140.1666316986084,"z":"9592163f.6a6de8","wires":[["df1e322.f20e1d"]]},{"id":"e6d67f33.19298","type":"inject","name":"Startup","topic":"","payload":"","payloadType":"none","repeat":"","crontab":"","once":true,"x":106.25,"y":74.41665744781494,"z":"9592163f.6a6de8","wires":[["5f03c10e.a0fc4","64617800.9b9e88","c7d0d88b.382f28","56b9f6ab.a94608"]]},{"id":"ebcef3df.14311","type":"function","name":"ToString","func":"msg.payload = msg.payload.toString().replace(/[\\n\\r]/g, '');\n\nreturn msg;","outputs":1,"noerr":0,"x":790.1666946411133,"y":174.91669178009033,"z":"9592163f.6a6de8","wires":[["6aa2d9f6.955d28"]]},{"id":"31047fa6.cefb8","type":"catch","name":"","x":71,"y":642,"z":"9592163f.6a6de8","wires":[["3622f9b9.c9dd06"]]},{"id":"3622f9b9.c9dd06","type":"debug","name":"","active":false,"console":"false","complete":"true","x":216,"y":642,"z":"9592163f.6a6de8","wires":[]},{"id":"64617800.9b9e88","type":"function","name":"MYS Initialize","func":"function MySHelper() { \n\nMySHelper.prototype.TOPIC_PREFIX = \"MYS-NODERED\";\n\nMySHelper.prototype.MIN_NODEID = 10;\n\n\n// don't touch below :)\n \nMySHelper.prototype.T_PRESENTATION = 0;\nMySHelper.prototype.T_SET = 1;\nMySHelper.prototype.T_REQ = 2;\nMySHelper.prototype.T_INTERNAL = 3;\nMySHelper.prototype.T_STREAM = 4;\n\nMySHelper.prototype.I_BATTERY_LEVEL = 0;\nMySHelper.prototype.I_TIME = 1;\nMySHelper.prototype.I_VERSION = 2;\nMySHelper.prototype.I_ID_REQUEST = 3;\nMySHelper.prototype.I_ID_RESPONSE = 4;\nMySHelper.prototype.I_INCLUSION_MODE = 5;\nMySHelper.prototype.I_CONFIG = 6;\nMySHelper.prototype.I_PING = 7;\nMySHelper.prototype.I_PING_ACK = 8;\nMySHelper.prototype.I_LOG_MESSAGE = 9;\nMySHelper.prototype.I_CHILDREN = 10;\nMySHelper.prototype.I_SKETCH_NAME = 11;\nMySHelper.prototype.I_SKETCH_VERSION = 12;\nMySHelper.prototype.I_REBOOT = 13;\nMySHelper.prototype.I_GATEWAY_READY = 14;\nMySHelper.prototype.I_REQUEST_SIGNING = 15;\nMySHelper.prototype.I_GET_NONCE = 16;\nMySHelper.prototype.I_GET_NONCE_RESPONSE = 17;\nMySHelper.prototype.I_HEARTBEAT = 18;\nMySHelper.prototype.I_PRESENTATION = 19;\n \nvar itype = {\nI_BATTERY_LEVEL: MySHelper.prototype.I_BATTERY_LEVEL,\nI_TIME: MySHelper.prototype.I_TIME,\nI_VERSION: MySHelper.prototype.I_VERSION,\nI_ID_REQUEST: MySHelper.prototype.I_ID_REQUEST,\nI_ID_RESPONSE: MySHelper.prototype.I_ID_RESPONSE,\nI_INCLUSION_MODE: MySHelper.prototype.I_INCLUSION_MODE,\nI_CONFIG: MySHelper.prototype.I_CONFIG,\nI_PING: MySHelper.prototype.I_PING,\nI_PING_ACK: MySHelper.prototype.I_PING_ACK,\nI_LOG_MESSAGE: MySHelper.prototype.I_LOG_MESSAGE,\nI_CHILDREN: MySHelper.prototype.I_CHILDREN,\nI_SKETCH_NAME: MySHelper.prototype.I_SKETCH_NAME,\nI_SKETCH_VERSION: MySHelper.prototype.I_SKETCH_VERSION,\nI_REBOOT: MySHelper.prototype.I_REBOOT,\nI_GATEWAY_READY: MySHelper.prototype.I_GATEWAY_READY,\nI_REQUEST_SIGNING: MySHelper.prototype.I_REQUEST_SIGNING,\nI_GET_NONCE: MySHelper.prototype.I_GET_NONCE,\nI_GET_NONCE_RESPONSE: MySHelper.prototype.I_GET_NONCE_RESPONSE,\nI_HEARTBEAT: MySHelper.prototype.I_HEARTBEAT,\nI_PRESENTATION: MySHelper.prototype.I_PRESENTATION\n};\n\nMySHelper.prototype.IString = function(I_SUBTYPE) {\n for (var prop in itype ) \n if( itype[ prop ] === parseInt(I_SUBTYPE) )\n return prop;\n};\n\nMySHelper.prototype.V_TEMP = 0;\nMySHelper.prototype.V_HUM = 1;\nMySHelper.prototype.V_LIGHT = 2;\nMySHelper.prototype.V_DIMMER = 3;\nMySHelper.prototype.V_PRESSURE = 4;\nMySHelper.prototype.V_FORECAST = 5;\nMySHelper.prototype.V_RAIN = 6;\nMySHelper.prototype.V_RAINRATE = 7;\nMySHelper.prototype.V_WIND = 8;\nMySHelper.prototype.V_GUST = 9;\nMySHelper.prototype.V_DIRECTION = 10;\nMySHelper.prototype.V_UV = 11;\nMySHelper.prototype.V_WEIGHT = 12;\nMySHelper.prototype.V_DISTANCE = 13;\nMySHelper.prototype.V_IMPEDANCE = 14;\nMySHelper.prototype.V_ARMED = 15;\nMySHelper.prototype.V_TRIPPED = 16;\nMySHelper.prototype.V_WATT = 17;\nMySHelper.prototype.V_KWH = 18;\nMySHelper.prototype.V_SCENE_ON = 19;\nMySHelper.prototype.V_SCENE_OFF = 20;\nMySHelper.prototype.V_HEATER = 21;\nMySHelper.prototype.V_HEATER_SW = 22;\nMySHelper.prototype.V_LIGHT_LEVEL = 23;\nMySHelper.prototype.V_VAR1 = 24;\nMySHelper.prototype.V_VAR2 = 25;\nMySHelper.prototype.V_VAR3 = 26;\nMySHelper.prototype.V_VAR4 = 27;\nMySHelper.prototype.V_VAR5 = 28;\nMySHelper.prototype.V_UP = 29;\nMySHelper.prototype.V_DOWN = 30;\nMySHelper.prototype.V_STOP = 31;\nMySHelper.prototype.V_IR_SEND = 32;\nMySHelper.prototype.V_IR_RECEIVE = 33;\nMySHelper.prototype.V_FLOW = 34;\nMySHelper.prototype.V_VOLUME = 35;\nMySHelper.prototype.V_LOCK_STATUS = 36;\nMySHelper.prototype.V_LEVEL = 37; \nMySHelper.prototype.V_VOLTAGE = 38; \nMySHelper.prototype.V_CURRENT = 39; \nMySHelper.prototype.V_RGB = 40; \nMySHelper.prototype.V_RGBW = 41;\nMySHelper.prototype.V_ID = 42;\nMySHelper.prototype.V_UNIT_PREFIX = 43;\nMySHelper.prototype.V_HVAC_SETPOINT_COOL = 44;\nMySHelper.prototype.V_HVAC_SETPOINT_HEAT = 45;\nMySHelper.prototype.V_HVAC_FLOW_MODE = 46;\nMySHelper.prototype.V_TEXT = 47;\n\nvar vtype = {\nV_TEMP: MySHelper.prototype.V_TEMP,\nV_HUM: MySHelper.prototype.V_HUM,\nV_LIGHT: MySHelper.prototype.V_LIGHT,\nV_DIMMER: MySHelper.prototype.V_DIMMER,\nV_PRESSURE: MySHelper.prototype.V_PRESSURE,\nV_FORECAST: MySHelper.prototype.V_FORECAST,\nV_RAIN: MySHelper.prototype.V_RAIN,\nV_RAINRATE: MySHelper.prototype.V_RAINRATE,\nV_WIND: MySHelper.prototype.V_WIND,\nV_GUST: MySHelper.prototype.V_GUST,\nV_DIRECTION: MySHelper.prototype.V_DIRECTION,\nV_UV: MySHelper.prototype.V_UV,\nV_WEIGHT: MySHelper.prototype.V_WEIGHT,\nV_DISTANCE: MySHelper.prototype.V_DISTANCE,\nV_IMPEDANCE: MySHelper.prototype.V_IMPEDANCE,\nV_ARMED: MySHelper.prototype.V_ARMED,\nV_TRIPPED: MySHelper.prototype.V_TRIPPED,\nV_WATT: MySHelper.prototype.V_WATT,\nV_KWH: MySHelper.prototype.V_KWH,\nV_SCENE_ON: MySHelper.prototype.V_SCENE_ON,\nV_SCENE_OFF: MySHelper.prototype.V_SCENE_OFF,\nV_HEATER: MySHelper.prototype.V_HEATER,\nV_HEATER_SW: MySHelper.prototype.V_HEATER_SW,\nV_LIGHT_LEVEL: MySHelper.prototype.V_LIGHT_LEVEL,\nV_VAR1: MySHelper.prototype.V_VAR1,\nV_VAR2: MySHelper.prototype.V_VAR2,\nV_VAR3: MySHelper.prototype.V_VAR3,\nV_VAR4: MySHelper.prototype.V_VAR4,\nV_VAR5: MySHelper.prototype.V_VAR5,\nV_UP: MySHelper.prototype.V_UP,\nV_DOWN: MySHelper.prototype.V_DOWN,\nV_STOP: MySHelper.prototype.V_STOP,\nV_IR_SEND: MySHelper.prototype.V_IR_SEND,\nV_IR_RECEIVE: MySHelper.prototype.V_IR_RECEIVE,\nV_FLOW: MySHelper.prototype.V_FLOW,\nV_VOLUME: MySHelper.prototype.V_VOLUME,\nV_LOCK_STATUS: MySHelper.prototype.V_LOCK_STATUS,\nV_LEVEL: MySHelper.prototype.V_LEVEL,\nV_VOLTAGE: MySHelper.prototype.V_VOLTAGE, \nV_CURRENT: MySHelper.prototype.V_CURRENT,\nV_RGB: MySHelper.prototype.V_RGB,\nV_RGBW: MySHelper.prototype.V_RGBW,\nV_ID: MySHelper.prototype.V_ID,\nV_UNIT_PREFIX: MySHelper.prototype.V_UNIT_PREFIX,\nV_HVAC_SETPOINT_COOL:MySHelper.prototype.V_HVAC_SETPOINT_COOL,\nV_HVAC_SETPOINT_HEAT:MySHelper.prototype.V_HVAC_SETPOINT_HEAT,\nV_HVAC_FLOW_MODE: MySHelper.prototype.V_HVAC_FLOW_MODE,\nV_TEXT: MySHelper.prototype.V_TEXT\n};\n\n\n\nMySHelper.prototype.VString = function(V_SUBTYPE) {\n for (var prop in vtype ) \n if( vtype[ prop ] === parseInt(V_SUBTYPE) )\n return prop;\n};\n \n\nMySHelper.prototype.S_DOOR = 0; // Door sensor; V_TRIPPED; V_ARMED\nMySHelper.prototype.S_MOTION = 1; // Motion sensor; V_TRIPPED; V_ARMED \nMySHelper.prototype.S_SMOKE = 2; // Smoke sensor; V_TRIPPED; V_ARMED\nMySHelper.prototype.S_LIGHT = 3; // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT\nMySHelper.prototype.S_BINARY = 3; // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT (same as MySHelper.prototype.S_LIGHT)\nMySHelper.prototype.S_DIMMER = 4; // Dimmable light or fan device; V_STATUS (on/off); V_DIMMER (dimmer level 0-100); V_WATT\nMySHelper.prototype.S_COVER = 5; // Blinds or window cover; V_UP; V_DOWN; V_STOP; V_DIMMER (open/close to a percentage)\nMySHelper.prototype.S_TEMP = 6; // Temperature sensor; V_TEMP\nMySHelper.prototype.S_HUM = 7; // Humidity sensor; V_HUM\nMySHelper.prototype.S_BARO = 8; // Barometer sensor; V_PRESSURE; V_FORECAST\nMySHelper.prototype.S_WIND = 9; // Wind sensor; V_WIND; V_GUST\nMySHelper.prototype.S_RAIN = 10; // Rain sensor; V_RAIN; V_RAINRATE\nMySHelper.prototype.S_UV = 11; // Uv sensor; V_UV\nMySHelper.prototype.S_WEIGHT = 12; // Personal scale sensor; V_WEIGHT; V_IMPEDANCE\nMySHelper.prototype.S_POWER = 13; // Power meter; V_WATT; V_KWH\nMySHelper.prototype.S_HEATER = 14; // Header device; V_HVAC_SETPOINT_HEAT; V_HVAC_FLOW_STATE; V_TEMP\nMySHelper.prototype.S_DISTANCE = 15; // Distance sensor; V_DISTANCE\nMySHelper.prototype.S_LIGHT_LEVEL = 16; // Light level sensor; V_LIGHT_LEVEL (uncalibrated in percentage); V_LEVEL (light level in lux)\nMySHelper.prototype.S_ARDUINO_NODE = 17 ; // Used (internally) for presenting a non-repeating Arduino node\nMySHelper.prototype.S_ARDUINO_REPEATER_NODE = 18; // Used (internally) for presenting a repeating Arduino node \nMySHelper.prototype.S_LOCK = 19; // Lock device; V_LOCK_STATUS\nMySHelper.prototype.S_IR = 20; // Ir device; V_IR_SEND; V_IR_RECEIVE\nMySHelper.prototype.S_WATER = 21; // Water meter; V_FLOW; V_VOLUME\nMySHelper.prototype.S_AIR_QUALITY = 22; // Air quality sensor; V_LEVEL\nMySHelper.prototype.S_CUSTOM = 23; // Custom sensor \nMySHelper.prototype.S_DUST = 24; // Dust sensor; V_LEVEL\nMySHelper.prototype.S_SCENE_CONTROLLER = 25; // Scene controller device; V_SCENE_ON; V_SCENE_OFF. \nMySHelper.prototype.S_RGB_LIGHT = 26; // RGB light. Send color component data using V_RGB. Also supports V_WATT \nMySHelper.prototype.S_RGBW_LIGHT = 27; // RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT\nMySHelper.prototype.S_COLOR_SENSOR = 28; // Color sensor; send color information using V_RGB\nMySHelper.prototype.S_HVAC = 28; // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT; V_HVAC_SETPOINT_COLD; V_HVAC_FLOW_STATE; V_HVAC_FLOW_MODE; V_TEMP\nMySHelper.prototype.S_MULTIMETER = 29; // Multimeter device; V_VOLTAGE; V_CURRENT; V_IMPEDANCE \nMySHelper.prototype.S_SPRINKLER = 30; // Sprinkler; V_STATUS (turn on/off); V_TRIPPED (if fire detecting device)\nMySHelper.prototype.S_WATER_LEAK = 31; // Water leak sensor; V_TRIPPED; V_ARMED\nMySHelper.prototype.S_SOUND = 32; // Sound sensor; V_TRIPPED; V_ARMED; V_LEVEL (sound level in dB)\nMySHelper.prototype.S_VIBRATION = 33; // Vibration sensor; V_TRIPPED; V_ARMED; V_LEVEL (vibration in Hz)\nMySHelper.prototype.S_MOISTURE = 34; // Moisture sensor; V_TRIPPED; V_ARMED; V_LEVEL (water content or moisture in percentage?) \nMySHelper.prototype.S_INFO = 35; // LCD text device / Simple information device on controller; V_TEXT\nMySHelper.prototype.S_GAS = 36; // Gas meter; V_FLOW; V_VOLUME\nMySHelper.prototype.S_GPS = 37; // GPS Sensor; V_POSITION\n \nvar stype = {\nS_DOOR: MySHelper.prototype.S_DOOR, // Door sensor; V_TRIPPED; V_ARMED\nS_MOTION: MySHelper.prototype.S_MOTION, // Motion sensor; V_TRIPPED; V_ARMED \nS_SMOKE: MySHelper.prototype.S_SMOKE, // Smoke sensor; V_TRIPPED; V_ARMED\nS_LIGHT: MySHelper.prototype.S_LIGHT, // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT\nS_BINARY: MySHelper.prototype.S_BINARY, // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT (same as MySHelper.prototype.S_LIGHT)\nS_DIMMER: MySHelper.prototype.S_DIMMER, // Dimmable light or fan device; V_STATUS (on/off); V_DIMMER (dimmer level 0-100); V_WATT\nS_COVER: MySHelper.prototype.S_COVER, // Blinds or window cover; V_UP; V_DOWN; V_STOP; V_DIMMER (open/close to a percentage)\nS_TEMP: MySHelper.prototype.S_TEMP, // Temperature sensor; V_TEMP\nS_HUM: MySHelper.prototype.S_HUM, // Humidity sensor; V_HUM\nS_BARO: MySHelper.prototype.S_BARO, // Barometer sensor; V_PRESSURE; V_FORECAST\nS_WIND: MySHelper.prototype.S_WIND, // Wind sensor; V_WIND; V_GUST\nS_RAIN: MySHelper.prototype.S_RAIN, // Rain sensor; V_RAIN; V_RAINRATE\nS_UV: MySHelper.prototype.S_UV, // Uv sensor; V_UV\nS_WEIGHT: MySHelper.prototype.S_WEIGHT, // Personal scale sensor; V_WEIGHT; V_IMPEDANCE\nS_POWER: MySHelper.prototype.S_POWER, // Power meter; V_WATT; V_KWH\nS_HEATER: MySHelper.prototype.S_HEATER, // Header device; V_HVAC_SETPOINT_HEAT; V_HVAC_FLOW_STATE; V_TEMP\nS_DISTANCE: MySHelper.prototype.S_DISTANCE, // Distance sensor; V_DISTANCE\nS_LIGHT_LEVEL: MySHelper.prototype.S_LIGHT_LEVEL, // Light level sensor; V_LIGHT_LEVEL (uncalibrated in percentage); V_LEVEL (light level in lux)\nS_ARDUINO_NODE: MySHelper.prototype.S_ARDUINO_NODE, // Used (internally) for presenting a non-repeating Arduino node\nS_ARDUINO_REPEATER_NODE:MySHelper.prototype.S_ARDUINO_REPEATER_NODE, // Used (internally) for presenting a repeating Arduino node \nS_LOCK: MySHelper.prototype.S_LOCK, // Lock device; V_LOCK_STATUS\nS_IR: MySHelper.prototype.S_IR, // Ir device; V_IR_SEND; V_IR_RECEIVE\nS_WATER: MySHelper.prototype.S_WATER, // Water meter; V_FLOW; V_VOLUME\nS_AIR_QUALITY: MySHelper.prototype.S_AIR_QUALITY, // Air quality sensor; V_LEVEL\nS_CUSTOM: MySHelper.prototype.S_CUSTOM, // Custom sensor \nS_DUST: MySHelper.prototype.S_DUST, // Dust sensor; V_LEVEL\nS_SCENE_CONTROLLER: MySHelper.prototype.S_SCENE_CONTROLLER, // Scene controller device; V_SCENE_ON; V_SCENE_OFF. \nS_RGB_LIGHT: MySHelper.prototype.S_RGB_LIGHT, // RGB light. Send color component data using V_RGB. Also supports V_WATT \nS_RGBW_LIGHT: MySHelper.prototype.S_RGBW_LIGHT, // RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT\nS_COLOR_SENSOR: MySHelper.prototype.S_COLOR_SENSOR, // Color sensor; send color information using V_RGB\nS_HVAC: MySHelper.prototype.S_HVAC, // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT; V_HVAC_SETPOINT_COLD; V_HVAC_FLOW_STATE; V_HVAC_FLOW_MODE; V_TEMP\nS_MULTIMETER: MySHelper.prototype.S_MULTIMETER, // Multimeter device; V_VOLTAGE; V_CURRENT; V_IMPEDANCE \nS_SPRINKLER: MySHelper.prototype.S_SPRINKLER, // Sprinkler; V_STATUS (turn on/off); V_TRIPPED (if fire detecting device)\nS_WATER_LEAK: MySHelper.prototype.S_WATER_LEAK, // Water leak sensor; V_TRIPPED; V_ARMED\nS_SOUND: MySHelper.prototype.S_SOUND, // Sound sensor; V_TRIPPED; V_ARMED; V_LEVEL (sound level in dB)\nS_VIBRATION: MySHelper.prototype.S_VIBRATION, // Vibration sensor; V_TRIPPED; V_ARMED; V_LEVEL (vibration in Hz)\nS_MOISTURE: MySHelper.prototype.S_MOISTURE, // Moisture sensor; V_TRIPPED; V_ARMED; V_LEVEL (water content or moisture in percentage?) \nS_INFO: MySHelper.prototype.S_INFO, // LCD text device / Simple information device on controller; V_TEXT\nS_GAS: MySHelper.prototype.S_GAS, // Gas meter; V_FLOW; V_VOLUME\nS_GPS: MySHelper.prototype.S_GPS // GPS Sensor; V_POSITION\n};\n\nMySHelper.prototype.SString = function(S_SUBTYPE) {\n for (var prop in stype ) \n if( stype[ prop ] === parseInt(S_SUBTYPE) )\n return prop;\n}; \n \n}\n\n\nvar MySHelperObj = new MySHelper();\n\ncontext.global.MYS = MySHelperObj;\n\nreturn msg;","outputs":1,"noerr":0,"x":325.25,"y":59.00000190734863,"z":"9592163f.6a6de8","wires":[[]]},{"id":"df1e322.f20e1d","type":"function","name":"Set Controller 1","func":"msg.controller = 1\n\nreturn msg;","outputs":1,"noerr":0,"x":602.0000076293945,"y":140.50000190734863,"z":"9592163f.6a6de8","wires":[["ebcef3df.14311"]]},{"id":"266b87b3.d99478","type":"switch","name":"route to controller n","property":"controller","rules":[{"t":"eq","v":"1"},{"t":"eq","v":"2"},{"t":"eq","v":"3"},{"t":"eq","v":"4"}],"checkall":"false","outputs":4,"x":94,"y":207.25000381469727,"z":"9592163f.6a6de8","wires":[["5f03c10e.a0fc4"],["c7d0d88b.382f28"],[],[]]},{"id":"c7d0d88b.382f28","type":"tcp request","server":"192.168.92.14","port":"5003","out":"char","splitc":"\\n","name":"MySWifi ESP8266 GW AES 14","x":370.5,"y":217.25000381469727,"z":"9592163f.6a6de8","wires":[["c5f14d8f.3a0eb"]]},{"id":"c5f14d8f.3a0eb","type":"function","name":"Set Controller 2","func":"msg.controller = 2\n\nreturn msg;","outputs":1,"noerr":0,"x":597.5000076293945,"y":218.750018119812,"z":"9592163f.6a6de8","wires":[["ebcef3df.14311"]]},{"id":"56b9f6ab.a94608","type":"file in","name":"read store for next ids","filename":"mysids.dump","format":"utf8","x":346,"y":97,"z":"9592163f.6a6de8","wires":[["57db23d6.a824dc"]]},{"id":"e000bd09.1fff4","type":"debug","name":"Debug","active":true,"console":"false","complete":"true","x":785,"y":470,"z":"9592163f.6a6de8","wires":[]},{"id":"57db23d6.a824dc","type":"function","name":"store to context.global.mysnextid","func":"if (msg.payload === undefined) {\n var mysnextid = {};\n\n obj = mysnextid; \n}\nelse \n{\ntry{\n obj = JSON.parse(msg.payload);\n }\n catch(e){\n \n var mysnextid = {};\n\n obj = mysnextid;\n \n }\n} \n\ncontext.global.mysnextid = obj;\n\nmsg.payload = context.global.mysnextid;\n\nreturn msg;","outputs":1,"noerr":0,"x":591,"y":96,"z":"9592163f.6a6de8","wires":[[]]},{"id":"dfba7d69.20458","type":"file","name":"dump mysids","filename":"mysids.dump","appendNewline":true,"createDir":false,"overwriteFile":"true","x":1434,"y":375,"z":"9592163f.6a6de8","wires":[]},{"id":"25efb0d3.da105","type":"inject","name":"Test Backup","topic":"","payload":"","payloadType":"none","repeat":"","crontab":"","once":false,"x":209,"y":456,"z":"9592163f.6a6de8","wires":[["e7d998a7.182668"]]},{"id":"e7d998a7.182668","type":"function","name":"Show context.global.mysnextid","func":"msg.payload = JSON.stringify(context.global.mysnextid);\n\nreturn msg;","outputs":1,"noerr":0,"x":427,"y":453,"z":"9592163f.6a6de8","wires":[["e000bd09.1fff4"]]},{"id":"e0e76d62.1f189","type":"function","name":"handle nextids","func":"// increase nextid, if nodeid >= nextid \n\nif (msg.nodeid < 255)\n{\n if (context.global.mysnextid[msg.controller] === undefined) {\n context.global.mysnextid[msg.controller] = msg.nodeid+1;\n }\n \n if (msg.nodeid >= context.global.mysnextid[msg.controller]) {\n context.global.mysnextid[msg.controller] = msg.nodeid+1; \n }\n \n}\n\nreturn msg;","outputs":1,"noerr":0,"x":1223,"y":368,"z":"9592163f.6a6de8","wires":[["dfba7d69.20458"]]},{"id":"a7d335f6.582cc8","type":"inject","name":"Test GetNodeId","topic":"","payload":"255;0;3;0;3;","payloadType":"string","repeat":"","crontab":"","once":false,"x":456,"y":264,"z":"9592163f.6a6de8","wires":[["c5f14d8f.3a0eb"]]}]
Features:
- Publish states to mqtt
- handle node-ids
- support multiple ethernet conrollers
- should be adoptable to serial controllers
Restrictions:
- read only, no values can be sent to nodes
- you will find others
-
- Fixed node-id handling for new nodes.
- added write support (see "MQTT to MYS" convert for details)
- parameters can be set in 'MYS initialize'
[{"id":"ba386057.845d3","type":"mqtt-broker","broker":"192.168.92.4","port":"1883","clientid":"NodeRed"},{"id":"e6ce260d.1931d8","type":"switch","z":"9592163f.6a6de8","name":"switch message type","property":"messageType","rules":[{"t":"eq","v":"0"},{"t":"eq","v":"1"},{"t":"eq","v":"2"},{"t":"eq","v":"3"},{"t":"eq","v":"4"}],"checkall":"true","outputs":5,"x":1259.166648864746,"y":182.50001335144043,"wires":[["8c663d73.7399c"],["4a1e5f84.b5e1a"],["7753f9a2.88ac08"],["1e4aa61b.e1b55a"],["60a0dde4.9f5f24"]]},{"id":"8c663d73.7399c","type":"function","z":"9592163f.6a6de8","name":"presentation","func":"msg.subTypeString = context.global.MYS.SString(msg.subType);\n\nmsg.topic = context.global.MYS.TOPIC_PREFIX + '/' + msg.controller + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.subTypeString;\n\nreturn msg;","outputs":1,"noerr":0,"x":1488.916648864746,"y":45.24998474121094,"wires":[["df9e131d.2061f","4d15a037.b2ea6"]]},{"id":"7753f9a2.88ac08","type":"function","z":"9592163f.6a6de8","name":"req","func":"msg.topic = \"req\";\nreturn msg;","outputs":1,"noerr":0,"x":1484.5000228881836,"y":182.75000190734863,"wires":[["4d15a037.b2ea6"]]},{"id":"1e4aa61b.e1b55a","type":"function","z":"9592163f.6a6de8","name":"internal","func":"msg.subTypeString = context.global.MYS.IString(msg.subType);\n\nmsg.topic = context.global.MYS.TOPIC_PREFIX + '/' + msg.controller + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.subTypeString;\n\nreturn msg;","outputs":1,"noerr":0,"x":1488.5000228881836,"y":233.00000190734863,"wires":[["df9e131d.2061f","4d15a037.b2ea6","b5e4f17d.4a1b1"]]},{"id":"60a0dde4.9f5f24","type":"function","z":"9592163f.6a6de8","name":"stream","func":"msg.topic = \"stream\";\nreturn msg;","outputs":1,"x":1496.5000228881836,"y":328.00000190734863,"wires":[[]]},{"id":"4d15a037.b2ea6","type":"debug","z":"9592163f.6a6de8","name":"debug","active":false,"console":"false","complete":"true","x":1845.7500267028809,"y":242.00000286102295,"wires":[]},{"id":"4a1e5f84.b5e1a","type":"function","z":"9592163f.6a6de8","name":"set","func":"msg.subTypeString = context.global.MYS.VString(msg.subType);\n\nmsg.topic = context.global.MYS.TOPIC_PREFIX + '/' + msg.controller + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.subTypeString;\n\n\nreturn msg;","outputs":1,"noerr":0,"x":1492.166648864746,"y":107.5,"wires":[["4d15a037.b2ea6","df9e131d.2061f"]]},{"id":"fc54bb91.03ab48","type":"debug","z":"9592163f.6a6de8","name":"","active":false,"console":"false","complete":"true","x":1218.9166259765625,"y":41.66668510437012,"wires":[]},{"id":"6aa2d9f6.955d28","type":"function","z":"9592163f.6a6de8","name":"Split GW Message","func":"\n var tokens = msg.payload.split(\";\")\n \n msg.rawData = tokens;\n if(tokens.length >= 6)\n {\n msg.nodeId = parseInt(tokens[0]);\n msg.childSensorId = parseInt(tokens[1]);\n msg.messageType = parseInt(tokens[2]);\n msg.ack = parseInt(tokens[3]);\n msg.subType = parseInt(tokens[4]);\n msg.payload = tokens[5];\n for (j=6; j<tokens.length; j++) \n msg.payload = msg.payload + ';' + tokens[j];\n }\n\nreturn msg;","outputs":1,"noerr":0,"x":1023.6666488647461,"y":180.66664123535156,"wires":[["e6ce260d.1931d8","fc54bb91.03ab48","e0e76d62.1f189"]]},{"id":"df9e131d.2061f","type":"mqtt out","z":"9592163f.6a6de8","name":"Publish to MQTT","topic":"","qos":"","retain":"","broker":"ba386057.845d3","x":1858.9166526794434,"y":181.16665649414062,"wires":[]},{"id":"b5e4f17d.4a1b1","type":"function","z":"9592163f.6a6de8","name":"hanlde internal messages","func":"//msg.subTypeString = \"\";\n//msg.topic = \"internal respones\";\n\nif (msg.subTypeString == 'I_TIME')\n{\n var payload = parseInt(new Date().getTime()/1000);\n\tvar command = context.global.MYS.T_INTERNAL; \n\tvar acknowledge = 0; // no ack\n\tvar type = context.global.MYS.I_TIME; // I_TIME\n\tmsg.payload = context.global.MYS.encode(msg.nodeId, msg.childSensorId, command, acknowledge, type, payload);\n return msg;\n \n}\nelse if (msg.subTypeString == 'I_ID_REQUEST')\n{\n msg.topic = \"I_ID_RESPONSE\";\n msg.subTypeString = \"I_ID_RESPONSE\";\n // 255;255;3;0;4;8 for ID 8\n var command = context.global.MYS.T_INTERNAL;\n\tvar acknowledge = 0; // no ack\n\tvar type = context.global.MYS.I_ID_RESPONSE; // I_ID_RESPONSE\n\n\tif (context.global.mysnextid[msg.controller] === undefined) {\n\t payload = context.global.MYS.MIN_NODEID;\n\t} \n\telse\n\t{\n\t payload = context.global.mysnextid[msg.controller];\n\t}\n\t\n msg.payload = context.global.MYS.encode(msg.nodeId, msg.childSensorId, command, acknowledge, type, payload);\n return msg; \n} \nelse if (msg.subTypeString == 'I_CONFIG')\n{\n var payload = 'M';\n\tvar command = context.global.MYS.T_INTERNAL; \n\tvar acknowledge = 0; // no ack\n\tvar type = context.global.MYS.I_CONFIG; // I_TIME\n\tmsg.payload = context.global.MYS.encode(msg.nodeId, msg.childSensorId, command, acknowledge, type, payload);\n return msg;\n}\nelse if (msg.subTypeString == 'I_INCLUSION_MODE')\n{\n // not yet implemented\n}\n\nreturn;\n\n\n","outputs":1,"noerr":0,"x":1694.916648864746,"y":543.4166889190674,"wires":[["4d15a037.b2ea6","266b87b3.d99478"]]},{"id":"e6d67f33.19298","type":"inject","z":"9592163f.6a6de8","name":"Startup","topic":"","payload":"","payloadType":"none","repeat":"","crontab":"","once":true,"x":145.25,"y":81.41665363311768,"wires":[["64617800.9b9e88","56b9f6ab.a94608","3e866f6d.c1799"]]},{"id":"ebcef3df.14311","type":"function","z":"9592163f.6a6de8","name":"ToString","func":"msg.payload = msg.payload.toString().replace(/[\\n\\r]/g, '');\n\nreturn msg;","outputs":1,"noerr":0,"x":829.1666946411133,"y":181.91668796539307,"wires":[["6aa2d9f6.955d28"]]},{"id":"31047fa6.cefb8","type":"catch","z":"9592163f.6a6de8","name":"","x":58,"y":449,"wires":[["3622f9b9.c9dd06"]]},{"id":"3622f9b9.c9dd06","type":"debug","z":"9592163f.6a6de8","name":"","active":false,"console":"false","complete":"true","x":224,"y":450,"wires":[]},{"id":"64617800.9b9e88","type":"function","z":"9592163f.6a6de8","name":"MYS Initialize","func":"function MySHelper() { \n\nMySHelper.prototype.TOPIC_PREFIX = \"MYS-NODERED\";\n\nMySHelper.prototype.MIN_NODEID = 10;\n\n\n// don't touch below :)\n \nMySHelper.prototype.T_PRESENTATION = 0;\nMySHelper.prototype.T_SET = 1;\nMySHelper.prototype.T_REQ = 2;\nMySHelper.prototype.T_INTERNAL = 3;\nMySHelper.prototype.T_STREAM = 4;\n\nMySHelper.prototype.I_BATTERY_LEVEL = 0;\nMySHelper.prototype.I_TIME = 1;\nMySHelper.prototype.I_VERSION = 2;\nMySHelper.prototype.I_ID_REQUEST = 3;\nMySHelper.prototype.I_ID_RESPONSE = 4;\nMySHelper.prototype.I_INCLUSION_MODE = 5;\nMySHelper.prototype.I_CONFIG = 6;\nMySHelper.prototype.I_PING = 7;\nMySHelper.prototype.I_PING_ACK = 8;\nMySHelper.prototype.I_LOG_MESSAGE = 9;\nMySHelper.prototype.I_CHILDREN = 10;\nMySHelper.prototype.I_SKETCH_NAME = 11;\nMySHelper.prototype.I_SKETCH_VERSION = 12;\nMySHelper.prototype.I_REBOOT = 13;\nMySHelper.prototype.I_GATEWAY_READY = 14;\nMySHelper.prototype.I_REQUEST_SIGNING = 15;\nMySHelper.prototype.I_GET_NONCE = 16;\nMySHelper.prototype.I_GET_NONCE_RESPONSE = 17;\nMySHelper.prototype.I_HEARTBEAT = 18;\nMySHelper.prototype.I_PRESENTATION = 19;\n \nvar itype = {\nI_BATTERY_LEVEL: MySHelper.prototype.I_BATTERY_LEVEL,\nI_TIME: MySHelper.prototype.I_TIME,\nI_VERSION: MySHelper.prototype.I_VERSION,\nI_ID_REQUEST: MySHelper.prototype.I_ID_REQUEST,\nI_ID_RESPONSE: MySHelper.prototype.I_ID_RESPONSE,\nI_INCLUSION_MODE: MySHelper.prototype.I_INCLUSION_MODE,\nI_CONFIG: MySHelper.prototype.I_CONFIG,\nI_PING: MySHelper.prototype.I_PING,\nI_PING_ACK: MySHelper.prototype.I_PING_ACK,\nI_LOG_MESSAGE: MySHelper.prototype.I_LOG_MESSAGE,\nI_CHILDREN: MySHelper.prototype.I_CHILDREN,\nI_SKETCH_NAME: MySHelper.prototype.I_SKETCH_NAME,\nI_SKETCH_VERSION: MySHelper.prototype.I_SKETCH_VERSION,\nI_REBOOT: MySHelper.prototype.I_REBOOT,\nI_GATEWAY_READY: MySHelper.prototype.I_GATEWAY_READY,\nI_REQUEST_SIGNING: MySHelper.prototype.I_REQUEST_SIGNING,\nI_GET_NONCE: MySHelper.prototype.I_GET_NONCE,\nI_GET_NONCE_RESPONSE: MySHelper.prototype.I_GET_NONCE_RESPONSE,\nI_HEARTBEAT: MySHelper.prototype.I_HEARTBEAT,\nI_PRESENTATION: MySHelper.prototype.I_PRESENTATION\n};\n\nMySHelper.prototype.IString = function(I_SUBTYPE) {\n for (var prop in itype ) \n if( itype[ prop ] === parseInt(I_SUBTYPE) )\n return prop;\n};\n\nMySHelper.prototype.V_TEMP = 0;\nMySHelper.prototype.V_HUM = 1;\nMySHelper.prototype.V_LIGHT = 2;\nMySHelper.prototype.V_STATUS = 2;\nMySHelper.prototype.V_DIMMER = 3;\nMySHelper.prototype.V_PRESSURE = 4;\nMySHelper.prototype.V_FORECAST = 5;\nMySHelper.prototype.V_RAIN = 6;\nMySHelper.prototype.V_RAINRATE = 7;\nMySHelper.prototype.V_WIND = 8;\nMySHelper.prototype.V_GUST = 9;\nMySHelper.prototype.V_DIRECTION = 10;\nMySHelper.prototype.V_UV = 11;\nMySHelper.prototype.V_WEIGHT = 12;\nMySHelper.prototype.V_DISTANCE = 13;\nMySHelper.prototype.V_IMPEDANCE = 14;\nMySHelper.prototype.V_ARMED = 15;\nMySHelper.prototype.V_TRIPPED = 16;\nMySHelper.prototype.V_WATT = 17;\nMySHelper.prototype.V_KWH = 18;\nMySHelper.prototype.V_SCENE_ON = 19;\nMySHelper.prototype.V_SCENE_OFF = 20;\nMySHelper.prototype.V_HEATER = 21;\nMySHelper.prototype.V_HEATER_SW = 22;\nMySHelper.prototype.V_LIGHT_LEVEL = 23;\nMySHelper.prototype.V_VAR1 = 24;\nMySHelper.prototype.V_VAR2 = 25;\nMySHelper.prototype.V_VAR3 = 26;\nMySHelper.prototype.V_VAR4 = 27;\nMySHelper.prototype.V_VAR5 = 28;\nMySHelper.prototype.V_UP = 29;\nMySHelper.prototype.V_DOWN = 30;\nMySHelper.prototype.V_STOP = 31;\nMySHelper.prototype.V_IR_SEND = 32;\nMySHelper.prototype.V_IR_RECEIVE = 33;\nMySHelper.prototype.V_FLOW = 34;\nMySHelper.prototype.V_VOLUME = 35;\nMySHelper.prototype.V_LOCK_STATUS = 36;\nMySHelper.prototype.V_LEVEL = 37; \nMySHelper.prototype.V_VOLTAGE = 38; \nMySHelper.prototype.V_CURRENT = 39; \nMySHelper.prototype.V_RGB = 40; \nMySHelper.prototype.V_RGBW = 41;\nMySHelper.prototype.V_ID = 42;\nMySHelper.prototype.V_UNIT_PREFIX = 43;\nMySHelper.prototype.V_HVAC_SETPOINT_COOL = 44;\nMySHelper.prototype.V_HVAC_SETPOINT_HEAT = 45;\nMySHelper.prototype.V_HVAC_FLOW_MODE = 46;\nMySHelper.prototype.V_TEXT = 47;\n\nvar vtype = {\nV_TEMP: MySHelper.prototype.V_TEMP,\nV_HUM: MySHelper.prototype.V_HUM,\nV_STATUS: MySHelper.prototype.V_STATUS,\nV_LIGHT: MySHelper.prototype.V_LIGHT,\nV_DIMMER: MySHelper.prototype.V_DIMMER,\nV_PRESSURE: MySHelper.prototype.V_PRESSURE,\nV_FORECAST: MySHelper.prototype.V_FORECAST,\nV_RAIN: MySHelper.prototype.V_RAIN,\nV_RAINRATE: MySHelper.prototype.V_RAINRATE,\nV_WIND: MySHelper.prototype.V_WIND,\nV_GUST: MySHelper.prototype.V_GUST,\nV_DIRECTION: MySHelper.prototype.V_DIRECTION,\nV_UV: MySHelper.prototype.V_UV,\nV_WEIGHT: MySHelper.prototype.V_WEIGHT,\nV_DISTANCE: MySHelper.prototype.V_DISTANCE,\nV_IMPEDANCE: MySHelper.prototype.V_IMPEDANCE,\nV_ARMED: MySHelper.prototype.V_ARMED,\nV_TRIPPED: MySHelper.prototype.V_TRIPPED,\nV_WATT: MySHelper.prototype.V_WATT,\nV_KWH: MySHelper.prototype.V_KWH,\nV_SCENE_ON: MySHelper.prototype.V_SCENE_ON,\nV_SCENE_OFF: MySHelper.prototype.V_SCENE_OFF,\nV_HEATER: MySHelper.prototype.V_HEATER,\nV_HEATER_SW: MySHelper.prototype.V_HEATER_SW,\nV_LIGHT_LEVEL: MySHelper.prototype.V_LIGHT_LEVEL,\nV_VAR1: MySHelper.prototype.V_VAR1,\nV_VAR2: MySHelper.prototype.V_VAR2,\nV_VAR3: MySHelper.prototype.V_VAR3,\nV_VAR4: MySHelper.prototype.V_VAR4,\nV_VAR5: MySHelper.prototype.V_VAR5,\nV_UP: MySHelper.prototype.V_UP,\nV_DOWN: MySHelper.prototype.V_DOWN,\nV_STOP: MySHelper.prototype.V_STOP,\nV_IR_SEND: MySHelper.prototype.V_IR_SEND,\nV_IR_RECEIVE: MySHelper.prototype.V_IR_RECEIVE,\nV_FLOW: MySHelper.prototype.V_FLOW,\nV_VOLUME: MySHelper.prototype.V_VOLUME,\nV_LOCK_STATUS: MySHelper.prototype.V_LOCK_STATUS,\nV_LEVEL: MySHelper.prototype.V_LEVEL,\nV_VOLTAGE: MySHelper.prototype.V_VOLTAGE, \nV_CURRENT: MySHelper.prototype.V_CURRENT,\nV_RGB: MySHelper.prototype.V_RGB,\nV_RGBW: MySHelper.prototype.V_RGBW,\nV_ID: MySHelper.prototype.V_ID,\nV_UNIT_PREFIX: MySHelper.prototype.V_UNIT_PREFIX,\nV_HVAC_SETPOINT_COOL:MySHelper.prototype.V_HVAC_SETPOINT_COOL,\nV_HVAC_SETPOINT_HEAT:MySHelper.prototype.V_HVAC_SETPOINT_HEAT,\nV_HVAC_FLOW_MODE: MySHelper.prototype.V_HVAC_FLOW_MODE,\nV_TEXT: MySHelper.prototype.V_TEXT\n};\n\n\n\nMySHelper.prototype.VString = function(V_SUBTYPE) {\n for (var prop in vtype ) \n if( vtype[ prop ] === parseInt(V_SUBTYPE) )\n return prop;\n};\n \nMySHelper.prototype.VNum = function(V_SUBTYPE) {\n sRet = vtype [V_SUBTYPE];\n if (sRet === undefined)\n sRet = V_SUBTYPE;\n return sRet;\n}\n\nMySHelper.prototype.S_DOOR = 0; // Door sensor; V_TRIPPED; V_ARMED\nMySHelper.prototype.S_MOTION = 1; // Motion sensor; V_TRIPPED; V_ARMED \nMySHelper.prototype.S_SMOKE = 2; // Smoke sensor; V_TRIPPED; V_ARMED\nMySHelper.prototype.S_LIGHT = 3; // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT\nMySHelper.prototype.S_BINARY = 3; // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT (same as MySHelper.prototype.S_LIGHT)\nMySHelper.prototype.S_DIMMER = 4; // Dimmable light or fan device; V_STATUS (on/off); V_DIMMER (dimmer level 0-100); V_WATT\nMySHelper.prototype.S_COVER = 5; // Blinds or window cover; V_UP; V_DOWN; V_STOP; V_DIMMER (open/close to a percentage)\nMySHelper.prototype.S_TEMP = 6; // Temperature sensor; V_TEMP\nMySHelper.prototype.S_HUM = 7; // Humidity sensor; V_HUM\nMySHelper.prototype.S_BARO = 8; // Barometer sensor; V_PRESSURE; V_FORECAST\nMySHelper.prototype.S_WIND = 9; // Wind sensor; V_WIND; V_GUST\nMySHelper.prototype.S_RAIN = 10; // Rain sensor; V_RAIN; V_RAINRATE\nMySHelper.prototype.S_UV = 11; // Uv sensor; V_UV\nMySHelper.prototype.S_WEIGHT = 12; // Personal scale sensor; V_WEIGHT; V_IMPEDANCE\nMySHelper.prototype.S_POWER = 13; // Power meter; V_WATT; V_KWH\nMySHelper.prototype.S_HEATER = 14; // Header device; V_HVAC_SETPOINT_HEAT; V_HVAC_FLOW_STATE; V_TEMP\nMySHelper.prototype.S_DISTANCE = 15; // Distance sensor; V_DISTANCE\nMySHelper.prototype.S_LIGHT_LEVEL = 16; // Light level sensor; V_LIGHT_LEVEL (uncalibrated in percentage); V_LEVEL (light level in lux)\nMySHelper.prototype.S_ARDUINO_NODE = 17 ; // Used (internally) for presenting a non-repeating Arduino node\nMySHelper.prototype.S_ARDUINO_REPEATER_NODE = 18; // Used (internally) for presenting a repeating Arduino node \nMySHelper.prototype.S_LOCK = 19; // Lock device; V_LOCK_STATUS\nMySHelper.prototype.S_IR = 20; // Ir device; V_IR_SEND; V_IR_RECEIVE\nMySHelper.prototype.S_WATER = 21; // Water meter; V_FLOW; V_VOLUME\nMySHelper.prototype.S_AIR_QUALITY = 22; // Air quality sensor; V_LEVEL\nMySHelper.prototype.S_CUSTOM = 23; // Custom sensor \nMySHelper.prototype.S_DUST = 24; // Dust sensor; V_LEVEL\nMySHelper.prototype.S_SCENE_CONTROLLER = 25; // Scene controller device; V_SCENE_ON; V_SCENE_OFF. \nMySHelper.prototype.S_RGB_LIGHT = 26; // RGB light. Send color component data using V_RGB. Also supports V_WATT \nMySHelper.prototype.S_RGBW_LIGHT = 27; // RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT\nMySHelper.prototype.S_COLOR_SENSOR = 28; // Color sensor; send color information using V_RGB\nMySHelper.prototype.S_HVAC = 28; // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT; V_HVAC_SETPOINT_COLD; V_HVAC_FLOW_STATE; V_HVAC_FLOW_MODE; V_TEMP\nMySHelper.prototype.S_MULTIMETER = 29; // Multimeter device; V_VOLTAGE; V_CURRENT; V_IMPEDANCE \nMySHelper.prototype.S_SPRINKLER = 30; // Sprinkler; V_STATUS (turn on/off); V_TRIPPED (if fire detecting device)\nMySHelper.prototype.S_WATER_LEAK = 31; // Water leak sensor; V_TRIPPED; V_ARMED\nMySHelper.prototype.S_SOUND = 32; // Sound sensor; V_TRIPPED; V_ARMED; V_LEVEL (sound level in dB)\nMySHelper.prototype.S_VIBRATION = 33; // Vibration sensor; V_TRIPPED; V_ARMED; V_LEVEL (vibration in Hz)\nMySHelper.prototype.S_MOISTURE = 34; // Moisture sensor; V_TRIPPED; V_ARMED; V_LEVEL (water content or moisture in percentage?) \nMySHelper.prototype.S_INFO = 35; // LCD text device / Simple information device on controller; V_TEXT\nMySHelper.prototype.S_GAS = 36; // Gas meter; V_FLOW; V_VOLUME\nMySHelper.prototype.S_GPS = 37; // GPS Sensor; V_POSITION\n \nvar stype = {\nS_DOOR: MySHelper.prototype.S_DOOR, // Door sensor; V_TRIPPED; V_ARMED\nS_MOTION: MySHelper.prototype.S_MOTION, // Motion sensor; V_TRIPPED; V_ARMED \nS_SMOKE: MySHelper.prototype.S_SMOKE, // Smoke sensor; V_TRIPPED; V_ARMED\nS_LIGHT: MySHelper.prototype.S_LIGHT, // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT\nS_BINARY: MySHelper.prototype.S_BINARY, // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT (same as MySHelper.prototype.S_LIGHT)\nS_DIMMER: MySHelper.prototype.S_DIMMER, // Dimmable light or fan device; V_STATUS (on/off); V_DIMMER (dimmer level 0-100); V_WATT\nS_COVER: MySHelper.prototype.S_COVER, // Blinds or window cover; V_UP; V_DOWN; V_STOP; V_DIMMER (open/close to a percentage)\nS_TEMP: MySHelper.prototype.S_TEMP, // Temperature sensor; V_TEMP\nS_HUM: MySHelper.prototype.S_HUM, // Humidity sensor; V_HUM\nS_BARO: MySHelper.prototype.S_BARO, // Barometer sensor; V_PRESSURE; V_FORECAST\nS_WIND: MySHelper.prototype.S_WIND, // Wind sensor; V_WIND; V_GUST\nS_RAIN: MySHelper.prototype.S_RAIN, // Rain sensor; V_RAIN; V_RAINRATE\nS_UV: MySHelper.prototype.S_UV, // Uv sensor; V_UV\nS_WEIGHT: MySHelper.prototype.S_WEIGHT, // Personal scale sensor; V_WEIGHT; V_IMPEDANCE\nS_POWER: MySHelper.prototype.S_POWER, // Power meter; V_WATT; V_KWH\nS_HEATER: MySHelper.prototype.S_HEATER, // Header device; V_HVAC_SETPOINT_HEAT; V_HVAC_FLOW_STATE; V_TEMP\nS_DISTANCE: MySHelper.prototype.S_DISTANCE, // Distance sensor; V_DISTANCE\nS_LIGHT_LEVEL: MySHelper.prototype.S_LIGHT_LEVEL, // Light level sensor; V_LIGHT_LEVEL (uncalibrated in percentage); V_LEVEL (light level in lux)\nS_ARDUINO_NODE: MySHelper.prototype.S_ARDUINO_NODE, // Used (internally) for presenting a non-repeating Arduino node\nS_ARDUINO_REPEATER_NODE:MySHelper.prototype.S_ARDUINO_REPEATER_NODE, // Used (internally) for presenting a repeating Arduino node \nS_LOCK: MySHelper.prototype.S_LOCK, // Lock device; V_LOCK_STATUS\nS_IR: MySHelper.prototype.S_IR, // Ir device; V_IR_SEND; V_IR_RECEIVE\nS_WATER: MySHelper.prototype.S_WATER, // Water meter; V_FLOW; V_VOLUME\nS_AIR_QUALITY: MySHelper.prototype.S_AIR_QUALITY, // Air quality sensor; V_LEVEL\nS_CUSTOM: MySHelper.prototype.S_CUSTOM, // Custom sensor \nS_DUST: MySHelper.prototype.S_DUST, // Dust sensor; V_LEVEL\nS_SCENE_CONTROLLER: MySHelper.prototype.S_SCENE_CONTROLLER, // Scene controller device; V_SCENE_ON; V_SCENE_OFF. \nS_RGB_LIGHT: MySHelper.prototype.S_RGB_LIGHT, // RGB light. Send color component data using V_RGB. Also supports V_WATT \nS_RGBW_LIGHT: MySHelper.prototype.S_RGBW_LIGHT, // RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT\nS_COLOR_SENSOR: MySHelper.prototype.S_COLOR_SENSOR, // Color sensor; send color information using V_RGB\nS_HVAC: MySHelper.prototype.S_HVAC, // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT; V_HVAC_SETPOINT_COLD; V_HVAC_FLOW_STATE; V_HVAC_FLOW_MODE; V_TEMP\nS_MULTIMETER: MySHelper.prototype.S_MULTIMETER, // Multimeter device; V_VOLTAGE; V_CURRENT; V_IMPEDANCE \nS_SPRINKLER: MySHelper.prototype.S_SPRINKLER, // Sprinkler; V_STATUS (turn on/off); V_TRIPPED (if fire detecting device)\nS_WATER_LEAK: MySHelper.prototype.S_WATER_LEAK, // Water leak sensor; V_TRIPPED; V_ARMED\nS_SOUND: MySHelper.prototype.S_SOUND, // Sound sensor; V_TRIPPED; V_ARMED; V_LEVEL (sound level in dB)\nS_VIBRATION: MySHelper.prototype.S_VIBRATION, // Vibration sensor; V_TRIPPED; V_ARMED; V_LEVEL (vibration in Hz)\nS_MOISTURE: MySHelper.prototype.S_MOISTURE, // Moisture sensor; V_TRIPPED; V_ARMED; V_LEVEL (water content or moisture in percentage?) \nS_INFO: MySHelper.prototype.S_INFO, // LCD text device / Simple information device on controller; V_TEXT\nS_GAS: MySHelper.prototype.S_GAS, // Gas meter; V_FLOW; V_VOLUME\nS_GPS: MySHelper.prototype.S_GPS // GPS Sensor; V_POSITION\n};\n\nMySHelper.prototype.SString = function(S_SUBTYPE) {\n for (var prop in stype ) \n if( stype[ prop ] === parseInt(S_SUBTYPE) )\n return prop;\n}; \n \n MySHelper.prototype.encode = function(destination, sensor, command, acknowledge, type, payload) {\n\tvar msg = destination.toString(10) + \";\" + sensor.toString(10) + \";\" + command.toString(10) + \";\" + acknowledge.toString(10) + \";\" + type.toString(10) + \";\";\n\tif (command == 4) {\n\t\tfor (var i = 0; i < payload.length; i++) {\n\t\t\tif (payload[i] < 16)\n\t\t\t\tmsg += \"0\";\n\t\t\tmsg += payload[i].toString(16);\n\t\t}\n\t} else {\n\t\tmsg += payload;\n\t}\n\tmsg += '\\n';\n\treturn msg.toString();\n}\n}\n\n\nvar MySHelperObj = new MySHelper();\n\ncontext.global.MYS = MySHelperObj;\n\nreturn msg;","outputs":1,"noerr":0,"x":364.25,"y":65.99999809265137,"wires":[[]]},{"id":"df1e322.f20e1d","type":"function","z":"9592163f.6a6de8","name":"Set Controller 1","func":"msg.controller = 1\n\nreturn msg;","outputs":1,"noerr":0,"x":641.0000076293945,"y":147.49999809265137,"wires":[["ebcef3df.14311"]]},{"id":"266b87b3.d99478","type":"switch","z":"9592163f.6a6de8","name":"route to controller n","property":"controller","rules":[{"t":"eq","v":"1"},{"t":"eq","v":"2"},{"t":"eq","v":"3"},{"t":"eq","v":"4"}],"checkall":"false","outputs":4,"x":133,"y":214.25,"wires":[["3e866f6d.c1799"],["c7d0d88b.382f28"],[],[]]},{"id":"c7d0d88b.382f28","type":"tcp request","z":"9592163f.6a6de8","server":"192.168.92.14","port":"5003","out":"sit","splitc":"0","name":"MySWifi ESP8266 GW AES 14","x":410.5,"y":207.24999618530273,"wires":[["c5f14d8f.3a0eb"]]},{"id":"c5f14d8f.3a0eb","type":"function","z":"9592163f.6a6de8","name":"Set Controller 2","func":"msg.controller = 2\n\nreturn msg;","outputs":1,"noerr":0,"x":653.5,"y":205.7500114440918,"wires":[["ebcef3df.14311"]]},{"id":"56b9f6ab.a94608","type":"file in","z":"9592163f.6a6de8","name":"read store for next ids","filename":"mysids.dump","format":"utf8","x":385,"y":103.99999618530273,"wires":[["57db23d6.a824dc"]]},{"id":"e000bd09.1fff4","type":"debug","z":"9592163f.6a6de8","name":"Debug","active":false,"console":"false","complete":"true","x":732,"y":361,"wires":[]},{"id":"57db23d6.a824dc","type":"function","z":"9592163f.6a6de8","name":"store to context.global.mysnextid","func":"if (msg.payload === undefined) {\n var mysnextid = {};\n\n obj = mysnextid; \n}\nelse \n{\ntry{\n obj = JSON.parse(msg.payload);\n }\n catch(e){\n \n var mysnextid = {};\n\n obj = mysnextid;\n \n }\n} \n\ncontext.global.mysnextid = obj;\n\nmsg.payload = context.global.mysnextid;\n\nreturn msg;","outputs":1,"noerr":0,"x":630,"y":102.99999618530273,"wires":[[]]},{"id":"dfba7d69.20458","type":"file","z":"9592163f.6a6de8","name":"dump mysids","filename":"mysids.dump","appendNewline":true,"createDir":false,"overwriteFile":"true","x":1473,"y":381.99999618530273,"wires":[]},{"id":"e0e76d62.1f189","type":"function","z":"9592163f.6a6de8","name":"handle nextids","func":"// increase nextid, if nodeid >= nextid \n// node.log(\"Handling next ids\");\n// node.log(\"nodeId: \" + msg.nodeId);\n\nbChanged = false;\n\nif (msg.nodeId === 0) return;\n\nif (msg.nodeId < 255)\n{\n // node.log(\"Test if next node-id must be set\");\n if (context.global.mysnextid[msg.controller] === undefined) {\n node.log(\"node-id not initialized yet\");\n context.global.mysnextid[msg.controller] = msg.nodeId+1;\n if (context.global.mysnextid[msg.controller] < context.global.MYS.MIN_NODEID)\n context.global.mysnextid[msg.controller] = context.global.MYS.MIN_NODEID;\n bChanged = true;\n }\n \n // node.log(\"Nexid stored \" + parseInt(context.global.mysnextid[msg.controller]));\n \n if (msg.nodeId >= parseInt(context.global.mysnextid[msg.controller])) {\n node.log(\"node-id >= next -> increase\");\n // convert to int\n context.global.mysnextid[msg.controller] = parseInt(context.global.mysnextid[msg.controller]);\n context.global.mysnextid[msg.controller] = msg.nodeId+1; \n if (context.global.mysnextid[msg.controller] < context.global.MYS.MIN_NODEID)\n context.global.mysnextid[msg.controller] = context.global.MYS.MIN_NODEID;\n bChanged = true;\n }\n\n if (bChanged) {\n node.log(\"next id must be stored\");\n msg.payload = JSON.stringify(context.global.mysnextid); \n return msg;\n }\n}\n\n\n","outputs":1,"noerr":0,"x":1262,"y":374.99999618530273,"wires":[["dfba7d69.20458","5c074c19.a3f8b4"]]},{"id":"8da09002.725f7","type":"function","z":"9592163f.6a6de8","name":"MQTT to MYS convert","func":"// topic = MYS-NODERED/set/controller/node-id/sensor-id/ack/sub-type\n// payload = payload :)\n\n var tokens = msg.topic.split(\"/\")\n \n msg.rawData = tokens;\n msg.tokens = tokens.length;\n if(tokens.length == 7)\n {\n if (tokens[0] != context.global.MYS.TOPIC_PREFIX) // not for us\n return;\n if (tokens[1] != 'set') // not for us\n return;\n \n msg.controller = parseInt(tokens[2]);\n msg.messageType = context.global.MYS.T_SET;\n msg.nodeId = parseInt(tokens[3]);\n msg.childSensorId = parseInt(tokens[4]);\n msg.ack = parseInt(tokens[5]);\n msg.subType = context.global.MYS.VNum(tokens[6]);\n \n msg.payload = context.global.MYS.encode(msg.nodeId, msg.childSensorId, msg.messageType, msg.ack, msg.subType, msg.payload);\n \n return msg; \n }\n","outputs":1,"noerr":0,"x":490,"y":361,"wires":[["e000bd09.1fff4","266b87b3.d99478"]]},{"id":"3e866f6d.c1799","type":"tcp request","z":"9592163f.6a6de8","server":"192.168.92.13","port":"5003","out":"sit","splitc":"0","name":"MySWifi ESP8266 GW AES 13","x":407,"y":145.99999618530273,"wires":[["df1e322.f20e1d"]]},{"id":"5c074c19.a3f8b4","type":"debug","z":"9592163f.6a6de8","name":"","active":true,"console":"false","complete":"false","x":1454,"y":543.9999961853027,"wires":[]},{"id":"c75fd7f4.38a028","type":"mqtt in","z":"9592163f.6a6de8","name":"Read MQTT Stream: change Topic to your needs","topic":"MYS-NODERED/set/#","broker":"ba386057.845d3","x":183.5,"y":362,"wires":[["8da09002.725f7"]]}]```
-
Stability is not sufficient. The connection gets lost from time to time.
Added a watchdog to add another connection, if no messages arrives.
Seems, that this is only interesting for me. If I get no feedback I will stop spaming this thread.
[{"id":"ba386057.845d3","type":"mqtt-broker","broker":"192.168.92.4","port":"1883","clientid":"NodeRed"},{"id":"e6ce260d.1931d8","type":"switch","z":"9592163f.6a6de8","name":"switch message type","property":"messageType","rules":[{"t":"eq","v":"0"},{"t":"eq","v":"1"},{"t":"eq","v":"2"},{"t":"eq","v":"3"},{"t":"eq","v":"4"}],"checkall":"true","outputs":5,"x":1259.166648864746,"y":182.50001335144043,"wires":[["8c663d73.7399c"],["4a1e5f84.b5e1a"],["7753f9a2.88ac08"],["1e4aa61b.e1b55a"],["60a0dde4.9f5f24"]]},{"id":"8c663d73.7399c","type":"function","z":"9592163f.6a6de8","name":"presentation","func":"msg.subTypeString = context.global.MYS.SString(msg.subType);\n\nmsg.topic = context.global.MYS.TOPIC_PREFIX + '/' + msg.controller + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.subTypeString;\n\nreturn msg;","outputs":1,"noerr":0,"x":1488.916648864746,"y":45.24998474121094,"wires":[["df9e131d.2061f","4d15a037.b2ea6"]]},{"id":"7753f9a2.88ac08","type":"function","z":"9592163f.6a6de8","name":"req","func":"msg.topic = \"req\";\nreturn msg;","outputs":1,"noerr":0,"x":1484.5000228881836,"y":182.75000190734863,"wires":[["4d15a037.b2ea6"]]},{"id":"1e4aa61b.e1b55a","type":"function","z":"9592163f.6a6de8","name":"internal","func":"msg.subTypeString = context.global.MYS.IString(msg.subType);\n\nmsg.topic = context.global.MYS.TOPIC_PREFIX + '/' + msg.controller + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.subTypeString;\n\nreturn msg;","outputs":1,"noerr":0,"x":1488.5000228881836,"y":233.00000190734863,"wires":[["df9e131d.2061f","4d15a037.b2ea6","b5e4f17d.4a1b1"]]},{"id":"60a0dde4.9f5f24","type":"function","z":"9592163f.6a6de8","name":"stream","func":"msg.topic = \"stream\";\nreturn msg;","outputs":1,"x":1496.5000228881836,"y":328.00000190734863,"wires":[[]]},{"id":"4d15a037.b2ea6","type":"debug","z":"9592163f.6a6de8","name":"debug","active":false,"console":"false","complete":"true","x":1845.7500267028809,"y":242.00000286102295,"wires":[]},{"id":"4a1e5f84.b5e1a","type":"function","z":"9592163f.6a6de8","name":"set","func":"msg.subTypeString = context.global.MYS.VString(msg.subType);\n\nmsg.topic = context.global.MYS.TOPIC_PREFIX + '/' + msg.controller + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.subTypeString;\n\n\nreturn msg;","outputs":1,"noerr":0,"x":1492.166648864746,"y":107.5,"wires":[["4d15a037.b2ea6","df9e131d.2061f"]]},{"id":"fc54bb91.03ab48","type":"debug","z":"9592163f.6a6de8","name":"","active":false,"console":"false","complete":"true","x":1218.9166259765625,"y":41.66668510437012,"wires":[]},{"id":"6aa2d9f6.955d28","type":"function","z":"9592163f.6a6de8","name":"Split GW Message","func":"\n var tokens = msg.payload.split(\";\")\n \n msg.rawData = tokens;\n if(tokens.length >= 6)\n {\n msg.nodeId = parseInt(tokens[0]);\n msg.childSensorId = parseInt(tokens[1]);\n msg.messageType = parseInt(tokens[2]);\n msg.ack = parseInt(tokens[3]);\n msg.subType = parseInt(tokens[4]);\n msg.payload = tokens[5];\n for (j=6; j<tokens.length; j++) \n msg.payload = msg.payload + ';' + tokens[j];\n }\n\nreturn msg;","outputs":1,"noerr":0,"x":1023.6666488647461,"y":180.66664123535156,"wires":[["e6ce260d.1931d8","fc54bb91.03ab48","e0e76d62.1f189"]]},{"id":"df9e131d.2061f","type":"mqtt out","z":"9592163f.6a6de8","name":"Publish to MQTT","topic":"","qos":"","retain":"","broker":"ba386057.845d3","x":1858.9166526794434,"y":181.16665649414062,"wires":[]},{"id":"b5e4f17d.4a1b1","type":"function","z":"9592163f.6a6de8","name":"hanlde internal messages","func":"//msg.subTypeString = \"\";\n//msg.topic = \"internal respones\";\n\nif (msg.subTypeString == 'I_TIME')\n{\n var payload = parseInt(new Date().getTime()/1000);\n\tvar command = context.global.MYS.T_INTERNAL; \n\tvar acknowledge = 0; // no ack\n\tvar type = context.global.MYS.I_TIME; // I_TIME\n\tmsg.payload = context.global.MYS.encode(msg.nodeId, msg.childSensorId, command, acknowledge, type, payload);\n return msg;\n \n}\nelse if (msg.subTypeString == 'I_ID_REQUEST')\n{\n msg.topic = \"I_ID_RESPONSE\";\n msg.subTypeString = \"I_ID_RESPONSE\";\n // 255;255;3;0;4;8 for ID 8\n var command = context.global.MYS.T_INTERNAL;\n\tvar acknowledge = 0; // no ack\n\tvar type = context.global.MYS.I_ID_RESPONSE; // I_ID_RESPONSE\n\n\tif (context.global.mysnextid[msg.controller] === undefined) {\n\t payload = context.global.MYS.MIN_NODEID;\n\t} \n\telse\n\t{\n\t payload = context.global.mysnextid[msg.controller];\n\t}\n\t\n msg.payload = context.global.MYS.encode(msg.nodeId, msg.childSensorId, command, acknowledge, type, payload);\n return msg; \n} \nelse if (msg.subTypeString == 'I_CONFIG')\n{\n var payload = 'M';\n\tvar command = context.global.MYS.T_INTERNAL; \n\tvar acknowledge = 0; // no ack\n\tvar type = context.global.MYS.I_CONFIG; // I_TIME\n\tmsg.payload = context.global.MYS.encode(msg.nodeId, msg.childSensorId, command, acknowledge, type, payload);\n return msg;\n}\nelse if (msg.subTypeString == 'I_INCLUSION_MODE')\n{\n // not yet implemented\n}\n\nreturn;\n\n\n","outputs":1,"noerr":0,"x":1694.916648864746,"y":543.4166889190674,"wires":[["4d15a037.b2ea6","266b87b3.d99478"]]},{"id":"e6d67f33.19298","type":"inject","z":"9592163f.6a6de8","name":"Startup","topic":"","payload":"","payloadType":"none","repeat":"","crontab":"","once":true,"x":145.25,"y":81.41665363311768,"wires":[["64617800.9b9e88","56b9f6ab.a94608","3e866f6d.c1799"]]},{"id":"ebcef3df.14311","type":"function","z":"9592163f.6a6de8","name":"ToString","func":"msg.payload = msg.payload.toString().replace(/[\\n\\r]/g, '');\n\nreturn msg;","outputs":1,"noerr":0,"x":829.1666946411133,"y":181.91668796539307,"wires":[["6aa2d9f6.955d28"]]},{"id":"31047fa6.cefb8","type":"catch","z":"9592163f.6a6de8","name":"","x":58,"y":449,"wires":[["3622f9b9.c9dd06"]]},{"id":"3622f9b9.c9dd06","type":"debug","z":"9592163f.6a6de8","name":"","active":false,"console":"false","complete":"true","x":224,"y":450,"wires":[]},{"id":"64617800.9b9e88","type":"function","z":"9592163f.6a6de8","name":"MYS Initialize","func":"function MySHelper() { \n\nMySHelper.prototype.TOPIC_PREFIX = \"MYS-NODERED\";\n\nMySHelper.prototype.MIN_NODEID = 10;\n\n\n// don't touch below :)\n \nMySHelper.prototype.T_PRESENTATION = 0;\nMySHelper.prototype.T_SET = 1;\nMySHelper.prototype.T_REQ = 2;\nMySHelper.prototype.T_INTERNAL = 3;\nMySHelper.prototype.T_STREAM = 4;\n\nMySHelper.prototype.I_BATTERY_LEVEL = 0;\nMySHelper.prototype.I_TIME = 1;\nMySHelper.prototype.I_VERSION = 2;\nMySHelper.prototype.I_ID_REQUEST = 3;\nMySHelper.prototype.I_ID_RESPONSE = 4;\nMySHelper.prototype.I_INCLUSION_MODE = 5;\nMySHelper.prototype.I_CONFIG = 6;\nMySHelper.prototype.I_PING = 7;\nMySHelper.prototype.I_PING_ACK = 8;\nMySHelper.prototype.I_LOG_MESSAGE = 9;\nMySHelper.prototype.I_CHILDREN = 10;\nMySHelper.prototype.I_SKETCH_NAME = 11;\nMySHelper.prototype.I_SKETCH_VERSION = 12;\nMySHelper.prototype.I_REBOOT = 13;\nMySHelper.prototype.I_GATEWAY_READY = 14;\nMySHelper.prototype.I_REQUEST_SIGNING = 15;\nMySHelper.prototype.I_GET_NONCE = 16;\nMySHelper.prototype.I_GET_NONCE_RESPONSE = 17;\nMySHelper.prototype.I_HEARTBEAT = 18;\nMySHelper.prototype.I_PRESENTATION = 19;\n \nvar itype = {\nI_BATTERY_LEVEL: MySHelper.prototype.I_BATTERY_LEVEL,\nI_TIME: MySHelper.prototype.I_TIME,\nI_VERSION: MySHelper.prototype.I_VERSION,\nI_ID_REQUEST: MySHelper.prototype.I_ID_REQUEST,\nI_ID_RESPONSE: MySHelper.prototype.I_ID_RESPONSE,\nI_INCLUSION_MODE: MySHelper.prototype.I_INCLUSION_MODE,\nI_CONFIG: MySHelper.prototype.I_CONFIG,\nI_PING: MySHelper.prototype.I_PING,\nI_PING_ACK: MySHelper.prototype.I_PING_ACK,\nI_LOG_MESSAGE: MySHelper.prototype.I_LOG_MESSAGE,\nI_CHILDREN: MySHelper.prototype.I_CHILDREN,\nI_SKETCH_NAME: MySHelper.prototype.I_SKETCH_NAME,\nI_SKETCH_VERSION: MySHelper.prototype.I_SKETCH_VERSION,\nI_REBOOT: MySHelper.prototype.I_REBOOT,\nI_GATEWAY_READY: MySHelper.prototype.I_GATEWAY_READY,\nI_REQUEST_SIGNING: MySHelper.prototype.I_REQUEST_SIGNING,\nI_GET_NONCE: MySHelper.prototype.I_GET_NONCE,\nI_GET_NONCE_RESPONSE: MySHelper.prototype.I_GET_NONCE_RESPONSE,\nI_HEARTBEAT: MySHelper.prototype.I_HEARTBEAT,\nI_PRESENTATION: MySHelper.prototype.I_PRESENTATION\n};\n\nMySHelper.prototype.IString = function(I_SUBTYPE) {\n for (var prop in itype ) \n if( itype[ prop ] === parseInt(I_SUBTYPE) )\n return prop;\n};\n\nMySHelper.prototype.V_TEMP = 0;\nMySHelper.prototype.V_HUM = 1;\nMySHelper.prototype.V_LIGHT = 2;\nMySHelper.prototype.V_STATUS = 2;\nMySHelper.prototype.V_DIMMER = 3;\nMySHelper.prototype.V_PRESSURE = 4;\nMySHelper.prototype.V_FORECAST = 5;\nMySHelper.prototype.V_RAIN = 6;\nMySHelper.prototype.V_RAINRATE = 7;\nMySHelper.prototype.V_WIND = 8;\nMySHelper.prototype.V_GUST = 9;\nMySHelper.prototype.V_DIRECTION = 10;\nMySHelper.prototype.V_UV = 11;\nMySHelper.prototype.V_WEIGHT = 12;\nMySHelper.prototype.V_DISTANCE = 13;\nMySHelper.prototype.V_IMPEDANCE = 14;\nMySHelper.prototype.V_ARMED = 15;\nMySHelper.prototype.V_TRIPPED = 16;\nMySHelper.prototype.V_WATT = 17;\nMySHelper.prototype.V_KWH = 18;\nMySHelper.prototype.V_SCENE_ON = 19;\nMySHelper.prototype.V_SCENE_OFF = 20;\nMySHelper.prototype.V_HEATER = 21;\nMySHelper.prototype.V_HEATER_SW = 22;\nMySHelper.prototype.V_LIGHT_LEVEL = 23;\nMySHelper.prototype.V_VAR1 = 24;\nMySHelper.prototype.V_VAR2 = 25;\nMySHelper.prototype.V_VAR3 = 26;\nMySHelper.prototype.V_VAR4 = 27;\nMySHelper.prototype.V_VAR5 = 28;\nMySHelper.prototype.V_UP = 29;\nMySHelper.prototype.V_DOWN = 30;\nMySHelper.prototype.V_STOP = 31;\nMySHelper.prototype.V_IR_SEND = 32;\nMySHelper.prototype.V_IR_RECEIVE = 33;\nMySHelper.prototype.V_FLOW = 34;\nMySHelper.prototype.V_VOLUME = 35;\nMySHelper.prototype.V_LOCK_STATUS = 36;\nMySHelper.prototype.V_LEVEL = 37; \nMySHelper.prototype.V_VOLTAGE = 38; \nMySHelper.prototype.V_CURRENT = 39; \nMySHelper.prototype.V_RGB = 40; \nMySHelper.prototype.V_RGBW = 41;\nMySHelper.prototype.V_ID = 42;\nMySHelper.prototype.V_UNIT_PREFIX = 43;\nMySHelper.prototype.V_HVAC_SETPOINT_COOL = 44;\nMySHelper.prototype.V_HVAC_SETPOINT_HEAT = 45;\nMySHelper.prototype.V_HVAC_FLOW_MODE = 46;\nMySHelper.prototype.V_TEXT = 47;\n\nvar vtype = {\nV_TEMP: MySHelper.prototype.V_TEMP,\nV_HUM: MySHelper.prototype.V_HUM,\nV_STATUS: MySHelper.prototype.V_STATUS,\nV_LIGHT: MySHelper.prototype.V_LIGHT,\nV_DIMMER: MySHelper.prototype.V_DIMMER,\nV_PRESSURE: MySHelper.prototype.V_PRESSURE,\nV_FORECAST: MySHelper.prototype.V_FORECAST,\nV_RAIN: MySHelper.prototype.V_RAIN,\nV_RAINRATE: MySHelper.prototype.V_RAINRATE,\nV_WIND: MySHelper.prototype.V_WIND,\nV_GUST: MySHelper.prototype.V_GUST,\nV_DIRECTION: MySHelper.prototype.V_DIRECTION,\nV_UV: MySHelper.prototype.V_UV,\nV_WEIGHT: MySHelper.prototype.V_WEIGHT,\nV_DISTANCE: MySHelper.prototype.V_DISTANCE,\nV_IMPEDANCE: MySHelper.prototype.V_IMPEDANCE,\nV_ARMED: MySHelper.prototype.V_ARMED,\nV_TRIPPED: MySHelper.prototype.V_TRIPPED,\nV_WATT: MySHelper.prototype.V_WATT,\nV_KWH: MySHelper.prototype.V_KWH,\nV_SCENE_ON: MySHelper.prototype.V_SCENE_ON,\nV_SCENE_OFF: MySHelper.prototype.V_SCENE_OFF,\nV_HEATER: MySHelper.prototype.V_HEATER,\nV_HEATER_SW: MySHelper.prototype.V_HEATER_SW,\nV_LIGHT_LEVEL: MySHelper.prototype.V_LIGHT_LEVEL,\nV_VAR1: MySHelper.prototype.V_VAR1,\nV_VAR2: MySHelper.prototype.V_VAR2,\nV_VAR3: MySHelper.prototype.V_VAR3,\nV_VAR4: MySHelper.prototype.V_VAR4,\nV_VAR5: MySHelper.prototype.V_VAR5,\nV_UP: MySHelper.prototype.V_UP,\nV_DOWN: MySHelper.prototype.V_DOWN,\nV_STOP: MySHelper.prototype.V_STOP,\nV_IR_SEND: MySHelper.prototype.V_IR_SEND,\nV_IR_RECEIVE: MySHelper.prototype.V_IR_RECEIVE,\nV_FLOW: MySHelper.prototype.V_FLOW,\nV_VOLUME: MySHelper.prototype.V_VOLUME,\nV_LOCK_STATUS: MySHelper.prototype.V_LOCK_STATUS,\nV_LEVEL: MySHelper.prototype.V_LEVEL,\nV_VOLTAGE: MySHelper.prototype.V_VOLTAGE, \nV_CURRENT: MySHelper.prototype.V_CURRENT,\nV_RGB: MySHelper.prototype.V_RGB,\nV_RGBW: MySHelper.prototype.V_RGBW,\nV_ID: MySHelper.prototype.V_ID,\nV_UNIT_PREFIX: MySHelper.prototype.V_UNIT_PREFIX,\nV_HVAC_SETPOINT_COOL:MySHelper.prototype.V_HVAC_SETPOINT_COOL,\nV_HVAC_SETPOINT_HEAT:MySHelper.prototype.V_HVAC_SETPOINT_HEAT,\nV_HVAC_FLOW_MODE: MySHelper.prototype.V_HVAC_FLOW_MODE,\nV_TEXT: MySHelper.prototype.V_TEXT\n};\n\n\n\nMySHelper.prototype.VString = function(V_SUBTYPE) {\n for (var prop in vtype ) \n if( vtype[ prop ] === parseInt(V_SUBTYPE) )\n return prop;\n};\n \nMySHelper.prototype.VNum = function(V_SUBTYPE) {\n sRet = vtype [V_SUBTYPE];\n if (sRet === undefined)\n sRet = V_SUBTYPE;\n return sRet;\n}\n\nMySHelper.prototype.S_DOOR = 0; // Door sensor; V_TRIPPED; V_ARMED\nMySHelper.prototype.S_MOTION = 1; // Motion sensor; V_TRIPPED; V_ARMED \nMySHelper.prototype.S_SMOKE = 2; // Smoke sensor; V_TRIPPED; V_ARMED\nMySHelper.prototype.S_LIGHT = 3; // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT\nMySHelper.prototype.S_BINARY = 3; // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT (same as MySHelper.prototype.S_LIGHT)\nMySHelper.prototype.S_DIMMER = 4; // Dimmable light or fan device; V_STATUS (on/off); V_DIMMER (dimmer level 0-100); V_WATT\nMySHelper.prototype.S_COVER = 5; // Blinds or window cover; V_UP; V_DOWN; V_STOP; V_DIMMER (open/close to a percentage)\nMySHelper.prototype.S_TEMP = 6; // Temperature sensor; V_TEMP\nMySHelper.prototype.S_HUM = 7; // Humidity sensor; V_HUM\nMySHelper.prototype.S_BARO = 8; // Barometer sensor; V_PRESSURE; V_FORECAST\nMySHelper.prototype.S_WIND = 9; // Wind sensor; V_WIND; V_GUST\nMySHelper.prototype.S_RAIN = 10; // Rain sensor; V_RAIN; V_RAINRATE\nMySHelper.prototype.S_UV = 11; // Uv sensor; V_UV\nMySHelper.prototype.S_WEIGHT = 12; // Personal scale sensor; V_WEIGHT; V_IMPEDANCE\nMySHelper.prototype.S_POWER = 13; // Power meter; V_WATT; V_KWH\nMySHelper.prototype.S_HEATER = 14; // Header device; V_HVAC_SETPOINT_HEAT; V_HVAC_FLOW_STATE; V_TEMP\nMySHelper.prototype.S_DISTANCE = 15; // Distance sensor; V_DISTANCE\nMySHelper.prototype.S_LIGHT_LEVEL = 16; // Light level sensor; V_LIGHT_LEVEL (uncalibrated in percentage); V_LEVEL (light level in lux)\nMySHelper.prototype.S_ARDUINO_NODE = 17 ; // Used (internally) for presenting a non-repeating Arduino node\nMySHelper.prototype.S_ARDUINO_REPEATER_NODE = 18; // Used (internally) for presenting a repeating Arduino node \nMySHelper.prototype.S_LOCK = 19; // Lock device; V_LOCK_STATUS\nMySHelper.prototype.S_IR = 20; // Ir device; V_IR_SEND; V_IR_RECEIVE\nMySHelper.prototype.S_WATER = 21; // Water meter; V_FLOW; V_VOLUME\nMySHelper.prototype.S_AIR_QUALITY = 22; // Air quality sensor; V_LEVEL\nMySHelper.prototype.S_CUSTOM = 23; // Custom sensor \nMySHelper.prototype.S_DUST = 24; // Dust sensor; V_LEVEL\nMySHelper.prototype.S_SCENE_CONTROLLER = 25; // Scene controller device; V_SCENE_ON; V_SCENE_OFF. \nMySHelper.prototype.S_RGB_LIGHT = 26; // RGB light. Send color component data using V_RGB. Also supports V_WATT \nMySHelper.prototype.S_RGBW_LIGHT = 27; // RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT\nMySHelper.prototype.S_COLOR_SENSOR = 28; // Color sensor; send color information using V_RGB\nMySHelper.prototype.S_HVAC = 28; // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT; V_HVAC_SETPOINT_COLD; V_HVAC_FLOW_STATE; V_HVAC_FLOW_MODE; V_TEMP\nMySHelper.prototype.S_MULTIMETER = 29; // Multimeter device; V_VOLTAGE; V_CURRENT; V_IMPEDANCE \nMySHelper.prototype.S_SPRINKLER = 30; // Sprinkler; V_STATUS (turn on/off); V_TRIPPED (if fire detecting device)\nMySHelper.prototype.S_WATER_LEAK = 31; // Water leak sensor; V_TRIPPED; V_ARMED\nMySHelper.prototype.S_SOUND = 32; // Sound sensor; V_TRIPPED; V_ARMED; V_LEVEL (sound level in dB)\nMySHelper.prototype.S_VIBRATION = 33; // Vibration sensor; V_TRIPPED; V_ARMED; V_LEVEL (vibration in Hz)\nMySHelper.prototype.S_MOISTURE = 34; // Moisture sensor; V_TRIPPED; V_ARMED; V_LEVEL (water content or moisture in percentage?) \nMySHelper.prototype.S_INFO = 35; // LCD text device / Simple information device on controller; V_TEXT\nMySHelper.prototype.S_GAS = 36; // Gas meter; V_FLOW; V_VOLUME\nMySHelper.prototype.S_GPS = 37; // GPS Sensor; V_POSITION\n \nvar stype = {\nS_DOOR: MySHelper.prototype.S_DOOR, // Door sensor; V_TRIPPED; V_ARMED\nS_MOTION: MySHelper.prototype.S_MOTION, // Motion sensor; V_TRIPPED; V_ARMED \nS_SMOKE: MySHelper.prototype.S_SMOKE, // Smoke sensor; V_TRIPPED; V_ARMED\nS_LIGHT: MySHelper.prototype.S_LIGHT, // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT\nS_BINARY: MySHelper.prototype.S_BINARY, // Binary light or relay; V_STATUS (or V_LIGHT); V_WATT (same as MySHelper.prototype.S_LIGHT)\nS_DIMMER: MySHelper.prototype.S_DIMMER, // Dimmable light or fan device; V_STATUS (on/off); V_DIMMER (dimmer level 0-100); V_WATT\nS_COVER: MySHelper.prototype.S_COVER, // Blinds or window cover; V_UP; V_DOWN; V_STOP; V_DIMMER (open/close to a percentage)\nS_TEMP: MySHelper.prototype.S_TEMP, // Temperature sensor; V_TEMP\nS_HUM: MySHelper.prototype.S_HUM, // Humidity sensor; V_HUM\nS_BARO: MySHelper.prototype.S_BARO, // Barometer sensor; V_PRESSURE; V_FORECAST\nS_WIND: MySHelper.prototype.S_WIND, // Wind sensor; V_WIND; V_GUST\nS_RAIN: MySHelper.prototype.S_RAIN, // Rain sensor; V_RAIN; V_RAINRATE\nS_UV: MySHelper.prototype.S_UV, // Uv sensor; V_UV\nS_WEIGHT: MySHelper.prototype.S_WEIGHT, // Personal scale sensor; V_WEIGHT; V_IMPEDANCE\nS_POWER: MySHelper.prototype.S_POWER, // Power meter; V_WATT; V_KWH\nS_HEATER: MySHelper.prototype.S_HEATER, // Header device; V_HVAC_SETPOINT_HEAT; V_HVAC_FLOW_STATE; V_TEMP\nS_DISTANCE: MySHelper.prototype.S_DISTANCE, // Distance sensor; V_DISTANCE\nS_LIGHT_LEVEL: MySHelper.prototype.S_LIGHT_LEVEL, // Light level sensor; V_LIGHT_LEVEL (uncalibrated in percentage); V_LEVEL (light level in lux)\nS_ARDUINO_NODE: MySHelper.prototype.S_ARDUINO_NODE, // Used (internally) for presenting a non-repeating Arduino node\nS_ARDUINO_REPEATER_NODE:MySHelper.prototype.S_ARDUINO_REPEATER_NODE, // Used (internally) for presenting a repeating Arduino node \nS_LOCK: MySHelper.prototype.S_LOCK, // Lock device; V_LOCK_STATUS\nS_IR: MySHelper.prototype.S_IR, // Ir device; V_IR_SEND; V_IR_RECEIVE\nS_WATER: MySHelper.prototype.S_WATER, // Water meter; V_FLOW; V_VOLUME\nS_AIR_QUALITY: MySHelper.prototype.S_AIR_QUALITY, // Air quality sensor; V_LEVEL\nS_CUSTOM: MySHelper.prototype.S_CUSTOM, // Custom sensor \nS_DUST: MySHelper.prototype.S_DUST, // Dust sensor; V_LEVEL\nS_SCENE_CONTROLLER: MySHelper.prototype.S_SCENE_CONTROLLER, // Scene controller device; V_SCENE_ON; V_SCENE_OFF. \nS_RGB_LIGHT: MySHelper.prototype.S_RGB_LIGHT, // RGB light. Send color component data using V_RGB. Also supports V_WATT \nS_RGBW_LIGHT: MySHelper.prototype.S_RGBW_LIGHT, // RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT\nS_COLOR_SENSOR: MySHelper.prototype.S_COLOR_SENSOR, // Color sensor; send color information using V_RGB\nS_HVAC: MySHelper.prototype.S_HVAC, // Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT; V_HVAC_SETPOINT_COLD; V_HVAC_FLOW_STATE; V_HVAC_FLOW_MODE; V_TEMP\nS_MULTIMETER: MySHelper.prototype.S_MULTIMETER, // Multimeter device; V_VOLTAGE; V_CURRENT; V_IMPEDANCE \nS_SPRINKLER: MySHelper.prototype.S_SPRINKLER, // Sprinkler; V_STATUS (turn on/off); V_TRIPPED (if fire detecting device)\nS_WATER_LEAK: MySHelper.prototype.S_WATER_LEAK, // Water leak sensor; V_TRIPPED; V_ARMED\nS_SOUND: MySHelper.prototype.S_SOUND, // Sound sensor; V_TRIPPED; V_ARMED; V_LEVEL (sound level in dB)\nS_VIBRATION: MySHelper.prototype.S_VIBRATION, // Vibration sensor; V_TRIPPED; V_ARMED; V_LEVEL (vibration in Hz)\nS_MOISTURE: MySHelper.prototype.S_MOISTURE, // Moisture sensor; V_TRIPPED; V_ARMED; V_LEVEL (water content or moisture in percentage?) \nS_INFO: MySHelper.prototype.S_INFO, // LCD text device / Simple information device on controller; V_TEXT\nS_GAS: MySHelper.prototype.S_GAS, // Gas meter; V_FLOW; V_VOLUME\nS_GPS: MySHelper.prototype.S_GPS // GPS Sensor; V_POSITION\n};\n\nMySHelper.prototype.SString = function(S_SUBTYPE) {\n for (var prop in stype ) \n if( stype[ prop ] === parseInt(S_SUBTYPE) )\n return prop;\n}; \n \n MySHelper.prototype.encode = function(destination, sensor, command, acknowledge, type, payload) {\n\tvar msg = destination.toString(10) + \";\" + sensor.toString(10) + \";\" + command.toString(10) + \";\" + acknowledge.toString(10) + \";\" + type.toString(10) + \";\";\n\tif (command == 4) {\n\t\tfor (var i = 0; i < payload.length; i++) {\n\t\t\tif (payload[i] < 16)\n\t\t\t\tmsg += \"0\";\n\t\t\tmsg += payload[i].toString(16);\n\t\t}\n\t} else {\n\t\tmsg += payload;\n\t}\n\tmsg += '\\n';\n\treturn msg.toString();\n}\n}\n\n\nvar MySHelperObj = new MySHelper();\n\ncontext.global.MYS = MySHelperObj;\n\nreturn msg;","outputs":1,"noerr":0,"x":383.25,"y":20,"wires":[[]]},{"id":"df1e322.f20e1d","type":"function","z":"9592163f.6a6de8","name":"Set Controller 1","func":"msg.controller = 1\n\nreturn msg;","outputs":1,"noerr":0,"x":641.0000076293945,"y":147.49999809265137,"wires":[["ebcef3df.14311"]]},{"id":"266b87b3.d99478","type":"switch","z":"9592163f.6a6de8","name":"route to controller n","property":"controller","rules":[{"t":"eq","v":"1"},{"t":"eq","v":"2"},{"t":"eq","v":"3"},{"t":"eq","v":"4"}],"checkall":"false","outputs":4,"x":133,"y":214.25,"wires":[["3e866f6d.c1799"],["c7d0d88b.382f28"],[],[]]},{"id":"c7d0d88b.382f28","type":"tcp request","z":"9592163f.6a6de8","server":"192.168.92.14","port":"5003","out":"sit","splitc":"0","name":"MySWifi ESP8266 GW AES 14","x":410.5,"y":207.24999618530273,"wires":[["c5f14d8f.3a0eb"]]},{"id":"c5f14d8f.3a0eb","type":"function","z":"9592163f.6a6de8","name":"Set Controller 2","func":"msg.controller = 2\n\nreturn msg;","outputs":1,"noerr":0,"x":653.5,"y":205.7500114440918,"wires":[["ebcef3df.14311"]]},{"id":"56b9f6ab.a94608","type":"file in","z":"9592163f.6a6de8","name":"read store for next ids","filename":"mysids.dump","format":"utf8","x":395,"y":65,"wires":[["57db23d6.a824dc"]]},{"id":"e000bd09.1fff4","type":"debug","z":"9592163f.6a6de8","name":"Debug","active":false,"console":"false","complete":"true","x":732,"y":361,"wires":[]},{"id":"57db23d6.a824dc","type":"function","z":"9592163f.6a6de8","name":"store to context.global.mysnextid","func":"if (msg.payload === undefined) {\n var mysnextid = {};\n\n obj = mysnextid; \n}\nelse \n{\ntry{\n obj = JSON.parse(msg.payload);\n }\n catch(e){\n \n var mysnextid = {};\n\n obj = mysnextid;\n \n }\n} \n\ncontext.global.mysnextid = obj;\n\nmsg.payload = context.global.mysnextid;\n\nreturn msg;","outputs":1,"noerr":0,"x":658,"y":53,"wires":[[]]},{"id":"dfba7d69.20458","type":"file","z":"9592163f.6a6de8","name":"dump mysids","filename":"mysids.dump","appendNewline":true,"createDir":false,"overwriteFile":"true","x":1473,"y":381.99999618530273,"wires":[]},{"id":"e0e76d62.1f189","type":"function","z":"9592163f.6a6de8","name":"handle nextids","func":"// increase nextid, if nodeid >= nextid \n// node.log(\"Handling next ids\");\n// node.log(\"nodeId: \" + msg.nodeId);\n\nbChanged = false;\n\nif (msg.nodeId === 0) return;\n\nif (msg.nodeId < 255)\n{\n // node.log(\"Test if next node-id must be set\");\n if (context.global.mysnextid[msg.controller] === undefined) {\n node.log(\"node-id not initialized yet\");\n context.global.mysnextid[msg.controller] = msg.nodeId+1;\n if (context.global.mysnextid[msg.controller] < context.global.MYS.MIN_NODEID)\n context.global.mysnextid[msg.controller] = context.global.MYS.MIN_NODEID;\n bChanged = true;\n }\n \n // node.log(\"Nexid stored \" + parseInt(context.global.mysnextid[msg.controller]));\n \n if (msg.nodeId >= parseInt(context.global.mysnextid[msg.controller])) {\n node.log(\"node-id >= next -> increase\");\n // convert to int\n context.global.mysnextid[msg.controller] = parseInt(context.global.mysnextid[msg.controller]);\n context.global.mysnextid[msg.controller] = msg.nodeId+1; \n if (context.global.mysnextid[msg.controller] < context.global.MYS.MIN_NODEID)\n context.global.mysnextid[msg.controller] = context.global.MYS.MIN_NODEID;\n bChanged = true;\n }\n\n if (bChanged) {\n node.log(\"next id must be stored\");\n msg.payload = JSON.stringify(context.global.mysnextid); \n return msg;\n }\n}\n\n\n","outputs":1,"noerr":0,"x":1262,"y":374.99999618530273,"wires":[["dfba7d69.20458","5c074c19.a3f8b4"]]},{"id":"8da09002.725f7","type":"function","z":"9592163f.6a6de8","name":"MQTT to MYS convert","func":"// topic = MYS-NODERED/set/controller/node-id/sensor-id/ack/sub-type\n// payload = payload :)\n\n var tokens = msg.topic.split(\"/\");\n \n msg.rawData = tokens;\n msg.tokens = tokens.length;\n if(tokens.length == 7)\n {\n if (tokens[0] != context.global.MYS.TOPIC_PREFIX) // not for us\n return;\n if (tokens[1] != 'set') // not for us\n return;\n \n msg.controller = parseInt(tokens[2]);\n msg.messageType = context.global.MYS.T_SET;\n msg.nodeId = parseInt(tokens[3]);\n msg.childSensorId = parseInt(tokens[4]);\n msg.ack = parseInt(tokens[5]);\n msg.subType = context.global.MYS.VNum(tokens[6]);\n \n msg.payload = context.global.MYS.encode(msg.nodeId, msg.childSensorId, msg.messageType, msg.ack, msg.subType, msg.payload);\n \n return msg; \n }\n","outputs":1,"noerr":0,"x":490,"y":361,"wires":[["e000bd09.1fff4","266b87b3.d99478"]]},{"id":"3e866f6d.c1799","type":"tcp request","z":"9592163f.6a6de8","server":"192.168.92.13","port":"5003","out":"sit","splitc":"0","name":"MySWifi ESP8266 GW AES 13","x":407,"y":145.99999618530273,"wires":[["df1e322.f20e1d","9386fdb0.6c79"]]},{"id":"5c074c19.a3f8b4","type":"debug","z":"9592163f.6a6de8","name":"","active":true,"console":"false","complete":"false","x":1454,"y":543.9999961853027,"wires":[]},{"id":"c75fd7f4.38a028","type":"mqtt in","z":"9592163f.6a6de8","name":"Read MQTT Stream: change Topic to your needs","topic":"MYS-NODERED/set/#","broker":"ba386057.845d3","x":183.5,"y":362,"wires":[["8da09002.725f7"]]},{"id":"9386fdb0.6c79","type":"function","z":"9592163f.6a6de8","name":"Watchdog controller 1","func":"if (isNaN(context.global.controller1count))\n context.global.controller1count=0;\n\n\ncontext.global.controller1count++;\n\n","outputs":1,"noerr":0,"x":630,"y":105,"wires":[[]]},{"id":"d465a67.f2b9a58","type":"inject","z":"9592163f.6a6de8","name":"Check health controller 1 every 5 minutes","topic":"","payload":"","payloadType":"none","repeat":"60","crontab":"","once":false,"x":173,"y":516,"wires":[["aa935a.ff556ca8"]]},{"id":"aa935a.ff556ca8","type":"function","z":"9592163f.6a6de8","name":"check health controlller 1","func":"if (isNaN(context.global.controller1count))\n context.global.controller1count=0;\n \nif (context.global.controller1count === 0) {\n // make a new connection to the controller\n msg.payload = \"\";\n node.log(\"no message recieved on mys controller 1, try to connect\");\n \n return msg;\n}\nelse\n{\n // reset counter\n context.global.controller1count=0;\n}\n","outputs":1,"noerr":0,"x":470,"y":510,"wires":[["c8b342e9.374cc","3e866f6d.c1799"]]},{"id":"c8b342e9.374cc","type":"debug","z":"9592163f.6a6de8","name":"","active":true,"console":"false","complete":"false","x":682,"y":511,"wires":[]}]```
-
It's not spam. You can share your flow !
-
@FotoFieber keep going. Each time you post a new release I get it, even if i'm not using it :).
But it really gives ideas on what we can do with node-red.
Anyway thanks for your work and haring
-
@FotoFieber Please keep going. I always load the scripts to node-red to learn. Thanks
-
@FotoFieber
Great work, keep going! I have a modified version of your flow with message resend if not received - but it's a bit ugly to publish here.
-
Hello! I've not had a chance to update my blog with new updates. I'm busy with converting over my site to a pure node-red backend and being able to push updates via NR on my laptop via clone-flow. But that aside....
There's currently a regression in the newest serial port node in NR.
Arduino Nano->SerialGateway->NR->MySensors works with receiving data. However
Data->MySensors encoder->Serial is currently not working. It's NOT MySensors' fault. If I open up console on Serial gateway and an actuator, I can manually send commands and show that radio does in fact work.Where I am at now, is trying to figure out where the node-red-node-serial is in error. I know the recent node.js has caused havoc in the node-red ecosystem, mainly with hardware-to-node modules.
But I'm glad people are referencing my work thus far
The CrankyLinuxUser (whois for email/phone) if you have any further questions.
-
Ok. I think I finally got to the root of the issue. It's a mixture of "Inject" and mysdecenc errors. Inject mangles "\n" on the string inject node, and mysdecenc doesn't add the proper ending of the payload "\n" to complete the transmission from the gateway to the node.
I have a flow, and inside it is 2 duplicate paths of the same data. The upper one is a manual MySensors node-red node done with functions, and the lower is using the node-red-contri-mysensors nodes.
[{"id":"90402c72.682b08","type":"serial-port","z":"ec82138a.7e61d","serialport":"/dev/ttyUSB4","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"cbb9cba0.69cf1","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"500","payloadType":"string","repeat":"","crontab":"","once":false,"x":131,"y":274,"wires":[["7fb75e44.d87738"]]},{"id":"359a983d.9e87d8","type":"debug","z":"ec82138a.7e61d","name":"","active":true,"console":"false","complete":"true","x":800,"y":380,"wires":[]},{"id":"9a892a68.a4d97","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"1000","payloadType":"string","repeat":"","crontab":"","once":false,"x":131,"y":316,"wires":[["7fb75e44.d87738"]]},{"id":"473303a0.d810ec","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"0","payloadType":"string","repeat":"","crontab":"","once":false,"x":129,"y":233,"wires":[["7fb75e44.d87738"]]},{"id":"c84afb59.3425a8","type":"template","z":"ec82138a.7e61d","name":"convert to payload","field":"payload","format":"handlebars","template":"{{nodeId}};{{childSensorId}};{{subType}};{{messageType}};{{ack}};{{payload}}","x":544,"y":270,"wires":[["359a983d.9e87d8","6fc996d1.7babb"]]},{"id":"7fb75e44.d87738","type":"function","z":"ec82138a.7e61d","name":"Manual MySensors","func":"msg.nodeId = 10;\nmsg.childSensorId = 10;\nmsg.subType = 1;\nmsg.messageType = 1;\nmsg.ack = 3;\n\nmsg.payload = msg.payload + \"\\n\" ;\n\nreturn msg;","outputs":1,"noerr":0,"x":332,"y":270,"wires":[["c84afb59.3425a8"]]},{"id":"6fc996d1.7babb","type":"serial out","z":"ec82138a.7e61d","name":"","serial":"90402c72.682b08","x":818,"y":323,"wires":[]},{"id":"98c26eed.2fb63","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"500","payloadType":"string","repeat":"","crontab":"","once":false,"x":136,"y":431,"wires":[["952f68a.e0ff198"]]},{"id":"5d0a69be.2b841","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"1000","payloadType":"string","repeat":"","crontab":"","once":false,"x":136,"y":473,"wires":[["952f68a.e0ff198"]]},{"id":"f32d1e54.bde4b","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"0","payloadType":"string","repeat":"","crontab":"","once":false,"x":134,"y":390,"wires":[["952f68a.e0ff198"]]},{"id":"d3587219.c775c8","type":"mysencap","z":"ec82138a.7e61d","name":"","nodeid":"10","childid":"10","subtype":"3","internal":0,"ack":true,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":478,"y":427,"wires":[["cf568bb2.74a438"]]},{"id":"cf568bb2.74a438","type":"mysdecenc","z":"ec82138a.7e61d","name":"","x":618,"y":427,"wires":[["6fc996d1.7babb","359a983d.9e87d8"]]},{"id":"952f68a.e0ff198","type":"function","z":"ec82138a.7e61d","name":"slash n on payload","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":314,"y":427,"wires":[["d3587219.c775c8"]]}]
You will have to change the nodes to correspond to your actuators as well as your serial port. Aside that, with the appropriate fix, it works well.
/ Off to create my NeoPixel Node
-
@cranky
One small bugfix to your ToString function.//msg.payload = msg.payload.toString().replace(/[\n\r]/g, ''); // sometimes we are receiving a several messages in one packet // we should spit them and emit one by one var outputMsg = []; msg.payload = msg.payload || ''; msg.payload = msg.payload.toString(); var parts = msg.payload.split("\n"); for (var id in parts) { var payload = parts[id].replace(/[\n\r]/g, ''); if (payload.length > 0) { outputMsg.push({ payload: payload, controller: msg.controller }); } } return [outputMsg];
-
The flow you are giving feedback on is from @FotoFieber , not I
I was a wee confused, as my flow didn't have a string conversion like that in there. Now, the Router->2d array IP addresses on nodered.org does, but I didn't link that.
Here's that link: http://flows.nodered.org/flow/9b48db38d8c2bee59367 . If you have a crappy ATT router, you can get a nice list of machines.
-
@cranky
Yep - you are right
Does anybody had a problem with retained messages from mqtt broker?
Seems to me I am receiving only some retained messages from mosquitto - not all of them Looks like it's a bug in nodered mqtt or mosquitto.
-
Thx for the bugfix. I have observed this problem on some occations but it didn't hurt too much. Glad you found the bug.
-
@hek As a meta-discussion, would you be so kind as to create a Node-Red Controller Subcategory?
Since Rasberry-Pi's recent addition to Raspbian including NR on all installs, I think we're going to see a lot more questions regarding the nRF and MySensors. And frankly, NR is just amazing
-
Thank you much, @hek !
-
Node-red is great. I'd be interested in entire flows, entire integrations for home automation purposes (ofc with credentials data taken out). So if anyone has something interesting to show please share thanks
-
Someone here have a flow working with ACK messages ? And retry feature ? For example 5 retries before failling ?
-
@Fabien
Please help me understand your requirement.Ack from node to gateway are AFAIK handled by the gateway. So this is not your recquirement.
Then you are maybe looking to send messages from node-red to some nodes with the ack flag set and if you don't get the message back within xx seconds you want to have transmitted it again up to n times.
Is this your requirement?
If yes, what are xx and n?
-
Yes my requierement is to send ACK from node-red controller, wait 1s for the message back from the node and send it 5 times. If it's not ok I let the swtich (only example, it can be another actuator) in the last state. For only one message it's quite easy but when you want to handle multiple message (and sometimes the same command), it's more difficult to handle the queue correctly.
-
@FotoFieber do you have some examples of flows that someone could start from?
-
@gohan
Have you seen my controller flow?I have a multi-protocol setup and use sensors from zwave, homegear, netatmo, mysensors, sonoff, mystrom... All the messages are standardised and everything can talk to everything (in theory, wired via node-red). This setup is quite complex but very flexible. If you want to control mysensors-devices only, this may be to complicated.
Warning: following code was not intended for general usage by anyone else but me.
Here is a shortened excerpt of my generic mapping code:
[{"id":"c912e7c5.0e2cf8","type":"function","z":"9496189e.de6028","name":"Map Messages to Generic Messages (HA/)","func":"var mqtt2mqtt = \n{\n// Netatmo\n// - Indoor, TV\n\"netatmo/dashboard_data/Temperature\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":1, \"room\":\"tv\", \"type\":\"S_TEMP\",\"index\":0, \"unit\":\"V_TEMP\"},\n\"netatmo/dashboard_data/Humidity\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":1, \"room\":\"tv\", \"type\":\"S_HUM\",\"index\":0, \"unit\":\"V_HUM\"},\n// Haustüre\n\"homegear/1234-5678-9abc/plain/45/1/STATE\":\n {\"destination\":\"\",\"payloadTransformation\":\"OpenClose\",\"floor\":1, \"room\":\"entrance\", \"type\":\"S_DOOR\",\"index\":0, \"unit\":\"V_TRIPPED\"},\n\n// Philio Motion/Door\n// Treppenhaus oben\n// 21.0 C\n\"fhem/ZWave/ZWave_SENSOR_NOTIFICATION_13/temperature\":\n {\"destination\":\"\",\"payloadTransformation\":\"SplitFirst\",\"floor\":1, \"room\":\"staircase\", \"type\":\"S_TEMP\",\"index\":0, \"unit\":\"V_TEMP\"},\n//4 %\n\"fhem/ZWave/ZWave_SENSOR_NOTIFICATION_13/luminance\":\n {\"destination\":\"\",\"payloadTransformation\":\"SplitFirst\",\"floor\":1, \"room\":\"staircase\", \"type\":\"S_LIGHT_LEVEL\",\"index\":0, \"unit\":\"V_LIGHT_LEVEL\"},\n// MyStrom\n\n\"myStrom/Switch1/watt\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":0, \"room\":\"laundry\", \"type\":\"S_LIGHT\",\"index\":0, \"unit\":\"V_POWER\"},\n\"myStrom/Switch1/on\":\n {\"destination\":\"\",\"payloadTransformation\":\"False0True1\",\"floor\":0, \"room\":\"laundry\", \"type\":\"S_LIGHT\",\"index\":1, \"unit\":\"V_STATUS\"},\n\n// Heat Befehle des UI\n\"HEAT/bedroom laura\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":1, \"room\":\"bedroom laura\", \"type\":\"S_HEATER\",\"index\":0, \"unit\":\"V_HEATER_SW\", \"append\":\"/SET\"},\n\n\"HEAT/bedroom parents\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":1, \"room\":\"bedroom parents\", \"type\":\"S_HEATER\",\"index\":0, \"unit\":\"V_HEATER_SW\", \"append\":\"/SET\"},\n\n// Temp/Hum Stube\n\"MYS-NODERED/2/167/1/V_TEMP\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":1, \"room\":\"living room\", \"type\":\"S_TEMP\",\"index\":0, \"unit\":\"V_TEMP\"},\n\"MYS-NODERED/2/167/2/V_HUM\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":1, \"room\":\"living room\", \"type\":\"S_HUM\",\"index\":0, \"unit\":\"V_HUM\"},\n\"MYS-NODERED/2/167/0/V_LEVEL\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":1, \"room\":\"living room\", \"type\":\"S_AIR_QUALITY\",\"index\":0, \"unit\":\"MM_PPM\"},\n // Temp/Hum/CO2 Badezimmer\n\"MYS-NODERED/2/15/1/V_TEMP\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":1, \"room\":\"bathroom\", \"type\":\"S_TEMP\",\"index\":0, \"unit\":\"V_TEMP\"},\n\"MYS-NODERED/2/15/2/V_HUM\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":1, \"room\":\"bathroom\", \"type\":\"S_HUM\",\"index\":0, \"unit\":\"V_HUM\"},\n\"MYS-NODERED/2/15/0/V_LEVEL\":\n {\"destination\":\"\",\"payloadTransformation\":\"\",\"floor\":1, \"room\":\"bathroom\", \"type\":\"S_AIR_QUALITY\",\"index\":0, \"unit\":\"MM_PPM\"},\n\n};\n\n\nfunction payloadTransformation(payload, transformation) {\n if (transformation == \"OnOff\") {\n\t\tif (payload === 0) {\n\t\t\tpayload = 'OFF';\n\t\t} \n\t\telse\n\t\t{\n\t\t\tpayload = 'ON';\n\t\t}\n\t} else if (transformation == \"RemoveBrackets\") {\n\t\tpayload = payload.replace(\"[\",\"\");\n\t\tpayload = payload.replace(\"]\",\"\");\n\t} else if (transformation == \"NetatmoBatteryIndoor\") {\n\t /* Battery range: 6000 ... 4200 */\n // const INDOOR_BATTERY_LEVEL_0 = 5640;/*full*/\n // const INDOOR_BATTERY_LEVEL_1 = 5280;/*high*/\n // const INDOOR_BATTERY_LEVEL_2 = 4920;/*medium*/\n // const INDOOR_BATTERY_LEVEL_3 = 4560;/*low*/\n /* Below 4560: very low */\n if (payload >= 5640) {\n payload = 100;\n } else if (payload < 4560) {\n payload = 0;\n } else {\n payload = 100.0 * (payload - 4560) / (5640 - 4560);\n }\n\t} else if (transformation == \"NetatmoBatteryOutdoor\") {\n /* Battery range: 6000 ... 3600 */\n // const BATTERY_LEVEL_0 = 5500;/*full*/\n // const BATTERY_LEVEL_1 = 5000;/*high*/\n // const BATTERY_LEVEL_2 = 4500;/*medium*/\n //const BATTERY_LEVEL_3 = 4000;/*low*/\n /* below 4000: very low */\n if (payload >= 5500) {\n payload = 100;\n } else if (payload < 4000) {\n payload = 0;\n } else {\n payload = 100.0 * (payload - 4000) / (5500 - 4000);\n }\n\t} else if (transformation == \"HomegearBatteryLOWBAT\") {\n if (payload == '[false]') {\n payload = 100;\n } else {\n payload = 0;\n }\n\t} else if (transformation == \"SplitFirst\") {\n\t var tokens = payload.split(\" \");\n payload = tokens[0];\n\t} else if (transformation == \"StringMotion\") {\n\t upper = payload.toUpperCase();\n\t if (upper.search(\"MOTION\") > -1) {\n\t payload = 1;\n\t }\n\t else\n\t {\n\t payload = 0;\n\t }\n\t} else if (transformation == \"False0True1\") {\n\t payload = payload.replace(\"[\",\"\");\n\t\tpayload = payload.replace(\"]\",\"\");\n\t upper = payload.toUpperCase();\n\t if (upper.search(\"FALSE\") > -1) {\n\t payload = 0;\n\t }\n\t else if (upper.search(\"TRUE\") > -1)\n\t {\n\t payload = 1;\n\t }\n\t} else if (transformation == \"False1True0\") {\n\t payload = payload.replace(\"[\",\"\");\n\t\tpayload = payload.replace(\"]\",\"\");\n\t upper = payload.toUpperCase();\n\t if (upper.search(\"FALSE\") > -1) {\n\t payload = 1;\n\t }\n\t else if (upper.search(\"TRUE\") > -1)\n\t {\n\t payload = 0;\n\t } if (upper.search(\"0\") > -1) {\n\t payload = 1;\n\t }\n\t else if (upper.search(\"1\") > -1)\n\t {\n\t payload = 0;\n\t }\n\t} else if (transformation == \"Off0On1\") {\n\t upper = payload.toUpperCase();\n\t if (upper.search(\"OFF\") > -1) {\n\t payload = 0;\n\t }\n\t else\n\t {\n\t payload = 1;\n\t }\n\t} else if (transformation == \"StringClosed\") { // 1 wenn nicht closed (open)\n\t upper = payload.toUpperCase();\n\t if (upper.search(\"CLOSED\") > -1) {\n\t payload = 0;\n\t }\n\t else\n\t {\n\t payload = 1;\n\t }\n\t} else \tif (transformation == \"OpenClose\") {\n\t\tif (payload == '[true]') {\n\t\t\tpayload = 1;\n\t\t} \n\t\telse\n\t\t{\n\t\t\tpayload = 0;\n\t\t}\n\t}\n\treturn payload;\n}\n\nmapping = mqtt2mqtt[msg.topic];\n\nif (mapping === undefined) {\n\treturn;\n}\nelse if (mapping.destination === undefined)\n{\n var outputMsgs = [];\n for (var j = 0; j < mapping.length; j++){\n \n destination = mapping[j].destination;\n \n if (destination === \"\") {\n destination = \"HA/\" + mapping[j].floor + \"/\" + mapping[j].room + \"/\" + mapping[j].type + \"/\" + mapping[j].index + \"/\" + mapping[j].unit;\n }\n \n //\"floor\":1, \"room\":\"Bathroom\", \"type\":\"S_HUM\",\"index\":0, \"unit\":\"V_HUM\"\n //\n var createmsg = { \n topic: destination, \n value: payloadTransformation(msg.payload,mapping[j].payloadTransformation), \n floor: mapping[j].floor,\n room: mapping[j].room,\n type: mapping[j].type,\n index: mapping[j].index,\n unit: mapping[j].unit,\n append: mapping[j].append,\n timestamp: Date.now(),\n source: msg.topic\n };\n \n \n if(typeof mapping[j].append !== \"undefined\") {\n createmsg.topic += mapping[j].append; \n }\n \n outputMsgs.push({ topic: createmsg.topic,\n payload: createmsg});\n }\n\n return [ outputMsgs ];\n}\nelse\n{\n var outputMsgs = [];\n \n destination = mapping.destination;\n \n if (destination === \"\") {\n destination = \"HA/\" + mapping.floor + \"/\" + mapping.room + \"/\" + mapping.type + \"/\" + mapping.index + \"/\" + mapping.unit;\n }\n \n var createmsg = { \n topic: destination, \n value: payloadTransformation(msg.payload,mapping.payloadTransformation),\n floor: mapping.floor,\n room: mapping.room,\n type: mapping.type,\n index: mapping.index,\n unit: mapping.unit,\n append: mapping.append,\n timestamp: Date.now(),\n source: msg.topic\n };\n\n \n if(typeof mapping.append !== \"undefined\") {\n createmsg.topic += mapping.append; \n }\n \n \n outputMsgs.push({ topic: createmsg.topic,\n payload: createmsg});\n \n return [ outputMsgs ];\n \n}","outputs":1,"noerr":0,"x":430.81597900390625,"y":368.27081298828125,"wires":[[]]}]
I persist all the current values in a global state and use alasql to get values from it.
[{"id":"e4db6599.e95a68","type":"mqtt in","z":"82560a8c.4f93a8","name":"HA Messages","topic":"HA/#","qos":"2","broker":"26224260.2d8dde","x":176,"y":68,"wires":[["6c3867ae.e5a808"]]},{"id":"f8f5de85.ce073","type":"debug","z":"82560a8c.4f93a8","name":"","active":false,"console":"false","complete":"true","x":528,"y":70,"wires":[]},{"id":"5bb12e6f.3a271","type":"function","z":"82560a8c.4f93a8","name":"HA State -> context.global.hastate","func":"var hastate = {};\n\nif (context.global.hastate === undefined)\n{\n context.global.hastate = hastate;\n}\n\nhc = hashcode(msg.topic);\n\nmsg.payload.topichc = hc;\n\ncontext.global.hastate[msg.topic] = msg.payload;\n\nreturn msg;\n\nfunction hashcode(str) {\n var hash = 0, i, chr, len;\n if (str.length === 0) return hash;\n for (i = 0, len = str.length; i < len; i++) {\n chr = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + chr;\n hash |= 0; // Convert to 32bit integer\n }\n return hash;\n}","outputs":1,"noerr":0,"x":641,"y":126,"wires":[[]]},{"id":"f6c2ddcb.2d25b","type":"comment","z":"82560a8c.4f93a8","name":"Restore State from Mongo","info":"","x":181,"y":193,"wires":[]},{"id":"1b115bf9.64b9f4","type":"inject","z":"82560a8c.4f93a8","name":"Restore context.global.hastate from Mongo","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"x":266.25,"y":242,"wires":[["eaaa6edf.b5414"]]},{"id":"98fa3c0.77ffec8","type":"function","z":"82560a8c.4f93a8","name":"restore context.global.hastate","func":"context.global.hastate = {};\n\nvar erg = {};\n\nfor (var item in msg.payload) {\n var payload = msg.payload[item];\n var topic = payload.topic;\n //delete payload.topic;\n delete payload._id;\n payload.topichc = hashcode(topic);\n erg[topic] = payload;\n}\n\nmsg.payload = erg;\n\ncontext.global.hastate = msg.payload;\n\nreturn msg;\n\nfunction hashcode(str) {\n var hash = 0, i, chr, len;\n if (str.length === 0) return hash;\n for (i = 0, len = str.length; i < len; i++) {\n chr = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + chr;\n hash |= 0; // Convert to 32bit integer\n }\n return hash;\n}","outputs":1,"noerr":0,"x":1074.25,"y":240.75,"wires":[["a7df8317.f084b","8172bfbb.14412"]]},{"id":"c2eaa629.552f18","type":"mongodb in","z":"82560a8c.4f93a8","mongodb":"135c13e7.1b136c","name":"Status aus Mongo lesen","collection":"STATE","operation":"find","x":807.5,"y":240.75,"wires":[["98fa3c0.77ffec8","304fc7dd.6070a8"]]},{"id":"a7df8317.f084b","type":"debug","z":"82560a8c.4f93a8","name":"","active":false,"console":"false","complete":"false","x":1170.75,"y":126,"wires":[]},{"id":"46b56401.cc231c","type":"debug","z":"82560a8c.4f93a8","name":"","active":true,"console":"false","complete":"false","x":565,"y":539,"wires":[]},{"id":"fcde162a.b0bfe8","type":"inject","z":"82560a8c.4f93a8","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":143,"y":540,"wires":[["59bf7cc5.978df4"]]},{"id":"59bf7cc5.978df4","type":"function","z":"82560a8c.4f93a8","name":"context.global.hastate","func":"msg.payload = context.global.hastate;\n\nreturn msg;","outputs":1,"noerr":0,"x":367,"y":542,"wires":[["46b56401.cc231c"]]},{"id":"eaaa6edf.b5414","type":"function","z":"82560a8c.4f93a8","name":"limit und skip setzen","func":"msg.limit = 65000;\nmsg.skip = 0;\n\nreturn msg;","outputs":1,"noerr":0,"x":556,"y":243,"wires":[["c2eaa629.552f18"]]},{"id":"8172bfbb.14412","type":"function","z":"82560a8c.4f93a8","name":"HASTATE bereinigen-> älter als 7 Tage","func":"var i=0;\n\nfor (var erg in context.global.hastate) {\n payload = context.global.hastate[erg];\n if ((Date.now() - payload.timestamp)>1000*60*60*24*7) {\n delete context.global.hastate[erg]; \n i++;\n }\n}\n\nmsg.payload = i;\n\nreturn msg;","outputs":1,"noerr":0,"x":448,"y":297,"wires":[["c07188b0.618918"]]},{"id":"1e5a496b.e5cdf7","type":"inject","z":"82560a8c.4f93a8","name":"","topic":"","payload":"","payloadType":"date","repeat":"3600","crontab":"","once":false,"x":151,"y":296,"wires":[["8172bfbb.14412"]]},{"id":"c07188b0.618918","type":"debug","z":"82560a8c.4f93a8","name":"","active":true,"console":"false","complete":"false","x":719,"y":297,"wires":[]},{"id":"6c3867ae.e5a808","type":"json","z":"82560a8c.4f93a8","name":"","x":367.5,"y":130,"wires":[["5bb12e6f.3a271","f8f5de85.ce073"]]},{"id":"304fc7dd.6070a8","type":"debug","z":"82560a8c.4f93a8","name":"","active":true,"console":"false","complete":"false","x":918,"y":377,"wires":[]},{"id":"26224260.2d8dde","type":"mqtt-broker","z":"","broker":"192.168.92.5","port":"1883","clientid":"","usetls":false,"verifyservercert":false,"compatmode":false,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"1","willRetain":"false","willPayload":"","birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":""},{"id":"135c13e7.1b136c","type":"mongodb","z":"","hostname":"192.168.92.5","port":"27017","db":"HASTATE","name":"HASTATE"}]
-
With this standardisation, I can write simple adapters. Here is one for imperihome:
[{"id":"83e8531b.e90b4","type":"debug","z":"a5e97fda.4d467","name":"","active":true,"console":"false","complete":"payload","x":851.2857437133789,"y":251.00000286102295,"wires":[]},{"id":"ab451d5a.6cd2e","type":"http in","z":"a5e97fda.4d467","name":"","url":"/LG53/system","method":"get","swaggerDoc":"","x":190.2857437133789,"y":163.00000286102295,"wires":[["bc40a5db.70b1b8"]]},{"id":"7cd541a2.7f6ba","type":"http in","z":"a5e97fda.4d467","name":"","url":"/LG53/devices","method":"get","swaggerDoc":"","x":178.2857437133789,"y":236.00000286102295,"wires":[["fe9ee011.09dfa"]]},{"id":"247f001b.66de7","type":"http in","z":"a5e97fda.4d467","name":"","url":"/LG53/rooms","method":"get","swaggerDoc":"","x":169.2857437133789,"y":313.00000286102295,"wires":[["2ed87d9a.fe1cd2"]]},{"id":"cfc02ef5.b0a42","type":"http response","z":"a5e97fda.4d467","name":"","x":733.2857437133789,"y":194.00000286102295,"wires":[]},{"id":"bc40a5db.70b1b8","type":"function","z":"a5e97fda.4d467","name":"","func":"msg.payload = { \"id\": \"ISS:LG53:03\", \"apiversion\": 1};\nreturn msg;","outputs":1,"noerr":0,"x":431.2857437133789,"y":160.00000286102295,"wires":[["cfc02ef5.b0a42"]]},{"id":"40424d8c.d0dc34","type":"comment","z":"a5e97fda.4d467","name":"Imperihome","info":"","x":171.2857437133789,"y":119.00000286102295,"wires":[]},{"id":"a77d6fd5.c5549","type":"inject","z":"a5e97fda.4d467","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":157.2857437133789,"y":277.00000286102295,"wires":[["2ed87d9a.fe1cd2"]]},{"id":"2ed87d9a.fe1cd2","type":"function","z":"a5e97fda.4d467","name":"rooms from context.global.hastate","func":"var alasql = global.get('alasql');\n\n\nvar ha = context.global.hastate;\nvar disprooms = [\n {room:'bedroom parents',disp:'Eltern'}, \n {room:'bedroom laura', disp:'Laura'},\n {room:'bedroom baba',disp:'Baba'},\n {room:'living room',disp:'Wohnzimmer'},\n {room:'backyard',disp:'Garten hinten'},\n {room:'basement',disp:'Keller'},\n {room:'bathroom',disp:'Bad'},\n {room:'entrance',disp:'Eingang'},\n {room:'kitchen',disp:'Küche'},\n {room:'laundry',disp:'Waschküche'},\n {room:'staircase',disp:'Treppenhaus'},\n {room:'shower',disp:'Dusche'},\n {room:'toilet',disp:'Gäste WC'},\n {room:'tv',disp:'Fernsehraum'}\n ];\n \n//var res = alasql('SELECT [1]->payload FROM ? WHERE [1]->payload->room=?',[ha, room]);\n\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, disp.[1]->disp disp FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room ORDER BY 1',[ha,disprooms]);\n\n\n\nvar rooms = [];\n\nfor (var room in res) {\n rooms.push( \n {\n \"id\" : 'room_' + hashcode(res[room].room).toString(),\n \"name\" : res[room].disp || res[room].room\n }\n );\n}\n\nvar resp = { \"rooms\": rooms };\n\nmsg.payload = JSON.stringify(resp);\n\n//msg.payload = JSON.stringify(res);\n\n//msg.payload = {\"rooms\": [{ \"id\": \"roomID1\", \"name\": \"Test Room\" }]};\nreturn msg;\n\n\nfunction hashcode(str) {\n var hash = 0, i, chr, len;\n if (str.length === 0) return hash;\n for (i = 0, len = str.length; i < len; i++) {\n chr = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + chr;\n hash |= 0; // Convert to 32bit integer\n }\n return hash;\n}","outputs":1,"noerr":0,"x":473.2857437133789,"y":287.00000286102295,"wires":[["83e8531b.e90b4","cfc02ef5.b0a42"]]},{"id":"a6a951b8.fedbf","type":"inject","z":"a5e97fda.4d467","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":166.2857437133789,"y":200.00000286102295,"wires":[["fe9ee011.09dfa"]]},{"id":"15947c1c.319ae4","type":"function","z":"a5e97fda.4d467","name":"","func":"var alasql = global.get('alasql');\n\nvar ha = context.global.hastate;\n\nvar device = Number(msg.req.params.deviceID);\nvar startdate = Number(msg.req.params.startdate);\nvar enddate = Number(msg.req.params.enddate);\n\n\n//var startdate = 1463992263701;\n//var enddate = 1463992263701;\n\nvar topic = alasql('SELECT VALUE ha.[1]->topic FROM ? ha WHERE ha.[1]->topichc=?',[ha,device]);\n\nmsg.topic = topic;\nmsg.startdate = startdate;\nmsg.enddate = enddate;\n\nreturn msg;","outputs":1,"noerr":0,"x":511.2857437133789,"y":683.000002861023,"wires":[["e65fbae2.f30598"]]},{"id":"7331dd31.45cae4","type":"http in","z":"a5e97fda.4d467","name":"ISS Rest Actions History","url":"/LG53/devices/:deviceID/:paramKey/histo/:startdate/:enddate","method":"get","swaggerDoc":"","x":159.2857437133789,"y":611.000002861023,"wires":[["15947c1c.319ae4"]]},{"id":"8746e45c.4cd538","type":"http response","z":"a5e97fda.4d467","name":"","x":716.2857437133789,"y":534.000002861023,"wires":[]},{"id":"e6416541.255858","type":"inject","z":"a5e97fda.4d467","name":"","topic":"deviceid","payload":"1897446547","payloadType":"str","repeat":"","crontab":"","once":false,"x":319.2857437133789,"y":696.000002861023,"wires":[["15947c1c.319ae4"]]},{"id":"eb3d187d.5eae98","type":"influxdb in","z":"a5e97fda.4d467","influxdb":"ab6501aa.2f69a","name":"Get History from Influx","query":"","x":945.2857437133789,"y":758.000002861023,"wires":[["d55f902c.1a3b4"]]},{"id":"e65fbae2.f30598","type":"function","z":"a5e97fda.4d467","name":"Select History","func":"measurement = msg.topic.split('/').join('.');\n\nmsg.query = \"SELECT time, value FROM /\" + measurement + \"/ WHERE time >= \" + msg.startdate + \"ms AND time <= \" + msg.enddate +\"ms ORDER BY time\";\n\nreturn msg;","outputs":1,"noerr":0,"x":722.2857437133789,"y":760.000002861023,"wires":[["eb3d187d.5eae98","8b54b1c8.95d46"]]},{"id":"c01efb63.763dc8","type":"inject","z":"a5e97fda.4d467","name":"","topic":"deviceid","payload":"1897446547","payloadType":"str","repeat":"","crontab":"","once":false,"x":340.2857437133789,"y":768.000002861023,"wires":[["64f1c1c5.dbb0d"]]},{"id":"64f1c1c5.dbb0d","type":"function","z":"a5e97fda.4d467","name":"","func":"msg.topic = \"HA/0/bedroom baba/S_TEMP/0/V_TEMP\";\n\nmsg.startdate = 1463993343938;\nmsg.enddate = 1464166145880;\n \nreturn msg;","outputs":1,"noerr":0,"x":529.2857437133789,"y":758.000002861023,"wires":[["e65fbae2.f30598"]]},{"id":"6ca3314f.2e221","type":"debug","z":"a5e97fda.4d467","name":"","active":false,"console":"false","complete":"false","x":1262.285743713379,"y":758.000002861023,"wires":[]},{"id":"8b54b1c8.95d46","type":"debug","z":"a5e97fda.4d467","name":"","active":false,"console":"false","complete":"query","x":955.2857437133789,"y":847.000002861023,"wires":[]},{"id":"d55f902c.1a3b4","type":"function","z":"a5e97fda.4d467","name":"Convert to Imperihome Format","func":"erg = msg.payload[0];\n\nvar resp = [];\n\nfor (var i in erg) {\n var mesDate = new Date(erg[i].time);\n \n resp.push( \n {\n \"value\" : erg[i].value,\n \"date\" : mesDate.getTime()\n }\n );\n}\n\nmsg.payload = {\"values\": resp };\n\nreturn msg;","outputs":1,"noerr":0,"x":979.2857437133789,"y":634.000002861023,"wires":[["6ca3314f.2e221","8746e45c.4cd538"]]},{"id":"2003094c.594996","type":"debug","z":"a5e97fda.4d467","name":"","active":true,"console":"false","complete":"req.params","x":434.2857437133789,"y":471.00000286102295,"wires":[]},{"id":"7eb92db4.13ccf4","type":"http in","z":"a5e97fda.4d467","name":"ISS Rest Actions","url":"/LG53/devices/:deviceID/action/:actionName/:actionParam","method":"get","swaggerDoc":"","x":129.2857437133789,"y":469.00000286102295,"wires":[["2003094c.594996","70c707e7.138c18"]]},{"id":"70c707e7.138c18","type":"function","z":"a5e97fda.4d467","name":"","func":"var alasql = global.get('alasql');\n\nvar ha = context.global.hastate;\n\nvar device = Number(msg.req.params.deviceID);\n\nvar topic = alasql('SELECT VALUE ha.[1]->topic FROM ? ha WHERE ha.[1]->topichc=?',[ha,device]);\n\nvar output = {};\n\noutput.topic = \"imperihome/\"+topic+\"/\" + msg.req.params.actionName;\noutput.payload = msg.req.params.actionParam;\n\nreturn output;","outputs":1,"noerr":0,"x":285.2857437133789,"y":543.000002861023,"wires":[["59c69af0.4ef8e4"]]},{"id":"59c69af0.4ef8e4","type":"debug","z":"a5e97fda.4d467","name":"","active":true,"console":"false","complete":"false","x":455.2857437133789,"y":541.000002861023,"wires":[]},{"id":"fe9ee011.09dfa","type":"function","z":"a5e97fda.4d467","name":"devices from context.global.hastate","func":"var alasql = global.get('alasql');\n\nvar devices = [];\n\n\nvar ha = context.global.hastate;\nvar disprooms = [\n {room:'bedroom parents',disp:'Eltern'}, \n {room:'bedroom laura', disp:'Laura'},\n {room:'bedroom baba',disp:'Baba'},\n {room:'living room',disp:'Wohnzimmer'},\n {room:'backyard',disp:'Garten hinten'},\n {room:'basement',disp:'Keller'},\n {room:'bathroom',disp:'Bad'},\n {room:'entrance',disp:'Eingang'},\n {room:'kitchen',disp:'Küche'},\n {room:'laundry',disp:'Waschküche'},\n {room:'staircase',disp:'Treppenhaus'},\n {room:'shower',disp:'Dusche'},\n {room:'toilet',disp:'Gäste WC'},\n {room:'tv',disp:'Fernsehraum'}\n ];\n \n\n// Tür/Fenstersensoren\n\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_DOOR\" ORDER BY 1',[ha,disprooms]);\n\n\nfor (var device in res) {\n devices.push( \n {\n \"id\" : res[device].srcid,\n \"name\" : \"FT\" + res[device].idx + \" \" + (res[device].disp || res[device].room),\n \"type\" : \"DevDoor\", \n \"room\" : 'room_' + hashcode(res[device].room).toString(),\n \"params\": [{\"key\": \"Tripped\",\"value\": res[device].wert, \"graphable\": true}]\n }\n );\n}\n\n// Motion\n//var res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_MOTION\" ORDER BY 1',[ha,disprooms]);\n\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx, ABS(DATEDIFF(Minute, ha.[1]->`timestamp`,NOW())) minuten FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_MOTION\" ORDER BY 1',[ha,disprooms]);\n\n\nfor (var device in res) {\n if (res[device].minuten > 15) {\n motion = 0; \n } else\n {\n motion = 1;\n }\n \n devices.push( \n {\n \"id\" : res[device].srcid,\n \"name\" : \"MO\" + res[device].idx + \" \" + (res[device].disp || res[device].room),\n \"type\" : \"DevMotion\", \n \"room\" : 'room_' + hashcode(res[device].room).toString(),\n \"params\": [{\"key\": \"Tripped\",\"value\": motion, \"graphable\": true}]\n }\n );\n}\n\n// Temperatur\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_TEMP\" ORDER BY 1',[ha,disprooms]);\n\nfor (var device in res) {\n devices.push( \n {\n \"id\" : res[device].srcid,\n \"name\" : \"Temp\" + res[device].idx + \" \" + (res[device].disp || res[device].room),\n \"type\" : \"DevTemperature\", \n \"room\" : 'room_' + hashcode(res[device].room).toString(),\n \"params\": [{\"key\": \"value\",\"value\": res[device].wert, \"graphable\": true}]\n }\n );\n}\n\n// Feuchtigkeit\n\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_HUM\" ORDER BY 1',[ha,disprooms]);\n\nfor (var device in res) {\n devices.push( \n {\n \"id\" : res[device].srcid,\n \"name\" : \"Hyg\" + res[device].idx + \" \" + (res[device].disp || res[device].room),\n \"type\" : \"DevHygrometry\", \n \"room\" : 'room_' + hashcode(res[device].room).toString(),\n \"params\": [{\"key\": \"value\",\"value\": res[device].wert, \"graphable\": true}]\n }\n );\n}\n\n// CO2\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_AIR_QUALITY\" ORDER BY 1',[ha,disprooms]);\n\nfor (var device in res) {\n devices.push( \n {\n \"id\" : res[device].srcid,\n \"name\" : \"CO2\" + res[device].idx + \" \" + (res[device].disp || res[device].room),\n \"type\" : \"DevCO2\", \n \"room\" : 'room_' + hashcode(res[device].room).toString(),\n \"params\": [{\"key\": \"value\",\"value\": res[device].wert, \"graphable\": true}]\n }\n );\n}\n\n// BARO\n\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_BARO\" ORDER BY 1',[ha,disprooms]);\n\nfor (var device in res) {\n devices.push( \n {\n \"id\" : res[device].srcid,\n \"name\" : \"Luftdruck\",\n \"type\" : \"DevPressure\", \n \"room\" : 'room_' + hashcode(res[device].room).toString(),\n \"params\": [{\"key\": \"value\",\"value\": res[device].wert, \"graphable\": true}]\n }\n );\n}\n\n// Licht\n\n\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_LIGHT_LEVEL\" ORDER BY 1',[ha,disprooms]);\n\nfor (var device in res) {\n devices.push( \n {\n \"id\" : res[device].srcid,\n \"name\" : \"Licht\" + res[device].idx + \" \" + (res[device].disp || res[device].room),\n \"type\" : \"DevLuminosity\", \n \"room\" : 'room_' + hashcode(res[device].room).toString(),\n \"params\": [{\"key\": \"value\",\"value\": res[device].wert,\"unit\":\"%\", \"graphable\": true}]\n }\n );\n}\n\n// Noise\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_SOUND\" ORDER BY 1',[ha,disprooms]);\n\nfor (var device in res) {\n devices.push( \n {\n \"id\" : res[device].srcid,\n \"name\" : \"Lärm\" + res[device].idx + \" \" + (res[device].disp || res[device].room),\n \"type\" : \"DevNoise\", \n \"room\" : 'room_' + hashcode(res[device].room).toString(),\n \"params\": [{\"key\": \"value\",\"value\": res[device].wert, \"graphable\": true}]\n }\n );\n}\n\n// S_LIGHT -> V_POWWER, V_STATUS\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_LIGHT\" AND [1]->`unit` = \"V_STATUS\" ORDER BY 1',[ha,disprooms]);\n\nfor (var device in res) {\n devices.push( \n {\n \"id\" : res[device].srcid,\n \"name\" : \"Schalter\" + res[device].idx + \" \" + (res[device].disp || res[device].room),\n \"type\" : \"DevSwitch\", \n \"room\" : 'room_' + hashcode(res[device].room).toString(),\n \"params\": [{\"key\": \"Status\",\"value\": res[device].wert, \"graphable\": true}]\n }\n );\n}\n\nvar res = alasql('SELECT DISTINCT ha.[1]->room room, ha.[1]->`topichc` srcid, ha.[1]->`value` wert, disp.[1]->disp disp, ha.[1]->`index` idx FROM ? ha LEFT JOIN ? disp ON ha.[1]->room = disp.[1]->room WHERE [1]->`type` = \"S_LIGHT\" AND [1]->`unit` = \"V_POWER\" ORDER BY 1',[ha,disprooms]);\n\nfor (var device in res) {\n devices.push( \n {\n \"id\" : res[device].srcid,\n \"name\" : \"Watt\" + res[device].idx + \" \" + (res[device].disp || res[device].room),\n \"type\" : \"DevElectricity\", \n \"room\" : 'room_' + hashcode(res[device].room).toString(),\n \"params\": [{\"key\": \"Watts\",\"value\": res[device].wert, \"graphable\": true}]\n }\n );\n}\n\n\nvar resp = { \"devices\": devices };\n\nmsg.payload = JSON.stringify(resp);\n\n//msg.payload = JSON.stringify(res);\n\n//msg.payload = {\"rooms\": [{ \"id\": \"roomID1\", \"name\": \"Test Room\" }]};\nreturn msg;\n\n\nfunction hashcode(str) {\n var hash = 0, i, chr, len;\n if (str.length === 0) return hash;\n for (i = 0, len = str.length; i < len; i++) {\n chr = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + chr;\n hash |= 0; // Convert to 32bit integer\n }\n return hash;\n}","outputs":1,"noerr":0,"x":449,"y":222,"wires":[["cfc02ef5.b0a42"]]},{"id":"ab6501aa.2f69a","type":"influxdb","z":"a5e97fda.4d467","hostname":"127.0.0.1","port":"8086","database":"HA","name":"Storage for HA"}]
New sensors appear with this setup automagically in imperihome.
-
At the moment I'm just playing around with the dashboard. I'll look at it and for sure I'll let you know
-
@FotoFieber
I like your approach to a Node Red implementation of a home automation controller for MySensors. I understand that the code has grown to the point where it will no longer fit in a post. Could you please upload your code to your GitHub so that the whole program is visible?
I understand that your code may not be up to date for the latest version but what I've seen of your code has already helped to improve my MySensors 2.3.0 compatible version.Thank you.
-
FotoFieber has been kind enough to post his Node-Red controller on GitHub at: https://github.com/FotoFieber/MySensorsNodeRedController
The direct link to the code to import is: https://raw.githubusercontent.com/FotoFieber/MySensorsNodeRedController/master/README.md
Thank you very much @FotoFieber !
Once I complete a few of the pieces added from his code, I'll post mine as well but it will be a few weeks as I'm traveling now.
-
@chisight I attempted to use this code but node-red would not let me import. Checked the json online and it does not appear to be valid.
-
A little clean up in notepad++ and I have a working flow!
I made some modifcations (of course) for my setup. The main one is the ability to get the sensor value type. Initially the code in the Parse node did:// msg.topic = context.global.MYS.TOPIC_PREFIX + '/' + msg.controller + ' / ' + msg.nodeId + ' / ' + msg.childSensorId + ' / ' + msg.subTypeString; var tokens = msg.topic.split('/'); msg.rawData = tokens; if(tokens.length >= 5) { msg.controller = parseInt(tokens[1]); msg.nodeId = parseInt(tokens[2]); msg.childSensorId = parseInt(tokens[3]); msg.subTypeString = tokens[4]; msg.subType = context.global.MYS.VNum(msg.subTypeString); msg.command = 1; // SET msg.acknowledge = 0; // no ack as default } return msg;
I modified the msg.subType to use:
msg.subType = context.global.MYS.VString(msg.subTypeString);
Now to set this up to write to my DB.
Many thanks to @FotoFieber and @chisight
-
@wergeld said in Node-Red as Controller:
A little clean up in notepad++ and I have a working flow!
You need to import the raw file, not the "formatted" one that github presents. You can also download the .zip or git clone it.
This is all @FotoFieber, I did nothing but request they post it for us.
Thank you for the notes on the updates that you did.
-
@chisight I had done the raw file import. Issue I was facing was with the single/double quotes being interchanged. Easy fix. I am not sure if my "fix" for the VString was necessary. I just wanted to see what each sensor value was going to return. I need to get my DB setup a little better (using SQL Server as I cant stand the rigidness of time-series DBs like Influx).
-
@wergeld Odd, I went to the raw file, hit select all in Firefox and right click copy, then went to Node Red and did the import from clipboard, no edits. Maybe it's something related to Windows, I did mine through Debian.
Still, good to know that some paths need the single/double quotes repaired so thank you.