Weather icons for OpenWeathermap in a Dashboard 2 template

The original dashboard had many icons built-in, so you only had to give the name of a weather icon for it to manifest on your dashboard.

@flowfuse/node-red-dashboard does not have built-in icons, but there are quite a few sets available on github.

I decided to try and use .svg icon files rather than images for DB2.
They proved bothersome; simple things such as colouring the icons and applying drop shadows for enhanced legibily have proved very difficult.

However, I think I have found an approach which works.

The OpenWeathermap API serves icon codes eg 11d for daytime thunderstorm and 11n for nighttime thunderstorm.
The only set of icons I found already named for these codes is from https://github.com/isneezy/open-weather-icons.

I downloaded the code from github, unzipped and copied the .svg files to a directory in ~/.node-red - ~/.node-red/node-red-static/icons_isneezy
(settings.js has httpStatic: '/home/pi/.node-red/node-red-static/',).
Note that you can't use a directory called icons and within it icons/isneezy

They look like this.
The first one is red to verify that they can be coloured and given a drop shadow.

Can this really be the full set of icons that the API uses?

[{"id":"7c092bfa153765fb","type":"ui-template","z":"1c6ae1a103560273","group":"ecd866dc62e442ac","page":"","ui":"","name":"Isneezy icons","order":1,"width":"6","height":"5","head":"","format":"<div class=\"dashboard-container\" style=\"background-color: aliceblue\">\n            <h3>Isneezy icons</h3>\n<p>These 19 icons are from https://github.com/isneezy/open-weather-icons</p>\n<p>Icon names do match the icon codes served by the OWM API, but is it a complete set? </p>\n<p>Served from ~/.node-red/node-red-static/icons_isneezy</p>\n<div class=\"daily-row\">\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/01d.svg'); color:red;\"></div><div class=\"icon-label\">01d</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/01n.svg');\"></div><div class=\"icon-label\">01n</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/02d.svg');\"></div><div class=\"icon-label\">02d</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/02n.svg');\"></div><div class=\"icon-label\">02n</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/03d.svg');\"></div><div class=\"icon-label\">03d</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/03n.svg');\"></div><div class=\"icon-label\">03n</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/04d.svg');\"></div><div class=\"icon-label\">04d</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/04n.svg');\"></div><div class=\"icon-label\">04n</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/09d.svg');\"></div><div class=\"icon-label\">09d</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/09n.svg');\"></div><div class=\"icon-label\">09n</div></div>\n</div>\n<div class=\"daily-row\">\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/10d.svg');\"></div><div class=\"icon-label\">10d</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/10n.svg');\"></div><div class=\"icon-label\">10n</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/11d.svg');\"></div><div class=\"icon-label\">11d</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/11n.svg');\"></div><div class=\"icon-label\">11n</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/1232n.svg');\"></div><div class=\"icon-label\">1232n</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/13d.svg');\"></div><div class=\"icon-label\">13d</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/13n.svg');\"></div><div class=\"icon-label\">13n</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/50d.svg');\"></div><div class=\"icon-label\">50d</div></div>\n<div class=\"icon-wrapper\"><div class=\"weather-icon\" style=\"--icon:url('/icons_isneezy/50n.svg');\"></div><div class=\"icon-label\">50n</div></div>\n</div>\n</div>\n","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":485,"y":135,"wires":[[]]},{"id":"1e82ef3985bd89ab","type":"ui-template","z":"1c6ae1a103560273","group":"","page":"33031fffa5689f5e","ui":"","name":"CSS","order":0,"width":0,"height":0,"head":"","format":".dashboard-container {\n    display: flex;\n    flex-direction: column;\n    justify-content: flex-start;\n    align-items: flex-start;\n    height: 100%;\n    width: 100%;\n    border: 4px solid black;\n    border-radius: 12px;\n    background-color: oklch(0.93 0.08 150);\n    overflow: hidden;\n    position: relative;\n    padding: 4px;\n    box-sizing: border-box;\n    box-shadow: 4px 4px 28px 0px rgba(0,0,0,0.3) inset\n}\n\n\n.icon {\n    flex: 1 1 0;\n    display: grid;\n    grid-template-rows: auto 1fr auto auto;\n    align-items: center;\n    justify-items: center;\n    text-align: center;\n    box-sizing: border-box;\n}\n/* === Daily row (8 columns, single line) === */\n.daily-row {\n    display: flex;\n    flex-direction: row;\n    flex-wrap: nowrap;\n    gap: 4px;\n    width: 100%;\n    /*\n    margin-top: 0.7em;\n    margin-bottom: 0.7em;\n    padding-top: 0.5em;\n    padding-bottom: 0.5em;\n    */\n    align-self: center;\n    box-sizing: border-box;\n    overflow: hidden;\n}\n\n.icon-wrapper {\n  display: inline-block;\n  filter:\n    drop-shadow(0 0.5px 0.8px rgba(0,0,0,0.55))   /* tight contact shadow */\n    drop-shadow(0 2px 3px rgba(0,0,0,0.28))       /* mid soft shadow */\n    drop-shadow(0 4px 6px rgba(0,0,0,0.18));      /* elevated soft offset */\n  margin: 2px;\n}\n/*\n.weather-icon {\n    max-width: 90%;\n    max-height: 100%;\n    object-fit: contain;\n}\n*/\n.weather-icon {\n  width: 50px;\n  height: 50px;\n  background-color: currentColor;\n  mask-image: var(--icon);\n  -webkit-mask-image: var(--icon);\n  mask-repeat: no-repeat;\n  -webkit-mask-repeat: no-repeat;\n  mask-size: contain;\n  -webkit-mask-size: contain;\n  mask-position: center;\n  -webkit-mask-position: center;\n  display: inline-block;\n}","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"page:style","className":"","x":455,"y":90,"wires":[[]]},{"id":"ecd866dc62e442ac","type":"ui-group","name":"demo","page":"33031fffa5689f5e","width":"15","height":1,"order":1,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"33031fffa5689f5e","type":"ui-page","name":"demo","ui":"e9c974f7c1d080d1","path":"/demo","icon":"home","layout":"grid","theme":"0d92c765bfad87e6","breakpoints":[{"name":"Default","px":"0","cols":"3"},{"name":"Tablet","px":"576","cols":"6"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":1,"className":"","visible":true,"disabled":false},{"id":"e9c974f7c1d080d1","type":"ui-base","name":"My Dashboard","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"headerContent":"page","navigationStyle":"default","titleBarStyle":"default","showReconnectNotification":true,"notificationDisplayTime":1,"showDisconnectNotification":true,"allowInstall":true},{"id":"0d92c765bfad87e6","type":"ui-theme","name":"Basic Blue Theme","colors":{"surface":"#4d58ff","primary":"#0094ce","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"2px","density":"default"}},{"id":"1776b636466222d8","type":"global-config","env":[],"modules":{"@flowfuse/node-red-dashboard":"1.29.0"}}]

A much larger set of icons - 120 of them - is available at https://github.com/rickellis/SVG-Weather-Icons/Masters-Tempestacons. These have descriptive rather than numeric filenames so I'd have to build a cross reference between OWM's codes and these filenames.

I downloaded these to icons_tempestacon and wrote a little bash script to generate part of a ui-template to show them

#! /usr/bin/bash
DIR=`basename $(pwd)`

printf "%s\n" '<div class="dashboard-container" :style="{ backgroundColor: msg.color}">'
printf "%s\n" '<div class="daily-row">'
for f in $(ls *.svg)
do
printf "%s(\'/%s/%s\')%s%s%s\n" '<div class="icon-wrapper"><div class="weather-icon" style="--icon:url' $DIR $f ';"></div><div class="icon-label">'$(basename $f .svg) '</div></div>'
done
printf "%s\n%s\n" '</div>' '</div>'

And after grouping the icons into multiple lines in the template, this is what I get

Rick Ellis has other weather icon sets too, not sure how many icons are not also in the Tempestacon set. By all means download them to find out!

1 Like

I thought that the mdi icons are built in.

If they are I've been barking down the wrong rabbithole for weeks.

Nice icons.

I always use SVG rather than anything else for web icons when I can. It can be a little tricky to get your head around them and some SVG's are dreadful for sure. But decent ones are easily coloured and sized once you've worked out the differences between color and fill, etc.