Category Archives: Node Red

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

A Thermostat Weekend

tmp3C7AAs I make changes and I don’t want to bore readers – I’m adding sections at the top of this article and moving earlier versions of the stat down the page. If you are new to this you might want to start at the bottom at the point in this blog entry marked “The Old Ways”.

The Newer Ways: You will read below about last weekend’s work on the thermostat control – here is the link to the current code which now also handles a de-humidifier (not on a timed basis) and a heating using indicators built into the gauge (my thanks to the author for his help). The image on the left depicts the latest version.

Mobile Thermostat panel by Peter ScargillThe New Ways: This is about a DIY Thermostat in Node-Red – if you want to read about how I got to this point, start at “The Old Ways” then come back up here. If not, read on. Here's a short video. So – you want a thermostat using Node-Red Dashboard (remember you can set all of that up on a variety of hardware alternatives using the script – which turns your little SBC into a potentially powerful central control system for IOT). Here it is.  You should be familiar with Node-Red, Node-Red dashboards and flows. If you need to know more about home control you could read all about it in the Home Control 2016 blog (quickly before I come up with a reason to change that to 2017). Lots of links in there to code for Esp8266s etc.

I’m assuming you have sensors and a relay board to control the heating and all you need is the pretty bit with glue in the middle, understand basic heating and are ready to go.

Here it is on the left – two days of solid graft. With this magic screen you can set up an entire week’s heating, controllable at hourly intervals – in a minute if that. Each hour can be poked with finger or mouse, adjusted and at the touch of a button replicated to the next hour. Similarly a whole day’s settings can be instantly replicated to the next day etc. You have control of the automatic temperature, with manual override as well as frost and stat settings and all on one colourful screen.

And if you don’t like it – it’s all there in source in Node-Red – what could be easier.  I must’ve made a dozen variations as you’ll see in “The Old Ways” before coming to this – what’s really exciting is that some of the control and display elements of Node-Red Dashboard are getting easier as I go along – at first I seemed to get no-where, now, the sky seems like the limit.

So – each of those coloured elements represents one of the 24 hours of the day – simply select by touch (the black bar will light up purple) an move left or right using the bottom arrows. The COPY button next to it will replicate an hour in the next one if you have selected an hour – or will copy a whole day if you’ve selected DAY. You can select frost and away settings and adjust temperatures there. On the top of the display is your actual temperature – and settings to adjust the SET temperature – and away from hours (>) to days (>>).  A is for automatic! When you have the settings the way you want them – use the disk icon to save or use the cancel icon to revert back to what you had before you started. That’s it – nothing else.  The data (a very small amount) is stored in your /home/pi directory but of course you can change that.

And here’s the flow you’ll be looking at – complete with lots of test buttons.

flow for the thermostat

This is slightly different to the code I’ve put up as I’m now monitoring actual temperature (the purple MQTT node top right – in the demo code I have kept the demo buttons).

The left side is entirely test material, storing values from your temperature and humidity sensors (the latter is not used as I ran out of room to display – maybe this week I’ll re-think the sizes slightly. I’m also pondering expanding the hour-day idea to hour-day-zone as I have two heating systems here but that will be later and I’ll leave this code intact).

Note: You’ll see some icons here – I’ve not distributed then as I’m not 100% sure of their copyright status – if you look around and look at an earlier blog talking about icons and .png files – there are no shortages of decent transparent .png icons for you to use – there are also a bunch of them built into Angular.

Temperature display from the new thermostatAll seems to work – in Chrome on the PC and on my HTC phone the displays are identical. Now – if anyone would care to ponder improvements – maybe find enough room in that right corner to get some more info…. do write in with ideas and code.

HOLD THE PHONE: I think I’m in love… check this beauty out on the right – found it HERE and modified the colours, text and size – a true work of art - quick modification in a browser and I changed parameters to make it do temperature (originally speed) change colour – etc…  I have it working in a simple local web page but sadly when I put it in a template right now – I get a white screen… I’m at a bit of a loss as to why.. if anyone wants to step in here….. it is so lovely it would be a shame to miss.

And finally: The original gauge here had a grey display with decimal points. I needed to get rid of those as I’m dealing in integers. I contacted the author Mykhailo Stadnyk

http://tech.scargill.net/yourls/gauges

At the end of that – two new parameters – valueInt:2 and valueDec:0 gave me what I wanted – a simple integer degrees printout.

If you are using my flows – and creating directories etc, always remember that Linux and Javascript are case-sensitive – don’t go making directories/files  in upper-case and addressing them in lower-case.

Oh – LEDS -  I just found this – lovely CSS LEDs  - I need to figure out how to add one into the canvas.. I’ve also asked hr writer of that gauge if he’d consider adding in an optional LED indicator for me (boiler active).

The Old Ways: Here is where this all started.

As it happens, a few days ago, reader Antonio pointed me to a little ESP8266 Thermostat – well, some code for it anyway, using one of those little 120*180 displays.

ESP8266 stat gave me ideasI’m not that partial to Arduino development but I grabbed the code and stuck it on my hardware. Some great ideas there – but the implementation using a rotary encoder left something to be desired – and the code doesn’t support MQTT – and minus temperatures messed the display up. Oh and it seems to be partly in Italian and partly in English. Oh and a good but not especially long-lasting sensor is sitting right next to warm electronics and a warm display.

Don’t get me wrong, a STERLING effort and no doubt it will go on to be very good – but it wasn’t quite what I was looking for. It certainly fired me up.

As you all by now know I’m an MQTT/Node-Red/Mobile phone kind of guy and so armed with my new knowledge of Node-Red Desktop I sat down with coffee on Friday morning and started to put together some new thermostat code (as if I needed more). One of the things I really liked about the ESP code was the timing page you see above. I have 5 time zones per day which can be any temperature – different at the weekend – but not without it’s issues – what if the weekend is not your “special” time for example – and it needs lots of controls.

This on the other hand was simple. I got to thinking – but if it was on a touch screen you would not have all that selecting nonsense and what about replicating settings for every day and….

And so it was that I sat down with a gallon of coffee and did what I always do – plough in with the code long before I’ve put a plan together. Sometimes it works, sometimes it doesn’t. Hey, I’m a one-man team!

Templates on Node-Red: Well, this time it did and I’m chuffed, but before getting into this – a quick lesson on using TEMPLATES in Node-Red Desktop.

Templates are easy – pretty much you can make a web page in a template – you can even have includes and JQuery comes with the deal.  The problem I’ve always had in the past is getting stuff in and out of the template – the examples given really don’t help and I spent HOURS trying to get to grips with this.

Scargill's very first Node-Red thermostatWhen we were messing with buttons (see other blog entries) I got a lot of help from folk, most of it I understood, getting variables into the Template I most definitely did not – but it worked and now the light is coming on.  Remember the good old days of ASP programming and other server-side interpreted coding – you had this code on the server which was NOT in the same space as the code in the web page. Well, this is similar.

The likes of msg.payload sits in Node-red along with global variables, context variables  etc. They do NOT reside in run-time Javascript on the web page and that had me going in circles for ages. Well, there is a way around it, digging through the code we ended up with for the buttons I extracted this and modified it a little…

(function(scope){
scope.$watch('msg', function(msg) {
// do stuff in here with msg… which includes any part of msg, even arrays etc.
});
})(scope);

So here we are on the web page – in a script tag – and we drop this in. I know – what the HELL is scope (yes I know what variable scope is). I can’t tell you in detail but I can tell you it works perfectly!  As soon as you inject the normal Node-Red msg (entire) object into the template – where that // comment is above, you can use the lot inside that function, calling javascript functions etc. Note that in typical examples elsewhere – inside that function you’d see the word data – and I’d previously then used “data.payload” etc. – however, keeping the name the same (msg) makes it easier.

Along with the ability to fire out information back to Node-Red with this and similar for buttons..

ng-click="send({payload: 'hello world'})"

The first attempt: With that realisation I started on my new little thermostat. The most COMPLICATED page is that of settings – and the project above that I really liked - got me started as gives you 24 settings every day of the week. FANTASTIC – but I had to make it easy. Now, it is REALLY easy. You can set up programs for the entire week in a minute.

Over on the right – you see my FIRST interpretation of this – yes, it works – I just don’t have a relay fastened up yet to DO something.

Ok –  the colours were not that subtle – don’t be awkward – I only started on Friday morning after a fear-filled, anaesthetic-devoid double-crown fitting at the dentists via a 90+ mile round trip. – yes, I was brave though it nearly reduced me to tears – so bear that in mind before criticising my colour taste  - I’ve change it as you’ll see later. The buttons are simply Angular buttons with png images inserted.

So – you can touch/click on any of the timings – or temperature, or day and using the up and down buttons (they’ll end up as left and right arrows) you can change the temperature from one of the presets for that time or the time slot you are playing with or the day. The black line under the relevant item will turn purple (for now).

Scargill's very first Node-Red thermostat flow

If you want to replicate the setting on subsequent hours, press/touch the copy button as often as you need (auto-increment). If you want to replicate the LOT, click on the DAY and then on the copy button and you’ll start whizzing through the days (auto-increment), coping the entire 24-hour schedule across – you can then tweak bits later. When you are happy you’ve not messed anything up – press the save button.

Now this lot is simply stored in an array – 24*7 bytes plus 4 bytes for the temperatures – so as an array, stored on SD it takes up almost no room – by using a 2-level array you could EASILY expand this into different ZONEs – so as well as a DAY field you’d have a ZONE field and a copy operation would copy the whole lot to the next zone –  etc. Seriously this is a DODDLE to set up.

Finally a cancel button…which simply restores the array from SD – that function is also called at power up to get the values in the first place. I could probably do with a timeout on saving to avoid the (admittedly small) write to SD on every change. Still – not something you’d do a lot of.

So now we have a non-volatile global array with all the info in (I jammed the temperature settings on to the end of the array) – a separate page will show the temperature with a nice pretty dial, let you change manually up and down that for a given time – what, 4 hours before reverting to auto? and of course you’d want to show the humidity and pressure – very important they are all super accurate so I’m thinking a single BME280 would do the lot for you!!!

And that’s it – the output of “process heat” is simply the required heat value, sent out every minute. I picked a minute – could be 5 minutes – if you are working with, say, an oil boiler you really don’t want to be changing things rapidly. You can use this value to display in another page as the “set” temperature and to compare with the REAL temperature to decide what to do with, say, a relay.  Options might include a manual override – which should time out after a couple of hours maybe – and maybe a longer-term override in case you want shopping or are away for a couple of days in which case you might want to go to the lowest setting (offset zero in the global array) for some period. Normally for manual override you’d simply ADD your override figure to the automatic figure – i.e. 2 degrees WARMER or COOLER. My next job will be to do a nice job of the main stat display page.

The main page will no doubt also feature the local weather forecast – again from a previous article. One could even add a complete week’s predictions with icons.

More on this in near future – here is the current FLOW for this (no support and it WILL change in time) so you can just drop it in into Node-Red. Aren’t you glad you adopted the latter!

Scargill's very first Node-Red thermostatAuto-learning

To do auto-learning I think I’d change this – instead of 4 fixed temperatures I’d allow arbitrary temperature between, say 14c and 26c for every time slot (could do that now)…

Now, given THAT you could maintain a separate array – and every time someone makes a manual change – this would added to the second array (initially zero in all values).

After, say 4 weeks, you could divide the array down by, say, 4 (so that X degrees updated on the same hour for all 4 weeks would show up as one change) – and merely ADD that to the main array – clearing the second array. That way the system would have learned from the last 4 weeks changes but be ready to adapt to another 4 weeks changes etc. That’s one way – without getting too silly about it can you think of a more USEFUL way of adapting?

Thermostat – The Return of the Stat: Well, it had to happen – once I started writing about this – I started thinking how DAFT that 4-temperature limit is – and so  - well, I changed it a bit…   a lot, actually.

The panels now gives full control for every hour of the week but because of the copy system, it still takes only a moment to set the entire week up and it did occur to me that it would be a doddle to extend this to a ZONE system with umpteen zones, even.

I’ve also spent ages working on colours so as you can see – as you adjust the temperatures, the colour changes per degree and it’s quite pretty.  And there is status help.

I’ve added in frost and away settings as you’ll need those for the front panel controls (up, down, set away, set frost).

I have to say, it looks beautiful on my screen. I’ve stripped out a lot of  CSS and put classes in to make the code at least partly readable. There’s a timeout on all the message that appear when you press buttons – should be 5 seconds but right now they vary a little – any Javascript experts - feel free to take a look at the function – but it all works well enough.

Here’s the second flow – this supersedes my first attempt.  Oh you’ll need to find some images – and change links accordingly. On my Pi2 I have a directory /home/pi/.node-red/public/myicons with a ton of folders in there with png images in them – well you have to make use of all that space.  You’ll need to find your own – there are many out there – make sure they are transparent. But then – if you’re working with Node-Red and Dashboard, it really is worth setting yourself up with a good selection of icons and images anyway.

Oh – the data… in “Process controls” you’ll see that we’re looking at an array of 168 bytes plus 2 bytes to store frost and away temperatures – that’s it. See later articles as this has all been improved.

Facebooktwittergoogle_pluspinterestlinkedin

New Day, New Dial

Scargill's thermostatWHAT a day I’ve had – messing around with a supposed DIY Alexa that isn’t… and getting to grips with dials. I wasted a lot of time on this (sorry Dave) before finally grasping the solution.

Here is the LATEST short video (Jan-10-2016)

So – in the last blog entry we took a look at the NEW Thermostat – this article looks at an even newer GAUGE - top left corner of the stat on the right – instead of a simple node-red-dashboard level node to show the temperature I have a pretty new gauge. All working as well! Indeed it is so useful I’ve decided to separate this out as I’m sure many of you will have a use for one or more of these.  Don’t get hung up on it being a thermometer – you can use it for anything – humidity, speed – whatever – completely programmable.

Here is the link to the gauge code. Pretty impressive stuff – there are examples over there – but the trick is, importing them into Node-Red-Dashboard. So – there is a library – under downloads – all in one.  Grab that .JS file and in my case I put it in a directory called /home/pi/.node-red/public/myjs -  that’s where I keep my .js files and Node-Red is aware of this. I’ve covered this before.

Armed with that file – you need a Node-Red-Dashboard TEMPLATE. In this case I set the template size at 3x3.  According I adjusted a couple of settings in this gauge to 160 * 160. pretty much you need the JAVASCRIPT source code for the dial – you get that from the site – and you need a <canvas> block. I’ve also added in a little chunk from earlier code to capture input to the node – that is used to alter the dial. And that is pretty much it.  What I would LIKE to do is dynamically adjust the size of the dial to fit whatever node size you use but I’m not yet succeeded with that.

Anyway – here’s the code for the dial you see here – to be inserted into the template note node to replace the existing gauge – and don’t forget to load in that .js file and make the template 3x3.

<script type="text/javascript" src="/myjs/gauge.min.js"></script>
<script>

   (function(scope){
        scope.$watch('msg', function(msg) {
           gauge.value=msg.payload;
        });
 
    })(scope);
var gauge = new RadialGauge({
    renderTo: 'canvas-id',
    width: 160,
    height: 160,
    units: "Degrees C",
    title: "Thermometer",
    minValue: 10,
    maxValue: 30,
    majorTicks: [
        '10',
        '15',
        '20',
        '25',
        '30'
    ],
    minorTicks: 5,
    strokeTicks: true,
   highlights  : [
        { from : 10,  to : 15, color : '#8888ff' },
        { from : 15, to : 20, color :  '#88ff88' },
        { from : 20, to : 25, color :  '#ffff00' },
        { from : 25, to : 30, color :  '#ff8888' }
    ],

    colorPlate: "#fff",
    borderShadowWidth: 0,
    borders: true,
    needleType: "arrow",
    needleWidth: 2,
    fontTitleSize: 42,
    needleCircleSize: 14,
    needleCircleOuter: true,
    needleCircleInner: false,
    animationDuration: 500,
    animationRule: "linear"
}).draw();

gauge.value = 18;

</script>
<canvas id="canvas-id">
    
</canvas>

ToDo – reduce the grey box from a float to an integer with 2 digits and get a 7-segment font into that grey box.

I’ve updated the original Thermostat page here..

Facebooktwittergoogle_pluspinterestlinkedin

A Christmas Script

tmp81FFOver the weekend and beyond, reader Antonio Fragola (Mr Shark) and I have been working on a couple of things together (no we’re not in the same country – Skype). Regular reader will know about the script (original blog material now ditched though the old script is still on BitBucket) that a couple of us originally developed to put Node-Red and several other packages onto the Raspberry Pi for home control purposes.

Well, that original script mutated to run on several different boards and my one big gripe has been the amount of interaction once the script starts.  THIS one is simple – and after reading some comments about how good Xenial (Ubuntu) is – we’ve also made the script compatible with this. So Raspbian, DietPi (Debian) and the Armbian versions of Debian and Xenial (Ubuntu).

Before I begin – no, we’re not a support shop – you may or may not end up having to tweak things for your system but please don’t write in to say “I tried this on a Mac and it doesn’t work”).

The level of interaction is now zero thanks to a new menu-driven approach and many improvements including using a VM (virtual machine) to test the whole thing at accelerated speeds. We’ve also put in some extras.

What is this about?

What we have here is an explanation of how to get Xenial running in a VM – the purpose of this is merely as a base to test the new script mentioned below which will install somewhat more than the original script (designed originally for Raspberry Pi but now working on several Debian-based devices and now Xenial) – namely:

  • Node-Red at port 1880 and lots of useful NODES
  • Mosquitto with Websockets
  • NODEJS/NPM
  • Webmin at port 10000
  • Apache at port 80
  • HA-Bridge at port 82 (suitable for Amazon Alexa)
  • SQLite and PHPLiteAdmin
  • MC File manager and editor
  • Lots more – see the menu screen

Typically this setup would be used as the basis of a nerve-centre to control and monitor home control gadgets such as the ESP8266 units we discuss in this blog, Sonoff controllers and much more. Armed with this software, controlling the home is easy – and more importantly can be done YOUR WAY.

The Virtual Machine

Let’s take a look at what we did – you can of course duplicate all of this as you go along. We used the excellent VMware of VirtualBox on Windows PCs. This explanation covers VMware.

So – first things first – as I’ve done a video of the Virtualbox installation complete with sample use of Node-Red, here we’ll discuss the VMWARE version.  Both of these were done as test mechanisms before using the script on real devices such as the Orange Pi Zero, Raspberry Pi, Odroid and other devices discussed at length in the blog.

We loaded up a copy of VMware (I used VirtualBox but the procedure is similar – VMware player is free of you can use the full commercial workstation) and made sure it works. That much is up to you. There is a wizard for creating new virtual machines -  we chose a CUSTOM machine. Steps from that point on were:

NEXT - NEXT – “I will install the operating system later” – NEXT
Linux / Ubuntu 64-bit – NEXT – d:\test  - NEXT
Number of processors – 1  - number of cores – 1 – NEXT
Memory for this machine – 1024MB – NEXT
Use Bridged Connection - NEXT
I/O Controller type LSI Logic - NEXT
Disk Type SCSI - NEXT
Create a new virtual Disk - NEXT
12GB (I used 16GB – 8GB would have done) – Store virtual disk as a single file - NEXT
At this point we gave the file a name – in our case d:\test\Ubuntu 640bit.vmdk -  NEXT – FINISH

Under settings – hardware – CD/DVD we ticked “Use ISO image file” and selected the file we loaded from the Ubuntu website – “Ubuntu-16.04.1-server-amd64.iso” – OK.

At this point you’ll note reference to AMD64 – that had me as well but it works a treat on INTEL hardware.

Start off the VM – you get asked which language to use (ENGLISH) and various options will come up – the first being “Install Ubuntu Server” – that’s the one.

Once again you’ll get a language question – English. Location – in my case “United Kingdom” – if you don’t fit into the rules use “Other”.

Time Zone in my case – EUROPE  and then country. Locale – in my case United Kingdom.

Hostname – we went with the default “Ubuntu” – but call it whatever you want.

At this point you get asked to create a user – it is important you make a user “pi”. Enter password also (though the new script will create user PI if it does not exist).

tmp6049Home encryption – we said no. When asked if the time zone was correct we said yes.

Partitioning – “use entire disk” (remember this is a virtual disk – not your real disk). You are then asked to confirm erasing disk – go with that. You then get asked to confirm AGAIN. YES.

HTTP Proxy just leave blank – CONTINUE.

Install security updates automatically.

Add OpenSSH server and CONTINUE (important for remote access)

Install GRUB bootloader – YES.

Installation is complete – CONTINUE. Let it run.

And voilà – one working copy of Ubuntu. You have a pi user – at this point you’ll want to give ROOT user a password (sudo passwd root).

You need ROOT user for the next step.

No matter what machine you are using – you need a “pi” user and to make life simple – and compatible with that of the original Raspberry Pi user, a little command line work is needed. The rest is handled in the script.

So as ROOT user…

adduser --quiet --disabled-password --shell /bin/bash --home /home/pi --gecos "User" pi echo "pi:password" | chpasswd usermod pi -g sudo echo "pi ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/pi chmod 0440 /etc/sudoers.d/pi

The FIRST and SECOND lines are not needed if you followed the instructions above as you already a “pi” user.

tmpB7DFSo now we have a pi user able to do SUDO commands.

The BASH Script

This part is about running the script and assumes a “pi” user with SUDO capability.

Create a file called script.sh in the pi directory and populate it from the script. https://bitbucket.org/snippets/scargill/94yxL

Ensure it has the right permissions.

and that is that. as PI user, in the /home/pi directory you should now have this script. DO NOT run this as ROOT user.

At this point BACK EVERYTHING UP to avoid disappointment – no, REALLY.

Execute as:

./script.sh

You will see a menu which will vary slightly depending on which system you are using – you won’t be asked about GPIO on a Raspberry Pi for example.

tmpE673

For the VM we left everything as you see here and tabbed to OK.

At this point you will be asked for a USER and ADMIN names (which can be user and admin if you like) and corresponding passwords. From there on – everything should happen with no user interaction.

After maybe 15 minutes – or an hour – depending on your system – you’ll see an invite to REBOOT – so REBOOT. When the board/VM boots up you will find hopefully a working system. Node-Red runs at port 1880, Webmin at port 10000 (Webmin needs Pi or ROOT username and pass until we figure out how to add in the ADMIN user).

You should have Apache at port 80  HA-BRIDGE (if installed) will run at port 82 – It seems that Amazon Echo is quite happy with this but the Google product wants port 80!

Node-Red should include MQTT which will need admin username and password as will Node-Red itself. USER name and password is used by Node-Red Dashboard.

There is also the excellent MC – a file manager and editor.

MC and MC EDIT

I hope this brief introduction sets you off in the right direction and of course no doubt there will be discussing in the notes below.

Update Dec 29: Early start this morning - just for the sake of it I’ve just taken the Ubuntu desktop image, installed it on a laptop (a very old laptop) and ran the script – perfect – everything installed. My thanks to Mr Shark for filling in the blanks in my Linux knowledge.

Update 05 Jan 2017: At the time of writing I'm having issues with PIXEL in VirtualBox and DEBIAN on VirtualBox in terms of Apache not loading.. I'm sure we'll sort that - meantime some useful links.   Debian  may not some with SUDO depending on which installation - here's a fix link that worked for me in my VirtualBox image.. If SSH setup won't allow remote access using passwords, here's a link that helped me.  Pixel of course will run in Virtualbox but by default it runs of a virtual DVD which is about as much use as an ashtray on a motorbike as nothing gets saved. Once running however it is a breeze to move over to the Virtual hard disk - you'll find that part way down the comments in this link.  So right now I have VirtualBox running Xenial, Pixel and Debian and the only issues I have are with Pixel and Debian - Apache - watch this space.  I’ve also improved the input for user and admin.

Important: Whatever you are using should have the SUDO command built in – it may not be obvious but Debian often does NOT have this installed by default – sort this FIRST. You should also make sure you have Pi user with SUDO group privilage – PI already has this of course and you may have added a user Pi – if not..

wget https://bitbucket.org/api/2.0/snippets/scargill/E5rG7/master/files/makepi
su -c "bash makepi"

Or, Here’s a useful link – takes seconds and is easy…  basically – as root you can do - apt-get install –y sudo….. and you should make sure that your PI user is part of the sudo group.

Facebooktwittergoogle_pluspinterestlinkedin

More Node-Red Dashboard Success

Dashboard buttonsWell, it looks like my revelations with hiding the mouse has upset WordPress – the previous blog on the subject makes some people’s mice disappear!  Good job I wasn’t testing a self-destruct button.

It’s been a good day today – I discovered SLACK and I’ve been happily chatting to folk about my Node-Red-Dashboard issues and at the end of it all, not only have the issues gone away but I’m making progress.

So – there are a couple of things to notice and some you won’t.

So firstly – my button experience until now on Node-Red-Dashboard has been blighted by a SWIPE command which meant if you pressed a button near the right of the screen and in any way slid your finger  to the right – the page would change – in the unreleased update to Node-Red-Dashboard (needs just a tad more work and docs apparently) that has gone.  Excellent. I’ve seen this “feature” in other packages and it really does not work if you’re supposed to interact with buttons.

In my last blog on the subject you’ll see I can hide that top menu if needed (the blue menu is great on a phone – not much use on a thermostat)… and today I discovered that desktop TEMPLATES have a spacing round them that DID make it impossible to make your own buttons that would be size compatible with the UI built-in buttons.

That is all now history. So – the built in buttons – no text wrap which make it hard to make small, a visual effect on press that really is hardly noticeable, inability to change colour or indeed anything other than text colour – all problems now history.

The garish red, green and blue buttons you see above – note the rounded edges you control, there is an attractive and obvious colour change pm press (and return to original colour after press without you having to program it ), audible feedback on press (on phones with vibrators), wrap on text – indeed you can put anything in there - icons etc.

This is due to a combination on my insistence on having flexibility – my own experience and lots of help from several guys on the web today – thanks everyone for filling in the missing bits! The end result of all of this – I really DO think that Dashboard is able to take on the big boys and I’m currently backing away from the alternatives.

So – the enabling technology here is the node-red-dashboard template – this has LOTS of potential and it is now easy to accept incoming information – and send out a value on press or whatever. You’ll note elsewhere that I’ve used this to make whole pages with colour-changing icons etc., well here I’m using one template per button – but that’s just for the purpose of demonstration.

Things that needed considering – CSS for button sizing, JS to get the button colour and change it while pressing then change it back – I was not going to get into setting each and every button press colour etc. More CSS for styling. All described below and trivial to implement.

SO it turns out that if you put a template on a page – make sure it is the first one – you can put nothing but JS and CSS in it – and it will not do anything VISIBLE – but will supply your functions and CSS for the whole page – isn’t that HANDY!!!

tmp3513Let’s take a look at what is driving the display up there (again ignoring the text at the top – start with the buttons). To the left you see a template all on it’s own – then 3 templates – then 3 buttons – not connected to anything as this is merely a demo.

So – the FIRST template has info we need – CSS and JS to make everything work – you just need this once for any page. The light blue buttons are there just to show you what buttons look like in Dashboard (i.e. not as good as they could be) – and the three templates are the three new coloured buttons you see above right – which react to being pressed both visually and with haptic feedback.

Let’s take a look at the FIRST template which makes it all possible. It looks easy now but trust me it has taken some head scratching to get this far.

<style>
  .filled { 
      height: 100% !important;

      padding: 0 !important;
      margin: 0 !important;
  }
  .nr-dashboard-template {
      padding: 0;
      margin: 0;
  }
  
  .rounded {
  border-radius: 15px 15px 15px 15px;
  font-size: 18px;
}
  
</style>

<script>
$('.vibrate').on('click', function() {
  navigator.vibrate(100);
});

function restore_bg(x) {
            $(this).css("background-color", x);
    };

$('.touched').on('mousedown', function() {
    
    var x= $(this).css("background-color");
    $(this).css("background-color", "yellow");
    
    setTimeout(restore_bg.bind(this,x),200);
    navigator.vibrate(100);
    });
    
</script>

NOTE: At the time of writing this colour change works on Chrome etc on a PC and Android phone – it does NOT work on Firefox/Chromium on a Pi – this needs resolving.

The class FILLED is important - this is the one that gets rid of the padding that both buttons and template use by default - to make the button fill to the size of the template. nr-dashboard-template is also involved. None of this seems to affect other items on the screen.

ROUNDED is simply a means of forcing rounding on buttons - you can adjust that radius to suit or eliminate it if you like.

The scripts - well VIBRATE merely invokes the haptic feedback when you press a button - easy when you know how.

TOUCHED and it's associated restore function are variations on the ones I used with images. The class allows on press for a button to store it's colour - change it's colour - wait for a while - and change it back - all without having to have individual colour control on the actual button  - which simply has the default colour you select.

Now let's take a look at once of those templates. Oh and I got those subtle colours from here - https://flatuicolors.com/

<md-button class="vibrate filled touched rounded" style="background-color:#c0392b" ng-click="send({payload: 'Hello World'})"> 
    Red<br/>button
</md-button>

Simple? Yes because the previous code makes it so. A button in a template - auto stretched by the code above and all it has added is the background colour - which the above code can manipulate - and the classes. That's it. The ng_click is what happens when you press the button - the template outputs a payload of whatever you've set. No, really that is it.  so on that output, msg.payload will be whatever you set it to be.

With background colour control, RGB and related buttons become simple - a page full of colours for RGB controls becomes possible.  Note in the class ROUNDED I changed the font size - well you could separate that off to a separate class - and create classes (say) BIGTEXT and LITTLETEXT for example - suitable for different size buttons.

When you grasp this - if you're not there already, immediately all sorts of ideas should come to mind -it's a bit like opening a new door to see all the things behind it. Within days my demo screen will look utterly amateurish as I start adding icons etc but today was important as it was, for me a confirmation that there really is not a lot you can't do with node-red-dashboard – so many congratulations to the original developer and the guys at IBM and everyone contributing. 

If you go to the ANGULAR site and look at their examples - most of them work no problem - changing these rectangular buttons to round ones is a snap!

Oh, talking of improving things  - here’s a snapshot hours later as things progress…NICE!

new buttons

 

Oh – here… http://flows.nodered.org/flow/4bfad41290eda31588ff63a23815ac5c  - if you want a play…. and YES that template uses a little white space – but next Node-Red-Dashboard release it will NOT – css and scripts only will NOT use up screen real estate – all coming together VERY well right now.

Facebooktwittergoogle_pluspinterestlinkedin

A Little Dashboard Something

tmp11D3Something for the weekend sir? How about a simple means to get visual and tactile feedback from node-red-dashboard buttons?

Or rather than large buttons – icons you may create or obtain yourself in a node-red-dashboard template.

To backtrack: For my own home control endeavours, I’ve been using a number of visual interfaces over time as some of you know – we’ve discussed in here – Imperihome and Blynk for example.

Recently I’ve been taking a look at Node-Red-Dashboard. Originally called Node-Red-Contrib-UI this has come a long way in recent months and I think is worth more investigation because of it’s ultimate flexibility.

I needed a set of controls for my thermostats – you’ll see an example in the image on the right. As well as turning heating up and down (and I have two separate systems for my office and home) – I have for some two years now had Node-Red handling 5 time-zones during the week and 5 at the weekend as well as frost fallback and holdoff controls (so we can turn the heating to frost setting if we pop out for the day (or for 6 months in one case)). Also as one of our properties is holiday rental, on the odd week it is not in use, it is handy to be able to stop down the heating for a few days, secure in the knowledge it will automatically turn back up when the time interval is done.

At the user end, I’ve used Imperihome for this and Blynk – and neither are ideal as I need so many controls.  Blynk controls are just too big and the slider values are not separately programmable – that is I can’t get them to show hours and minutes. Imperihome has controls for every imaginable device – but very few “generic” controls.

setup windowsThe Node-Red-Dashboard template has always been my favourite option but in the past seemed complicated and control over I/O was limited. Not any more. As you can see, it came to the rescue with a little coding. The standard  numeric up-down control in the dashboard is BORING with an awful pair of up-down arrows with no kind of feedback. History.

The controls you see here are my own effort – all in one template – and hence I have more control over the vertical spacing without which this would take several pages.

So – for any given control you are looking at programme time, temperature for that programme, up and down controls for the programme time and temperature. A feature of the template control (un-tick both arrows in the setup window) separates inputs from outputs – so you can fire information into the node and use that for display only – and buttons can fire values back out – but the standard buttons were WAY too big – so – I used images. Each section here is nothing more than a standard DIV with 3 spans – the final span holding four images.

<div layout="row" layout-align="space-between" style="padding:0px; text-align: left; margin:2px; border:2px solid black;">
<span style="width:28%;padding-top:5px;padding-left:5px;">{{"P1: "+ msg.payload.p1}}</span>
<span style="width:28%;padding-top:5px;padding-left:5px;">{{"T1: "+ msg.payload.t1 + "c"}}</span>
<span style="width:44%; padding-top:3px;">
    <img class="lightup" src="http://xx/icons/timed.png" ng-click="send({payload: 'p1dn' })" height="24px"/>&nbsp;
    <img class="lightup" src="http://xx/icons/timeu.png" ng-click="send({payload: 'p1up' })" height="24px"/>&nbsp;
    <img class="lightup" src="http://xx/icons/tempd.png" ng-click="send({payload: 't1dn' })" height="24px"/>&nbsp;
    <img class="lightup" src="http://xx/icons/tempu.png" ng-click="send({payload: 't1up' })" height="24px"/>
</span>
</div>

I’ve shortened the URL for the images (any old publically available place) to fit onscreen. I put them on my website in a folder called “icons”- but that’s arbitrary.

So – you’ll see the “moustaches” {{}} surrounding incoming information – my first ignorant thought when using one of these templates was that you were limited to msg.payload – but no you are not – you can send an entire object in there.  Hence the page is a series of the above DIVs. Each image (used as a button) sends out a unique message and a simple lookup table decides what to do with them.

template

So above, the blue template is the page you see up at the top – the output is passed to a function in which you can use a case statement to decide what you want to do with each button press.  The second function is triggered every couple of seconds and formats your various settings into an object for injecting into the function (in case these values are altered elsewhere, you want to see changes appear on your phone display). The output from the first function ALSO feeds that function so any changes you make with the buttons – once processed – show immediate changes in the values you see in the topmost image.

So – all very nice – press the anti-clockwise time or clockwise green images – the times change (in my case in 15 minute intervals but they are actually stored in minutes – hence the second function does a bit of formatting).

But it is all very boring – you get no visual feedback from the images – and no tactile feedback from the phone. Well, let me say that I’ve spent several hours going down blind alleys – and learned a lot today. The end result – visual “brightup” icons when you press them – AND full tactile “vibrate” feedback on mobile devices.

<script>
function restore_icon() {
        $(this).attr('src',$(this).attr('src').replace("_b.png",".png"));
    };

$('.lightup').on('mousedown', function() {
    $(this).attr('src',$(this).attr('src').replace(".png","_b.png"));  
    setTimeout(restore_icon.bind(this),500);
    navigator.vibrate(100);
    });
</script>

And it is SO easy once you know how.

It turns out you can use jQuery inside the templates – which is awfully handy – and a modern line to control the buzzer.

When you create or use a (.png) (transparent) image you want as a button – make another with a suffix “_b” for bright. The code below on press replaces the image with the bright version and shortly thereafter with the original.  At the same time the excruciatingly simple vibrate line makes the phone vibrate briefly.  You have no idea where I’ve been with this – but note it is a recent addition but modern phones and tablets should handle it.

Note the class=”lightup” in the above img definitions. Stick this code at the top of the template and all will work magically..

The second part of this code changes the image to the bright version and starts off a short vibrate – while setting a timer at the end of which – the original image is replaced. It is that simple. Because I don’t refer to the actual image – you can have several different images which will operate in the same way.

I’m no CSS expert but with a little care and reading up you can make a pretty control page all in one template completely under your control – and of course – making the alternative image brighter was just my idea – you may chose another path. “Blynk”-type controls should be a doddle.

Have a nice weekend.

 

Enjoy.

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

Variable Persistence in Node-Red

It is my understanding that Node-Red will eventually have persistent variables - but while we're waiting - this is how I do it. Using the global.get and global.set mechanisms, I store a single object.

So - when Node-Red pops up it looks to the SD for that object - if not there it creates and initialises it. If there, it reads it into the struct. There is a countdown timer in the object and the function controlling all of this is called every 5 seconds. If the counter is zero, nothing happens. If the counter is true, it is decremented. If it gets to zero, the object is saved to disk over-writing the original.  It is that simple and it has worked for me for a long time now.

So imagine a Node-Red user function - with a 5 second timer feeding it (the INJECT NODE) - the payload of the latter is irrelevant.

Here's the function - the object and it's internal bits are mine - you'd alter them for whatever you need.

/ The purpose of this code is to update an object on change. At power up check for file and create if necessary
// var is "intel" in this case
var fs = global.get("fs");
var fl="/home/pi/intel.data";

if (global.get("intel")!==undefined) // Remember - don't use !== with null
    {
        if (global.get("intel.Counter")!==0) // if the var exists - now check counter
        {
         global.set("intel.Counter",global.get("intel.Counter")-1); // if counter is non-zero - decrement it
         if (global.get("intel.Counter")===0)  // if counter drops to zero update file
            {
                   fs.writeFile(fl, JSON.stringify(global.get("intel")), function(err) {
                    if(err) {
                        return console.log(err);
                        }
                    }); 
            }
        }
    }
    else 
    {   // If no var (powerup scenario) ..does the file exist?
        try {
                fs.accessSync(fl, fs.F_OK);
                // If file exists create the VAR by reading the file into it
                fs.readFile(fl, 'utf8', function (err,data) {
                  if (err) {
                    return console.log(err);
                        }
                  global.set("intel",JSON.parse(data));
                });
            } catch (e) 
            {
                // Otherwise create both var AND file -  ensuring counter is zero. New bits can be added dynamically
                intel = {
                        ShelfWhiteLight:0,
                        BoilerState:0,
                        ShelfRgbState:0,
                        ShelfRgbLevel:0,
                        ShelfRgbColour:"AAAAAAAA",
                        OfficeRgbState:0,
                        gOfficeRgbLevel:0,
                        OfficeRgbColour:"AAAAAAAA",
                        PergolaRgbState:0,
                        PergolaRgbLevel:0,
                        PergolaRgbColour:"AAAAAAAA",
                        Counter : 0
                    };
                    fs.writeFile(fl, JSON.stringify(intel), function(err) {
                    if(err) {
                        return console.log(err);
                        }
                    }); 
            }
    }

 

 

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

IOT Manager Revisited

This started off as a very short blog some time ago – you’ll see  comments below but I’ve re-written it. I occasionally like to revisit stuff I have reviewed or played with ages ago because, well, things change. Had I not persevered with ImperiHome I would not now have a perfectly good IOT controller on my phone as originally it did not support Node-Red (Peter Oakes and I soon fixed that - documented elsewhere) and that package is now my preferred central control tool (the fact that it is now bog-standard fitment on the world’s most popular SBC – the Raspberry Pi – is another good reason to stick with it).

(Some regular readers may ask – what happened to BLYNK? – well,  it is still running back in the UK reliably – has been doing so for nearly 6 months – I just happen to prefer Imperihome).

IOT ManagerSo, IOT Manager is a weird one – the programming is different to many of the systems out there which try to be all things to all people – supporting endless devices many of which will no doubt bite the dust in time and it is not yet as advanced as either Blynk or Imperihome, but the author is keen – has done a LOT of changes for me and is rapidly approaching the point where it will compete with the likes of Imperihome.

http://esp8266.ru/iotmanager/

Let me say that at the time of writing you need the BETA version of IOT Manager to get the best out of it. Joinging the beta program is trivial.

So on first revisiting IOT Manager, could I HELL remember how to use it.  One of it’s original “features” was support for websockets for MQTT – fine – but it ran rather slowly and I think that’s one reason I abandoned it – so when I noted that it now also supports MQTT directly – with username and password – and figured I’d give it another shot.

So I loaded up the Android App and filled in my MQTT broker details and… nothing. Try as I might I could not figure out how to add a widget. All I had was a screen that said “no data” and a green indicator showing that it was indeed connected to my MQTT server (public address). It didn’t help that the website went on about Arduinos and stuff and really didn’t seem to get to the bottom of how to quickly get started if you didn’t have one of those. The documentation has still not quite caught up with developments.

ChartHaving loaded up IOT Manager there are no settings on the phone to create widgets  – instead, MQTT messages tell it what to do and YOU send those from, for example Node-Red! It’s really easy once you get past that hurdle.

So how the package NOW works is to initially send out a request for updates on the number and details of pages needed – and to ask for details of widgets required.

From then on the phone will request updates on specific page widgets as and when a page is selected or focus is lost. This minimises the information that needs to be sent.

When a button is pressed the info is sent back from the App by MQTT. I’ve chosen to process all of this with Node-Red. Plain NodeJS would no doubt do just as well.

Here is a list of the current widgets which includes sliders and power buttons as well as toggles…

  •       anydata
  •       simple-btn
  •       display-value
  •       small-badge
  •       power-button
  •       range
  •       toggle
  •       SteelSeries
  •       fillgauge
  •       chart

The CHART widget is new and I’ve not yet had time to test it but here’s an example on the right above.

In the example below I have three pages (named page1, page2 and page3). On the first page are two switches and a slider (range7). On the second are 3 level gauges and on page 3 are a couple of thermometer-type displays.

IOT Manager - my Node-Red code - Peter Scargill

This is what they look like…

1[4]  2[4]  3

What we have here is an APP that connects to your MQTT server (or a public one) and at that point sits and does nothing.

Essentially once the phone is connected it is listening to an MQTT subscribe. Your controller – say, Node-Red on a Raspberry Pi or even a simple ESP8266 (but you still need an MQTT broker either locally or a publically-available broker)  when it turns on and connects to the same MQTT broker, sends some init code and magically a bunch of controls appear on the phone – you can then use the controls and they send out info back to Node-Red or whatever you want to use as a central controller. What is great about this is that it could be dynamic – as this is set at the control end, not the App end.

I centralise everything via Node-Red which of course can publish and subscribe to MQTT and then control my devices from there. I decided to write the code for Node-Red to give others a starting point.

So you can see in the diagram above the two SUBSCRIBES. That info is passed to a couple of functions – here they are…

var topic=msg.topic.split("/")[3];
global.set("IoTmanager_" + topic,msg.payload);

And now the second function...

var prefix = "/IoTmanager";
var deviceId = "bedrock";
var config = [];

var pagesList = {
    pages: [
        { pageId: 10, pageName: "page1" },
        { pageId: 20, pageName: "page2" },
        { pageId: 30, pageName: "page3" }
    ]
};

var id = "0";
var widget="toggle";
  config[0] = { 
  id : id,
  page: pagesList.pages[0].pageName, 
  pageId: pagesList.pages[0].pageId,
  descr : "pump 1",
  widget : widget,
  itemstyle : "",
  itemclass : "",
  topic: prefix + "/" + deviceId + "/" + widget + id,
  color : "orange",
  style : ""
};


  id = "1";
  widget="toggle";
  config[1] = {
  id : id,
  page: pagesList.pages[0].pageName,
  pageId: pagesList.pages[0].pageId,
  descr : "pump 2",
  widget : widget,
  style1 : "",
  class1 : "",
  topic: prefix + "/" + deviceId + "/" + widget + id,
  color : "blue",
  style : ""
};

  id = "7";
  widget="range";
  config[7] = {
  id : id,
  page: pagesList.pages[0].pageName,
  pageId: pagesList.pages[0].pageId,
  descr : "range 1",
  widget : widget,
  topic: prefix + "/" + deviceId + "/" + widget + id,
  color : "blue",
  style1 : "\"style\":\"range-balanced\"",   
  badge1 : "\"badge\":\"badge-balanced\""
};


  id = "2";
  widget="fillgauge";
  config[2] = {
  id : id,
  page: pagesList.pages[1].pageName,
  pageId: pagesList.pages[1].pageId,
  widget : widget,
  class1 : "item no-border",
  style1 : "",
  descr  : "Water level",
  class2 : "light text-center",
  style2 : "font-size:24px;font-weight:bold;padding-bottom:5px;",
  topic: prefix + "/" + deviceId + "/" + widget + id,
  width  : "150",
  height : "150",
  class3 : "text-center",
  style3 : "",
  widgetConfig : {
  }
};

  id = "3";
  widget="fillgauge";
  config[3] = {
  id : id,
  page: pagesList.pages[1].pageName,
  pageId: pagesList.pages[1].pageId,
  widget : widget,
  class1 : "no-border text-center col-xs-4",
  style1 : "",
  descr  : "Fuel level",
  class2 : "assertive text-center",
  style2 : "font-size:14px;padding-bottom:5px;",
  topic: prefix + "/" + deviceId + "/" + widget + id,
  width  : "70px",
  height : "70px",
  class3 : "text-center",
  style3 : "",
  widgetConfig : {
    circleColor : "#FF7777",
    textColor : "#FF4444",
    waveTextColor : "#FFAAAA",
    waveColor : "#FFDDDD",
    circleThickness : 0.2,
    textVertPosition : 0.2,
    waveAnimateTime : 1000
  }
};

  id = "4";
  widget="fillgauge";
  config[4] = {
  id        : id,
  page: pagesList.pages[1].pageName,
  pageId: pagesList.pages[1].pageId, 
  widget    : widget,
  class1    : "no-border text-center col-xs-4",
  style1    : "",
  descr     : "Water level",
  class2    : "energized",
  style2    : "font-size:14px;padding-bottom:5px;",
  topic: prefix + "/" + deviceId + "/" + widget + id,
  width     : "70px",
  height    : "70px",
  class3    : "text-center",
  style3    : "",
  widgetConfig : {
    circleColor : "#D4AB6A",
    textColor : "#553300",
    waveTextColor : "#805615",
    waveColor : "#AA7D39",
    circleThickness : 0.1,
    circleFillGap : 0.2,
    textVertPosition : 0.8,
    waveAnimateTime : 2000,
    waveHeight : 0.3,
    waveCount : 1
  }
};

    id = "5";
    widget="steel";
    config[5] = {
    id     : id,
    page: pagesList.pages[2].pageName,
    pageId: pagesList.pages[2].pageId,
    descr  :"Steel 1",
    widget : widget,
    topic: prefix + "/" + deviceId + "/" + widget + id,
    widgetConfig : {
    width  : "auto",
    height : 100,
    type   : "Linear",
    titleString: "Thermometer 1",
    unitString : "temp C",
    threshold: 90
}
};

    id = "6";
    widget="steel";
    config[6] = {
    id     : id,
    page: pagesList.pages[2].pageName,
    pageId: pagesList.pages[2].pageId,
    descr  :"Steel 2",
    widget : widget,
    topic: prefix + "/" + deviceId + "/" + widget + id,
    widgetConfig : {
    width  : "auto",
    height : 100,
    type   : "Linear",
    titleString: "Humidity 1",
    unitString : "% Hum",
    threshold: 90
}
};


// extract command and param
var msg2 = JSON.parse(msg.payload.toString());

if (msg2.command==="getPages")
    {
     msg.topic=prefix + "/" + deviceId + "/response";
     msg.payload=JSON.stringify(pagesList);
     node.send(msg);   
    }

else if (msg2.command === "getPageById" && msg2.param > 0) 
    {
                 pagesList.pages.forEach(function(item, i, arr) {
                // it is one of our pages?
                if (item.pageId === msg2.param) {
                    // node.warn('Request is for existing page "' + item.pageName + '", pageId="' + msg2.param + '"');
                    pubPage(msg2.param);
                }
            });
    }

else if (msg2.command === "getPageById" && msg2.param === 0) 
        {
            //node.warn('Request is for All pages.');
            pubPage(0);
        }






function pubPage(page) {

    // check all widgets and pub widgets config from requested page
    config.forEach(function(item, i, arr) {
        if (item.pageId === page || page === 0) {

            // pub config for one widget
            msg.topic=prefix + "/" + deviceId + "/config";
            msg.payload=JSON.stringify(item);
            node.send(msg);
            //node.warn("Page " + item.pageId + " id " + i);
            // pub status for one widget
            pubStatus(i);
        }
    });
}


function pubStatus(i) {
var status;
switch (i)
    {
        case 0 : status=global.get("IoTmanager_toggle0"); break;
        case 1 : status=global.get("IoTmanager_toggle1"); break;
        case 2 : status=global.get("IoTmanager_fillgauge2"); break;
        case 3 : status=global.get("IoTmanager_fillgauge3"); break;
        case 4 : status=global.get("IoTmanager_fillgauge4"); break;
        case 5 : status=global.get("IoTmanager_steel5"); break;
        case 6 : status=global.get("IoTmanager_steel6"); break;
        case 7 : status=global.get("IoTmanager_range7"); break;

    }
msg.topic=config[i].topic + "/status";
msg.payload=JSON.stringify({ status: status });
node.send(msg);
}

As for individual items - well, to turn on or off a switch is as easy as...

var fred=msg.payload;
msg.topic="/IoTmanager/bedrock/toggle0/status";
msg.payload="{\"status\":\""+fred+"\"}";
global.set("IoTmanager_toggle0",fred);
return msg;

Depending on whether you fire the string "0" or "1" at that function it will turn on or off the switch.

The main function above is comprised mainly of definitions for the various items and you can find out more about them at the author's site - indeed that IS the place to look in case he changes anything and expect him to add more in future.

So - do we have an up and coming competitor for Blynk and Imperihome? I'll leave that for you to decide.

Facebooktwittergoogle_pluspinterestlinkedin