Severe Weather Alerts from the US National Weather Service

Looking over the last two days of data for my nws_alerts, it looks like the sensor drops to 0 when the API isn’t working. I think that means there’s no way for the component to know that the alert it sees when the API comes back is old. To prevent my alerts from running wild from the API instability, I’m going to add an input_text to record the NWS ID for the alert in the [0] position and a condition to make sure the new alert doesn’t match the last NWS ID registered. When the API comes back up, it looks like the alerts remain in the same position in the array. I’ll get the yaml worked out in the next day or two.

1 Like

Right, tht’s basically what I’m doing with the variable instead of the input text. The advantage is that the variable will allow me to capture a history of old id’s in the attributes.

I’m not sure if it will be needed or not but since it will be easy to set up I will use it.

OTOH, using an input text creates a challenge in figuring out exactly when to update the input text based on a state change so you can compare the new id with the old. Keeping a list of old id’s solves that problem.

But TBH, it does create it’s own issue tho. I’m not sure yet how to create a single list out of a list of key:value pairs. I’m getting there tho. I just need a bit more google-fu. Or maybe i’ll take the easy route and ask the guru’s here on the forum. :wink:

And be aware of what I posted above about changing the way the id’s are going to be captured. you may need to adjust your comparison depending on how you are going to do it. I should be putting out the new version later today if work doesn’t get busy.

Something like this would work, where alerts is your key:value pair.

list_of_alerts = []
for alert in alerts:
     list_of_alerts.append(alert)

How do you then iterate thru the list of attributes of an entity?

I may not be seeing it but I don’t know how the code above would do that.

for example here is the entity and its attributes:

and here is the list of attributes as json:

I’m not sure yet how to write the template to create a list of values out of the list of “key:value” pairs in the attributes.

here you go:

{% for key, value in states....attributes %}
    {{ key }}
    {{ value }}
{% endfor %}

Not happy about it:

if I remove one of the test entries it stops complaining but it will only ever give me the keys but never the value of the keys.

Strange I got the example right from the jinja page: https://jinja.palletsprojects.com/en/master/templates/#for

Actually I just figured it out. It was easier than expected.

thanks for the help tho. :+1:

What’s funny is that everything I needed to know was already included in my question in my post above.

:laughing:

I’ve updated the integration with the above noted changes. it should be available in HACS now or soon if not.

@Maker2000

this is the approach I’ve taken to filter the new event id’s:

  1. install the custom variable integration: https://github.com/rogro82/hass-variables

  2. create a variable:

variable:
  nws_alerts_event_ids:
    value: 'none'
    restore: true
  1. create an automation to update the variable and it’s attributes:
automation:
  - alias: NWS Update Event ID Variable
    initial_state: 'on'
    trigger:
      - platform: state
        entity_id: sensor.nws_alerts
    condition:
      - condition: template
        value_template: "{{ trigger.from_state.state != 'Unknown' }}"
    action:
      service: variable.set_variable
      data:
        variable: nws_alerts_event_ids
        attributes_template: >
          {
            "history_1": "{{ variable.state }}",
            "history_2": "{{ variable.attributes.history_1 }}",
            "history_3": "{{ variable.attributes.history_2 }}",
            "history_4": "{{ variable.attributes.history_3 }}",
            "history_5": "{{ variable.attributes.history_4 }}",
            "history_6": "{{ variable.attributes.history_5 }}",
            "history_7": "{{ variable.attributes.history_6 }}",
            "history_8": "{{ variable.attributes.history_7 }}",
            "history_9": "{{ variable.attributes.history_8 }}",
            "history_10": "{{ variable.attributes.history_9 }}"
          }
      data_template:
        value: "{{ (trigger.to_state.attributes.event_id).split('-')[0] }}"
  1. add a condition to your other notification/announcement automations:
condition:
  - condition: template
    value_template: "{{ (trigger.to_state.attributes.event_id).split('-')[0] not in states.variable.nws_test_alerts_event_ids.attributes.values()|list }}"

I haven’t had much opportunity to test it but in the limited amount of time I have it seems to work.

Let me know if there are any issues with it.

To make it easier to keep track of changes to the code that I have used in this thread I copied my current NWS Alerts package to my github repo.

It can be found here:

2 Likes

Thank you for putting all the effort into fixing the bug from the NWS api. I applied those changes and I guess now we have to wait and see for the next API outage.

Correct me if I am wrong, but the new variable only updates from the ‘unknown’ state of the nws_alerts? I had the feeling during the outage it was also switching between 1 and 0, without taking the value ‘unknown’. If that’s true, it may still cause problems.

To that end I was thinking whether it is worth to connect the unique event id with the expiration date of the message and have the alert only use this initial information until expired. This, however, may be a bigger restructuring and probably doesn’t account if weather events are cancelled (if that even occurs).

No, the other way around.

it updates if the from state was not unknown

condition:
  - condition: template
    value_template: "{{ trigger.from_state.state != 'Unknown' }}"

that’s what the “!=” means.

it will update from anything except unknown.

And TBH, you could probably leave that out. It was in there from some testing I was doing a while back and I just left it in since I didn’t figure it would hurt anything.

OK, got it. I’ve got a lot to learn :slight_smile:

1 Like

I updated my NWS automations to take advantage of the new work. The notification triggered only once, despite the instability in the api:

All is working as expected so far, so no need for me to build the inputs to smooth this out. Yay!

1 Like

Actually I was looking into this again and I realized that in the previous issue (from post 223) just filtering on the latest alert event might be a problem.

I have seen it before during really active weather conditions that the alert count could jump from, for example, 3 directly to 5 with no 4 in between. So that means the number 4 alert will not be acted on (pop-up or announcement if needed) and could result in an emergency alert being missed.

I don’t know how big of a concern that would be since it is kind of rare and if the weather is that crazy then most people would already be aware of it and be more vigilant and hopefully wouldn’t just rely on HA to keep them safe.

That said, I may try to come up with a way that if there is a jump of more than 1 in the alert count then make sure the ones in between get acted upon.

:thinking:

1 Like

well, I gave it a shot and all I can say is - Wow! this is going to make the automations way long!

At least using the new “choose” option for the actions streamlines it a little bit. And I got to play with the new options.

Here is just the pop-up notification automation to give sample of how complex it’s going to get:

first I created an input boolean to tell me if I got multiple alerts at once:

input_boolean:
  nws_multi_alert:
    name: NWS Multiple Alerts At Once

I used the following automation to set its state:

  - alias: 'NWS Check for Multi Alerts'
    initial_state: 'on'
    trigger:
      - platform: state
        entity_id: sensor.nws_alerts
    condition:
      - condition: template
        value_template: "{{ states('sensor.nws_alerts') | int > 0 }}"
      - condition: template
        value_template: '{{ trigger.to_state.state|int > trigger.from_state.state|int }}'
    action:
      - choose:
          - conditions:
              - condition: template
                value_template: '{{ (trigger.to_state.state | int - trigger.from_state.state|int) > 1 }}'
            sequence:
              - service: input_boolean.turn_on
                entity_id: input_boolean.nws_multi_alert
          - conditions:
            - condition: template
              value_template: '{{ (trigger.to_state.state | int - trigger.from_state.state|int) == 1 }}'
            sequence:
              - service: input_boolean.turn_off
                entity_id: input_boolean.nws_multi_alert

then I used it in the automation:

  - alias: 'NWS Weather Alert Pop Up Control'
    initial_state: 'on'
    trigger:
      - platform: state
        entity_id: sensor.nws_alerts
    condition:
      - condition: template
        value_template: "{{ states('sensor.nws_alerts') | int > 0 }}"
      - condition: template
        value_template: '{{ trigger.to_state.state|int > trigger.from_state.state|int }}'
      - condition: template
        value_template: "{{ (trigger.to_state.attributes.event_id).split('-')[0] not in states.variable.nws_alerts_event_ids.attributes.values()|list }}"
    action:
      - choose:
        - conditions:
            - condition: state
              entity_id: input_boolean.nws_multi_alert
              state: 'on'
            - condition: template
              value_template: '{{ (trigger.to_state.state | int - trigger.from_state.state|int) == 2 }}'
            - condition: template
              value_template: "{{ (trigger.to_state.attributes.event_id).split('-')[1] not in states.variable.nws_alerts_event_ids.attributes.values()|list }}"
          sequence:
            - service: script.nws_popup_on_wx_alert
              data_template:
                title: >
                  "{{ state_attr('sensor.nws_alerts', 'title').split(' - ')[0] }}"
                message: >
                  "{{ state_attr('sensor.nws_alerts', 'display_desc').split('\n\n-\n\n')[0] }}"
            - service: script.nws_popup_on_wx_alert
              data_template:
                title: >
                  "{{ state_attr('sensor.nws_alerts', 'title').split(' - ')[1] }}"
                message: >
                  "{{ state_attr('sensor.nws_alerts', 'display_desc').split('\n\n-\n\n')[1] }}"
        - conditions:
            - condition: state
              entity_id: input_boolean.nws_multi_alert
              state: 'on'
            - condition: template
              value_template: '{{ (trigger.to_state.state | int - trigger.from_state.state|int) == 3 }}'
            - condition: template
              value_template: "{{ (trigger.to_state.attributes.event_id).split('-')[1] not in states.variable.nws_alerts_event_ids.attributes.values()|list }}"
            - condition: template
              value_template: "{{ (trigger.to_state.attributes.event_id).split('-')[2] not in states.variable.nws_alerts_event_ids.attributes.values()|list }}"
          sequence:
            - service: script.nws_popup_on_wx_alert
              data_template:
                title: >
                  "{{ state_attr('sensor.nws_alerts', 'title').split(' - ')[0] }}"
                message: >
                  "{{ state_attr('sensor.nws_alerts', 'display_desc').split('\n\n-\n\n')[0] }}"
            - service: script.nws_popup_on_wx_alert
              data_template:
                title: >
                  "{{ state_attr('sensor.nws_alerts', 'title').split(' - ')[1] }}"
                message: >
                  "{{ state_attr('sensor.nws_alerts', 'display_desc').split('\n\n-\n\n')[1] }}"
            - service: script.nws_popup_on_wx_alert
              data_template:
                title: >
                  "{{ state_attr('sensor.nws_alerts', 'title').split(' - ')[2] }}"
                message: >
                  "{{ state_attr('sensor.nws_alerts', 'display_desc').split('\n\n-\n\n')[2] }}"
        default:
          service: script.nws_popup_on_wx_alert
          data_template:
            title: >
              "{{ state_attr('sensor.nws_alerts', 'title').split(' - ')[0] }}"
            message: >
              "{{ state_attr('sensor.nws_alerts', 'display_desc').split('\n\n-\n\n')[0] }}"

and that’s only if I get no more than 3 alerts at once, which I think is reasonable.

Still trying to decide if it’s worth it…

@finity just FYI put a lil PR in for the config flow, it auto populates the zone id(s) based on the lat/lon from Home Assistant.

2 Likes

Seems to be handling excessive alerts well too:

image

Ooof :stuck_out_tongue:

1 Like

That looks like no fun at all. :sweat: :sweat: :sweat:

lol my template can’t hold the list of alert titles now :stuck_out_tongue:

2 Likes