MySensors v2: decode/send messages with Node-RED [Exclusive Guide]

12:02 pm November 4, 201612161

objects MySensors communicate with each other in the form of small text messages sent by radio waves. It is very easy to decode messages in following the technical specifications of the API available on the series official website of the project . The MySensors library allows to facilitate the development of applications of all kinds (mobile, robotics, home automation) without having to manage the communication between the devices layer. We use Node-RED to decode the messages received by a gateway network or series.

to learn more about the MySensors Bookstore, you can also read this article

MySensors communicates with small messages of 32 bytes (the maximum size of messages sent by a chip nRF24L01). Header (header) of the message is 7 bytes. It is composed thus:

node-id ; child-sensor-id ; message-type ; ack ; sub-type ; payload n

  • node-id: number of the node.
  • child-sensor-id: the identifier of a child. For example the temperature measured by a sensor DHT22.
  • message-type: type of message
    • 0. Presentation of the node. It is sent during execution of the function presentation() at the start of the node
    • 1. Set. Sending data by a sensor
    • 2. Req. Request to an actuator to execute the requested command
    • 3. Internal. Internal message
    • 4. Stream. Used to update wireless (OTA)
  • ack: request acknowledgement receipt (or acknowledgement)
  • sub-type: the subtype depends on the message type
  • payload: content of the message. It is limited to 25 bytes.

25 bytes may seem small, but the nRF24L01 is not designed to transmit large messages, States or physical measures.

there are two types of gateway MySensors. The serial gateway that plugs into the USB of a computer or a Raspberry. It is convenient to start and read the debugging messages sent on the serial port (for example with the monitor series of the Arduino IDE). The network gateway is now very simple (and cheap) to make using an ESP8266 (explanations in article ). You can install it (hide it!) in place or radio reception is better and it doesn’t hog a USB port of the Raspberry Pi.

serial gateway, gateway series on USB

to connect to a gateway series, add a Node (in Input) serial

Node-red serial node

open to set it up and press the pencil to configure the serial port. Press on the magnifying glass and choose the USB port on which the gateway is connected. For example/dev/ttyUSB0.

node-red serial liste gateway usb

node-red serial ok

the speed of communication with the gateway defaults to 115200 baud. Leave the default configuration. 8-bit Data, Parity None, Stop Bits 1.

node-red serial settings

save the configuration by pressing Done .

LAN Gateway, gateway network

to connect to a network gateway, we will use a Node TCP

node-red tcp mysensors lan gateway

configure the connection as well:

  • Type: Connect to
  • Port: 5003 by default (to adapt to your configuration)
  • at host : the ip address of the gateway resea.
  • output: stream of… String
  • name
  • save with Done

node-red tcp mysensors lan gateway settings parametres

the plugin node-red-contrib-mysensors developed by Thomas Mørch allows to decode messages MySensors and send to a node. He moved with this command

 npm install node-red-contrib-mysensors 

after installation, restart Node-RED with the following commands and refresh the browser.

 node-red-stop node-red-start 

you now have a new range called mysensors. It is composed of three Nodes

  • mysdecenc : encoder / decoder of messages MySensors
  • mysencap : prepares the message to send to the node
  • mysdebug : makes readable messages MySensors

function mysdebug

Let’s go by the end for once. The function mysdebug allows to decode and make it more readable messages in sent by the gateway. Each code is replaced by its meaning.

node-red mysensors mysdebug

decoded messages displayed in the console. Everything is not correctly decoded (in the current version of the plugin).

node-red mysensors mysdecenc mysdebug console log

this function allows to decode messages MySensors. to use, simply plug it into a gateway (series or network). Output (payload), we get directly the payload of each message. Every piece of available information is published on a different stream:

  • msg.payload : (payload) message sent by the node content
  • msg.nodeId : node from which the message
  • msg.childSensorId : Id of the child attached to the node
  • msg.messageType : type of message
  • msg.ack : request for acknowledgement
  • msg.subType : subtype of message

this architecture present advantages and disadvantages. We get directly output the payload of each message, but this can quickly become complicated to filter the data from any sensor.

node-red mysensors mysdecenc mysdebug

decoded messages displayed in the console.

node-red mysensors mysdecenc mysdebug console log

Code du flow

[{"id":"62351421.a2a7ec","type":"serial in","z":"eb4ead14.fd77f","name":"MySensors Serial Gateway","serial":"219cc581.f9b252","x":145.6666717529297,"y":134.66666412353516,"wires":[["2027984.714eb68","d8174c63.f752a"]]},{"id":"893c2411.1181e8","type":"debug","z":"eb4ead14.fd77f","name":"","active":false,"console":"false","complete":"payload","x":559,"y":35,"wires":[]},{"id":"d8174c63.f752a","type":"mysdecenc","z":"eb4ead14.fd77f","name":"","x":372.5,"y":36,"wires":[["893c2411.1181e8","80842fe1.74a72"]]},{"id":"80842fe1.74a72","type":"debug","z":"eb4ead14.fd77f","name":"","active":false,"console":"false","complete":"nodeId","x":559.5,"y":80 ,"wires":[]},{"id":"2027984.714eb68","type":"mysdebug","z":"eb4ead14.fd77f","name":"","x":374.5,"y":135,"wires":[["ed9596a0.eaa2b8"]]},{"id":"ed9596a0.eaa2b8","type":"debug","z":"eb4ead14.fd77f","name":"","active":false,"console":"false","complete":"false","x":561.5,"y":140,"wires":[]},{"id":"219cc581.f9b252","type":"serial-port","z":"","serialport":"/dev/ttyUSB0","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\n","bin":"false","out":"char","addchar":false}]

Fonction de décodage renvoyant un objet JSON

Je trouve plus facile et plus explicite de manipuler a JSON object. I developed a small function that you can add to your projects Node-RED. It decodes each message and created a JSON object to the key: value format.

node-red mysensors decoder projetsdiy

she reference a payload with the following information:

  • nodeId : Id of the node issuing the message
  • sensorId : Id of the child
  • mode : presentation, set, req, internal, stream
  • type: number of the subtype of data (depending on mode)
  • typeLabel : language of the type of data
  • value : content of the message (payload)

you can also install this flow from the official website of Node-RED http://flows.nodered.org/flow/fa02078c160cb3e00e09f4980b534490

 / * MySensors v2 Message Decoder * Payload: JSON object * www.projetsdiy.fr - oct. 2016 * / var mySensorsMessage = {} var newPayload = {};
var messaGE = msg.payload.toString ();
message = message.replace(/(rn|n|r)/gm, "");
var tokens = message.split(";") if(tokens.length == 6) {mySensorsMessage.nodeId = parseInt(tokens[0]);
    mySensorsMessage.childSensorId = parseInt(tokens[1]);
    mySensorsMessage.messageType = parseInt(tokens[2]);
    mySensorsMessage.ack = parseInt(tokens[3]);
    mySensorsMessage.subType = parseInt(tokens[4]);
    mySensorsMessage.value = Number(tokens[5]);

    var messageType = mySensorsMessage.messageType;
    var subType = mySensorsMessage.subType;
    var labelPresentation = ["S_DOOR","S_MOTION","S_SMOKE","S_LIGHT","S_BINARY","S_DIMMER","S_COVER","S_TEMP","S_HUM","S_BARO","S_WIND","S_RAIN","S_UV","S_WEIGHT","S_POWER","S_HEATER","S_DISTANCE","S_LIGHT_LEVEL","S_ARDUINO_NODE","S_ARDUINO_REPEATER_NODE","S_LOCK","S_IR","S_WATER","S_AIR_QUALITY","S_CUSTOM","S_DUST","S_SCENE_CONTROLLER","S_RGB_LIGHT","S_RGBW_LIGHT","S_COLOR_SENSOR","S_HVAC","S_MULTIMETER","S_SPRINKLER","S_WATER_LEAK","S_SOUND","S_VIBRATION","S_MOISTURE","S_INFO","S_GAS","S_GPS","S_WATER_QUALITY"];
    var labelSet = ["V_TEMP","V_HUM","V_STATUS","V_LIGHT","V_PERCENTAGE","V_DIMMER","V_PRESSURE","V_FORECAST","V_RAIN","V_RAINRATE","V_WIND","V_GUST","V_DIRECTION","V_UV","V_WEIGHT","V_DISTANCE","V_IMPEDANCE","V_ARMED","V_TRIPPED","V_WATT","V_KWH","V_SCENE_ON","V_SCENE_OFF","V_HVAC_FLOW_STATE","V_HVAC_SPEED","V_LIGHT_LEVEL","V_VAR1","V_VAR2","V_VAR3","V_VAR4","V_VAR5","V_UP","V_DOWN","V_STOP","V_IR_SEND","V_IR_RECEIVE","V_FLOW","V_VOLUME","V_LOCK_STATUS","V_LEVEL","V_VOLTAGE","V_CURRENT","V_RGB","V_RGBW","V_ID","V_UNIT_PREFIX","V_HVAC_SETPOINT_COOL","V_HVAC_SETPOINT_HEAT","V_HVAC_FLOW_MODE","V_TEXT","V_CUSTOM","V_POSITION","V_IR_RECORD","V_PH","V_ORP","V_EC","V_VAR","V_VA","V_POWER_FACTOR"] var labelInternal = ["I_BATTERY_LEVEL","I_TIME","I_VERSION","I_ID_REQUEST","I_ID_RESPONSE","I_INCLUSION_MODE","I_CONFIG","I_FIND_PARENT","I_FIND_PARENT_RESPONSE","I_LOG_MESSAGE","I_CHILDREN","I_SKETCH_NAME","I_SKETCH_VERSION","I_REBOOT","I_GATEWAY_READY","I_REQUEST_SIGNING","I_GET_NONCE","I_GET_NONCE_RESPONSE","I_HEARTBEAT","I_PRESENTATION","I_DISCOVER","I_DISCOVER_RESPONSE","I_HEARTBEAT_RESPONSE","I_LOCKED","I_PING","I_PONG","I_REGISTRATION_REQUEST","I_REGISTRATION_RESPONSE","I_DEBUG"] switch (messageType) {case 0: / / Presentation newPayload.mode = "Presentation";}
            newPayload.type = labelPresentation [subType];
            break;
        case 1: / / Set newPayload.nodeId = mySensorsMessage.nodeId;
            newPayload.sensorId = mySensorsMessage.childSensorId;
            newPayload.mode = "Set";
            newPayload.type = subType;
            newPayload.typeLabel = labelSet [subType];
            newPayload.value = mySensorsMessage.value;
            break;
        case 2: / / Req newPayload.nodeId = mySensorsMessage.nodeId;
            newPayload.sensorId = mySensorsMessage.childSensorId;
            newPayload.mode = "Req";
            newPayload.type = subType;
            newPayload.typeLabel = labelSet [subType];
            newPayload.value = mySensorsMessage.value;
            break;  
        case 3: / / Internal newPayload.nodeId = mySensorsMessage.nodeId;
            newPayload.sensorId = mySensorsMessage.childSensorId;
            newPayload.mode = "Internal";
            newPayload.type = subType;
            newPayload.typeLabel = labelInternal [subType];
            newPayload.value = mySensorsMessage.value;
            break;    
        box 4: / / Stream - OTA firmware update newPayload.nodeId = mySensorsMessage.nodeId;
            newPayload.mode = "stream";
            break;
        default: break;
    } msg.payload = newPayload; 
} else {msg.payload = "Error! Nothing to decode"} return msg; 

here’s what you get with the service. Each message is now explicit and formatted in the form of a JSON object easier to exploit in a project.
node-red mysensors decoder projetsdiy console log

you can modify according to your needs. {[

code of the flow

 [{"id":"61bbd468.bddf9c","type":"tcp in","z":"eb4ead14.fd77f","name":"MySensors Gateway","server":"client","host":"192.168.1.20","port":"5003","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"x":169.88886260986328,"y":226.92767333984375,"wires":[["f4fd4940.32ba8"]]}, {"id": "f4fd4940.32ba8", "type": "function", "z": "eb4ead14.fd77f", "name": "Decode MySensor Message", "func": "/ * MySensors v2 Message Decodern * Payload: JSON objectn * www.projetsdiy.fr - oct."} 2016n * / nvar mySensorsMessage = {nvar newPayload = {}; message = msg.payload.toString();nmessage = message.replace(/(\r\n|\n|\r)/gm, "");nvar = message.split(";")nif(tokens.length tokens nvar is 6) n {n mySensorsMessage.nodeId = parseInt(tokens[0]); n mySensorsMessage.childSensorId = parseInt(tokens[1]); n mySensorsMessage.messageType = parseInt(tokens[2]); n mySensorsMessage.ack = parseInt(tokens[3]); n mySensorsMessage.subType = parseInt(tokens[4]); n mySensorsMessage.value = Number(tokens[5]); nn var messageType = mySensorsMessage.messageType; n var subType = mySensorsMessage.subType; n var labelPresentation = ["S_DOOR","S_MOTION","S_SMOKE","S_LIGHT","S_BINARY","S_DIMMER","S_COVER","S_TEMP","S_HUM","S_BARO","S_WIND","S_RAIN","S_UV","S_WEIGHT","S_POWER","S_HEATER","S_DISTANCE","S_LIGHT_LEVEL","S_ARDUINO_NODE","S_ARDUINO_REPEATER_NODE","S_LOCK","S_IR","S_WATER","S_AIR_QUALITY","S_CUSTOM","S_DUST","S_SCENE_CONTROLLER","S_RGB_LIGHT","S_RGBW_LIGHT","S_COLOR_SENSOR","S_HVAC","S_MULTIMETER","S_SPRINKLER","S_WATER_LEAK","S_SOUND","S_VIBRATION","S_MOISTURE","S_INFO","S_GAS","S_GPS","S_WATER_QUALITY"]; n var labelSet = ["V_TEMP","V_HUM","V_STATUS","V_LIGHT","V_PERCENTAGE","V_DIMMER","V_PRESSURE","V_FORECAST","V_RAIN","V_RAINRATE","V_WIND","V_GUST","V_DIRECTION","V_UV","V_WEIGHT","V_DISTANCE","V_IMPEDANCE","V_ARMED","V_TRIPPED","V_WATT","V_KWH","V_SCENE_ON","V_SCENE_OFF","V_HVAC_FLOW_STATE","V_HVAC_SPEED","V_LIGHT_LEVEL","V_VAR1","V_VAR2","V_VAR3","V_VAR4","V_VAR5","V_UP","V_DOWN","V_STOP","V_IR_SEND","V_IR_RECEIVE","V_FLOW","V_VOLUME","V_LOCK_STATUS","V_LEVEL","V_VOLTAGE","V_CURRENT","V_RGB","V_RGBW","V_ID","V_UNIT_PREFIX","V_HVAC_SETPOINT_COOL","V_HVAC_SETPOINT_HEAT","V_HVAC_FLOW_MODE","V_TEXT","V_CUSTOM","V_POSITION","V_IR_RECORD","V_PH","V_ORP","V_EC","V_VAR","V_VA","V_POWER_FACTOR"] n var labelInternal = ["I_BATTERY_LEVEL","I_TIME","I_VERSION","I_ID_REQUEST","I_ID_RESPONSE","I_INCLUSION_MODE","I_CONFIG","I_FIND_PARENT","I_FIND_PARENT_RESPONSE","I_LOG_MESSAGE","I_CHILDREN","I_SKETCH_NAME","I_SKETCH_VERSION","I_REBOOT","I_GATEWAY_READY","I_REQUEST_SIGNING","I_GET_NONCE","I_GET_NONCE_RESPONSE","I_HEARTBEAT","I_PRESENTATION","I_DISCOVER","I_DISCOVER_RESPONSE","I_HEARTBEAT_RESPONSE","I_LOCKED","I_PING","I_PONG","I_REGISTRATION_REQUEST","I_REGISTRATION_RESPONSE","I_DEBUG"] n n switch (messageType) {n box} 0: / / Presentationn n newPayload.mode = "Presentation";n newPayload.type = labelPresentation [subType]; n break; n case 1: / / Setn newPayload.nodeId = mySensorsMessage.nodeId; newPayload.sensorId = n mySensorsMessage.childSensorId; n newPayload.mode = "Set";n newPayload.type = subType; n newPayload.typeLabel = labelSet [subType]; n newPayload.value = mySensorsMessage.value; n break; n case 2: / / Reqn newPayload.nodeId = mySensorsMessage.nodeId; newPayload.sensorId = n mySensorsMessage.childSensorId; n newPayload.mode = "Req";n newPayload.type = subType; n newPayload.typeLabel = labelSet [subType]; n newPayload.value = mySensorsMessage.value; n break;  n case 3: / / Internaln newPayload.nodeId = mySensorsMessage.nodeId; newPayload.sensorId = n mySensorsMessage.childSensorId; n newPayload.mode = "Internal";n newPayload.type = subType; n newPayload.typeLabel = labelInternal [subType]; n newPayload.value = mySensorsMessage.value; n break;    {n box 4: / / Stream - OTA firmware updaten newPayload.nodeId = mySensorsMessage.nodeId; newPayload.mode = "stream";n n break; n default:n break; n} nn msg.payload = newPayload; n} else {n msg.payload = "Error! Nothing to decode"n} nnreturn msg;","outputs":1,"noerr":0,"x":394.5555419921875,"y":279.5555725097656,"wires":[["22cb3401.ef7e24","2d12c5a2.7304aa","fd30fa09.244ce8"]]},{"id":"fd30fa09.244ce8","type":"debug","z":"eb4ead14.fd77f","name":"","active":true,"console":"false","complete":"false","x":628.5,"y":235,"wires":[]}]

La fonction mysencap

La dernière fonction mysencap proposée par le plugin permet de formater un message avant de le publier sur un noeud du réseau MySensors. We can send you want within the limits of 25 bytes. We should also add a return line ( n ) before you inject it into the function. For example, you can retrieve the State of a switch created with the plugin node-red-contrib-ui to turn on or turn off an Led (or a lamp by a relay). We will see this plugin in detail in a future tutorial.

Add a Node swich

http://www.projetsdiy.fr/wp-content/uploads/2016/10/17.-node-red-contrib-ui switch

give it a name. For the output value, enter 1 and 0 for Off. It’s not very important, it may very well leave True/False. It will take just to test the good value in the node MySensors Arduino code.

configuration switch node-red-contrib-ui

go to the page of interface at the address

 http://IP_NODE-RED:1880 / ui 

you now have a two-State switch.

node-red-contrib-ui switch mysensors

it remains more to prepare the message. Add a function and paste this code to add a return to the line.

 msg.payload = msg.payload + "n" return msg; 

then add a mysencap Node and specify the parameters of the destination of the message node. The type of message must be Request. Here is an example:

configuration mysencap node-red mysensors.

it remains more to inject into a Node mysdecenc before you send the message on a gateway (series or network) MySensors.

piloter relai led mysensors depuis node-red

add this code on the MySensor node to intercept messages sent to this object.

 void receive (const MyMessage & message) {Serial.print("Message recu pour le capteur:");
     Serial.print (message.sensor);
     Serial.print(", Nouveau statut:");
     Serial.println (message.getBool ()); 
} 

and, if the switch is pressed, one receives good messages on the node from the Node-RED flow.

node-red mysensors iot reception message receive

Le code du flow

[{"id":"f34523e0.fa94a","type":"mysdecenc","z":"e1e0f04d.8c404","name":"","x":546.388916015625,"y":276,"wires":[["a9d71461.a61de8"]]},{"id":"45e9c56a.b8cdec","type":"mysencap","z":"e1e0f04d.8c404","name":"","nodeid":"3","childid":"0","subtype":"2","internal":0,"ack":false,"msgtype":"2","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":400,"y":220.3333282470703,"wires":[["f34523e0.fa94a"]]},{"id":"a9d71461.a61de8","type":"tcp out","z":"e1e0f04d.8c404","host":"192.168.1.20","port":"5003","beserver":"client","base64":false ,"end":false,"name":"to MySensors","x":738,"y":232.3333282470703,"wires":[]},{"id":"d253489c.087998","type":"function","z":"e1e0f04d.8c404","name":"slash n","func":"msg.payload = msg.payload + "\n"nreturn msg;","outputs":1,"noerr":0,"x":274,"y":276.3333282470703,"wires":[["45e9c56a.b8cdec"]]},{"id":"af4ddcee.88eaf","type":"ui_switch","z":"e1e0f04d.8c404","tab":"6df01db6.d8538c","name":"Switch","topic":"","group":"","order":1,"onvalue":"1","offvalue":"0","x":149,"y":224.3333282470703,"wires":[["d253489c.087998"]]},{"id" [{"": "6df01db6.d8538c", "type": "ui_tab", "z": "","name": "Show", "icon": "store", "order": "1"}]