I use Node-Red for a lot of things and I have recently wanted to send notifications via SMS instead of an email, and I wanted to be able to receive SMS messages as well. I have had issues with the email node. It doesn’t always send for me (I’m using Google’s SMTP) and I don’t have a loud email notification on my phone. Because tons of emails thats why. But text messages on my phone have a very loud notification. I also wanted to be able to send messages to my Node-Red server, doing that via email is cumbersome. So texting it is. Plus sending/receiving an SMS is way cooler than a boring email. I know I can send texts to my phone via email (on most carriers) but that still requires using email and the email node. Don’t want to.
Enter Twilio. I have used Twilio before in the past with their free service tier and never got around to actually using it. The free service lets you do all the same stuff (I think) as the paid service but all the texts have a “This message was sent by Twilio – ” tag attached before every message. So I think thats why I never used it. Well I looked into it again and this time I just upgraded my account right away. Not fucking around. I just threw down $20 bucks. You buy a phone number for $1 per month and then you pay for all the messages you send. The cost per message (at this time) is somewhere around $0.0075 cents! Sweet! I figure I should be able to get a years worth of my number rental and a few messages off that $20 bucks.
So lets use Node-Red to send and receive an SMS with Twilio, it’s why you’re here right? Not for my ramblings.
To send an SMS from Node-Red is dead simple. Just install the Twilio node. It gives you a new output node. Just send you data to the node and off the SMS goes.
To be able to receive a message from Twilio your Node-Red needs to be accessible from the outside world. Twilio needs to be able to see the XML we are going to generate. In my searches for doing this I got a fucking headache. I found a few blogs out there with info on this but nothing concrete. It was actually pretty simple, at least for me. I have also already done this before in a previous post. I happen to run Apache for my web server, which is already setup and open to the world, DNS already setup. All I had to do was create a subdomain (not required) and point a the new vhost to my Node-Red server/install (via ProxyPass). Once this was done Twilio could access my Node-Red served pages. I also have (but I don’t think is required?) SSL already setup. I used Let’s Encrypt on my Apache server. However you do it is fine, you just need to be able to see at least 1-2 Node-Red generated pages from the web. I honestly found this to be one of the more pain in the ass tasks to deal with. Good luck.
The switch node checks msg.Body with msg.req.query.Body for an incoming command. If the switch matches a command it routes it to a function node. If it matches a command it also checks that command for an ON or OFF and outputs the results as a 1 or 0 for you to do with what you like. So you would text your Twilio number “mySwitch on” or “mySwitch off” and bam! Otherwise it passes it off to a different function node to process the message further. That node checks the incoming message for a global. By this I mean you text your Twilio number “read mySensor” and this function node sees the “read” command and then checks for a sensor name (mySensor). It matches this name against a global you have saved and spits back the results after being XML’d. So when you text “read mySensor” it checks the mySensor global and texts you back with “mySensor: yourvalue”. Awesome.
Tip: the switch node is case sensitive, so be careful. The function nodes change everything to caps I assume to simplify stuff I dunno. I didn’t write it. Also when you change the sensor name make sure to edit the substr to match the character limit of your sensor name. Example: WEMO would be 4, MYSWITCH is 8 characters. Same thing if you change the READ query.
Here’s the flow, I included a testing global for you as well:
1 |
[{"id":"2ae927d8.5bde18","type":"http in","z":"c0516cfd.4f261","name":"","url":"/twiliosms","method":"get","swaggerDoc":"","x":220,"y":740,"wires":[["4893a45a.60540c","f3d48024.a344"]]},{"id":"ef0e3c3c.3f3ea","type":"function","z":"c0516cfd.4f261","name":"Process SMS","func":"// Process SMS request and create a response\n// If SMS starts with READ (match is not case sensitive) then use REST to access\n// a global context to read a previously stored value from a sensor\n// If READ is not found then just it returns what you sent\n\nvar responseMsg = \"\";\nvar smsMsg = msg.req.query.Body;\n\nif( smsMsg.substr(0,4).toUpperCase() == \"READ\" ) {\n\tvar name = smsMsg.substr(4).trim();\n\tvar reading = context.global[name]; // This is where it grabs your global\n\tresponseMsg = name + \": \" + reading; // This is the message you will get\n} else {\n // This is the message you get if it cant find your global\n\tresponseMsg = \"You sent: \" + msg.req.query.Body;\n}\n\n// Create JSON object for payload response, and format it for Twilio\nvar messageObj = { \"Response\": { \"Sms\": responseMsg } };\n\n// Need to return received msg object, but with new payload\nmsg.payload = messageObj;\n\nreturn msg;\n","outputs":"1","noerr":0,"x":660,"y":760,"wires":[["13584066.d156","3379a357.0094dc"]]},{"id":"36410242.7bcd9e","type":"http response","z":"c0516cfd.4f261","name":"Send TwiML","x":1070,"y":760,"wires":[]},{"id":"f3d48024.a344","type":"switch","z":"c0516cfd.4f261","name":"Switch","property":"req.query.Body","propertyType":"msg","rules":[{"t":"cont","v":"mySwitch","vt":"str"},{"t":"nnull"}],"outputs":2,"x":450,"y":740,"wires":[["c5a4681b.783a88"],["ef0e3c3c.3f3ea"]]},{"id":"c5a4681b.783a88","type":"function","z":"c0516cfd.4f261","name":"Process mySwitch","func":"// Setup mySwitch message based on on/off received for mySwitch command\n\nvar smsMsg = msg.req.query.Body;\n\nif( smsMsg.substr(0,8).toUpperCase() == \"MYSWITCH\" ) {\n\tvar status = smsMsg.substr(8).trim();\n\tif( status.toUpperCase() == \"ON\" )\n\t\tmsg.payload = \"1\";\n\telse if( status.toUpperCase() == \"OFF\" )\n\t\tmsg.payload = \"0\";\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"x":670,"y":720,"wires":[["adb95e4a.d3065"]]},{"id":"adb95e4a.d3065","type":"debug","z":"c0516cfd.4f261","name":"","active":true,"console":"false","complete":"false","x":890,"y":720,"wires":[]},{"id":"13584066.d156","type":"xml","z":"c0516cfd.4f261","name":"","attr":"","chr":"","x":870,"y":760,"wires":[["36410242.7bcd9e"]]},{"id":"3379a357.0094dc","type":"debug","z":"c0516cfd.4f261","name":"","active":true,"console":"false","complete":"false","x":890,"y":800,"wires":[]},{"id":"4893a45a.60540c","type":"debug","z":"c0516cfd.4f261","name":"","active":true,"console":"false","complete":"false","x":470,"y":780,"wires":[]},{"id":"59868f57.52fd","type":"debug","z":"c0516cfd.4f261","name":"","active":true,"console":"false","complete":"false","x":890,"y":660,"wires":[]},{"id":"61bf58e6.a8c5c8","type":"globalGetSet","z":"c0516cfd.4f261","name":"mySensor","topic":"","context":"msg","variable":"payload","outContext":"global","outVar":"mySensor","x":640,"y":660,"wires":[["59868f57.52fd"]]},{"id":"51cda2d4.21bffc","type":"inject","z":"c0516cfd.4f261","name":"","topic":"","payload":"70.45","payloadType":"str","repeat":"","crontab":"","once":true,"x":450,"y":660,"wires":[["61bf58e6.a8c5c8"]]}] |
This is where I got the information on the Twilio node (from the creator it seems) and how to receive messages. But I found it about as clear as mud. (Note: the json2xml node doesn’t exist anymore. Just use the XML node now.)
http://blog.thiseldo.co.uk/?p=1090
Here is the original flow on flows.node.red.org, but its a little outdated.
http://flows.nodered.org/flow/d65e0c5e4f5fef767be2
Some other pages I found helpful along the way:
http://flows.nodered.org/flow/bce112d484f93a8c282a
https://groups.google.com/d/msg/node-red/YBVKXhJLI90/gUh3T-O6BAAJ
https://www.thethingsnetwork.org/forum/t/parse-data-with-node-red/835/9
http://noderedguide.com/node-red-lecture-3-basic-nodes-and-flows/
https://github.com/Leonidas-from-XIV/node-xml2js/issues/87
https://www.twilio.com/docs/api/twiml/sms/your_response
IVR with Twilio and Node-Red example flow
http://flows.nodered.org/flow/637b5f6128a8d423503f