Back

Automatizare și card pentru avertizare meteo ANM

Acest tutorial te va ajuta să configurezi un sistem complet de monitorizare a alertelor meteo în Home Assistant. Este optimizat pentru județul Galați dar adaptabil pentru orice județ. Integrează datele oficiale ANM cu o filtrare locală și o afișare elegantă. Tutorialul se adresează celor cu un nivel mediu de cunoștințe despre Home Assistant, și se bazează pe integrarea Alertă ANM din GitHub, realizată de aurelmarius.

Cerințe Prealabile

  • Integrarea Alerta ANM creată de aurelmarius instalată. (disponibilă pe GitHub). ATENȚIE! Se instalează doar integrarea iar ca urmare veți avea un senzor numit sensor.avertizari_meteo_anm, adică doar pașii 1 și 2 din readme. Nu faceți senzorul propus de el și nici automatizarea. După instalarea integrării, dați restart la Home Assistant iar după repornire verificați în Developers Tools – State dacă aveți senzorul sensor.avertizari_meteo_anm.
  • Cardul custom fold-entity-row instalat din HACS.
  • Senzorii vor fi instalati în locația templates/ iar pentrtu a putea fi citiți trebuie să adăugați in configuration.yaml aceasta linie:
template: !include_dir_merge_list templates/

Pasul 1: Configurarea Senzorului Local (Galați) – înlocuiți în codul yaml, ”GL” cu județul vostru (BR, CV, BV etc).

Vom crea un senzor care „ascultă” senzorul general ANM și filtrează doar alertele care vizează județul interesat. Pentru asta vom face un fisier yaml cu File Editor. Acest fișier trebuie salvat în templates/. Dacă nu aveți acest folder îl creați cu File Editor. El trebuie să fie in același folder cu configuration.yaml.

Fișier: /config/templates/meteo_galati.yaml

- sensor:
    - name: "Avertizare Meteo județ"
      unique_id: sensor.avertizare_meteo_judet
      state: >
        {% set judet = 'GL' %}
        {% set avertizari = state_attr('sensor.avertizari_meteo_anm', 'avertizari') %}
        {% set alerta_jud = (avertizari | selectattr('judet', 'eq', judet) | selectattr('culoare', 'gt', '0') | list) %}
        {% if alerta_jud | length > 0 %}
          alerta
        {% else %}
          liniste
        {% endif %}
      attributes:
        mesaj: >
          {% set judet = 'GL' %}
          {% set avertizari = state_attr('sensor.avertizari_meteo_anm', 'avertizari') %}
          {% set luni = {'ianuarie':'01', 'februarie':'02', 'martie':'03', 'aprilie':'04', 'mai':'05', 'iunie':'06', 'iulie':'07', 'august':'08', 'septembrie':'09', 'octombrie':'10', 'noiembrie':'11', 'decembrie':'12'} %}
          {% set alerta_jud = (avertizari | selectattr('judet', 'eq', judet) | selectattr('culoare', 'gt', '0') | list) %}
          {% if alerta_jud | length > 0 %}
            {% set avertizare = alerta_jud[0] %}
            {% set culoare = 'Galben' if avertizare.culoare == '1' else 'Portocaliu' if avertizare.culoare == '2' else 'Rosu' if avertizare.culoare == '3' else 'Verde' %}
            {% set interval = avertizare.intervalul.split('–') %}
            {% if interval | length == 2 %}
              {% set inceput = interval[0].strip() %}
              {% set sfarsit = interval[1].strip().replace(';', '') %}
              {% set zi_inceput, luna_inceput = inceput.split(', ')[0].split(' ') if ' ' in inceput.split(', ')[0] else ('', '') %}
              {% set ora_inceput = inceput.split(', ')[1].replace('ora ', '').strip() if ', ' in inceput else '' %}
              {% set zi_sfarsit, luna_sfarsit = sfarsit.split(', ')[0].split(' ') if ' ' in sfarsit.split(', ')[0] else ('', '') %}
              {% set ora_sfarsit = sfarsit.split(', ')[1].replace('ora ', '').strip() if ', ' in sfarsit else '' %}
              {% set luna_inceput = luni.get(luna_inceput, None) %}
              {% set luna_sfarsit = luni.get(luna_sfarsit, None) %}
              {% if luna_inceput and luna_sfarsit and ora_inceput and ora_sfarsit %}
                {% set an_curent = now().year %}
                {% set data_inceput_dt = as_datetime(an_curent ~ '-' ~ luna_inceput ~ '-' ~ zi_inceput ~ 'T' ~ ora_inceput ~ ':00') %}
                {% set data_sfarsit_dt = as_datetime(an_curent ~ '-' ~ luna_sfarsit ~ '-' ~ zi_sfarsit ~ 'T' ~ ora_sfarsit ~ ':00') %}
                {% set azi = now().date() %}
                {% set maine = (now() + timedelta(days=1)).date() %}
                {% if data_inceput_dt.date() == azi -%}
                  Avertizare cod {{ culoare }} pentru Galați începând de azi, ora {{ data_inceput_dt.strftime('%H:%M') }}
                {%- elif data_inceput_dt.date() == maine -%}
                  Avertizare cod {{ culoare }} pentru Galați începând de mâine, ora {{ data_inceput_dt.strftime('%H:%M') }}
                {%- else -%}
                  Avertizare cod {{ culoare }} pentru Galați începând de {{ data_inceput_dt.strftime('%d %B') }}, ora {{ data_inceput_dt.strftime('%H:%M') }}
                {%- endif %}
                {%- if data_sfarsit_dt.date() == azi -%}
                  până azi, ora {{ data_sfarsit_dt.strftime('%H:%M') }}
                {%- elif data_sfarsit_dt.date() == maine -%}
                  până mâine, ora {{ data_sfarsit_dt.strftime('%H:%M') }}
                {%- else -%}
                  până la {{ data_sfarsit_dt.strftime('%d %B') }}, ora {{ data_sfarsit_dt.strftime('%H:%M') }}
                {%- endif %}
              {% else %}
                Datele de început sau sfârșit nu sunt valide.
              {% endif %}
            {% else %}
              Intervalul de avertizare nu este complet.
            {% endif %}
          {% else %}
            Nicio avertizare detectată.
          {% endif %}
        fenomene_vizate: >
          {% set judet = 'GL' %}
          {% set avertizari = state_attr('sensor.avertizari_meteo_anm', 'avertizari') %}
          {% set alerta_jud = (avertizari | selectattr('judet', 'eq', judet) | selectattr('culoare', 'gt', '0') | list) %}
          {% if alerta_jud | length > 0 %}
            {% set avertizare = alerta_jud[0] %}
            {% set mesaj_html = avertizare.mesaj %}
            {% set mesaj_curat = mesaj_html | regex_replace('<[^>]+>', '') | replace('&ndash;', '-') | replace('&icirc;', 'î') | replace('&acirc;', 'â') | replace('&Icirc;', 'Î') | replace('&Acirc;', 'Â') | replace('&nbsp;', ' ') | replace('&quot;', '\"') | replace('&lt;', '<') | replace('&gt;', '>') | replace('&amp;', '&') | replace('&rsquo;', '’') | replace('&lsquo;', '‘') | replace('&euro;', '€') | replace('&hellip;', '...') %}
            {% set fenomene = mesaj_curat | regex_findall('Fenomene vizate: ([^Z]+)') %}
            {{ fenomene | join(', ') }}
          {% else %}
            Nicio avertizare detectată.
          {% endif %}
        tip_cod: >
          {% set judet = 'GL' %}
          {% set avertizari = state_attr('sensor.avertizari_meteo_anm', 'avertizari') %}
          {% set alerta_jud = (avertizari | selectattr('judet', 'eq', judet) | selectattr('culoare', 'gt', '0') | list) %}
          {% if alerta_jud | length > 0 %}
            {% set avertizare = alerta_jud[0] %}
            {{ 'Galben' if avertizare.culoare == '1' else 'Portocaliu' if avertizare.culoare == '2' else 'Rosu' if avertizare.culoare == '3' else 'Verde' }}
          {% else %}
            Nicio avertizare detectată.
          {% endif %}

Pasul 2: Senzorul de Mesaj (Curățare Regex)

Acest senzor este esențial pentru estetică. El elimină toate bucățile de text inutile din mesajul ANM (care de obicei include toate culorile de alertă la un loc) și păstrează doar ce este relevant pentru culoarea curentă și județul de interes. Înlocuiți GL cu județul vostru.

Locație /config/templates/mesaj_meteo_galati.yaml

- sensor:
    - name: "Mesaj Meteo Galati"
      unique_id: mesaj_meteo_galati
      icon: mdi:alert-decagram
      
      # --- SECȚIUNEA NOUĂ (AVAILABILITY) ---
      # Dacă senzorul sursă e unknown/unavailable (ex: la restart), 
      # și acest senzor devine unavailable, blocând declanșarea automatizărilor.
      availability: >
        {{ states('sensor.avertizari_meteo_anm') not in ['unknown', 'unavailable', 'None'] }}

      state: >
        {% set gl = state_attr('sensor.avertizari_meteo_anm', 'avertizari') | selectattr('judet', 'eq', 'GL') | list %}
        {{ 'alerta' if gl | length > 0 else 'liniste' }}

      attributes:
        # Aici calculăm cel mai grav cod bazat pe ID-ul culorii din toate mesajele active
        # 3=Rosu, 2=Portocaliu, 1=Galben, 0=Verde
        tip_cod: >
          {% set gl = state_attr('sensor.avertizari_meteo_anm', 'avertizari') | selectattr('judet', 'eq', 'GL') | list %}
          {% set max_code = gl | map(attribute='culoare') | map('int') | max | default(0) %}
          {% if max_code == 3 %} Rosu
          {% elif max_code == 2 %} Portocaliu
          {% elif max_code == 1 %} Galben
          {% else %} Verde
          {% endif %}
        
        mesaj_complet: >
          {% set gl_list = state_attr('sensor.avertizari_meteo_anm', 'avertizari') | selectattr('judet', 'eq', 'GL') | list %}
          
          {% if gl_list | length > 0 %}
            {% set ns = namespace(text_final='') %}
            
            {% for item in gl_list %}
              {# 1. Curățăm HTML-ul de bază #}
              {% set msg_raw = item.mesaj | replace('<br />', '\n') | replace('</p>', '\n') | regex_replace('<[^>]*>', '') | replace('&nbsp;', ' ') | replace('&ndash;', '-') | trim %}
              
              {# 2. LOGICA DE FILTRARE: Ștergem părțile care nu corespund culorii curente #}
              {# Definim ce culoare are mesajul curent (1=Galben, 2=Portocaliu, 3=Roșu) #}
              {% set cod = item.culoare | int(0) %}
              
              {# Aplicăm filtre Regex pentru a elimina blocurile de text ale altor coduri #}
              {# Regex-ul caută "COD X" și șterge totul până la următorul "COD Y" sau finalul textului #}
              
              {% if cod == 1 %}
                 {# Dacă e GALBEN, ștergem Portocaliu și Roșu #}
                 {% set msg_raw = msg_raw | regex_replace('COD PORTOCALIU[\\s\\S]*?(?=COD|$)', '') %}
                 {% set msg_raw = msg_raw | regex_replace('COD ROSU[\\s\\S]*?(?=COD|$)', '') %}
                 {% set msg_raw = msg_raw | regex_replace('COD ROȘU[\\s\\S]*?(?=COD|$)', '') %}
              
              {% elif cod == 2 %}
                 {# Dacă e PORTOCALIU, ștergem Galben și Roșu #}
                 {% set msg_raw = msg_raw | regex_replace('COD GALBEN[\\s\\S]*?(?=COD|$)', '') %}
                 {% set msg_raw = msg_raw | regex_replace('COD ROSU[\\s\\S]*?(?=COD|$)', '') %}
                 {% set msg_raw = msg_raw | regex_replace('COD ROȘU[\\s\\S]*?(?=COD|$)', '') %}
              
              {% elif cod == 3 %}
                 {# Dacă e ROȘU, ștergem Galben și Portocaliu #}
                 {% set msg_raw = msg_raw | regex_replace('COD GALBEN[\\s\\S]*?(?=COD|$)', '') %}
                 {% set msg_raw = msg_raw | regex_replace('COD PORTOCALIU[\\s\\S]*?(?=COD|$)', '') %}
              {% endif %}

              {# 3. Curățăm eventualele rânduri goale duble rămase după tăiere #}
              {% set msg_final = msg_raw | regex_replace('\n\s*\n', '\n\n') | trim %}

              {# 4. Adăugăm la textul final #}
              {% set ns.text_final = ns.text_final ~ '\n\n' ~ msg_final %}
            {% endfor %}
            
            {{ ns.text_final | trim }}
          {% else %}
            Nu sunt avertizări active pentru județul Galați.
          {% endif %}

Pasul 3: Configurarea Cardului în Interfață (Dashboard)

Vom folosi cardul fold-entity-row pentru a păstra interfața curată. Mesajul detaliat va fi ascuns sub un meniu extensibil. Trebuie instalat din HACS. Înlocuiți sensor.avertizare_meteo_galati și sensor.mesaj_meteo_galati cu senzorii creați mai sus pe care i-ați denumit după județul vostru. Adaugați un card Manual și inserați codul yaml de mai jos.

Codul pentru Cardul Lovelace:

type: conditional
conditions:
  - condition: state
    entity: sensor.avertizare_meteo_judet
    state: alerta
card:
  type: custom:fold-entity-row
  padding: 0
  clickable: true
  head:
    type: custom:button-card
    entity: sensor.mesaj_meteo_galati
    name: AVERTIZARE METEO
    icon: mdi:alert
    show_name: true
    show_icon: true
    show_state: false
    tap_action:
      action: none
    styles:
      card:
        - background-color: transparent
        - box-shadow: none
        - padding: 0px
        - margin: 0px
        - pointer-events: none
      icon:
        - width: 22px
        - height: 22px
        - color: |
            [[[ 
              const msg = (entity.attributes.mesaj_complet || '').toString().toLowerCase();
              if (msg.includes('rosu') || msg.includes('roșu')) return '#e74c3c';
              if (msg.includes('portocaliu')) return '#e67e22';
              if (msg.includes('galben')) return '#f1c40f';
              return 'var(--primary-text-color)';
            ]]]
        - animation: blink 1s ease-in-out infinite
      name:
        - font-weight: 900
        - font-size: 16px
        - text-transform: uppercase
        - color: |
            [[[ 
              const msg = (entity.attributes.mesaj_complet || '').toString().toLowerCase();
              if (msg.includes('rosu') || msg.includes('roșu')) return '#e74c3c';
              if (msg.includes('portocaliu')) return '#e67e22';
              if (msg.includes('galben')) return '#f1c40f';
              return 'var(--primary-text-color)';
            ]]]
  entities:
    - type: custom:button-card
      entity: sensor.mesaj_meteo_galati
      show_name: false
      show_label: true
      show_state: false
      show_icon: false
      label: |
        [[[ 
          // 1. PRELUARE DATE
          var text_complet = entity.attributes.mesaj_complet || 'Nu există detalii.';
          var sensor_ids = states['sensor.anm_avertizare_id'];
          var lista_ids = [];

          if (sensor_ids && sensor_ids.state && sensor_ids.state != '0' && sensor_ids.state != 'unavailable') {
              lista_ids = sensor_ids.state.split(',');
          }

          var html_final = '';
          
          // 2. LOGICA SMART
          const regex = /MESAJ\s+(\d+)([\s\S]*?)(?=(?:MESAJ\s+\d+)|$)/gi;
          let match;
          let gasit_mesaje_multiple = false;

          while ((match = regex.exec(text_complet)) !== null) {
              gasit_mesaje_multiple = true;
              let numar_mesaj = parseInt(match[1]);
              let msg = match[2];
              
              // --- A. Procesare Text ---
              let highlightColor = 'var(--primary-text-color)';
              const lowerMsg = msg.toLowerCase();
              if (lowerMsg.includes('rosu') || lowerMsg.includes('roșu')) highlightColor = '#e74c3c';
              else if (lowerMsg.includes('portocaliu')) highlightColor = '#e67e22';
              else if (lowerMsg.includes('galben')) highlightColor = '#f1c40f';

              // Formatare subtitluri
              msg = msg.replace(/(\d{2})(Fenomene)/g, '$1<br>$2');
              msg = msg.replace(/(viscol)(Zone)/g, '$1<br>$2');
              msg = msg.replace(/(textului)/g, '$1<br>');
              msg = msg.replace(/Interval de valabilitate:?/g, `<br>• <b style="color: ${highlightColor}">Interval:</b>`);
              msg = msg.replace(/Fenomene(?: și zone)? vizate:?/g, `<br>• <b style="color: ${highlightColor}">Fenomene:</b>`);
              msg = msg.replace(/Zone afectate:?/g, `<br>• <b style="color: ${highlightColor}">Zone:</b>`);
              
              // Formatare COD (rând nou)
              msg = msg.replace(/COD GALBEN/g, '<br><span style="background-color: #f1c40f; color: black; padding: 2px 4px; border-radius: 4px; font-weight: bold;">COD GALBEN</span>');
              msg = msg.replace(/COD PORTOCALIU/g, '<br><span style="background-color: #e67e22; color: black; padding: 2px 4px; border-radius: 4px; font-weight: bold;">COD PORTOCALIU</span>');
              msg = msg.replace(/COD ROSU/g, '<br><span style="background-color: #e74c3c; color: white; padding: 2px 4px; border-radius: 4px; font-weight: bold;">COD ROSU</span>');
              
              // Formatare LOCAȚII (Colorate + Subliniate)
              const regexCuvinte = /(sudul\s+Moldovei|Moldov[a-zĂÂÎȘȚăâîșț]*|Gala[tț]i[a-zĂÂÎȘȚăâîșț]*|sud-est[a-zĂÂÎȘȚăâîșț\-]*)/gi;
              msg = msg.replace(regexCuvinte, `<b style="color: ${highlightColor}; text-decoration: underline;">$&</b>`);

              html_final += `<div style="margin-bottom: 10px; border-left: 4px solid ${highlightColor}; padding-left: 10px;">
                                <div style="font-weight: 900; text-decoration: underline; margin-bottom: 5px; color: ${highlightColor}">MESAJ ${numar_mesaj}</div>
                                <div style="color: var(--primary-text-color);">${msg}</div>
                             </div>`;

              // --- B. Procesare Hartă ---
              let mapIndex = numar_mesaj - 1;
              if (mapIndex < lista_ids.length) {
                  var id = lista_ids[mapIndex];
                  if (id && id.trim() != '') {
                      var url_anm = 'www.meteoromania.ro/wp-content/plugins/meteo/harti/harta.svg.php?id_avertizare=' + id;
                      var url_img = 'https://images.weserv.nl/?url=' + url_anm;
                      html_final += `<div style="margin-bottom: 25px; margin-top: 5px;">
                                       <img src="${url_img}" style="width: 96%; display: block; margin: 0 auto; border-radius: 8px; border: 1px solid #ddd; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
                                     </div>`;
                  }
              }
          }

          // 3. CAZUL DEFAULT
          if (!gasit_mesaje_multiple) {
               let msg = text_complet;
               let highlightColor = 'var(--primary-text-color)';
               const lowerMsg = msg.toLowerCase();
               if (lowerMsg.includes('rosu') || lowerMsg.includes('roșu')) highlightColor = '#e74c3c';
               else if (lowerMsg.includes('portocaliu')) highlightColor = '#e67e22';
               else if (lowerMsg.includes('galben')) highlightColor = '#f1c40f';
               
               msg = msg.replace(/(\d{2})(Fenomene)/g, '$1<br>$2');
               msg = msg.replace(/(viscol)(Zone)/g, '$1<br>$2');
               msg = msg.replace(/(textului)/g, '$1<br>');
               msg = msg.replace(/Interval de valabilitate:?/g, `<br>• <b style="color: ${highlightColor}">Interval:</b>`);
               msg = msg.replace(/Fenomene(?: și zone)? vizate:?/g, `<br>• <b style="color: ${highlightColor}">Fenomene:</b>`);
               msg = msg.replace(/Zone afectate:?/g, `<br>• <b style="color: ${highlightColor}">Zone:</b>`);
               
               msg = msg.replace(/COD GALBEN/g, '<br><span style="background-color: #f1c40f; color: black; padding: 2px 4px; border-radius: 4px; font-weight: bold;">COD GALBEN</span>');
               msg = msg.replace(/COD PORTOCALIU/g, '<br><span style="background-color: #e67e22; color: black; padding: 2px 4px; border-radius: 4px; font-weight: bold;">COD PORTOCALIU</span>');
               msg = msg.replace(/COD ROSU/g, '<br><span style="background-color: #e74c3c; color: white; padding: 2px 4px; border-radius: 4px; font-weight: bold;">COD ROSU</span>');
               
               const regexCuvinte = /(sudul\s+Moldovei|Moldov[a-zĂÂÎȘȚăâîșț]*|Gala[tț]i[a-zĂÂÎȘȚăâîșț]*|sud-est[a-zĂÂÎȘȚăâîșț\-]*)/gi;
               msg = msg.replace(regexCuvinte, `<b style="color: ${highlightColor}; text-decoration: underline;">$&</b>`);

               html_final += `<div style="margin-bottom: 10px; border-left: 4px solid ${highlightColor}; padding-left: 10px;">
                                <div style="color: var(--primary-text-color);">${msg}</div>
                              </div>`;
               
               if (lista_ids.length > 0) {
                  var id = lista_ids[0];
                  var url_anm = 'www.meteoromania.ro/wp-content/plugins/meteo/harti/harta.svg.php?id_avertizare=' + id;
                  var url_img = 'https://images.weserv.nl/?url=' + url_anm;
                  html_final += `<div style="margin-bottom: 25px;"><img src="${url_img}" style="width: 96%; display: block; margin: 0 auto; border-radius: 8px; border: 1px solid #ddd; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"></div>`;
               } else {
                  var timestamp = new Date().getTime();
                  var url_png = 'https://images.weserv.nl/?url=www.meteoromania.ro/images/avertizari/harta.png&v=' + timestamp;
                  html_final += `<div style="margin-top: 15px;"><img src="${url_png}" style="width: 96%; display: block; margin: 0 auto; border-radius: 8px; border: 1px solid #ddd; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"></div>`;
               }
          }

          return html_final;
        ]]]
      styles:
        card:
          - padding: 16px
          - margin-top: 10px
          - border-radius: 12px
          - box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2)
        label:
          - text-align: left
          - font-size: 13px
          - line-height: 1.5
          - color: var(--secondary-text-color)
          - white-space: normal
      tap_action:
        action: url
        url_path: https://www.meteoromania.ro/avertizari/

Pasul 4: Exemplu de automatizare a notificărilor (iPhone + HTML5)

Această automatizare trimite o notificare cu detalii despre cod, interval și fenomene. Este configurată să fie critică (sunet special) pentru Cod Portocaliu și Roșu. Înlocuiți sensor.avertizare_meteo_galati și sensor.mesaj_meteo_galati cu senzorii creați mai sus pe care i-ați denumit după județul vostru.

Configurație: Settings -> Automations

alias: Notificare Meteo Detaliată ANM (iPhone + HTML5)
description: >-
  Trimite Intervalul și Fenomenele. Verifică validitatea senzorului sursă pentru
  a evita erorile la restart.
triggers:
  - trigger: state
    entity_id: sensor.mesaj_meteo_galati
conditions:
  - condition: state
    entity_id: sensor.mesaj_meteo_galati
    state: alerta
  - condition: template
    value_template: >-
      {{ states('sensor.avertizari_meteo_anm') not in ['unavailable', 'unknown',
      'None'] }}
  - condition: template
    value_template: |-
      {% if trigger.from_state is not none %}
        {% set old_state = trigger.from_state.state %}
        {% set old_msg = trigger.from_state.attributes.mesaj_complet | default('') %}
        {% set new_msg = trigger.to_state.attributes.mesaj_complet | default('') %}
        
        {# Ignorăm dacă senzorul de mesaj vine el însuși din 'unknown' #}
        {% if old_state in ['unavailable', 'unknown'] %}
          false
        {% else %}
          {{ old_state != 'alerta' or old_msg != new_msg }}
        {% endif %}
      {% else %}
        false
      {% endif %}
    enabled: true
actions:
  - action: homeassistant.update_entity
    target:
      entity_id: sensor.anm_avertizare_id
  - action: notify.mobile_app_iphone_16_pro
    data:
      title: >-
        {% set text = state_attr('sensor.mesaj_meteo_galati', 'mesaj_complet') |
        lower | default('') %}  {% if 'rosu' in text or 'roșu' in text %}
          🚨 COD ROȘU GALAȚI #modifica judetul
        {% elif 'portocaliu' in text %}
          🟠 COD PORTOCALIU GALAȚI #modifica judetul
        {% elif 'galben' in text %}
          ⚠️ COD GALBEN GALAȚI #modifica judetul
        {% else %}
          ℹ️ Informare Meteo Galați #modifica judetul
        {% endif %}
      message: >-
        {# Curățare și formatare text #} {% set raw_text =
        state_attr('sensor.mesaj_meteo_galati', 'mesaj_complet') | default('')
        %} {% set text = raw_text | replace('&icirc;', 'î') | replace('&Icirc;',
        'Î') | replace('&acirc;', 'â') | replace('&Acirc;', 'Â') |
        replace('&#238;', 'î') %}

        {% set split_interval = text.split('Interval de valabilitate:') %} {% if
        split_interval | length > 1 %}
          {% set interval = split_interval[1].split('Fenomene')[0] | trim %}
        {% else %}
          {% set interval = "Vezi aplicația" %}
        {% endif %}

        {% set split_fenomene = text.split('Fenomene') %} {% if split_fenomene |
        length > 1 %}
          {% set raw_fen = split_fenomene[1].split('Zone')[0] | replace('vizate:', '') | replace('și zone vizate:', '') | trim %}
          {% set lista = raw_fen.split(',') %}
          {% set fenomene_formatat = namespace(out='') %}
          {% for item in lista %}
            {% set fenomene_formatat.out = fenomene_formatat.out + '\n- ' + item | trim %}
          {% endfor %}
          {% set fenomene_final = fenomene_formatat.out %}
        {% else %}
          {% set fenomene_final = " Vezi aplicația" %}
        {% endif %}

        🕒 {{ interval }}

        💨 Fenomene vizate:{{ fenomene_final }}
      data:
        url: http://ha.local/dashboard
        push:
          sound:
            name: >-
              {% set text = state_attr('sensor.mesaj_meteo_galati',
              'mesaj_complet') | lower | default('') %} {% if 'rosu' in text or
              'roșu' in text or 'portocaliu' in text %}
                critical
              {% else %}
                default
              {% endif %}
            volume: 1
  - action: notify.html5
    data:
      title: >-
        {% set text = state_attr('sensor.mesaj_meteo_galati', 'mesaj_complet') |
        lower | default('') %}  {% if 'rosu' in text or 'roșu' in text %}
          🚨 COD ROȘU GALAȚI #modifica judetul
        {% elif 'portocaliu' in text %}
          🟠 COD PORTOCALIU GALAȚI #modifica judetul
        {% elif 'galben' in text %}
          ⚠️ COD GALBEN GALAȚI #modifica judetul
        {% else %}
          ℹ️ Informare Meteo Galați #modifica judetul
        {% endif %}
      message: >-
        {% set raw_text = state_attr('sensor.mesaj_meteo_galati',
        'mesaj_complet') | default('') %} {% set text = raw_text |
        replace('&icirc;', 'î') | replace('&Icirc;', 'Î') | replace('&acirc;',
        'â') | replace('&Acirc;', 'Â') | replace('&#238;', 'î') %}

        {% set split_interval = text.split('Interval de valabilitate:') %} {% if
        split_interval | length > 1 %}
          {% set interval = split_interval[1].split('Fenomene')[0] | trim %}
        {% else %}
          {% set interval = "Vezi aplicația" %}
        {% endif %}

        {% set split_fenomene = text.split('Fenomene') %} {% if split_fenomene |
        length > 1 %}
          {% set raw_fen = split_fenomene[1].split('Zone')[0] | replace('vizate:', '') | replace('și zone vizate:', '') | trim %}
          {% set lista = raw_fen.split(',') %}
          {% set fenomene_formatat = namespace(out='') %}
          {% for item in lista %}
            {% set fenomene_formatat.out = fenomene_formatat.out + '\n- ' + item | trim %}
          {% endfor %}
          {% set fenomene_final = fenomene_formatat.out %}
        {% else %}
          {% set fenomene_final = " Vezi aplicația" %}
        {% endif %}

        🕒 {{ interval }}

        💨 Fenomene vizate:{{ fenomene_final }}
      data:
        tag: alerta-meteo-galati
        url: http://ha.local/dashboard
        icon: /static/icons/weather_alert.png
mode: single

Rezultat Final:

  1. Dashboard Curat: Cardul apare în dashboard doar când e o alertă activă în județul setat.
  2. Atenție Sporită: Telefonul sună critic la Cod Roșu.
  3. Informație Utilă: Notificarea nu îți spune doar că e alertă, ci îți listează exact fenomenele (ex: – Grindină, – Vijelie) și orele, precum și harta zonelor de interes publicată de meteoromania.ro.

Bonus: Automatizare care te notifică la finalul avertizării meteo

alias: Notificare Meteo Expirată (iPhone + HTML5)
description: >-
  Trimite notificare pe iPhone și HTML5 când alerta meteo a trecut și senzorul
  revine la starea 'liniste'.
triggers:
  - trigger: state
    entity_id: sensor.mesaj_meteo_galati
    to: liniste
conditions:
  - condition: template
    value_template: >-
      {{ states('sensor.avertizari_meteo_anm') not in ['unavailable', 'unknown',
      'None'] }}
  - condition: template
    value_template: |-
      {% if trigger.from_state is not none %}
        {% set old_state = trigger.from_state.state %}
        {% set old_msg = trigger.from_state.attributes.mesaj_complet | default('') %}
        {% set new_msg = trigger.to_state.attributes.mesaj_complet | default('') %}
        
        {# Ignorăm dacă senzorul de mesaj vine el însuși din 'unknown' #}
        {% if old_state in ['unavailable', 'unknown'] %}
          false
        {% else %}
          {{ old_state != 'liniste' or old_msg != new_msg }}
        {% endif %}
      {% else %}
        false
      {% endif %}
actions:
  - action: notify.mobile_app_iphone_16_pro
    data:
      title: ✅ Alertă Meteo Finalizată
      message: Nu mai sunt avertizări meteo active în Galați. Vremea s-a liniștit.
      data:
        url: http://ha.local/dashboard0
        push:
          sound: default
  - action: notify.html5
    data:
      title: ✅ Alertă Meteo Finalizată
      message: Nu mai sunt avertizări meteo active în Galați. Vremea s-a liniștit.
      data:
        url: http://ha.local/dashboard
        tag: alerta-meteo-galati
mode: single