Home Assistant & CO2

Depuis le temps que je domotise, je ne m'étais jamais vraiment posé la question du taux de CO2 (infos ici) présent dans mon habitation. Une des raisons de cette négligence étant que le coût des capteurs connectés était il y a encore un peu trop élevé. C'était sans compter sur Ikea qui avec sa nouvelle ligne de produits Matter en propose un au nom bien de chez eux et dont la puce utilisée semble de bonne facture.

Après des mois (voire années) de phase beta l'intégration des produit Matter over Thread sur Home Assistant fonctionne maintenant correctement, et on peut même se passer de l'application mobile pour appairer les objets (explications à venir si j'ai le temps). Pour ce post on va donc partir du principe que le capteur Alpstuga est reconnu par Home Assistant, qu'il le soit directement sur le serveur Tread intégré ou via une passerelle annexe (Aqara, Apple, Alexa, etc.).

Objectif

Jusqu'à présent je faisais tourner la VMC en grande vitesse en cas de besoin avec un hygrostat basé sur le taux d'humidité de la salle de bain. Cela fonctionne plutôt correctement, et le deal maintenant est de continuer à résorber l'humidité et y associant l'éliminatioin du CO2. Au préalable j'ai bien sur vérifié que le fait de forcer la VMC fait bien baisser le niveau de CO2 dans la maison.

On ne repèrera jamais assez qu'au delà ce cet outil mécanique, la base consiste à aérer généreusement les habitats tous les jours. Je ne vais pas vois refaire l'article, c'est très bien expliqué sur ce site.

Donc exit l'hygrostat, il va falloir créer une automation:pour combiner les deux fonctions, et comme j'ai déjà une automation qui permet de forcer la VMC dans une tranche horaire ou via un timer pour les WC, je devrais désactiver la nouvelle en cas de forçage (todo : voir la première à la fin de l'article).

Une automatisation basée sur une valeur brute (instantanée) va poser problème à ma VMC, elle va se déclencher au moindre pic et à terme ruiner le moteur. Pour faire quelque chose de plus propre, il nous faut passer par des sensors de filtrage et une gestion de l'hystérésis.

Depuis maintenant pas mal de versions, Home Assistant permet de créer ces capteurs complexes directement dans l'interface utilisateur sans toucher au fichier configuration.yaml. Il est ainsi possible de les modifier en live (tout au mois en partie) et cela sera plus simple pour ceux qui ne sont pas familiers de la syntaxe YAML. Pour ceux qui persistent en YAML n'oubliez d'ajouter un unique_id:à chaque sensor:ou binary_sensor:en utilisant ce générateur si vous manquez d'inspiration !

Jo se pose ici le code yaml de ces sensors pour plus de lisibilité mais je les ai tous créés avec l'UI.

Création des Sensors de Moyenne (Filtres)

On utilise l'intégration filter pour lisser les données sur une fenêtre de 15 minutes. Cela évite les déclenchements "yoyo" :

sensor:
  # Moyenne CO2 lissée sur 15 minutes
  - platform: filter
    name: "Ikea ALPSTUGA Air Quality 01 Co2 (Filtered)"
    unique_id: fb209449-7e2c-451a-b169-10
    entity_id: sensor.alpstuga_co2
    filters:
      - filter: time_simple_moving_average
        window_size: "00:15:00"
        precision: 0

  # Moyenne Humidité lissée sur 15 minutes
  - platform: filter
    name: "Humidité SdB (Filtered)"
    unique_id: fb209449-7e2c-451a-b169-11
    entity_id: sensor.alpstuga_humidity
    filters:
      - filter: time_simple_moving_average
        window_size: "00:15:00"
        precision: 1

On peu aussi utiliser un sensor de type statistic pour parvenir à un résultat sensiblement identique.

Création des Binaires de Seuil (Hystérésis)

Plutôt que de mettre les chiffres dans l'automation, on crée des threshold helpers. La VMC s'allume à un seuil haut et ne s'éteint qu'une fois redescendue sous un seuil bas.

J'ai cédé à la mode et perdu pas mal de temps avec différentes IA qui me racontaient littéralement des conneries, le principe est pourtant très simple et il suffit de lire la doc :

Logique Hystérésis Threshold HA
Quand la valeur du sensor augmente
Set Turns on when Turns off when
only upper sensor > (upper + hyst) never
only lower never sensor > (lower + hyst)
upper & lower sensor > (lower + hyst) sensor > (upper + hyst)
Quand la valeur du sensor diminue
Set Turns on when Turns off when
only upper never sensor < (upper - hyst)
only lower sensor < (lower - hyst) never
upper & lower sensor < (upper - hyst) sensor < (lower - hyst)

Ce qui nous donne :

binary_sensor:
  # Capteur de seuil pour le CO2
  - platform: threshold
    name: "Ikea ALPSTUGA Air Quality 01 Co2 (Threshold)"
    unique_id: fb209449-7e2c-451a-b169-20
    entity_id: sensor.ikea_alpstuga_air_quality_01_co2_filtered
    upper: 800       # S'allume dès que l'on dépasse 900 ppm
    hysteresis: 100  # Reste ON jusqu'à redescendre sous 700 ppm

# Capteur de seuil pour l'Humidité
  - platform: threshold
    name: "Humidité SdB (Filtered Threshold)"
    unique_id: fb209449-7e2c-451a-b169-21
    entity_id: sensor.humidite_sdb_filtered
    upper: 60       # S'allume dès que l'on dépasse 65%
    hysteresis: 5   # Reste ON jusqu'à redescendre sous 55%
    

Le cas de la douche

Pour l'humidité de la salle de bain, il faut être plus réactif pour faire tourner la VMC pendant une douche, en complément on va ajouter un sensor de type derivative (dérivée) pour détecter la vitesse de montée de l'humidité plutôt que son taux absolu (car 65% un jour de pluie, c'est l'humidité normale, mais une montée de +10% en 2 minutes, c'est forcément une douche).

Le Sensor de Dérivée

sensor:
  - platform: derivative
    name: "Humidité SdB (Derivative)"
    unique_id: fb209449-7e2c-451a-b169-30
    source: sensor.alpstuga_humidity
    unit_time: min
    time_window: "00:01:00"
    max_sub_interval: "00:00:30" # Force le calcul toutes les 30s
  

Le Binary Sensor de Seuil (pour l'automation)

binary_sensor:
  - platform: threshold
    name: "Humidité SdB (Derivative Threshold)"
    unique_id: fb209449-7e2c-451a-b169-31
    entity_id: sensor.humidite_sdb_derivative
    upper: 3         # S'allume si la hausse > 3% / min
    hysteresis: 2    # S'éteint si la hausse tombe sous 1% / min (3 - 2)

Avantages

  1. Stabilité du moteur : Le lissage nous permet d'ignorer les variations brusques (quelqu'un qui souffle sur le capteur).
  2. Pas de micro-déclenchements : L'hystérésis (le gap entre 900 et 700 ppm pour le CO2) empêche la VMC de s'allumer/éteindre toutes les 2 minutes quand on est juste à la limite du seuil.
  3. Indépendance : Si l'humidité baisse mais que le CO2 reste élevé (soirée avec du monde), la VMC reste allumée grâce à la condition de vérification croisée dans l'action de coupure.

Automatisation

J'ai oublié l'idée d'intégrer cette partie dans un choose: de mon automation initiale, et pour cause, il me faut désactiver cette nouvelle automation (ou lui poser une condition) quand la VMC tourne en mode planifié ou via un bouton de marche forcée.

automation:
- id: "140dce7e-cbb0-4dfd-8cfa-c5b968d78a7f-vmc-auto"
    alias: "VMC : Auto"
    # mode: restart
    triggers:
      - trigger: state
        entity_id: binary_sensor.ikea_alpstuga_air_quality_01_co2_threshold # threshold CO2
        from: "off"
        to: "on"
        id: Co2
      - trigger: state
        entity_id: binary_sensor.humidite_sdb_threshold # threshold Humidité
        from: "off"
        to: "on"
        id: Humidité
      - trigger: state
        entity_id: binary_sensor.humidite_sdb_derivative_threshold # threshold sur la dérivée
        from: "off"
        to: "on"
        id: Humidité Derivative
      # off dans les deux sens pour ne pas avoir de déclenchements inutiles
      - trigger: state
        entity_id: binary_sensor.ikea_alpstuga_air_quality_01_co2_threshold # threshold CO2
        from: "on"
        to: "off"
        id: Co2
      - trigger: state
        entity_id: binary_sensor.humidite_sdb_threshold # threshold Humidité
        from: "on"
        to: "off"
        id: Humidité
      - trigger: state
        entity_id: binary_sensor.humidite_sdb_derivative_threshold # threshold sur la dérivée
        from: "on"
        to: "off"
        id: Humidité Derivative

    conditions: "{{ states('sensor.temp_exterieur') | float > 1 }}"
    actions:
      - conditions: "{{ trigger.id in ['thresholdW', 'Co2', 'Humidité', 'Humidité Derivative'] }}"
        sequence:
          - if:
              "{{ is_state('binary_sensor.ikea_alpstuga_air_quality_01_co2_threshold', 'on') or is_state('binary_sensor.humidite_sdb_threshold', 'on') or is_state('binary_sensor.humidite_sdb_derivative_threshold', 'on') }}"
            then:
              - service: switch.turn_on
                target:
                  entity_id: switch.sw02_vmc
              - action: notify.slack_hass_canaletto
                data:
                  message: "{{now().strftime('%d/%m/%Y, %H:%M')}} > VMC Auto Start | {{ trigger.id }} | Sdb : {{ states('sensor.humidite_sdb_filtered') }}%. Co2 : {{ states('sensor.ikea_alpstuga_air_quality_01_co2_filtered') }} ppm"
            else:
              - service: switch.turn_off
                target:
                  entity_id: switch.sw02_vmc
              - action: notify.slack_hass_canaletto
                data:
                  message: "{{now().strftime('%d/%m/%Y, %H:%M')}} > VMC Auto Stop | {{ trigger.id }} | Sdb : {{ states('sensor.humidite_sdb_filtered') }}%. Co2 : {{ states('sensor.ikea_alpstuga_air_quality_01_co2_filtered') }} ppm"

J'ai éclaté les triggers uniquement pour avoir mon log Slack plus clair. Je les ai passé en from:/to: afin de limiter les déclenchements inutiles.

To do

  • Capteur de mauvaise odeurs pour les WC ?
  • Gérer les PM2.5 ?