KNMI Weather dashboard (free api key)

Description:


Check out this Node-RED flow for a dynamic weather dashboard! Utilizing APIs to fetch live weather data, this flow showcases current weather conditions along with forecasted data. With clean UI components, it presents temperature, wind speed, sunrise and sunset times, and more, all in a visually appealing layout.

Features:

  • Live Weather Icon Refresh Button: A button to manually refresh weather data.
  • Current Weather Description: Displays a summary of the current weather condition in a specific location.
  • Temperature: Real-time temperature display.
  • Wind Information: Wind speed and direction are presented along with corresponding icons.
  • Sunrise and Sunset Times: Shows the time of sunrise and sunset for the current day.
  • Weather Forecast: Forecasts for the upcoming hours and days, including weather icons and temperatures.
  • Dynamic Layout: Designed for easy viewing and interaction, with responsive components.

API Integration: To access live weather data, the flow integrates with the KNMI Data Platform API. Make sure to set up a global environment variable for the API key in your Node-RED settings. You can obtain your free API key from KNMI Data Platform.

Get Started: Experience real-time weather updates and forecasts by deploying this Node-RED flow. Customize it to suit your preferences and explore further enhancements to enrich the user experience. Stay informed about the weather conditions in your area with this intuitive weather dashboard!

Sharing: Feel free to share this weather dashboard flow with others who might find it useful. Let's make staying updated with the weather both informative and enjoyable!

KNMI (NL) Weather Dashboard Displaying Live Weather Data

Click to see flowJson
[
    {
        "id": "017e05fb8a189aea",
        "type": "ui_button",
        "z": "08f0ee2de8b69d0f",
        "name": "IconRefresh",
        "group": "dd70abe0.14cb38",
        "order": 1,
        "width": 3,
        "height": 2,
        "passthru": false,
        "label": "",
        "tooltip": "Refresh",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "{{msg.payload.liveweer[0].icon}} fa-4x",
        "payload": "true",
        "payloadType": "bool",
        "topic": "",
        "topicType": "str",
        "x": 810,
        "y": 40,
        "wires": [
            [
                "29dc907a91581671"
            ]
        ]
    },
    {
        "id": "f20aafe5b032faba",
        "type": "ui_text",
        "z": "08f0ee2de8b69d0f",
        "group": "dd70abe0.14cb38",
        "order": 7,
        "width": 6,
        "height": 1,
        "name": "Description",
        "label": "{{msg.payload.liveweer[0].samenv}} ",
        "format": "{{msg.payload.liveweer[0].plaats}}",
        "layout": "col-center",
        "className": "",
        "style": false,
        "font": "",
        "fontSize": "",
        "color": "#000000",
        "x": 810,
        "y": 80,
        "wires": []
    },
    {
        "id": "6a934a71b9970f87",
        "type": "ui_text",
        "z": "08f0ee2de8b69d0f",
        "group": "dd70abe0.14cb38",
        "order": 5,
        "width": 3,
        "height": 1,
        "name": "Wind",
        "label": "",
        "format": "{{msg.payload.liveweer[0].windbft}}&nbsp;&nbsp;<i class=\"wi wi-darksky-wind\"></i>&nbsp;&nbsp;{{msg.payload.liveweer[0].windr}}",
        "layout": "col-center",
        "className": "",
        "style": false,
        "font": "",
        "fontSize": "",
        "color": "#000000",
        "x": 790,
        "y": 160,
        "wires": []
    },
    {
        "id": "d7710bd07a91060e",
        "type": "ui_text",
        "z": "08f0ee2de8b69d0f",
        "group": "dd70abe0.14cb38",
        "order": 6,
        "width": 3,
        "height": 1,
        "name": "SunriseTime",
        "label": "",
        "format": "<i class=\"wi wi-owm-01d\"></i>&nbsp;<i class=\"fa fa-arrow-up\"></i>&nbsp;&nbsp;{{msg.payload.liveweer[0].sup}}",
        "layout": "row-center",
        "className": "",
        "style": false,
        "font": "",
        "fontSize": "",
        "color": "#000000",
        "x": 810,
        "y": 200,
        "wires": []
    },
    {
        "id": "7200eb23d0aede89",
        "type": "ui_text",
        "z": "08f0ee2de8b69d0f",
        "group": "dd70abe0.14cb38",
        "order": 9,
        "width": 3,
        "height": 1,
        "name": "SunsetTime",
        "label": "",
        "format": "<i class=\"wi wi-wu-sunny\"></i>&nbsp;<i class=\"fa fa-arrow-down\"></i>&nbsp;&nbsp;{{msg.payload.liveweer[0].sunder}}",
        "layout": "row-center",
        "className": "",
        "style": false,
        "font": "",
        "fontSize": "",
        "color": "#000000",
        "x": 810,
        "y": 240,
        "wires": []
    },
    {
        "id": "6a0be2f1762de69b",
        "type": "ui_template",
        "z": "08f0ee2de8b69d0f",
        "group": "dd70abe0.14cb38",
        "name": "Forecast2",
        "order": 10,
        "width": 13,
        "height": 2,
        "format": "<div style=\"height: 100%; justify-content: center; align-items: center;\">\n  <div layout=\"rowicons\" layout-align=\"space-around start\">\n    <span flex ng-repeat=\"iconClass in msg.payload.rowicons | limitTo:10 track by $index\"\n          ng-style=\"{'color': $index >= 6 ? '#0b8f95' : 'white', 'text-align': 'center', 'padding-top': '5px', 'padding-bottom': '5px'}\">\n          <i class=\"wi wi-fw fa-2x\" ng-class=\"iconClass\"></i><br>\n          {{msg.payload.rowtext[$index].a}}<br>\n          <span ng-if=\"$index < 6\">{{msg.payload.rowtext[$index].b}}\n          </span>\n    <span ng-if=\"$index >= 6\">{{msg.payload.rowtext[$index].b}}\n    </span>\n    </span>\n  </div>\n</div>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": false,
        "templateScope": "local",
        "className": "",
        "x": 800,
        "y": 280,
        "wires": [
            []
        ],
        "info": "<i class=\"wi wi-fw wi-darksky-partly-cloudy-day fa-4x\" ng-class=\"icon\"></i>"
    },
    {
        "id": "d891232313dad1c3",
        "type": "ui_text",
        "z": "08f0ee2de8b69d0f",
        "group": "dd70abe0.14cb38",
        "order": 3,
        "width": 2,
        "height": 1,
        "name": "Temperature",
        "label": "",
        "format": "<p style=\"font-size: 200%\">{{msg.payload.liveweer[0].temp}} °C</p>",
        "layout": "row-left",
        "className": "",
        "style": false,
        "font": "",
        "fontSize": "",
        "color": "#000000",
        "x": 810,
        "y": 120,
        "wires": []
    },
    {
        "id": "8002d527d22432ad",
        "type": "ui_ui_control",
        "z": "08f0ee2de8b69d0f",
        "name": "Refresh",
        "events": "all",
        "x": 140,
        "y": 80,
        "wires": [
            [
                "81ce5179f58a16b9"
            ]
        ]
    },
    {
        "id": "f62a1604ab6cc4c4",
        "type": "http request",
        "z": "08f0ee2de8b69d0f",
        "name": "weerlive.nl",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "https://weerlive.nl/api/weerlive_api_v2.php?key={{api}}&locatie=s-Hertogenbosch",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 350,
        "y": 140,
        "wires": [
            [
                "488244e40a39012d"
            ]
        ]
    },
    {
        "id": "11f90d284642746c",
        "type": "inject",
        "z": "08f0ee2de8b69d0f",
        "name": "",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "true",
        "payloadType": "bool",
        "x": 150,
        "y": 140,
        "wires": [
            [
                "81ce5179f58a16b9"
            ]
        ]
    },
    {
        "id": "488244e40a39012d",
        "type": "function",
        "z": "08f0ee2de8b69d0f",
        "name": "formatPayload",
        "func": "if (!msg.payload.hasOwnProperty('wk_verw')) {\n  msg.payload = flow.get(\"arr\");\n} else { flow.set(\"arr\", msg.payload) }\n\nif (msg.payload.liveweer[0].plaats === \"s-Hertogenbosch\") {\n  msg.payload.liveweer[0].plaats = \"'s-Hertogenbosch\";\n} \n\nconst iconMap = {\n  \"zonnig\": \"wi-darksky-clear-day\",\n  \"bliksem\": \"wi-darksky-thunderstorm\",\n  \"regen\": \"wi-darksky-rain\",\n  \"buien\": \"wi-darksky-rain\",\n  \"hagel\": \"wi-darksky-hail\",\n  \"mist\": \"wi-darksky-fog\",\n  \"sneeuw\": \"wi-darksky-snow\",\n  \"bewolkt\": \"wi-darksky-cloudy\",\n  \"lichtbewolkt\": \"wi-darksky-partly-cloudy-day\",\n  \"halfbewolkt\": \"wi-darksky-partly-cloudy-day\",\n  \"halfbewolkt_regen\": \"wi-darksky-partly-cloudy-day\",\n  \"zwaarbewolkt\": \"wi-darksky-cloudy\",\n  \"nachtmist\": \"wi-darksky-fog\",\n  \"helderenacht\": \"wi-darksky-clear-night\",\n  \"nachtbewolkt\": \"wi-darksky-partly-cloudy-night\",\n  \"default\": \"wi-arrow\"\n};\nconst dataArray = [\"liveweer\", \"wk_verw\", \"uur_verw\"];\n\nfunction dayName(nr) {\n  const days = ['Zo', 'Ma', 'Di', 'Wo', 'Do', 'Vr', 'Za'];\n  return days[nr % 7];\n};\n\nfunction getWeatherIcon(weatherDescription) {\n  if (!weatherDescription) return iconMap[\"default\"];  // Return default if undefined\n  return iconMap[weatherDescription.toLowerCase()] || iconMap[\"default\"];\n};\nmsg.payload.rowicons = [];\ndataArray.forEach(data => {\n    msg.payload[data].forEach(item => {\n        item.icon = getWeatherIcon(item.image);\n        msg.payload.rowicons.push(item.icon);\n    });\n});\nmsg.payload.rowtext = [] ;\n\nfor (var i = 1; i <= 6; i++) {\n  msg.payload.rowtext.push({\n    \"a\": msg.payload.uur_verw[i].uur.split(' ')[1],\n    \"b\": msg.payload.uur_verw[i].temp + '°C'\n  });\n};\nfor (var i = 1; i <= 4; i++) {\n  msg.payload.rowtext.push({\n    \"a\": dayName(new Date(msg.payload.liveweer[0].timestamp * 1000).getDay() + i),\n    \"b\": msg.payload.wk_verw[i].max_temp + '/' + msg.payload.wk_verw[i].min_temp\n  });\n\n};\nreturn msg;\n\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 540,
        "y": 140,
        "wires": [
            [
                "d891232313dad1c3",
                "6a934a71b9970f87",
                "f20aafe5b032faba",
                "d7710bd07a91060e",
                "7200eb23d0aede89",
                "017e05fb8a189aea",
                "6a0be2f1762de69b"
            ]
        ]
    },
    {
        "id": "a7cd33e3477c8a45",
        "type": "link in",
        "z": "08f0ee2de8b69d0f",
        "name": "",
        "links": [
            "29dc907a91581671"
        ],
        "x": 185,
        "y": 200,
        "wires": [
            [
                "81ce5179f58a16b9"
            ]
        ]
    },
    {
        "id": "29dc907a91581671",
        "type": "link out",
        "z": "08f0ee2de8b69d0f",
        "name": "Refresh",
        "links": [
            "a7cd33e3477c8a45"
        ],
        "x": 915,
        "y": 40,
        "wires": []
    },
    {
        "id": "feba6f750349f33d",
        "type": "inject",
        "z": "08f0ee2de8b69d0f",
        "name": "",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "true",
        "payloadType": "bool",
        "x": 350,
        "y": 80,
        "wires": [
            [
                "488244e40a39012d"
            ]
        ]
    },
    {
        "id": "81ce5179f58a16b9",
        "type": "change",
        "z": "08f0ee2de8b69d0f",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "api",
                "pt": "msg",
                "to": "weerLive_api",
                "tot": "env"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 245,
        "y": 140,
        "wires": [
            [
                "f62a1604ab6cc4c4"
            ]
        ],
        "l": false
    },
    {
        "id": "dd70abe0.14cb38",
        "type": "ui_group",
        "name": "Actions",
        "tab": "ad4a1223.94ae8",
        "order": 2,
        "disp": true,
        "width": 13,
        "collapse": false,
        "className": ""
    },
    {
        "id": "ad4a1223.94ae8",
        "type": "ui_tab",
        "z": "9cf3a6d.1104258",
        "name": "Het Weer",
        "icon": "dashboard",
        "order": 1,
        "disabled": false,
        "hidden": false
    }
]
4 Likes

Ummm, what flow?

1 Like

Me was sure i had past it into the msg, ooops now it is there

I was thinking of create a dedicated node for the knmi data, because they have lots of (historical) metrics available via their API, but then thought about a dashboard with all that information that I will never look at :')

Note: you do not have to register for an API key, they have a public API key available, see this page and click "obtain an API token", see anonymous key.

Oh my I have that in the post

My point was the key without having a login/register.