MeteoAlarm info card

The MeteoAlarm integration provides weather alarms for many regions in Europe.
The integration provides a binary sensor with several attributes that give current information about many types of weather alarms for the specified region.

I created some extra template sensors and a frontend card that uses the MeteoAlarm integration to warn for any local weather alert in a specific region.
This setup is based on the standard Home Assistant possibilities with one exception: I am using the Card-mod plugin to set the background color of the Tile card depending on the alarm severity level.
The card combines a Tile card, a Conditional card, a Markdown card, an Entity filter card and an Entities card.

This is an example of an effective weather alarm:
HA_MeteoAlarm_current_EN_20240126-0900
It shows the current severity level (green, yellow, orange or red), the awareness type including specific icon, the description, the time and date from when until when the warning is valid and the time and day the warning is published.

When the alarm will be effective in the near future this is indicated as “Future alarm” with the details of the coming alarm:
HA_MeteoAlarm_future_EN_20240126-0734

When there is no current alarm (level Green) only the upper Tile card is shown in green like this:
HA_MeteoAlarm_no-alarm_EN_20240126-1112

It sometimes can take a while for the MeteoAlarm integration to revert to a safe state after the real alarm is already is expired. In those cases the alarm will be shown like this:
HA_MeteoAlarm_expired_EN_20240126-1100

From two days ago until two days after the current day the days are indicated with terms like “two days ago”, “yesterday”, tomorrow” etc., and for dates further away from the current day it is indicated with the real date.
It currently is set-up for the region Friesland in the Netherlands, in the English language.

This is the Yaml code:
Binary sensor:

binary_sensor:
  - platform: meteoalarm
    name: "MeteoAlarm Friesland"
    country: "netherlands"
    province: "Friesland"
    language: "en-GB"

Template sensors (modern format):

template:
  - sensor:
      # Meteoalarm Friesland
    - name: MeteoAlarm Friesland - Event
      unique_id: maf_event
      state: "{{ state_attr('binary_sensor.meteoalarm_friesland', 'event') }}"
      icon: mdi:shield-sun-outline
      availability: "{{ state_attr('binary_sensor.meteoalarm_friesland', 'event') not in ['unknown', 'unavailable'] }}"
    - name: MeteoAlarm Friesland - Type
      unique_id: maf_type
      state: >
        {% set mat = state_attr('binary_sensor.meteoalarm_friesland', 'awareness_type').split("; ")[0] %}
        {% if mat == "1" %}
          Wind
        {% elif mat == "2" %}
          Snow - Ice
        {% elif mat == "3" %}
          Thunderstorms
        {% elif mat == "4" %}
          Fog
        {% elif mat == "5" %}
          Extreme high temperature
        {% elif mat == "6" %}
          Extreme low temperature
        {% elif mat == "7" %}
          Coastal event
        {% elif mat == "8" %}
          Forestfire
        {% elif mat == "9" %}
          Avalanges
        {% elif mat == "10" %}
          Rain
        {% elif mat == "12" %}
          Flood
        {% elif mat == "13" %}
          Rain - Flood
        {% else %}
          Unknown
        {% endif %}
      icon: mdi:shield-sun-outline
      availability: "{{ state_attr('binary_sensor.meteoalarm_friesland', 'awareness_type') not in ['unknown', 'unavailable'] }}"
    - name: MeteoAlarm Friesland - Level
      unique_id: maf_level
      state: >
        {% set mal = state_attr('binary_sensor.meteoalarm_friesland', 'awareness_level').split("; ")[0] %}
        {% if mal == "1" %}
          Green
        {% elif mal == "2" %}
          Yellow
        {% elif mal == "3" %}
          Orange
        {% elif mal == "4" %}
          Red
        {% else %}
          Unknown
        {% endif %}
      icon: mdi:shield-sun-outline
      availability: "{{ state_attr('binary_sensor.meteoalarm_friesland', 'awareness_level') not in ['unknown', 'unavailable'] }}"
    - name: MeteoAlarm Friesland - Effective
      unique_id: maf_effective
      state: "{{ as_timestamp(state_attr('binary_sensor.meteoalarm_friesland', 'effective')) | timestamp_custom('%d %b %H:%M') }}"
      icon: mdi:clipboard-text-clock-outline
      availability: "{{ state_attr('binary_sensor.meteoalarm_friesland', 'effective') not in ['unknown', 'unavailable'] }}"
    - name: MeteoAlarm Friesland - Effective Day
      unique_id: maf_effectiveday
      state: >
        {% set ts_effective = as_timestamp(state_attr('binary_sensor.meteoalarm_friesland', 'effective')) %}
        {% set tstring = ts_effective | timestamp_custom('%Y-%m-%d %H:%M:%S') %}
        {% set effectivetime = ts_effective | timestamp_custom( 'at %H:%M') %}
        {% set tz = now().timestamp() | timestamp_custom('%z') %}
        {% set date = strptime(tstring+tz, '%Y-%m-%d %H:%M:%S%z') %}
        {% set cdate = now().replace(hour=0).replace(minute=0).replace(second=0).replace(microsecond=0) %}
        {% set change = (date - cdate).days %}
        {% if change == -2 %}
          two days ago {{ effectivetime }}
        {% elif change == -1 %}
          yesterday {{ effectivetime }}
        {% elif change == 0 %}
          today {{ effectivetime }}
        {% elif change == 1 %}
          tomorrow {{ effectivetime }}
        {% elif change == 2 %}
          in two days {{ effectivetime }}
        {% else %}
          {% set days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] %}
          {% set months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] %}
          {{ days[date.weekday()] }} {{ date.day }} {{ months[date.month-1] }} {{ effectivetime }}
        {% endif %}
      icon: mdi:clipboard-text-clock-outline
      availability: "{{ state_attr('binary_sensor.meteoalarm_friesland', 'effective') not in ['unknown', 'unavailable'] }}"
    - name: MeteoAlarm Friesland - Onset
      unique_id: maf_onset
      state: "{{ as_timestamp(state_attr('binary_sensor.meteoalarm_friesland', 'onset')) | timestamp_custom('%d %b %H:%M') }}"
      icon: mdi:clipboard-text-clock-outline
      availability: "{{ state_attr('binary_sensor.meteoalarm_friesland', 'onset') not in ['unknown', 'unavailable'] }}"
    - name: MeteoAlarm Friesland - Onset Day
      unique_id: maf_onsetday
      state: >
        {% set ts_onset = as_timestamp(state_attr('binary_sensor.meteoalarm_friesland', 'onset')) %}
        {% set tstring = ts_onset | timestamp_custom('%Y-%m-%d %H:%M:%S') %}
        {% set onsettime = ts_onset | timestamp_custom( 'at %H:%M') %}
        {% set tz = now().timestamp() | timestamp_custom('%z') %}
        {% set date = strptime(tstring+tz, '%Y-%m-%d %H:%M:%S%z') %}
        {% set cdate = now().replace(hour=0).replace(minute=0).replace(second=0).replace(microsecond=0) %}
        {% set change = (date - cdate).days %}
        {% if change == -2 %}
          two days ago {{ onsettime }}
        {% elif change == -1 %}
          yesterday {{ onsettime }}
        {% elif change == 0 %}
          today {{ onsettime }}
        {% elif change == 1 %}
          tomorrow {{ onsettime }}
        {% elif change == 2 %}
          in two days {{ onsettime }}
        {% else %}
          {% set days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] %}
          {% set months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] %}
          {{ days[date.weekday()] }} {{ date.day }} {{ months[date.month-1] }} {{ onsettime }}
        {% endif %}
      icon: mdi:clipboard-text-clock-outline
      availability: "{{ state_attr('binary_sensor.meteoalarm_friesland', 'onset') not in ['unknown', 'unavailable'] }}"
    - name: MeteoAlarm Friesland - Expires
      unique_id: maf_expires
      state: "{{ as_timestamp(state_attr('binary_sensor.meteoalarm_friesland', 'expires')) | timestamp_custom('%d %b %H:%M') }}"
      icon: mdi:clipboard-text-clock-outline
      availability: "{{ state_attr('binary_sensor.meteoalarm_friesland', 'expires') not in ['unknown', 'unavailable'] }}"
    - name: MeteoAlarm Friesland - Expires Day
      unique_id: maf_expiresday
      state: >
        {% set ts_expires = as_timestamp(state_attr('binary_sensor.meteoalarm_friesland', 'expires')) %}
        {% set tstring = ts_expires | timestamp_custom('%Y-%m-%d %H:%M:%S') %}
        {% set expirestime = ts_expires | timestamp_custom( 'at %H:%M') %}
        {% set tz = now().timestamp() | timestamp_custom('%z') %}
        {% set date = strptime(tstring+tz, '%Y-%m-%d %H:%M:%S%z') %}
        {% set cdate = now().replace(hour=0).replace(minute=0).replace(second=0).replace(microsecond=0) %}
        {% set change = (date - cdate).days %}
        {% if change == -2 %}
          two days ago {{ expirestime }}
        {% elif change == -1 %}
          yesterday {{ expirestime }}
        {% elif change == 0 %}
          today {{ expirestime }}
        {% elif change == 1 %}
          tomorrow {{ expirestime }}
        {% elif change == 2 %}
          in two days {{ expirestime }}
        {% else %}
          {% set days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] %}
          {% set months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] %}
          {{ days[date.weekday()] }} {{ date.day }} {{ months[date.month-1] }} {{ expirestime }}
        {% endif %}
      icon: mdi:clipboard-text-clock-outline
      availability: "{{ state_attr('binary_sensor.meteoalarm_friesland', 'expires') not in ['unknown', 'unavailable'] }}"
    - name: MeteoAlarm Friesland - Current
      unique_id: maf_current
      state: >
        {% set bma = states( 'binary_sensor.meteoalarm_friesland' ) %}
        {% if bma == 'off' %}
          No alarm
        {% else %}
          {% set ts_onset = as_timestamp(state_attr('binary_sensor.meteoalarm_friesland', 'onset')) %}
          {% set ts_expires = as_timestamp(state_attr('binary_sensor.meteoalarm_friesland', 'expires')) %}
          {% set tz = now().timestamp() %}
          {% if tz < ts_onset %}
            Future: {{ states( 'sensor.meteoalarm_friesland_level' ) }} alarm for {{ states( 'sensor.meteoalarm_friesland_type' ) }}
          {% elif tz > ts_onset and tz < ts_expires %}
            {{ states( 'sensor.meteoalarm_friesland_level' ) }} alarm: {{ states( 'sensor.meteoalarm_friesland_type' ) }}
          {% else %}
            Expired {{ states( 'sensor.meteoalarm_friesland_level' ) }} alarm for {{ states( 'sensor.meteoalarm_friesland_type' ) }}
          {% endif %}
        {% endif %}
      icon: >
        {% set bma = states( 'binary_sensor.meteoalarm_friesland' ) %}
        {% if bma == 'off' %}
          mdi:shield-sun-outline
        {% else %}
          {% set mat = state_attr('binary_sensor.meteoalarm_friesland', 'awareness_type').split("; ")[0] %}
          {% if mat == "1" %}
            mdi:weather-windy
          {% elif mat == "2" %}
            mdi:weather-snowy-heavy
          {% elif mat == "3" %}
            mdi:weather-lightning
          {% elif mat == "4" %}
            mdi:weather-fog
          {% elif mat == "5" %}
            mdi:sun-thermometer-outline
          {% elif mat == "6" %}
            mdi:snowflake-thermometer
          {% elif mat == "7" %}
            mdi:shore
          {% elif mat == "8" %}
            mdi:pine-tree-fire
          {% elif mat == "9" %}
            mdi:landslide
          {% elif mat == "10" %}
            mdi:weather-pouring
          {% elif mat == "12" %}
            mdi:home-flood
          {% elif mat == "13" %}
            mdi:waves-arrow-up
          {% else %}
            mdi:shield-sun-outline
          {% endif %}
        {% endif %}
      availability: "{{ states('binary_sensor.meteoalarm_friesland') not in ['unknown', 'unavailable'] }}"

Card:

type: vertical-stack
cards:
  - type: tile
    entity: sensor.meteoalarm_friesland_current
    show_entity_picture: false
    vertical: false
    hide_state: false
    name: MeteoAlarm Friesland
    card_mod:
      style: |
        ha-card {
          background-color:
            {%- set bma = states( 'binary_sensor.meteoalarm_friesland' ) %}
            {%- if bma == 'off' %}#90ee90
            {%- else %}
              {%- set mal = states( 'sensor.meteoalarm_friesland_level' ) %}
              {%- set mac = states( 'sensor.meteoalarm_friesland_current' ) %}
              {%- if mal == 'Green' %}#90ee90
              {%- elif 'Future' in mac %}#90ee90
              {%- elif mal == 'Yellow' %}#ffff00
              {%- elif mal == 'Orange' %}#ffa500
              {%- elif mal == 'Red' %}#ff3300
              {%- else %}#ffaec9
              {%- endif %}
            {%- endif %}
        }
  - type: conditional
    conditions:
      - condition: state
        entity: binary_sensor.meteoalarm_friesland
        state: 'on'
    card:
      type: markdown
      content: >
        **{{ state_attr('binary_sensor.meteoalarm_friesland', 'description') |
        trim }}** {% if 'Future' in states(
        'sensor.meteoalarm_friesland_current' ) %}
          **Starts {{states( 'sensor.meteoalarm_friesland_onset_day' ) }}** {% else %}
          **Ends {{states( 'sensor.meteoalarm_friesland_expires_day' ) }}**
        {% endif %}
  - type: entity-filter
    show_empty: false
    entities:
      - entity: sensor.meteoalarm_friesland_onset_day
        name: 'Start:'
      - entity: sensor.meteoalarm_friesland_expires_day
        name: 'End:'
      - entity: sensor.meteoalarm_friesland_effective_day
        name: 'Published:'
    state_filter:
      - operator: '!='
        value: unknown
    card:
      type: entities

If you want to set it up for your own local region you have to modify these entries in the Yaml code:

binary_sensor: name, country, province, language (ensure to use the correct country and province (region) names, see MeteoAlarm integration)

template_sensors: names, unique_ids, name of the binary_sensor and the template sensors

card: the names of the binary_sensor and the template sensors

If you want to have more regions shown in the frontend you can duplicate these sensors and card. Just ensure to create unique ids and names.

If you want to translate the used terms to another language you have to modify these entries in the Yaml code:

binary_sensor: language

template sensors: the terms for the weather types (Wind, Snow – Ice etc.), the terms for the levels (Green, Yellow etc.) , the term “at” for the time indications (3x), the terms for the days (two days ago, yesterday etc. 3x) the names of the weekdays and months (3x), the terms “No alarm”, Future:”, “Expired”, “alarm for”.

card: Green, Future, Yellow, Orange, Red, Starts, Ends, Start, End, Published

Enjoy!

If anyone has some tips for improvements of this set-up then please let me know.

6 Likes

@thusassistint

Hi, thank you very much for sharing your code. I works perfectly. I just implemented it for Lower Austria.
And as a beginner I really appreciate your detailed description.
Simply perfect.

Thanks

Perhaps an idea … it’s difficult to read the white text on the green background on my mobile. What about implementing an easy way to change the color of the text? Or could you please share a link of an easy how to change text and background color in a card?

Thanks and br,

check the card-mod thread, first post, link at the bottom and select the card you need to change.

its a generic thing you want to do, nothing special related to MeteoAlarm, so a good thing to check out

btw, if you’d want to translate the time and dates to your local language, I suggest you install custom_template Easy_time (find in on HACS) , set your default language in it and use things like:

      {% from 'easy_time.jinja' import weekday, month %}
      {% set meteo = 'binary_sensor.meteoalarm_brabant' %}

      {% set van = state_attr(meteo,'effective')|as_datetime|as_local %}
      {% set tot = state_attr(meteo,'expires')|as_datetime|as_local %}
      {% set gepubliceerd = state_attr(meteo,'onset')|as_datetime|as_local %}

      <b>Geldig:</b>

      <i>van: </i>{{weekday(van)}} {{van.day}} {{month(van)}} {{van.strftime('%H:%M')}}
      <i>tot: </i> {{weekday(tot)}} {{tot.day}} {{month(tot)}} {{tot.strftime('%H:%M')}}

      <b>Gepubliceerd:</b> {{weekday(gepubliceerd) ~' '~gepubliceerd.day~' '~month(gepubliceerd)~' om '~gepubliceerd.strftime('%H:%M') }}

Aware I use Onset in a wrong way, but that is besides the templating suggestion :wink:

1 Like

Hi Marius,
Thanks for your immediate response. Highly appreciate the hint. As you said it’s a good starting point for a beginner.
Anyhow it’s challenging for a beginner because you have millions of puzzles and it’s almost impossible to get it to an picture.
Perhaps you can help me with another issue. Having MeteoAlarm working the next step is getting notified if there is an alarm.
My knowledge ends with I get an notification if there is any alarm. It would be great to get which alarm it is at what severity level.

Thanks

added all your code but a get the error " ‘None’ has no attribute ‘split’". any ideas why?

This happens because there currently is no alarm for the region that you defined.
The attribute split is used in three locations in the template, like for instance:


{% set mat = state_attr('binary_sensor.meteoalarm_friesland', 'awareness_type').split("; ")[0] %}

When there is no alarm for the specified region the state of the binary_sensor as given by the MeteoAlarm integration is “off”, and the attribute awareness_type does not exist, hence the error message.
Personally I just ignore these logs, but you might be able to filter these kind of errors from the log using the Logbook Exclude option if you like.

Hi, I’m new to templating and YAML, and I’m having trouble with entity: sensor.meteoalarm_friesland_current on the Card part. I followed the steps to add the binary sensor and template to my configuration.yaml file and translated everything, but I can’t find the entity anywhere, where does it come from? Do I need an actual sensor, is it a helper, how do I create it? Thank you very much! :grinning:

dont ignore, just fix the template. it’s rather easy.

you can fix it by testing whether the attribute exists, or, somewhat easier, by checking if the binary_sensor is ‘on’.

in pseudo code

if entity exists, and has attribute, then split the string, else show a default string

or, in true yaml

best

{% if has_value('binary_sensor.meteoalarm_brabant') and
state_attr('binary_sensor.meteoalarm_brabant','headline') is not none %}
{{state_attr('binary_sensor.meteoalarm_brabant','headline').split(' - ')[0]}}
{% else %} Geen Meteoalarm
{% endif %}

easier:

{% if is_state('binary_sensor.meteoalarm_brabant','on')  %}
  {{state_attr('binary_sensor.meteoalarm_brabant','headline').split(' - ')[0]}}
{% else %} Geen Meteoalarm
{% endif %}

Personally I find the first option best, and safest (there could be the incidental hiccup that the binary would be ‘on’ but didn’t have the attribute…)

1 Like

That is one of the template sensors as defined in the Template section.
The names of these sensors is defined by Home Assistant based on the name as specified in the templates.
In the example the template name is:

    - name: MeteoAlarm Friesland - Current

Home Assistance translates this into:

sensor.meteoalarm_friesland_current

I think that all spaces are replaced by underscores, all letters are changed to lower case and all dashes are omitted.
So you have to check what has been changed during your translations.

To check which sensors are defined in your case you can go to Developer tools → STATES and type some text in the Entity field. This will show a list of all entities containing this text.
For the shown example typing “meteoalarm” or “friesland” will show all entities related to the shown MeteoAlarm InfoCard setup.
Does that make sense?

1 Like

Thanks, I will look into this.

1 Like

Hi, thanks for the reply and explanation, I had no idea how to get those sensors to work, thanks so much, I just changed them and it works great, thanks so much!!

I have a question about the meteoalarm integration to get that working before I start adding the card.

On the map in the meteoalarm website there is yellow warning for the region I specified (level 2), yet the binary sensor is off. How can I debug it?
So the name of the region is found on the meteoalarm website?

As is stated on the MeteoAlarm Integration web page, it is crucial to write the country name exactly as it appears in the MeteoAlarm feed. And the same counts for the region or province.

Yes, its not easy, but you can find the names of all the supported regions on the MeteoAlarm website.
Go to the Redistribution Hub, and download the Geocodes file, which is in JSON format.
In there you can find all possible countries with their regions.
Its a large file, but it is text based, so is searchable.
For instance, this is what is shown for the province Friesland in the Netherlands, when the file is opened in Notepad++ with the JSON Viewer plug-in:

MA_JSON_NL

I found a better way to get the correct MeteoAlarm region code names: the MeteoAlarm EMMA_ID Region explorer tool.
You can even search an arbitrary address, and the applicable region Name is shown:

1 Like

Gonna try this, thanks!

I tried it, for Croatia i added country “Croatia” and province “Kvarner and Kvarneric region” and it has a yellow alarm currently, while the integration says “safe”.

Doesn’t work properly.

any errors in the log? asking because your country name should be in lowercases, as explained in the docs MeteoAlarm - Home Assistant

not sure if you tried long enough :wink: those warnings are not always in sync at all, and can take some time updating from the resource

Yes, I did test it, and you are right: the Kvarner region appears to be non-functional in the MeteoAlarm Integration like this.
When as a test I changed the Name to “Velebit channel region” it does work for that region, so it looks like something is wrong with the Kvarner naming.
However, I now found a much better way to define the regions: it appears that you can also use the EMMA_ID for the name :slight_smile:
So in your case if you change the Name into “HR802” it should work:

binary_sensor:
  - platform: meteoalarm
    name: "MeteoAlarm Kvarner"
    country: "croatia"
    province: "HR802"

And one more thing: when you change something to the binary_sensor you have to restart Home Assistant to activate the changed settings.

1 Like

maybe that is the main point here, will check that too

I did create a test config for marksev1 with

  - platform: meteoalarm
    name: Meteoalarm Kroatië
    country: croatia
    language: nl-NL
    province: Kvarner and Kvarneric region

but it still is off, and showing no alert at all
btw, I also tried the croatian version with the connecting ‘I’, also without succes. (it was displayed like that in the lookup tool)

but… changing to the HR802 province config results in an error log:

meteoalarm: Error on device update!
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 737, in _async_add_entity
    await entity.async_device_update(warning=False)
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1320, in async_device_update
    await hass.async_add_executor_job(self.update)
  File "/usr/local/lib/python3.13/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/src/homeassistant/homeassistant/components/meteoalarm/binary_sensor.py", line 84, in update
    expiration_date = dt_util.parse_datetime(alert["expires"])
                                             ~~~~~^^^^^^^^^^^
KeyError: 'expires'