Editors

Programming editors, like music, are a matter of personal taste and I don’t hope to convert anyone here today. I would however like to bring something to your attention which I discovered at the weekend.

I’m a “Notepad++” man. I don’t particularly like the look of NotePad++ but it is fast and flexible and has colour-coding. It’s a Windows only program but has lots of plug-ins. It is my favourite editor. Well, it was.

I’ve recently been toying with other editors such as Atom but invariably I last a matter of hours with new things before finding bugs – which I am very good at, unfortunately. I think the first issue I had with Atom was Javascript refactoring but there were other issues which, all in sent me scampering back to NotePad++

There is of course Visual Studio – and that’s very nice for Windows users if you can handle it being slow as molasses – I can’t. Life is way too short to sit and wait for it to start up.

Then there is Sublime Text 3. I started warming up to that too – but again little niggles I didn’t like.

Until recently I figured I may as well stick with NotePad++ but for a chance trip to see my friend Jonathan. As always when we meet up he has stuff I’m not up to speed with and vice-versa and so it was that in the course of conversation he asked me if I was using Visual Studio Code?

My immediate reaction wasn’t totally positive – thinking it would have something to do with Visual Studio and hence “tarred with the same brush”. Anyway, being Jonathan I could not dismiss this out of hand so I asked him to show me what he was on about.

Well, things have certainly changed at Microsoft, haven’t they! Presumably partly due to Steve Ballmer disappearing off the scene?

Visual Studio Code is an editor – simple as that – a code editor. I’ve been playing with it for hours now and done some major upgrades to one of my nodes with it.  This fast, free (and importantly advert-free) clean multi-panel editor appears to have everything that Notepad++ has – and VERY much more. The first thing I noticed on pulling in my JavaScript Visual Studio Codecode was the really nice colour coding and the dark theme. The second thing – and in all honesty one of the main reasons I’m attracted to this – is the really good Intellisense.  Was it that or the document formatting, turning my spiders web of a program into a very neat job at a button-press.

Or was it the gob-smacking list of extensions? Or the GIT integration, file compare… whatever, I’m a convert.

There are some features you might not believe if you’ve not kept up with Microsoft… extensions for debugging via Chrome (yes, that’s the competitor’s program) or the (untested by me) stunning fact that this editor is also available for the MAC and LINUX !!! What!!???! In my case I’m happy to stick with editing in Windows.

So – free, better than what I’m using now, fast, flexible and supported by Microsoft Why wouldn’t I be impressed. If you give the editor a go (which takes no time at all in Windows), you might be too. Integrates no problem as the primary editor for WinSCP.

Lovely.

Facebooktwittergoogle_pluspinterestlinkedin

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

AlexaPi and a Warning

Amazon DOTIt’s been a busy week already – I’ve been saving up a load of “Can we write articles for your blog?” emails and this morning I decided to take a look. The sample articles were ATTROCIOUS and now I know why so many articles are bad out there – they are written to order by people who just write stuff. Well, no thanks. I’ve asked the lot of them to remove me from their databases.

In the course of the post coming in I noted a Github notice of a new version of ALEXAPI – now for those of you who don’t live in the USA or America, Amazon Alexa is a box that you can talk to and control your home, play music (theirs, not yours) and generally buy Amazon products without needing to be able to read and write. It’s a wonderful thing. ALEXAPI claims to do the same on a Raspberry Pi or similar.

I have two of the Amazon DOT devices (which are very reasonably priced at £49 as against the full on unit which IMHO is, like the Google unit and others, way OVER priced). Very happy with them. Well, I’d be happier if they had an RJ45 connection instead of just WIFI – but that’s ok.

So what do we do with these? Well, we have shopping lists, we listen to music (on Maureen’s account as she has Prime, I don’t) and we control house heating, lighting etc. All in all they’re part of the family – and the BIRDSONG skill drives our cats NUTS which is a lot of fun.

And so it was that I found this link interesting in the email this morning. With this software, a usb mic and speaker of some kind, not only can you emulate an Alexa on a Raspberry Pi but on all manner of other devices.

Now, I long ago gave up on using a Pi, £32 for the Pi, plus powered speaker, plus decent mic plus case plus power supply comes to WAY over the cost of a ready-built Echo complete with REALLY pretty lights and a microphone array.

But this morning for a moment I was distracted – one could use an Orange Pi Zero which is only a few quid!!!  And off I went and followed the instructions. So – before I start, if you want to play with this – you CAN install this on an Orange Pi Zero (Armbian is good), it DOES work and you CAN completely uninstall if. Been there, done that.

I stuck in my USB audio adaptor, powered speaker, 3.5mm stereo microphone and installed the software. I filled in the details on Amazon which gave me the necessary keys to update the config on the AlexaPi.  I rebooted the Orange Pi Zero and…

Nothing.  As usual, audio settings. I talked to some VERY helpful people on their forums who guided me through changing the settings to the USB audio device. I tested it – audio output – perfect. Audio input – perfect. I thanked them,  rebooted and…

“Hello”…

Well, I nearly fell off my seat. “Alexa, what time is it?” – after quite some delay (this is NOTHING like a DOT which responds almost instantly) the unit came back with the time.  I tried a radio station and LO, it played the radio station. By now I was getting excited… I could put up with the delay.

Sadly, and this is no reflection on the obviously hard work done by the designers, things went downhill from there.

“change accounts” I said, wanting to switch to my wife’s account as she has Amazon music. No other people in the account setup. That could have been just a technicality so I ignored that. remember I know exactly how to use these things as I have two DOTS.

“Set a timer” – turns out the unit does not do lists – most likely API-related.

“Find my devices” – this was the killer. It took some hunting down but it was actually in the UNINSTALL instructions that I found … “AVS API doesn't have a way to connect the devices to Amazon.”

That last one was the killer. That and the mic – the problem is – Amazon put a lot of work into the mics – and they handle speech over background music reasonably well. I can blast my music and shout over the couch “ALEXA – SHUT UP” – and it promptly obeys. Not so the AlexaPi – while playing the radio could I HELL get it to take any notice of me until I turned the music down – and I was only sitting 2ft away.

I uninstalled the lot – and my Orange Pi Zero seems to be as good as new. So if you want something new to play with – or if you have a very limited set of needs – have a play. For me – I’d rather fork out £49 at this point.

It was suggested that one thing this software could to that the real thing can’t – is respond asynchronously – i.e. use it to output speech without a command – that is an annoying omission on the Amazon system – though if you write a special skill you can have it say what you want in reply – but then you have to call the skill and have a secure connection etc. 

But then it occurred to me – I have a Raspberry Pi running the house and HABRIDGE – and it has Node-Red and I already have IVONA speech on it – all I need is a speaker and when the DOT talks to HABRIDGE to fire an MQTT control message to my lighting and heating – it can also send off some speech itself. Don’t know why I didn’t think of that before.

So there it is.

Facebooktwittergoogle_pluspinterestlinkedin

Node Red and HighCharts

HiChart Charts in Node-RedFirst things first – HighCharts are not free for commercial use. However, for your own website, a school site or a non-profit organisation they are free to use. You are also OK to make modifications. So – that’s the “cover my back” bit out of the way – now, how to use them in Node-Red.

I’ve looked at this before, because their charts are very, very nice.  As some of you know, I’m now sold on Grafana but I also really like the idea of using charts with my favourite database – SQLITE and this is not supported as far as I can see with Grafana. Indeed I’m glad there is a Node-Red Node for InfluxDB as I had trouble getting my head around inputting data into InfluxDB otherwise (the node makes it REALLY easy).

And so it was that I came back to HighCharts. Now one of the demos of theirs that I really like, involves plotting variable numbers of time-based lines in a graph (temperature, humidity etc)– with potentially missing values. I found when using other chart systems that if you had the odd missing value due to power failure etc, you had to fix that – with the HighCharts demo it just draws a smooth curve between the two.

Another of their demos features zooming and it is only in the last couple of days when taking another look – that I realised you could combine the two – zoomable multi-line graphs.

What you see on the right is little more than a tweeked version of their basic demo – with a few bits taken out to make the whole thing work in the limited space we typically have in Node-Red Desktop – and zooming built in.

I tested everything in JSFiddle and then tried dumping it into Node-Red – nothing – zilch. I found that using the libraries remotely just would not work. Out of desperation I grabbed the libraries, one of which is big and put them into one of my usual “myjs” directories on the Raspberry Pi and lo and behold, it all worked.

Sample data into HiCharts

Here you see above my test – now bear in mind this is very preliminary. In the brown FUNCTION nodes I have 2 different sets of data just to test things… and these feed an object in msg.payload through to the Dashboard UI. I’ve made two of these – using two different DIVs. One is called “mine1” and the other is called “mine2” – they fill DIV ids “container1” and “container2" respectively. Everything else is the same.

So – starting off with their demo here http://www.highcharts.com/demo/spline-irregular-time

I took that demo and wrapped the lot in a function (object) – so as to hide everything from the outside world in case I wanted two or more of these on a page. I then wrapped the code inside a local, externally accessible function. This could be way more efficient – but I wanted something up and running and as you will see I have two completely independent graphs here.

Here is the code inside the blue template. The only thing that changes is the reference to the DIV (container1/container2) and the references to the new object (mine1/mine2) – and of course near the end I’ve fed unique titles and subtitles when creating the object but the latter do not have to be unique.

<script src="/myjs/highcharts.js"></script>
<script src="/myjs/exporting.js"></script>
<div id="container1" style="min-width: 300px; height: 300px; margin: 0 auto"></div>

<script>
   (function(scope){
        scope.$watch('msg', function(msg) {
          mine1.graph(msg.payload);
        });
    })(scope);


var sample_data1=[{
        name: 'Winter 2012-2013',
        // Define the data points. All series have a dummy year
        // of 1970/71 in order to be compared on the same x axis. Note
        // that in JavaScript, months start at 0 for January, 1 for February etc.
        data: [
            [Date.UTC(1970, 9, 21), 0],
            [Date.UTC(1970, 10, 4), 0.28],
            [Date.UTC(1970, 10, 9), 0.25],
            [Date.UTC(1970, 10, 27), 0.2],
            [Date.UTC(1970, 11, 2), 0.28],
            [Date.UTC(1970, 11, 26), 0.28],
            [Date.UTC(1970, 11, 29), 0.47],
            [Date.UTC(1971, 0, 11), 0.79],
            [Date.UTC(1971, 0, 26), 0.72],
            [Date.UTC(1971, 1, 3), 1.02],
            [Date.UTC(1971, 1, 11), 1.12],
            [Date.UTC(1971, 1, 25), 1.2],
            [Date.UTC(1971, 2, 11), 1.18],
            [Date.UTC(1971, 3, 11), 1.19],
            [Date.UTC(1971, 4, 1), 1.85],
            [Date.UTC(1971, 4, 5), 2.22],
            [Date.UTC(1971, 4, 19), 1.15],
            [Date.UTC(1971, 5, 3), 0]
        ]
    }, {
        name: 'Winter 2013-2014',
        data: [
            [Date.UTC(1970, 9, 29), 0],
            [Date.UTC(1970, 10, 9), 0.4],
            [Date.UTC(1970, 11, 1), 0.25],
            [Date.UTC(1971, 0, 1), 1.66],
            [Date.UTC(1971, 0, 10), 1.8],
            [Date.UTC(1971, 1, 19), 1.76],
            [Date.UTC(1971, 2, 25), 2.62],
            [Date.UTC(1971, 3, 19), 2.41],
            [Date.UTC(1971, 3, 30), 2.05],
            [Date.UTC(1971, 4, 14), 1.7],
            [Date.UTC(1971, 4, 24), 1.1],
            [Date.UTC(1971, 5, 10), 0]
        ]
    }, {
        name: 'Winter 2014-2015',
        data: [
            [Date.UTC(1970, 10, 25), 0],
            [Date.UTC(1970, 11, 6), 0.25],
            [Date.UTC(1970, 11, 20), 1.41],
            [Date.UTC(1970, 11, 25), 1.64],
            [Date.UTC(1971, 0, 4), 1.6],
            [Date.UTC(1971, 0, 17), 2.55],
            [Date.UTC(1971, 0, 24), 2.62],
            [Date.UTC(1971, 1, 4), 2.5],
            [Date.UTC(1971, 1, 14), 2.42],
            [Date.UTC(1971, 2, 6), 2.74],
            [Date.UTC(1971, 2, 14), 2.62],
            [Date.UTC(1971, 2, 24), 2.6],
            [Date.UTC(1971, 3, 2), 2.81],
            [Date.UTC(1971, 3, 12), 2.63],
            [Date.UTC(1971, 3, 28), 2.77],
            [Date.UTC(1971, 4, 5), 2.68],
            [Date.UTC(1971, 4, 10), 2.56],
            [Date.UTC(1971, 4, 15), 2.39],
            [Date.UTC(1971, 4, 20), 2.3],
            [Date.UTC(1971, 5, 5), 2],
            [Date.UTC(1971, 5, 10), 1.85],
            [Date.UTC(1971, 5, 15), 1.49],
            [Date.UTC(1971, 5, 23), 1.08]
        ]
    }];
    
function doit(theContainer,title,subtitle)
{
this.graph=function(xx)
{
Highcharts.chart(theContainer, {
    chart: {
        zoomType: 'x',
        type: 'spline'
    },
    title: {
        text: title
    },
    subtitle: {
        text: subtitle
    },
    credits: { enabled: false },
    xAxis: {
        type: 'datetime',
        dateTimeLabelFormats: { // don't display the dummy year
            month: '%e. %b',
            year: '%b'
        },
        title: {
            text: 'Date'
        }
    },
    
    exporting: {
            buttons: {
                contextButton: {
                    enabled: false
                } } },

    yAxis: {
        title: {
            text: 'Snow depth (m)'
        },
        min: 0
    },
    tooltip: {
       headerFormat: '<b>{series.name}</b><br>',
       pointFormat: '{point.x:%e. %b}: {point.y:.2f} m'
    },

    plotOptions: {
        spline: {
            marker: {
                enabled: false
            }
        }
    },

    series: xx
});

}

}
mine1=new doit("container1","title1","Subtitle1");
mine1.graph(sample_data1);
</script>


and here is the code inside one of those orange functions – the only thing that changes is the data.

msg.payload=[{
        name: 'Win 2012-2013',
        // Define the data points. All series have a dummy year
        // of 1970/71 in order to be compared on the same x axis. Note
        // that in JavaScript, months start at 0 for January, 1 for February etc.
        data: [
            [Date.UTC(1970, 9, 21), 0],
            [Date.UTC(1970, 10, 4), 0.28],
            [Date.UTC(1970, 10, 9), 0.25],
            [Date.UTC(1970, 10, 27), 0.2],
            [Date.UTC(1970, 11, 2), 0.28],
            [Date.UTC(1970, 11, 26), 0.28],
            [Date.UTC(1970, 11, 29), 0.47],
            [Date.UTC(1971, 0, 11), 0.79],
            [Date.UTC(1971, 0, 26), 0.72],
            [Date.UTC(1971, 1, 3), 1.02],
            [Date.UTC(1971, 1, 11), 1.12],
            [Date.UTC(1971, 1, 25), 1.2],
            [Date.UTC(1971, 2, 11), 1.18],
            [Date.UTC(1971, 3, 11), 1.19],
            [Date.UTC(1971, 4, 1), 1.85],
            [Date.UTC(1971, 4, 5), 2.22],
            [Date.UTC(1971, 4, 19), 1.15],
            [Date.UTC(1971, 5, 3), 0]
        ]
    }, {
        name: 'Win 2013-2014',
        data: [
            [Date.UTC(1970, 9, 29), 0],
            [Date.UTC(1970, 10, 9), 0.4],
            [Date.UTC(1970, 11, 1), 0.25],
            [Date.UTC(1971, 0, 1), 1.66],
            [Date.UTC(1971, 0, 10), 1.8],
            [Date.UTC(1971, 1, 19), 1.76],
            [Date.UTC(1971, 2, 25), 2.62],
            [Date.UTC(1971, 3, 19), 2.41],
            [Date.UTC(1971, 3, 30), 2.05],
            [Date.UTC(1971, 4, 14), 1.7],
            [Date.UTC(1971, 4, 24), 1.1],
            [Date.UTC(1971, 5, 10), 0]
        ]
    }, {
        name: 'Win 2014-2015',
        data: [
            [Date.UTC(1970, 10, 25), 0],
            [Date.UTC(1970, 11, 6), 0.25],
            [Date.UTC(1970, 11, 20), 1.41],
            [Date.UTC(1970, 11, 25), 1.64],
            [Date.UTC(1971, 0, 4), 1.6],
            [Date.UTC(1971, 0, 17), 2.55],
            [Date.UTC(1971, 0, 24), 2.62],
            [Date.UTC(1971, 1, 4), 2.5],
            [Date.UTC(1971, 1, 14), 2.42],
            [Date.UTC(1971, 2, 6), 2.74],
            [Date.UTC(1971, 2, 14), 2.62],
            [Date.UTC(1971, 2, 24), 2.6],
            [Date.UTC(1971, 3, 2), 2.81],
            [Date.UTC(1971, 3, 12), 2.63],
            [Date.UTC(1971, 3, 28), 2.77],
            [Date.UTC(1971, 4, 5), 2.68],
            [Date.UTC(1971, 4, 10), 2.56],
            [Date.UTC(1971, 4, 15), 2.39],
            [Date.UTC(1971, 4, 20), 2.3],
            [Date.UTC(1971, 5, 5), 2],
            [Date.UTC(1971, 5, 10), 1.85],
            [Date.UTC(1971, 5, 15), 1.49],
            [Date.UTC(1971, 5, 23), 1.08]
        ]
    }];
    
return msg;

With more work, this could be really useful – and don’t forget to check the BIG range of graphs and other widgets in the HiCharts demos – there is some wonderful stuff in there.

Back to databases - as you can see it would not be hard at all to pull data like this out of just about any database! That's my next job after I tidy this up a bit.

Facebooktwittergoogle_pluspinterestlinkedin

Garden Data Collection

MiFloraThis entry is all about InfluxDB, Grafana and a cute little Bluetooth garden sensor!

Some time ago a pal of mine and I did some swaps of spare kit and I ended up with a Mi Flora sensor.  A rather pleasing looking device,  the MI Flora has a 3v lithium button cell and can transmit by Bluetooth LE, the light level, temperature, battery level and moisture.

Battery is supposed to last for months. I’ve provided an AliExpress link above which puts the units at under £8 Inc. postage. No doubt that price will vary dramatically depending on where you chose to spend your money. Amazon charge more like £13.

So having pulled off the protective tab which meant the battery would work, I put the unit to one side as I had no idea how to read it.

A week or so later in Spain, with poor weather my pal Jay came on to ask me if I’d used it. I had not – and so we decided to give it a go. As it turned out I had some cheap Bluetooth 4 dongles I’d bought on a whim last year. I plugged one into my Raspberry Pi 2. The program “hcitool” lets you scan for Bluetooth devices and as it happens it was already installed on the Pi. From the command prompt:

sudo hcitool lescan

Instant success as the Mi Flora device with it’s MAC address was revealed. I made a note of the MAC address.

I would need Python 3 to experiment – but this was already installed on the Pi and some code to get the information from the unit. This code turned out to be ok with a little modification. I ended up creating a folder called /home/pi/myflora and dumping the lot in there.

Jay had modified the program to send MQTT. That of course needed the PAHO client. In order to do that I needed something called PIP.

sudo apt-get install python3-pip

sudo pip3 install paho-mqtt

Note NOT pip (which works for Python 2.7) but pip3.

I then added to the MI flora directory a test program which Jay sent me called bathroom.py – presumably because he’d put the sensor in his bathroom – I adjusted the output slightly as I was putting my unit in the garden

import sys
import paho.mqtt.client as mqtt

from miflora.miflora_poller import MiFloraPoller, \
MI_CONDUCTIVITY, MI_MOISTURE, MI_LIGHT, MI_TEMPERATURE, MI_BATTERY

poller = MiFloraPoller("C4:7C:8D:32:08:63")
print("Getting data from Mi Flora")
print("FW: {}".format(poller.firmware_version()))
print("Name: {}".format(poller.name()))
print("Temperature: {}".format(poller.parameter_value("temperature")))
print("Moisture: {}".format(poller.parameter_value(MI_MOISTURE)))
print("Light: {}".format(poller.parameter_value(MI_LIGHT)))
print("Conductivity: {}".format(poller.parameter_value(MI_CONDUCTIVITY)))
print("Battery: {}".format(poller.parameter_value(MI_BATTERY)))

# Publishing the results to MQTT
mqttc = mqtt.Client("miflorabathroom")
mqttc.username_pw_set("admin","xxxx")
mqttc.connect("192.168.1.19", 1883)
mqttc.publish("miflora/garden", "{ \"battery\" : " + str(poller.parameter_value(MI_BATTERY)) + ", \"version\" : \"" + str(poller.firmware_version()) + "\", \"sunlight\" : " + str(poller.parameter_value(MI_LIGHT)) + ", \"temperature\" : " + str(poller.parameter_value("temperature")) + ", \"moisture\" : " + str(poller.parameter_value(MI_MOISTURE)) + ", \"fertility\" : " + str(poller.parameter_value(MI_CONDUCTIVITY)) + " }")
mqttc.loop(2)
# End of MQTT section

So the idea was that running “python3 garden.py” would send some MQTT to my Mosquitto MQTT broker – and indeed it did (change MAC address for the MI Flora and MQTT details in the above).  Subscribing to “miflora/garden” did the trick – I could fire off the program and with in seconds I’d see the resulting JSON package coming out into my MQTT-Spy client.

Next job was to get Node-Red talking to the MI Flora – I used an INJECT node, set to retrigger every 15 minutes – firing off to an EXEC node which contained nothing more than “python3 /home/pi/miflora/bathroom.py”

That worked – so now I had a regular supply of data in the form of an easy to use JSON package.

I split the package up – and fed it into a Node-Red Dashboard graph – and that was my first disappointment. If you fire more than 4 items into those graphs – the popup fails to show all of them – and the graphs are not very good anyway. I think a lot more work needs to go into that.

I do use GROVESTREAMS on-line (which is REALLY flexible) to store data remotely but there’s a limit as to how far back you can read for free – that was not the case when I first started using them and wrote the Node-Red-Contrib-Grove node to make it all easy.

So now I was on a search for a decent graphics package that would run on the Raspberry Pi (or similar). NOT as easy as it sound,  unless you’re very easily pleased when it comes to graphics.

After a lot of experimenting I decided to give Grafana a shot. I think if I started writing this blog again, I would would have Grafana in the title because this really, as it turns out, is the star of the show.

Having seen a few screenshots, I had visions of populating  a SQLITE 3 database and firing that data into Grafana.

Erm, no. Despite (wait for it) using SQLITE internally to store users and dashboards, the package does not actually support SQLITE for data !!!  I've explained that now, to save you some confusion later. When I did the install, it kept referring to SQLITE and could I HELL figure out how to set up a database for my data – that’s why.

As a Pi user (that means SD use so I’m not keen on MySQL as SD has limited WRITE capability and I worry about databases shortening the life of the SD) the options for data sources did not look appealing to me at all, the least offensive being INFLUX and that is the one I settled on – partly as there is a node for it available for Node-Red.  Despite the pretty website this is still very preliminary at version 1.02. Influx doesn’t use terms like tables and fields which kept me going for a couple of hours – but it is good at storing time-stamped data – indeed you don’t even do the time-stamping. You create an empty database and start firing data at the DB in pairs – stream name – and data value – it really is very simple once you get started. I guess you could think of it as a single table with pairs of data-name and data-value.  I went down a few dead ends and discovered if you got your stream names wrong – good luck renaming them as INFLUX does not support renaming!

Anyway, it ‘s all very easy once you get started. I did things backwards and installed Grafana first. Here’s what I did – no guarantee it will work for you.

You might want to consider reading this before using InfluxDB on the Pi for long-term use - there are very few build options for small SBCs and this article gives the impression it likes more RAM than we would normally have on the likes of the Pi. I do have to say though that it is working just fine on mine after several days of operation. Comments welcome.

I grabbed the Grafana file for my Pi from here. https://github.com/fg2it/grafana-on-raspberry

sudo dpkg -i grafana_4.1.2-1487023783_armhf.deb
sudo /bin/systemctl daemon-reload
sudo /bin/systemctl enable grafana-server

That was Grafana up and running on port 3000 – user name admin, password admin to actually DO anything – and quickly change that password!!! I did that, went into the ini file and disabled user registration as the admin can do that and opened up port 3000 redirect in my router so I could access this from the outside world. That all worked well.

wget http://ftp.us.debian.org/debian/pool/main/i/influxdb/influxdb_1.0.2+dfsg1-1_armhf.deb

sudo dpkg -i influxdb_1.0.2+dfsg1-1_armhf.deb

That set up influx and that ran without further ado at port 8083. I did NOT open that up to the outside world. In there I created a new empty database called “logger”

logger

In Grafana – which supports influx without any changes, I followed Engineer John’s instructions to set up the data-source and a new Dashboard.

So the next thing – would be to get some data.  I played with this for some time – should I keep incoming data source names simple – as you can’t rename them? Then Jay pointed out that in Grafana you can ALIAS names. That did it. So in influxDB node for Node-Red, you fire in a payload – and depending where you want to put your data – you use msg.measurement.. Yes, exactly, what’s wrong with msg.topic you might ask. So here is my little MI Flora MQTT node firing values into InfluxDB

MiFlora[6]

And that yellow function block…

node.status({fill:"blue",shape:"dot",text: msg.payload});

tmp=JSON.parse(msg.payload);

msg.measurement="battery"; msg.payload=tmp.battery; node.send(msg);
msg.measurement="sunlight"; msg.payload=tmp.sunlight; node.send(msg);
msg.measurement="temperature"; msg.payload=tmp.temperature; node.send(msg);
msg.measurement="moisture"; msg.payload=tmp.moisture; node.send(msg);
msg.measurement="fertility"; msg.payload=tmp.fertility; node.send(msg);

Yes, I know – far better ways to do this – but it was my first stab at it and it worked. For general use however I added an incoming function that merely copies msg.topic into msg.measurement and that means any single data-source coming in via MQTT can be blasted straight into InFluxDB.

Yes, that’s write – you don’t create tables or fields – you just send in field names and data and that’s it!

I also fed in some data from my general sensors – with horrible topics like pergola/lighting but of course thanks to the Grafana alias ability – names like that would not show up in Dashboards.

Having stored up some data it was time to get it into graphs – I took the VERY simplest approach of showing lines as I have at this point no idea what some of the Grafana functions do – I DO know that smoothing the data might be fun as Grafana relies on the data-source to do that and Influx doesn’t do that.  What IS nice is that you don’t have to worry about things like “I want the last 5 minute’s worth” or “show me the last month’s worth” as Grafana does all of that for you – from here  it gets easy.

New dashboard and under metrics ADD ROW – takes an hour or so to get to grips with this..

Grafana setup

I’ve expanded the top one here – I have 3 lines in that one graph – see the blank ALIAS BY  - if you want to change the source name (in this case battery) put something in there.

And that  is how I got to this point…

Graphing

So top left you see battery, moisture and temperature from the MI Flora unit. I chose to separate off light level as the range of values is WAY higher… and on the right I’ve started with another unrelated sensor incoming from MQTT and as you see using the ALIAS I’ve renamed the stream (topic) to “Kitchen OS Temperature” – yes, it really IS that cold inland Spain right now.

But this is merely the beginning – now I will put all my other data from the UK and Spain into here – lots of it and some day I might even manage to extract individual graphs back into Node-Red Dashboard, but right now, I’m happy with these pages. Looking good.

There’s a lot to take in – and I am as you can see NOT an expert at this yet so before firing questions back – you might want to spend some time looking at the links on this blog entry and using Google. If you think another database is better by all means write in to say why – and if you think there’s a better easy-to-fit-in-Pi graphing system, preferable one that works with SQLITE – again do let us know. I started all of this with zero information late afternoon yesterday and had it all working by the end of last night – so it’s not THAT big a deal even if my clumsy writing makes it look that way.

Not entirely sure what’s going on the this battery level on my first day – but it did occur to me that the unit is intended for putting into plant-pots – not sitting outside in the sopping rain so I’ve covered it in cling-film!! As we’re off back to the UK for a few weeks,  I don’t want to come back to a rusted heap.  Note the Mi Flora battery at the top – seems to be self-recovering!!

I have to say, having taken the plunge I DO like Grafana. It isn’t perfect… I tried the GAUGES plug-in which was great using one gauge but as soon as I tried more than one, all SORTS of things went wrong – eventually I stopped using it.. but the graphs are fine. I’m already seeing benefits of monitoring – the top right graph shows the effect of watering a blocked-in area of the patio in Spain – the watering has been good for nearly 3 days up to now and by the look of it will be good for a week. As we pay per litre, such info is useful. Of course, things will be different in the summer but the automatic system currently offline (ice) waters twice a day – this may WELL prove to be totally over the top.

Update: the little Bluetooth sensor has now been running for several weeks and the battery remains at 80%

Grafana output

Update 27/03/2017: I've been hitting issues with out of bounds temperature data - ie a couple of duff readings crept in - with values like 2000 and -64  which of course flattened the data completely. I realised quickly that InfluxDB has no DELETE function and as far as I could tell - things like comparing data with a value made the graph line disappear.

I put something up on the web and someone came back and asked if I was using InfluxDB 1.2 which apparently has a DELETE function. Well, I wasn't - I was way back at 1.01 - worse - the same folder where that came from only went up to 1.1

However, thanks to THIS helpful chap - I easily updated to Influx 1.2 without the issue he described. I STILL can't add something like "where value < 100" but maybe I can delete ??? Anyone with more info on this please by all means chip in...

 

 


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

The LCD Object

lcdIt has been a very busy week for us here in Spain – what with partying and what-not, so I’ve not had as much time as I would like to develop my JavaScript object skills, however, I’ve managed to get much further with a project I’ve been working on in the background – a little LCD display.

I wanted to simulate a real LCD and you’ll have seen in an earlier blog entry that I managed some JavaScript code to do this.  Well, I’ve had all SORTS of unexpected issues, now resolved and I’ll detail here what I’ve done.

colour changeSo first off, I was having some interaction with other objects on the page – resolved – but an issue that came to light when I got here to Spain – with my little Raspberry Pi that is running this stuff left in England – was that of loading external items – for example, images and fonts.  Designing items for Node-Red Dashboard is slightly different to working on an empty web page as you’re basically working inside a DIV – you don’t have the luxury of ONLOAD and HEADERS etc. and I found myself getting annoyed with my web seven-segment font not working when first loaded  - i.e. initial text would show up in a default font because of the time it takes to load the web font from England. I could not understand why this would always happen – surely there’s some caching going on? But if you read the comments in previous blogs – that apparently is not the case as the templates in Node-Red Desktop add a timestamp to URL calls which kills the cache. Well, not ALL of it but certainly makes life difficult when trying to load up fonts and images. 

LCD in redAnyway, the first idea that came out of various comments was to URL encode the fonts – and of course, wanting to keep with good practice I put all of that into a separate style sheet. NO! The page has to load the style sheet, so the problem doesn’t go away. The answer lay in having the font inline – now that SOUNDS messy but actually it’s not that big a deal especially if you don’t have wrapping turned on – it’s just a one liner – albeit a very long line. The breakthrough came when I read a suggested link which took me to Fontsquirrel – having initially used this 14-segment font for my LCD only to find that the capital S was a bit naff and the spacing was NOT identical on all characters, I was then quite excited when I found an excellent WOFF file called segment14 here.  Mono spaced and with a decent S.

Lovely, but of course this still had the same issue with loading – not a big issue at home but as soon as myself and the source were separated by a plane trip – the loading issue became apparent. Anyway, Joe Lippa and Antonio (Mr Shark) have been feeding me links and it turns out that FontSquirrel can load up the font and return a CSS file with the code all inline (they don’t appear to have 7 or 14 segment fonts so it is as well you can upload fonts you have found -  and have them converted) – so no external loading.  In the data that came back was a WOFF data block and a WOFF2 data block – I ditched the former as the latter works just fine.  I’ve put links to fonts here – I’ve modified them for my own use but you should know I’m not claiming any ownership of the fonts – others have done the excellent work on designing the fonts.

Purple LCDWith the font issue resolved I set about making a basic object for a display (which will no doubt mutate – but right now can be dropped into a template in Node-Red to show lines of simulated 7-segment display in a variety of colours. Methods can be invoked to updated the two lines and to change the colours – both background and foreground. I managed my colours by trial and error but you can of course change them and add more.

Simple testing of the LCD objectThis, then, is merely the first stage – everything works – you can change colours and text… so much more can be done – choice of how many lines, how many characters, what font size etc. but all of that is easy to add once the basic idea is in place. This is going to be added to my armoury of gauges and shapes available in Node-Red Dashboard – I’m playing with the GITHUB beta right now and it is coming along VERY nicely – now that the actual template width and height can be tweaked.

Anyway, there it is… if you want to play with this – grab the code and paste into a template via the “import clipboard” option (top right – 3 bars)– yes, it’s big because of the font – but very do-able. You can replicate this and make two or more displays but more likely the object and font should be split off into another template if you plan to do that. 

JSON

Note that in my test inject nodes I am now injecting JSON, not text (see image above and note the {} which means JSON is selected – then I’ve filled in some standard JSON text to adjust two variables) – just as easy but more powerful as you’ll see in the text injectors.

When this information comes into the node it is processed as such…

(function(scope){
        scope.$watch('msg', function(msg) {
            if ((msg.payload.lcdm1!==undefined)&&(msg.payload.lcdm1!==undefined)) lcd2.update(msg.payload.lcdm1,msg.payload.lcdm2);
            if (msg.payload.colour!==undefined) lcd2.updateCol(msg.payload.colour);
        });
})(scope);

Right now I don’t allow on or the other line to be processed but only both at once – but that would be easy to change.

If you look into the code there are two methods (functions) of relevance once the object is defined – this.update and this.updateCol – which are merely setting internal variables then calling the update function.  The text update function could easily be split into two.

At the very end, the LCD is created, needing only a DIV to work in..

var lcd2 = new myLcd("newDiv1");

I called it lcd2 as I also tried putting several on a page to ensure there was no interaction. They need unique names and unique div names and several will co-exist no problem (though it would make sense to have only one copy of the object definition if you want to do the job properly).

See previous blog entries for related info on LCD simulation (alpha blending of the all-segments on character under the actual text).

Specific questions are invited in the comments area (not 2 years later please).

Facebooktwittergoogle_pluspinterestlinkedin

Odds and Ends

Just a few odds and ends… we’ve arrived safely in Spain and I’m not getting quite as much blogging time as I’d like as there are repair jobs to do – but I managed a little item on Node-Red earlier – I’ve had people in here asking for simple-use examples – so that’s the first.

Gauge Progress: I’ve not forgotten my HTML5 Canvas gauge – it’s coming along nicely but along the way I’m hitting minor bottlenecks on image loading – and image pre-loaders are not helping. Most but not all of this came to light when I moved thousands of miles away from home with the attendant delays! I’ll return to this one soon.

Node-Red Menus: Regular readers may recall from earlier blogs that I’ve been griping about the menu in Node-Red being there even if you have only one page. Some may have noticed that a blog reader pointed out a simple CSS solution – well, now there is better – Node-Red master as of now has an option to turn the menu off. I’d give it a day before updating to make sure the latest version had filtered through to updates.

Mint Linux: I wrote a while ago about this – so often these things fall by the wayside – well, I’m still using it – can’t find anything wrong with it on my little black laptop.  It isn’t Windows but for development work – it runs a lot faster on that old hardware than Windows 7 did and everything works right down to my Logitech Bluetooth headphones. Anyone else using this on an Intel-powered laptop?

Raspberry Pi Power backups: You’ll probably know I’ve covered this in the past – various solutions for backing up the little SBCs in the event of power failure. My best solution up to now has been RavPower battery charging units – but not all of them seem to work in the same way. I did find a little LIPO unit that works on one round 3v6 battery but it’s power output would not work for a RPI3 for example (which takes more power than the RPI2. Well, I’ve just discovered and sent off for one of these. It’ll take a few weeks but I’ll let you know how that goes. Anyone bought something similar? How did that go for 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

A Deep Learning Weekend

Gauge by Peter ScargillWell, this has been an interesting journey (a deep learning WEEK more like it) as I’ve been working on making my own widgets for Node-Red. I thought I’d share some of the things I’ve picked up. Experienced JavaScript object users please look away now. Those not interested in JavaScript look away now.

Note: The original video for this is out of date as I have learned more – the new video has some extra code, too – here it is - https://youtu.be/mTAPrvB1EeI

C Programmer: As a life-long C programmer, I came into JavaScript with some trepidation. Like alternative universes, JavaScript may look similar to C – but it is not the same – and that led to all manner of silly mistakes over time. However as I see a tiny light at the end of the tunnel, I have to say, it was worth the effort. Despite being a client-side interpreted language, it really is great fun to use.

The gauge: Well, as long as you keep it simple that is. When designing my first attempt at a gauge for Node-Red, I realised that a typical gauge operation goes like this:

Some features such as the background are typically set in an init function once only (and as such it would be better if the user is not involved in this. Other features such as needle positions are set dynamically and will change during operation.

This is generally handled one of two ways – either by setting a value and then calling an update function, or by running something in the background which checks for value changes so all you have to do is change a variable. On many of the gauges you’ll see flashing lights and smooth movement of gauge needles – that implies something running constantly or at least checking for changes and running when change is needed.

Concerns: This worries me as there can be quite some overhead in updating an entire gauge, umpteen times a second. So I decided that what was needed was a layering system as you might find in Photoshop – such that I could lay down the basic design and background of a gauge once only then dynamically clear and write to a top layer whenever changes are required. Such changes might include the state of a flashing light – or a needle not being where you want it, requiring successive incremental updates until the needle or needles do get to be where you want.

I then started thinking about variables and functions (methods). Did I want to update variables such as the needle pointer directly (direct variable manipulation) – or did I want to manipulate the input value before passing it through (that needs  a method/function).

That led me to create, as you will have seen earlier, a large blob of JavaScript for my gauge, including initial setup – then a timer-driven function to update the gauge regularly. That was stage one.

HTML5 Canvas: In the process I discovered (by looking at what others had done) that HTML5 Canvas (which really is easy once you get past the initial learning curve) Is a great choice. What did not come so easily was the realisation that the canvasses themselves are indeed transparent and you can layer one directly on top of another – just like Gimp or Photoshop layers. That led me to split the job into two – the overall backdrop which remains fixed throughout operation – and the top layer with my LEDs, needles and set points on it.

Adding a bunch of variables to this for setup and defaults brought me out into a sweat as I struggled to imagine how two or more gauges would interact. And THAT led me onto objects – something I’d never really touched in JavaScript before  – specifically to wrap up my entire code into a definition – which meant I could then simply create instances for EACH gauge without worrying about all those variables interacting. That was the point I last few days in deep learning.

Having wrapped everything up in a bulletproof package I was then faced with the question of how to access required functions and data externally. The obvious way (and the one I’ve adopted) is a series of callable functions for example:  mygauge1.needle1(50);

In the process I had to learn how to hide functions within the definition and make functions accessible externally. That was easy enough.

Here is a simple example – the assumption is that you have a jQuery link (to update a div) and a DIV called “fred”

1.  function myobj(){
2.  this.v1=5;
3.  init=function(passThis) { setInterval(every25ms, 25,passThis); }
4.  this.doubleit=function(r) { this.v1=r*2; }
5.  every25ms=function (passThis) { $("#fred").html(passThis.v1); }
6.  init(this);
7.  }

8.  brian=new myobj;
9.  //brian.doubleit(12);
10. //brian.v1=7;

There is a lot to this – and I’ll be using the word “this” a lot – so for clarify I’ll use italics for the special meaning of this.  It may look strange at first but if you follow me it soon won’t.

Definition: So the point of this was to create a test object definition – an object that would simply put a value in a DIV (I know, slightly overkill but I was trying to prove a point).  We start off with the definition in line 1.

Take a look at the code above – there is a lot in here despite their being only 9 lines. I figured any more and people might run away.

Firstly on line 1,  we define a type of object. A “myobj” type.  I’m not making anything here – just defining it (ends in line 7).

On line 2 – we define an externally available variable – v1. “this” makes it accessible externally (try removing “this”).

In line 3, we are defining  a function called init.  When the instance is created on line 8, init will be called internally (by line 6) and will start off a timer which will run every 25ms and which will call an internal function called “every25ms” (line 5), passing this to it. Do not get hung up on this yet.

Line 4 defines a function (again made available externally by “this” and called “doubleit”,  will double whatever is passed to it.

The  “every25ms”  function on line 5 which is to be called every 25ms by init… simply prints out the local variable.

Line 6 calls init (which is NOT accessible externally) when the instance is created in line 8 - to initialise the instance and start off the timer – this saves running an init externally.  From line 8 onwards,  the function “every25ms” is called every 25ms to put the value of this.v1 onto the DIV.

You’ll see “5” appear in your DIV if you test this somewhere – that’s the initial value. Note "passThis" – (arbitrary name). Because the function init is private - I don't prefix it with "this" – when it sets the interval timer it has pass to the timer function the outer “this”… - so I pass "this" in the init call.  This is new as a result of feedback in here suggesting a private “init” function that was no accessible externally. In the original version I used this.init() - and passing this worked. Removing that resulted in the timer callback function using the wrong "this".  Trace it through and it makes sense. The callback function needs to know about the outer "this".

Line 8 is where things start to happen. At that point, the instance (brian) is created and the timer starts all on it’s own -  thanks to the internal init function.

So far so good. How do I now interact with that variable v1? I wanted the choice of updating a variable or calling a function. The two commented lines are two ways to do this – their operation should be self-explanatory.

Line 9 simply won’t interact with local functions inside the definition and we don’t want them to – we want interaction with specific functions in each instance of the object – like “brian” for example. And that’s where “this” comes in. Add “this” to a variable name or a function name – and it becomes accessible to the outside world. For example you CANNOT do brian.init() or worse, brian.every25ms() and that’s a good thing!

Scope: So using this technique allowed me to keep all variables and functions private and only “expose” those I needed. LOVELY.  If I only wanted to use function and not expose any variables – I would not use for example “this” as a prefix to v1.

These ideas then form the basis of my current gauge. I can built a massive machine with lots of variables and functions inside and have no worries about interactions with other gauges because I’m only “exposing” stuff I want…. and gauge1.v1 has nothing to do with gauge2.v1

Of course I’m assuming that was as clear as mud -  but if you are interested, go have a play in this CodePen where I’ve left the code. See the number that comes up in the working area – try un-commenting those functions (methods) in lines 9 and 10. See what happens if you replace passThis.v1 with this.v1 or just v1.  See what happens if you remove references to this altogether. CodePen is great as changes run immediately and safely.

Merely experimenting with the code in that CodePen should do what it did for me – clear a massive amount of mental fog.

Simply creating v1 – and removing this and passThis in referring to v1 – leads to disaster – v1 is accessible externally on it’s own –so kiss goodbye to multiple instances.  But the same code using “var v1” leads to a save internal v1 NOT accessible as “brian.v1”. Your choice.

My new gauge object is coming along nicely – and a minimal installation involves little more than a link and a couple of lines of code – stunning how these simple ideas change the whole game.

Facebooktwittergoogle_pluspinterestlinkedin

A week of Learning

Working on the gauge in CodePenSome may be wondering if I’ve gone off on holiday, as I normally post here on an almost daily basis. Well, if you regularly read the comments sections you’ll see I’ve been heavily involved in answering questions, but more importantly I’ve taken one step back and two steps forward on this gauge thing. Read on.

But firstly – WIN SOMETHING! You’ve probably heard me talk about my pal Peter Oakes in Canada – he has an excellent YouTube Channel in which he talks about IOT – well, he’s just launched a competition and the prizes look pretty damned impressive indeed. Take a quick looks over here – you might want to participate…. https://www.hackster.io/contests/IOT2020

Thanks:  Before going any further, I’d like to take this opportunity to thank some people in there without naming names – for several donations received this week – you have no idea how this helps motivation, knowing that your work is appreciated. Thank you, guys!

The Gauge: Now - regular visitors will know I’ve been doing a lot of work on Node-Red-Dashboard-compatible widgets recently as I really do think this is the way forward for mobile access to DIY home control systems and also for desktop and wall access via touch displays -  but one thing that has bothered me up to now was the clumsiness of some of my coding – global variables all over the place, a lot of opportunity for interference from one node to another etc. Everything just works but the perfectionist in me wants to “do the job properly”.

So earlier this week I took a step back, seeing what “proper programmers” had done with turning these widgets into “objects”, with clean interfacing to the outside world. Well, trust me, it isn’t that easy. I asked around as to how I might encapsulate my Javascript into an object, exposing only those bits that needed to be exposed. No-one I know well enough to ask for help, could help in this particular instance! So, I took a step back, grabbed some coffee and thanks to my friend Google, I’m pleased to say I’m getting somewhere.

Shortly you will see my gauge once again featured in these pages but the way it is done and bits you’ll need to look at have been dramatically changed as has the chance of unwanted interaction – and the overhead has been substantially reduced due to a series of insights which have followed each other – and some of them I’m sure some others have missed. Read on.

So first off, I made a gauge with pretty colours – you’ll see it elsewhere in this blog. It works – why take it any further?

Well, the gauge features nice, smoothly moving needles and other bits. What’s wrong with that?  Every time the needle is updated in the existing design, the entire gauge has to be re-drawn. This is not uncommon but just felt wrong to me. To tackle this I had to understand LAYERS. It turns out that if you make the position of CANVASSES absolute, you can put one on top of another (you also need to understand zIndex but that’s easy). If you can do that, then you can draw the gauge backdrop including the text and pretty-coloured segments once only on the bottom layer and only then clear and update the top layer, say, 50 times a second with needle updates etc. That saves some calculating.

But now I needed two CANVAS items which looks a little odd when setting up so I worked out how to create both, totally in Javascript. That led to another problem, in Node-Red you can’t just put your CANVAS elements in the top left corner of the page BODY – it won’t work. I then reasoned that both CANVASSES could sit inside a DIV on top of each others – and indeed they can. So now all that is needed in HTML is to define a DIV and the Javascript will do the rest.

That still left me with a mass of messy Javascript - and the thought of explaining what was and what was not relevant to end users in the blog here was keeping me awake. That’s when I started looking into this whole object encapsulation thing. 2 days ago that was a distant world, something for the future. Today, I wonder why I waited so long to take the effort to learn. I had to learn some new tricks in the process – however, when you eventually see the new gauge, setting it up will be as easy as this.

var gauge1= new petesGauge;

gauge1.init({
  container: "myDiv",
  });


gauge1.value1(90);

Define a gauge, point it to a DIV at which point it appears magically – and then dynamically set a value which will slowly change in front of your eyes. No other information exposed to the outside world, no need to do anything other than set up an empty DIV and add a link to the Javascript compressed library.

Part of the magic here is in the encapsulation I’ve learned to handle – but also of course there are many defaults. In the top section you’ll be able to override defaults and turns things on and off if you want – and in the bottom section there will be several settable items – the value of two gauge needles, the value of set points, visibility of LEDs etc. All easy to use options.

I’m on the right path – I understand what I’m doing but I’ve only so much time to code this up.

If anyone fancies themselves a whiz at JS Objects, I’ve fathomed out how to get and set global vars in the object with simple methods – no problem but can i hell interact externally with internal vars – happy to have a chat with anyone interested in enlightening me.

jsFiddle helped me get this far but the best tool for the job IMHO apart from lack of formatting – is CodePen – you can make code changes dynamically and see changes in real time – what a difference this makes. Oh and I realised the one thing missing from my LCD display (not shown above) is the overspill of side lighting typically seen on real LCD displays. That’s coming soon.

New Toys: I’ve also discovered (thanks to MrShark) Atom this week which promises to be a great editor both in Windows and on my little SBCs.  My MINT installation, apart from falling to bits visually after a “sleep” operation, continues to function well on the laptop and I’ve received some nice new DIN rail brackets from China which can screw onto the back of a perspex sheet for mounting boards and supplies. More on all of this later. Incidentally for those wondering, my testbed wireless Orange Pi Zero and twin NanoPi M3 units are still sitting on the bench, still working perfectly despite disconnecting the WIFI several times deliberately.

Desktop Touch Controller: And on another subject, how is my Desktop Pi Touch Controller doing? For some time Desktop Controllernow I’ve had a 5” touch screen attached to a Raspberry Pi 2, using Node-Red Dashboard as a simple controller for my office – to turn lights on and off and keep an eye on temperatures etc.  Works a treat using Chromium in “kiosk mode” – but two things have annoyed me – one being that menu from Node-Red Dashboard – the second being the ability of the browser to fail occasionally due to connection issues and put up a stupid message instead of trying to reconnect.  Well, I may have cracked both of these as for the last few days the little unit has been sitting there rock-solidly doing it’s job.

The annoying Node-Red-Dashboard unwanted menu problem (well I only have one page on this unit – why do I want a menu) was solved simply by a reader who wrote in to suggest this added to the style.

#toolbar {display:none;}

Yes, that’s it – simple as that. Gone – space retrieved.

The second came from here. http://www.labs.bristolmuseums.org.uk/running-google-chrome-in-kiosk-mode-tips-tricks-and-workarounds/

So I have a couple of templates on the page – one at the top with my CSS and some useful Javascript – the second at the bottom.

I’ve added this to the top

<body onClick=”location.reload()”>

and this to the bottom.

<script type=”text/javascript”> $(function() { setTimeout(function () { if($(“#VisitorStoriesHelpText”).length>0){ $(‘body’).attr(“onClick”,””) } }, 1 * 1 * 1000);}); </script>

And yes, I know that body code is really not appropriate in a Node-Red template – but guess what… it seems to work. I’ve not had an issue with the display for days now. May be a fluke of course – but fingers crossed.

Facebooktwittergoogle_pluspinterestlinkedin