Minneapolis Snow Emergency Alert

Living in a city with snow emergency rules, like Minneapolis, can be tricky when the emergency rules are in effect. They are quick to tow your vehicle if you park in the wrong spot. So I decided to work on my HA skills and try to save myself from getting towed this year.

I feel like I have a lot of duplicate code, and would love to get feedback on how I can simplify the sensors and templates. I’m using 6 rest sensors for the same JSON file. How can I consolidate these into a single sensor? The notices array only contains 1 element when there is no emergency, and 6 if a snow emergency has been declared. I’m not sure what it looks like during the non winter months (we have like 5 of those…).

The json resource for my templates come from the city’s website, specifically this JSON.

Resource JSON

{
    "notices": [
		{
 "publishDate": "2021-11-16T12:58:00-06:00",
 "expireDate": "",
 "html": "<section class=\"organism organism--inline-alert\" data-id=\"snow-emergency-html\" data-version=\"202202224709851.0\">    <div class=\"grid-container fluid\">      <div class=\"grid-x grid-margin-x\">        <div class=\"cell\">          <div class=\"inline-alert notice\">            <div class=\"grid-x grid-margin-x align-middle\">            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--date\">\n\n                <div\n                     class=\"atom atom--time text-center\"\n                     data-time\n                     data-time-format=\"h:mma\"\n                     data-time-content=\".time--content\"\n                     data-time-clock=\".time--clock\"\n                     >\n                  <div class=\"fa fa-circle time--clock\">\n                    <div class=\"time--minute time--arms\"><\/div>\n                    <div class=\"time--hour time--arms\"><\/div>\n                  <\/div>\n                  <div class=\"time--content\">...<\/div>\n                <\/div>\n\n              <\/div>\n            <\/div>\n                            <div class=\"cell large-auto\">                <div class=\"inline-alert--message\">                  <div aria-live=\"polite\" role=\"alert\">                    <h3 class=\"headline\"><i class=\"fal fa-Normal parking (low res)\" aria-hidden=\"true\"><\/i>No Snow Emergency declared<\/h3>                    <div>There’s currently no Snow Emergency. Normal parking rules apply.<\/div>                  <\/div>                <\/div>              <\/div>                            <div class=\"cell large-shrink\">                  <div class=\"inline-alert--link\">                                          <a href=\"https://www.minneapolismn.gov/getting-around/snow/snow-emergencies/snow-parking-rules/\"  class=\"atom atom--shadow-button button tiny short\" tabindex=\"0\">    Snow Emergency Parking Rules  <\/a>                  <\/div>                <\/div>                          <\/div>          <\/div>        <\/div>      <\/div>    <\/div>  <\/section>",
 "id": "snow-emergency-html",
 "noticetype": "notice",
 "version": "202202224709850.0"
},
		{
 "date": "2022-02-22T15:16:40-06:00",
 "noticetype": "warning",
 "publishDate": "2022-02-22T15:12:00-06:00",
 "expireDate": "2022-02-22T21:00:00-06:00",
 "html": "<span id=\"d.en.25223\"><\/span>\n<section class=\"organism organism--inline-alert\" data-id=\"snow-emergency-html\" data-version=\"2522323.0\">\n  <div class=\"grid-container fluid\">\n    <div class=\"grid-x grid-margin-x\">\n      <div class=\"cell\">\n        <div class=\"inline-alert warning\">\n          <div class=\"grid-x grid-margin-x align-middle\">\n\n            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--date\">\n\n                <div\n                     class=\"atom atom--time text-center\"\n                     data-time\n                     data-time-format=\"h:mma\"\n                     data-time-content=\".time--content\"\n                     data-time-clock=\".time--clock\"\n                     >\n                  <div class=\"fa fa-circle time--clock\">\n                    <div class=\"time--minute time--arms\"><\/div>\n                    <div class=\"time--hour time--arms\"><\/div>\n                  <\/div>\n                  <div class=\"time--content\">...<\/div>\n                <\/div>\n\n              <\/div>\n            <\/div>\n\n            <div class=\"cell large-auto\">\n              <div class=\"inline-alert--message\">\n                <div aria-live=\"polite\" role=\"alert\">\n                  <h3 class=\"headline\">Snow Emergency declared<\/h3>\n                  <div>Day 1 rules begin at 9 p.m. tonight. Do not park on either side of Snow Emergency Routes.<\/div>\n                <\/div>\n              <\/div>\n            <\/div>\n\n            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--link\">\n\n\n                <a href=\"https://www.minneapolismn.gov/getting-around/snow/snow-emergencies/snow-parking-rules/\" class=\"atom atom--shadow-button button tiny short\" tabindex=\"0\">Snow Emergency Parking Rules<\/a>\n\n              <\/div>\n            <\/div>\n\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/section>",
 "id": "snow-emergency-html",
 "version": "2522323.0"
},{
 "date": "2022-02-22T15:16:41-06:00",
 "noticetype": "warning",
 "publishDate": "2022-02-22T21:00:00-06:00",
 "expireDate": "2022-02-23T08:00:00-06:00",
 "html": "<span id=\"d.en.23856\"><\/span>\n<section class=\"organism organism--inline-alert\" data-id=\"snow-emergency-html\" data-version=\"2385630.0\">\n  <div class=\"grid-container fluid\">\n    <div class=\"grid-x grid-margin-x\">\n      <div class=\"cell\">\n        <div class=\"inline-alert warning\">\n          <div class=\"grid-x grid-margin-x align-middle\">\n\n            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--date\">\n\n                <div\n                     class=\"atom atom--time text-center\"\n                     data-time\n                     data-time-format=\"h:mma\"\n                     data-time-content=\".time--content\"\n                     data-time-clock=\".time--clock\"\n                     >\n                  <div class=\"fa fa-circle time--clock\">\n                    <div class=\"time--minute time--arms\"><\/div>\n                    <div class=\"time--hour time--arms\"><\/div>\n                  <\/div>\n                  <div class=\"time--content\">...<\/div>\n                <\/div>\n\n              <\/div>\n            <\/div>\n\n            <div class=\"cell large-auto\">\n              <div class=\"inline-alert--message\">\n                <div aria-live=\"polite\" role=\"alert\">\n                  <h3 class=\"headline\">Snow Emergency in effect. Day 1 rules apply.<\/h3>\n                  <div>Snow Emergency Day 1 rules are in effect from 9 p.m. until 8 a.m. (overnight). Do not park on either side of Snow Emergency Routes.<\/div>\n                <\/div>\n              <\/div>\n            <\/div>\n\n            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--link\">\n\n\n                <a href=\"https://www.minneapolismn.gov/getting-around/snow/snow-emergencies/snow-parking-rules/\" class=\"atom atom--shadow-button button tiny short\" tabindex=\"0\">Snow Emergency Parking Rules<\/a>\n\n              <\/div>\n            <\/div>\n\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/section>",
 "id": "snow-emergency-html",
 "version": "2385630.0"
},{
 "date": "2022-02-22T15:16:42-06:00",
 "noticetype": "warning",
 "publishDate": "2022-02-23T08:00:00-06:00",
 "expireDate": "2022-02-23T20:00:00-06:00",
 "html": "<span id=\"d.en.23844\"><\/span>\n<section class=\"organism organism--inline-alert\" data-id=\"snow-emergency-html\" data-version=\"2384425.0\">\n  <div class=\"grid-container fluid\">\n    <div class=\"grid-x grid-margin-x\">\n      <div class=\"cell\">\n        <div class=\"inline-alert warning\">\n          <div class=\"grid-x grid-margin-x align-middle\">\n\n            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--date\">\n\n                <div\n                     class=\"atom atom--time text-center\"\n                     data-time\n                     data-time-format=\"h:mma\"\n                     data-time-content=\".time--content\"\n                     data-time-clock=\".time--clock\"\n                     >\n                  <div class=\"fa fa-circle time--clock\">\n                    <div class=\"time--minute time--arms\"><\/div>\n                    <div class=\"time--hour time--arms\"><\/div>\n                  <\/div>\n                  <div class=\"time--content\">...<\/div>\n                <\/div>\n\n              <\/div>\n            <\/div>\n\n            <div class=\"cell large-auto\">\n              <div class=\"inline-alert--message\">\n                <div aria-live=\"polite\" role=\"alert\">\n                  <h3 class=\"headline\">Snow Emergency in effect. Day 2 rules apply.<\/h3>\n                  <div>Snow Emergency Day 2 rules are in effect from 8 a.m. until 8 p.m. tonight. Do not park on the even side of streets that are not Snow Emergency Routes. Do not park on either side of parkways.<\/div>\n                <\/div>\n              <\/div>\n            <\/div>\n\n            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--link\">\n\n\n                <a href=\"https://www.minneapolismn.gov/getting-around/snow/snow-emergencies/snow-parking-rules/\" class=\"atom atom--shadow-button button tiny short\" tabindex=\"0\">Snow Emergency Parking Rules<\/a>\n\n              <\/div>\n            <\/div>\n\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/section>",
 "id": "snow-emergency-html",
 "version": "2384425.0"
},{
 "date": "2022-02-22T15:16:43-06:00",
 "noticetype": "warning",
 "publishDate": "2022-02-23T20:00:00-06:00",
 "expireDate": "2022-02-24T08:00:00-06:00",
 "html": "<span id=\"d.en.28150\"><\/span>\n<section class=\"organism organism--inline-alert\" data-id=\"snow-emergency-html\" data-version=\"281508.0\">\n  <div class=\"grid-container fluid\">\n    <div class=\"grid-x grid-margin-x\">\n      <div class=\"cell\">\n        <div class=\"inline-alert warning\">\n          <div class=\"grid-x grid-margin-x align-middle\">\n\n            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--date\">\n\n                <div\n                     class=\"atom atom--time text-center\"\n                     data-time\n                     data-time-format=\"h:mma\"\n                     data-time-content=\".time--content\"\n                     data-time-clock=\".time--clock\"\n                     >\n                  <div class=\"fa fa-circle time--clock\">\n                    <div class=\"time--minute time--arms\"><\/div>\n                    <div class=\"time--hour time--arms\"><\/div>\n                  <\/div>\n                  <div class=\"time--content\">...<\/div>\n                <\/div>\n\n              <\/div>\n            <\/div>\n\n            <div class=\"cell large-auto\">\n              <div class=\"inline-alert--message\">\n                <div aria-live=\"polite\" role=\"alert\">\n                  <h3 class=\"headline\">Snow Emergency in effect. Day 2 ended at 8 p.m. Day 3 rules begin at 8 a.m.<\/h3>\n                  <div>A Snow Emergency is in effect. Between 8 p.m. - 8 a.m., move your vehicle from the odd side of streets that are not Snow Emergency Routes. Day 3 rules begin at 8 a.m.<\/div>\n                <\/div>\n              <\/div>\n            <\/div>\n\n            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--link\">\n\n\n                <a href=\"https://www.minneapolismn.gov/getting-around/snow/snow-emergencies/snow-parking-rules/\" class=\"atom atom--shadow-button button tiny short\" tabindex=\"0\">Snow Emergency Parking Rules<\/a>\n\n              <\/div>\n            <\/div>\n\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/section>",
 "id": "snow-emergency-html",
 "version": "281508.0"
},{
 "date": "2022-02-22T15:16:44-06:00",
 "noticetype": "warning",
 "publishDate": "2022-02-24T08:00:00-06:00",
 "expireDate": "2022-02-24T20:00:00-06:00",
 "html": "<span id=\"d.en.23900\"><\/span>\n<section class=\"organism organism--inline-alert\" data-id=\"snow-emergency-html\" data-version=\"2390014.0\">\n  <div class=\"grid-container fluid\">\n    <div class=\"grid-x grid-margin-x\">\n      <div class=\"cell\">\n        <div class=\"inline-alert warning\">\n          <div class=\"grid-x grid-margin-x align-middle\">\n\n            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--date\">\n\n                <div\n                     class=\"atom atom--time text-center\"\n                     data-time\n                     data-time-format=\"h:mma\"\n                     data-time-content=\".time--content\"\n                     data-time-clock=\".time--clock\"\n                     >\n                  <div class=\"fa fa-circle time--clock\">\n                    <div class=\"time--minute time--arms\"><\/div>\n                    <div class=\"time--hour time--arms\"><\/div>\n                  <\/div>\n                  <div class=\"time--content\">...<\/div>\n                <\/div>\n\n              <\/div>\n            <\/div>\n\n            <div class=\"cell large-auto\">\n              <div class=\"inline-alert--message\">\n                <div aria-live=\"polite\" role=\"alert\">\n                  <h3 class=\"headline\">Snow Emergency declared. Day 3 rules apply.<\/h3>\n                  <div>Snow Emergency Day 3 rules are in effect from 8 a.m. until 8 p.m. tonight. Do not park on the odd side of streets that are not Snow Emergency Routes.<\/div>\n                <\/div>\n              <\/div>\n            <\/div>\n\n            <div class=\"cell large-shrink\">\n              <div class=\"inline-alert--link\">\n\n\n                <a href=\"https://www.minneapolismn.gov/getting-around/snow/snow-emergencies/snow-parking-rules/\" class=\"atom atom--shadow-button button tiny short\" tabindex=\"0\">Snow Emergency Parking Rules<\/a>\n\n              <\/div>\n            <\/div>\n\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/section>",
 "id": "snow-emergency-html",2522323
 "version": "2390014.0"
},
        {
            "": ""
        }
    ]
}

Senors and Templates

sensor:
- platform: rest
  name: Snow Emergency Notice
  resource: https://www.minneapolismn.gov/media/minneapolismngov/site-assets/javascript/snow-emergency/emergency-en-1.json
  value_template: "OK"
  json_attributes_path: "$.notices[0]"
  json_attributes:
    - date
    - noticetype
    - publishDate
    - expireDate
    - html
    - id
    - version
- platform: rest
  name: Snow Emergency Declared
  resource: https://www.minneapolismn.gov/media/minneapolismngov/site-assets/javascript/snow-emergency/emergency-en-1.json
  value_template: "OK"
  json_attributes_path: "$.notices[1]"
  json_attributes:
    - date
    - noticetype
    - publishDate
    - expireDate
    - html
    - id
    - version
- platform: rest
  name: Snow Emergency Day1
  resource: https://www.minneapolismn.gov/media/minneapolismngov/site-assets/javascript/snow-emergency/emergency-en-1.json
  value_template: "OK"
  json_attributes_path: "$.notices[2]"
  json_attributes:
    - date
    - noticetype
    - publishDate
    - expireDate
    - html
    - id
    - version
- platform: rest
  name: Snow Emergency Day2
  resource: https://www.minneapolismn.gov/media/minneapolismngov/site-assets/javascript/snow-emergency/emergency-en-1.json
  value_template: "OK"
  json_attributes_path: "$.notices[3]"
  json_attributes:
    - date
    - noticetype
    - publishDate
    - expireDate
    - html
    - id
    - version
- platform: rest
  name: Snow Emergency Day2 Ended
  resource: https://www.minneapolismn.gov/media/minneapolismngov/site-assets/javascript/snow-emergency/emergency-en-1.json
  value_template: "OK"
  json_attributes_path: "$.notices[4]"
  json_attributes:
    - date
    - noticetype
    - publishDate
    - expireDate
    - html
    - id
    - version
- platform: rest
  name: Snow Emergency Day3
  resource: https://www.minneapolismn.gov/media/minneapolismngov/site-assets/javascript/snow-emergency/emergency-en-1.json
  value_template: "OK"
  json_attributes_path: "$.notices[5]"
  json_attributes:
    - date
    - noticetype
    - publishDate
    - expireDate
    - html
    - id
    - version
- platform: template
  sensors:
    snow_emergency_state:
      value_template: >-
        {% set cur = as_timestamp(now()) %}
        {% set notice_pub = as_timestamp(state_attr('sensor.snow_emergency_notice', 'publishDate')) %}
        {% set notice_exp = as_timestamp(state_attr('sensor.snow_emergency_notice', 'expireDate')) %}
        {% set declared_pub = as_timestamp(state_attr('sensor.snow_emergency_declared', 'publishDate')) %}
        {% set declared_exp = as_timestamp(state_attr('sensor.snow_emergency_declared', 'expireDate')) %}
        {% set day1_pub = as_timestamp(state_attr('sensor.snow_emergency_day1', 'publishDate')) %}
        {% set day1_exp = as_timestamp(state_attr('sensor.snow_emergency_day1', 'expireDate')) %}
        {% set day2_pub = as_timestamp(state_attr('sensor.snow_emergency_day2', 'publishDate')) %}
        {% set day2_exp = as_timestamp(state_attr('sensor.snow_emergency_day2', 'expireDate')) %}
        {% set day2_ended_pub = as_timestamp(state_attr('sensor.snow_emergency_day2_ended', 'publishDate')) %}
        {% set day2_ended_exp = as_timestamp(state_attr('sensor.snow_emergency_day2_ended', 'expireDate')) %}
        {% set day3_pub = as_timestamp(state_attr('sensor.snow_emergency_day3', 'publishDate')) %}
        {% set day3_exp = as_timestamp(state_attr('sensor.snow_emergency_day3', 'expireDate')) %}
        {% if (cur > declared_pub) and (cur < declared_exp)  %}
          DECLARED 
        {% elif (cur > day1_pub) and (cur < day1_exp)  %}
          DAY1
        {% elif (cur > day2_pub) and (cur < day2_exp)  %}
          DAY2
        {% elif (cur > day2_ended_pub) and (cur < day2_ended_exp)  %}
          DAY2_ENDED
        {% elif (cur > day3_pub) and (cur < day3_exp)  %}
          DAY3
        {% elif (cur > notice_pub) %}
          NOTICE
        {% else %}
          NOT WINTER
        {% endif %}
      icon_template: > 
        {% set state = states('sensor.snow_emergency_state') %}
        {% if state == 'DECARED' %}
          mdi:snowflake-alert
        {% elif state == 'DAY1' %}
          mdi:snowflake-alert
        {% elif state == 'DAY2' %}
          mdi:snowflake-variant
        {% elif state == 'DAY2_ENDED' %}
          mdi:snowflake-melt
        {% elif state == 'DAY3' %}
          mdi:snowflake-melt
        {% elif state == 'NOTICE' %}
          mdi:snowflake
        {% elif state == 'NOT WINTER' %}
          mdi:sun-snowflake
        {% else %}
          mdi:alert-box
        {% endif %}

Vertical Stack with custom:html-template-card

type: vertical-stack
cards:
  - type: button
    entity: sensor.snow_emergency_state
    show_state: true
  - type: custom:html-template-card
    ignore_line_breaks: true
    content: >
      {% if states('sensor.snow_emergency_state') == "DECLARED" %}
        {{ state_attr('sensor.snow_emergency_declared', 'html') }}
      {% elif states('sensor.snow_emergency_state') == "DAY1" %}
        {{ state_attr('sensor.snow_emergency_day1', 'html') }}
      {% elif states('sensor.snow_emergency_state') == "DAY2" %}
        {{ state_attr('sensor.snow_emergency_day2', 'html') }}
      {% elif states('sensor.snow_emergency_state') == "DAY2_ENDED" %}
        {{ state_attr('sensor.snow_emergency_day2_ended', 'html') }}
      {% elif states('sensor.snow_emergency_state') == "DAY3" %}
        {{ state_attr('sensor.snow_emergency_day3', 'html') }}
      {% elif states('sensor.snow_emergency_state') == "NOTICE" %}
        {{ state_attr('sensor.snow_emergency_notice', 'html') }}
      {% elif states('sensor.snow_emergency_state') == "NO WINTER" %}
        NO WINTER
      {% else %}
        FAIL
      {% endif %}


      <a href="https://apps.minneapolismn.gov/SnowEmergencyMapApp/"
      target="_blank"> Parking Map </a>

Screenshot

you can combine all the sensors into one rest call by using the rest integration.

I also noticed a typo in your icon_template code. You wrote “DECARED” instead of “DECLARED”.

Other than that I don’t see any other obvious improvements. Especially if it’s working as you expect.

@finity Thanks for your input. I now see how these can all be under the same rest resource call. However, I would like to combine this all into one sensor. I haven’t seen any documentation for dealing with looping through the json elements. I would like to first count the notice elements, if there is only one then I know there is no emergency in place. If there are more than one, I’d like to be able to handle getting all the attributes through the value_template function. Is this possible, or am I trying to use this function in a way it was never intended?

I wouldn’t know how to do that.

But if it’s working like you want it to and creates the output you want then I don’t see a reason to change it.

What’s the advantage you see in making it all into one sensor?

For one, it would allow me to use the count of the elements, in other sensors. It would also allow me to deduplicate a lot of the attribute code. Mainly, I just want to know if this approach is technically possible; and if it is, I want to learn how to use it.

I figured out how to get all of the data into one sensor, now I can work on munging the data.

rest:
  resource: https://www.minneapolismn.gov/media/minneapolismngov/site-assets/javascript/snow-emergency/emergency-en-1.json
  sensor:
  - name: snow testing 
    value_template: "foo"
    json_attributes_path: "."
    json_attributes:
      - notices

Then I can work with the arrays like this:

{{ state_attr('sensor.snow_testing', 'notices')[0].publishDate }}
1 Like

I managed to trim the sensor code down from 130 lines to 20. Now I’m on a new quest.

Is it technically possibly to make set variables available outside the scope of where they are called in the value_template? Is there, maybe, a way to include them (or something similar) as a json_attributes?

In the following code, I return the state for sensor.snow_testing as the value of the headline variable that is “set” in the if block (that is inside a for block). I have 2 other variables in this if block (message and link) that I would like to reuse (or just use in this case). How can I go about making these variables accessible to other sensors/cards/etc?

  - name: snow testing 
    json_attributes_path: "."
    json_attributes:
      - notices
    value_template: >-
      {% set cur = as_timestamp(now()) %}
      {% set regex_headline = '>.*<' %}
      {% set regex_message = '>.*<' %}
      {% set regex_link = '\"http.*\/\"' %}
      {% for data in value_json.notices %}
        {% set publish = as_timestamp(data.publishDate) | float(0) %}
        {% set expire = as_timestamp(data.expireDate) | float(0) %}
        {% set html = as_timestamp(data.html) %}
        {% if (cur > publish) and (cur < expire) %}
          {% set headline = data.html | regex_findall_index(regex_headline, 4) | regex_replace('[><]','') %}
          {% set message = data.html | regex_findall_index(regex_message, 5) | regex_replace('[><]','') %}
          {% set link = data.html | regex_findall_index(regex_link, 0) | regex_replace('"','') %}
          {{ headline }}
        {% endif %}
      {% endfor %}

sensor

{{ states('sensor.snow_testing') }}

value

Snow Emergency declared. Day 3 rules apply.