Environment Canada Integration and Colour-Coded Alerts

UPDATE 2026-04-15: Depending on the wording of the alerts, the code below may not work. See my post below.

I’m using the code below in my Dashboard to display weather alerts from the Environment Canada integration. Card-mod and auto-entities must be installed.

It will pulse a solid frame of red, orange or yellow: around the row, with red pulses being the fastest. The background will be a translucent color of the highest alert color. It will sort by red, orange or yellow alerts followed by warnings, advisory and watches. Statements will be grey and will not pulse. Note that this will only list two alerts per alert type.

The appropriate icon will be used and that icon will match the color of the alert. Alerts are clickable - you will need replace “report_e.html?onrm26” with the correct link for your area

Enjoy.

type: custom:mod-card
card_mod:
  style: >
    {% set warn = state_attr('sensor.windsor_environment_canada_warnings',
    'alert_1') | string + " " +
    state_attr('sensor.windsor_environment_canada_warnings', 'alert_2') | string
    %}  {% set watch = state_attr('sensor.windsor_environment_canada_watches',
    'alert_1') | string + " " +
    state_attr('sensor.windsor_environment_canada_watches', 'alert_2') | string
    %}  {% set adv = state_attr('sensor.windsor_environment_canada_advisory',
    'alert_1') | string + " " +
    state_attr('sensor.windsor_environment_canada_advisory', 'alert_2') | string
    %}  {% set stat = state_attr('sensor.windsor_environment_canada_statements',
    'alert_1') | string + " " +
    state_attr('sensor.windsor_environment_canada_statements', 'alert_2') |
    string %}  {% set combined = warn + " " + watch + " " + adv + " " + stat %}

    {% if combined and 'None' not in combined or combined | trim != "" %}
      {% set color = 'red' if 'Red' in combined 
                else 'orange' if 'Orange' in combined 
                else 'yellow' if 'Yellow' in combined 
                else 'grey' if 'Statement' in combined or (stat and 'None' not in stat)
                else none %}
      {% set pulse_speed = '1s' if 'Red' in combined 
                      else '2s' if 'Orange' in combined 
                      else '3s' if 'Yellow' in combined
                      else '0s' %}
      
      ha-card {
        {% if color and color != 'grey' %} animation: pulse {{ pulse_speed }} infinite; {% endif %}
        background: {{ 'rgba(255, 0, 0, 0.2)' if color == 'red' 
                       else 'rgba(255, 165, 0, 0.2)' if color == 'orange' 
                       else 'rgba(255, 255, 0, 0.2)' if color == 'yellow' 
                       else 'rgba(128, 128, 128, 0.2)' if color == 'grey' 
                       else 'none' }};
        border: 2px solid {{ color if color else 'transparent' }};
      }
      @keyframes pulse {
        0% { box-shadow: 0 0 0 0px {{ color }}; }
        70% { box-shadow: 0 0 0 15px rgba(0, 0, 0, 0); }
        100% { box-shadow: 0 0 0 0px rgba(0, 0, 0, 0); }
      }
    {% endif %}
card:
  type: custom:auto-entities
  show_empty: false
  card:
    type: entities
    theme: Dark
    card_mod:
      style: >
        ha-card { background: none !important; border: none !important;
        box-shadow: none !important; font-size: larger !important} .card-content
        { padding: 8px !important; }
  filter:
    template: |
      {% set sensors = [
        'sensor.windsor_environment_canada_warnings',
        'sensor.windsor_environment_canada_watches',
        'sensor.windsor_environment_canada_advisory',
        'sensor.windsor_environment_canada_statements'
      ] %}

      {% set ns = namespace(rows=[]) %}

      {% for s in sensors %}
        {% for i in range(1, 5) %}
          {% set attr = 'alert_' ~ i %}
          {% set text = state_attr(s, attr) %}
          {% if text and text != 'None' and text | trim != "" %}
            
            {# Define sorting weights: Color first, then Type #}
            {% set color_prio = 10 if 'Red' in text else 20 if 'Orange' in text else 30 if 'Yellow' in text else 40 %}
            {% set type_prio = 1 if 'warnings' in s else 2 if 'watches' in s else 3 if 'advisory' in s else 4 %}
            {% set sort_score = color_prio + type_prio %}

            {% set row_color = 'red' if 'Red' in text else 'orange' if 'Orange' in text else 'yellow' if 'Yellow' in text else 'grey' %}
            {% set row_icon = 'mdi:alert' if row_color == 'red' else 'mdi:alert-rhombus' if row_color == 'orange' else 'mdi:alert-circle' if row_color == 'yellow' else 'mdi:alert-box' %}
            
            {% set ns.rows = ns.rows + [{
              "sort_by": sort_score,
              "type": "attribute",
              "attribute": "hide_state",
              "entity": s,
              "name": text,
              "icon": row_icon,
              "tap_action": {
                "action": "url",
                "url_path": "https://weather.gc.ca/warnings/report_e.html?onrm26"
              },
              "card_mod": {
                "style": "state-badge { color: " ~ row_color ~ " !important; } :host { --card-mod-icon-color: " ~ row_color ~ "; }"
              }
            }] %}
          {% endif %}
        {% endfor %}
      {% endfor %}

      {# This sorts by the combined color + type score #}
      {{ ns.rows | sort(attribute='sort_by') }}

3 Likes

Nice, I’m going to steal your pulse css for my EC alerts badge. I have a different solution for this that I’ve been meaning to share that includes the actual alert text via markdown, even have my VPE ask me if I want to hear the details on each change. I’ll drop a link here once I get to sharing it later this week or weekend.

Hoping you didn’t get as badly hammered on Sunday as we did in the Toronto to Hamilton area.

Update: It appears that Environment Canada has changed the wording of the alert_1 attribute in that the color indicator in the text is not being included. For example, the alert_1 attribute would be “Yellow Warning - Severe Thunderstorm Watch” but over the past few days the alert_1 attribute is “Severe Thunderstorm”.

This may be a glitch or it be a change in how this information is being made available. The above code will not work properly if the words ‘Red’, ‘Orange’ or ‘Yellow’ are not in the alert text.

I’m going to do more investigation into what exactly is happening.

Are you sure it was an alert and not just a statement? I pulled up the alert overlay on the radar to find an area that had coloured messages and when I navigated there the page definitely has a colour in the text, standard statements (grey?) don’t.

This was just now

I should have been more clear. It is the text in the alert_1 attribute for the warnings and watches sensor that is missing the color code wording. In the past, it would read “Yellow Warning - Severe Thunderstorm Warning”. Over the past few days, the text in that attribute is “Severe Thunderstorm Warning”.

My code above relies on “Red”, “Orange” or “Yellow” being in the text of the alert_1 attribute.

Would be interested to see what you built.

I built this intergration.

Going to be honest, it was coded by AI but I’ve been using this for a few months now, thought I would publish it for others.

2 Likes

You know I had the whole thing written up and ready to share when michaeldavie released a HACS version of the integration, no need for it now so I shelved the whole thing.