# Compact Multi-location Weather Display

**URL:** <https://discourse.nodered.org/t/compact-multi-location-weather-display/57833>\
**Category:** Share Your Projects\
**Tags:** node-red-dashboard\
**Created:** [5 February 2022 15:13 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833 "2022-02-05T15:13:34Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [5 May 2025 13:16 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/21 "2025-05-05T13:16:31Z")

</div>

OK, looks like the old keys were no longer valid. The new key has now started working.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [5 May 2025 13:22 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/22 "2025-05-05T13:22:13Z")

</div>

Looks like the v2.5 API no longer quite returns what was expected in your original flow however.

`msg.payload.current` no longer in the returned data.

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [5 May 2025 13:30 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/23 "2025-05-05T13:30:51Z")

</div>

FWIW, this is the current iteration in Dashboard 1

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/7/0/70ea112139131a403c416580f084354d52352bdd.png)  
It shows wind speed, UVI, forecast rain or forecast snow on a single line, whichever is deemed most significant.

CSS

```auto
[{"id":"54f4826637021f7e","type":"ui_template","z":"b8d7f4fe20eeb12b","g":"9bac35c7409568ce","group":"8b0e39ea5423124a","name":"CSS","order":3,"width":1,"height":1,"format":"<style>\n:root {\n/* these are the colours of the three layers */\n--background: 126,219,251; /* blue */\n--r1: 250; --g1: 250; --b1: 147; /* yellow */\n--r2: 255; --g2: 179; --b2: 179; /* red */\n/* and text */\n--textcolor: black;\n--alertcolor: chocolate; \n--raincolor: blue;\n--snowcolor: white;\n--windcolor: black;\n--uvicolor: red;\n}\n.weatherwidget{\n position: relative;\n height: 289px;\n width: calc(100% - 1px);\n background-color: rgb(var(--background));\n}\n\n.bordered{\n box-sizing: border-box;\n border:4px solid black;\n margin-bottom: 2px;\n}\n.rounded {\n border-radius: 10px;\n}\n.weatherwidget .layer1 {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n /* box-shadow: 4px 4px 28px 0px rgba(0,0,0,0.3) inset;*/\n background-color: rgba(var(--r1), var(--g1), var(--b1), var(--layer1alpha));\n}\n.weatherwidget .layer2 {\nposition: absolute;\nwidth: 100%;\nheight: 100%;\ntop: 0;\nbox-shadow: 4px 4px 28px 0px rgba(0,0,0,0.3) inset;\nbackground-color: rgba(var(--r2), var(--g2), var(--b2), var(--layer2alpha));\n}\n\n .weatherwidget .location {\n position: absolute;\n top: -5px;\n left: 6px;\n height: 56px;\n font-family: \"Times New Roman\", serif;\n font-size: 40px;\n color: var(--textcolor);\n text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);\n overflow: hidden;\n }\n\n .weatherwidget .location .placename {\n position: relative;\n float: left;\n max-width: 330px;\n }\n\n .weatherwidget .location .forecasttime {\n position: relative;\n font-size: 24px;\n font-size: 0.7em;\n float: left;\n margin-top: 11px;\n font-family: \"Calibri\", sans-serif;\n }\n\n .weatherwidget .location .current {\n height: 90px;\n width: 80px;\n }\n\n .weatherwidget .temperature {\n position: absolute;\n top: 37px;\n left: 00px;\n height: 40px;\n color: var(--textcolor);\n font-family: calibri, sans-serif;\n text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);\n float: left;\n clear: left;\n margin-left: 7px;\n font-size: 40px;\n }\n\n .weatherwidget .temperature .actual {\n position: relative;\n float: left;\n height: 40px;\n }\n\n .weatherwidget .temperature .actual .value {\n position: relative;\n font-size: 40px;\n height: 40px;\n }\n\n .weatherwidget .temperature .feelslike {\n position: relative;\n float: left;\n font-size: 32px;\n margin-left: 20px;\n margin-top: 5px;\n }\n\n .weatherwidget .temperature .feelslike .value {\n position: relative;\n float: left;\n margin-left: 20px;\n }\n\n\n .weatherwidget .currentwrapper {\n position: absolute;\n width: 100px;\n height: 64px;\n right: 10px;\n top: 0px;\n }\n\n .weatherwidget .current {\n position: ;\n color: var(--textcolor);\n font-size: 16px;\n font-family: verdana, sans-serif;\n }\n\n .weatherwidget .current .wind {\n position: absolute;\n top: 8px;\n right: 0px;\n }\n\n .weatherwidget .current .pressure {\n position: absolute;\n top: 26px;\n right: 0px;\n }\n\n .weatherwidget .current .humidity {\n position: absolute;\n top: 44px;\n right: 0px;\n }\n\n .weatherwidget .comments {\n position: absolute;\n top: 77px;\n right: 10px;\n font-size: 16px;\n color: var(--alertcolor);\n font-family: verdana, sans-serif;\n text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);\n height: 18px;\n width: 98%;\n text-align: right;\n }\n\n .weatherwidget .provider {\n position: absolute;\n top: 230px;\n left: 10px;\n font-size: 12px;\n height: 18px;\n width: 100px;\n }\n\n .weatherwidget .iconswrapper {\n position: absolute;\n top: 97px;\n width: 100%;\n color: var(--textcolor);\n text-align: center;\n font-family: verdana, sans-serif;\n }\n\n .weatherwidget .iconswrapper .hourly {\n position: relative;\n top: 0px;\n float: left;\n margin-left: 10px;\n height: 77px;\n }\n\n .weatherwidget .iconswrapper .daily {\n position: relative;\n float: right;\n height: 77px;\n }\n\n .weatherwidget .iconswrapper .icon {\n float: left;\n min-width: 40px;\n }\n .weatherwidget .iconswrapper .daily .icon {\n float: left;\n min-width: 50px;\n }\n\n .weatherwidget .iconswrapper .icon i {\n padding-bottom: 5px;\n font-size: 26px;\n /* using fa-2x instead makes icon slightly too wide */\n text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);\n }\n\n .weatherwidget .iconswrapper .subtitle {\n font-size: 11px;\n margin-bottom: 2px;\n }\n .norway img {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n }\n</style>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":330,"y":260,"wires":[[]]},{"id":"8b0e39ea5423124a","type":"ui_group","name":"Buttons","tab":"9217190ce8cf176f","order":3,"disp":false,"width":2,"collapse":false,"className":""},{"id":"9217190ce8cf176f","type":"ui_tab","name":"Widgets","icon":"dashboard","disabled":false,"hidden":false}]

```

Function to process OWM response

```auto
[{"id":"6064346f6717ae79","type":"function","z":"b8d7f4fe20eeb12b","g":"9bac35c7409568ce","name":"Adjust output","func":"function dateformat(timestamp, timezone) {\n if (timestamp < 10000000000) { timestamp *= 1000; } // convert Unix to JS timestamp if needed\n const date = new Date(timestamp);\n var options = {\n weekday: 'short', hour: 'numeric', minute: 'numeric',\n timeZone: timezone,\n hour12: false\n };\n var answer = (new Intl.DateTimeFormat('en-US', options).formatToParts(date));\n if (answer[2].value == \"24\") answer[2].value = \"00\";\n\n return { dayname: answer[0].value, time: answer[2].value + \":\" + answer[4].value };\n}\n\nfunction degreesToCompass(deg) {\n if (deg > 11.25 && deg <= 33.75) { return \"NNE\"; }\n else if (deg <= 56.25) { return \"NE\"; }\n else if (deg <= 78.75) { return \"ENE\"; }\n else if (deg <= 101.25) { return \"E\"; }\n else if (deg <= 123.75) { return \"ESE\"; }\n else if (deg <= 146.25) { return \"SE\"; }\n else if (deg <= 168.75) { return \"SSE\"; }\n else if (deg <= 191.25) { return \"S\"; }\n else if (deg <= 213.75) { return \"SSW\"; }\n else if (deg <= 236.25) { return \"SW\"; }\n else if (deg <= 258.75) { return \"WSW\"; }\n else if (deg <= 281.25) { return \"W\"; }\n else if (deg <= 303.75) { return \"WNW\"; }\n else if (deg <= 326.25) { return \"NW\"; }\n else if (deg <= 348.75) { return \"NNW\"; }\n else { return \"N\"; }\n}\n\nconst cold = msg.save.coldat\nconst hot = msg.save.hotat\nconst temp = msg.payload.current.temp\nconst alertstyle = \"color: var(--alertcolor)\"\n\nmsg.payload.layer1alpha = 2 * (temp - cold) / (hot - cold) // 0 at cold, 1 at halfway \nmsg.payload.layer2alpha = msg.payload.layer1alpha - 1 // 0 at halfway, 1 at hot\nmsg.payload.location = msg.save.location\nmsg.payload.provider = \"OpenWeatherMap\"\n\n// wind as compass points \nmsg.payload.current.wind_point = degreesToCompass(msg.payload.current.wind_deg);\nmsg.payload.current.wind_knots = msg.payload.current.wind_speed * 1.944;\nmsg.payload.current.wind_mph = msg.payload.current.wind_speed * 2.237;\n\n// The time the forecast was delivered from OWM\nmsg.payload.forecasttime = dateformat(msg.payload.current.dt, msg.payload.timezone).time;\n\n// Weather alerts\nmsg.payload.comments = \"\"\nif (msg.payload.hasOwnProperty('alerts') && msg.payload.comments == \"\") { // There may be several weather alerts\n msg.payload.alerts.forEach(alert => {\n if (alert.tags.length > 0 && msg.payload.comments == \"\") { // There may be several weather alerts but only space to show one\n msg.payload.comments = alert.event; // Don't choose any without tags (may be general info)\n const start = new Date(alert.start * 1000)\n const end = new Date(alert.end * 1000)\n msg.payload.comments += \" \" + dateformat(start, msg.payload.timezone).dayname + \" \" + dateformat(start, msg.payload.timezone).time\n msg.payload.comments += \" - \" + dateformat(end, msg.payload.timezone).dayname + \" \" + dateformat(end, msg.payload.timezone).time\n }\n })\n}\n\n\n// Get rain & snow qty and alerts for each hour, Adjust display to show local time\n// Not sure if browser timezone is relevant (check again in BST!)\nfunction doit(element, index) {\n let precipitation = 0;\n let date = new Date(element.dt * 1000);\n element.localtime = dateformat(element.dt, msg.payload.timezone).time;\n // trigger levels for rain, snow, wind and UVI display\n element.rainmm = (element.hasOwnProperty('rain') && element.rain['1h'] > 0.5) ? Math.round(element.rain[\"1h\"]) + \"mm\" : \"\"\n element.snowmm = (element.hasOwnProperty('snow') && element.snow[\"1h\"] > 0.5) ? Math.round(element.snow[\"1h\"]) + \"mm\" : \"\"\n\n element.strongwind = (element.wind_speed > 8) ? Math.round(element.wind_speed *1.944) + \"kt\" : \"\" // 8m/s = force 5\n element.uvindex = (element.uvi > 5) ? \"uvi \" + Math.round(element.uvi) : \"\"\n\n if (element.strongwind != \"\") {\n element.note = element.strongwind\n element.notestyle = \"color: var(--windcolor)\"\n }\n else if (element.snowmm != \"\") {\n element.note = element.snowmm\n element.notestyle = \"color: var(--snowcolor)\"\n }\n else if (element.rainmm != \"\") {\n element.note = element.rainmm\n element.notestyle = \"color: var(--raincolor)\"\n }\n else if (element.uvindex != \"\") {\n element.note = element.uvindex\n element.notestyle = \"color: var(--uvicolor)\"\n }\n\n if (msg.payload.hasOwnProperty('alerts')) {\n msg.payload.alerts.forEach(alert => {\n if (alert.tags.length > 0 && element.dt < alert.end && (element.dt + 3600) > alert.start) {\n element.warning = alert.event\n element.iconstyle = alertstyle\n }\n });\n }\n}\nmsg.payload.hourly.forEach(doit);\n\n// Get rain & snow qty and alerts for each day\nmsg.payload.daily.forEach(element => {\n const date = new Date(element.dt * 1000);\n element.day = dateformat(element.dt, msg.payload.timezone).dayname;\n element.rainmm = element.snowmm = element.strongwind = \"\"\n\n if (element.hasOwnProperty('rain') && element.rain > 1) {\n element.rainmm = Math.round(element.rain) + \"mm\";\n }\n if (element.hasOwnProperty('snow') && element.snow > 1) {\n element.snowmm = Math.round(element.snow) + \"mm\";\n }\n if (element.wind_speed >= 8) { // 8m/s = force 5\n element.strongwind = Math.round(element.wind_speed) + \"kt\"; \n } \n if (element.strongwind != \"\") {\n element.note = element.strongwind\n element.notestyle = \"color: var(--windcolor)\"\n }\n else if (element.snowmm != \"\") {\n element.note = element.snowmm\n element.notestyle = \"color: var(--snowcolor)\"\n }\n else if (element.rainmm != \"\") {\n element.note = element.rainmm\n element.notestyle = \"color: var(--raincolor)\"\n }\n\n if (msg.payload.hasOwnProperty('alerts')) {\n msg.payload.alerts.forEach(alert => {\n if (element.dt <= alert.end && (element.dt + 86400) >= alert.start) {\n element.warning = alert.event;\n element.iconstyle = alertstyle\n }\n });\n }\n\n});\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":450,"y":360,"wires":[["a2e3fcd6e473d252"]]}]

```

The template

```auto
[{"id":"2db865c851446fe0","type":"ui_template","z":"b8d7f4fe20eeb12b","g":"9bac35c7409568ce","group":"b76a9ba1d517ea75","name":"Elsewhere","order":4,"width":10,"height":5,"format":"<div class=\"weatherwidget rounded\">\n <div class=\"layer1 rounded\" style=\"--layer1alpha: {{msg.payload.layer1alpha}};\">\n <div class=\"layer2 rounded bordered\" style=\"--layer2alpha: {{msg.payload.layer2alpha}}\">\n \n <div class=\"location\">\n <div class=\"placename\">\n {{(msg.payload.location)}}\n </div>\n <div class=\"forecasttime\">\n &VeryThinSpace;@&VeryThinSpace;{{msg.payload.forecasttime}}\n </div>\n </div>\n <div class=\"temperature\">\n <div class=\"actual\">\n {{msg.payload.current.temp | number:1}}°C\n </div>\n <div class=\"feelslike\">\n ({{msg.payload.current.feels_like |number:0}}°)\n </div>\n </div>\n \n <div class=\"currentwrapper\">\n <div class=\"current\">\n <div class=\"wind\">\n {{msg.payload.current.wind_knots | number:0}}kt {{msg.payload.current.wind_point}}\n </div>\n <div class=\"pressure\">\n {{msg.payload.current.pressure}}hPa\n </div>\n <div class=\"humidity\">\n {{msg.payload.current.humidity}}%\n </div>\n </div>\n </div>\n <div class=\"provider\">{{msg.payload.provider}}</div>\n <div class=\"comments\">{{msg.payload.comments}}</div> \n \n\n <div class=\"iconswrapper\">\n <div class=\"hourly\">\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[1].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[1].weather[0].icon}}\" style=\"{{msg.payload.hourly[1].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[1].temp | number:0}}°</div>\n <div class=\"subtitle note\" style = \"{{msg.payload.hourly[1].notestyle}}\">{{msg.payload.hourly[1].note}}</div>\n \n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[2].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[2].weather[0].icon}}\" style=\"{{msg.payload.hourly[2].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[2].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[2].notestyle}}\">{{msg.payload.hourly[2].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[3].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[3].weather[0].icon}}\" style=\"{{msg.payload.hourly[3].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[3].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[3].notestyle}}\">{{msg.payload.hourly[3].note}}</div>\n\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[4].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[4].weather[0].icon}}\" style=\"{{msg.payload.hourly[4].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[4].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[4].notestyle}}\">{{msg.payload.hourly[4].note}}</div>\n\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[5].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[5].weather[0].icon}}\" style=\"{{msg.payload.hourly[5].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[5].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[5].notestyle}}\">{{msg.payload.hourly[5].note}}</div>\n\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[6].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[6].weather[0].icon}}\" style=\"{{msg.payload.hourly[6].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[6].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[6].notestyle}}\">{{msg.payload.hourly[6].note}}</div>\n\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[7].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[7].weather[0].icon}}\" style=\"{{msg.payload.hourly[7].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[7].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[7].notestyle}}\">{{msg.payload.hourly[7].note}}</div>\n\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[8].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[8].weather[0].icon}}\" style=\"{{msg.payload.hourly[8].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[8].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[8].notestyle}}\">{{msg.payload.hourly[8].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[9].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[9].weather[0].icon}}\" style=\"{{msg.payload.hourly[9].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[9].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[9].notestyle}}\">{{msg.payload.hourly[9].note}}</div>\n \n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[10].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[10].weather[0].icon}}\" style=\"{{msg.payload.hourly[10].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[10].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[10].notestyle}}\">{{msg.payload.hourly[10].note}}</div>\n \n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[11].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[11].weather[0].icon}}\" style=\"{{msg.payload.hourly[11].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[11].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[11].notestyle}}\">{{msg.payload.hourly[11].note}}</div>\n \n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[12].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[12].weather[0].icon}}\" style=\"{{msg.payload.hourly[12].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[12].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[12].notestyle}}\">{{msg.payload.hourly[12].note}}</div>\n \n </div>\n\n </div>\n <div class=\"daily\">\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[0].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[0].weather[0].icon}}\" style=\"{{msg.payload.daily[1].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[0].temp.min | number:0}}/{{msg.payload.daily[0].temp.max | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[0].notestyle}}\">{{msg.payload.daily[0].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[1].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[1].weather[0].icon}}\" style=\"{{msg.payload.daily[1].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[1].temp.min | number:0}}/{{msg.payload.daily[1].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[1].notestyle}}\">{{msg.payload.daily[1].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[2].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[2].weather[0].icon}}\" style=\"{{msg.payload.daily[2].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[2].temp.min | number:0}}/{{msg.payload.daily[2].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[2].notestyle}}\">{{msg.payload.daily[2].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[3].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[3].weather[0].icon}}\" style=\"{{msg.payload.daily[3].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[3].temp.min | number:0}}/{{msg.payload.daily[3].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[3].notestyle}}\">{{msg.payload.daily[3].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[4].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[4].weather[0].icon}}\" style=\"{{msg.payload.daily[4].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[4].temp.min | number:0}}/{{msg.payload.daily[4].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[4].notestyle}}\">{{msg.payload.daily[4].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[5].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[5].weather[0].icon}}\" style=\"{{msg.payload.daily[5].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[5].temp.min | number:0}}/{{msg.payload.daily[5].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[5].notestyle}}\">{{msg.payload.daily[5].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[6].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[6].weather[0].icon}}\" style=\"{{msg.payload.daily[6].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[6].temp.min | number:0}}/{{msg.payload.daily[6].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[6].notestyle}}\">{{msg.payload.daily[6].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[7].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[7].weather[0].icon}}\" style=\"{{msg.payload.daily[7].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[7].temp.min | number:0}}/{{msg.payload.daily[7].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[7].notestyle}}\">{{msg.payload.daily[7].note}}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":750,"y":400,"wires":[[]]},{"id":"b76a9ba1d517ea75","type":"ui_group","name":"Widgets","tab":"9217190ce8cf176f","order":1,"disp":false,"width":"10","collapse":false,"className":""},{"id":"9217190ce8cf176f","type":"ui_tab","name":"Widgets","icon":"dashboard","disabled":false,"hidden":false}]

```

---

<div class="post-metadata">

**Author:** ![Sean-McG](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/sean-mcg/32/54677_2.png) [@Sean-McG](https://discourse.nodered.org/u/Sean-McG)\
**Post date:** [5 May 2025 14:00 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/24 "2025-05-05T14:00:44Z")

</div>

Maybe the other half would like some cute icons  
🤣  
 ![Animation](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/5/8/58c8f0f856a40831b7f1e61036d9a737efec6b41.gif)

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [5 May 2025 14:13 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/25 "2025-05-05T14:13:21Z")

</div>

Are you saying my icons are ugly too? 😉

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [5 May 2025 14:19 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/26 "2025-05-05T14:19:31Z")

</div>

> [@jbudd](#):
>
> icons are ugly too?

I prefer your icons actually. 🙂

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [5 May 2025 14:26 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/27 "2025-05-05T14:26:10Z")

</div>

> [@jbudd](#):
>
> FWIW, this is the current iteration in Dashboard 1

Any chance you could post the whole thing because I'm still not getting the same data as you. Did you switch to the v3.0 API maybe?

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [5 May 2025 14:52 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/28 "2025-05-05T14:52:52Z")

</div>

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/9/d/9df5d63d2bc625504f95a2ef63510b385fef167b.png)

```auto
[{"id":"2bb77cea1390576c","type":"tab","label":"Flow 4","disabled":false,"info":"","env":[]},{"id":"3b28964ee1188afa","type":"group","z":"2bb77cea1390576c","name":"OpenWeatherMap to weather display","style":{"label":true,"stroke":"#3f93cf","fill":"#addb7b","fill-opacity":"0.26","color":"#000000"},"nodes":["6aa4a1cae35f5ee3","4b13d4dd49a3c6a4","3fa63013e8890640","111f70b8217e8abf","8ae66e1034d97e15","fbd3c64a91a6693b","5e44bdea91b611fd","2f044bc04f2c18ea"],"x":14,"y":119,"w":652,"h":162},{"id":"30addf816e5e367c","type":"group","z":"2bb77cea1390576c","name":"Openweathermap NB uses global.openweathermapid","style":{"label":true,"fill":"#e3f3d3","fill-opacity":"0.57","stroke":"#3f93cf","color":"#000000"},"nodes":["7a7386c418a0a8b9","311efcbb8e90dbbc","f68a7664af2afd6b","4eb17950d5469054"],"x":14,"y":19,"w":502,"h":82},{"id":"6aa4a1cae35f5ee3","type":"link call","z":"2bb77cea1390576c","g":"3b28964ee1188afa","name":"OWM","links":["4eb17950d5469054"],"linkType":"static","timeout":"30","x":550,"y":180,"wires":[["4b13d4dd49a3c6a4"]]},{"id":"4b13d4dd49a3c6a4","type":"function","z":"2bb77cea1390576c","g":"3b28964ee1188afa","name":"Adjust output","func":"function dateformat(timestamp, timezone) {\n if (timestamp < 10000000000) { timestamp *= 1000; } // convert Unix to JS timestamp if needed\n const date = new Date(timestamp);\n var options = {\n weekday: 'short', hour: 'numeric', minute: 'numeric',\n timeZone: timezone,\n hour12: false\n };\n var answer = (new Intl.DateTimeFormat('en-US', options).formatToParts(date));\n if (answer[2].value == \"24\") answer[2].value = \"00\";\n\n return { dayname: answer[0].value, time: answer[2].value + \":\" + answer[4].value };\n}\n\nfunction degreesToCompass(deg) {\n if (deg > 11.25 && deg <= 33.75) { return \"NNE\"; }\n else if (deg <= 56.25) { return \"NE\"; }\n else if (deg <= 78.75) { return \"ENE\"; }\n else if (deg <= 101.25) { return \"E\"; }\n else if (deg <= 123.75) { return \"ESE\"; }\n else if (deg <= 146.25) { return \"SE\"; }\n else if (deg <= 168.75) { return \"SSE\"; }\n else if (deg <= 191.25) { return \"S\"; }\n else if (deg <= 213.75) { return \"SSW\"; }\n else if (deg <= 236.25) { return \"SW\"; }\n else if (deg <= 258.75) { return \"WSW\"; }\n else if (deg <= 281.25) { return \"W\"; }\n else if (deg <= 303.75) { return \"WNW\"; }\n else if (deg <= 326.25) { return \"NW\"; }\n else if (deg <= 348.75) { return \"NNW\"; }\n else { return \"N\"; }\n}\n\nconst cold = msg.save.coldat\nconst hot = msg.save.hotat\nconst temp = msg.payload.current.temp\nconst alertstyle = \"color: var(--alertcolor)\"\n\nmsg.payload.layer1alpha = 2 * (temp - cold) / (hot - cold) // 0 at cold, 1 at halfway \nmsg.payload.layer2alpha = msg.payload.layer1alpha - 1 // 0 at halfway, 1 at hot\nmsg.payload.location = msg.save.location\nmsg.payload.provider = \"OpenWeatherMap\"\n\n// wind as compass points \nmsg.payload.current.wind_point = degreesToCompass(msg.payload.current.wind_deg);\nmsg.payload.current.wind_knots = msg.payload.current.wind_speed * 1.944;\nmsg.payload.current.wind_mph = msg.payload.current.wind_speed * 2.237;\n\n// The time the forecast was delivered from OWM\nmsg.payload.forecasttime = dateformat(msg.payload.current.dt, msg.payload.timezone).time;\n\n// Weather alerts\nmsg.payload.comments = \"\"\nif (msg.payload.hasOwnProperty('alerts') && msg.payload.comments == \"\") { // There may be several weather alerts\n msg.payload.alerts.forEach(alert => {\n if (alert.tags.length > 0 && msg.payload.comments == \"\") { // There may be several weather alerts but only space to show one\n msg.payload.comments = alert.event; // Don't choose any without tags (may be general info)\n const start = new Date(alert.start * 1000)\n const end = new Date(alert.end * 1000)\n msg.payload.comments += \" \" + dateformat(start, msg.payload.timezone).dayname + \" \" + dateformat(start, msg.payload.timezone).time\n msg.payload.comments += \" - \" + dateformat(end, msg.payload.timezone).dayname + \" \" + dateformat(end, msg.payload.timezone).time\n }\n })\n}\n\n\n// Get rain & snow qty and alerts for each hour, Adjust display to show local time\n// Not sure if browser timezone is relevant (check again in BST!)\nfunction doit(element, index) {\n let precipitation = 0;\n let date = new Date(element.dt * 1000);\n element.localtime = dateformat(element.dt, msg.payload.timezone).time;\n // trigger levels for rain, snow, wind and UVI display\n element.rainmm = (element.hasOwnProperty('rain') && element.rain['1h'] > 0.5) ? Math.round(element.rain[\"1h\"]) + \"mm\" : \"\"\n element.snowmm = (element.hasOwnProperty('snow') && element.snow[\"1h\"] > 0.5) ? Math.round(element.snow[\"1h\"]) + \"mm\" : \"\"\n\n element.strongwind = (element.wind_speed > 8) ? Math.round(element.wind_speed *1.944) + \"kt\" : \"\" // 8m/s = force 5\n element.uvindex = (element.uvi > 5) ? \"uvi \" + Math.round(element.uvi) : \"\"\n\n if (element.strongwind != \"\") {\n element.note = element.strongwind\n element.notestyle = \"color: var(--windcolor)\"\n }\n else if (element.snowmm != \"\") {\n element.note = element.snowmm\n element.notestyle = \"color: var(--snowcolor)\"\n }\n else if (element.rainmm != \"\") {\n element.note = element.rainmm\n element.notestyle = \"color: var(--raincolor)\"\n }\n else if (element.uvindex != \"\") {\n element.note = element.uvindex\n element.notestyle = \"color: var(--uvicolor)\"\n }\n\n if (msg.payload.hasOwnProperty('alerts')) {\n msg.payload.alerts.forEach(alert => {\n if (alert.tags.length > 0 && element.dt < alert.end && (element.dt + 3600) > alert.start) {\n element.warning = alert.event\n element.iconstyle = alertstyle\n }\n });\n }\n}\nmsg.payload.hourly.forEach(doit);\n\n// Get rain & snow qty and alerts for each day\nmsg.payload.daily.forEach(element => {\n const date = new Date(element.dt * 1000);\n element.day = dateformat(element.dt, msg.payload.timezone).dayname;\n element.rainmm = element.snowmm = element.strongwind = \"\"\n\n if (element.hasOwnProperty('rain') && element.rain > 1) {\n element.rainmm = Math.round(element.rain) + \"mm\";\n }\n if (element.hasOwnProperty('snow') && element.snow > 1) {\n element.snowmm = Math.round(element.snow) + \"mm\";\n }\n if (element.wind_speed >= 8) { // 8m/s = force 5\n element.strongwind = Math.round(element.wind_speed) + \"kt\"; \n } \n if (element.strongwind != \"\") {\n element.note = element.strongwind\n element.notestyle = \"color: var(--windcolor)\"\n }\n else if (element.snowmm != \"\") {\n element.note = element.snowmm\n element.notestyle = \"color: var(--snowcolor)\"\n }\n else if (element.rainmm != \"\") {\n element.note = element.rainmm\n element.notestyle = \"color: var(--raincolor)\"\n }\n\n if (msg.payload.hasOwnProperty('alerts')) {\n msg.payload.alerts.forEach(alert => {\n if (element.dt <= alert.end && (element.dt + 86400) >= alert.start) {\n element.warning = alert.event;\n element.iconstyle = alertstyle\n }\n });\n }\n\n});\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":240,"wires":[["8ae66e1034d97e15"]]},{"id":"3fa63013e8890640","type":"change","z":"2bb77cea1390576c","g":"3b28964ee1188afa","name":"","rules":[{"t":"set","p":"save","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":180,"wires":[["6aa4a1cae35f5ee3"]]},{"id":"111f70b8217e8abf","type":"function","z":"2bb77cea1390576c","g":"3b28964ee1188afa","name":"Setup","func":"if (msg.payload == \"Roaraima\") {\n msg.payload = {\n \"location\": \"Roaraima\",\n \"lat\":2.887965,\"long\":-60.674325,\"altitude\":84,\n \"coldat\": 10, \"hotat\": 30\n }\n}\nif (msg.payload == \"Everest Base Camp\") {\n msg.payload = {\n \"location\": \"Everest Base Camp\", \n \"lat\": 28.003896, \"long\": 86.853968, \"altitude\": 5364,\n \"coldat\": -10, \"hotat\": 15\n }\n}\n\nif (msg.payload == \"Capel Curig\") {\n msg.payload = {\n \"location\": \"Capel Curig\",\n \"lat\": 53.104864, \"long\": -3.911907, \"altitude\": 197,\n \"coldat\": 0, \"hotat\": 20\n }\n}\nif (msg.payload == \"Torshavn\") {\n msg.payload = {\n \"location\": \"Tórshavn Faroe Is.\",\n \"lat\": 62.005204, \"long\": -6.762804, \"altitude\": 0,\n \"coldat\": 0, \"hotat\": 20\n }\n}\nif (msg.payload == \"Death Valley\") {\n msg.payload = {\n \"location\": \"Death Valley\",\n \"lat\": 36.498484, \"long\": -117.091708, \"altitude\": 1400,\n \"coldat\": 0, \"hotat\": 30\n }\n}\nif (msg.payload == \"Laredo\") {\n msg.payload = {\n \"location\": \"Laredo Texas\",\n \"lat\": 27.541515, \"long\": -99.463180, \"altitude\": 0,\n \"coldat\": 0, \"hotat\": 20\n }\n}\n\nif (msg.payload === \"reload\") {\n msg.payload = context.get('savedlocation')\n}\ncontext.set ('savedlocation', msg.payload)\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":180,"wires":[["3fa63013e8890640"]]},{"id":"8ae66e1034d97e15","type":"ui_template","z":"2bb77cea1390576c","g":"3b28964ee1188afa","group":"a2c542e2c9c946bf","name":"Display","order":1,"width":10,"height":5,"format":"<div class=\"weatherwidget rounded\">\n <div class=\"layer1 rounded\" style=\"--layer1alpha: {{msg.payload.layer1alpha}};\">\n <div class=\"layer2 rounded bordered\" style=\"--layer2alpha: {{msg.payload.layer2alpha}}\">\n \n <div class=\"location\">\n <div class=\"placename\">\n {{(msg.payload.location)}}\n </div>\n <div class=\"forecasttime\">\n &VeryThinSpace;@&VeryThinSpace;{{msg.payload.forecasttime}}\n </div>\n </div>\n <div class=\"temperature\">\n <div class=\"actual\">\n {{msg.payload.current.temp | number:1}}°C\n </div>\n <div class=\"feelslike\">\n ({{msg.payload.current.feels_like |number:0}}°)\n </div>\n </div>\n \n <div class=\"currentwrapper\">\n <div class=\"current\">\n <div class=\"wind\">\n {{msg.payload.current.wind_knots | number:0}}kt {{msg.payload.current.wind_point}}\n </div>\n <div class=\"pressure\">\n {{msg.payload.current.pressure}}hPa\n </div>\n <div class=\"humidity\">\n {{msg.payload.current.humidity}}%\n </div>\n </div>\n </div>\n <div class=\"provider\">{{msg.payload.provider}}</div>\n <div class=\"comments\">{{msg.payload.comments}}</div> \n \n\n <div class=\"iconswrapper\">\n <div class=\"hourly\">\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[1].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[1].weather[0].icon}}\" style=\"{{msg.payload.hourly[1].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[1].temp | number:0}}°</div>\n <div class=\"subtitle note\" style = \"{{msg.payload.hourly[1].notestyle}}\">{{msg.payload.hourly[1].note}}</div>\n \n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[2].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[2].weather[0].icon}}\" style=\"{{msg.payload.hourly[2].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[2].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[2].notestyle}}\">{{msg.payload.hourly[2].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[3].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[3].weather[0].icon}}\" style=\"{{msg.payload.hourly[3].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[3].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[3].notestyle}}\">{{msg.payload.hourly[3].note}}</div>\n\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[4].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[4].weather[0].icon}}\" style=\"{{msg.payload.hourly[4].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[4].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[4].notestyle}}\">{{msg.payload.hourly[4].note}}</div>\n\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[5].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[5].weather[0].icon}}\" style=\"{{msg.payload.hourly[5].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[5].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[5].notestyle}}\">{{msg.payload.hourly[5].note}}</div>\n\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[6].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[6].weather[0].icon}}\" style=\"{{msg.payload.hourly[6].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[6].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[6].notestyle}}\">{{msg.payload.hourly[6].note}}</div>\n\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[7].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[7].weather[0].icon}}\" style=\"{{msg.payload.hourly[7].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[7].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[7].notestyle}}\">{{msg.payload.hourly[7].note}}</div>\n\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[8].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[8].weather[0].icon}}\" style=\"{{msg.payload.hourly[8].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[8].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[8].notestyle}}\">{{msg.payload.hourly[8].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[9].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[9].weather[0].icon}}\" style=\"{{msg.payload.hourly[9].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[9].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[9].notestyle}}\">{{msg.payload.hourly[9].note}}</div>\n \n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[10].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[10].weather[0].icon}}\" style=\"{{msg.payload.hourly[10].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[10].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[10].notestyle}}\">{{msg.payload.hourly[10].note}}</div>\n \n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[11].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[11].weather[0].icon}}\" style=\"{{msg.payload.hourly[11].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[11].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[11].notestyle}}\">{{msg.payload.hourly[11].note}}</div>\n \n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.hourly[12].localtime}}</div>\n <i class=\"wi wi-owm-{{msg.payload.hourly[12].weather[0].icon}}\" style=\"{{msg.payload.hourly[12].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.hourly[12].temp | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.hourly[12].notestyle}}\">{{msg.payload.hourly[12].note}}</div>\n \n </div>\n\n </div>\n <div class=\"daily\">\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[0].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[0].weather[0].icon}}\" style=\"{{msg.payload.daily[1].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[0].temp.min | number:0}}/{{msg.payload.daily[0].temp.max | number:0}}°</div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[0].notestyle}}\">{{msg.payload.daily[0].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[1].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[1].weather[0].icon}}\" style=\"{{msg.payload.daily[1].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[1].temp.min | number:0}}/{{msg.payload.daily[1].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[1].notestyle}}\">{{msg.payload.daily[1].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[2].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[2].weather[0].icon}}\" style=\"{{msg.payload.daily[2].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[2].temp.min | number:0}}/{{msg.payload.daily[2].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[2].notestyle}}\">{{msg.payload.daily[2].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[3].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[3].weather[0].icon}}\" style=\"{{msg.payload.daily[3].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[3].temp.min | number:0}}/{{msg.payload.daily[3].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[3].notestyle}}\">{{msg.payload.daily[3].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[4].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[4].weather[0].icon}}\" style=\"{{msg.payload.daily[4].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[4].temp.min | number:0}}/{{msg.payload.daily[4].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[4].notestyle}}\">{{msg.payload.daily[4].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[5].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[5].weather[0].icon}}\" style=\"{{msg.payload.daily[5].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[5].temp.min | number:0}}/{{msg.payload.daily[5].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[5].notestyle}}\">{{msg.payload.daily[5].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[6].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[6].weather[0].icon}}\" style=\"{{msg.payload.daily[6].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[6].temp.min | number:0}}/{{msg.payload.daily[6].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[6].notestyle}}\">{{msg.payload.daily[6].note}}</div>\n </div>\n <div class=\"icon\">\n <div class=\"subtitle time\">{{msg.payload.daily[7].day}}</div>\n <i class=\"wi wi-owm-{{msg.payload.daily[7].weather[0].icon}}\" style=\"{{msg.payload.daily[7].iconstyle}}\"></i>\n <div class=\"subtitle temp\">{{msg.payload.daily[7].temp.min | number:0}}/{{msg.payload.daily[7].temp.max | number:0}}°\n </div>\n <div class=\"subtitle note\" style=\"{{msg.payload.daily[7].notestyle}}\">{{msg.payload.daily[7].note}}</div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":580,"y":240,"wires":[[]]},{"id":"fbd3c64a91a6693b","type":"ui_dropdown","z":"2bb77cea1390576c","g":"3b28964ee1188afa","name":"","label":"","tooltip":"","place":"Select option","group":"a2c542e2c9c946bf","order":2,"width":"5","height":"1","passthru":true,"multiple":false,"options":[{"label":"Roaraima, Brasil","value":"Roaraima","type":"str"},{"label":"Capel Curig","value":"Capel Curig","type":"str"},{"label":"Everest Base Camp","value":"Everest Base Camp","type":"str"},{"label":"Torshavn, Faroe Is.","value":"Torshavn","type":"str"},{"label":"Laredo","value":"Laredo","type":"str"},{"label":"Death Valley","value":"Death Valley","type":"str"}],"payload":"","topic":"topic","topicType":"msg","className":"","x":100,"y":240,"wires":[["111f70b8217e8abf"]]},{"id":"5e44bdea91b611fd","type":"ui_button","z":"2bb77cea1390576c","g":"3b28964ee1188afa","name":"","group":"a2c542e2c9c946bf","order":3,"width":"2","height":"1","passthru":false,"label":"Reload","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"reload","payloadType":"str","topic":"topic","topicType":"msg","x":100,"y":200,"wires":[["111f70b8217e8abf"]]},{"id":"2f044bc04f2c18ea","type":"ui_template","z":"2bb77cea1390576c","g":"3b28964ee1188afa","group":"a2c542e2c9c946bf","name":"CSS","order":3,"width":1,"height":1,"format":"<style>\n:root {\n/* these are the colours of the three layers */\n--background: 126,219,251; /* blue */\n--r1: 250; --g1: 250; --b1: 147; /* yellow */\n--r2: 255; --g2: 179; --b2: 179; /* red */\n/* and text */\n--textcolor: black;\n--alertcolor: chocolate; \n--raincolor: blue;\n--snowcolor: white;\n--windcolor: black;\n--uvicolor: red;\n}\n.weatherwidget{\n position: relative;\n height: 289px;\n width: calc(100% - 1px);\n background-color: rgb(var(--background));\n}\n\n.bordered{\n box-sizing: border-box;\n border:4px solid black;\n margin-bottom: 2px;\n}\n.rounded {\n border-radius: 10px;\n}\n.weatherwidget .layer1 {\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n /* box-shadow: 4px 4px 28px 0px rgba(0,0,0,0.3) inset;*/\n background-color: rgba(var(--r1), var(--g1), var(--b1), var(--layer1alpha));\n}\n.weatherwidget .layer2 {\nposition: absolute;\nwidth: 100%;\nheight: 100%;\ntop: 0;\nbox-shadow: 4px 4px 28px 0px rgba(0,0,0,0.3) inset;\nbackground-color: rgba(var(--r2), var(--g2), var(--b2), var(--layer2alpha));\n}\n\n .weatherwidget .location {\n position: absolute;\n top: -5px;\n left: 6px;\n height: 56px;\n font-family: \"Times New Roman\", serif;\n font-size: 40px;\n color: var(--textcolor);\n text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);\n overflow: hidden;\n }\n\n .weatherwidget .location .placename {\n position: relative;\n float: left;\n max-width: 330px;\n }\n\n .weatherwidget .location .forecasttime {\n position: relative;\n font-size: 24px;\n font-size: 0.7em;\n float: left;\n margin-top: 11px;\n font-family: \"Calibri\", sans-serif;\n }\n\n .weatherwidget .location .current {\n height: 90px;\n width: 80px;\n }\n\n .weatherwidget .temperature {\n position: absolute;\n top: 37px;\n left: 00px;\n height: 40px;\n color: var(--textcolor);\n font-family: calibri, sans-serif;\n text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);\n float: left;\n clear: left;\n margin-left: 7px;\n font-size: 40px;\n }\n\n .weatherwidget .temperature .actual {\n position: relative;\n float: left;\n height: 40px;\n }\n\n .weatherwidget .temperature .actual .value {\n position: relative;\n font-size: 40px;\n height: 40px;\n }\n\n .weatherwidget .temperature .feelslike {\n position: relative;\n float: left;\n font-size: 32px;\n margin-left: 20px;\n margin-top: 5px;\n }\n\n .weatherwidget .temperature .feelslike .value {\n position: relative;\n float: left;\n margin-left: 20px;\n }\n\n\n .weatherwidget .currentwrapper {\n position: absolute;\n width: 100px;\n height: 64px;\n right: 10px;\n top: 0px;\n }\n\n .weatherwidget .current {\n position: ;\n color: var(--textcolor);\n font-size: 16px;\n font-family: verdana, sans-serif;\n }\n\n .weatherwidget .current .wind {\n position: absolute;\n top: 8px;\n right: 0px;\n }\n\n .weatherwidget .current .pressure {\n position: absolute;\n top: 26px;\n right: 0px;\n }\n\n .weatherwidget .current .humidity {\n position: absolute;\n top: 44px;\n right: 0px;\n }\n\n .weatherwidget .comments {\n position: absolute;\n top: 77px;\n right: 10px;\n font-size: 16px;\n color: var(--alertcolor);\n font-family: verdana, sans-serif;\n text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);\n height: 18px;\n width: 98%;\n text-align: right;\n }\n\n .weatherwidget .provider {\n position: absolute;\n top: 230px;\n left: 10px;\n font-size: 12px;\n height: 18px;\n width: 100px;\n }\n\n .weatherwidget .iconswrapper {\n position: absolute;\n top: 97px;\n width: 100%;\n color: var(--textcolor);\n text-align: center;\n font-family: verdana, sans-serif;\n }\n\n .weatherwidget .iconswrapper .hourly {\n position: relative;\n top: 0px;\n float: left;\n margin-left: 10px;\n height: 77px;\n }\n\n .weatherwidget .iconswrapper .daily {\n position: relative;\n float: right;\n height: 77px;\n }\n\n .weatherwidget .iconswrapper .icon {\n float: left;\n min-width: 40px;\n }\n .weatherwidget .iconswrapper .daily .icon {\n float: left;\n min-width: 50px;\n }\n\n .weatherwidget .iconswrapper .icon i {\n padding-bottom: 5px;\n font-size: 26px;\n /* using fa-2x instead makes icon slightly too wide */\n text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);\n }\n\n .weatherwidget .iconswrapper .subtitle {\n font-size: 11px;\n margin-bottom: 2px;\n }\n .norway img {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n }\n</style>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":90,"y":160,"wires":[[]]},{"id":"7a7386c418a0a8b9","type":"function","z":"2bb77cea1390576c","g":"30addf816e5e367c","name":"Setup","func":"const owmid = global.get(\"openweathermapid\")\n\nmsg.url = \"https://api.openweathermap.org/data/3.0/onecall?\"\nmsg.url += \"lat=\" + msg.payload.lat + \"&lon=\" + msg.payload.long + \"&units=metric\"\nmsg.url += \"&appid=\" + owmid\nreturn msg;\n\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":150,"y":60,"wires":[["f68a7664af2afd6b"]]},{"id":"311efcbb8e90dbbc","type":"link out","z":"2bb77cea1390576c","g":"30addf816e5e367c","name":"OWM Out","mode":"return","links":[],"x":475,"y":60,"wires":[]},{"id":"f68a7664af2afd6b","type":"http request","z":"2bb77cea1390576c","g":"30addf816e5e367c","name":"Openweathermap","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":330,"y":60,"wires":[["311efcbb8e90dbbc"]]},{"id":"4eb17950d5469054","type":"link in","z":"2bb77cea1390576c","g":"30addf816e5e367c","name":"OWM In","links":[],"x":55,"y":60,"wires":[["7a7386c418a0a8b9"]]},{"id":"a2c542e2c9c946bf","type":"ui_group","name":"Widgets","tab":"06cc06cd798102d2","order":1,"disp":false,"width":"10","collapse":false,"className":""},{"id":"06cc06cd798102d2","type":"ui_tab","name":"Widgets","icon":"dashboard","disabled":false,"hidden":false}]

```

ps The display for Everest Basecamp shows a problem when locations have non-integer timezone offsets (Nepal Time is 5h:45m ahead of UTC) but the hourly forecasts are clearly for whole hour timestamps. I guess these times should be rounded up.

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/7/d79bf9547fe678606780bb2e5a35ebe48e0b1316.png)

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [5 May 2025 15:58 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/29 "2025-05-05T15:58:28Z")

</div>

Brrr, wrong time of year for base camp. I was once up that way. 🏔 😀

This is round the back of Everest, looking up at Lhotse and Nuptse from Chukhung.

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/7/6/7633889386ba8913250b42fe0262cf975e7052ba.jpeg)

---

<div class="post-metadata">

**Author:** ![patrizioperrone](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/patrizioperrone/32/100573_2.png) [@patrizioperrone](https://discourse.nodered.org/u/patrizioperrone)\
**Post date:** [11 May 2025 14:48 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/31 "2025-05-11T14:48:03Z")

</div>

Hello is there any update on Dashboard 2.0 conversion for this project?

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [11 May 2025 15:11 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/32 "2025-05-11T15:11:31Z")

</div>

Not from me and i doubt if i will do any more work on it.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [11 May 2025 18:41 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/33 "2025-05-11T18:41:29Z")

</div>

I started on a web component version but it is low priority for me, I'll try to get back to it at some point.

---

<div class="post-metadata">

**Author:** ![patrizioperrone](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/patrizioperrone/32/100573_2.png) [@patrizioperrone](https://discourse.nodered.org/u/patrizioperrone)\
**Post date:** [11 May 2025 19:21 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/34 "2025-05-11T19:21:20Z")

</div>

Thanks for ypur reply.

---

<div class="post-metadata">

**Author:** ![patrizioperrone](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/patrizioperrone/32/100573_2.png) [@patrizioperrone](https://discourse.nodered.org/u/patrizioperrone)\
**Post date:** [22 September 2025 18:11 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/35 "2025-09-22T18:11:35Z")

</div>

Hello do you get by any chance the dashboard.c9nverted to version ? Thanks

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [22 September 2025 18:47 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/36 "2025-09-22T18:47:24Z")

</div>

No, sorry, a lot going on and nowhere near enough time to do everything I'd like I'm afraid. It is still on my list, just quite a way's down.

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [25 September 2025 08:29 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/37 "2025-09-25T08:29:35Z")

</div>

I'm trying to rewrite this template to work in Dashboard 2.

Chatgpt has already done some of the work, we are currently struggling with getting icons to show up.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [25 September 2025 09:52 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/38 "2025-09-25T09:52:53Z")

</div>

Let us know if we can help @jbudd

---

<div class="post-metadata">

**Author:** ![jbudd](https://avatars.discourse-cdn.com/v4/letter/j/5f8ce5/32.png) [@jbudd](https://discourse.nodered.org/u/jbudd)\
**Post date:** [25 September 2025 12:06 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/39 "2025-09-25T12:06:16Z")

</div>

I have it fetching OWM forecast and displaying the icons.

Currently working on the background colour, which is supposed to be blue at the perceived "cold" point for the location and red at the "hot" point.  
Originally I did this by varying the transparency of three layers but it seems much more sensible to vary the hue of a single layer.  
Any suggestions around this?

Current snapshot, some CSS stripped out for now & an unhappy colour!

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/a/a/aa3f7c9449029efaf7d9d88dc9df996a42f7fcee.png)

---

<div class="post-metadata">

**Author:** ![Buckskin](https://avatars.discourse-cdn.com/v4/letter/b/b9e5f3/32.png) [@Buckskin](https://discourse.nodered.org/u/Buckskin)\
**Post date:** [25 September 2025 17:06 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/40 "2025-09-25T17:06:28Z")

</div>

This web page gives some good ideas for manipulating HSL colours in CSS [Color Manipulation With CSS Variables and HSL](https://codesalad.dev/blog/color-manipulation-with-css-variables-and-hsl-16) now all you need to do is work out a mathematical equation to change a colour using your 'feels like' temperature - to a colour with an 'other half' approval rating greater than 'ugly'

---

<div class="post-metadata">

**Author:** ![patrizioperrone](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/patrizioperrone/32/100573_2.png) [@patrizioperrone](https://discourse.nodered.org/u/patrizioperrone)\
**Post date:** [15 November 2025 04:39 UTC](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833/41 "2025-11-15T04:39:52Z")

</div>

hello do you have an update on this project by any chance?

[Previous page](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833.md?page=1)

[Next page](https://discourse.nodered.org/t/compact-multi-location-weather-display/57833.md?page=3)
