Severe Weather Alerts from the US National Weather Service

Thanks for the kind words.

I’m really glad I can help others be just a bit more safe.

2 Likes

Oh and of course don’t forget to also thank @firstof9 since he’s been doing most of the heavy lifting on the code recently.

(and thanks for reminding me to post this with your :heart: @firstof9 :grinning_face_with_smiling_eyes: )

2 Likes

I help when I can :slight_smile: :beers:

1 Like

Definitely! Thank you @firstof9 as well!

1 Like

First, thank you thank you thank you @finity and @firstof9 for this great rewrite and integration. Absolutely love it. I’m working through setting up for Alexa announcements and am wondering if there is a way to search the alerts for the words “watch” or “warning” instead of maintaining a test list?

I do this:

- alias: NWS Announce Weather Alert
  id: announce_weather_alert
  trigger:
    - platform: state
      entity_id: sensor.nws_alerts_gps_2
  action:
    - repeat:
        sequence:
          - variables:
              alert: "{{ repeat.item }}"
          - if:
              - condition: template
                value_template: "{{ ('Tornado' in alert.Event) and (alert.Type == 'Alert') }}"
            then:
              sequence:
                - metadata: {}
                  data:
                    priority: True
                    volume: 0.9
                    this_message: >-
                      The National Weather Service has {{ iif(alert.Type ==
                      'Alert', 'issued a', 'updated the') }} {{alert.Event}}
                      for our area. {% if(alert.Event != alert.Headline) %}
                        {{ alert.Headline }}
                      {% else %}
                        It will expire in {{alert.Expires | as_datetime() | time_until(2)}}. {{ (alert.Instruction or '') | replace('\n', ' ') }}
                      {% endif %}
                  action: script.house_announcement
            else:
              - metadata: {}
                data:
                  volume: 0.9
                  this_message: >-
                    The National Weather Service has {{ iif(alert.Type == 'Alert',
                    'issued a', 'updated the') }} {{alert.Event}} for our area. {%
                    if(alert.Event != alert.Headline) %}
                      {{ alert.Headline }}
                    {% else %}
                      It will expire in {{alert.Expires | as_datetime() | time_until(2)}}. {{ (alert.Instruction or '') | replace('\n', ' ') }}
                    {% endif %}
                action: script.house_announcement
        for_each: >-
          {{ trigger.to_state.attributes.Alerts | reject('in',
          trigger.from_state.attributes.Alerts) | list() |
          sort(attribute='Expires') }}    

I filter the word “tornado” and allow it to override my announcer script to play the alert even if “night mode”/“silent mode” is enabled (suppresses TTS notifications after 9pm local time).

Edit: This is modified from the scripts posted here:

2 Likes

there is an open issue on the github repo that has suggested alternative automations. I’ve been working on tweaking those a bit and I’m pretty sure I’m pretty much there.

I’ll be adding those to my repo shortly but here are the ones I’m using now for testing based on those:

automation:

  - alias: NWS Test - Mobile App Notifications
    id: nws_test_mobile_app_notifications
    description: ""
    trigger:
      - platform: state
        entity_id: sensor.nws_alerts_test
    condition:
      - condition: numeric_state
        entity_id: sensor.nws_alerts_test
        above: 0
    action:
      - repeat:
          sequence:
            - service: script.turn_on
              continue_on_error: true
              entity_id: script.notification_pushover_message
              data:
                variables:
                  target: my_phone
                  message: "NWS Test: {{ repeat.item.Event }}"
                  sound: echo
            - delay:
                seconds: 5
          for_each: "{{ trigger.to_state.attributes.Alerts | reject('in', trigger.from_state.attributes.Alerts) | sort(attribute='ID') | list() }}"
    mode: queued
    initial_state: "on"
    max: 10         


#################################################################


  - alias: NWS Test - Persistent Notifications
    id: nws_test_persistent_notifications
    description: ""
    trigger:
      - platform: state
        entity_id: sensor.nws_alerts_test
    condition: 
      - condition: numeric_state
        entity_id: sensor.nws_alerts_test
        above: 0
    action:
      - repeat:
          sequence:
            - service: script.nws_alerts_persistent_notification
              data:
                notification_id: "NWS_{{ repeat.item.ID }}"
                title: "NWS Test: {{ repeat.item.Event }}"
                message: "{{ repeat.item.Description }}"
            - delay:
                seconds: 5
          for_each: "{{ trigger.to_state.attributes.Alerts | reject('in', trigger.from_state.attributes.Alerts) | sort(attribute='ID') | list() }}"
    mode: queued
    initial_state: "on"
    max: 10
    
    
######################################################
    
    
  - alias: NWS Test - TTS Announcements
    id: nws_test_tts_announcements
    description: ""
    trigger:
      - platform: state
        entity_id: sensor.nws_alerts_test
    condition:
      - condition: numeric_state
        entity_id: sensor.nws_alerts_test
        above: 0
    action:
      - repeat:
          sequence:
            - variables:
                alert: "{{ repeat.item }}"
            - if:
                - condition: template
                  value_template: "{{ ('Tornado Warning' in alert.Event) and (alert.Type == 'Alert') }}"
              then:
                - service: script.turn_on
                  entity_id: script.nws_alerts_test_announce
                  data:
                    variables:
                      message: This is only a test. The National Weather Service Has issued a tornado warning for our area! this is only a test. 
                - delay:
                    minutes: 1
          for_each: "{{ trigger.to_state.attributes.Alerts | reject('in', trigger.from_state.attributes.Alerts) | list() | sort(attribute='ID') }}"
      - repeat:
          sequence:
            - variables:
                alert: "{{ repeat.item }}"
            - if:
                - condition: template
                  value_template: "{{ ('Severe Thunderstorm Warning' in alert.Event) and (alert.Type == 'Alert') }}"
              then:
                - service: script.turn_on
                  entity_id: script.nws_alerts_test_announce
                  data:
                    variables:
                      message: This is only a test. The National Weather Service Has issued a severe thunderstorm warning for our area! this is only a test.
                - delay:
                    minutes: 1
          for_each: "{{ trigger.to_state.attributes.Alerts | reject('in', trigger.from_state.attributes.Alerts) | list() | sort(attribute='ID') }}"
    mode: queued
    initial_state: "on"
    max: 10

Of course you’ll need to modify for your needs.

And in my production setup I use two different scripts for the announcements. one for tornados that announces everywhere and one for everything else that doesn’t announce in the bedrooms.

I may still tweak a bit but likely not much.

2 Likes

Wonderful, thank you guys! I will take a closer look as this stuff you sent :slight_smile:

1 Like

Since this seems to be gathering several examples, here’s what I have, combining some of what is above. Vertical stack card, but only display if the title contains “Watch” or “Warning” (see Watch/Warning/Advisory Definitions for the possible alerts and definitions, and https://www.weather.gov/media/alert/CAP_v12_guide_05-16-2017.pdf for even more definitions)

title: Alerts
type: vertical-stack
cards:
  - type: conditional
    conditions:
      - entity: sensor.nws_alerts
        state_not: '0'
    card:
      type: markdown
      content: |
        {% set num_alerts = states('sensor.nws_alerts_2') | int  %}
        {% for alert_num in range(num_alerts) %}
        {% set alert = state_attr('sensor.nws_alerts_2', 'Alerts')[alert_num].Event %}
        {% if 'Warning' in alert or 'Watch' in alert %}
        ---
        ## {{ state_attr('sensor.nws_alerts_2', 'Alerts')[alert_num].Event }}
        {{ state_attr('sensor.nws_alerts_2', 'Alerts')[alert_num].Description }}
        {% endif %}
        {% endfor %}

You could also trigger the display of the alert on other things, like the Severity being “Extreme” or “Severe” for example. I’m still working on the logic for notifications.

the examples shown above work pretty well.

what do those lack that you’re looking for?

Perhaps a better phrasing would be “still working through the notifications, because I’m figuring out notifications in general, and what I even want”. The persistent notification example seems good, I’m just trying to wrap my head around it!

1 Like

I have a FR in an issue from @GreyBandit which is also related to a request from @Sekonicpr above about the “ends” vs “expires” data from the API.

The request is to add “ends”.

I can actually see why the “ends” might be better data to provide than the “expires” data. TBH, I’m not really sure why “expires” is there but I think someone asked for that data a long time back.

I don’t use “expires” in any way personally so I have no strong opinion either way.

I resist the urge to make anything break but I also resist the urge to just add every field from the API to the attributes since it makes the sensor harder to read for us mere humans.

So the question I’ll ask here is does anyone actually use the “expires” in automations or rely on that data that using “ends” wouldn’t actually be a better alternative?

I’m suggesting replacing “expires” with “ends” instead of having both.

Seeing as how elections are in the air in the US i’ll (hopefully) solve this question with a poll.

“ends” vs “expires”
  • Keep “expires” only
  • remove “expires” and add “ends” only
  • keep “expires” and still add “ends”
0 voters

the poll closes in 2 weeks so I’ll make the decision then.

but for full disclosure the option to have both will need to have a strong mandate to be implemented.

1 Like

So I’m a bit of a purist. The EAS message that comes through the SAME header format only has the fields for start time and duration. The duration is not a date/time it ends at, just how long after the message is issued that it will auto expire and no longer be active. You could use the issue date/time and add the duration to it to get expiration date/time, yes. And that information may be available over the API (which is different than the EAS message). So that said, personally I’d choose neither, but if I had to it would be just expires.

Here’s what an API response looks like:

Hello! I think we need both, or we need some logic … what I have found is that:

(1) When populated, “ends” is the best indicator of when the alert is no longer applicable. Looking at other web sites and how they present alerts for my area, this is always the value that is shown (when it is not null).

(2) However, “ends” is sometimes null. In those cases, the value for “expires” is the one that seems to communicate when the alert is no longer applicable.

I manually changed my local copy of your integration several months ago to add “ends”. I have also included this … which is admittedly a bit of a hack but has resulted in my alert end dates/times always matching what I see displayed elsewhere:

        if tmp_dict["Ends"] == None:
            tmp_dict["Ends"] = alert["properties"]["expires"]

Realizing this is a hack, I don’t expect you to implement the same. However, I would request both attributes be available so we can build the necessary logic into our dashboards. Thank you!

I’ve updated the example code in the “nws_alerts_package.yaml” at the repo using the above code. It’s way cleaner and doesn’t use any external dependencies.

thanks again to @T3chArmy for the suggestions. the ones I put in the repo are only minimally modified from their suggestions.

1 Like

I also just added the “Ends” attribute (keeping “Expires”) along with another requested “AreasAffected”.

the poll might not have had hardly any votes but the people spoke and I listened. No need to continue it.

:laughing:

2 Likes

Hi:
Thank for add end attribute. In the Headline attribute is there any way that when I use it for notifications it doesn’t show all caps?

Here is my test sensor converted to be capitalized lower case:

{{ state_attr('sensor.nws_alerts_test', 'Alerts')[0].Headline|title }}

the result was:

“HEAT ADVISORY REMAINS IN EFFECT UNTIL 8 PM PDT FRIDAY”

then after conversion:

“Heat Advisory Remains In Effect Until 8 Pm Pdt Friday”

you can make it all lower case by:

{{ state_attr('sensor.nws_alerts_test', 'Alerts')[0].Headline|lower }}

which results in:

“heat advisory remains in effect until 8 pm pdt friday”

or to capitalize the first letter of the sentence:

{{ state_attr('sensor.nws_alerts_test', 'Alerts')[0].Headline|capitalize }}

result:

“Heat advisory remains in effect until 8 pm pdt friday”

3 Likes

Thank finity now I have everything what I need!!!

1 Like