Note de ce sujet :
  • Moyenne : 4 (1 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
Tuto: Notification et acquittement d'un entretien périodique (Low Code)
#1
Bonjour,

Ce tuto (Low code) traite l'envoi d'une notification sur le smartphone pour rappeler le changement du filtre en amont de l'adoucisseur avec un pictogramme dans le Dashboard qui clignotera en rouge jusqu'à l'acquittement (effectué manuellement une fois le filtre remplacé).
Il pourra facilement être adapté et éventuellement complété comme indiqué ici par XeNo.

1) Utilisation du calendrier Home Assistant
- Dans HA/calendrier, créer un calendrier local "Test Filtre adoucisseur"
   

- dans la fenêtre à gauche, cocher le calendrier puis cliquer sur "Ajouter un évènement" (en bas à droite),
ajuster la périodicité si l'une de celles proposées convient mais, dans l'exemple, le filtre est changé 3 fois par an donc je crée un évènement unique qui sera dupliqué manuellement 3 fois pour l'année (et éventuellement plus pour les années suivantes)
   

2) Créer une entrée booléenne
- Dans HA/Paramètres/Appareils et Services/Entrée, cliquer sur "Créer une entrée", puis '"Interrupteur" et compléter :
   

3) Créer une automatisation
- Dans HA/Automatisations et Scènes/Automatisation, cliquer sur "Créer une automatisation" puis "Créez une nouvelle automatisation (vide)" ;
- sélectionner les 3 points en haut à droite puis "modifier en yaml"
   
- effacer le code et le remplacer par celui ci-dessous :
Code :
alias: test notification changement filtre adoucisseur
description: >-
  Envoie une notification lorsque calendar.test_filtre_adoucisseur passe de
  désactivé à activé.
triggers:
  - entity_id: calendar.test_filtre_adoucisseur
    from: "off"
    to: "on"
    trigger: state
conditions: []
actions:
  - data:
      title: Changement du filtre requis
      message: >-
        Il est temps de changer le filtre de l'adoucisseur. Merci d'acquitter
        une fois terminé.
    action: notify.mobile_app_iphone_y
  - action: input_boolean.turn_on
    target:
      entity_id: input_boolean.test_acquittement_changement_filtre_adoucisseur
    data: {}
mode: single

- Enregistrer et renommer "test notification changement filtre adoucisseur"
- Cliquer sur HA/Outils de développement/onglet YAML/ AUTOMATISATIONS pour redémarrer les automatisations.

4) Dans le Dashboard
     
Le pictogramme clignote en rouge lorsque le filtre est à changer et une fois celui-ci remplacé, il faut cliquer sur le pictogramme pour acquitter.

- Dans une vue du Dashboard, ajouter une carte "Manuel" ; effacer la 1ère ligne puis coller le code suivant:
Code :
type: custom:button-card
state:
 - value: "on"
   color: red
   icon: mdi:air-filter
   styles:
     icon:
       - animation:
           - blink 1s linear infinite
 - value: "off"
   color: null
tap_action:
 action: toggle
entity: input_boolean.test_acquittement_changement_filtre_adoucisseur
icon: mdi:air-filter
name: Filtre Adoucisseur

C'est une carte custum-card-button (à installer avec HACS)

Pour tester immédiatement le fonctionnement, il suffit d'ajouter un évènement dans le calendrier "Test filtre adoucisseur" dont le début est quelques minutes après l'heure de test (pour acquitter il faut attendre au moins une minute).

Pour supprimer un calendrier local :
- dans HA/Appareils et services/Intégrations, sélectionner l'intégration "Calendrier local"
- cliquer sur les 3 points situés à droite du nom du calendrier à supprimer, puis "supprimer".
Répondre
#2
Merci pour le tuto c'est sympa !

En fait ici c'est le fonctionnement inverse de celui que j'ai proposé. C'est des dates fixes qui envoient une notif pour réinitialiser.
Il faudrait mixer les 2 versions, des cartes intelligentes avec détection de temps/volumes qui envoient une notif quand il faut changer le/les filtres.
Je vais tenter d'ajouter la notification à tout ça.
Répondre
#3
Bonjour,

Modification avec une carte qui affiche la date à laquelle le filtre a été remplacé et le volume filtré depuis le dernier remplacement.

[Image: 049j.jpg]
Lorsqu'on clique sur la carte :
- un clavier s'affiche pour entrer le code afin de déverrouiller la carte ; cette étape supplémentaire permet d'éviter une RAZ non souhaitée (à installer avec HACS https://github.com/iantrich/restriction-card) ;


un second clic provoque :
- le remplacement de la date par la date du jour
- la RAZ de la consommation depuis le dernier remplacement


Code d'une des cartes :
Code :
type: custom:restriction-card
restrictions:
 confirm: null
 pin:
   text: Entrez le code
   code: 1234
card:
 type: custom:button-card
 icon: mdi:air-filter
 name: Puits 25 u +  Charbon
 entity: input_text.date_changement_filtres_puits
 show_state: true
 tap_action:
   action: call-service
   service: script.raz_et_maj_date
 styles:
   card:
     - height: 120px
     - background: none
   icon:
     - color: var(--primary-color)
     - width: 40px
     - margin-right: 0px
   name:
     - font-size: 16px
     - color: white
     - padding-left: 10px
   state:
     - font-size: 12px
     - color: yellow
     - padding-left: 10px
 state_display: |
   [[[
     return "<span style='color: white;'>Changé le : </span>" + states['input_text.date_changement_filtres_puits'].state +
            "<br><span style='color: white;'>Conso. depuis cette date : </span>" + states['sensor.conso_eau_totale_changement_filtres_puits'].state + " L";
   ]]]

Il faut un input_texte dans le fichier configuration.yaml 
Code :
input_text:
 date_changement_filtres_puits:
   name: Date Changement Filtres Puits
   max: 10

Le code du sensor contenant la consommation dans knx_sensor.yaml
Code :
#Conso eau TOTALE depuis changement des filtres puits
 - name: conso_eau_totale_changement_filtres_puits
   state_address: "7/4/2"
   type: "volume_liquid_litre"
   state_class: total_increasing


Et un script (dans le fichier scripts.yaml) qui envoie la RAZ au compteur (dans mon cas, un objet avec DPT 1.015 dans la GA 7/4/3) et qui écrit la date du jour dans le "input_texte"
Code :
################################################
# RAZ Conso eau + date changement filtres puits #
################################################
raz_et_maj_date:
 alias: "RAZ consommation + mise à jour date"
 sequence:
   - service: knx.send
     data:
       address: "7/4/3"
       payload: "RESET"
       type: "DPT1.015"
   - delay: "00:00:01"
   - service: input_text.set_value
     target:
       entity_id: input_text.date_changement_filtres_puits
     data:
       value: "{{ now().strftime('%d-%m-%Y') }}"
 mode: single


Remarque :
Pour la mise au point, notamment pour vérifier que la date change bien, on peut utiliser l'onglet ACTIONS dans les outils de développement pour entrer une date différente de la date du jour.
1) Dans le champ "Action", saisir "input_text.set_value"
2) Copier ce code suivant dans la zone en dessous d'Action
Code :
action: input_text.set_value
data:
 value: 01-02-2025
target:
 entity_id: input_text.date_changement_filtres_puits

3) Cliquer sur "Exécuter l'action"
Répondre
#4
Salut Yves,

Pas mal tout ça !
Au final c'est la même chose que mes cards ici, tu n'as juste pas la mise en forme card mod en template (c'est ce qui consomme le plus de ligne de code au final)

Par contre si je comprends bien ton code là, tu reinitialises ton compteur d'eau knx ? Le global ? Ca ne fausse pas ton comptage général ?
J'avais utilisé un compteur HA dédié dans mes scripts/cards pour ne pas toucher ce qui vient du KNX.
Répondre
#5
Rappel de l'autre manière de faire
Avec gestion d'un calendrier qui garde en mémoire les changements et qui permet aussi d'avoir un choix dans le type de filtre.

Le visuel
Les Cards :
   
Toujours dynamiques (c'etait avant le double filtre, mais c'est pareil)
   

En cliquant dessus pour changer le/les filtre(s) :
   

Le choix du filtre :
   

L'entrée agenda qui est générée (qui s'adapte si on change l'un des filtres ou les 2)
   
Répondre
#6
(12/02/2025, 18:46:33)XeNo a écrit : Salut Yves,

Pas mal tout ça !
Au final c'est la même chose que mes cards ici, tu n'as juste pas la mise en forme card mod en template (c'est ce qui consomme le plus de ligne de code au final)

Par contre si je comprends bien ton code là, tu reinitialises ton compteur d'eau knx ? Le global ? Ca ne fausse pas ton comptage général ?
J'avais utilisé un compteur HA dédié dans mes scripts/cards pour ne pas toucher ce qui vient du KNX.

J'ai deux compteurs KNX (réseau et puits) et j'utilise pour cette fonctionnalité des registres partiels ; les registres utilisés pour les consommations ne sont donc pas impactés.

L'avantage de le faire en KNX c'est qu'en cas de plantage de HA/NUC les index seront toujours là (de plus, j'utilise un Zennio KCI qui dispose d'une batterie pour continuer à compter les impulsions en cas de coupure secteur).
Répondre
#7
@XeNo, c'est bien d'avoir complété le tuto ; ça donne le choix entre un traitement par KNX et un par HA !
Répondre
#8
Pour faire tout ça :
1re étape :
Creer un calendrier HA, soit local, soit Google, soit ce que vous voulez.
   

2ème étape :
Creer les entités suivantes (ici pour 2 filtres) un input_number (pour stocker une valeur), un input_datetime (pour stocker la date)
   

3ème étape :
Réaliser un script qui sera actionné quand on cliquera sur la tuile, il est en 3 étapes :
1/ stocker la date du jour au moment du clic dans input_datetime
2/ stocker le cubage total au moment du clic dans input_number
3/ Creer un event agenda qui a comme nom, le type de changement de filtre (moi cuve ou ville), et en description les informations précédentes (durée de vie, cubage)
Attention, il faudra autant de scripts que de bouton lovelace souhaité (que de filtre à changer en somme)
Le script est long parce que ca gère 1 filtre, l'autre, ou les 2.
Le script qui est lancé :
Code :
alias: Set Change Filtres Cuve1-2
sequence:
 - if:
     - condition: and
       conditions:
         - condition: not
           conditions:
             - condition: state
               entity_id: input_select.liste_type_filtre_eau_cuve_1_nouveau
               state: Pas de changement de filtre
         - condition: not
           conditions:
             - condition: state
               entity_id: input_select.liste_type_filtre_eau_cuve_2_nouveau
               state: Pas de changement de filtre
   then:
     - action: calendar.create_event
       target:
         entity_id: calendar.filtres_eau
       data:
         summary: Changement filtres cuve
         description: >
           Premiere filtration - Le {{
           states('input_select.liste_type_filtre_eau_cuve_1_courant') }} a
           duré {{ (now() -
           states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days
           }} jours/{{ (states('sensor.volume_cuve_litre') | int) -
           (states('input_number.volume_changement_filtre_cuve_1_litre') | int)
           }} Litres

           Deuxième filtration - Le {{
           states('input_select.liste_type_filtre_eau_cuve_2_courant') }} a
           duré {{ (now() -
           states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days
           }} jours/{{ (states('sensor.volume_cuve_litre') | int) -
           (states('input_number.volume_changement_filtre_cuve_2_litre') | int)
           }} Litres
         start_date: |
           {{ now().date() }}
         end_date: |
           {{ now().date() + timedelta(days=1) }}
     - action: input_select.select_option
       metadata: {}
       data:
         option: "{{states('input_select.liste_type_filtre_eau_cuve_1_nouveau')}}"
       target:
         entity_id: input_select.liste_type_filtre_eau_cuve_1_courant
     - action: input_button.press
       target:
         entity_id: input_button.sensor_date_filtre_eau_cuve_1
       data: {}
     - action: input_number.set_value
       target:
         entity_id: input_number.volume_changement_filtre_cuve_1_litre
       data:
         value: "{{ states('sensor.volume_cuve_litre') }}"
     - action: input_select.select_option
       metadata: {}
       data:
         option: "{{states('input_select.liste_type_filtre_eau_cuve_2_nouveau')}}"
       target:
         entity_id: input_select.liste_type_filtre_eau_cuve_2_courant
     - action: input_button.press
       target:
         entity_id: input_button.sensor_date_filtre_eau_cuve_2
       data: {}
     - action: input_number.set_value
       target:
         entity_id: input_number.volume_changement_filtre_cuve_2_litre
       data:
         value: "{{ states('sensor.volume_cuve_litre') }}"
 - if:
     - condition: and
       conditions:
         - condition: not
           conditions:
             - condition: state
               entity_id: input_select.liste_type_filtre_eau_cuve_1_nouveau
               state: Pas de changement de filtre
         - condition: state
           entity_id: input_select.liste_type_filtre_eau_cuve_2_nouveau
           state: Pas de changement de filtre
   then:
     - action: calendar.create_event
       target:
         entity_id: calendar.filtres_eau
       data:
         summary: Changement filtres cuve
         description: >-
           Premiere filtration - Le {{
           states('input_select.liste_type_filtre_eau_cuve_1_courant') }} a
           duré {{ (now() -
           states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days
           }} jours/{{ (states('sensor.volume_cuve_litre') | int) -
           (states('input_number.volume_changement_filtre_cuve_1_litre') | int)
           }} Litres
         start_date: |
           {{ now().date() }}
         end_date: |
           {{ now().date() + timedelta(days=1) }}
     - action: input_select.select_option
       metadata: {}
       data:
         option: "{{states('input_select.liste_type_filtre_eau_cuve_1_nouveau')}}"
       target:
         entity_id: input_select.liste_type_filtre_eau_cuve_1_courant
     - action: input_button.press
       target:
         entity_id: input_button.sensor_date_filtre_eau_cuve_1
       data: {}
     - action: input_number.set_value
       target:
         entity_id: input_number.volume_changement_filtre_cuve_1_litre
       data:
         value: "{{ states('sensor.volume_cuve_litre') }}"
 - if:
     - condition: and
       conditions:
         - condition: not
           conditions:
             - condition: state
               entity_id: input_select.liste_type_filtre_eau_cuve_2_nouveau
               state: Pas de changement de filtre
         - condition: state
           entity_id: input_select.liste_type_filtre_eau_cuve_1_nouveau
           state: Pas de changement de filtre
   then:
     - action: calendar.create_event
       target:
         entity_id: calendar.filtres_eau
       data:
         summary: Changement filtre cuve
         description: >-
           Deuxième filtration - Le {{
           states('input_select.liste_type_filtre_eau_cuve_2_courant') }} a
           duré {{ (now() -
           states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days
           }} jours/{{ (states('sensor.volume_cuve_litre') | int) -
           (states('input_number.volume_changement_filtre_cuve_2_litre') | int)
           }} Litres
         start_date: |
           {{ now().date() }}
         end_date: |
           {{ now().date() + timedelta(days=1) }}
     - action: input_select.select_option
       metadata: {}
       data:
         option: "{{states('input_select.liste_type_filtre_eau_cuve_2_nouveau')}}"
       target:
         entity_id: input_select.liste_type_filtre_eau_cuve_2_courant
     - action: input_button.press
       target:
         entity_id: input_button.sensor_date_filtre_eau_cuve_2
       data: {}
     - action: input_number.set_value
       target:
         entity_id: input_number.volume_changement_filtre_cuve_2_litre
       data:
         value: "{{ states('sensor.volume_cuve_litre') }}"
description: Creer une entrée agenda pour le changement des filtre eau de Cuve 1 et 2
icon: mdi:calendar-check-outline


4 et 5/ Et enfin, le code de la carte associée, le code est chargé parce qu'il y a pas mal de mise en forme conditionnelle pour les statuts d'alertes. Sans mise en forme il est tout petit.
J'ai conditionné, pour l'instant et de manière arbitraire le cubage à 10m3, il sera certainement plus haut par la suite. Par contre j'ai également mis une condition de temps, j'estime qu'à 6 mois, le filtre doit être changé pour des raisons d'hygiène évidente.
Il y a une demande de validation avec le choix du filtre, pas d'erreur de manip possible
Le code de la tuile concernée (ici double étage de filtration toujours)
Code :
         - type: custom:mushroom-template-card
           icon: mdi:air-filter
           icon_color: blue
           name: Filtre changé ?
           layout: vertical
           primary: Etat filtres eau de cuve
           tap_action:
             action: fire-dom-event
             browser_mod:
               service: browser_mod.popup
               data:
                 title: Changement des filtres d'eau de cuve
                 content:
                   type: custom:vertical-stack-in-card
                   cards:
                     - type: horizontal-stack
                       cards:
                         - type: vertical-stack
                           cards:
                             - type: custom:mushroom-title-card
                               title: null
                               subtitle: >-
                                 Choisir les types de filtres qui seront
                                 utilisés pour le remplacement puis valider.
                               card_mod:
                                 style: |
                                   ha-card {
                                     margin-left: 30px;
                                     margin-right: 30px;
                                   }
                             - type: custom:mushroom-select-card
                               entity: >-
                                 input_select.liste_type_filtre_eau_cuve_1_nouveau
                               name: >-
                                 Type de filtre qui sera installé en première
                                 filtration ?
                               secondary_info: none
                               card_mod:
                                 style: |
                                   ha-card {
                                     margin-left: 30px;
                                     margin-right: 30px;
                                   }
                             - type: custom:mushroom-select-card
                               entity: >-
                                 input_select.liste_type_filtre_eau_cuve_2_nouveau
                               name: >-
                                 Type de filtre qui sera installé en seconde
                                 filtration ?
                               secondary_info: none
                               card_mod:
                                 style: |
                                   ha-card {
                                     margin-left: 30px;
                                     margin-right: 30px;
                                   }
                             - type: horizontal-stack
                               cards:
                                 - type: custom:gap-card
                                 - type: custom:mushroom-template-card
                                   icon: mdi:tooltip-check-outline
                                   primary: Valider
                                   fill_container: false
                                   icon_color: green
                                   tap_action:
                                     action: call-service
                                     confirmation:
                                       text: >-
                                         Valider le changement du/des filtre(s)
                                         d'eau de cuve maintenant ?
                                     service: script.set_change_filtres_cuve1_2
                                   card_mod:
                                     style:
                                       .: |
                                         ha-card {
                                           margin-top: 30px;
                                           margin-bottom: 30px;
                                         }
                                 - type: custom:gap-card
           secondary: "{% if ((now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days > 180) and ((now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days > 180) %}\n  Vie filtre 1 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int)) / 1000) }} m³\n  Vie filtre 2 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int)) / 1000) }} m³\n  Filtre à changer !\n{% elif ((now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days > 180) %}\n  Vie filtre 1 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int)) / 1000) }} m³\n  Vie filtre 2 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int)) / 1000) }} m³\n  Filtre 1 à changer !\n{% elif ((now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days > 180) %}\n  Vie filtre 1 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int)) / 1000) }} m³\n  Vie filtre 2 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int)) / 1000) }} m³\n  Filtre 2 à changer !\n{% elif ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) > 10000 ) and ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) > 10000 ) %}\n  Vie filtre 1 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int)) / 1000) }} m³\n  Vie filtre 2 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int)) / 1000) }} m³\n  Filtre à changer !\n{% elif ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) > 10000 ) %}\n  Vie filtre 1 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int)) / 1000) }} m³\n  Vie filtre 2 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int)) / 1000) }} m³\n  Filtre 1 à changer !\n{% elif ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) > 10000 ) %}\n  Vie filtre 1 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int)) / 1000) }} m³\n  Vie filtre 2 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int)) / 1000) }} m³\n  Filtre 2 à changer !\n{% elif ((((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) < 10000) and ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) > 8000))) or ((((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) < 10000) and ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) > 8000))) %}\n  Vie filtre 1 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int)) / 1000) }} m³\n  Vie filtre 2 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int)) / 1000) }} m³\n  Changement Filtres à prévoir\n{% elif (((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) < 10000) and ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) > 8000)) %}\n  Vie filtre 1 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int)) / 1000) }} m³\n  Vie filtre 2 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int)) / 1000) }} m³\n  Changement Filtre 1 à prévoir\n{% elif (((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) < 10000) and ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) > 8000)) %}\t\t\t\t\n  Vie filtre 1 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int)) / 1000) }} m³\nVie filtre 2 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int)) / 1000) }} m³ Changement Filtre 2 à prévoir     {% else %}\n  Vie filtre 1 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int)) / 1000) }} m³\nVie filtre 2 : {{ (now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days }} jour(s) / {{ '%0.2f' | format(((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int)) / 1000) }} m³ {% endif %}\n"
           badge_icon: >
             {% if ((now() -
             states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days
             > 180) and ((now() -
             states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days
             > 180) %}
               mdi:alert
             {% elif ((now() -
             states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days
             > 180) %}
               mdi:alert
             {% elif ((now() -
             states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days
             > 180) %}
               mdi:alert
             {% elif ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) > 10000 ) and ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) > 10000 ) %}
               mdi:alert
             {% elif ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) > 10000 ) %}
               mdi:alert
             {% elif ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) > 10000 ) %}
               mdi:alert
             {% elif ((((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) < 10000) and ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) > 8000))) or ((((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) < 10000) and ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) > 8000))) %}
               mdi:information-symbol
             {% elif (((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) < 10000) and ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) > 8000)) %}
               mdi:information-symbol
             {% elif (((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) < 10000) and ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) > 8000)) %}
               mdi:information-symbol
             {% endif %}
           badge_color: >
             {% if ((now() -
             states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days
             > 180) and ((now() -
             states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days
             > 180) %}
               red
             {% elif ((now() -
             states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days
             > 180) %}
               red
             {% elif ((now() -
             states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days
             > 180) %}
               red
             {% elif ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) > 10000 ) and ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) > 10000 ) %}
               red
             {% elif ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) > 10000 ) %}
               red
             {% elif ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) > 10000 ) %}
               red
             {% elif ((((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) < 10000) and ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) > 8000))) or ((((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) < 10000) and ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) > 8000))) %}
               amber
             {% elif (((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) < 10000) and ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_1_litre') |
             int) > 8000)) %}
               amber
             {% elif (((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) < 10000) and ((states('sensor.volume_cuve_litre') | int) -
             (states('input_number.volume_changement_filtre_cuve_2_litre') |
             int) > 8000)) %}
               amber
             {% endif %}
           multiline_secondary: true
           card_mod:
             style:
               .: >
                 {% if ((now() -
                 states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days
                 > 180) and ((now() -
                 states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days
                 > 180) %}

                 ha-card {
                   animation: ping 1s infinite;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     70% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((now() -
                 states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days
                 > 180) %}

                 ha-card {
                   animation: ping 1s infinite;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     70% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((now() -
                 states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days
                 > 180) %}

                 ha-card {
                   animation: ping 1s infinite;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     70% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((states('sensor.volume_cuve_litre') | int) -
                 (states('input_number.volume_changement_filtre_cuve_1_litre')
                 | int) > 10000 ) and ((states('sensor.volume_cuve_litre') |
                 int) -
                 (states('input_number.volume_changement_filtre_cuve_2_litre')
                 | int) > 10000 ) %}

                 ha-card {
                   animation: ping 1s infinite;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     70% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((states('sensor.volume_cuve_litre') | int) -
                 (states('input_number.volume_changement_filtre_cuve_1_litre')
                 | int) > 10000 ) %}

                 ha-card {
                   animation: ping 1s infinite;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     70% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((states('sensor.volume_cuve_litre') | int) -
                 (states('input_number.volume_changement_filtre_cuve_2_litre')
                 | int) > 10000 ) %}

                 ha-card {
                   animation: ping 1s infinite;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     70% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }                  

                 {% else %}
                   
                 ha-card {
                   padding-bottom: 15px !important;
                 }  

                 {% endif %}
               mushroom-badge-icon$: >
                 {% if ((now() -
                 states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days
                 > 180) and ((now() -
                 states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days
                 > 180) %}

                 .badge {
                   animation: ping 1s infinite;
                   --badge-icon-size: 22px;
                   --badge-size: 30px;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     50% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((now() -
                 states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days
                 > 180) %}

                 .badge {
                   animation: ping 1s infinite;
                   --badge-icon-size: 22px;
                   --badge-size: 30px;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     50% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((now() -
                 states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days
                 > 180) %}

                 .badge {
                   animation: ping 1s infinite;
                   --badge-icon-size: 22px;
                   --badge-size: 30px;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     50% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((states('sensor.volume_cuve_litre') | int) -
                 (states('input_number.volume_changement_filtre_cuve_1_litre')
                 | int) > 10000 ) and ((states('sensor.volume_cuve_litre') |
                 int) -
                 (states('input_number.volume_changement_filtre_cuve_2_litre')
                 | int) > 10000 ) %}

                 .badge {
                   animation: ping 1s infinite;
                   --badge-icon-size: 22px;
                   --badge-size: 30px;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     50% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((states('sensor.volume_cuve_litre') | int) -
                 (states('input_number.volume_changement_filtre_cuve_1_litre')
                 | int) > 10000 ) %}

                 .badge {
                   animation: ping 1s infinite;
                   --badge-icon-size: 22px;
                   --badge-size: 30px;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     50% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((states('sensor.volume_cuve_litre') | int) -
                 (states('input_number.volume_changement_filtre_cuve_2_litre')
                 | int) > 10000 ) %}

                 .badge {
                   animation: ping 1s infinite;
                   --badge-icon-size: 22px;
                   --badge-size: 30px;
                 }

                 @keyframes ping {
                     0% {box-shadow: 0 0 0 0 rgba(var(--rgb-red), 0.7);}
                     50% {box-shadow: 0 0 0 10px transparent;}
                     100% {box-shadow: 0 0 0 0 transparent;}
                 }

                 {% elif ((((states('sensor.volume_cuve_litre') | int) -
                 (states('input_number.volume_changement_filtre_cuve_1_litre')
                 | int) < 10000) and ((states('sensor.volume_cuve_litre') |
                 int) -
                 (states('input_number.volume_changement_filtre_cuve_1_litre')
                 | int) > 8000))) or ((((states('sensor.volume_cuve_litre') |
                 int) -
                 (states('input_number.volume_changement_filtre_cuve_2_litre')
                 | int) < 10000) and ((states('sensor.volume_cuve_litre') |
                 int) -
                 (states('input_number.volume_changement_filtre_cuve_2_litre')
                 | int) > 8000))) %}

                 .badge {
                   --badge-icon-size: 40px;
                   --badge-size: 30px;

                 {% elif (((states('sensor.volume_cuve_litre') | int) -
                 (states('input_number.volume_changement_filtre_cuve_1_litre')
                 | int) < 10000) and ((states('sensor.volume_cuve_litre') |
                 int) -
                 (states('input_number.volume_changement_filtre_cuve_1_litre')
                 | int) > 8000)) %}

                 .badge {
                   --badge-icon-size: 40px;
                   --badge-size: 30px;

                 {% elif (((states('sensor.volume_cuve_litre') | int) -
                 (states('input_number.volume_changement_filtre_cuve_2_litre')
                 | int) < 10000) and ((states('sensor.volume_cuve_litre') |
                 int) -
                 (states('input_number.volume_changement_filtre_cuve_2_litre')
                 | int) > 8000)) %}

                 .badge {
                   --badge-icon-size: 40px;
                   --badge-size: 30px;

                 {% endif %}
               mushroom-shape-icon$: |
                 .shape {
                   --icon-symbol-size: 40px;
                   --icon-size: 60px;
                 }
               mushroom-state-info$: "{% if ((now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days > 180) and ((now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days > 180) %}\n.container {\n  --card-secondary-color: red;\n}\n{% elif ((now() - states('input_button.sensor_date_filtre_eau_cuve_1')|as_datetime).days > 180) %}\n.container {\n  --card-secondary-color: red;\n}\n{% elif ((now() - states('input_button.sensor_date_filtre_eau_cuve_2')|as_datetime).days > 180) %}\n.container {\n  --card-secondary-color: red;\n}\n{% elif ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) > 10000 ) and ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) > 10000 ) %}\n.container {\n  --card-secondary-color: red;\n}\n{% elif ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) > 10000 ) %}\n.container {\n  --card-secondary-color: red;\n}\n{% elif ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) > 10000 ) %}\n.container {\n  --card-secondary-color: red;\n}\n{% elif ((((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) < 10000) and ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) > 8000))) or ((((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) < 10000) and ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) > 8000))) %}\n.container {\n  --card-secondary-color: orange;\n}\n{% elif (((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) < 10000) and ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_1_litre') | int) > 8000)) %}\n.container {\n  --card-secondary-color: orange;\n}\n{% elif (((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) < 10000) and ((states('sensor.volume_cuve_litre') | int) - (states('input_number.volume_changement_filtre_cuve_2_litre') | int) > 8000)) %}\t\t\t\t\n.container {\n  --card-secondary-color: orange;\n}\n{% endif %}\n"


Voilà !
Répondre
#9
(12/02/2025, 19:00:58)Ives a écrit : @XeNo, c'est bien d'avoir complété le tuto ; ça donne le choix entre un traitement par KNX et un par HA !



Pour envoyer le reset sur le KNX en plus de HA il suffit d'ajouter ça à mon script (en modifiant la GA concernée par le reset partiel). Ca permet d'avoir l'index sur HA ET sur le KNX

Code :
  - service: knx.send
    data:
      address: "7/4/3"
      payload: "RESET"
      type: "DPT1.015"

C'est pas vraiment ça qui change, c'est surtout la partie Calendrier, multi filtres, choix du filtre et dynamisme de la tuile. C'est pour ça que je dis que c'est une autre manière de faire.
Répondre
#10
(12/02/2025, 19:10:32)XeNo a écrit : C'est pas vraiment ça qui change, c'est surtout la partie Calendrier, multi filtres, choix du filtre et dynamisme de la tuile. C'est pour ça que je dis que c'est une autre manière de faire.

J'ai bien vu et compris (et l'esthétique de tes cartes est top) mais l'idée de départ du tuto était "Low Code" ; avec cette dernière version de carte j'en ai un peu mais ça reste "raisonnable".
Répondre
#11
Il faudrait fusionner les 2 méthodes pour lowcoder au max.
Le template cardmod que j'utilise est trop lourd, il faut le déporter dans un script et utiliser des variables comme tu le fais avec ton calendar.
Ajouter la strate de verrouillage avant le changement peut être interessant aussi
Par contre le calendar imposé n'est pas dynamique, si tu décales ton changement (vacances ou autres) ton entrée suivante ne bougera pas dans le temps sauf à le faire manuellement.

Je vais essayer de lowcoder mes cards en ajoutant un script qui check les conditions et set des variables (0 rien, 1 à prévoir, 2 à changer) et baser le cardmod uniquement sur ces 3 valeurs, ce devrait réduire drastiquement les conditions et sera moins lourd à l'affichage si c'est un script qui le gère.
Répondre
#12
j'ai fait pas mal de choses sympas* avec Gemini qui comprend assez bien le code home-assistant si jamais. Il faut faire plusieurs itération, mais ça va de toutes façons plus vite que d'écrire le code à la main, le tester, recommencer et ainsi de suite.

(* : à partir de mon antenne météo griesser, je récupère la radiance en w/m2 et via les lux par facade, je calcule la puissance en W fourni gratuitement par le soleil en temps réel dans la maison, le tout en prenant en compte le type de verre des vitres, l'ombre portée du batiment sur les vitres et la position et l'orientation des lames des BSO, valeur que je compare ensuite avec l'apport en chaleur fourni par les sèches-serviettes et aussi le plancher chauffant sur PAC (le connecteur KNX me fourni l'info en W fourni) => c'est hors sujet sur ce thread donc je n'en dirai pas plus, mais c'est pour expliquer ce que Gemini m'a permis de faire en 2h top chrono.
Répondre
#13
Partage ton experience et ton code sur un autre thread dans ce cas Smile
Répondre


Atteindre :


Utilisateur(s) parcourant ce sujet : 1 visiteur(s)