Skip to content

Instantly share code, notes, and snippets.

@mbo18
Last active May 13, 2025 12:34
Show Gist options
  • Save mbo18/6c8222d60f41a8fcf46e27410a18403a to your computer and use it in GitHub Desktop.
Save mbo18/6c8222d60f41a8fcf46e27410a18403a to your computer and use it in GitHub Desktop.
Gestion filtration piscine (avancé)
blueprint:
name: "Gestion filtration piscine (avancé)"
description: "Gestion automatique de la filtration/pompe de la piscine"
domain: automation
homeassistant:
min_version: 2024.6.0
input:
temperature_piscine:
name: "Capteur de température de la piscine"
description: "La température permet de calculer la durée de filtration"
selector:
entity:
filter:
domain: sensor
device_class: temperature
multiple: false
switch_pompe:
name: "Entité de contrôle de la pompe"
description: "Pour pouvoir allumer et éteindre la pompe selon les heures calculées de début et fin de filtration"
selector:
entity:
filter:
domain:
- switch
- light
- input_boolean
multiple: true
bouton_reset:
name: "Bouton de reset du temps de filtration"
description: "Permet de (re)lancer le calcul de la durée et des horaires de filtration"
selector:
entity:
filter:
domain: input_button
multiple: false
parametres_generaux:
name: "Paramètres généraux"
icon: mdi:cog
input:
mode_filtration:
name: "Mode de filtration de la piscine"
description: >
Courbe : Calcul de la durée selon une courbe en fonction de la température de la piscine
Hivernage : Fait marcher la pompe 3h par jour si la température de l'eau est inférieure ou égale 10°C, 24h si la température est en dessous de la température hors gel et le mode hors gel est activé. Au dessus de 10°C, le temps de filtration est égal à la température de l'eau divisée par 3.
Automatique : Combine le mode Courbe et le mode Hivernage afin de ne pas avoir à changer de mode au cours de l'année. Le mode hivernage s'active dès que l'eau passe en dessous de la température configurée
Forcé : Force le fonctionnement de la pompe
Inactif : Coupe la pompe et la gestion de la filtration
selector:
entity:
filter:
domain: input_select
multiple: false
ajustement:
name: "Coefficient d'ajustement du temps de filtration"
description: "Permet d'influer à la baisse ou à la hausse le temps de filtration pour l'adapter à vos besoins"
selector:
entity:
filter:
domain: input_number
multiple: false
parametres_mode_courbe:
name: "Paramètres du mode Courbe"
icon: mdi:refresh-auto
input:
heure_pivot:
name: "Heure pivot de filtration"
description: "Heure autour de laquelle les horaires de filtration sont calculés"
selector:
entity:
filter:
domain: sensor
device_class: timestamp
multiple: false
duree_coupure:
name: "Durée de coupure de la filtration"
description: "Permet de définir une pause dans la filtration autour de l'heure pivot"
selector:
entity:
filter:
domain: input_number
multiple: false
parametres_mode_hiver:
name: "Paramètres du mode Hivernage"
icon: mdi:snowflake
input:
heure_hivernage:
name: "Heure pivot de filtration en hivernage"
description: "Heure autour de laquelle les horaires de filtration sont calculés en hivernage"
selector:
entity:
filter:
domain: sensor
device_class: timestamp
multiple: false
duree_coupure_hiver:
name: "Durée de coupure de la filtration"
description: "Permet de définir une pause dans la filtration autour de l'heure pivot"
selector:
entity:
filter:
domain: input_number
multiple: false
activation_hors_gel:
name: "Mode hors gel"
description: "En mode hors gel, la filtration est permanente si la température de la piscine est en dessous de la température hors gel"
default: "Activé"
selector:
select:
options:
- "Activé"
- "Désactivé"
temperature_hors_gel:
name: "Température hors gel"
description: "En dessous de cette température la filtration est permanente"
default: 1
selector:
number:
min: -5
max: 5
step: 1
unit_of_measurement: °C
mode: slider
parametres_mode_automatique:
name: "Paramètres du mode Automatique"
icon: mdi:refresh-auto
input:
temp_passage_hiver:
name: "Température de déclenchement du mode Hivernage"
description: "En dessous de cette température, activation du mode Hivernage"
default: 15
selector:
number:
min: 0
max: 20
step: 1
unit_of_measurement: °C
mode: slider
entites_pour_calcul:
name: "Entités pour stocker les données du calcul"
icon: mdi:database
input:
duree_filtration:
name: "Durée de filtration de la piscine"
selector:
entity:
filter:
domain: input_number
multiple: false
heure_debut_filtration_1_piscine:
name: "Heure début 1ère période de filtration"
selector:
entity:
filter:
domain: input_datetime
multiple: false
heure_fin_filtration_1_piscine:
name: "Heure fin 1ère période de filtration"
selector:
entity:
filter:
domain: input_datetime
multiple: false
heure_debut_filtration_2_piscine:
name: "Heure début 2ième période de filtration"
selector:
entity:
filter:
domain: input_datetime
multiple: false
heure_fin_filtration_2_piscine:
name: "Heure fin 2ième période de filtration"
selector:
entity:
filter:
domain: input_datetime
multiple: false
mode: single
max_exceeded: silent
variables:
temp_piscine: !input temperature_piscine
mode_filtration: !input mode_filtration
coef: !input ajustement
activation_hors_gel: !input activation_hors_gel
temp_hors_gel: !input temperature_hors_gel
duree_coupure: !input duree_coupure
duree_coupure_hiver: !input duree_coupure_hiver
heure_p: !input heure_pivot
heure_pivot: "{{ states(heure_p) | as_timestamp | timestamp_custom('%H:%M:%S') }}"
heure_p_h: !input heure_hivernage
heure_pivot_hiver: "{{ states(heure_p_h) | as_timestamp | timestamp_custom('%H:%M:%S') }}"
temp_passage_hiver: !input temp_passage_hiver
duree_de_filtration_courbe: >-
{# Pour assurer un temps minimum de filtration la temperature de calcul est forcée a 10°C #}
{% set temp = max(states(temp_piscine)|float(10), 10) %}
{# y = (0.00335 * temperature^3) + (-0.14953 * temperature^2) + (2.43489 * temperature) -10.72859 #}
{% set a = 0.00335 * states(coef)|float / 100 %}
{% set b = -0.14953 * states(coef)|float / 100 %}
{% set c = 2.43489 * states(coef)|float / 100 %}
{% set d = -10.72859 * states(coef)|float / 100 %}
{% set hours = (a * temp**3) + (b * temp**2) + (c * temp) + d %}
{% set minutes = (hours * 60)|round(0) %}
{{ min(minutes, 1440) }}
duree_de_filtration_hivernage: >-
{% set temp = states(temp_piscine)|float(10) %}
{% set min_duree = 240 %}
{% set max_duree = 1440 %}
{% if activation_hors_gel == 'Activé' and temp <= temp_hors_gel %}
{{ max_duree }}
{% elif temp < 10 %}
{{ min_duree }}
{% else %}
{{ ((temp / 3) * 60)|round(0) }}
{% endif %}
duree_de_filtration_automatique: >-
{% set temp = states(temp_piscine)|float(10) %}
{% set min_duree = 240 %}
{% set max_duree = 1440 %}
{% if activation_hors_gel == 'Activé' and temp <= temp_hors_gel %}
{{ max_duree }}
{% elif temp < 10 %}
{{ min_duree }}
{% elif temp < temp_passage_hiver %}
{{ ((temp / 3) * 60)|round(0) }}
{% else %}
{% set a = 0.00335 * states(coef)|float / 100 %}
{% set b = -0.14953 * states(coef)|float / 100 %}
{% set c = 2.43489 * states(coef)|float / 100 %}
{% set d = -10.72859 * states(coef)|float / 100 %}
{% set hours = (a * temp**3) + (b * temp**2) + (c * temp) + d %}
{% set minutes = (hours * 60)|round(0) %}
{{ min(minutes, 1440) }}
{% endif %}
trigger:
- platform: time
at: !input heure_debut_filtration_1_piscine
id: "1"
- platform: time
at: !input heure_fin_filtration_1_piscine
id: "2"
- platform: time
at: !input heure_debut_filtration_2_piscine
id: "3"
- platform: time
at: !input heure_fin_filtration_2_piscine
id: "4"
- platform: state
entity_id: !input bouton_reset
id: "5"
- platform: state
entity_id: !input mode_filtration
id: "6"
action:
# Calcul des heures de début et fin des périodes
- if:
- or:
- condition: trigger # Si fin de la 2nd période
id: "4"
- condition: trigger # Si reset
id: "5"
- condition: trigger # Si changement de mode
id: "6"
then:
- choose:
# mode Courbe
- conditions:
- condition: state
entity_id: !input mode_filtration
state: "Courbe"
sequence:
- service: input_number.set_value
target:
entity_id: !input duree_filtration
data:
value: "{{ duree_de_filtration_courbe }}"
- service: input_datetime.set_datetime
target:
entity_id: !input heure_debut_filtration_1_piscine
data:
datetime: >-
{% set time = today_at(heure_pivot) - timedelta(minutes=duree_de_filtration_courbe/2) - timedelta(minutes=states(duree_coupure)|int/2) %}
{% if time < today_at("00:00:00") %}
{{ today_at("00:01:00") }}
{% else %}
{{ time }}
{% endif %}
- service: input_datetime.set_datetime
target:
entity_id: !input heure_fin_filtration_1_piscine
data:
datetime: "{{ today_at(heure_pivot) - timedelta(minutes=states(duree_coupure)|int/2) }}"
- service: input_datetime.set_datetime
target:
entity_id: !input heure_debut_filtration_2_piscine
data:
datetime: "{{ today_at(heure_pivot) + timedelta(minutes=states(duree_coupure)|int/2) }}"
- service: input_datetime.set_datetime
target:
entity_id: !input heure_fin_filtration_2_piscine
data:
datetime: >-
{% set time = today_at(heure_pivot) + timedelta(minutes=duree_de_filtration_courbe/2) + timedelta(minutes=states(duree_coupure)|int/2) %}
{% if time > today_at("23:59:00") %}
{{ today_at("23:59:00") }}
{% else %}
{{ time }}
{% endif %}
# mode Automatique
- conditions:
- condition: state
entity_id: !input mode_filtration
state: "Automatique"
sequence:
- service: input_number.set_value
target:
entity_id: !input duree_filtration
data:
value: "{{ duree_de_filtration_automatique }}"
- service: input_datetime.set_datetime
target:
entity_id: !input heure_debut_filtration_1_piscine
data:
datetime: >-
{% if states(temp_piscine)|float >= temp_passage_hiver %}
{% set time = today_at(heure_pivot) - timedelta(minutes=duree_de_filtration_automatique/2) - timedelta(minutes=states(duree_coupure)|int/2) %}
{% else %}
{% set time = today_at(heure_pivot_hiver) - timedelta(minutes=duree_de_filtration_automatique/2) - timedelta(minutes=states(duree_coupure_hiver)|int/2) %}
{% endif %}
{% if time < today_at("00:00:00") or duree_de_filtration_automatique == 1440 %}
{{ today_at("00:01:00") }}
{% else %}
{{ time }}
{% endif %}
- service: input_datetime.set_datetime
target:
entity_id: !input heure_fin_filtration_1_piscine
data:
datetime: >-
{% if states(temp_piscine)|float >= temp_passage_hiver %}
{{ today_at(heure_pivot) - timedelta(minutes=states(duree_coupure)|int/2) }}
{% else %}
{{ today_at(heure_pivot_hiver) - timedelta(minutes=states(duree_coupure_hiver)|int/2) }}
{% endif %}
- service: input_datetime.set_datetime
target:
entity_id: !input heure_debut_filtration_2_piscine
data:
datetime: >-
{% if states(temp_piscine)|float >= temp_passage_hiver %}
{{ today_at(heure_pivot) + timedelta(minutes=states(duree_coupure)|int/2) }}
{% else %}
{{ today_at(heure_pivot_hiver) + timedelta(minutes=states(duree_coupure_hiver)|int/2) }}
{% endif %}
- service: input_datetime.set_datetime
target:
entity_id: !input heure_fin_filtration_2_piscine
data:
datetime: >-
{% if states(temp_piscine)|float >= temp_passage_hiver %}
{% set time = today_at(heure_pivot) + timedelta(minutes=duree_de_filtration_automatique/2) + timedelta(minutes=states(duree_coupure)|int/2) %}
{% else %}
{% set time = today_at(heure_pivot_hiver) + timedelta(minutes=duree_de_filtration_automatique/2) + timedelta(minutes=states(duree_coupure_hiver)|int/2) %}
{% endif %}
{% if time > today_at("23:59:00") or duree_de_filtration_automatique == 1440 %}
{{ today_at("23:59:00") }}
{% else %}
{{ time }}
{% endif %}
# mode Hivernage
- conditions:
- condition: state
entity_id: !input mode_filtration
state: "Hivernage"
sequence:
- service: input_number.set_value
target:
entity_id: !input duree_filtration
data:
value: "{{ duree_de_filtration_hivernage }}"
- service: input_datetime.set_datetime
target:
entity_id: !input heure_debut_filtration_1_piscine
data:
datetime: >-
{% set time = today_at(heure_pivot_hiver) - timedelta(minutes=duree_de_filtration_hivernage/2) - timedelta(minutes=states(duree_coupure_hiver)|int/2) %}
{% if time < today_at("00:00:00") or duree_de_filtration_automatique == 1440 %}
{{ today_at("00:01:00") }}
{% else %}
{{ time }}
{% endif %}
- service: input_datetime.set_datetime
target:
entity_id: !input heure_fin_filtration_1_piscine
data:
datetime: "{{ today_at(heure_pivot_hiver) - timedelta(minutes=states(duree_coupure_hiver)|int/2) }}"
- service: input_datetime.set_datetime
target:
entity_id: !input heure_debut_filtration_2_piscine
data:
datetime: "{{ today_at(heure_pivot_hiver) + timedelta(minutes=states(duree_coupure_hiver)|int/2) }}"
- service: input_datetime.set_datetime
target:
entity_id: !input heure_fin_filtration_2_piscine
data:
datetime: >-
{% set time = today_at(heure_pivot_hiver) + timedelta(minutes=duree_de_filtration_hivernage/2) + timedelta(minutes=states(duree_coupure_hiver)|int/2) %}
{% if time > today_at("23:59:00") or duree_de_filtration_automatique == 1440 %}
{{ today_at("23:59:00") }}
{% else %}
{{ time }}
{% endif %}
# mode Forcé
- conditions:
- condition: state
entity_id: !input mode_filtration
state: "Forcé"
sequence:
- service: input_number.set_value
target:
entity_id: !input duree_filtration
data:
value: 1440
- service: input_datetime.set_datetime
target:
entity_id:
- !input heure_debut_filtration_1_piscine
- !input heure_fin_filtration_1_piscine
- !input heure_debut_filtration_2_piscine
- !input heure_fin_filtration_2_piscine
data:
time: "00:00:00"
- service: homeassistant.turn_on
target:
entity_id: !input switch_pompe
# mode Inactif
- conditions:
- condition: state
entity_id: !input mode_filtration
state: "Inactif"
sequence:
- service: input_number.set_value
target:
entity_id: !input duree_filtration
data:
value: 0
- service: input_datetime.set_datetime
target:
entity_id:
- !input heure_debut_filtration_1_piscine
- !input heure_fin_filtration_1_piscine
- !input heure_debut_filtration_2_piscine
- !input heure_fin_filtration_2_piscine
data:
time: "00:00:00"
- service: homeassistant.turn_off
target:
entity_id: !input switch_pompe
- if:
- "{{ states(mode_filtration) not in ['Forcé', 'Inactif'] }}"
then:
- choose:
# Demarrage de la pompe en debut de periode
- conditions:
- condition: trigger
id: "1"
sequence:
- service: homeassistant.turn_on
target:
entity_id: !input switch_pompe
- conditions:
- condition: trigger
id: "3"
- "{{ states(duree_coupure)|int > 0 }}"
sequence:
- service: homeassistant.turn_on
target:
entity_id: !input switch_pompe
# Arrêt de la pompe en fin de periode
- conditions:
- condition: trigger
id: "2"
- "{{ states(duree_coupure)|int > 0 }}"
sequence:
- service: homeassistant.turn_off
target:
entity_id: !input switch_pompe
- conditions:
- condition: trigger
id: "4"
sequence:
- service: homeassistant.turn_off
target:
entity_id: !input switch_pompe
# Si changement de mode
- conditions:
- condition: trigger
id: "6"
sequence:
- if:
- or:
- condition: time
after: !input heure_debut_filtration_1_piscine
before: !input heure_fin_filtration_1_piscine
- condition: time
after: !input heure_debut_filtration_2_piscine
before: !input heure_fin_filtration_2_piscine
then:
- service: homeassistant.turn_on
target:
entity_id: !input switch_pompe
else:
- service: homeassistant.turn_off
target:
entity_id: !input switch_pompe
@gaetanars
Copy link

gaetanars commented Apr 24, 2025

Merci beaucoup pour ce blueprint très complet.
J'aurai une petite proposition supplémentaire qui serait de rajouter un trigger en cas de changement d'état du switch qui gère la pompe de piscine pour pouvoir s'assurer que son état est bien celui attendu dans la plage horaire.

Le cas d'usage que j'imagine est par exemple un utilisateur qui se trompe et change l'état du switch depuis son Dashboard par exemple.

Il serait aussi intéressant de relancer un calcul de la filtration lorsqu'il y a un changement sur les entités d'heure pivot et de durée de coupure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment