Category Archives: Skycons

Node Red Weather

One of the many things that Node-Red makes easy to capture – is the weather – and all credit is due to the people who put the DARKSKY API together.

Animated weather

What you are seeing above is a 6 day forecast in ANIMATED, COLOUR images (I appreciate it does not look animated here). It is LOVELY. This is running on my Raspberry Pi and of course the display, being a web page can be displayed on a tablet, a PC screen, a phone or an integrated touch-screen. Don’t go using old browsers though – this makes use of HTML5 and vector graphics so you should be reasonably up to date.

To get a nice pretty weather forecast for your home control display or whatever you plan to use it for, you need:

a. information

b. A display mechanism

In this case the information comes from DarkSky via a simple API

DarkSky

If you wish to “call” the DarkSky API you may do this up to 1000 times a day for free. Reader Jay and I felt that grabbing the information every 5 minutes might be a good start. Once the novelty wears off you might consider every 15 minutes or so. A timestamp node is simply used as a trigger – to get the information when Node-Red powers up and every 5 minutes from there on.

An HTTP request gets you a massive object with just about everything you could ever want to know about the weather and finally a function attempts to read that object with minimal error checking. I say this because in the past I’ve had the very odd bad package from DarkSky using the NODE that is available (I suggest you avoid that at least for now) which does not harm but looks bad in the logs!

The “http request” node in the middle requires little information – just your unique code which you get when you sign up (for free) with DarkSky – and your longitude and latitude.

DarkSky details

Here is the full URL I used with a fictional key – and my own coordinates.

https://api.darksky.net/forecast/xxxxxxxxxxxx/55.130575,-2.2534091?units=uk2

Now you COULD read all the information from the new object and make a whole boatload of MQTT messages – some of which you might never use. If you were to do this – your flow might look like this.. and my thanks to reader Jay for saving me all that work.

massive flow

i think you’ll agree that is slightly over the top – but it does give you an idea of how much info you can get out of this and that is NOT a complete list.

On the other hand it was good fun for a bit, checking out all the info

info from DarkSky

So, instead, what we’re going to do is simply pull out of the object what we need… See below. When this is called, the function I’ve dropped in after that simply contains…

try {
var weathertest=msg.payload.currently;
global.set("DarkSky",msg.payload);
node.send (msg);
}
catch(e) {}

"weathertest" is used purely to provoke an error if there is something wrong with the data and can be ignored from now on. So now with luck we have an object called “DarkSky” out of which we can pull all manner of things as needed – and of course being global we can access this from any flow at any time.

So – here’s a EXAMPLE function to get the current weather summary

try {
msg.payload=global.get("DarkSky").currently.summary;
node.send(msg);
}
catch(e) {}

What’s with the “try—catch”? Well, this is new for me – that comment I made above about accessing anything at any time - I got sick of seeing harmless complains about undefined objects in my logs due to using something before it has been defined – or bad data coming through etc.,  so my new thing is to actually check that a variable exists before using it. If you call this function BEFORE you’ve grabbed the weather for the very first time – nothing will output – simple!

So – how far can we go with this? VERY far – it’s a BIG object but for what we need here – it is all very simple.

global.get(“DarkSky”).when.what

where “when” is one of the following:

  • minutely
  • hourly
  • currently
  • daily.data[x] where x starts at 1 for today and goes to 7 days,

msg.payload=global.get("DarkSky").daily.data[2].humidity;  // humidity for tomorrow !!

“what” can be one of the following:

  • summary
  • nearestStormDistance
  • precipIntensity
  • precipProbability
  • temperature
  • apparentTemperature
  • humidity
  • windSpeed
  • visibility
  • cloudCover
  • pressure
  • icon

I’m sure you’ll  agree that’s a pretty damned comprehensive selection, nicely hidden away in an object for you to pick out what you need. cloudCover and humidity you might want to multiply by 100 to make them useful – and temperature is in degrees C though you can no doubt change that to anything you want – read the API docs.

For now what we’re interested in is the icon – the name of an icon to represent the weather for seven days. The icon can be one of the following:

  • clear-day
  • clear-night
  • partly-cloudy-day
  • partly-cloudy-night
  • cloudy
  • rain
  • sleet
  • snow
  • wind
  • fog

It JUST so happens that there is a set of animated icons called SKYCONS which match up with this exactly – and they are in technicolour – you have control over the colour of various bits of them including:

  • main
  • moon
  • fog
  • fogbank
  • snow
  • leaf
  • rain
  • sun

So putting this all together – you can make a full colour set of icons which adjust for each of several days. As I am using Node-Red Dashboard, 6 icons fit nicely onto my phone so I simply picked the next 6 days.

You might want to satisfy yourself that you can grab this data before moving onto the next stage. Get yourself a DarkSky account, punch in the details and maybe go and grab today’s weather. Of course without these icons you still have lots of info you can use for wall displays or maybe calculating what to do with your heating system – for example in cold weather, if it is damp I like to ramp the heating up just a little more.

And now, onto the imagery.

You will need to be comfortable with creating a folder to put JavaScript libraries for use with Node-Red. In the Node-Red settings file you can define such a directory – just make sure you don’t call it “js” as Node-Red already has one of those and you’ll end up in trouble. I call mine “myjs”.  Go and grab the skycons.js file and put it on your system. You’ll find a lot of information in that link I’ve just given you.

For 6 days your flow will look like this..

weather flow

So – every 5 minutes or however often you choose, grab the relevant icon from the global object you are populating and inject it into one of these templates.

Here is the code for template 1.

<script src="/myjs/skycons.js"></script>

<canvas id="icon1"  width="50" height="50"></canvas>

<script>
var skycons = new Skycons({"monochrome": false, 
                "colors": { 
                      "main": "#779966", 
                      "moon":"#666666",
                      "fog": "#555522",
                      "fogbank": "#884488",
                      "cloud": "#999999",
                      "snow": "#aaaaaa",
                      "leaf":"#00ff00",
                      "rain": "#0000ff",
                      "sun": "#ff3300"
                    } });
skycons.add("icon1", Skycons.PARTLY_CLOUDY_DAY);
skycons.play();

    (function(scope) {
        scope.$watch('msg.payload', function(data) {
           if (data=="clear-day") skycons.set("icon1", Skycons.CLEAR_DAY);
           if (data=="clear-night") skycons.set("icon1", Skycons.CLEAR_NIGHT);
           if (data=="partly-cloudy-day") skycons.set("icon1", Skycons.PARTLY_CLOUDY_DAY);
           if (data=="partly-cloudy-night") skycons.set("icon1", Skycons.PARTLY_CLOUDY_NIGHT);
           if (data=="cloudy") skycons.set("icon1", Skycons.CLOUDY);
           if (data=="rain") skycons.set("icon1", Skycons.RAIN);
           if (data=="sleet") skycons.set("icon1", Skycons.SLEET);
           if (data=="snow") skycons.set("icon1", Skycons.SNOW);
           if (data=="wind") skycons.set("icon1", Skycons.WIND);
           if (data=="fog") skycons.set("icon1", Skycons.FOG);
        });
    })(scope);

</script>

The other templates are identical EXCEPT that: they don’t need the include – and they don’t need the definition of skycons. Also – wherever you see “icon1” – change that to “icon2” etc.. up to “icon6” assuming you want 6 days. “icon7” if you want to go all the way to 7 days.

If this does not work smoothly – check out that you ARE pointing to the javascript library and that you’ve made no mistakes – check that the data is actually going into the template node and make sure you have an up to date Node-Red and Node-Red Dashboard.  That will serve well later as I’m no-where NEAR finished making use of templates… just the thorny matter of getting data into and out of them to get to grips with.

If you have problems formatting these images - I noted when moving them mine came out stretched - this is some js and css  I use for other purposes but I think you need the padding css in a template (make this the first template - auto size - it will not show up) - to remove padding around the edges .

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

      padding: 0 !important;
      margin: 0 !important;
  }
  .nr-dashboard-template {
      padding: 0;
      margin: 0;
  }
  
  .rounded {
  border-radius: 12px 12px 12px 12px;
}
 
   .bigfont {
  font-size: 18px;
}

   .smallfont {
  font-size: 12px;
}
  
</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(80);
    });
    
</script>
Facebooktwittergoogle_pluspinterestlinkedin