diff --git a/README.md b/README.md index 6525312..d7b329d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,15 @@ # Alerts from the US National Weather Service (nws_alerts) +## BREAKING CHANGES IN V5.0 + +This is a pretty much complete rewrite of the integration to better organize the data for the alerts. All of the data provided by the older versions is still included but it's laid out very differently and as such none of the associated automations package or dashboard examples will continue to function as there currently are. + +I have done extensive testing to ensure that the new updated package examplews work as desired but of course I caouldn't test every situation. + +Use at your own risk! + +## Description: + An updated version of the nws_alerts custom integration for Home Assistant originally found at github.com/eracknaphobia/nws_custom_component This integration retrieves updated weather alerts every minute from the US NWS API (by default but it can be changed in the config options). @@ -12,8 +22,6 @@ The sensor that is created is used in my "NWS Alerts" package: https://github.co You can also display the generated alerts in your frontend. For example usage see: https://github.com/finity69x2/nws_alerts/blob/master/lovelace/alerts_tab -(note: this frontend example uses a custom card but it's not necessary for it's use in the frontend. it's only an example and how I currently use it in my HA) - ## Installation: Manually: @@ -38,8 +46,6 @@ After installing the integration you can then configure it using the instruction NOTE: As of HA versoin 2024.5.x the yaml configuration option is broken. I don't know if it will ever be fixed so the only viable config option is via the UI -There are two ways to configure this integration. - You can configure the integration via the "Configuration->Integrations" section of the Home Assistant UI: Click on "+ Add Integration" buuton in the bottom right corner. @@ -56,45 +62,4 @@ https://github.com/finity69x2/nws_alerts/blob/master/lookup_options.md If you select the "Using a device tracker" option under the "GPS Location" option then HA will use the GPS coordinates provided by that tracker to query for alerts so you should follow the same recommendations for using GPS coordinates when using that option. -Or manually via an entry in your configuration.yaml file: - -To create a sensor instance add the following configuration to your sensor definitions using the zone_id found above: - -``` -- platform: nws_alerts - zone_id: 'PAC049' -``` - -or enter comma separated values for multiple zones: - -``` -- platform: nws_alerts - zone_id: 'PAC049,WVC031' -``` - -or by entering in specific GPS coordinates: - -``` -- platform: nws_alerts - gps_loc: 39.52, -119.81 -``` - -or, finally, by adding a device_tracker entity: - -``` -- platform: nws_alerts - tracker: 'device_tracker.your_tracker_entity' -``` - - -After you restart Home Assistant then you should have a new sensor called "sensor.nws_alerts" in your system. - -You can overide the sensor default name ("sensor.nws_alerts") to one of your choosing by setting the "name:" option: - -``` -- platform: nws_alerts - zone_id: 'INZ009,INC033' - name: My NWS Alerts Sensor -``` - -Using the configuration example above the sensor will then be called "sensor.my_nws_alerts_sensor". +After you restart Home Assistant then you should have a new sensor (by default) called "sensor.nws_alerts" in your system. diff --git a/custom_components/nws_alerts/__init__.py b/custom_components/nws_alerts/__init__.py index 1910800..859defe 100644 --- a/custom_components/nws_alerts/__init__.py +++ b/custom_components/nws_alerts/__init__.py @@ -1,6 +1,8 @@ """ NWS Alerts """ +import hashlib import logging +import uuid from datetime import timedelta import aiohttp @@ -156,6 +158,7 @@ async def _async_update_data(self): data = await update_alerts(self.config, coords) except Exception as error: raise UpdateFailed(error) from error + _LOGGER.debug("Data: %s", data) return data async def _get_tracker_gps(self): @@ -231,18 +234,7 @@ async def async_get_alerts(zone_id: str = "", gps_loc: str = "") -> dict: """Query API for Alerts.""" url = "" - values = { - "state": 0, - "event": None, - "event_id": None, - "message_type": None, - "event_status": None, - "event_severity": None, - "event_onset": None, - "event_expires": None, - "display_desc": None, - "spoken_desc": None, - } + alerts = {} headers = {"User-Agent": USER_AGENT, "Accept": "application/geo+json"} data = None @@ -261,117 +253,42 @@ async def async_get_alerts(zone_id: str = "", gps_loc: str = "") -> dict: _LOGGER.error("Problem updating NWS data: (%s) - %s", r.status, r.body) if data is not None: - events = [] - headlines = [] - event_id = "" - message_type = "" - event_status = "" - event_severity = "" - event_onset = "" - event_expires = "" - display_desc = "" - spoken_desc = "" features = data["features"] + alert_list = [] for alert in features: - event = alert["properties"]["event"] - if "NWSheadline" in alert["properties"]["parameters"]: - headline = alert["properties"]["parameters"]["NWSheadline"][0] - else: - headline = event - - id = alert["id"] - type = alert["properties"]["messageType"] - status = alert["properties"]["status"] - description = alert["properties"]["description"] - instruction = alert["properties"]["instruction"] - severity = alert["properties"]["severity"] - certainty = alert["properties"]["certainty"] - onset = alert["properties"]["onset"] - expires = alert["properties"]["expires"] - - # if event in events: - # continue - - events.append(event) - headlines.append(headline) - - if display_desc != "": - display_desc += "\n\n-\n\n" - - display_desc += ( - "\n>\nHeadline: %s\nStatus: %s\nMessage Type: %s\nSeverity: %s\nCertainty: %s\nOnset: %s\nExpires: %s\nDescription: %s\nInstruction: %s" - % ( - headline, - status, - type, - severity, - certainty, - onset, - expires, - description, - instruction, - ) - ) - - if event_id != "": - event_id += " - " - - event_id += id - - if message_type != "": - message_type += " - " - - message_type += type - - if event_status != "": - event_status += " - " - event_status += status + tmp_dict = {} - if event_severity != "": - event_severity += " - " + # Generate stable Alert ID + id = await generate_id(alert["id"]) - event_severity += severity + tmp_dict["Event"] = alert["properties"]["event"] + tmp_dict["ID"] = id + tmp_dict["URL"] = alert["id"] - if event_onset != "": - event_onset += " - " - - event_onset += onset - - if event_expires != "": - event_expires += " - " - - event_expires += expires + event = alert["properties"]["event"] + if "NWSheadline" in alert["properties"]["parameters"]: + tmp_dict["Headline"] = alert["properties"]["parameters"]["NWSheadline"][0] + else: + tmp_dict["Headline"] = event + + tmp_dict["Type"] = alert["properties"]["messageType"] + tmp_dict["Status"] = alert["properties"]["status"] + tmp_dict["Severity"] = alert["properties"]["severity"] + tmp_dict["Certainty"] = alert["properties"]["certainty"] + tmp_dict["Onset"] = alert["properties"]["onset"] + tmp_dict["Expires"] = alert["properties"]["expires"] + tmp_dict["Description"] = alert["properties"]["description"] + tmp_dict["Instruction"] = alert["properties"]["instruction"] - if headlines: - num_headlines = len(headlines) - i = 0 - for headline in headlines: - i += 1 - if spoken_desc != "": - if i == num_headlines: - spoken_desc += "\n\n-\n\n" - else: - spoken_desc += "\n\n-\n\n" + alert_list.append(tmp_dict) - spoken_desc += headline + alerts["state"] = len(features) + alerts["alerts"] = alert_list - if len(events) > 0: - event_str = "" - for item in events: - if event_str != "": - event_str += " - " - event_str += item + return alerts - values["state"] = len(events) - values["event"] = event_str - values["event_id"] = event_id - values["message_type"] = message_type - values["event_status"] = event_status - values["event_severity"] = event_severity - values["event_onset"] = event_onset - values["event_expires"] = event_expires - values["display_desc"] = display_desc - values["spoken_desc"] = spoken_desc - return values +async def generate_id(val: str) -> str: + hex_string = hashlib.md5(val.encode("UTF-8")).hexdigest() + return str(uuid.UUID(hex=hex_string)) diff --git a/custom_components/nws_alerts/config_flow.py b/custom_components/nws_alerts/config_flow.py index eb70103..cd840f7 100644 --- a/custom_components/nws_alerts/config_flow.py +++ b/custom_components/nws_alerts/config_flow.py @@ -1,4 +1,5 @@ """Adds config flow for NWS Alerts.""" + from __future__ import annotations import logging diff --git a/custom_components/nws_alerts/manifest.json b/custom_components/nws_alerts/manifest.json index 8a4c674..d505733 100644 --- a/custom_components/nws_alerts/manifest.json +++ b/custom_components/nws_alerts/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_polling", "issue_tracker": "https://github.com/finity69x2/nws_alerts/issues", "requirements": [], - "version": "4.1" + "version": "5.0" } diff --git a/custom_components/nws_alerts/sensor.py b/custom_components/nws_alerts/sensor.py index a66e310..6e607ee 100644 --- a/custom_components/nws_alerts/sensor.py +++ b/custom_components/nws_alerts/sensor.py @@ -37,58 +37,6 @@ _LOGGER = logging.getLogger(__name__) -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_ZONE_ID): cv.string, - vol.Optional(CONF_GPS_LOC): cv.string, - vol.Optional(CONF_TRACKER): cv.string, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_INTERVAL, default=DEFAULT_INTERVAL): int, - vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): int, - } -) - - -async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): - """Configuration from yaml""" - if DOMAIN not in hass.data.keys(): - hass.data.setdefault(DOMAIN, {}) - if CONF_ZONE_ID in config: - config.entry_id = slugify(f"{config.get(CONF_ZONE_ID)}") - elif CONF_GPS_LOC in config: - config.entry_id = slugify(f"{config.get(CONF_GPS_LOC)}") - elif CONF_TRACKER in config: - config.entry_id = slugify(f"{config.get(CONF_TRACKER)}") - else: - raise ValueError("GPS, Zone or Device Tracker needs to be configured.") - config.data = config - else: - if CONF_ZONE_ID in config: - config.entry_id = slugify(f"{config.get(CONF_ZONE_ID)}") - elif CONF_GPS_LOC in config: - config.entry_id = slugify(f"{config.get(CONF_GPS_LOC)}") - elif CONF_TRACKER in config: - config.entry_id = slugify(f"{config.get(CONF_TRACKER)}") - else: - raise ValueError("GPS, Zone or Device Tracker needs to be configured.") - config.data = config - - # Setup the data coordinator - coordinator = AlertsDataUpdateCoordinator( - hass, - config, - config[CONF_TIMEOUT], - config[CONF_INTERVAL], - ) - - # Fetch initial data so we have data when entities subscribe - await coordinator.async_refresh() - - hass.data[DOMAIN][config.entry_id] = { - COORDINATOR: coordinator, - } - async_add_entities([NWSAlertSensor(hass, config)], True) - async def async_setup_entry(hass, entry, async_add_entities): """Setup the sensor platform.""" @@ -124,12 +72,12 @@ def icon(self): return self._icon @property - def state(self): + def state(self) -> int | None: """Return the state of the sensor.""" if self.coordinator.data is None: return None elif "state" in self.coordinator.data.keys(): - return self.coordinator.data["state"] + return int(self.coordinator.data["state"]) return None @property @@ -141,16 +89,9 @@ def extra_state_attributes(self): return attrs attrs[ATTR_ATTRIBUTION] = ATTRIBUTION - attrs["title"] = self.coordinator.data["event"] - attrs["event_id"] = self.coordinator.data["event_id"] - attrs["message_type"] = self.coordinator.data["message_type"] - attrs["event_status"] = self.coordinator.data["event_status"] - attrs["event_severity"] = self.coordinator.data["event_severity"] - attrs["event_onset"] = self.coordinator.data["event_onset"] - attrs["event_expires"] = self.coordinator.data["event_expires"] - attrs["display_desc"] = self.coordinator.data["display_desc"] - attrs["spoken_desc"] = self.coordinator.data["spoken_desc"] - + x = 0 + if "alerts" in self.coordinator.data: + attrs["Alerts"] = self.coordinator.data["alerts"] return attrs @property diff --git a/info.md b/info.md index 9541d97..4cba6cb 100644 --- a/info.md +++ b/info.md @@ -1,6 +1,6 @@ # Alerts from the US National Weather Service (nws_alerts) -## Possible Breaking Change +## Breaking Change for V5.0 Modified the format of the list of event_id in the attributes @@ -24,36 +24,10 @@ Clone the Repository and copy the "nws_alerts" directory to your "custom_compone You can find your Zone or County ID by going to https://alerts.weather.gov/, scroll down to your state and click on the “zone list” and/or "county list" then look for the entry for your county. -There are two ways to configure this integration. +The intergration is configured via the "Configuration->Integrations" section of the Home Assistant UI. -Manually via an entry in your configuration.yaml file: +Look for the integration labeled "NWS Alerts" and follow the on-screen prompts. -To create a sensor instance add the following configuration to your sensor definitions using the zone_id found above: +Using the configuration example above by default the sensor will then be called "sensor.nws_alerts". -``` -- platform: nws_alerts - zone_id: 'PAC049' -``` - -or enter comma separated values for multiple zones: - -``` -- platform: nws_alerts - zone_id: 'PAC049,WVC031' -``` - -After you restart Home Assistant then you should have a new sensor called "sensor.nws_alerts" in your system. - -You can overide the sensor default name ("sensor.nws_alerts") to one of your choosing by setting the "name:" option: - -``` -- platform: nws_alerts - zone_id: 'INZ009,INC033' - name: My NWS Alerts Sensor -``` - -Using the configuration example above the sensor will then be called "sensor.my_nws_alerts_sensor" - -Or you can configure the integration via the "Configuration->Integrations" section of the Home Assistant UI. - -Look for the integration labeled "NWS Alerts" +If desired you can modify the sensor name via the UI in the initial configuration or later in the entity configuration dialogue box. diff --git a/lovelace/alerts_tab.yaml b/lovelace/alerts_tab.yaml index 5135336..4dbf934 100644 --- a/lovelace/alerts_tab.yaml +++ b/lovelace/alerts_tab.yaml @@ -1,24 +1,10 @@ -## The following custom plugins are used in the example below: -## custom:vertical-layout: https://github.com/thomasloven/lovelace-layout-card -## custom:stack-in-card: https://github.com/ofekashery/vertical-stack-in-card -## custom:entity-attributes-card: https://github.com/custom-cards/entity-attributes-card - -## all of them can be inbstalled via HACS - +######################################################################################### title: "Alerts" visible: false -type: custom:vertical-layout -layout: - max_cols: 4 +panel: true cards: - - - type: custom:stack-in-card + - type: vertical-stack cards: - - type: entities - title: Severe Weather Alerts - show_header_toggle: false - entities: - - sensor.nws_alerts - type: conditional conditions: - entity: sensor.nws_alerts @@ -30,33 +16,8 @@ cards: {% for alert_num in range(num_alerts) %} --- # NWS Alert {{ alert_num + 1 }} - {% if state_attr('sensor.nws_alerts', 'title').split(' - ')[alert_num] is defined %} - ## {{ states.sensor.nws_alerts.attributes.title.split(' - ')[alert_num] }} - {{ state_attr('sensor.nws_alerts', 'display_desc').split('\n\n-\n\n')[alert_num] }} - {% else %} - none - {% endif %} + + ## {{ state_attr('sensor.nws_alerts', 'Alerts')[alert_num].Event }} + + {{ state_attr('sensor.nws_alerts', 'Alerts')[alert_num].Description }} {% endfor %} - - - type: entities - title: NWS Alerts History - show_header_toggle: false - state_color: true - entities: - - sensor.nws_alerts_event_ids - - type: custom:entity-attributes-card - heading_name: Name - heading_state: State - entity: sensor.nws_alerts_event_ids - filter: - include: - - sensor.nws_alerts_event_ids.history_1 - - sensor.nws_alerts_event_ids.history_2 - - sensor.nws_alerts_event_ids.history_3 - - sensor.nws_alerts_event_ids.history_4 - - sensor.nws_alerts_event_ids.history_5 - - sensor.nws_alerts_event_ids.history_6 - - sensor.nws_alerts_event_ids.history_7 - - sensor.nws_alerts_event_ids.history_8 - - sensor.nws_alerts_event_ids.history_9 - - sensor.nws_alerts_event_ids.history_10 diff --git a/lovelace/alerts_view_built_in.yaml b/lovelace/alerts_view_built_in.yaml deleted file mode 100644 index ffecb39..0000000 --- a/lovelace/alerts_view_built_in.yaml +++ /dev/null @@ -1,117 +0,0 @@ -title: Alerts -type: panel -cards: - - square: false - type: grid - cards: - - type: tile - entity: sensor.nws_alerts - name: National Weather Service Alerts - show_entity_picture: false - hide_state: false - vertical: false - state_content: - - state - - last-changed - - event_id - - event_status - - event_expires - - type: vertical-stack - cards: - - type: conditional - conditions: - - condition: numeric_state - entity: sensor.nws_alerts - above: 0 - card: - type: markdown - content: >- - # NWS First Active Alert - - --- - - {% if (states('sensor.nws_alerts')) | int > 0 %} - - ## {{ states.sensor.nws_alerts.attributes.title.split(' - ')[0] }} - - {{ state_attr('sensor.nws_alerts','display_desc').split('\n\n-\n\n')[0] }} - - {% endif -%} - - type: conditional - conditions: - - condition: numeric_state - entity: sensor.nws_alerts - above: 1 - card: - type: markdown - content: >- - # NWS Second Active Alert - - --- - - {% if (states('sensor.nws_alerts')) | int > 1 %} - - ## {{ states.sensor.nws_alerts.attributes.title.split(' - ')[1] }} - - {{ state_attr('sensor.nws_alerts','display_desc').split('\n\n-\n\n')[1] }} - - {% endif -%} - - type: conditional - conditions: - - condition: numeric_state - entity: sensor.nws_alerts - above: 2 - card: - type: markdown - content: >- - # NWS Third Active Alert - - --- - - {% if (states('sensor.nws_alerts')) | int > 2 %} - - ## {{ states.sensor.nws_alerts.attributes.title.split(' - ')[2] }} - - {{ state_attr('sensor.nws_alerts','display_desc').split('\n\n-\n\n')[2] }} - - {% endif -%} - - type: conditional - conditions: - - condition: numeric_state - entity: sensor.nws_alerts - above: 3 - card: - type: markdown - content: >- - # NWS Fourth Active Alert - - --- - - {% if (states('sensor.nws_alerts')) | int > 3 %} - - ## {{ states.sensor.nws_alerts.attributes.title.split(' - ')[3] }} - - {{ state_attr('sensor.nws_alerts','display_desc').split('\n\n-\n\n')[3] }} - - {% endif -%} - - type: conditional - conditions: - - condition: numeric_state - entity: sensor.nws_alerts - above: 4 - card: - type: markdown - content: >- - # NWS Fifth Active Alert - - --- - - {% if (states('sensor.nws_alerts')) | int > 4 %} - - ## {{ states.sensor.nws_alerts.attributes.title.split(' - ')[5] }} - - {{ state_attr('sensor.nws_alerts','display_desc').split('\n\n-\n\n')[5] }} - - {% endif -%} - title: Severe Weather Alerts - columns: 1 diff --git a/packages/nws_alerts_package.yaml b/packages/nws_alerts_package.yaml index 04df7da..019d8e6 100644 --- a/packages/nws_alerts_package.yaml +++ b/packages/nws_alerts_package.yaml @@ -10,7 +10,6 @@ # https://api.weather.gov/alerts/active?zone=INZ009,INC033 - ######################## BINARY SENSOR ######################################### binary_sensor: @@ -26,311 +25,780 @@ binary_sensor: {% else %} mdi:weather-sunny {% endif %} - - -######################## INPUT BOOLEAN ######################################### - -input_boolean: - nws_multi_alert: - name: NWS Multiple Alerts At Once - + ############################## VARIABLE ##################################### -## this uses the hass_variable custom component. - +## this uses the hass_variable custom integration. ## you can install thru HACS or manually from https://github.com/Wibias/hass-variables - -## if you don't install this custom integration the NWS Alerts integration will still function -## but you will need to modify the code in this package to remove references to "sensor.nws_alerts_event_ids" +## This custom integration isn't needed for the NWS Alerts integration to function +## but I use it for my automations so that I can keep track of which alerts have been notified and/or announced variable: nws_alerts_event_ids: value: 'none' - restore: true + restore: false + nws_alerts_announced_ids: + value: 'none' + restore: false ######################## AUTOMATION ########################################### automation: - - alias: 'NWS Check for Multi Alerts' + + - alias: NWS Alerts Update Event ID History + id: nws_alerts_update_event_id_history initial_state: 'on' trigger: - platform: state entity_id: sensor.nws_alerts - condition: - - "{{ states('sensor.nws_alerts') | int > 0 }}" - - '{{ trigger.to_state.state|int > trigger.from_state.state|int }}' action: - - choose: - - conditions: - - '{{ (trigger.to_state.state | int - trigger.from_state.state|int) > 1 }}' - sequence: - - service: input_boolean.turn_on - entity_id: input_boolean.nws_multi_alert - - delay: - seconds: 30 - - service: input_boolean.turn_on - entity_id: input_boolean.nws_multi_alert - - conditions: - - '{{ (trigger.to_state.state | int - trigger.from_state.state|int) == 1 }}' - sequence: - - service: input_boolean.turn_off - entity_id: input_boolean.nws_multi_alert - - - alias: 'NWS Weather Alert Pop Up Control' + - delay: + minutes: 5 + - repeat: + sequence: + - delay: + seconds: 5 + - condition: template + value_template: > + {% set ns = namespace(ids=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set id = state_attr('sensor.nws_alerts', 'Alerts')[x].ID %} + {% set ns.ids = ns.ids + [id] %} + {% endfor -%} + {% set current_id_list = set(ns.ids) %} + {% set history_id_list = set( (states.sensor.nws_alerts_event_ids.attributes.values()| reject('match', 'nws_alerts_event_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ (current_id_list.difference(history_id_list)|list) | count > 0 }} + - service: variable.update_sensor + target: + entity_id: sensor.nws_alerts_event_ids + data: + value: > + {% set ns = namespace(ids=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set id = state_attr('sensor.nws_alerts', 'Alerts')[x].ID %} + {% set ns.ids = ns.ids + [id] %} + {% endfor -%} + {% set current_id_list = set(ns.ids) %} + {% set history_id_list = set( (states.sensor.nws_alerts_event_ids.attributes.values()| reject('match', 'nws_alerts_event_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {% if (current_id_list.difference(history_id_list)|list)[0] is defined %} + {{ (current_id_list.difference(history_id_list)|list)[0] }} + {% endif %} + - service: variable.update_sensor + target: + entity_id: sensor.nws_alerts_event_ids + data: + attributes: + history_1: > + {% set ns = namespace(ids=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set id = state_attr('sensor.nws_alerts', 'Alerts')[x].ID %} + {% set ns.ids = ns.ids + [id] %} + {% endfor -%} + {% set current_id_list = set(ns.ids) %} + {% set history_id_list = set( (states.sensor.nws_alerts_event_ids.attributes.values()| reject('match', 'nws_alerts_event_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {% if (current_id_list.difference(history_id_list)|list)[0] is defined %} + {{ (current_id_list.difference(history_id_list)|list)[0] }} + {% endif %} + history_2: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_1') }}" + history_3: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_2') }}" + history_4: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_3') }}" + history_5: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_4') }}" + history_6: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_5') }}" + history_7: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_6') }}" + history_8: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_7') }}" + history_9: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_8') }}" + history_10: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_9') }}" + history_11: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_10') }}" + history_12: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_11') }}" + history_13: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_12') }}" + history_14: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_13') }}" + history_15: "{{ state_attr('sensor.nws_alerts_event_ids', 'history_14') }}" + until: + - condition: template + value_template: > + {% set ns = namespace(ids=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set id = state_attr('sensor.nws_alerts', 'Alerts')[x].ID %} + {% set ns.ids = ns.ids + [id] %} + {% endfor -%} + {% set current_id_list = set(ns.ids) %} + {% set history_id_list = set( (states.sensor.nws_alerts_event_ids.attributes.values()| reject('match', 'nws_alerts_event_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ (current_id_list.difference(history_id_list)|list) | count == 0}} + + ######################## PERSISTENT NOTIFICATIONS ########################################### + + ## This will send up to 3 persistent notifications for alerts. + ## If there are more than 3 alerts there will be a fourth notification to check the NWS for further information. + + - alias: 'NWS Alerts Create Persistent Notifications' + id: nws_alerts_create_persistent_notifications initial_state: 'on' trigger: - platform: state entity_id: sensor.nws_alerts condition: - "{{ states('sensor.nws_alerts') | int > 0 }}" - - '{{ trigger.to_state.state|int > trigger.from_state.state|int }}' - - "{{ (state_attr('sensor.nws_alerts', 'event_id').split('-')[0] not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'event_id').split('-')[0] != states('sensor.nws_alerts_event_ids')) }}" action: - - delay: - seconds: 5 - choose: - conditions: - - condition: state - entity_id: input_boolean.nws_multi_alert - state: 'on' - - '{{ (trigger.to_state.state | int - trigger.from_state.state|int) == 2 }}' - - "{{ (state_attr('sensor.nws_alerts', 'event_id').split('-')[1] not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'event_id').split('-')[1] != states('sensor.nws_alerts_event_ids')) }}" + - "{{ states('sensor.nws_alerts') | int >= 3 }}" sequence: - - service: script.nws_popup_on_wx_alert - data: - 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: - title: > - "{{ state_attr('sensor.nws_alerts', 'title').split(' - ')[1] }}" - message: > - "{{ state_attr('sensor.nws_alerts', 'display_desc').split('\n\n-\n\n')[1] }}" + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[0].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[0].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.nws_alerts_persistent_notification + data: + notification_id: "nwswxalert0" + title: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[0].Event }} + message: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[0].Description }} + - delay: + seconds: 2 + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[1].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[1].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.nws_alerts_persistent_notification + data: + notification_id: "nwswxalert1" + title: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[1].Event }} + message: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[1].Description }} + - delay: + seconds: 2 + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[2].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[2].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.nws_alerts_persistent_notification + data: + notification_id: "nwswxalert2" + title: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[2].Event }} + message: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[2].Description }} - conditions: - - condition: state - entity_id: input_boolean.nws_multi_alert - state: 'on' - - '{{ (trigger.to_state.state | int - trigger.from_state.state|int) == 3 }}' - - "{{ (state_attr('sensor.nws_alerts', 'event_id').split('-')[1] not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'event_id').split('-')[1] != states('sensor.nws_alerts_event_ids')) }}" - - "{{ (state_attr('sensor.nws_alerts', 'event_id').split('-')[2] not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'event_id').split('-')[2] != states('sensor.nws_alerts_event_ids')) }}" + - "{{ states('sensor.nws_alerts') | int == 2 }}" sequence: - - service: script.nws_popup_on_wx_alert - data: - 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: - 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: - 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: - title: > - "{{ state_attr('sensor.nws_alerts', 'title').split(' - ')[0] }}" - message: > - "{{ state_attr('sensor.nws_alerts', 'display_desc').split('\n\n-\n\n')[0] }}" - - - alias: NWS Notification Weather Alert + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[0].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[0].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.nws_alerts_persistent_notification + data: + notification_id: "nwswxalert0" + title: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[0].Event }} + message: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[0].Description }} + - delay: + seconds: 2 + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[1].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[1].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.nws_alerts_persistent_notification + data: + notification_id: "nwswxalert1" + title: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[1].Event }} + message: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[1].Description }} + - conditions: + - "{{ states('sensor.nws_alerts') | int == 1 }}" + sequence: + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[0].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[0].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.nws_alerts_persistent_notification + data: + notification_id: "nwswxalert0" + title: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[0].Event }} + message: > + {{ state_attr('sensor.nws_alerts', 'Alerts')[0].Description }} + - delay: + seconds: 2 + - condition: template + value_template: "{{ states('sensor.nws_alerts') | int >= 4 }}" + - condition: template + value_template: > + {% set ns = namespace(ids=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set id = state_attr('sensor.nws_alerts', 'Alerts')[x].ID %} + {% set ns.ids = ns.ids + [id] %} + {% endfor -%} + {% set current_id_list = set(ns.ids) %} + {% set history_id_list = set( (states.sensor.nws_alerts_event_ids.attributes.values()| reject('match', 'nws_alerts_event_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ (current_id_list.difference(history_id_list)|list) | count > 0 }} + - condition: template + value_template: > + {{ (state_attr('sensor.nws_alerts', 'Alerts')[0].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) + and (state_attr('sensor.nws_alerts', 'Alerts')[0].ID != states('sensor.nws_alerts_event_ids')) }} + - service: script.nws_alerts_persistent_notification + data: + notification_id: "nwswxalert4" + title: More Than 3 New Alerts! + message: Check your local National Weather Service for all current alerts! + + +########################## NOTIFICATIONS ########################################################################## + + ## This will send up to 3 notifications for alerts. + ## If there are more than 3 alerts there will be a fouth notification to check the NWS for further information. + + - alias: NWS Alerts Notification Weather Alert + id: nws_alerts_notification_weather_alert initial_state: 'on' trigger: platform: state entity_id: sensor.nws_alerts condition: - "{{states('sensor.nws_alerts') | int > 0}}" - - '{{ trigger.to_state.state|int > trigger.from_state.state|int }}' - - "{{ (state_attr('sensor.nws_alerts', 'event_id').split('-')[0] not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'event_id').split('-')[0] != states('sensor.nws_alerts_event_ids')) }}" action: - ## substitute your desired notification platform here - - service: notify.pushbullet + - choose: + - conditions: + - "{{ states('sensor.nws_alerts') | int >= 3 }}" + sequence: + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[0].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[0].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.turn_on + continue_on_error: true + entity_id: script.notification_pushover_message + data: + variables: + target: Jeffs_phone + message: > + "NWS: {{ state_attr('sensor.nws_alerts', 'Alerts')[0].Event }}" + sound: echo + - delay: + seconds: 2 + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[1].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[1].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.turn_on + continue_on_error: true + entity_id: script.notification_pushover_message + data: + variables: + target: Jeffs_phone + message: > + "NWS: {{ state_attr('sensor.nws_alerts', 'Alerts')[1].Event }}" + sound: echo + - delay: + seconds: 2 + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[2].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[2].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.turn_on + continue_on_error: true + entity_id: script.notification_pushover_message + data: + variables: + target: Jeffs_phone + message: > + "NWS: {{ state_attr('sensor.nws_alerts', 'Alerts')[2].Event }}" + sound: echo + - conditions: + - "{{ states('sensor.nws_alerts') | int == 2 }}" + sequence: + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[0].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[0].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.turn_on + continue_on_error: true + entity_id: script.notification_pushover_message + data: + variables: + target: Jeffs_phone + message: > + "NWS: {{ state_attr('sensor.nws_alerts', 'Alerts')[0].Event }}" + sound: echo + - delay: + seconds: 2 + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[1].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[1].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.turn_on + continue_on_error: true + entity_id: script.notification_pushover_message + data: + variables: + target: Jeffs_phone + message: > + "NWS: {{ state_attr('sensor.nws_alerts', 'Alerts')[1].Event }}" + sound: echo + - conditions: + - "{{ states('sensor.nws_alerts') | int == 1 }}" + sequence: + - if: + - "{{ (state_attr('sensor.nws_alerts', 'Alerts')[0].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) and (state_attr('sensor.nws_alerts', 'Alerts')[0].ID != states('sensor.nws_alerts_event_ids')) }}" + then: + - service: script.turn_on + continue_on_error: true + entity_id: script.notification_pushover_message + data: + variables: + target: Jeffs_phone + message: > + "NWS: {{ state_attr('sensor.nws_alerts', 'Alerts')[0].Event }}" + sound: echo + - delay: + seconds: 5 + - condition: template + value_template: "{{ states('sensor.nws_alerts') | int >= 4 }}" + - condition: template + value_template: > + {% set ns = namespace(ids=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set id = state_attr('sensor.nws_alerts', 'Alerts')[x].ID %} + {% set ns.ids = ns.ids + [id] %} + {% endfor -%} + {% set current_id_list = set(ns.ids) %} + {% set history_id_list = set( (states.sensor.nws_alerts_event_ids.attributes.values()| reject('match', 'nws_alerts_event_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ (current_id_list.difference(history_id_list)|list) | count > 0 }} + - condition: template + value_template: > + {{ (state_attr('sensor.nws_alerts', 'Alerts')[0].ID not in states.sensor.nws_alerts_event_ids.attributes.values()|list) + and (state_attr('sensor.nws_alerts', 'Alerts')[0].ID != states('sensor.nws_alerts_event_ids')) }} + - service: script.turn_on + continue_on_error: true + entity_id: script.notification_pushover_message data: - message: > - "NWS: {{ state_attr('sensor.nws_alerts', 'title').split(' - ')[0] }}" - - - alias: NWS Announce Weather Alert - initial_state: 'on' + variables: + target: Jeffs_phone + message: "NWS: More Than 3 New Alerts! Check your local National Weather Service for all current alerts!" + sound: echo + + + ############################## ANNOUNCEMENTS ############################################################## + +## this is where you will determine which alerts are announced instead of simply being sent to a notification. +## it will announce every new alert that matches the criteria in the "test_list" even if there are more than one of the same type of alert +## (i.e. if there are two tornado warnings issued at the same time then you will get two announcements in a row for a tornado warning). +## I only typically trigger announcements for dangerous weather (tornadoes & severe thunderstorms) but I've included others as examples. +## you will need to add or remove any events as needed in the "test_list" and also the "repeat" section as dsired. + +## also I am using the Alexa Media Player custom integration to play the announcement. If you don't use that integration you may have to adjust the service call for your system. + +## lastly, I am calling two different scripts for announcements - one for very dangedrous weather (i.e. tornoados) that will play throughtout the house including the bedrooms +## and a different one for everything else that won't wake people up for, for example, a heat advisory. +## modify this to your desired requirements. + + - alias: NWS Alerts Announce Weather Alert + id: nws_alerts_announce_weather_alert trigger: - platform: state - entity_id: sensor.nws_alerts + entity_id: sensor.nws_alerts_test condition: - condition: and - conditions: - - "{{states('sensor.nws_alerts') | int > 0}}" - - '{{ trigger.to_state.state|int > trigger.from_state.state|int }}' - - "{{ ('Severe Thunderstorm Warning' in state_attr('sensor.nws_alerts', 'title')) or ('Tornado Warning' in state_attr('sensor.nws_alerts', 'title')) }}" - - "{{ (state_attr('sensor.nws_alerts', 'event_id').split('-')[0] not in states.sensor.nws_alerts_event_ids.attributes.values()|list) }}" - - "{{ (state_attr('sensor.nws_alerts', 'event_id').split('-')[0] != states('sensor.nws_alerts_event_ids')) }}" + - "{{states('sensor.nws_alerts') | int > 0}}" + - condition: template + value_template: > + {% set ns = namespace(ids=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set id = state_attr('sensor.nws_alerts_test', 'Alerts')[x].ID %} + {% set ns.ids = ns.ids + [id] %} + {% endfor -%} + {% set current_id_list = set(ns.ids) %} + {% set history_id_list = set( (states.sensor.nws_alert_event_ids.attributes.values()| reject('match', 'nws_alerts_event_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ (current_id_list.difference(history_id_list)|list) | count > 0 }} + - condition: template + value_template: > + {% set ns = namespace(events=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event %} + {% set ns.events = ns.events + [event] %} + {% endfor -%} + {% set alerts_list = set(ns.events) %} + {% set test_list = set(['Tornado Warning', 'Severe Thunderstorm Warning', 'Air Quality Alert', 'Heat Advisory', 'Severe Thunderstorm Watch', 'Excessive Heat Warning' ]) %} + {{ test_list.intersection(alerts_list) | count > 0 }} + action: + - repeat: + count: "{{ states('sensor.nws_alerts') | int }}" + sequence: + - if: + - condition: template + value_template: > + {% set ns_events = namespace(events=[]) %} + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event %} + {% set ns_events.events = ns_events.events + [event] %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {%- set history_id_list = set( (states.sensor.nws_alerts_announced_ids.attributes.values() | reject('match', 'nws_alerts_announced_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ ns_dict.events_dict[repeat.index - 1].event == 'Tornado Warning' and ns_dict.events_dict[repeat.index - 1].id not in history_id_list }} + then: + - service: script.turn_on + entity_id: script.nws_alerts_announce_tornado_warning + data: + variables: + message: Attention!!,,,Attention!!,,,The National Weather Service Has issued a tornado warning for our area! + - service: variable.update_sensor + target: + entity_id: sensor.nws_alerts_announced_ids + data: + value: > + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {{ ns_dict.events_dict[repeat.index - 1].id}} + ## set this delay to ensure that any audio is completed before triggering the next announcement + - delay: + minutes: 1 + - repeat: + count: "{{ states('sensor.nws_alerts') | int }}" + sequence: + - if: + - condition: template + value_template: > + {% set ns_events = namespace(events=[]) %} + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event %} + {% set ns_events.events = ns_events.events + [event] %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {%- set history_id_list = set( (states.sensor.nws_alerts_announced_ids.attributes.values() | reject('match', 'nws_alerts_announced_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ ns_dict.events_dict[repeat.index - 1].event == 'Severe Thunderstorm Warning' and ns_dict.events_dict[repeat.index - 1].id not in history_id_list }} + then: + - service: script.turn_on + entity_id: script.nws_alerts_announce_thunderstorm_warning + data: + variables: + message: Attention!!,,,Attention!!,,,The National Weather Service Has issued a severe thunderstorm warning for our area! + - service: variable.update_sensor + target: + entity_id: sensor.nws_alerts_announced_ids + data: + value: > + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {{ ns_dict.events_dict[repeat.index - 1].id}} + - delay: + minutes: 1 + - repeat: + count: "{{ states('sensor.nws_alerts') | int }}" + sequence: + - if: + - condition: template + value_template: > + {% set ns_events = namespace(events=[]) %} + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event %} + {% set ns_events.events = ns_events.events + [event] %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {%- set history_id_list = set( (states.sensor.nws_alerts_announced_ids.attributes.values() | reject('match', 'nws_alerts_announced_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ ns_dict.events_dict[repeat.index - 1].event == 'Heat Advisory' and ns_dict.events_dict[repeat.index - 1].id not in history_id_list }} + then: + - service: script.turn_on + entity_id: script.nws_alerts_announce + data: + variables: + message: Attention!!,,,Attention!!,,,The National Weather Service Has issued a heat advisory for our area! + - service: variable.update_sensor + target: + entity_id: sensor.nws_alerts_announced_ids + data: + value: > + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {{ ns_dict.events_dict[repeat.index - 1].id}} + - delay: + minutes: 1 + - repeat: + count: "{{ states('sensor.nws_alerts') | int }}" + sequence: + - if: + - condition: template + value_template: > + {% set ns_events = namespace(events=[]) %} + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event %} + {% set ns_events.events = ns_events.events + [event] %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {%- set history_id_list = set( (states.sensor.nws_alerts_announced_ids.attributes.values() | reject('match', 'nws_alerts_announced_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ ns_dict.events_dict[repeat.index - 1].event == 'Severe Thunderstorm Watch' and ns_dict.events_dict[repeat.index - 1].id not in history_id_list }} + then: + - service: script.turn_on + entity_id: script.nws_alerts_announce_thunderstorm_warning + data: + variables: + message: Attention!!,,,Attention!!,,,The National Weather Service Has issued a severe thunderstorm watch for our area! + - service: variable.update_sensor + target: + entity_id: sensor.nws_alerts_announced_ids + data: + value: > + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {{ ns_dict.events_dict[repeat.index - 1].id}} + - delay: + minutes: 1 + - repeat: + count: "{{ states('sensor.nws_alerts') | int }}" + sequence: + - if: + - condition: template + value_template: > + {% set ns_events = namespace(events=[]) %} + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event %} + {% set ns_events.events = ns_events.events + [event] %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {%- set history_id_list = set( (states.sensor.nws_alerts_announced_ids.attributes.values() | reject('match', 'nws_alerts_announced_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ ns_dict.events_dict[repeat.index - 1].event == 'Air Quality Alert' and ns_dict.events_dict[repeat.index - 1].id not in history_id_list }} + then: + - service: script.turn_on + entity_id: script.nws_alerts_announce_thunderstorm_warning + data: + variables: + message: Attention!!,,,Attention!!,,,The National Weather Service Has issued an air quality alert for our area! + - service: variable.update_sensor + target: + entity_id: sensor.nws_alerts_announced_ids + data: + value: > + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {{ ns_dict.events_dict[repeat.index - 1].id}} + - delay: + minutes: 1 + - repeat: + count: "{{ states('sensor.nws_alerts') | int }}" + sequence: + - if: + - condition: template + value_template: > + {% set ns_events = namespace(events=[]) %} + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event %} + {% set ns_events.events = ns_events.events + [event] %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {%- set history_id_list = set( (states.sensor.nws_alerts_announced_ids.attributes.values() | reject('match', 'nws_alerts_announced_ids') | reject('match', 'None') | reject('match', 'unknown'))|list ) %} + {{ ns_dict.events_dict[repeat.index - 1].event == 'Excessive Heat Warning' and ns_dict.events_dict[repeat.index - 1].id not in history_id_list }} + then: + - service: script.turn_on + entity_id: script.nws_alerts_announce_thunderstorm_warning + data: + variables: + message: Attention!!,,,Attention!!,,,The National Weather Service Has issued an excessive heat warning for our area! + - service: variable.update_sensor + target: + entity_id: sensor.nws_alerts_announced_ids + data: + value: > + {% set ns_dict = namespace(events_dict=[]) %} + {% for x in range(0,states('sensor.nws_alerts')|int ) %} + {% set event_dict_list = dict(event = state_attr('sensor.nws_alerts', 'Alerts')[x].Event, id=state_attr('sensor.nws_alerts', 'Alerts')[x].ID) %} + {% set ns_dict.events_dict = ns_dict.events_dict + [event_dict_list] %} + {% endfor -%} + {{ ns_dict.events_dict[repeat.index - 1].id}} + - delay: + minutes: 1 + + - alias: NWS Alerts Update Announced Event ID History + id: nws_alerts_update_announced_event_id_history + initial_state: 'on' + trigger: + - platform: state + entity_id: sensor.nws_alerts_announced_ids + to: action: - ## substitute your own media players here + - service: variable.update_sensor + target: + entity_id: sensor.nws_alerts_announced_ids + data: + attributes: + history_1: "{{ states('sensor.nws_alerts_announced_ids') }}" + history_2: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_1') }}" + history_3: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_2') }}" + history_4: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_3') }}" + history_5: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_4') }}" + history_6: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_5') }}" + history_7: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_6') }}" + history_8: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_7') }}" + history_9: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_8') }}" + history_10: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_9') }}" + history_11: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_10') }}" + history_12: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_11') }}" + history_13: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_12') }}" + history_14: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_13') }}" + history_15: "{{ state_attr('sensor.nws_alerts_announced_ids', 'history_14') }}" + + +################################# SCRIPT ################################### + +script: + nws_alerts_persistent_notification: + alias: NWS Alerts Persistent Notifications + sequence: + - service: > + {% if states('sensor.nws_alerts') != '0' %} + persistent_notification.create + {% endif %} + data: + notification_id: "{{ notification_id }}" + message: "{{ message }}" + title: '{{ title }}' + +## you will need to modify the following two scripts for your system media players and if you use the provided example alert tone + + nws_alerts_announce_tornado_warning: + alias: NWS Alerts Announce Tornado Warning + sequence: - service: media_player.volume_set data: entity_id: + - media_player.basement_dot - media_player.bedroom_2_dot + - media_player.big_room_dot - media_player.computer_room_dot - - media_player.kitchen_dot - media_player.garage_dot - - media_player.basement_dot - - media_player.sunroom_dot + - media_player.kitchen_dot - media_player.livingroom_dot + - media_player.master_bedroom_dot + - media_player.sunroom_dot + - media_player.upper_hall_dot volume_level: 0.9 - service: notify.alexa_media data: target: + - media_player.basement_dot - media_player.bedroom_2_dot + - media_player.big_room_dot - media_player.computer_room_dot - - media_player.kitchen_dot - media_player.garage_dot - - media_player.basement_dot - - media_player.sunroom_dot + - media_player.kitchen_dot - media_player.livingroom_dot + - media_player.master_bedroom_dot + - media_player.sunroom_dot + - media_player.upper_hall_dot data: type: tts - message: > - {% if 'Severe Thunderstorm Warning' in state_attr('sensor.nws_alerts', 'title') %} - Attention!,,,Attention!,,,The National Weather Service Has issued a severe thunderstorm warning for our area - {% elif 'Tornado Warning' in state_attr('sensor.nws_alerts', 'title') %} - Attention!,,,Attention!,,,The National Weather Service Has issued a tornado warning for our area - {% endif %} + message: "{{ message }}" - delay: '00:00:15' - service: notify.alexa_media data: - message: "