Hello World,
(Let me start by saying I am in no way a real programmer. I learned dBaseIV, Fortran, Cobol and some C++ at school, but that’s a long time ago).
I made this little project because I was not satisfied by the way the WeatherUnderground weather alerts are implemented. The fact that the attributes can grow dynamic based on the number of alerts, which is very difficult to handle and automate (at least in my eyes), made me create this.
Plus the fact that it appears that the WU API will be shut down (?), plus the fact that the info for European alerts is very limited also in the WU sensor.
So I started looking for something else, which I found on the meteoalarm.eu website. This is by the way also the source for the WU weather alerts for Europe, so why not try to integrate it directly.
At the end, this project will give you some sensors that are feed by MQTT. These sensors will contain the weather alerts (for today and tomorrow) (max 3 alerts per day) for your region.
Prerequisites
- An MQTT broker. I use the HASS built in one, which works fine.
- A webserver that can process PHP pages. As far as I could find, the HASS built-in webserver (your www directory) is not capable to do that. I use my Synology DiskStation for it. If there is a real need for this, I am thinking about setting one up on Azure that can be used by everybody.
- NodeRed connected to your HASS
Setup
1.We will first declare some sensors that will be used.
- platform: mqtt
state_topic: "meteoalarm/todaydata0JSON"
name: "MeteoAlarm Today Data1"
value_template: "{{ value_json }}"
json_attributes:
- icon
- awarenesstype
- awarenesstypedescription
- awarenesslevel
- awarenesscolour
- periodfrom
- perioduntil
- platform: mqtt
state_topic: "meteoalarm/todaydescription0JSON"
name: "MeteoAlarm Today Description1"
value_template: "{{ value_json }}"
json_attributes:
- description
- platform: mqtt
state_topic: "meteoalarm/todaydata1JSON"
name: "MeteoAlarm Today Data2"
value_template: "{{ value_json }}"
json_attributes:
- icon
- awarenesstype
- awarenesstypedescription
- awarenesslevel
- awarenesscolour
- periodfrom
- perioduntil
- platform: mqtt
state_topic: "meteoalarm/todaydescription1JSON"
name: "MeteoAlarm Today Description2"
value_template: "{{ value_json }}"
json_attributes:
- description
- platform: mqtt
state_topic: "meteoalarm/todaydata2JSON"
name: "MeteoAlarm Today Data3"
value_template: "{{ value_json }}"
json_attributes:
- icon
- awarenesstype
- awarenesstypedescription
- awarenesslevel
- awarenesscolour
- periodfrom
- perioduntil
- platform: mqtt
state_topic: "meteoalarm/todaydescription2JSON"
name: "MeteoAlarm Today Description3"
value_template: "{{ value_json }}"
json_attributes:
- description
- platform: mqtt
state_topic: "meteoalarm/tomorrowdata0JSON"
name: "MeteoAlarm Tomorrow Data1"
value_template: "{{ value_json }}"
json_attributes:
- icon
- awarenesstype
- awarenesstypedescription
- awarenesslevel
- awarenesscolour
- periodfrom
- perioduntil
- platform: mqtt
state_topic: "meteoalarm/tomorrowdescription0JSON"
name: "MeteoAlarm Tomorrow Description1"
value_template: "{{ value_json }}"
json_attributes:
- description
- platform: mqtt
state_topic: "meteoalarm/tomorrowdata1JSON"
name: "MeteoAlarm Tomorrow Data2"
value_template: "{{ value_json }}"
json_attributes:
- icon
- awarenesstype
- awarenesstypedescription
- awarenesslevel
- awarenesscolour
- periodfrom
- perioduntil
- platform: mqtt
state_topic: "meteoalarm/tomorrowdescription1JSON"
name: "MeteoAlarm Tomorrow Description2"
value_template: "{{ value_json }}"
json_attributes:
- description
- platform: mqtt
state_topic: "meteoalarm/tomorrowdata2JSON"
name: "MeteoAlarm Tomorrow Data3"
value_template: "{{ value_json }}"
json_attributes:
- icon
- awarenesstype
- awarenesstypedescription
- awarenesslevel
- awarenesscolour
- periodfrom
- perioduntil
- platform: mqtt
state_topic: "meteoalarm/tomorrowdescription2JSON"
name: "MeteoAlarm Tomorrow Description3"
value_template: "{{ value_json }}"
json_attributes:
- description
- platform: mqtt
state_topic: "meteoalarm/publishtime"
name: "MeteoAlarm Publish Time"
value_template: "{{ value_json }}"
json_attributes:
- publishtime
2.Let’s declare some templates for the sensors. The template-sensors will be used to display the final information. Note that you see an icon_template and an entity_template. That’s because lovelace does not display an icon_template but does show an entity_template. The icon_template is there for those that do not use lovelace.
Templates are also needed because you can’t display attributes of a sensor in lovelace (out of the box).
meteoalarm_today_alarm1:
friendly_name: "Alarm Description Today 1"
value_template: "{{states.sensor.meteoalarm_today_description1.attributes.description}}"
icon_template: "{{states.sensor.meteoalarm_today_data1.attributes.icon}}"
entity_picture_template: "{{states.sensor.meteoalarm_today_data1.attributes.icon}}"
meteoalarm_today_alarm2:
friendly_name: "Alarm Description Today 2"
value_template: "{{states.sensor.meteoalarm_today_description2.attributes.description}}"
icon_template: "{{states.sensor.meteoalarm_today_data2.attributes.icon}}"
entity_picture_template: "{{states.sensor.meteoalarm_today_data2.attributes.icon}}"
meteoalarm_today_alarm3:
friendly_name: "Alarm Description Today 3"
value_template: "{{states.sensor.meteoalarm_today_description3.attributes.description}}"
icon_template: "{{states.sensor.meteoalarm_today_data3.attributes.icon}}"
entity_picture_template: "{{states.sensor.meteoalarm_today_data3.attributes.icon}}"
meteoalarm_tomorrow_alarm1:
friendly_name: "Alarm Description Tomorrow 1"
value_template: "{{states.sensor.meteoalarm_tomorrow_description1.attributes.description}}"
icon_template: "{{states.sensor.meteoalarm_tomorrow_data1.attributes.icon}}"
entity_picture_template: "{{states.sensor.meteoalarm_tomorrow_data1.attributes.icon}}"
meteoalarm_tomorrow_alarm2:
friendly_name: "Alarm Description Tomorrow 2"
value_template: "{{states.sensor.meteoalarm_tomorrow_description2.attributes.description}}"
icon_template: "{{states.sensor.meteoalarm_tomorrow_data2.attributes.icon}}"
entity_picture_template: "{{states.sensor.meteoalarm_tomorrow_data2.attributes.icon}}"
meteoalarm_tomorrow_alarm3:
friendly_name: "Alarm Description Tomorrow 3"
value_template: "{{states.sensor.meteoalarm_tomorrow_description3.attributes.description}}"
icon_template: "{{states.sensor.meteoalarm_tomorrow_data3.attributes.icon}}"
entity_picture_template: "{{states.sensor.meteoalarm_tomorrow_data3.attributes.icon}}"
meteoalarm_publishtime:
friendly_name: "Time Published"
value_template: "{{states.sensor.meteoalarm_publish_time.attributes.publishtime}}"
3.Configure your webserver to gather the data from the meteoalarm.eu website.
The meteoalarm website does not provide the required information in any parsable format. I tried different methods (rest, rss, …) but none was satisfying.
In the end I found https://github.com/waynedgrant/meteo-alarm-weather-warnings, which provide some php pages that outputs the meteoalarm data in a parsable JSON.
So, go to the above GitHub page, and follow the installation instructions. For those running the webserver on a Synology, I had to rename the .json file also to a .php.
Once installed, you should be able to browse to http://yourwebserverIP/location_of_php_files/warnings.json?country=UK
This should output you the alarms for the UK.
This is the most important step. As long as you can’t see the UK data, there is no use by going any further.
4.Import the flow in your NodeRed and configure.
Here is the flow:
[{"id":"36a15efd.e65432","type":"tab","label":"MeteoAlarm Data Parsing","disabled":false,"info":""},{"id":"aa1c4018.39b15","type":"http request","z":"36a15efd.e65432","name":"Meteo Alarm Data Belgium/Brabant","method":"GET","ret":"obj","url":"http://192.168.1.10/meteoalarm//warnings.php?country=BE®ion=004","tls":"","x":435,"y":80,"wires":[["a0002bd4.2033b8"]]},{"id":"e782efc.9d39c1","type":"inject","z":"36a15efd.e65432","name":"Every 30 min","topic":"","payload":"","payloadType":"date","repeat":"1800","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":100,"wires":[["aa1c4018.39b15"]]},{"id":"565e34a.f573ecc","type":"api-call-service","z":"36a15efd.e65432","name":"Publish as MQTT","server":"7d2f835e.e2f72c","service_domain":"mqtt","service":"publish","data":"","mergecontext":"","x":1270,"y":240,"wires":[[]]},{"id":"a0002bd4.2033b8","type":"split","z":"36a15efd.e65432","name":"Split Array","splt":"\\n","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":false,"addname":"","x":665,"y":80,"wires":[["bb440ce1.7ae2c"]]},{"id":"bb440ce1.7ae2c","type":"filter","z":"36a15efd.e65432","name":"Filter Header Array","property":"parts.index","propertyType":"msg","asArray":false,"itemProperty":"","itemPropertyType":"item","rules":[{"t":"eq","v":"1","vt":"num","output":1}],"checkall":"true","outputs":1,"x":845,"y":80,"wires":[["df2a1a0.1fc7de8"]]},{"id":"df2a1a0.1fc7de8","type":"split","z":"36a15efd.e65432","name":"Split Array","splt":"\\n","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":false,"addname":"","x":1025,"y":80,"wires":[["d8959832.791fa8"]]},{"id":"df12cc2d.f8782","type":"split","z":"36a15efd.e65432","name":"Split Array","splt":"\\n","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":false,"addname":"","x":110,"y":160,"wires":[["e5419e0e.d34b3"]]},{"id":"e5419e0e.d34b3","type":"split","z":"36a15efd.e65432","name":"Split Array","splt":"\\n","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":false,"addname":"","x":270,"y":160,"wires":[["60fbff36.df0ee","17d1c1c9.24687e","2f125f7c.babec"]]},{"id":"60fbff36.df0ee","type":"filter","z":"36a15efd.e65432","name":"Filter Today","property":"parts.index","propertyType":"msg","asArray":false,"itemProperty":"","itemPropertyType":"item","rules":[{"t":"eq","v":"3","vt":"num","output":1}],"checkall":"true","outputs":1,"x":130,"y":280,"wires":[["5a30b602.0dc4c8"]]},{"id":"17d1c1c9.24687e","type":"filter","z":"36a15efd.e65432","name":"Filter Tomorrow","property":"parts.index","propertyType":"msg","asArray":false,"itemProperty":"","itemPropertyType":"item","rules":[{"t":"eq","v":"4","vt":"num","output":1}],"checkall":"true","outputs":1,"x":140,"y":497,"wires":[["3de5bab.f04ac46"]]},{"id":"2f125f7c.babec","type":"filter","z":"36a15efd.e65432","name":"Filter Publish Date","property":"parts.index","propertyType":"msg","asArray":false,"itemProperty":"","itemPropertyType":"item","rules":[{"t":"eq","v":"5","vt":"num","output":1}],"checkall":"true","outputs":1,"x":530,"y":240,"wires":[["ebb76eac.16201"]]},{"id":"d8959832.791fa8","type":"filter","z":"36a15efd.e65432","name":"Filter Region Array","property":"parts.index","propertyType":"msg","asArray":false,"itemProperty":"","itemPropertyType":"item","rules":[{"t":"eq","v":"1","vt":"num","output":1}],"checkall":"true","outputs":1,"x":1205,"y":80,"wires":[["df12cc2d.f8782"]]},{"id":"5a30b602.0dc4c8","type":"split","z":"36a15efd.e65432","name":"","splt":"\\n","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":false,"addname":"","x":110,"y":340,"wires":[["634db611.cd1fe8"]]},{"id":"e80028d1.40d908","type":"template","z":"36a15efd.e65432","name":"Templating the output Part1","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"data\":\n{\"topic\": \"{{payload.mqtttopic}}\",\n\"payload\": \"{\\\"icon\\\": \\\"{{payload.awareness.icon}}\\\", \\\"awarenesstype\\\": \\\"{{payload.awareness.awareness_type.type}}\\\", \\\"periodfrom\\\": \\\"{{payload.period.from}}\\\", \\\"perioduntil\\\": \\\"{{payload.period.until}}\\\"}\"\n}\n}","output":"str","x":1100,"y":471,"wires":[["db448239.4065a"]]},{"id":"3cf02b43.79c334","type":"template","z":"36a15efd.e65432","name":"Templating the output Part2","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"data\":\n{\"topic\": \"{{payload.mqtttopic}}\",\n\"payload\": \"{\\\"description\\\": \\\"{{payload.description}}\\\"}\"\n}\n}","output":"str","x":1100,"y":380,"wires":[["db448239.4065a"]]},{"id":"f604b49d.8bf518","type":"template","z":"36a15efd.e65432","name":"Set MQTT topic","field":"payload.mqtttopic","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"meteoalarm/{{payload.day}}description{{parts.index}}JSON","output":"str","x":535,"y":385,"wires":[["fb462f0.61786d"]]},{"id":"3de5bab.f04ac46","type":"split","z":"36a15efd.e65432","name":"","splt":"\\n","spltType":"str","arraySplt":"1","arraySpltType":"len","stream":false,"addname":"","x":110,"y":557,"wires":[["bba2a0ae.36ef7"]]},{"id":"ebb76eac.16201","type":"template","z":"36a15efd.e65432","name":"Templating the output","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"data\":\n{\"topic\": \"meteoalarm/publishtime\",\n\"payload\": \"{\\\"publishtime\\\": \\\"{{payload}}\\\"}\"\n}\n}","output":"str","x":1000,"y":240,"wires":[["565e34a.f573ecc"]]},{"id":"db448239.4065a","type":"change","z":"36a15efd.e65432","name":"Fix forwardslash","rules":[{"t":"change","p":"payload","pt":"msg","from":"/","fromt":"str","to":"\\/","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":423,"wires":[["565e34a.f573ecc"]]},{"id":"45522501.e71adc","type":"template","z":"36a15efd.e65432","name":"Set MQTT topic","field":"payload.mqtttopic","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"meteoalarm/{{payload.day}}data{{parts.index}}JSON","output":"str","x":535,"y":472,"wires":[["e80028d1.40d908"]]},{"id":"634db611.cd1fe8","type":"template","z":"36a15efd.e65432","name":"Set payload today","field":"payload.day","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"today","output":"str","x":290,"y":340,"wires":[["f604b49d.8bf518","45522501.e71adc","3737cb5b.c1c254"]]},{"id":"bba2a0ae.36ef7","type":"template","z":"36a15efd.e65432","name":"Set payload tomorrow","field":"payload.day","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"tomorrow","output":"str","x":280,"y":557,"wires":[["f604b49d.8bf518","45522501.e71adc","3737cb5b.c1c254"]]},{"id":"3737cb5b.c1c254","type":"switch","z":"36a15efd.e65432","name":"3, 2 or 1 message?","property":"parts.count","propertyType":"msg","rules":[{"t":"lt","v":"3","vt":"num"},{"t":"lt","v":"2","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":521,"y":657,"wires":[["afd44d93.1eabe","11f31c68.2504e4"],["cd2a2198.50812","e023b6a2.270688"]]},{"id":"afd44d93.1eabe","type":"template","z":"36a15efd.e65432","name":"Set MQTT topic","field":"payload.mqtttopic","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"meteoalarm/{{payload.day}}description2JSON","output":"str","x":731,"y":578,"wires":[["3adcd0c6.bb7c2"]]},{"id":"cd2a2198.50812","type":"template","z":"36a15efd.e65432","name":"Set MQTT topic","field":"payload.mqtttopic","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"meteoalarm/{{payload.day}}description1JSON","output":"str","x":731,"y":678,"wires":[["3adcd0c6.bb7c2"]]},{"id":"3adcd0c6.bb7c2","type":"template","z":"36a15efd.e65432","name":"Cleaning the output Part2","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"data\":\n{\"topic\": \"{{payload.mqtttopic}}\",\n\"payload\": \"{\\\"description\\\": \\\".\\\"}\"\n}\n}","output":"str","x":981,"y":578,"wires":[["db448239.4065a"]]},{"id":"cba777b8.2c1898","type":"template","z":"36a15efd.e65432","name":"Cleaning the output Part1","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"data\":\n{\"topic\": \"{{payload.mqtttopic}}\",\n\"payload\": \"{\\\"icon\\\": \\\"\\\", \\\"awarenesstype\\\": \\\"\\\", \\\"periodfrom\\\": \\\"\\\", \\\"perioduntil\\\": \\\"\\\"}\"\n}\n}","output":"str","x":981,"y":718,"wires":[["db448239.4065a"]]},{"id":"11f31c68.2504e4","type":"template","z":"36a15efd.e65432","name":"Set MQTT topic","field":"payload.mqtttopic","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"meteoalarm/{{payload.day}}data2JSON","output":"str","x":731,"y":618,"wires":[["cba777b8.2c1898"]]},{"id":"e023b6a2.270688","type":"template","z":"36a15efd.e65432","name":"Set MQTT topic","field":"payload.mqtttopic","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"meteoalarm/{{payload.day}}data1JSON","output":"str","x":731,"y":718,"wires":[["cba777b8.2c1898"]]},{"id":"fae59f6b.0874d","type":"comment","z":"36a15efd.e65432","name":"cleaning events if not used anymore","info":"","x":391,"y":717,"wires":[]},{"id":"694dd005.43e98","type":"comment","z":"36a15efd.e65432","name":"Parsing and stripping the big array","info":"","x":740,"y":140,"wires":[]},{"id":"ace6ce8e.c5bd8","type":"comment","z":"36a15efd.e65432","name":"Actual logic to create different payloads","info":"","x":230,"y":400,"wires":[]},{"id":"4c0ee102.942a2","type":"trigger-state","z":"36a15efd.e65432","name":"Trigger when HASS starts","server":"7d2f835e.e2f72c","entityid":"input_boolean.hass_started","debugenabled":false,"constraints":[{"id":"t6gql6qbmwq","targetType":"this_entity","targetValue":"","propertyType":"previous_state","propertyValue":"old_state.state","comparatorType":"is","comparatorValueDatatype":"bool","comparatorValue":"false"},{"id":"7gq42boq8op","targetType":"this_entity","targetValue":"","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":"is","comparatorValueDatatype":"bool","comparatorValue":"true"}],"constraintsmustmatch":"all","outputs":2,"customoutputs":[],"x":130,"y":40,"wires":[["aa1c4018.39b15"],[]]},{"id":"fb462f0.61786d","type":"function","z":"36a15efd.e65432","name":"Remove English text / stripe to 220 char","func":"var shortdescription = msg.payload.description.substring(0, 220) + \"...\";\nvar description_vl = msg.payload.description.split('vlaams:')[1];\nvar shortdescription_vl = description_vl.substring(0, 220);\nif (typeof description_vl != 'undefined')\n {\n msg.payload.description=shortdescription_vl.replace(/(\\r\\n|\\n|\\r)/gm,\" \");\n }\nelse\n {\n msg.payload.description=shortdescription.replace(/(\\r\\n|\\n|\\r)/gm,\" \");\n }\n\nreturn [ msg ];","outputs":1,"noerr":0,"x":800,"y":380,"wires":[["3cf02b43.79c334"]]},{"id":"7d2f835e.e2f72c","type":"server","z":"","name":"Home Assistant","url":"https://YOURHASSIP:8123","pass":"YOURKEY"}]
And it looks like this:
You will need the following nodes:
- HTTP Request
- Split
- Filter
- Template
- Switch
- Function
The top part of the flow:
- Requests every 30 minutes the data on to the webserver (or during HASS startup)
- Splits the received JSON multiple times untill we get 3 messages (today, tomorrow, time published)
The middle part:
- Does the actual logic.
- Splits the different messages for the day
- Sets the correct MQTT topic
- Parses the data in the correct format
- Publishes as MQTT
The bottom part:
- cleans the sensors if there were multiple alerts but is now back to none.
What you need to change:
As always, make sure the flow has your HASSIP and KEY at the bottom of the flow before importing.
You need to change the node “Meteo Alarm Data Belgium/Brabant” and change the URL to correspond to your webserver and to your country and region.
You can find your country region by going to the meteoalarm.eu website and search for your region.
In the end you will get something like: https://www.meteoalarm.eu/nl_NL/0/0/BE004.html where
BE is the country code
004 is the region code (ALWAYS only the 3-digit code)
You will also need to change “Remove English text / stripe to 220 char” node if you want only the data in your language (or only in English) Now it has been setup to delete the English text if “Vlaams” is detected.
You will probably have to wait until one real alarm comes in, so that you know what you need to filter on. Do not change anything else, since it will break the flow.
We need to remove hard returns and we need to limit the message to 250 chars total, otherwise the publish of the message to MQTT will fail.
You are done. Deploy and click on the input node.
Some extra remarks:
I have split up the real “description” of the alert with the rest of the data. So every alert has 2 MQTT messages. This has been done to make the description as long as possible. A complete message cannot exceed 255 charachters. If I would have put everything in one message, the description would have been very short. Now I cut the message at 220 characters (after splitting the English text).
The fix forwardslash is needed since there appears to be a bug in the template node that spawns weird characters instead of a /. This node fixes that.
The publish data is in BST. I did not find a way to fix that to e.g. CET. If somebody can, please let me know.
You can integrate in lovelace as follows. This will only display the active alerts (with their corresponding color) and hide the other entities if they are empty. (Empty is a dot (.), since lovelace’s filter does not accept a space as something to filter on.
- type: custom:vertical-stack-in-card
title: Weerwaarschuwing
cards:
- type: entities
entities:
- entity: sensor.meteoalarm_today_alarm1
name: "Vandaag"
- type: conditional
conditions:
- entity: sensor.meteoalarm_today_alarm2
state_not: "."
card:
type: entities
entities:
- sensor.meteoalarm_today_alarm2
- type: conditional
conditions:
- entity: sensor.meteoalarm_today_alarm3
state_not: "."
card:
type: entities
entities:
- sensor.meteoalarm_today_alarm3
- type: entities
entities:
- entity: sensor.meteoalarm_tomorrow_alarm1
name: "Morgen"
- type: conditional
conditions:
- entity: sensor.meteoalarm_tomorrow_alarm2
state_not: "."
card:
type: entities
entities:
- sensor.meteoalarm_tomorrow_alarm2
- type: conditional
conditions:
- entity: sensor.meteoalarm_tomorrow_alarm3
state_not: "."
card:
type: entities
entities:
- sensor.meteoalarm_tomorrow_alarm3
- type: entities
entities:
- entity: sensor.meteoalarm_publishtime
icon: "mdi:update"
To conclude, I hope you like it and that it can be of use for some of you. But if you think this can be done better or can be enhanced, please let me know. As said, my first project in Nodered 2 weeks after I installed it.
Greetz.