Forked from alexsotoaguilera/alternative-plant-problem-notification.yaml
Last active
February 27, 2026 16:38
-
-
Save lucaam/92bc73d01d3d527438eb21a834adb2bd to your computer and use it in GitHub Desktop.
Home Assistant Blueprint: Alternative Plant problem notification
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| blueprint: | |
| name: "Plant Problem Notifications / Notifiche Problemi Piante" | |
| description: | | |
| IT: Controlla lo stato delle piante e invia notifiche chiare per ogni problema. | |
| EN: Monitors plant status and sends clear notifications for each problem. | |
| Requires: https://github.com/Olen/homeassistant-plant | |
| domain: automation | |
| author: Claude (based on blueprint by Alex Soto Aguilera) | |
| homeassistant: | |
| min_version: 2022.4.0 | |
| input: | |
| language: | |
| name: "Language / Lingua" | |
| description: "EN: Choose notification language. IT: Scegli la lingua delle notifiche." | |
| default: "Italiano" | |
| selector: | |
| select: | |
| options: | |
| - "Italiano" | |
| - "English" | |
| notification_time: | |
| name: "Check time / Orario di controllo" | |
| description: "EN: Time to check all plants. IT: Orario in cui si controllano le piante." | |
| default: "09:00:00" | |
| selector: | |
| time: {} | |
| exclude: | |
| name: "Excluded plants / Piante da escludere" | |
| description: "EN: Plants to exclude. IT: Piante da non notificare." | |
| default: [] | |
| selector: | |
| entity: | |
| domain: plant | |
| multiple: true | |
| devices_to_notify: | |
| name: "Devices to notify / Dispositivi da notificare" | |
| description: "EN: Devices with the HA app installed. IT: Dispositivi con l'app HA installata." | |
| default: [] | |
| selector: | |
| device: | |
| filter: | |
| - integration: mobile_app | |
| multiple: true | |
| notify_low_moisture: | |
| name: "Low moisture / Poca acqua" | |
| description: "EN: Soil too dry. IT: Terreno troppo secco." | |
| default: true | |
| selector: | |
| boolean: {} | |
| notify_high_moisture: | |
| name: "High moisture / Troppa acqua" | |
| description: "EN: Soil too wet. IT: Terreno troppo bagnato." | |
| default: true | |
| selector: | |
| boolean: {} | |
| notify_low_illuminance: | |
| name: "Low light / Poca luce" | |
| description: "EN: Not enough light. IT: Luce insufficiente." | |
| default: true | |
| selector: | |
| boolean: {} | |
| notify_high_illuminance: | |
| name: "Too much light / Troppa luce" | |
| description: "EN: Too much light. IT: Troppa luce." | |
| default: true | |
| selector: | |
| boolean: {} | |
| notify_low_temperature: | |
| name: "Low temperature / Temperatura bassa" | |
| description: "EN: Temperature too low. IT: Temperatura troppo bassa." | |
| default: true | |
| selector: | |
| boolean: {} | |
| notify_high_temperature: | |
| name: "High temperature / Temperatura alta" | |
| description: "EN: Temperature too high. IT: Temperatura troppo alta." | |
| default: true | |
| selector: | |
| boolean: {} | |
| notify_low_humidity: | |
| name: "Low air humidity / Umidita aria bassa" | |
| description: "EN: Air humidity too low. IT: Umidita dell'aria troppo bassa." | |
| default: false | |
| selector: | |
| boolean: {} | |
| notify_high_humidity: | |
| name: "High air humidity / Umidita aria alta" | |
| description: "EN: Air humidity too high. IT: Umidita dell'aria troppo alta." | |
| default: false | |
| selector: | |
| boolean: {} | |
| notify_low_conductivity: | |
| name: "Low nutrients / Pochi nutrienti" | |
| description: "EN: Low conductivity, needs fertilizer. IT: Conduttivita bassa, serve fertilizzante." | |
| default: false | |
| selector: | |
| boolean: {} | |
| notify_high_conductivity: | |
| name: "Too many nutrients / Troppi nutrienti" | |
| description: "EN: High conductivity, too much fertilizer. IT: Conduttivita alta, troppo fertilizzante." | |
| default: false | |
| selector: | |
| boolean: {} | |
| # ── Variabili globali (non si referenziano tra loro, quindi OK in un blocco) ─── | |
| variables: | |
| language_input: !input language | |
| language: "{{ 'it' if language_input == 'Italiano' else 'en' }}" | |
| exclude_list: !input exclude | |
| notify_low_moisture: !input notify_low_moisture | |
| notify_high_moisture: !input notify_high_moisture | |
| notify_low_illuminance: !input notify_low_illuminance | |
| notify_high_illuminance: !input notify_high_illuminance | |
| notify_low_temperature: !input notify_low_temperature | |
| notify_high_temperature: !input notify_high_temperature | |
| notify_low_humidity: !input notify_low_humidity | |
| notify_high_humidity: !input notify_high_humidity | |
| notify_low_conductivity: !input notify_low_conductivity | |
| notify_high_conductivity: !input notify_high_conductivity | |
| notification_title: > | |
| {% if language == 'it' %}🌱 Attenzione alla tua pianta! | |
| {% else %}🌱 Plant alert! | |
| {% endif %} | |
| plants_with_problems: > | |
| {% set excluded = exclude_list if exclude_list is iterable and exclude_list is not string else [] %} | |
| {% set ns = namespace(result=[]) %} | |
| {% for s in states.plant %} | |
| {% if s.state == 'problem' and s.entity_id not in excluded %} | |
| {% set ns.result = ns.result + [s.entity_id] %} | |
| {% endif %} | |
| {% endfor %} | |
| {{ ns.result }} | |
| trigger: | |
| - platform: time | |
| at: !input notification_time | |
| condition: | |
| - condition: template | |
| value_template: "{{ plants_with_problems | length > 0 }}" | |
| action: | |
| - repeat: | |
| for_each: !input devices_to_notify | |
| sequence: | |
| - variables: | |
| device_to_notify: "{{ repeat.item }}" | |
| - repeat: | |
| for_each: "{{ plants_with_problems }}" | |
| sequence: | |
| # ── STEP 1: identita e liste entita ───────────────────────────── | |
| # Queste non si referenziano tra loro → OK in un solo blocco | |
| - variables: | |
| plant_entity: "{{ repeat.item }}" | |
| plant_name: "{{ state_attr(repeat.item, 'friendly_name') | default(repeat.item) }}" | |
| plant_sensors: > | |
| {{ device_entities(device_id(repeat.item)) | |
| | select('match', '^sensor\\.') | list }} | |
| plant_numbers: > | |
| {{ device_entities(device_id(repeat.item)) | |
| | select('match', '^number\\.') | list }} | |
| # ── STEP 2: valori correnti ────────────────────────────────────── | |
| # Ora plant_sensors e plant_numbers sono gia risolti dallo step 1 | |
| - variables: | |
| cur_moisture: > | |
| {% set e = plant_sensors | select('search', 'moisture|soil') | list %} | |
| {{ states(e[0]) | float(-1) if e else -1 }} | |
| cur_illuminance: > | |
| {% set e = plant_sensors | select('search', 'illuminance|light|lux') | list %} | |
| {{ states(e[0]) | float(-1) if e else -1 }} | |
| cur_temperature: > | |
| {% set e = plant_sensors | select('search', 'temperature|temp') | list %} | |
| {{ states(e[0]) | float(-999) if e else -999 }} | |
| cur_humidity: > | |
| {% set e = plant_sensors | select('search', 'humidity|air') | list %} | |
| {{ states(e[0]) | float(-1) if e else -1 }} | |
| cur_conductivity: > | |
| {% set e = plant_sensors | select('search', 'conductivity|conduct') | list %} | |
| {{ states(e[0]) | float(-1) if e else -1 }} | |
| # ── STEP 3: soglie min/max ─────────────────────────────────────── | |
| - variables: | |
| min_moisture: > | |
| {% set e = plant_numbers | select('search', 'min.*soil|min.*moisture') | list %} | |
| {{ states(e[0]) | float(-1) if e else -1 }} | |
| max_moisture: > | |
| {% set e = plant_numbers | select('search', 'max.*soil|max.*moisture') | list %} | |
| {{ states(e[0]) | float(9999) if e else 9999 }} | |
| min_illuminance: > | |
| {% set e = plant_numbers | select('search', 'min.*illuminance|min.*light') | list %} | |
| {{ states(e[0]) | float(-1) if e else -1 }} | |
| max_illuminance: > | |
| {% set e = plant_numbers | select('search', 'max.*illuminance|max.*light') | list %} | |
| {{ states(e[0]) | float(9999) if e else 9999 }} | |
| min_temperature: > | |
| {% set e = plant_numbers | select('search', 'min.*temp') | list %} | |
| {{ states(e[0]) | float(-999) if e else -999 }} | |
| max_temperature: > | |
| {% set e = plant_numbers | select('search', 'max.*temp') | list %} | |
| {{ states(e[0]) | float(9999) if e else 9999 }} | |
| min_humidity: > | |
| {% set e = plant_numbers | select('search', 'min.*humidity|min.*air') | list %} | |
| {{ states(e[0]) | float(-1) if e else -1 }} | |
| max_humidity: > | |
| {% set e = plant_numbers | select('search', 'max.*humidity|max.*air') | list %} | |
| {{ states(e[0]) | float(9999) if e else 9999 }} | |
| min_conductivity: > | |
| {% set e = plant_numbers | select('search', 'min.*conduct') | list %} | |
| {{ states(e[0]) | float(-1) if e else -1 }} | |
| max_conductivity: > | |
| {% set e = plant_numbers | select('search', 'max.*conduct') | list %} | |
| {{ states(e[0]) | float(9999) if e else 9999 }} | |
| # ── STEP 4: costruzione messaggi ──────────────────────────────── | |
| # Ora cur_* e min_*/max_* sono risolti dagli step 2 e 3 | |
| - variables: | |
| problems: > | |
| {% set it = (language == 'it') %} | |
| {% set ns = namespace(msgs=[]) %} | |
| {% if notify_low_moisture and cur_moisture >= 0 and min_moisture >= 0 and cur_moisture < min_moisture %} | |
| {% set msg = ('💧 Aggiungi acqua alla pianta ' if it else '💧 Add water to plant ') | |
| ~ plant_name ~ ' (' ~ ('umidita terreno: ' if it else 'soil moisture: ') | |
| ~ cur_moisture | int ~ '%, ' ~ ('minimo: ' if it else 'min: ') | |
| ~ min_moisture | int ~ '%)' %} | |
| {% set ns.msgs = ns.msgs + [msg] %} | |
| {% endif %} | |
| {% if notify_high_moisture and cur_moisture >= 0 and max_moisture < 9999 and cur_moisture > max_moisture %} | |
| {% set msg = ('🌊 Troppa acqua per la pianta ' if it else '🌊 Too much water for plant ') | |
| ~ plant_name ~ ' (' ~ ('umidita terreno: ' if it else 'soil moisture: ') | |
| ~ cur_moisture | int ~ '%, ' ~ ('massimo: ' if it else 'max: ') | |
| ~ max_moisture | int ~ '%)' %} | |
| {% set ns.msgs = ns.msgs + [msg] %} | |
| {% endif %} | |
| {% if notify_low_illuminance and cur_illuminance >= 0 and min_illuminance >= 0 and cur_illuminance < min_illuminance %} | |
| {% set msg = ('🌑 Poca luce per la pianta ' if it else '🌑 Not enough light for plant ') | |
| ~ plant_name ~ ' (' ~ cur_illuminance | int ~ ' lx, ' | |
| ~ ('minimo: ' if it else 'min: ') ~ min_illuminance | int ~ ' lx)' %} | |
| {% set ns.msgs = ns.msgs + [msg] %} | |
| {% endif %} | |
| {% if notify_high_illuminance and cur_illuminance >= 0 and max_illuminance < 9999 and cur_illuminance > max_illuminance %} | |
| {% set msg = ('☀️ Troppa luce per la pianta ' if it else '☀️ Too much light for plant ') | |
| ~ plant_name ~ ' (' ~ cur_illuminance | int ~ ' lx, ' | |
| ~ ('massimo: ' if it else 'max: ') ~ max_illuminance | int ~ ' lx)' %} | |
| {% set ns.msgs = ns.msgs + [msg] %} | |
| {% endif %} | |
| {% if notify_low_temperature and cur_temperature > -999 and min_temperature > -999 and cur_temperature < min_temperature %} | |
| {% set msg = ('❄️ Temperatura troppo bassa per la pianta ' if it else '❄️ Temperature too low for plant ') | |
| ~ plant_name ~ ' (' ~ cur_temperature | round(1) ~ 'C, ' | |
| ~ ('minimo: ' if it else 'min: ') ~ min_temperature | round(1) ~ 'C)' %} | |
| {% set ns.msgs = ns.msgs + [msg] %} | |
| {% endif %} | |
| {% if notify_high_temperature and cur_temperature > -999 and max_temperature < 9999 and cur_temperature > max_temperature %} | |
| {% set msg = ('🌡️ Temperatura troppo alta per la pianta ' if it else '🌡️ Temperature too high for plant ') | |
| ~ plant_name ~ ' (' ~ cur_temperature | round(1) ~ 'C, ' | |
| ~ ('massimo: ' if it else 'max: ') ~ max_temperature | round(1) ~ 'C)' %} | |
| {% set ns.msgs = ns.msgs + [msg] %} | |
| {% endif %} | |
| {% if notify_low_humidity and cur_humidity >= 0 and min_humidity >= 0 and cur_humidity < min_humidity %} | |
| {% set msg = ('🏜️ Umidita aria bassa per la pianta ' if it else '🏜️ Air humidity too low for plant ') | |
| ~ plant_name ~ ' (' ~ cur_humidity | int ~ '%, ' | |
| ~ ('minimo: ' if it else 'min: ') ~ min_humidity | int ~ '%)' %} | |
| {% set ns.msgs = ns.msgs + [msg] %} | |
| {% endif %} | |
| {% if notify_high_humidity and cur_humidity >= 0 and max_humidity < 9999 and cur_humidity > max_humidity %} | |
| {% set msg = ('💦 Umidita aria alta per la pianta ' if it else '💦 Air humidity too high for plant ') | |
| ~ plant_name ~ ' (' ~ cur_humidity | int ~ '%, ' | |
| ~ ('massimo: ' if it else 'max: ') ~ max_humidity | int ~ '%)' %} | |
| {% set ns.msgs = ns.msgs + [msg] %} | |
| {% endif %} | |
| {% if notify_low_conductivity and cur_conductivity >= 0 and min_conductivity >= 0 and cur_conductivity < min_conductivity %} | |
| {% set msg = ('🌿 Pochi nutrienti per la pianta ' if it else '🌿 Not enough nutrients for plant ') | |
| ~ plant_name ~ ' (' ~ ('conduttivita: ' if it else 'conductivity: ') | |
| ~ cur_conductivity | int ~ ' uS/cm, ' | |
| ~ ('minimo: ' if it else 'min: ') ~ min_conductivity | int ~ ' uS/cm)' %} | |
| {% set ns.msgs = ns.msgs + [msg] %} | |
| {% endif %} | |
| {% if notify_high_conductivity and cur_conductivity >= 0 and max_conductivity < 9999 and cur_conductivity > max_conductivity %} | |
| {% set msg = ('⚡ Troppi nutrienti per la pianta ' if it else '⚡ Too many nutrients for plant ') | |
| ~ plant_name ~ ' (' ~ ('conduttivita: ' if it else 'conductivity: ') | |
| ~ cur_conductivity | int ~ ' uS/cm, ' | |
| ~ ('massimo: ' if it else 'max: ') ~ max_conductivity | int ~ ' uS/cm)' %} | |
| {% set ns.msgs = ns.msgs + [msg] %} | |
| {% endif %} | |
| {{ ns.msgs }} | |
| # ── STEP 5: invio notifiche ────────────────────────────────────── | |
| - repeat: | |
| for_each: "{{ problems }}" | |
| sequence: | |
| - service: "notify.mobile_app_{{ device_attr(device_to_notify, 'name') | slugify }}" | |
| data: | |
| title: "{{ notification_title | trim }}" | |
| message: "{{ repeat.item }}" | |
| data: | |
| tag: "plant_{{ plant_entity | slugify }}_{{ repeat.index }}" | |
| group: "{{ 'piante' if language == 'it' else 'plants' }}" | |
| color: "#4CAF50" | |
| mode: single |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment