[Tuto] Piloter l'éclairage de son aquarium

Bonjour,

L’objectif du tuto

Celles et ceux qui ont un aquarium savent que le pilotage de l’éclairage est très important pour la bonne santé des plantes et donc de ses habitants.
L’objectif du tuto est très simple : disposer d’un dashboard qui permet de:

  • indiquer la durée d’éclairage max désirée
  • l’heure d’allumage le matin (pour avoir son aquarium allumé le matin, c’est boooo)
  • l’heure d’extinction le soir (pour avoir son aquarium allumé le soir, c’est boooo)
  • le ratio entre la matin et le soir (30% le matin par exemple, le reste le soir)

Tout le reste (c’est pas grand chose mais quand même) est calculé et on affiche les comptes à rebours etc…
Ce qui fait que quand on commence à avoir des algues… hop on modifie la durée, et quand les plantes font la gueule, hop on réajuste (si c’était aussi simple…)

C’est parti…

  1. Durée éclairage 180L :

    Créer un input_number.

    Valeur min : 1

    Valeur max : 24

    Pas : 1

    Mode d’affichage : champs de saisie

    unité de mesure : h

    input_number.duree_eclairage_180l

  2. Répartition Matin/Soir 180L :

    Créer un input_number.

    Valeur min : 1

    Valeur max : 100

    Pas : 1

    Mode d’affichage : curseur

    unité de mesure : %

    input_number.repartition_matin_soir_180l

  3. Heure allumage matin 180L :

    Crée une entrée date et/ou heure

    Sélectionner heure

    input_datetime.heure_allumage_matin_180l

  4. Heure extinction matin 180L :

    Crée une entrée date et/ou heure

    Sélectionner heure

    input_datetime.heure_extinction_matin_180l

  5. Heure allumage soir 180L :

    Crée une entrée date et/ou heure

    Sélectionner heure

    input_datetime.heure_allumage_soir_180l

  6. Heure extinction soir 180L :

    Crée une entrée date et/ou heure

    Sélectionner heure

    input_datetime.heure_extinction_soir_180l

  7. Compte à rebours avant prochain allumage 180L :

    Crée un sensor template

    Contenu du template:

{% set timezone = now().tzinfo %}
{% set allumage_matin_str = states('input_datetime.heure_allumage_matin_180l') %}
{% set allumage_soir_str = states('input_datetime.heure_allumage_soir_180l') %}

{% if allumage_matin_str != 'unknown' and allumage_soir_str != 'unknown' and allumage_matin_str and allumage_soir_str %}
  {% set allumage_matin = strptime(allumage_matin_str, '%H:%M:%S').replace(tzinfo=timezone) %}
  {% set allumage_soir = strptime(allumage_soir_str, '%H:%M:%S').replace(tzinfo=timezone) %}
  {% set maintenant = now() %}

  {% if maintenant.time() < allumage_matin.time() %}
    {{ (allumage_matin - maintenant).seconds | timestamp_custom('%H:%M:%S', false) }}
  {% elif maintenant.time() < allumage_soir.time() %}
    {{ (allumage_soir - maintenant).seconds | timestamp_custom('%H:%M:%S', false) }}
  {% else %}
    {{ ((allumage_matin + timedelta(days=1)) - maintenant).seconds | timestamp_custom('%H:%M:%S', false) }}
  {% endif %}
{% else %}
  Indisponible
{% endif %}

sensor.compte_a_rebours_avant_prochain_allumage_180l

  1. Compte à rebours avant prochaine extinction 180L :

    Crée un sensor template

    Contenu du template:

{% set timezone = now().tzinfo %}
{% set extinction_matin_str = states('input_datetime.heure_extinction_matin_180l') %}
{% set extinction_soir_str = states('input_datetime.heure_extinction_soir_180l') %}

{% if extinction_matin_str != 'unknown' and extinction_soir_str != 'unknown' and extinction_matin_str and extinction_soir_str %}
  {% set extinction_matin = strptime(extinction_matin_str, '%H:%M:%S').replace(tzinfo=timezone) %}
  {% set extinction_soir = strptime(extinction_soir_str, '%H:%M:%S').replace(tzinfo=timezone) %}
  {% set maintenant = now() %}

  {% if maintenant.time() < extinction_matin.time() %}
    {{ (extinction_matin - maintenant).seconds | timestamp_custom('%H:%M:%S', false) }}
  {% elif maintenant.time() < extinction_soir.time() %}
    {{ (extinction_soir - maintenant).seconds | timestamp_custom('%H:%M:%S', false) }}
  {% else %}
    {{ ((extinction_matin + timedelta(days=1)) - maintenant).seconds | timestamp_custom('%H:%M:%S', false) }}
  {% endif %}
{% else %}
  Indisponible
{% endif %}

sensor.compte_a_rebours_avant_prochaine_extinction_180l

  1. Prochain allumage aquarium 180l :

    Crée un sensor template

    Contenu du template:

{% set allumage_matin = states('input_datetime.heure_allumage_matin_180l') %}
{% set allumage_soir = states('input_datetime.heure_allumage_soir_180l') %}
{% set maintenant = now().strftime('%H:%M:%S') %}
       
{% if maintenant < allumage_matin %}
  {{ allumage_matin }}
{% elif maintenant < allumage_soir %}
  {{ allumage_soir }}
{% else %}
  {{ 'Demain à ' ~ allumage_matin }}
{% endif %}

sensor.prochain_allumage_aquarium_180l

Création des automations

  1. Calcul des heures eclairage aquarium 180L :

    Créer une automation, puis modifier en YAML (menu 3 points en haut à droite)

alias: Calcul des heures eclairage aquarium 180L
description: Calcul des heures extinction et allumage basées sur les paramètres
triggers:
  - entity_id:
      - input_number.duree_eclairage_180l
      - input_datetime.heure_allumage_matin_180l
      - input_datetime.heure_extinction_soir_180l
      - input_number.repartition_matin_soir_180l
    trigger: state
conditions: []
actions:
  - variables:
      duree_totale: "{{ states('input_number.duree_eclairage_180l') | int }}"
      repartition: "{{ states('input_number.repartition_matin_soir_180l') | int / 100 }}"
      heure_allumage_matin: >-
        {{ strptime(states('input_datetime.heure_allumage_matin_180l'),
        '%H:%M:%S') }}
      heure_extinction_soir: >-
        {{ strptime(states('input_datetime.heure_extinction_soir_180l'),
        '%H:%M:%S') }}
  - data:
      entity_id: input_datetime.heure_extinction_matin_180l
      time: >
        {{ (as_timestamp(heure_allumage_matin) + (duree_totale * repartition *
        3600)) | timestamp_custom('%H:%M:%S', false) }}
    action: input_datetime.set_datetime
  - data:
      entity_id: input_datetime.heure_allumage_soir_180l
      time: >
        {{ (as_timestamp(heure_extinction_soir) - (duree_totale * (1 -
        repartition) * 3600)) | timestamp_custom('%H:%M:%S', false) }}
    action: input_datetime.set_datetime
mode: single

  1. Éteindre la lumière aquarium 180L :

    Créer une automation, puis modifier en YAML (menu 3 points en haut à droite)

alias: Éteindre la lumière aquarium 180L
description: Éteint la lumière de aquarium 180L aux heures calculées
triggers:
  - value_template: >-
      {{ now().strftime('%H:%M') ==
      states('input_datetime.heure_extinction_matin_180l')[:5] }}
    trigger: template
  - value_template: >-
      {{ now().strftime('%H:%M') ==
      states('input_datetime.heure_extinction_soir_180l')[:5] }}
    trigger: template
conditions: []
actions:
  - target:
      entity_id: switch.alim_buffet_socket_3
    action: switch.turn_off
    data: {}
mode: single
  1. Allumer la lumière aquarium 180L :

    Créer une automation, puis modifier en YAML (menu 3 points en haut à droite)

alias: Allumer la lumière aquarium 180L
description: Allume la lumière de aquarium 180L aux heures programmées
triggers:
  - value_template: >-
      {{ now().strftime('%H:%M') ==
      states('input_datetime.heure_allumage_matin_180l')[:5] }}
    trigger: template
  - value_template: >-
      {{ now().strftime('%H:%M') ==
      states('input_datetime.heure_allumage_soir_180l')[:5] }}
    trigger: template
conditions: []
actions:
  - target:
      entity_id: switch.alim_buffet_socket_3
    action: switch.turn_on
    data: {}
mode: single

Création du lovelace

Créer une pile verticale pour l’affichage

type: vertical-stack
cards:
  - type: custom:mushroom-title-card
    title: ""
    subtitle: Aquarium 180l
  - type: entities
    entities:
      - entity: input_datetime.heure_extinction_matin_180l
      - entity: input_datetime.heure_allumage_soir_180l
      - entity: sensor.compte_a_rebours_avant_prochaine_extinction_180l
        name: Avant prochaine extinction
        icon: mdi:clock-alert
      - entity: sensor.prochain_allumage_aquarium_180l
        name: Avant prochain allumage
        icon: mdi:clock-check
    layout_options:
      grid_columns: 5
      grid_rows: auto
layout_options:
  grid_columns: 5
  grid_rows: auto

Créer une pile verticale pour la configuration

type: vertical-stack
cards:
  - type: custom:mushroom-title-card
    title: ""
    subtitle: Aquarium 180l
  - type: entities
    entities:
      - entity: input_number.duree_eclairage_180l
        name: Durée éclairage (heures)
      - entity: input_datetime.heure_allumage_matin_180l
        name: Heure allumage le matin
      - entity: input_datetime.heure_extinction_soir_180l
        name: Heure extinction le soir
      - entity: input_number.repartition_matin_soir_180l
        name: Répartition Matin/Soir (%)
  - show_name: true
    show_icon: true
    type: button
    tap_action:
      action: perform-action
      perform_action: homeassistant.update_entity
      data:
        entity_id:
          - automation.calcul_des_heures_eclairage_aquarium_120l
      target: {}
    name: Mettre à jour éclairage 180l
    show_state: false
  - type: custom:mushroom-title-card
    title: ""
    subtitle: Entretien 180l
  - type: entities
    entities:
      - entity: switch.alim_buffet_socket_4
      - entity: switch.flow_aquarium_prise_1
        name: Pompe de surface
        icon: mdi:water-pump
  - type: entities
    entities:
      - entity: light.alim_buffet_socket_3_lumiere_aqua_blanche
        name: Lumière Aqua 180
layout_options:
  grid_columns: 5
  grid_rows: auto

Et voilà.
Il ne reste plus qu’à entrer les 4 données. Et tout ce passe … :slight_smile:

Et pour celles et ceux qui veulent faire les choses encore mieux, vous pouvez enlever la possibilité d’éditer l’heure d’extinction matin et l’heure d’allumage soir (pour éviter toute mauvaise manip).

Cela équivaut à faire des petits sensors display

sensor:
  - platform: template
    sensors:
      heure_extinction_matin_180l_display:
        friendly_name: "Heure extinction matin 180L"
        value_template: "{{ states('input_datetime.heure_extinction_matin_180l') }}"
      heure_allumage_soir_180l_display:
        friendly_name: "Heure allumage soir 180L"
        value_template: "{{ states('input_datetime.heure_allumage_soir_180l') }}"

Puis de les utiliser dans lovelace :

type: vertical-stack
cards:
  - type: custom:mushroom-title-card
    title: ""
    subtitle: Aquarium 180l
  - type: entities
    entities:
      - entity: sensor.heure_extinction_matin_180l_display
      - entity: sensor.heure_allumage_soir_180l_display
      - entity: sensor.compte_a_rebours_avant_prochaine_extinction_180l
        name: Avant prochaine extinction
        icon: mdi:clock-alert
      - entity: sensor.prochain_allumage_aquarium_180l
        name: Avant prochain allumage
        icon: mdi:clock-check
    layout_options:
      grid_columns: 5
      grid_rows: auto
layout_options:
  grid_columns: 5
  grid_rows: auto

Et ça donne un truc non éditable dans la partie affichage :

2 « J'aime »

Salut merci pour ce tuto ,

j ai cette erreur a la création du premier template sensor , tu sais pas d ou ca peux venir ? indentation ?

sensor:
  - platform: template
    sensors:
    {% set timezone = now().tzinfo %}
{% set allumage_matin_str = states('input_datetime.heure_allumage_matin_180l') %}
{% set allumage_soir_str = states('input_datetime.heure_allumage_soir_180l') %}

{% if allumage_matin_str != 'unknown' and allumage_soir_str != 'unknown' and allumage_matin_str and allumage_soir_str %}
  {% set allumage_matin = strptime(allumage_matin_str, '%H:%M:%S').replace(tzinfo=timezone) %}
  {% set allumage_soir = strptime(allumage_soir_str, '%H:%M:%S').replace(tzinfo=timezone) %}
  {% set maintenant = now() %}

  {% if maintenant.time() < allumage_matin.time() %}
    {{ (allumage_matin - maintenant).seconds | timestamp_custom('%H:%M:%S', false) }}
  {% elif maintenant.time() < allumage_soir.time() %}
    {{ (allumage_soir - maintenant).seconds | timestamp_custom('%H:%M:%S', false) }}
  {% else %}
    {{ ((allumage_matin + timedelta(days=1)) - maintenant).seconds | timestamp_custom('%H:%M:%S', false) }}
  {% endif %}
{% else %}
  Indisponible
{% endif %}

Humm.
Tu as fais un copier coller dans ton fichier configuration.yaml ou dans un helper créé dans l’environnement graphique ?

Je te recommande d’aller dans Paramètres / Appareils et services / Entrées / Créer une entrée / Tu fais défiler jusqu’à {} Template puis Modéliser un capteur
Tu arrives là :

Puis tu colles dans « modèle de l’état » la partie de code fourni
Puis le nom du capteur également

Petite modification sur les automations :

triggers:
  - value_template: >-
      {{ now().strftime('%H:%M') ==
      states('input_datetime.heure_allumage_matin_180l')[:5] }}
    trigger: template
  - value_template: >-
      {{ now().strftime('%H:%M') ==
      states('input_datetime.heure_allumage_soir_180l')[:5] }}
    trigger: template

à la place de :

triggers:
  - value_template: >-
      {{ now().strftime('%H:%M:%S') ==
      states('input_datetime.heure_allumage_matin_180l')[:5] }}
    trigger: template
  - value_template: >-
      {{ now().strftime('%H:%M:%S') ==
      states('input_datetime.heure_allumage_soir_180l')[:5] }}
    trigger: template

Permet de faire le déclenchement à la minute et non à la seconde.
du coup :
(‹ %H:%M:%S ›) devient (‹ %H:%M ›)
et [:5] permet de tronquer la valeur de ‹ input_datetime.heure_allumage_soir_180l ›

En effet, l’automation était « sautée » si la comparaison n’était pas réalisée pile-poile dans la bonne seconde (elle produisait toujours un false)

1 « J'aime »

salut , alors merci bcp de ce conseil , je ne connaissais pas , je créer bêtement des fichiers .yaml
Pour le moment je n ai rien de bon , je continu mes recherches , ( sympa le projet :slight_smile: )
Je me suis lancé dans les sondes TDS c’est sympa aussi pour l’aquarium :slight_smile:
je te tiens informé de l’évolution.

ca commence a ressembler a ton tuto !=)

je dois regarder 2/3 trucs car il me semble que le compte a rebours ne fonctionne pas .

Merci encore pour ce tuto , super facile a mettre en place si on ne le lis pas en diagonale comme moi .

:wink:
Merci ^^

Tu utilises quoi pour la partie TDS ?

Hello.
Une sonde TDS avec une sonde dallas couplée a un esp32.

hello , j ai bcp d 'erreur dans les logs , une idée ?

Source: components/template/template_entity.py:199
intégration: Template (documentation, problèmes)
S'est produit pour la première fois: 14:08:02 (4 occurrences)
Dernier enregistrement: 14:08:02

TemplateError('ValueError: Template error: as_timestamp got invalid input '' when rendering template 'alias: Calcul des heures eclairage aquarium 180L description: Calcul des heures extinction et allumage basées sur les paramètres triggers: - entity_id: - input_number.duree_eclairage_180l - input_datetime.heure_allumage_matin_180l - input_datetime.heure_extinction_soir_180l - input_number.repartition_matin_soir_180l trigger: state conditions: [] actions: - variables: duree_totale: "{{ states('input_number.duree_eclairage_180l') | int }}" repartition: "{{ states('input_number.repartition_matin_soir_180l') | int / 100 }}" heure_allumage_matin: >- {{ strptime(states('input_datetime.heure_allumage_matin_180l'), '%H:%M:%S') }} heure_extinction_soir: >- {{ strptime(states('input_datetime.heure_extinction_soir_180l'), '%H:%M:%S') }} - data: entity_id: input_datetime.heure_extinction_matin_180l time: > {{ (as_timestamp(heure_allumage_matin) + (duree_totale * repartition * 3600)) | timestamp_custom('%H:%M:%S', false) }} action: input_datetime.set_datetime - data: entity_id: input_datetime.heure_allumage_soir_180l time: > {{ (as_timestamp(heure_extinction_soir) - (duree_totale * (1 - repartition) * 3600)) | timestamp_custom('%H:%M:%S', false) }} action: input_datetime.set_datetime mode: single' but no default was specified') while processing template 'Template<template=(alias: Calcul des heures eclairage aquarium 180L description: Calcul des heures extinction et allumage basées sur les paramètres triggers: - entity_id: - input_number.duree_eclairage_180l - input_datetime.heure_allumage_matin_180l - input_datetime.heure_extinction_soir_180l - input_number.repartition_matin_soir_180l trigger: state conditions: [] actions: - variables: duree_totale: "{{ states('input_number.duree_eclairage_180l') | int }}" repartition: "{{ states('input_number.repartition_matin_soir_180l') | int / 100 }}" heure_allumage_matin: >- {{ strptime(states('input_datetime.heure_allumage_matin_180l'), '%H:%M:%S') }} heure_extinction_soir: >- {{ strptime(states('input_datetime.heure_extinction_soir_180l'), '%H:%M:%S') }} - data: entity_id: input_datetime.heure_extinction_matin_180l time: > {{ (as_timestamp(heure_allumage_matin) + (duree_totale * repartition * 3600)) | timestamp_custom('%H:%M:%S', false) }} action: input_datetime.set_datetime - data: entity_id: input_datetime.heure_allumage_soir_180l time: > {{ (as_timestamp(heure_extinction_soir) - (duree_totale * (1 - repartition) * 3600)) | timestamp_custom('%H:%M:%S', false) }} action: input_datetime.set_datetime mode: single) renders=4>' for attribute '_attr_native_value' in entity 'sensor.eteindre_la_lumiere_aquarium_180l'```