Get weather forecast from api.met.no (AKA yr.no)
Please change "set geolocation" node according your location.
PS: time rounded to near hour
PSS: cache data stored at flow.context
PSSS: please DO NOT poll yr.no without caching! otherwise you may BUNNED by IP via yr.no service.
[{"id":"ea60fc0d.0ac8","type":"http request","z":"e6a54674.5ab678","name":"api.met.no","method":"GET","ret":"obj","paytoqs":false,"url":"https://api.met.no/weatherapi/locationforecast/1.9/.json?lat={{{lat}}}&lon={{{lon}}}","tls":"","persist":false,"proxy":"","authType":"","x":190,"y":2100,"wires":[["e7232287.fb624"]]},{"id":"e4492649.6d0e88","type":"debug","z":"e6a54674.5ab678","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":710,"y":2040,"wires":[]},{"id":"7a209ce8.986264","type":"inject","z":"e6a54674.5ab678","name":"","topic":"","payload":"","payloadType":"date","repeat":"60","crontab":"","once":true,"onceDelay":0.1,"x":190,"y":1980,"wires":[["5df118c8.e31f18"]]},{"id":"def2ae81.57c36","type":"change","z":"e6a54674.5ab678","name":"set geolocation","rules":[{"t":"set","p":"lat","pt":"msg","to":"0.76644","tot":"str"},{"t":"set","p":"lon","pt":"msg","to":"0.79872","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":200,"y":2060,"wires":[["ea60fc0d.0ac8"]]},{"id":"e7232287.fb624","type":"function","z":"e6a54674.5ab678","name":"save met_public_forecast","func":"if (msg.payload) {\n flow.set(\"met_public_forecast\", msg.payload);\n msg.payload = msg.payload.product.time;\n return msg;\n}","outputs":1,"noerr":0,"x":390,"y":2100,"wires":[["c4c6c2fc.6484d"]]},{"id":"5df118c8.e31f18","type":"function","z":"e6a54674.5ab678","name":"check met_public_forecast","func":"var met_public_forecast = flow.get(\"met_public_forecast\") || null;\nif (met_public_forecast) {\n var now = Date.now();\n var nextrun = new Date(met_public_forecast.meta.model.nextrun); // some mock date\n nextrun = nextrun.getTime(); \n if (now < nextrun) {\n msg.payload = met_public_forecast;\n msg.payload = msg.payload.product.time;\n node.send([null, msg]);\n // node.warn(\"cache\");\n return\n }\n}\nnode.send([msg, null]);\n// node.warn(\"update\");","outputs":2,"noerr":0,"x":240,"y":2020,"wires":[["def2ae81.57c36"],["c4c6c2fc.6484d"]]},{"id":"c4c6c2fc.6484d","type":"function","z":"e6a54674.5ab678","name":"parse","func":"function isSimpleNode(node) {\n return node.location.symbol !== undefined;\n}\n\nfunction hasTemperatureRange(node) {\n return node.location.minTemperature && node.location.maxTemperature;\n}\n\nfunction dateToForecastISO(date) {\n return date.utc().format('YYYY-MM-DDTHH:mm:ss[Z]');\n}\n\nvar self = {times : {}};\n\nmsg.payload.forEach(function (node) {\n\n const simple = isSimpleNode(node);\n const temps = hasTemperatureRange(node);\n\n if (!simple) {\n self.times[node.to] = node;\n } else {\n const parent = self.times[node.to];\n\n parent.icon = node.location.symbol.id;\n parent.rain = node.location.precipitation.value + ' ' + node.location.precipitation.unit;\n\n parent.rainDetails = {\n minRain: 'minvalue' in node.location.precipitation ? node.location.precipitation.minvalue : null,\n maxRain: 'minvalue' in node.location.precipitation ? node.location.precipitation.maxvalue : null,\n rain: node.location.precipitation.value,\n unit: node.location.precipitation.unit\n };\n\n if (temps) {\n parent.minTemperature = node.location.minTemperature;\n parent.maxTemperature = node.location.maxTemperature;\n }\n }\n});\n\nfunction getForecastForTime(forecast, date) {\n date.setSeconds(0);\n if (date.getMinutes() > 30) {\n date.setHours(date.getHours() + 1);\n date.setMinutes(0);\n } else {\n date.setMinutes(0);\n }\n // console.log(date);\n\n var utc = new Date(date.getTime() + date.getTimezoneOffset() * 60000);\n var fc = null;\n for (var time in forecast.times) {\n if (new Date(time) >= utc) {\n fc = forecast.times[time];\n break;\n }\n }\n return fc;\n}\n\nmsg.payload = getForecastForTime(self, new Date());\nreturn msg;","outputs":1,"noerr":0,"x":550,"y":2040,"wires":[["e4492649.6d0e88"]]}]