UK MET Office Severe Weather Warnings

The card works perfectly fine, it is just a notification on the mobile phone (at least Android)

You can always get rid of extra lines, just use >- instead of |
If you want to force a new line when you do that, you need to have 2 returns then.

1 Like

got it - I don’t have an Android phone.

If anyone would like to easily use warnings data in any card I suggest to add attributes data to your region template sensor like below:

- sensor:
  - name: "Weather Alerts Oxfordshire"
    state: >
      {{ state_attr('sensor.weather_alerts','entries')
        | map(attribute='summary')
        | select('search', 'Manchester') 
        | list
        | count
      }}
    attributes:
      warnings: >-
        {%- set data = namespace(warnings=[]) %}
        {%- 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 summary = item.summary | regex_findall_index('(.*) of (.*) affecting .* valid from (.*) to (.*)', ignorecase=True) %}
          {%- set color = item.summary.split(' ')[0] %}
          {%- 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') %}

          {%- set data.warnings = data.warnings + [
            {
              "summary": summary[0],
              "type": type,
              "color": color,
              "time_utc_from": time_utc_from,
              "time_utc_to": time_utc_to,
              "time_local_from": time_local_from,
              "time_local_to": time_local_to,
              "date_from": date_from,
              "date_to": date_to,
              "url": item.link,
              "icon": "mdi:" + icon
            }
          ]
          %}
        {%- endfor %}
        {%- endfor %}
        {{ data.warnings }}

You will get additional list of warnings in sensor attributes with easily accesible data :slight_smile:

Thanks for providing this. I’ve just set up a notification automation for my weather alerts. Do you know if It’s possible to include the link URL within the notification, so that you can click on it and go to the specific weather warning on the MET Office website? I can do this successfully on my dashboard using a markdown card for the weather alert, by using:

{% set link = item.link %}

and then

<a href="{{ link }}" target="_blank">

however it doesn’t look like you can template the link in the notify notification in the same way?

Yes, you can.

Here is my version. Just check the link part out.

- 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 %}

and the sensors. Note the feedparser one include the link…

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" # for conditional card & markdown card as weather_alerts can be !=0 but have no Oxon content
        state: >
          {{ state_attr('sensor.weather_alerts','entries')
            | map(attribute='summary')
            | select('search', 'Oxfordshire') 
            | list
            | count
          }}

Thanks @jchh - Can you show me how you are referencing the link within your notification automation please?

ugh - my mistake - I don’t currently have the url in my notification - sorry. Here it is anyway.

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

:slight_smile: No problem. I’ll keep searching to see if there is a way to include the clickable url. I can include the non-clickable plain text url by referencing {{ link }} within the message, but not sure how to make it clickable. I tried an actionable notification instead, however targetting the relevant URL from the alert attribute is proving difficult, but I’m sure there will be a way somehow…

      - action: "URI" # Must be set to URI if you plan to use a URI
        title: "View Warning"
        uri: "{{ link }}" 

If you already have access to the link.

1 Like

Thanks, that’s exactly what I was trying with the actionable notifications, however that only works if you have a known static url, so http://www.google.co.uk for example, in the uri field. I’m trying to work out how to target the dynamic link which is an attribute of the weather alert entries for each given weather alert - just like I am doing in my markdown card which @jchh is also using.

For example, the following sends me a notification, but there is no actionable link to click, as the {{ link}} seemingly cannot be referenced due to only setting it in the message variable:

alias: Weather Alerts
description: ""
trigger:
  - platform: state
    entity_id: sensor.weather_alerts_devon
condition:
  - condition: template
    value_template: "{{ trigger.to_state.state not in ['unknown', 'unavailable','0'] }}"
  - condition: template
    value_template: "{{ trigger.from_state.state not in ['unknown', 'unavailable','0'] }}"
action:
  - service: notify.mobile_app_scott_s23plus
    data:
      title: ⛅ Met Office
      message: "{{ message }}"
      data:
        actions:
          - action: URI
            title: View Warning
            uri: "{{ link }}"

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) %}
        {% set summary = item.summary | regex_findall_index('(.*) affecting South West England: (.*) valid from (.*) to (.*)', ignorecase=True) %}
        {% set time_from = as_timestamp(strptime(summary[2], "%H%M %a %d %b")) | timestamp_custom("%H:%M %d/%m") %}
        {% set time_to = as_timestamp(strptime(summary[3], "%H%M %a %d %b")) | timestamp_custom("%H:%M %d/%m") %}
        {% set link = item.link %}
        <b>⚠️ {{ summary[0] }}</b>
        {{ item.summary.split(':')[0] | title }}
        {{ time_from }} ➜ {{ time_to }}
        {%- if date_from == date_to %}
          {{ date_from }}
        {%- else %}
          {{ date_from }} ➜ {{ date_to }}
        {%- endif %}
      {%- endfor %}
    {%- endfor %}

Swapping out the {{ link }} for a specific url such as google, works fine within the notification. So this is where I get stuck, trying to reference the dynamic url which is within the ‘link’ of the weather alert sensor entries attribute.

variables:
  warning: |
    {%- 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) %}
          {% set w = item %}
      {%- endfor %}
    {%- endfor %}
    {{ w }}
  message: |
        {% set summary = warning.summary | regex_findall_index('(.*) affecting South West England: (.*) valid from (.*) to (.*)', ignorecase=True) %}
        {% set time_from = as_timestamp(strptime(summary[2], "%H%M %a %d %b")) | timestamp_custom("%H:%M %d/%m") %}
        {% set time_to = as_timestamp(strptime(summary[3], "%H%M %a %d %b")) | timestamp_custom("%H:%M %d/%m") %}
        {% set link = warning.link %}
        <b>⚠️ {{ summary[0] }}</b>
        {{ warning.summary.split(':')[0] | title }}
        {{ time_from }} ➜ {{ time_to }}
        {%- if date_from == date_to %}
          {{ date_from }}
        {%- else %}
          {{ date_from }} ➜ {{ date_to }}
        {%- endif %}
      {%- endfor %}
    {%- endfor %}

Now {{ warning.link }} should be an actual link you can access.

1 Like

Thanks Andrew. I’ve tried the code above, but unfortunately the notification no longer generates, and errors are showing in my log:

Logger: homeassistant.helpers.template
Source: helpers/template.py:2318
First occurred: 17:40:56 (6 occurrences)
Last logged: 17:42:24

Template variable warning: 'w' is undefined when rendering '{%- 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) %} {% set w = item %} {%- endfor %} {%- endfor %} {{ w }}'
Template variable warning: 'str object' has no attribute 'summary' when rendering '{%- 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) %} {% set summary = warning.summary | regex_findall_index('(.*) affecting South West England: (.*) valid from (.*) to (.*)', ignorecase=True) %} {% set time_from = as_timestamp(strptime(summary[2], "%H%M %a %d %b")) | timestamp_custom("%H:%M %d/%m") %} {% set time_to = as_timestamp(strptime(summary[3], "%H%M %a %d %b")) | timestamp_custom("%H:%M %d/%m") %} {% set link = warning.link %} <b>⚠️ {{ summary[0] }}</b> {{ warning.summary.split(':')[0] | title }} {{ time_from }} ➜ {{ time_to }} {%- if date_from == date_to %} {{ date_from }} {%- else %} {{ date_from }} ➜ {{ date_to }} {%- endif %} {%- endfor %} {%- endfor %}'

I added some missing formatting to the message variable, as the ‘for’ statements were missing - here is the automation code I am trying to use, based on your variable code:

alias: Weather Alerts Testing
description: ""
trigger:
  - platform: state
    entity_id: sensor.weather_alerts_devon
condition:
  - condition: template
    value_template: "{{ trigger.to_state.state not in ['unknown', 'unavailable','0'] }}"
  - condition: template
    value_template: "{{ trigger.from_state.state not in ['unknown', 'unavailable','0'] }}"
action:
  - service: notify.mobile_app_scott_s23plus
    data:
      title: ⛅ Met Office
      message: "{{ message }}"
      data:
        actions:
          - action: URI
            title: View Warning
            uri: "{{ warning.link }}"
variables:
  warning: |
    {%- 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) %}
          {% set w = item %}
      {%- endfor %}
    {%- endfor %}
    {{ w }}
  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) %}
        {% set summary = warning.summary | regex_findall_index('(.*) affecting South West England: (.*) valid from (.*) to (.*)', ignorecase=True) %}
            {% set time_from = as_timestamp(strptime(summary[2], "%H%M %a %d %b")) | timestamp_custom("%H:%M %d/%m") %}
            {% set time_to = as_timestamp(strptime(summary[3], "%H%M %a %d %b")) | timestamp_custom("%H:%M %d/%m") %}
            {% set link = warning.link %}
            <b>⚠️ {{ summary[0] }}</b>
            {{ warning.summary.split(':')[0] | title }}
            {{ time_from }} ➜ {{ time_to }}
            {%- if date_from == date_to %}
              {{ date_from }}
            {%- else %}
              {{ date_from }} ➜ {{ date_to }}
            {%- endif %}
          {%- endfor %}
        {%- endfor %}

Apologies if I’ve misunderstood something

I don’t have this sensor to be able to test with unfortunately, can you copy and paste the attributes from the states page for this sensor, so I can use that to test with please.

The reason the message part is missing the for stuff, is because by doing all that in the warning variable before the message one, then ALL the stuff that was previously populated in the message for loops, should have been populated in the warning variable which should output a single item object - which can then be accessed in the message variable. But that will only work if the warning variable is properly populated which it has not been hence the message ‘w’ is undefined

Sure thing, here are the attributes from the sensor.weather_alerts:

entries: 
- title: Yellow warning of rain affecting South West England
  title_detail:
    type: text/plain
    language: null
    base: https://www.metoffice.gov.uk/public/data/PWSCache/WarningsRSS/Region/sw
    value: Yellow warning of rain affecting South West England
  links:
    - rel: alternate
      type: text/html
      href: >-
        https://www.metoffice.gov.uk/weather/warnings-and-advice/uk-warnings#?date=2024-02-08&id=251453ce-6e89-4156-bacb-79a5de9960c7&referrer=rss
    - length: '15285'
      type: image/png
      href: >-
        https://data.consumer-digital.api.metoffice.gov.uk/v1/warnings/rss/image/yellow-rain.png
      rel: enclosure
  link: >-
    https://www.metoffice.gov.uk/weather/warnings-and-advice/uk-warnings#?date=2024-02-08&id=251453ce-6e89-4156-bacb-79a5de9960c7&referrer=rss
  summary: >-
    Yellow warning of rain affecting South West England: Bath and North East
    Somerset, Bournemouth Christchurch and Poole, Bristol, Cornwall, Devon,
    Dorset, Gloucestershire, North Somerset, Plymouth, Somerset, South
    Gloucestershire, Swindon, Torbay, Wiltshire valid from 0200 Thu 08 Feb to
    0600 Fri 09 Feb
  summary_detail:
    type: text/html
    language: null
    base: https://www.metoffice.gov.uk/public/data/PWSCache/WarningsRSS/Region/sw
    value: >-
      Yellow warning of rain affecting South West England: Bath and North East
      Somerset, Bournemouth Christchurch and Poole, Bristol, Cornwall, Devon,
      Dorset, Gloucestershire, North Somerset, Plymouth, Somerset, South
      Gloucestershire, Swindon, Torbay, Wiltshire valid from 0200 Thu 08 Feb to
      0600 Fri 09 Feb
  id: >-
    https://www.metoffice.gov.uk/weather/warnings-and-advice/uk-warnings#?date=2024-02-08&id=251453ce-6e89-4156-bacb-79a5de9960c7&referrer=rss&region=South
    West England
  guidislink: false

icon: mdi:rss
friendly_name: Weather Alerts

and my sensor config if it helps:

- 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"

@mobile.andrew.jones solution is pretty much correct, just the {{ w }} is in the wrong place. It should looks like below:

warning: |
    {%- 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) %}
          {% set w = item %}
          {{ w }}
      {%- endfor %}
    {%- endfor %}
1 Like

Great, that works now - thank you both for your help with that, much appreciated!

1 Like

Only a minor thing, as this is working correctly, however I noticed that an warning has appeared in my logs after running the automation to test it. The warning is due to the date not being defined, like the time_from and time_to is:

Logger: homeassistant.helpers.template
Source: helpers/template.py:2318
First occurred: 09:54:08 (1 occurrences)
Last logged: 09:54:08

Template variable warning: 'date_from' is undefined when rendering '{%- 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) %} {% set summary = warning.summary | regex_findall_index('(.*) affecting South West England: (.*) valid from (.*) to (.*)', ignorecase=True) %} {% set time_from = as_timestamp(strptime(summary[2], "%H%M %a %d %b")) | timestamp_custom("%H:%M %d/%m") %} {% set time_to = as_timestamp(strptime(summary[3], "%H%M %a %d %b")) | timestamp_custom("%H:%M %d/%m") %} {% set link = warning.link %} <b>⚠️ {{ summary[0] }}</b> {{ warning.summary.split(':')[0] | title }} {{ time_from }} ➜ {{ time_to }} {%- if date_from == date_to %} {{ date_from }} {%- else %} {{ date_from }} ➜ {{ date_to }} {%- endif %} {%- endfor %} {%- endfor %}'

is this a case of needing to define the date_from and date_to within the message variable?

Yes, that’s correct. You have in your code {% set time_from …, {% set time_to … and {% set link … but missing setting the date variables, so you need to add below the link this:

{% 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:] %}
1 Like

Great, thank you :slight_smile: I’m going to tweak the time_from and time_to definitions now, as they are also including the date, and my notification comes through like this currently:

Hopefully i can get that changed and tested before the warning dissappears - always a fun challenge when these warnings popup! Thanks again for your help

1 Like