Category Archives: node.js

Big Timer

tmp17DBBig Timer is probably the best timer for Node-Red, providing a general purpose timer as well as  handling summer/winter correctly as well as (importantly) lighting up time (for which it needs longitude and latitude). After all you probably don’t turn the outside lights on at 6pm!! You turn them on when it gets DARK.

Updated to v 1.5.6 –March 06, 2017 - Recommend updating. Here’s a new video!

BigTimers

What: Node-Red-Contrib-Bigtimer is both a simple timer – and a full-function timer – depending on your needs. At it’s simplest, you set on and off times, the topic and payload you need to go out to, say, MQTT and your longitude and latitude (most browsers will fill this in automatically), you then set your schedule and you are done.

Why: Existing timers didn’t do what I wanted – also – I have a watering system – I want it to run at dusk and dawn every day – but not in December through February (ice)!  I had to have control over both days of the week and months. Existing timers didn’t do that either. Many seemed to be based on the old mechanical timers but without moving parts. That won’t do.

Firstly: the name. It’s a timer – but it’s a BIG one – so I’ve called it BigTimer. (note: the original scheduler is no longer developed – BigTimer does everything Scheduler does and much, much more).

Secondly: it has an input. You can inject various words into BigTimer – and get instant over-ride action. "1" or “on”, "0" or “off”. "auto" or  “default” etc.

Does that need explaining? “on” for manual override to on, “off” for manual override to  off (both of which reset on the next auto state change), “default” or “auto” to return the timer to normal operation. More details later.

Manual Override: If you set the timer to turn on, say at dusk and off at midnight, you can override the setting during the day by sending “on” to the input. This override will reset at the next auto change of state.

If you inject "manual" in conjunction with  “on” and “off”, the state will change until the set timeout (in minutes) times out - so if you turn the lights on in manual and forget you did it? The unit will return to default operation in X minutes (which you can set - defaulting to 24 hours - 1440 minutes) after any manual change you make. You can also send a "sync" command which simply outputs the current state with a side effect of decrementing the timeout counter - handy for testing.

Here is a test setup for BigTimer, just using simply injection nodes:

BigTimer test setup

And here’s what happens if you press ON (a simple inject – you can send that message in the payload by any means you like)…

Bigtimer test setup[6]

But what are those other two outputs?

Output 1: is a message – you control the topic and payload – so I use it, for example, as I do, to send a message to MQTT to control something. You can have this message go out once – or every minute. There are other components to the msg object on the first output, there for information only.

Object

In this example (version 1.5.5 of Bigtimer onwards) you see various items in the output -also note that this view is in Node-Red 0.16.2 which is different to older versions – I strongly recommend you upgrade if using an earlier version.

You can see msg.payload which is whatever you enter in order to fire a message off to another node or function to make something happen. In addition (and for information only) we have msg.state, msg.value, msg.AutoState, msg.manualState and others. For simple use, you can of course ignore the additional outputs, but they are handy for checking. msg.state shows “on”, “off” or “none” and in the case of the first two (on/off) msg.time shows the time for the next change of state.

Output 2: outputs a 1 or 0 every minute when checking (in msg.payload) – you can use that to light up something.

Output 3: puts out another text message in msg.payload which you can set – I point it to a speech synth so it might say “external lighting coming on”. There is one message for the ON state, another for the OFF state. Ignore it if you don’t have a use for it.

And to get this node?

Make sure you are in your Node-Red installation folder (for example /home/pi/.node-red) and type:

npm install node-red-contrib-bigtimer

So in my case, I keep all my nodes under /home/pi/.node-red/node-modules.  So I do the install from /home/pi/.node-red

Restart Node-red and Bob’s your uncle – it should appear on the left with the other Nodes. If you happen to have the ADMIN node in Node-red you don’t even need to do any of that – you can install node-red-contrib-bigtimer straight from the admin tab.

In addition, I have recently,  as a response to a sensible request from one of our blog readers, changed the code so that if either the ON payload or OFF payload is blank – then no message will be sent at that time – this means you can now easily OR timers together. So if you need several time intervals in a day or other complicated setup you can simply use a number of timers and feel the first output to one common destination!

Here’s an example of TWO timers simply sending stuff to a debug node for testing…

two BIGTIMERS

Backtrack for Beginners: Node-Red is a simple-to-use but very powerful visual tool for wiring the Internet of Things and a tool for connecting together hardware devices, APIs and online services in new and interesting ways. It is also a lot of fun.

I control a range of Arduino and ESP-8266 devices using Raspberry PI2 and smiilar. You can of course run Node-Red and the other tools on a wide range of machines – Orange Pi, Roseapple Pi, Odroid C2 etc using Debian, DietPi, Xenial etc. I even have my normal installation script running on a laptop using Mint Linux.

tmp871On this particular Pi I run MQTT (Mosquito with Websockets), SQLITE, APACHE and Node-Red. I started using Blynk as my mobile remote controller then went on to using ImperiHome but today I concentrate on using Node-Red Dashboard which has (IMHO) so very much potential.  I also use Nextion touch-LCD display devices for local displays. All of this can be managed within Node-Red. If you find this interesting you might like my  home control 2016 post here or the Nextion Wi-Fi Touch Display article.

Here (as requested): to the right is a screenshot of a typical setup… click on the image to enlarge.

So in total you have a timer you can set to go on and off at specific times of the day, or dusk and dawn, on certain days, certain months, you can even set it to run on specific days of the month (Christmas day?) or even certain weekdays of every month (second Tuesday).

You can tick a box to have it output on power-up or not, you can tick a box to have it auto-repeat the message every minute or not. You can add positive and negative offsets to the times (including dusk and dawn etc.), you can optionally add your OWN offset to the UTC time of the host computer and you even select a random value within the limits of the offsets (security lighting etc.) You can temporarily suspend the schedule via a tick box or a message.

And here are the words the node will accept at the input to override automatic operations. The input is not case-sensitive.

sync simply forced output
on or 1 turn the output on
off or 0 turn the output off
default or auto return to auto state
stop stop the scheduler
on_override manually override the on time (in minutes or hours and minutes - space separated
off_override manually override the off time (in minutes or hours and minutes - space separated)

In the drop-down boxes for on and off times you can select times or words like dusk,dawn, sunrise, sunset, night etc. All are dependent on the longitude and latitude you put into the relevant boxes and will adjust every day as necessary.

A good way to learn about BigTimer is to put a debug node (set to show the complete message) on the top output – and inject text payloads (using the INJECT node) to the inputs as demonstrated above. 

Output from error and warnOut of the first output, as well as the normal msg.payload, you can extract msg.state which might be “on”, “off”, or “auto” – and msg.value which might be 1 or 0.  This is so that if you are using say, ImperiHome and store states in global variables, if the time reverts back to auto, you can let ImperiHome know what is happening.

Another way to test BigTimer a good way to do it is like this..

Big Timer Node

In the FUNCTION nodes to the right of BigTimer, I’ve simply put node.error(msg); and node.error(msg); respectively. The only difference is one has a red bar (error) the other a yellow bar (warn). These make a handy alternative to using the debug node for testing.

Recent additions to the inputs include on_override and off_override. These are in response to requests to be able to change the on and off times from the Dashboard. Please note that override information you inject here (in hours and minute or just minutes, space-delimited) is lost when Node-Red is restarted or the board rebooted.

If you make good use of this node – please put a link to this blog entry somewhere in your writings so people will come back here. Or if proves REALLY useful you could feed my Ebay habit – there’s a link on the right of the blog.

See the Node-Red info panel in Node-Red for up to date information.

Enjoy and please do report any issues back here.


If you like this post – please share a link to it by social media, by email with friends or on your website.
More readers means more feedback means more answers for all of us. Thank you!

Facebooktwittergoogle_pluspinterestlinkedin

NR Templates and the Inject Node

When testing Node-Red, the common INJECT node is invaluable. Indeed it is just about the only way to instantly inject information into another node. Here is a typical example.

Inject and Debug Nodes

It doesn’t get any simpler than this. Here I have merely dropped an “Inject” node onto the Node-Red working surface along with a “Debug” node. I’ve made no changes to either of them.  Note that “inject” and “debug” nodes come as standard with Node-Red.

Node-Red setup

Correctly set up, on the right of the Node-Red screen, you can see (or make available via the top-right three horizontal bars – view – “debug messages”) a debug window and simply by pressing that button-like item to the left of the inject node, you can put a timestamp into the debug window as such:

Debug window

Simple enough. Note that this says (in red) “msg.payload”.  In homage I guess to MQTT, the inject node outputs a simple object which deals primarily with msg.topic and msg.payload. You can use these for whatever messages you want.  The debug node by default shows only msg.payload but you can of course change this to show the entire message object.

Full debug message

Note that here (image above) we also see a blank topic (because the unmodified inject node has that as empty – you could put “Merry Christmas” in there if you like. Also included is _msgid which is of no interest to us for now unless you have a specific need for a unit number.

In general then,  you can fire out msg.topic and msg.payload from the inject node.  Instead of putting out a timestamp,  you can put out a string (for example “Hello world”) and this is output in msg.payload.

Hello world

Output Hello World

Expanding the INJECT output

For many purposes, we are done – you know know how to output a value into msg.payload and you can easily add msg.topic to that.  An inject node then can directly output data suitable for, say an MQTT node which needs both msg.topic and msg.payload.

For some purposes however, this is not enough.

Messages

In the above image, I need to inject one of two messages into a template. Easy enough, “message 1” as string into one injector, “message 2” into another. But what if we have a string of messages for different purposes going into that template?

On way to differentiate them would be to use topic.

if (msg.topic==”needle1”)  { /*use msg.payload to influence  a gauge needle */ }
if (msg.topic==”lcd”) { /* use msg.payload to influence a display */ }

Another way to do this is by putting a function node after the inject node…

msg.needle=msg.payload;

The output of this then, is your message sitting inside msg.needle instead of msg.payload.

Do-able but two things about that. Firstly you still can only output one message at a time and now you have the extra work and additional screen real estate used up for the additional function node. Not very elegant. If that works for you – stop here.

So what if we want a simpler way that may include sending multiple messages out at once.

In the inject.node you can’t change the name of “msg.payload” – but you can change what it outputs – a number, a string etc.. and in this case of particular interest, JSON.

Let’s take an example. Let’s say that by pressing the test button we want to set a needle value to 10 AND we want to send the message “hello” to an LCD display in our gauge.

Sending an object

Sending several messages in a JSON string

This LOOKS like you are sending a string of text but look what comes out – when you view the debug payload:

image

Not a string, but an object  - but how do you make use of this? Simple. In your template – or function or whatever you are firing this message into:

if (msg.payload.needle!==undefined) { /*make use of msg.payload.needle */ }
if (msg.payload.lcd!==undefined) { /* make use of msg.payload.lcd  */ }

This way, directly from a single inject node you can send either one, or several messages at once. The check for undefined means you don’t always have to send all of them.

Hence, for example, in testing my gauge, I can have a number of buttons testing  different parts of the gauge and one of them sending messages to both lines of the internal LCD at once without making a big mess of the screen. In the example below, the bottom two injects each send 2 different commands to the gauge when pressed.

Testing the gauge

But what about existing objects

Another way to send multiple messages through the injector allows you to make use of existing global objects…

Injecting objects

In this example, I happen to have an existing object called “thermostat” – which can be referred to as “context.global.thermostat” though the more modern way to do that is by use of global.get and global.put.

Armed with the above, which contains in this case lots of information about the state of my house… I can send that – either manually or of course in a timed fashion, to the debug node.

thermostat object

A little confusing at first until you notice the three dots at the bottom… which mean “I’m only showing you some of the result. Click on them and..

expanded object

Far too much information to display here – but I think you get the point – though msg.payload looks restrictive – in fact you can send a whole load of information thanks to the ability of the INJECT node to carry an object in msg.payload.

In this case, if you set DEBUG to look for msg.payload.desired you will indeed see a result of 23.

Can I create an object? Sure:

Test object creation

In this case – the content of the injector is irrelevant. Just drag it onto the screen.  Here we have (for the sake of it) two debug nodes – one is looking for msg.payload.actual and the other is looking for msg.payload.desired.

And here are the contents of that simple function node in the middle.

msg.payload={
desired:25,
actual:23
}
return msg;

Debugging:  Keith Howell wrote in to remind me about node.warn and node.error – two very handy debugging functions. Here’s an example of use…

node.warn

Again out of sheer laziness I’ve used the inject node on the left straight out of the box as it were. On the right the orange “test” function – again – drag from the left… double-click to open and enter the following:

node.warn("just info, really!");
node.error("ooh errr!");

and the result in the debug area when you press the timestamp button…

Debugging

Isn’t that handy – the only difference here being the colour – yellow for warning (I’d have used blue but hey ho) and red for error.  Using this instead of a debug node could save a little real estate on the screen in some cases.

Facebooktwittergoogle_pluspinterestlinkedin

LCD Display for Node-Red

Pete's LCDAs must be obvious by now, I’m on a roll here. Having decided that Node-Red Dashboard is the way forward ( would in the past have used BLYNK or Imperihome) I’ve been getting to grips with the dashboard and as you’ll see if you check recent blogs I’ve had a fair bit of success with various CANVAS based libraries, getting them into the Dashboard.

Pete's LCDAnd so it was that over the weekend, MrShark contacted me with this link – a very nice, simple stand-along clock display. Well, that fired me up and so I grabbed the code and started ripping it apart.  One thing led to another and here we have a nice LCD display programmable in a wide range of (I have to say stunning) colours and able to display temperature or weather icons on the right  – and in the process I learned a few things such as what position-absolute is all about and a great deal about transparency.

Pete's LCDIn the display here you see the use of border shadows, 7-segment display fonts and transparency to give the impression of an old-fashioned LCD display – I think it does a nice job.  The code here displays the time, date and day automatically and you can inject temperature into it – but a brief look and you’ll soon realise that you could put just about anything in there – so I look forward to feedback from readers.  To make this work, from the link above I had to grab 3 fonts (DSEG7Modern-Italic.woff,  DSEG14Modern-Italic.woff and DSEG7Modern-BoldItalic.woff – also required is  DSEGWeather.woff) from the link above (into myfonts – see previous blogs for the reason I made up directory names like myfonts and mycss etc).

Pete's LCDSo – here is the code to put into a Dashboard template – you just need to inject msg.payload to set the temperature OR weather icons depending on mode – see flow – most of this is just for you to experiment with.

tmp484EThere are several spans in here – all position absolute – which means they overlap and are all relative to the top left of the main DIV – the trick with the LCD is simply the 8 figure semi-transparent – with you number or letter sitting on top of it. Works a treat I should say.  You’ll want a 6*2 size for the template… but of course you may choose to resize this completely.

flow

tmpF88BAn important item include the z-index, I’ve used 50 and 51 arbitrarily – the original code this all came from used 100 and that ended up over-writing the Node-Red Dashboard menu! Of course if you don’t want to show temperature you could make that humidity or anything else really.

tmpA42CInjecting weather – see flow – includes: characters “0” to “9” for; background all segments, sun, cloud, rain, hard rain, snow, thunder rain, thunder hard rain, thunder, sun and cloud and finally “:” for all off.

Below is the code for the flow - make sure you have those fonts and inject this lot into a page in the dashboard - you'll need to change the tab details to suit yourself.

Oh, this page I found while looking for colour ideas…

[{"id":"5439cd84.a88ae4","type":"ui_template","z":"c552e8d2.712b48","group":"1e03a2b2.83a61d","name":"Time and Temp","order":0,"width":"6","height":"2","format":"<script>\n    var icon=\"T\";\n\n        \n    var colours={\n    \"blackOnOrange\": {items:[\"#222\",\"#fb7c00\"]},    \n    \"blackOnGreen\" : {items:[\"#222\",\"#66ac66\"]},\n    \"blackOnBlue\" : {items:[\"#222\",\"#8888ff\"]},\n    \"blackOnYellow\" : {items:[\"#222\",\"#bbbb44\"]},\n    \"blackOnWhite\" : {items:[\"#222\",\"#aaaaaa\"]},\n    \"blackOnPink\" : {items:[\"#222\",\"#ff8888\"]},\n    \"yellowOnRed\" : {items:[\"#ccaa22\",\"#aa2222\"]},\n    \"whiteOnCyan\" : {items:[\"#dddddd\",\"#227777\"]},\n    \"orangeOnBlack\" : {items:[\"#ff8800\",\"#000000\"]},  \n    \"limeOnBlack\" : {items:[\"#00cc55\",\"#000000\"]},  \n    }  \n    \n    var daylist = [\"sun\", \"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\"];\n    (function(scope){ \n            scope.$watch('msg', function(msg) {\n               if (typeof(msg.type) != \"undefined\") icon=msg.type;\n    \n               if (icon==\"t\")\n                    {\n                        $(\"#DSEGWEATHER-BACK\").text(\" \");\n                        $(\"#DSEGWEATHER-ICON\").text(\" \");\n                        $(\"#DSEGTempcF\").text(\"C\");\n                        $(\"#DSEGTempcB\").text(\"8\");                        \n                        if (typeof(msg.payload) != \"undefined\") { $(\"#DSEGTempF\").text(msg.payload);  $(\"#DSEGTempB\").text(\"88\"); }\n                    }\n                else\n                    {\n                        $(\"#DSEGTempF\").text(\"\");\n                        $(\"#DSEGTempcF\").text(\"\");\n                        $(\"#DSEGTempB\").text(\"\");\n                        $(\"#DSEGTempcB\").text(\"\");\n                        $(\"#DSEGWEATHER-BACK\").text(\"0\");\n                        if (typeof(msg.payload) != \"undefined\") $(\"#DSEGWEATHER-ICON\").text(msg.payload);\n                        \n                    }\n               if (typeof(msg.colour) != \"undefined\") {\n                              $(\".Clock-Wrapper\").css('background-color', colours[msg.colour].items[1]);  $(\".lcdClock\").css('color', colours[msg.colour].items[0]); \n                              if (colours[msg.colour].items[1]==\"#000000\") $(\".background\").css('color',\"rgba(255,255,255,0.15)\"); else  $(\".background\").css('color',\"rgba(0,0,0,0.1)\");\n                        }\n            });\n    })(scope);\n\n    function genTimerStrings(tm, num){\n    \n    \tvar i;\n    \tvar ret = tm.toString(10);\n    \tvar left = ret.length;\n    \n    \tif( left < num){\n    \t\tfor(i=0; i<( num - left ); i++ ){\n    \t\t\tret = String(0) + ret;\n    \t\t}\n    \t}\n    \treturn ret;\n    }\n\n    function updateTimer(){\n    \tvar ret;\n    \tvar date = new Date();\n    \tvar tm_year, tm_mon, tm_date, tm_hour, tm_min, tm_sec, tm_msec,tm_day;\n    \tvar colon;\n    \ttm_year = date.getFullYear();\n    \ttm_mon = date.getMonth()+1;\n    \ttm_date = date.getDate();\n    \ttm_day = date.getDay();\n    \ttm_hour = date.getHours();\n    \ttm_min = date.getMinutes();\n    \ttm_sec = date.getSeconds();\n    \ttm_msec = date.getMilliseconds();\n    \n    \ttm_mon = genTimerStrings(tm_mon, 2);\n    \ttm_date = genTimerStrings(tm_date, 2);\n    \ttm_hour = genTimerStrings(tm_hour, 2);\n    \ttm_min = genTimerStrings(tm_min, 2);\n    \ttm_sec = genTimerStrings(tm_sec, 2);\n    \ttm_day = daylist[tm_day];\n    \n    \tif( tm_msec > 499 ){\n    \t\tcolon = ' ';\n    \t}else{\n    \t\tcolon = ':';\n    \t}\n    \n    \tdocument.getElementById(\"DSEGClock\").innerHTML = tm_hour + colon + tm_min + \"<span style=\\\"font-size:30px;\\\">\"  + tm_sec + \"</span>\";\n    \tdocument.getElementById(\"DSEGClock-Year\").innerHTML = \"<span class=\\\"D7MI\\\">\" + tm_year + \"-\" + tm_mon + \"-\" + tm_date + ' ' + \"</span><span class=\\\"D14MI\\\">\" + tm_day  +  \".\" + \"</span>\";\n    \n    \tsetTimeout(\"updateTimer()\", 500 - date.getMilliseconds()%500 );\n    }\n\n    updateTimer();\n    \n</script>\n\n<style type=\"text/css\">\n.lcdClock {\n\tbackground-color:#fbfbfb;\n\tfont-size:100%;\n\tpadding-left:10px;\n\tpadding-right:10px;\n\tpadding-bottom:10px;\n\tmax-width:300px;\n\tline-height:160%;\n\tcolor:#222;\n\tfont-family:Meiryo, 'Lucida Grande','Hiragino Kaku Gothic ProN', sans-serif;\n}\n\n@font-face {\n  font-family: \"D7MI\";\n  src: url(\"/myfonts/DSEG7Modern-Italic.woff\") format('woff');\n}\n\n@font-face {\n  font-family: \"D14MI\";\n  src: url(\"/myfonts/DSEG14Modern-Italic.woff\") format('woff');\n}\n\n@font-face {\n  font-family: \"D7MBI\";\n  src: url(\"/myfonts/DSEG7Modern-BoldItalic.woff\") format('woff');\n}\n\n@font-face {\n  font-family: \"DWEATHER\";\n  src: url(\"/myfonts/DSEGWeather.woff\") format('woff');\n}\n\n.Weather-Background{\n\tz-index:50;\n\tposition:absolute;\n\ttop:24px;\n\tleft:226px;\n\tfont-size:68px;\n}\n\n.Weather-Front{\n\tz-index:51;\n\tposition:absolute;\n\ttop:24px;\n\tleft:226px;\n\tfont-size:68px;\n}\n\n.D7MI {\nfont-family: \"D7MI\";\n}\n\n.D7MBI {\nfont-family: \"D7MBI\";\n}\n\n.D14MI {\nfont-family: \"D14MI\";\n}\n\n.DWEATHER {\nfont-family: \"DWEATHER\";\nfont-size:68px;\nheight:68px;\n}\n\n.Clock-Wrapper{\n\tposition:relative;\n\tborder:6px solid #000;\n\tborder-radius:9px;\n\theight:68px;\n\twidth:280px;\n\tbackground-color:#fb7c00;\n\tbackground-color:#66ac66;\n\tbox-shadow: 4px 4px 28px 0px rgba(0,0,0,0.3) inset; \n}\n\n.Clock-Time-Background{\n\tz-index:50;\n}\n\n.Clock-Time-Front{\n\tz-index:51;\n}\n\n.Clock-Time-Background,.Clock-Time-Front {\n   \tposition:absolute;\n\ttop:38px;\n\tleft:5px; \n\tfont-size:42px;\n}\n\n.background { color:rgba(0,0,0,0.1); }\n\n.Clock-Year-Background{\n\tz-index:50;\n\tfont-size:18px;\n}\n\n.Clock-Year-Front{\n\tz-index:51;\n}\n\n.Clock-Year-Background,.Clock-Year-Front {\n   \tposition:absolute;\n\ttop:2px;\n\tleft:5px; \n\tfont-size:18px;\n}\n\n.temp { z-index:51; }\n.tempBack { z-index:50; color:rgba(0,0,0,0.1); }\n.temp,.tempBack {\n   \tposition:absolute;\n\ttop:28px;\n\tleft:210px; \n\tfont-size:42px;\n}\n\n.tempc { z-index:51; }\n.tempcBack { z-index:50;  }\n.tempc,.tempcBack {\n   \tposition:absolute;\n\ttop:36px;\n\tleft:278px; \n\tfont-size:24px;\n}\n\n#DSEG7_OUTPUT{\n\tfont-family: \"D7MI\";\n}\n\n#DSEG14_OUTPUT{\n\tfont-family: \"D14MI\";\n}\n\n#DSEG14_OUTPUT, #DSEG7_OUTPUT{\n\tfont-size:18px;\n\tmargin-top:2px;\n\tmargin-bottom:10px;\n}\n\n</style>\n\n\n<div class=\"Clock-Wrapper center lcdClock\">\n\t<span class=\"Clock-Time-Background background  D7MBI\">88:88<span style=\"font-size:30px;\">88</span></span>\n\t<span id=\"DSEGClock\" class=\"Clock-Time-Front D7MBI\"></span>\n\t<span class=\"Clock-Year-Background background\"><span class=\"D7MI\">2088-88-88</span><span class=\"D14MI\"> ~~~</span></span>\n\t<span id=\"DSEGClock-Year\" class=\"Clock-Year-Front\"></span>\n\t\n\t<span id=\"DSEGTempF\" class=\"temp D7MBI\">00</span>\n\t<span id=\"DSEGTempB\" class=\"tempBack background D7MBI\">88</span>\t\n\t<span id=\"DSEGTempcF\" class=\"tempc D7MI\">C</span>\n\t<span id=\"DSEGTempcB\" class=\"tempcBack background D7MI\">8</span>\n\t\n\t\n\t<span id=\"DSEGWEATHER-BACK\" class=\"Weather-Background background DWEATHER\"></span>\n\t<span id=\"DSEGWEATHER-ICON\" class=\"Weather-Front DWEATHER\"></span>\n\t\t\n</div>\n\n","storeOutMessages":true,"fwdInMessages":false,"x":480,"y":1480,"wires":[[]]},{"id":"e26a920b.fd916","type":"inject","z":"c552e8d2.712b48","name":"21c","topic":"","payload":"21","payloadType":"num","repeat":"","crontab":"","once":false,"x":90,"y":1220,"wires":[["5439cd84.a88ae4"]]},{"id":"a92b9b7a.795228","type":"inject","z":"c552e8d2.712b48","name":"32c","topic":"","payload":"32","payloadType":"num","repeat":"","crontab":"","once":false,"x":90,"y":1260,"wires":[["5439cd84.a88ae4"]]},{"id":"6d378317.dd743c","type":"inject","z":"c552e8d2.712b48","name":"green","topic":"","payload":"blackOnGreen","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1400,"wires":[["a23865de.5f59b8"]]},{"id":"24a314bf.90927c","type":"inject","z":"c552e8d2.712b48","name":"orange","topic":"","payload":"blackOnOrange","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1440,"wires":[["a23865de.5f59b8"]]},{"id":"a23865de.5f59b8","type":"function","z":"c552e8d2.712b48","name":"","func":"msg.colour=msg.payload;\nmsg.payload=undefined;\nreturn msg;","outputs":1,"noerr":0,"x":270,"y":1480,"wires":[["5439cd84.a88ae4"]]},{"id":"c8edfc9b.be6ce","type":"inject","z":"c552e8d2.712b48","name":"blue","topic":"","payload":"blackOnBlue","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1480,"wires":[["a23865de.5f59b8"]]},{"id":"18a1c3a.b9c283c","type":"inject","z":"c552e8d2.712b48","name":"yellow","topic":"","payload":"blackOnYellow","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1520,"wires":[["a23865de.5f59b8"]]},{"id":"a5c4dd24.4b6ff","type":"inject","z":"c552e8d2.712b48","name":"white","topic":"","payload":"blackOnWhite","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1560,"wires":[["a23865de.5f59b8"]]},{"id":"83e6ddc0.ec7bd","type":"inject","z":"c552e8d2.712b48","name":"pink","topic":"","payload":"blackOnPink","payloadType":"str","repeat":"","crontab":"","once":false,"x":90,"y":1600,"wires":[["a23865de.5f59b8"]]},{"id":"ebfd33d8.c8b13","type":"inject","z":"c552e8d2.712b48","name":"red and light text","topic":"","payload":"yellowOnRed","payloadType":"str","repeat":"","crontab":"","once":false,"x":120,"y":1640,"wires":[["a23865de.5f59b8"]]},{"id":"26972f6.8af94d","type":"inject","z":"c552e8d2.712b48","name":"cyan and white","topic":"","payload":"whiteOnCyan","payloadType":"str","repeat":"","crontab":"","once":false,"x":120,"y":1680,"wires":[["a23865de.5f59b8"]]},{"id":"10449ff5.d9588","type":"inject","z":"c552e8d2.712b48","name":"Type t for TEXT","topic":"","payload":"t","payloadType":"str","repeat":"","crontab":"","once":false,"x":120,"y":1760,"wires":[["fe927255.d2e2a"]]},{"id":"3e44785a.6181b8","type":"inject","z":"c552e8d2.712b48","name":"Type w for weather","topic":"","payload":"w","payloadType":"str","repeat":"","crontab":"","once":false,"x":130,"y":1800,"wires":[["fe927255.d2e2a"]]},{"id":"fe927255.d2e2a","type":"function","z":"c552e8d2.712b48","name":"","func":"msg.type=msg.payload;\nmsg.payload=undefined;\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":1740,"wires":[["5439cd84.a88ae4"]]},{"id":"94706c5b.a9292","type":"inject","z":"c552e8d2.712b48","name":"weather 2","topic":"","payload":"2","payloadType":"str","repeat":"","crontab":"","once":false,"x":100,"y":1299,"wires":[["5439cd84.a88ae4"]]},{"id":"77b95bb8.1ce774","type":"inject","z":"c552e8d2.712b48","name":"weather 3","topic":"","payload":"3","payloadType":"str","repeat":"","crontab":"","once":false,"x":100,"y":1339,"wires":[["5439cd84.a88ae4"]]},{"id":"30c75186.ef732e","type":"inject","z":"c552e8d2.712b48","name":"lime on black","topic":"","payload":"limeOnBlack","payloadType":"str","repeat":"","crontab":"","once":false,"x":110,"y":1720,"wires":[["a23865de.5f59b8"]]},{"id":"1e03a2b2.83a61d","type":"ui_group","z":"","name":"testy","tab":"f9bab960.c839b8","disp":true,"width":"6"},{"id":"f9bab960.c839b8","type":"ui_tab","z":"","name":"testy","icon":"dashboard"}]
Facebooktwittergoogle_pluspinterestlinkedin

RGraph with Node-Red

RGraph GaugeHaving gone from spending countless hours staring at HTML5 CANVAS, I’m now at the “meh” stage as it starts to dawn on my how it works.

And so it was that I stumbled on RGraph – or put another way, Christmas for widget-lovers.

If you’ve been following these blog entries you’ll know that Node-Red has TEMPLATES in the UI – and that you can put your own stuff into the templates and that recently the fog has lifted on getting variables in and out of the templates.

In recent blogs I’ve been constantly improving a thermostat control page and that took me off looking for a gauge with two pointers – one to show temperature, the other to show humidity.

And that’s when I stumbled upon RGraph. If you read this – and understand it – you will open the doors to a boatload of gauges, thermometers, charts and graphs so tuck in:

First things first, if you’ve already played with Node-Red in here you will likely have made a /myjs folder (home/pi/.node-red/public/myjs or similar – defined in your Node-Red settings.js file) to put various Javascript files in. Well, add this lot in a sub-folder called RGraph – you can call it freddy if you like but I thought it reasonable to use the name the way they use it. I grabbed the latest stable version from here. Inside there is a folder called RGraph – and inside that is a folder called libraries – I grabbed the contents of that folder and put it inside my /public/RGraph folder. It may be there is a use for other stuff in there – but for now that’s all I’ve taken.

So – then I dropped in a template – made it 6*6 and inside that template I put this lot – code shown below.

Now, if you don’t like my colours – change them. You can change just about anything including the size but you may need to adjust the font size if you do that. Experiment!

To change the two pointers – which I’ve chosen to call temperature and humidity – you might use them for petrol and oil – or whatever….I simply pass MSG as is common in Node-Red – but not msg.template – instead msg.temperature and msg.humidity – you can call them whatever you like.

The point of this is not to demonstrate my crap taste in colours – once you follow what I’ve done here – that entire, massive library of CANVAS-related gauges and charts is yours for the taking!  You can make the gauges interactive – but as I had two, not one pointers in this example, I skipped that. Details are in the extensive RGraph documentation.  Copy me and drop them an encouraging lines to say MORE IOT PLEASE!!

Oh and if you don’t like animation – where I say “grow” say “draw”.

(As an aside, I got this working today as well - https://www.codeproject.com/Articles/304874/HTML-Canvas-Aqua-Gauge)  very pretty but doesn’t scale well.

Prerequisites: Far too often in blogs like this we “assume” that everyone is keeping up – if not – may I suggest a quick look at this page I put up specifically to give a little background – which might help explain this article.

<script src="/myjs/RGraph/RGraph.common.core.js" ></script>
<script src="/myjs/RGraph/RGraph.gauge.js" ></script>

<script language="javascript" type="text/javascript">

           (function(scope){ 
                scope.$watch('msg', function(msg) {
                   gauge3.value=[msg.temperature,msg.humidity];
                   gauge3.grow();
                });
            })(scope);
            
            var gauge3 = new RGraph.Gauge({
                id: 'cvs',
                min: 0,
                max: 100,
                value: [23,60],
                options: {
                    titleTop: 'Temperature',
                    titleTopSize: '16',
                    titleTopFont: 'Impact',
                    titleTopColor: '#ff8888',
                    titleTopPos: 0.25,
                    titleBottom: 'Humidity',
                    titleBottomSize: '14',
                    titleBottomFont: 'Impact',
                    titleBottomColor: '#8888ff',
                    titleBottomPos: 0.3,
                    backgroundColor: 'black',
                    backgroundGradient: true,
                    centerpinColor: '#666',
                    needleSize: [null, 50],
                    needleColors: ['Gradient(transparent:yellow:orange:#ff8888:#ff8888)', 
                                    'Gradient(transparent:cyan:green:blue:blue)'],
                    textColor: 'white',
                    tickmarksBigColor: 'white',
                    tickmarksMediumColor: 'white',
                    tickmarksSmallColor: 'white',
                    borderWidth: 1,
                    borderOuter: '#666',
                    borderInner: '#3333',
                    colorsRanges: [
                                    [0,10,'rgba(0,0,255,0.6)'], 
                                    [10,20,'rgba(0,128,255,0.6)'], 
                                    [20,30,'rgba(0,255,255,0.6)'], 
                                    [30,40,'rgba(0,255,128,0.6)'], 
                                    [40,50,'rgba(0,255,0,0.6)'], 
                                    [50,60,'rgba(128,255,0,0.6)'], 
                                    [60,70,'rgba(255,255,0,0.6)'], 
                                    [70,80,'rgba(255,128,0,0.6)'],                                                                                                                                                 
                                    [80,90,'rgba(255,64,0,0.6)'],   
                                    [90,100,'rgba(255,0,0,1']
                                  ],
                    textAccessible: true
                }
            });
            gauge3.grow();

    </script>

    <canvas id="cvs" width="300" height="300">[No canvas support]</canvas>
 
Facebooktwittergoogle_pluspinterestlinkedin

Node-Red Objects to File and Back

This is a major re-write of a year-old blog. At the time, I simply wanted to store a global object in a file and retrieve it. Things have changed, I realise the way we did this was awful – hence the re-write.

One way is to save the object as a persistent message in MQTT - another to a database, another to a file. I like the idea of a file as somehow it just seems that this will lead to the least WRITES – and that might be important for SD.

Why would you want to do this? Well, specifically my own requirement is to save the state of a home control object which has all sorts of info about a heading system. Let's call the object "thermostat" and it may have all sorts of innards -"thermostat.temperature", "thermostat.set", "thermostat.fallback" etc. In my case about 20 items. Not something you want to split up into individual variables.  I used this as I have 2 parts of the house with separate heating and so I could duplicate all the code simply using two separate objects. I need to store them on disk when changes are made - and retrieve them on power up.

And this is where the original article went wrong...

The easy and obvious way is to use an inject node which runs once only on startup - to feed a file function - which gets the contents of the file - and stores them into an object. Now - you need to do this in the LEFT-MOST tab in Node-Red as this is executed first - before any other tabs - so you get to define the object BEFORE it gets used.

That's not the end of it of course - what happens if this is a new installation and the file does not exist? Well, in that case, you check for the "undefined" object coming out of the file node - create the object with defaults - and store the result in the (new) file. Easy. And that's what this article was originally about.

Except that on close inspection - it didn't work. Originally, Node-Red didn't guarantee that the left-most tab would work first - now it does run first. But that still didn't get it - when I started looking - there were (non-fatal) error messages showing that clearly the object was being used before it had been defined!

Now, why would that be? The answer lies in the fact that (just about) everything in Node-Red is asynchronous - i.e. it does not hang around to wait. So here I was using a file input node assuming the file would be opened - and my function would be executed before anything else. Nooooo.  The file node accepts the command to open a file - but then while it is waiting for this - other things can happen - that is, other flows can run which is EXACTLY what I did NOT want to happen. My thanks to the guys at the Node-Red Google forums for that insight.

The solution is simple once you now what the problem is. Firstly we need a function (which I made into a sub-flow) which takes in a file path, opens up the file and returns either the contents of the file in the payload or returns "undefined" if the file is not there - just as the normal file-in node would do... but synchronously.

There is also the matter of SAVING an updated object – I’ve used a second timer for that – one which checks every second – but NOT at the start. It simply outputs the text “check. So – at the start, the file is read, if it is not there, “undefined” is returned.

If “undefined” then create the object and store it. If defined, read it. If “check” – check if object.counter is true and if so decrement it – if now zero, update the object to disk. By doing this all in the same place, a lof of code duplication is avoided. Indeed as I have TWO thermostats I can use the same code with a different object and re-use one of the timers.

update objects to and from disk

Read file sync is a sub-flow – could just as easily be a function – but I put it in a sub-flow as the content is the same every time – it is the initial inject that is passing the file name.  The two (orange functions are the same other than the actual object name (thermostat and office_thermostat).

Here’s the content of the function at the heart of Read File Sync

var fs=global.get("fs");
try {
msg.payload = fs.readFileSync(msg.payload).toString();
}
catch (ex)
{
msg.payload=undefined;    
}
return msg;

And here is my code in the orange top function – the brown item on the right is just a file write node. Clearly this is for my particular application but you should get the general idea..

if (msg.payload===undefined) // if the file was not valid - create the object, predefine, store
    {
       var stat = {
        max_humidity : 100,
        display_temperature : 22,
        desired : 22,
        display_humidity : 45,
        heating : 0,
        display_external_temperature : 14,
        display_external_humidity : 54,
        display_status : "Normal",
        display_enabled : 0,
        display_last_page : "home",
        display_last_colour : 0,
        pass : "",
        display_dim : 60,
        
        frost : 14,
        hold : 0,
    
        p1 : 180,
        p2 : 480,
        p3 : 600,
        p4 : 1080,
        p5 : 1380,

        pw1 : 180,
        pw2 : 480,
        pw3 : 600,
        pw4 : 1080,
        pw5 : 1380,
        
        t1 : 16,
        t2 : 21,
        t3 : 19,
        t4 : 21,
        t5 : 18,
    
        tw1 : 16,
        tw2 : 21,
        tw3 : 19,
        tw4 : 21,
        tw5 : 18, 
    
        temperature_offset : 0,
        last_state : -1,
        current_state : 0,
        update : 0,
        daynow: 1
    };
    global.set("thermostat",stat);
    msg.payload=JSON.stringify(stat);
    return msg; 
    }
else if (msg.payload=="check") // this is the every second check - assuming file exists
    {
    if (global.get("thermostat.update")!==0)
        {
        global.set("thermostat.update",global.get("thermostat.update")-1);
        if (global.get("thermostat.update")===0)
            {
            msg.payload=JSON.stringify(global.get("thermostat"));
            return msg;
            }
        }
    }
else // read in the file if it was valid - don't output anything
    {
    global.set("thermostat",JSON.parse(msg.payload));
    global.set("thermostat.laststate",-1); // detecting change of timezone
    global.set("thermostat.temperature_offset",0);
    }


Not sure how useful you feel this is for your projects compared to a database – but it is simple and fast. The point of the global object, of course, is that you can use it on any page in your node-red setup. Certainly, by careful use of the timer when updating, you can vastly decrease the number of WRITES compared to a normal database setup. Handy for those of us on a Raspberry Pi with limited SD writes.

There are those who put their hands up in horror at the idea of globals - I do not. I like the idea of having the ability to view or update things from any tab (flow) with ease.  Real world apps? I've been using this (bearing in mind the initial issue with start up values just resolved) in a holiday rental since April - with people in all the time - running the heating and some lighting - not one issue.

Facebooktwittergoogle_pluspinterestlinkedin

Node Red Sunday

Node-RedIt is Sunday, I’ve done my 4,000 steps down to the village for coffee and back and I’m having a play.

I use Node-Red on a Raspberry Pi to control just about everything in two houses – as my confidence in the setup has grown, I’m currently keeping the Pi up 24/7 with no sign of any issues (well, it could ALWAYS be faster). Normally I control the likes of ESP8266 boards with this to do everything from monitoring temperature, pressure and humidity to controlling heating, fans, lights and more.

It occurred to me, as I’ve also had success with my script in getting Node-Red, Sqlite, MQTT and other software running on other SBCs including the really cheap new ones coming out of the woodwork that it would be nice to be able to talk to them with the same software especially those running Armbian as I’ve had a lot of success with that personally.

So I’ve made a start. I thought you might find this preliminary effort interesting.

In my controllers, MQTT is at the heart of everything and facilitates utterly reliable message sending from device to Pi and Pi to device (indeed there is no reason I could not do device to device really). I thought it might be nice to start off with a little bit of code that simulates what the ESP8266s do constantly – turn things on and off.

So typically, given a device called fred, I might turn a relay on or off using MQTT messages:

topic: fred/toesp
payload: {out0:1}

Let me first explain why I do it this way. So MQTT typically works by sending simple messages back and forth – they have a topic (address) and a payload (data).  My devices, for example fred, listen for two topics:

fred/toesp
esp

That way I can send a message to a SPECIFIC device – or to all of them at once (OTA for example)

If the device needs to send messages back they will always be of the form:

fred/fromesp/out0

in this case the payload returned would be the current state of out0.

So that represents the basics. Here I will show how a cheap controller running Node-Red can accept commands – I won’t go into the actual mechanics of turning a light on and off because for example the GPIO commands used in a Raspberry Pi won’t work on a NanoPi NEO – alternative methods are used. I’ll simply cover how to get to that point.

So here is the simplest possible setup on the Pi, to turn a couple of outputs on and off.

MQTT

This is nothing more than 4 INJECT nodes dropped onto a flow along with an MQTT output. Typically the content of one of these nodes might be:

INJECT

Simple enough. When pressed the node outputs a topic of nanopineo2/toesp and a payload of {out0:1}

This would work with one of my ESP8266 units to turn output 0 on. “nanopineo2” is just the name of one of my NEO units running Node-Red.

Here’s what’s at the other end to make this work.

Nanopi Neo

Two MQTT inputs feeding a function. So the function will work if either the generic “toesp” is called or a device-specific version. In that first function I check out the command – really simple – and will be dramatically improved soon.

// An attempt over time to emulate my code in ESP8266 - taking commands from MQTT
// and processing I/O
// for example message {out26:1}

var m=msg.payload;

if ((m.charAt(m.length-1)=="}") && (m.charAt(0)=="{")) // ignore if not in braces
{
    m = m.substring(1, m.length-1);
    var breakup=m.split(":");
    var getname=breakup[0];
    var sendto=breakup[1].split(",")
    
    switch (getname)
    {
    case 'out0' :  msg.topic='out0'; msg.payload=sendto[0]; node.send(msg); break;
    case 'out1' :  msg.topic='out1'; msg.payload=sendto[0]; node.send(msg); break;
    default: break;
    }
}

The output is reduced to the actual command “out0” for example – and a value. So the next item is a switch in this case selecting “out0” or “out1” and ignoring everything else. The outputs from that switch go to functions which simulate actually controlling something – like a LED for example and in my demo the colour of the black dot changes from black to red when you send a command to turn that output on.

if (msg.payload==1)
  { 
      msg.payload="lamp1.val=100"; node.send(msg); 
      node.status({fill:"red",shape:"dot"});      
  }
else
  {
      msg.payload="lamp1.val=0"; node.send(msg); 
      node.status({fill:"black",shape:"dot"});
  }
  

And that is it for now. As you can see, this can RAPIDLY be expanded to cover every port bit available on your micro, it could control PWM etc. The next step will be to take {command:arg1,arg2….arg6} and parse the arguments into an array. That will then allow PWM and other kind of controls. If you really don’t care about pricing you could do the whole lot with a bunch of Raspberry Pis… but with new Orange Pi boards coming out at under a tenner, the options are endless.

Facebooktwittergoogle_pluspinterestlinkedin

Node-Red on a Phone

I have to hand ALL the credit to Dave at the Node-Red Google Groups for this – and you might want to pop any questions in that direction because I know even less about running Android at the command prompt than I do Debian!

Running Node-Red on your Android phone or tablet!! Yes you CAN. it turns out that it is dead easy. Using a terminal program (App store) such as Termux.

So basically install Termux as you would any other app.. and run it – you get the usual black terminal screen. I did this just now on my HTC ONE-M8 – might work on yours – might not.

apt update
apt upgrade
apt install coreutils nano nodejs
npm install -g --unsafe-perm node-red
node-red

That’s it -  you’re up and running.

Well, so that is Node-Red running – of course if you close the terminal you stop Node-Red so the first thing to find out is how to press control-C in that terminal!!! Any ideas anyone?

Once I got back in – instead of starting Node-red I did the following..

cd .node-red

npm install node-red-dashboard

npm install node-red-contrib-admin

npm install node-red-contrib-bigtimer

cd

node-red

Once you run node-red – you can go into the browser on the phone and run 127.0.0.1:1880 and lo and behold- node-red  - probably more usefully would be to go to the phone’s WIFI setup and find out what the IP address is – and run Node-Red in a browser on your PC and that same port number. 

Now why on EARTH would you want to do this. Well, if you could get node-red running as a service on an old tablet – along with MQTT (not sure about that one) all as services – you have a home control server base – with several hours of reliable battery backup (you’d have to run a task to stop the thing turning off I guess.

Well, something for the weekend! As answers (hopefully) emerge for the following – also running my phone with SCP from the PC would be good… I’ve no idea what the user is or the password!!!! I’ll update this.

And the first update – control characters on that terminal… here.

Meanwhile – MQTT Broker Pro which will soon have it’s own basic authentication and which already comes up on phone boot – works a treat – here are the two of them running together as seen on my PC browser.

Node Red on a Phone

Be aware – that the MQTT server does not work if you use “localhost” – you need to use “127.0.0.1” or if you want to access the MQTT server externally – the IP address of the phone. And yes I’ve tested accessing the MQTT broker externally – which is another good reason for it to have a user name and password.

All good stuff.

Facebooktwittergoogle_pluspinterestlinkedin

Some thoughts on Node Red variables

In learning how to use Node-Red I’ve changed my coding countless times as I’ve found better ways to do things.

Please note that in 2017, the way I use global variables here is out of date. It still works but for example context.global.fred=1 is now written as global.set("fred",1). Read this later article on using globals and context variables.

I’m currently working on my thermostat code using a Nextion touch-sensitive display, Raspberry Pi2 as controller and ESP8266s for relay and temperature/humidity sensing. This was a slow-running project until my old Arduino-based heating controller packed in yesterday without warning and so now the fate of the household heating is in the hands of an on-going project.

So the general idea is easy enough – lots of settings for weekdays and weekends, read sensor, control relay. That’s pretty much it in a nutshell except that on my first attempt I didn’t take into account power cuts – and when the power was restored to the Pi, hardcoded defaults took over instead of the settings I’d put in using the display.

So there’s a need for lots of variables and a means to store them permanently. This is what I’ve come up with and the logic behind it:

In order to pass variables around in Node-Red, you need to use “context.global” variables as these are the only ones that will work from page to page (i.e. from powering up node-red to powering down across all pages of your project). This can make for messy variable names for those of us who like to keep things short because we’re lazy or developing typists finger.

context.global.stat_inside_temperature

etc..

I’m a C person and so a struct is ideal for me – keeps everything together.  The nearest I get to that in JavaScript is an object and that’s fine.

A global object containing everything to do with my stat.

   var stat = {
display_temperature : 22,
display_humidity : 45,
heating : 0,
display_external_temperature : 14,
display_external_humidity : 54,
display_status : "Normal",
display_target_temperature : 20,
display_enabled : 0,
display_last_page : "home",
display_last_colour : 0,
pass : "",
display_dim : 60,
peak : 21,
night : 16,
frost : 12,
hold : 0,
weekon : 480,
weekoff : 720,
weon : 480,
weoff : 720,
week2on : 780,
week2off : 1380,
we2on : 780,
we2off : 1380,
temperature_manual_override : 0,
update : 0
};

That stat var of course is only valid while the relevant function is in use and is invisible outside of that particular page hence…

context.global.stat=stat;

So now we have a nice but somewhat longwinded way to access the variables..

context.global.stat.display_temperature;

(I know I should probably use displayTemperature but there’s no global replace in the Node-Red editor (hint)).

Because JavaScript objects are passed by reference – you can use a reference to this in other pages which makes things a little more readable.

var stat=context.global.stat

Hence

stat.display_temperature;

That’s more like it and you can write to that new variable and it will update the original as they are one and the same.

The obvious solution for storing variables permanently, is a database, but I’m trying to minimise that to keep writes down for the time when I run all of this and much more on an SD (currently using a little 2.5” drive with the Pi2).

The file node lets you read and write text files and so the next challenge was how to get that object into a text file – easy:

msg.payload=JSON.stringify(context.global.stat);

That JSON string can be saved directly to disk and the inverse is true of course…

context.global.stat=JSON.parse(msg.payload);

The good part of that is that the string saved to disk is readable and if need be directly writeable.

Thankfully when the file node reads a file if the file is not there, it returns “undefined” so in my function I check for undefined and if so – create a new one with defaults in it. I added a timeout variable in there and whenever I update any item in the object I also set a counter to 10.  That counter is decremented every second and when it reaches zero, the object is updated on disk. That means I can do all sorts of adjusting of controls on the Nextion display and only when I’m done will there be a single block write to the disk. The READ is only done once when Node-Red powers up.

Seems like a reasonable solution and it’s nice and warm in here.

In an earlier blog you’ll see my Nextion display solution which is quite pretty ( created my own imagery because built-in Nextion options are currently not that good) – here just for reference is the current Node-Red block controlling the display and the stat itself including disk reading and writing.

tmp7866

Facebooktwittergoogle_pluspinterestlinkedin

Drilling into Blynk

zeRGBaYesterday I referred to using DELAY in Node-Red to slow down one of the Blynk controls. To backtrack a little…  We’re talking here about controlling devices such as ESP8266 boards using MQTTT – which I maintain is the best way to have a boatload of devices around the place and talk to them. I do this from a Raspberry Pi 2, using Node-Red which is a visual system, relatively easily fitted to the Pi (see my articles about my script). Once you have this in place, you can use simple (but excellent tools such as MQTT-Spy to send out MQTT messages to your devices and get input from them.

But in the real world who wants to sit there programming a tool just to turn a light on. So there are various options including the rather expensive Raspberry Pi touch display. A better option IMHO for local operation are the Nextion touch displays which work serially. I’ve covered these elsewhere -  a project that is still in it’s early stages but with a little work is usable – so much so that I plan to use them in my place here in Spain and back in the UK as thermostat wall mounts – I’ve covered that elsewhere under “Nextion”.

And so to Blynk. For many months I’ve been trying to get a decent control/display combo for the mobile phone. I’ve written my own in jQuery mobile and used the likes of NETIO and THINGSTUD.IO – all of these are viable methods – another that is coming up is Blynk – again very preliminary and I’ve reported lots of issues with this – but it works.

There are several useful controls – you see in the image above some simple LEDs (which can be set to various intensities though you can’t programmatically set the colour, sadly), some simple status outputs and two buttons (which can be set to ON/OFF or push to operate). They also have a controller called the zeRGBa which is a visual controller for setting RGB lighting. You see 4 of them in use top right of this article. You can basically move your finger over the control – which will then fire out RFGB values. Thankfully you can set the maximums as not everyone works in the 0-255 space. My PWM controls for ESP8266 use 0-99 for example.  This widget falls down currently in 2 areas, firstly you cannot SET it’s position – you can only use it as an output control. Secondly and arguably more importantly it sends out rather too many commands one after another when you move the unit around. I prefer courser control, smoothing the transition in my ESP boards.

So, given a control that fires out RGB sets rather too rapidly, how can Node-Red help. Thanks to the developers who I’m fortunate enough to get lots of feedback from, it’s actually quite easy.

RGB Control

Here we see 3 inputs from the App coming in via the Blynk Node. The first thing I need is a function to convert that data (a simple array of 3 values) into an MQTT statement to fire out.

msg.topic="sidewall/toesp";
msg.payload="{rgb:4," + msg.payload[0]+","+ msg.payload[1]+","+ msg.payload[2]+",70,1}";
return msg;

Easy enough – I set the topic for MQTT to my wall RGB ESP8266 board (the format is my own, don’t get hung up on that) and I use a message payload of say “{rgb:4,255,0,0,70,1}” – what the hell does that mean? Again my own format… the braces are there for technical reasons – my ESP boards accept MQTT or serial – and the ESP’s put out some crap at the beginning and debug info – so I wrap my messages in “{}” just as delimiters. So the actual message is “rgb:4,255,0,0,70,1” – which means – using output 4 of the ESP, send out RGB 255,0,0 (i.e. RED), smooth the transition from one colour to another over 70ms – and I can’t remember what the last parameter is – irrelevant here.

If you look at the code, what you’re getting from the Blynk node is an array (msg.payload[0-2]) so a simple substitution.

That one string goes out RATHER TOO QUICKLY on message after another for my little boards and I was wanting to slow them down just a touch. the DELAY node can be used for this..

delay

Absolutely brilliant – so it will not allow more than 16 message a second – and if it gets more – it will drop some intermediates. Works perfectly – the actual rate of course depends on your project. I had utterly missed this – thinking that node was nothing more than a simple delay as suggested by the name – but dig in and it has so much more to offer.

So right now I can control several RGB devices around the house, limited only by the somewhat large size of the zeRGBa widget and the inability of BLYNK right now to handle several pages per project (though as of the other day you can seamlessly move between projects which helps).

In  case you’re wondering – the language used in the functions is JavaScript  - who’s ability to make life easy when it comes to handling different types of data such as arrays and JSON, is a wonder.  I look forward to the day we have a PROPER, fully working interpreter on the ESPs themselves.

Oh – and to run the Blynk server on your own kit – you need Java 8

apt-get install oracle-java8-jdk

And I made my blynk directory and those below it full read/write/execute.

Facebooktwittergoogle_pluspinterestlinkedin

Raspberry Pi Serial and Node-Red issues

SOLVED: Node-Red serial I/O

serial

Looks simple doesn’t it – tie RX and TX together on your Raspberry Pi and press the button – text comes out of the other end – except that it doesn’t. More likely the Pi will CRASH (not something you see every day).

Serial out seems fine – no error messages, you can change baud rate and according to my scope, all is fine on pin 8 of the RPi2.  Input on the other hand, can cause interrupt issues, messages on the console and crashing – and almost never actually produces any output.

So what is the problem?Well, one of the guys at the Node-Red forum set me onto this link.  http://jeelabs.org/2012/09/20/serial-hookup-jeenode-to-raspberry-pi/

And therein lies the problem – by default – the RPI uses the serial port for communications. Trying to add another hook to the serial in interrupt – kills the Pi.

The solution is simple – extracted from the above link.

  1. edit the file /etc/inittab as root (I used “sudo vi /etc/inittab”)
  2. change this line: T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100 to#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100. I.e. comment it out, and save these changes.
  3. run the command “sudo kill -1 1” to pick up these inittab changes

And that  - was that  - I now have comms in and out  - the idea being to put a serial display such as the NEXTION onto the Pi with simple touch input commands – and an output display showing status, temperature etc. DODDLE in Node-Red once you have serial up and running.

Facebooktwittergoogle_pluspinterestlinkedin