UK MET Office Severe Weather Warnings

type: custom:stack-in-card
cards:
  - type: markdown
    content: >
      {% if state_attr('sensor.weather_alerts','entries') != 0 %}
        {% for item in state_attr('sensor.weather_alerts','entries') %}
          {% for type, icon in
            [
              ('extreme heat', 'weather-sunny-alert'),
              ('fog', 'weather-fog'),
              ('ice', 'car-traction-control'),
              ('lightning', 'weather-lightning'),
              ('rain', 'weather-pouring'),
              ('rain, wind', 'weather-pouring'),
              ('snow', 'weather-snowy-heavy'),
              ('snow, ice', 'weather-snowy-heavy'),
              ('thunderstorm', 'weather-lightning'),
              ('thunderstorms', 'weather-lightning-rainy'),
              ('wind', 'weather-windy')
              ('flood', 'flooding')
            ]
            if type == item.summary | regex_findall_index('.*warning of (.*) affecting Somerset.*', ignorecase=True) %}
            {% set color = item.summary.split(' ')[0] %}
            {% set summary = item.summary | regex_findall_index('(.*) affecting South West England: (.*) valid from (.*) to (.*)', ignorecase=True) %}
            {% set link = item.link %}
            {% set time_utc_from = summary[2][0:2] ~':'~ summary[2][2:4] %}
            {% set time_utc_to = summary[3][0:2] ~':'~ summary[3][2:4] %}
            {% set date_from = summary[2][5:8] +'-'+ summary[2][9:11] +'-'+ summary[2][12:] %}
            {% set date_to = summary[3][5:8] +'-'+ summary[3][9:11] +'-'+ summary[3][12:] %}
            {% set time_local_from = ((now().date() ~ ' ' ~ time_utc_from ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}  
            {% set time_local_to = ((now().date() ~ ' ' ~ time_utc_to ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}
      |  |  |

      | -: | -- |

      | <font color = {%- if 'Yellow' == color %}'gold' {%- elif 'Amber' ==
      color %}'darkorange' {%- else %}'firebrick' {%- endif %}> <ha-icon icon={{
      "'mdi:" + icon + "'" }}> </ha-icon></font> | <a href='{{ link }}'>**{{
      summary[0] }}** </a> |

      || from **{{ time_local_from }}** to **{{ time_local_to }}** on **{{
      date_from }}** |
          {% endfor %}
      <br>
        {% endfor %}
      {% else %} No warnings at present {% endif %}

Could you help me with the correct format for Somerset & south west?

I’m wondering if I’m adding my sensors wrong?

When you have more than 1 sensor is it correct to use sensor again or should they all be under a single class?

sensor: 
######## Frost Sensor:
  - platform: template 
    sensors:
      24hrlowtemp:
        value_template: >
          {% set start = now().replace(hour=0,minute=0,second=0, microsecond=0) %}
          {% set end = (start + timedelta(days=1)) %}
          {% set start = start.strftime("%Y-%m-%dT%H:%M:%S+00:00") %}
          {% set end = end.strftime("%Y-%m-%dT%H:%M:%S+00:00") %}
          {{ state_attr('weather.forecast_home', 'forecast') | selectattr('datetime', '>=', start) | selectattr('datetime','<=', end) | map(attribute='templow') | list | max }}
### Weather - Tomo Rain Probability 
template:
- sensor:
    name: rain tomo
    state: >
      {{ state_attr('weather.home', 'forecast')[1].precipitation_probability }}

### Weather - Alerts System
sensor: #-----------------------------------------------------------------------
- platform: feedparser
  name: "Weather Alerts"
  feed_url: 'https://www.metoffice.gov.uk/public/data/PWSCache/WarningsRSS/Region/sw'
  date_format: '%a, %b %d %I:%M %p'
  inclusions:
    - summary
    - link

Keep the together like this and they need the same indentation:

sensor: 
######## Frost Sensor:
- platform: template 
  sensors:
    24hrlowtemp:
      value_template: >
        {% set start = now().replace(hour=0,minute=0,second=0, microsecond=0) %}
        {% set end = (start + timedelta(days=1)) %}
        {% set start = start.strftime("%Y-%m-%dT%H:%M:%S+00:00") %}
        {% set end = end.strftime("%Y-%m-%dT%H:%M:%S+00:00") %}
        {{ state_attr('weather.forecast_home', 'forecast') | selectattr('datetime', '>=', start) | 

### Weather - Alerts System
- platform: feedparser
  name: "Weather Alerts"
  feed_url: 'https://www.metoffice.gov.uk/public/data/PWSCache/WarningsRSS/Region/sw'
  date_format: '%a, %b %d %I:%M %p'
  inclusions:
    - summary
    - link

selectattr('datetime','<=', end) | map(attribute='templow') | list | max }}
### Weather - Tomo Rain Probability 
template:
- sensor:
    name: rain tomo
    state: >
      {{ state_attr('weather.home', 'forecast')[1].precipitation_probability }}

Thanks have it working now & so where you have additional sensors & templates how are you adding those or are you using this met office as a separate met.yaml?

Sure. Try this:

type: custom:stack-in-card
cards:
- type: markdown
  content: >
    {% if state_attr('sensor.weather_alerts','entries') != [] %}
      {% for item in state_attr('sensor.weather_alerts','entries') %}
        {% for type, icon in
          [
            ('extreme heat', 'weather-sunny-alert'),
            ('fog', 'weather-fog'),
            ('ice', 'car-traction-control'),
            ('lightning', 'weather-lightning'),
            ('rain', 'weather-pouring'),
            ('rain, wind', 'weather-pouring'),
            ('snow', 'weather-snowy-heavy'),
            ('snow, ice', 'weather-snowy-heavy'),
            ('thunderstorm', 'weather-lightning'),
            ('thunderstorms', 'weather-lightning-rainy'),
            ('wind', 'weather-windy')
          ]
          if type == item.summary | regex_findall_index('.*warning of (.*) affecting.*', ignorecase=True) and item.summary | regex_findall('Somerset', ignorecase=True) %}
          {% set color = item.summary.split(' ')[0] %}
          {% set summary = item.summary | regex_findall_index('(.*) affecting South West England: (.*) valid from (.*) to (.*)', ignorecase=True) %}
          {% set link = item.link %}
          {% set time_utc_from = summary[2][0:2] ~':'~ summary[2][2:4] %}
          {% set time_utc_to = summary[3][0:2] ~':'~ summary[3][2:4] %}
          {% set date_from = summary[2][5:8] +'-'+ summary[2][9:11] +'-'+ summary[2][12:] %}
          {% set date_to = summary[3][5:8] +'-'+ summary[3][9:11] +'-'+ summary[3][12:] %}
          {% set time_local_from = ((now().date() ~ ' ' ~ time_utc_from ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}  
          {% set time_local_to = ((now().date() ~ ' ' ~ time_utc_to ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}
    |  |  |

    | -: | -- |

    | <font color = {%- if 'Yellow' == color %}'gold' {%- elif 'Amber' == color %}'darkorange' {%- else %}'firebrick' {%- endif %}>
    <ha-icon icon={{ "'mdi:" + icon + "'" }}>
    </ha-icon></font>
    | <a href='{{ link }}'>**{{ summary[0] }}** </a>
    |

    | from: | **{{ time_local_from }}**, {{ date_from }} |

    | to: | **{{ time_local_to }}**, {{ date_to }} |
        {% endfor %}
    <br>
      {% endfor %}
    {% else %} No warnings at present
    {% endif %}

Screenshot 2023-11-30 at 13.43.09

1 Like

Amazing thanks so much.
I need to set up something to keep the syntax when copying & pasting on mac.

I have them separated out with the use of !include which means everything is easier to find and I don’t mess up things I want left alone.

I use packages so, rather than keeping “sensors” together for all sensors, I keep “Met office” together in a single file which has all the sensors, templates, automations etc needed.

This is literally my “Met Office Weather Alerts” package (single file):

met_office_alerts.yaml

sensor: #-----------------------------------------------------------------------

- platform: feedparser
  name: "Weather Alerts"
  feed_url: 'http://metoffice.gov.uk/public/data/PWSCache/WarningsRSS/Region/sw'
  date_format: '%a, %b %d %I:%M %p'
  inclusions:
    - summary
    - link


template: #---------------------------------------------------------------------

- sensor:
    - name: "Weather Alerts Oxfordshire" # used for conditional card as sensor.weather_alerts also shows non-Oxfordshire alerts
      state: >
        {{ state_attr('sensor.weather_alerts','entries')
          | map(attribute='summary')
          | select('search', 'Oxfordshire') 
          | list
          | count
        }}


automation: #-------------------------------------------------------------------

- alias: "Weather: Notify weather warnings"
  id: weather_notify_warnings
  trigger:
    - platform: state
      entity_id: sensor.weather_alerts_oxfordshire
  variables:
    message: |
      {% for item in state_attr('sensor.weather_alerts','entries') %}
        {% for type in [
          ('extreme heat'),('fog'),('ice'),('lightning'),('rain'),('rain, wind'),('snow'),('snow, ice'),('thunderstorm'),('thunderstorms'),('wind')]
          if type == item.summary | regex_findall_index('.*warning of (.*) affecting.*', ignorecase=True) and item.summary | regex_findall('Oxfordshire', ignorecase=True) %}
          {% set summary = item.summary | regex_findall_index('(.*) of (.*) affecting .* valid from (.*) to (.*)', ignorecase=True) %}
          {% set time_utc_from = summary[2][0:2] ~':'~ summary[2][2:4] %}
          {% set time_utc_to = summary[3][0:2] ~':'~ summary[3][2:4] %}
          {% set date_from = summary[2][5:8] +'-'+ summary[2][9:11] +'-'+ summary[2][12:] %}
          {% set date_to = summary[3][5:8] +'-'+ summary[3][9:11] +'-'+ summary[3][12:] %}
          {% set time_local_from = ((now().date() ~ ' ' ~ time_utc_from ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}  
          {% set time_local_to = ((now().date() ~ ' ' ~ time_utc_to ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}
      {{ summary[0] }}
      {{ summary[1] }}
      {{ time_local_from }}➜{{ time_local_to }}
      {{ date_from }}
        {% endfor %}
      {% endfor %}
  condition:
    - "{{ trigger.to_state.state not in ['unknown', 'unavailable','0'] }}"
    - "{{ trigger.from_state.state not in ['unknown', 'unavailable','0'] }}"
  action:
    - service: notify.notify
      data:
        title: "Met Office"
        message: "{{ message }}"
        data:
          tag: weather_alert  # will replace earlier alerts with this tag
1 Like

Also on Mac. I use BBedit for all my yaml editing.

Thanks, I’ve updated my code for the dates from/to section to match yours, as it looks a bit clearer than what I was using :+1:

2 Likes

Just had a last minute met office warning of ice go off at around 10pm on my phone from met office app. Took about 10mins to show in home-assistant but no notification from home-assistant from the automation which did work a few days ago…

Does it only look per ‘day’? or does it ping out as they come in?

Looks like the somerset sensor isn’t working as no entity with this name…

Any ideas on what I’ve missed? Thanks

Ok all fixed. Was some syntax errors but mainly I need to start using separate.yaml files to keep it all working.

Thanks guys for making this its super cool!

Glad you got it sorted!

you can set the frequency (it’s optional but not sure what the default is):

sensor:
  platform: feedparser
  scan_interval:
    hours: 1

Although I’m searching the region ‘sw’ I’m also checking the summary for ‘Devon’ - in the same way as posted above for ‘Somerset’

if type == item.summary | regex_findall_index('.*warning of (.*) affecting.*', ignorecase=True) and item.summary | regex_findall('Devon' ignorecase=True) %}

As the current Ice warning for the region sw only applies to Gloucestershire, Swindon and Wiltshire, I was expecting to see the ‘No warnings at present’ message in my alerts popup, as per the code:

{% else %} No warnings at present

However nothing is rendering in my popup at all. I’ve used the same spacing and indentation as per what has been posted above, as far as I can tell. I’ve tried swapping ‘Devon’ for ‘Gloucestershire’, and reloaded my templates, but I’m still not getting the current warning displaying in my popup. Is anyone able to check this with their code and see if the same happens? If not, there must be something not quite right with my code here:

Code
- type: markdown
  content: >
    {% if state_attr('sensor.weather_alerts','entries') != [] %}
      {% for item in state_attr('sensor.weather_alerts','entries') %}
        {% for type, icon in
          [
            ('extreme heat', 'weather-sunny-alert'),
            ('fog', 'weather-fog'),
            ('ice', 'car-traction-control'),
            ('lightning', 'weather-lightning'),
            ('rain', 'weather-pouring'),
            ('rain, wind', 'weather-pouring'),
            ('snow', 'weather-snowy-heavy'),
            ('snow, ice', 'weather-snowy-heavy'),
            ('thunderstorm', 'weather-lightning'),
            ('thunderstorms', 'weather-lightning-rainy'),
            ('wind', 'weather-windy')
          ]
          if type == item.summary | regex_findall_index('.*warning of (.*) affecting.*', ignorecase=True) and item.summary | regex_findall('Devon' ignorecase=True) %}
          {% set color = item.summary.split(' ')[0] %}
          {% set summary = item.summary | regex_findall_index('(.*) affecting South West England: (.*) valid from (.*) to (.*)', ignorecase=True) %}
          {% set link = item.link %}
          {% set time_utc_from = summary[2][0:2] ~':'~ summary[2][2:4] %}
          {% set time_utc_to = summary[3][0:2] ~':'~ summary[3][2:4] %}
          {% set date_from = summary[2][5:8] +'-'+ summary[2][9:11] +'-'+ summary[2][12:] %}
          {% set date_to = summary[3][5:8] +'-'+ summary[3][9:11] +'-'+ summary[3][12:] %}
          {% set time_local_from = ((now().date() ~ ' ' ~ time_utc_from ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}  
          {% set time_local_to = ((now().date() ~ ' ' ~ time_utc_to ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}
    |  |  |

    | -: | -- |

    | <font color = {%- if 'Yellow' == color %}'gold' {%- elif 'Amber' == color %}'darkorange' {%- else %}'firebrick' {%- endif %}>
    <ha-icon icon={{ "'mdi:" + icon + "'" }}>
    </ha-icon></font>
    | <a href='{{ link }}'>**{{ summary[0] }}** </a>
    |

    | from: | **{{ time_local_from }}**, {{ date_from }} |

    | to: | **{{ time_local_to }}**, {{ date_to }} |
        {% endfor %}
    <br>
      {% endfor %}
    {% else %} No warnings at present
    {% endif %}

@Scoff Well spotted. It works when there are no weather alerts at all, but not when there are alerts, just not for your area. Here is the ‘fix’:

Create a new sensor that is specific to Devon:

template: #---------------------------------------------------------------------
  - sensor:
      - name: "Weather Alerts Devon"
        state: >
          {{ state_attr('sensor.weather_alerts','entries')
            | map(attribute='summary')
            | select('search', 'Devon') 
            | list
            | count
          }}

…and then change that line in the card to:

      content: >
        {% if states('sensor.weather_alerts_devon') != '0' %}

Sorry, I didn’t notice this as I use (my version of) sensor.weather_alerts_devon in a conditional card that hides the whole thing when there is no alert.

Please let me know that this works for you.

For anyone else that is using this code, here is the full package (for se/Oxon):

Code
sensor: #-----------------------------------------------------------------------
  - platform: feedparser
    name: "Weather Alerts"
    feed_url: 'http://metoffice.gov.uk/public/data/PWSCache/WarningsRSS/Region/se'
    scan_interval:
      hours: 1
    date_format: '%a, %b %d %I:%M %p'
    inclusions:
      - summary
      - link

template: #---------------------------------------------------------------------
  - sensor:
      - name: "Weather Alerts Oxfordshire"
        state: >
          {{ state_attr('sensor.weather_alerts','entries')
            | map(attribute='summary')
            | select('search', 'Oxfordshire') 
            | list
            | count
          }}

automation: #-------------------------------------------------------------------
  - alias: "Weather: Notify weather warnings"
    id: weather_notify_warnings
    trigger:
      - platform: state
        entity_id: sensor.weather_alerts_oxfordshire
    variables:
      message: |
        {% for item in state_attr('sensor.weather_alerts','entries') %}
          {% for type in [
            ('extreme heat'),('fog'),('ice'),('lightning'),('rain'),('rain, wind'),('snow'),('snow, ice'),('thunderstorm'),('thunderstorms'),('wind')]
            if type == item.summary | regex_findall_index('.*warning of (.*) affecting.*', ignorecase=True) and item.summary | regex_findall('Oxfordshire', ignorecase=True) %}
            {% set summary = item.summary | regex_findall_index('(.*) of (.*) affecting .* valid from (.*) to (.*)', ignorecase=True) %}
            {% set time_utc_from = summary[2][0:2] ~':'~ summary[2][2:4] %}
            {% set time_utc_to = summary[3][0:2] ~':'~ summary[3][2:4] %}
            {% set date_from = summary[2][5:8] +'-'+ summary[2][9:11] +'-'+ summary[2][12:] %}
            {% set date_to = summary[3][5:8] +'-'+ summary[3][9:11] +'-'+ summary[3][12:] %}
            {% set time_local_from = ((now().date() ~ ' ' ~ time_utc_from ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}  
            {% set time_local_to = ((now().date() ~ ' ' ~ time_utc_to ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}
        {{ summary[0] }}
        {{ summary[1] }}
        {{ time_local_from }}➜{{ time_local_to }}
        {{ date_from }}
          {% endfor %}
        {% endfor %}
    condition:
      - "{{ trigger.to_state.state not in ['unknown', 'unavailable','0'] }}"
      - "{{ trigger.from_state.state not in ['unknown', 'unavailable','0'] }}"
    action:
      - service: notify.notify
        data:
          title: "Met Office"
          message: "{{ message }}"
          data:
            tag: weather_alert  # will replace earlier alerts with this tag

…and the card:

type: markdown
content: >
  {% if states('sensor.weather_alerts_oxfordshire') != '0' %}
    {% for item in state_attr('sensor.weather_alerts','entries') %}
      {% for type, icon in
        [
          ('extreme heat', 'weather-sunny-alert'),
          ('fog', 'weather-fog'),
          ('ice', 'car-traction-control'),
          ('lightning', 'weather-lightning'),
          ('rain', 'weather-pouring'),
          ('rain, wind', 'weather-pouring'),
          ('snow', 'weather-snowy-heavy'),
          ('snow, ice', 'weather-snowy-heavy'),
          ('thunderstorm', 'weather-lightning'),
          ('thunderstorms', 'weather-lightning-rainy'),
          ('wind', 'weather-windy')
        ]
        if type == item.summary | regex_findall_index('.*warning of (.*) affecting.*', ignorecase=True) and item.summary | regex_findall('Oxfordshire', ignorecase=True) %}
        {% set color = item.summary.split(' ')[0] %}
        {% set summary = item.summary | regex_findall_index('(.*) affecting London & South East England: (.*) valid from (.*) to (.*)', ignorecase=True) %}
        {% set link = item.link %}
        {% set time_utc_from = summary[2][0:2] ~':'~ summary[2][2:4] %}
        {% set time_utc_to = summary[3][0:2] ~':'~ summary[3][2:4] %}
        {% set date_from = summary[2][5:8] +'-'+ summary[2][9:11] +'-'+ summary[2][12:] %}
        {% set date_to = summary[3][5:8] +'-'+ summary[3][9:11] +'-'+ summary[3][12:] %}
        {% set time_local_from = ((now().date() ~ ' ' ~ time_utc_from ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}  
        {% set time_local_to = ((now().date() ~ ' ' ~ time_utc_to ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}
  |  |  |

  | -: | -- |

  | <font color = {%- if 'Yellow' == color %}'gold' {%- elif 'Amber' == color %}'darkorange' {%- else %}'firebrick' {%- endif %}>
  <ha-icon icon={{ "'mdi:" + icon + "'" }}>
  </ha-icon></font>
  | <a href='{{ link }}'>**{{ summary[0] }}** </a>
  |

  | from: | **{{ time_local_from }}**, {{ date_from }} |

  | to: | **{{ time_local_to }}**, {{ date_to }} |
      {% endfor %}
  <br>
    {% endfor %}
  {% else %} No warnings at present
  {% endif %}

btw, how did you hide your code behind that drop-down arrow? Edit: worked it out - thanks!

1 Like

Ahh I see, thanks very much for that, i’ll get the additional devon specific sensor set up, and amend my card to reference that sensor accordingly. :+1:

This is great, I just had to modified automation a bit as it produces to many empty lines. Also added some emojis :wink:

- alias: "Weather: Notify weather warnings"
  id: weather_notify_warnings
  trigger:
    - platform: state
      entity_id: sensor.weather_alerts_oxfordshire
  variables:
    message: |
      {%- for item in state_attr('sensor.weather_alerts','entries') %}
        {%- for type in [
          ('extreme heat'),('fog'),('ice'),('lightning'),('rain'),('rain, wind'),('snow'),('snow, ice'),('thunderstorm'),('thunderstorms'),('wind')]
          if type == item.summary | regex_findall_index('.*warning of (.*) affecting.*', ignorecase=True) and item.summary | regex_findall('Oxfordshire', ignorecase=True) %}
          {%- set summary = item.summary | regex_findall_index('(.*) of (.*) affecting .* valid from (.*) to (.*)', ignorecase=True) %}
          {%- set time_utc_from = summary[2][0:2] ~':'~ summary[2][2:4] %}
          {%- set time_utc_to = summary[3][0:2] ~':'~ summary[3][2:4] %}
          {%- set date_from = summary[2][5:8] +'-'+ summary[2][9:11] +'-'+ summary[2][12:] %}
          {%- set date_to = summary[3][5:8] +'-'+ summary[3][9:11] +'-'+ summary[3][12:] %}
          {%- set time_local_from = ((now().date() ~ ' ' ~ time_utc_from ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}  
          {%- set time_local_to = ((now().date() ~ ' ' ~ time_utc_to ~ "+00:00") | as_datetime | as_local).strftime('%H:%M') %}
          <b>⚠️ {{ summary[0] }}</b>
          {{ summary[1] }}
          {{ time_local_from }} ➜ {{ time_local_to }}
          {%- if date_from == date_to %}
            {{ date_from }}
          {%- else %}
            {{ date_from }} ➜ {{ date_to }}
          {%- endif %}
        {%- endfor %}
      {%- endfor %}
  condition:
    - "{{ trigger.to_state.state not in ['unknown', 'unavailable','0'] }}"
    - "{{ trigger.from_state.state not in ['unknown', 'unavailable','0'] }}"
  action:
    - service: notify.notify
      data:
        title: "⛅ Met Office"
        message: "{{ message }}"
        data:
          tag: weather_alert  # will replace earlier alerts with this tag

Interesting - I don’t get any empty lines at all.

Maybe that’s Android issue. BTW empty lines are between each item (when you have at least 2 warnings) so they are initially not well visible but when you put the message part code into the dev tools template, you may see it @jchh

No, I haven’t had extra lines with 2 simultaneous warnings (at least I didn’t notice it), but will double check the next time I get 2 warnings.

Dev tools does not always display exactly the same as in the card.