Blynk is great for using and control connected objects from your iOS or Android smartphone. If you have developed objects connected using the MySensors library to communicate over long distances using radio waves, it is very easy to return the data using Node-RED. This tutorial only deals with sending data from a MySensors probe. We will see in a next tutorial how to control MySensors actuators from the Blynk application.
Before you begin
If you do not already have Node-RED, follow the tutorial that corresponds to your environment:
- Install Node-RED on Windows or MacOS
- On Raspberry Pi, Raspbian distribution
- About Orange Pi, Armbian distribution
- Ubuntu 16.04LTS
You can also read this tutorial to learn how to easily manage modules.
Install node-red-contrib-blynk-websockets for Node-RED
Open the palette manager and do a search on the keyword Blynk. You should get 2 modules:
- Node-red-contrib-blynk
- Node-red-contrib-blynk-websockets. The npm page of the plugin is here
The first plugin (node-red-contrib-blynk) is now obsolete. It still works but will not receive any updates. Install the 2nd plugin node-red-contrib-blynk-websockets. Once the installation is complete, you will have a new palette composed of 4 tools
- read event: retrieve read events
- write event: retrieve write events
- write: allows to publish something on Blynk
- email: allows to use an email via the Blynk server
At the time of writing this article, the plugin is not yet documented. I had to look a bit. I’ll have to apologize if there are any errors. In any case do not hesitate to share if you have any other information than mine.
Using Node-RED as a gateway between MySensors and Blynk
Node-RED lends itself very well to this game. Apart from decoding the messages (the flow is lower) coming from the Gateway MySensors, there will be no programming. Here’s how we’ll do it:
- The sensor transmits the measurements by radio waves (2.4GHz) to the Gateway MySensors (follow this tutorial to make a WiFi network gateway).
- One connects to the MySensors network gateway from Node-RED using flow TCP/IP.
- MySensors are decoded
- Each measure is sent to the Virtual Ply of the Blynk project
- The Blynk server receives the data
- The mobile application connects to the Blynk server to retrieve the measurements
Connecting to the MySensors Gateway
To connect to a network gateway, we will use the TCP Node
Configure the connection as follows:
- Type: Connect to
- Port: 5003 by default (to suit your configuration)
- At host: the ip address of the network gateway
- Output: stream of … String
- Give a name
- Save with Done
Decode MySensors messages
In this tutorial we saw how to decode on-the-fly messages received by the MySensors gateway. We will use it again because we have to send the data individually to Blynk. Paste the decoder flow into your Node-RED project and connect it to the previously created TCP Node.
[{"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 Decoder\n* Payload : JSON object\n* www.projetsdiy.fr - oct. 2016\n*/\nvar mySensorsMessage = {}\nvar newPayload = {};\nvar message = msg.payload.toString();\nmessage = message.replace(/(\\r\\n|\\n|\\r)/gm, \"\");\nvar tokens = message.split(\";\")\nif(tokens.length == 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]);\n\n 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 case 0: // Presentation\n \n newPayload.mode = \"Presentation\";\n newPayload.type = labelPresentation[subType];\n break;\n case 1: // Set\n newPayload.nodeId= mySensorsMessage.nodeId;\n newPayload.sensorId= 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: // Req\n newPayload.nodeId= mySensorsMessage.nodeId;\n newPayload.sensorId= 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: // Internal\n newPayload.nodeId= mySensorsMessage.nodeId;\n newPayload.sensorId= mySensorsMessage.childSensorId;\n newPayload.mode= \"Internal\";\n newPayload.type= subType;\n newPayload.typeLabel= labelInternal[subType];\n newPayload.value= mySensorsMessage.value;\n break; \n case 4: // Stream - OTA firmware update\n newPayload.nodeId= mySensorsMessage.nodeId;\n newPayload.mode= \"stream\";\n break;\n default:\n break;\n }\n\n msg.payload = newPayload; \n} else {\n msg.payload = \"Error! Nothing to decode\"\n} \n\nreturn 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":[]}]
Installation of the gateway
Now that the messages are decoded, we will be able to extract what we are interested in and send it to Blynk. To do this, you need to retrieve the following information:
- The Token of the project on which you want to publish the data
- The virtual pins on which to send the data. Here it will be V0 for temperature and V1 for humidity
- The IP address of the Blynk server and the websocket port
Node-RED will communicate in Websocket with the Blynk server. For a non-secure link, the default port is 8082.
ws://IP_BLYNK_SERVER:8082/websocket
If you have your own local Blynk server, replace IP_BLYNK_SERVER with the IP address. If you used your official Blynk account, the server is cloud.blynk.cc.
Finally if you have set up an SSL certificate, you can secure the exchanges with Node-RED by logging onto the websocket
wss://IP_BLYNK_SERVER:9443/websocket
You can change the ports in the Blynk server.properties configuration file
In the Node-RED palette, search the keyword Blynk. Place the write Node on the flow
Press the pencil to the right of the pick list to add a connection
- Url: the url of the websocket
- Project key: the token to which the data is to be sent
- Name: give a name to the connection
- Save the configuration
Back in the Node write:
- Select the connection from the list.
- Indicate the virtual Pin (just the number).
- Give a name
- Save
Do the same for moisture. Connect the Node Write to the measurement extraction filter. Here’s what you need to get
The complete flow code
[{"id":"eb4ba8fd.56e7b8","type":"tcp in","z":"ae5a00f5.9de7a","name":"MySensors Gateway","server":"client","host":"192.168.1.20","port":"5003","datamode":"stream","datatype":"utf8","newline":"","topic":"","base64":false,"x":110,"y":120,"wires":[["6172d989.fe7678","c29897bf.f9dfc8"]]},{"id":"6172d989.fe7678","type":"function","z":"ae5a00f5.9de7a","name":"Decode MySensor Message","func":"/* MySensors v2 Message Decoder\n* Payload : JSON object\n* www.projetsdiy.fr - oct. 2016\n*/\nvar mySensorsMessage = {}\nvar newPayload = {};\nvar timestamp = new Date();\nvar message = msg.payload.toString();\nmessage = message.replace(/(\\r\\n|\\n|\\r)/gm, \"\");\nvar tokens = message.split(\";\")\nif(tokens.length == 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]);\n\n 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 case 0: // Presentation\n newPayload.timestamp = timestamp;\n newPayload.mode = \"Presentation\";\n newPayload.type = labelPresentation[subType];\n break;\n case 1: // Set\n newPayload.timestamp = timestamp;\n newPayload.nodeId= mySensorsMessage.nodeId;\n newPayload.sensorId= 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: // Req\n newPayload.timestamp = timestamp;\n newPayload.nodeId= mySensorsMessage.nodeId;\n newPayload.sensorId= 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: // Internal\n newPayload.timestamp = timestamp;\n newPayload.nodeId= mySensorsMessage.nodeId;\n newPayload.sensorId= mySensorsMessage.childSensorId;\n newPayload.mode= \"Internal\";\n newPayload.type= subType;\n newPayload.typeLabel= labelInternal[subType];\n newPayload.value= mySensorsMessage.value;\n break; \n case 4: // Stream - OTA firmware update\n newPayload.timestamp = timestamp;\n newPayload.nodeId= mySensorsMessage.nodeId;\n newPayload.mode= \"stream\";\n break;\n default:\n break;\n }\n\n msg.payload = newPayload; \n} else {\n msg.payload = \"Error! Nothing to decode\"\n} \n\nreturn msg;","outputs":1,"noerr":0,"x":380,"y":120,"wires":[["7652f827.9cb588","e74cb85e.1cd2f8"]]},{"id":"7652f827.9cb588","type":"function","z":"ae5a00f5.9de7a","name":"Filter: temperature ","func":"if (msg.payload.nodeId == 3 && msg.payload.type === 0) {\n var msg;\n msg.payload = msg.payload.value;\n msg.topic = \"Temperature\"\n return msg;\n} ","outputs":1,"noerr":0,"x":630,"y":80,"wires":[["78896415.6e454c"]]},{"id":"e74cb85e.1cd2f8","type":"function","z":"ae5a00f5.9de7a","name":"Filter: humidity","func":"if (msg.payload.nodeId == 3 && msg.payload.type === 1) {\n var msg;\n msg.payload = msg.payload.value;\n msg.topic = \"Humidity\"\n return msg;\n} ","outputs":1,"noerr":0,"x":620,"y":140,"wires":[["aa8a8b27.16b158"]]},{"id":"78896415.6e454c","type":"blynk-websockets-out-write","z":"ae5a00f5.9de7a","name":"Blynk -> V0 (Temperature)","pin":0,"client":"d94baf97.38207","x":870,"y":80,"wires":[]},{"id":"aa8a8b27.16b158","type":"blynk-websockets-out-write","z":"ae5a00f5.9de7a","name":"Blynk -> V1 (Humidity)","pin":"1","client":"d94baf97.38207","x":860,"y":140,"wires":[]},{"id":"d94baf97.38207","type":"blynk-websockets-client","z":"","name":"Blynk Local Server","path":"ws://192.168.1.24:8082/websocket","key":"ed151c7d8547497ea951d3c7ad87ebe8"}]
Deploy flow and open the Blynk application on your iOS or Android smartphone. You now receive data from your MySensors objects without any changes to their code.
- Integrate Arduino / ESP8266 + Blynk IoT to iOS with Homebridge and HomeKit
- Recycle a remote-controlled car (RC car) with an ESP8266, Shield Motor Wemos d1 mini and Blynk
- Connecting an ESP8266 to Blynk on WiFi with Johnny-Five (Firmata WiFi)
- IoT development based on Orange Pi, Arduino (Firmata), Nodejs, Blynk and Johnny-Five
- Blynk + Node.js + Johnny-Five: drive a Pan-Tilt PTZ SG90 kit on Orange Pi with an Arduino / Firmata
- Blynk + ESP8266: drive a Pan-Tilt PTZ SG90 in WiFi with a smartphone or tablet