AirGradient Outdoor Monitor zur Steuerung der Hausventilation

Hallo an alle,

ich habe seit gestern einen AirGradient Outdoor Monitor (Model O-1PST) im Betrieb. Er dient (neben weiteren Indoor-Sensoren) dazu zu entscheiden, ob und mit welcher Stufe meine Hauslüftungsanlage laufen soll. Meine Lüftungsanlage versorgt alle Räume zugleich und hat drei Leistungsstufen. Würde sie immer auf voller Stufe laufen, wäre der Stromverbrauch hoch und die Luft trocken. Die Anlage soll daher immer situativ passend zum Bedarf laufen. Außerdem soll sie ausgehen, wenn die Außenluft schlecht ist.

Hat jemand vielleicht schon einmal etwas Ähnliches bei sich umgesetzt und will sich dazu austauschen? Mich würde z.B. besonders interessieren, wie man am geschicktesten das Problem umgeht, dass die Werte des AirGradient Outdoor Monitors bei hoher Luftfeuchtigkeit ungenau werden können.

Anbei einmal meine bisherige Automation, die wegen ihrer Komplexität für Außenstehende aber vermutlich nicht gänzlich verständlich sein wird. Ich habe sie zum besseren Verständnis hier von der Gemini-KI automatisch kommentieren lassen:

alias: "Lüftungsanlage: situativ passendes Level"
description: >
  Hygroskopie-kompensierte Steuerung via AirGradient Outdoor. 
  Nutzt NOx und VOC zur Validierung von PM2.5 bei hoher Luftfeuchtigkeit.
  Inklusive Korrektur für gebäudenahe VOC-Fehlmessungen (Terrassentür).

triggers:
  - minutes: /5
    trigger: time_pattern # Periodischer Check zur Sicherheit
  - entity_id:
      - sensor.airgradient_pm25
      - sensor.airgradient_voc_index
      - sensor.airgradient_nox_index
    trigger: state # Sofortige Reaktion auf Luftqualitätsänderungen
  - entity_id:
      - timer.schnellluftung
      - calendar.besuch
      - calendar.quarantane
      - calendar.abwesend
      - sensor.terrassentur_state
    trigger: state # Reaktion auf Kontextänderungen (Tür, Kalender, Timer)
  - entity_id: sensor.dunstabzugshaube_power
    above: 8
    trigger: numeric_state
  - entity_id: sensor.stromzahler_power_curr
    below: -70
    trigger: numeric_state # Trigger für Solar-Überschuss-Lüftung

conditions:
  - condition: state
    entity_id: input_boolean.luftungsanlage_belegung_ubergeordnet
    state: "off" # Globaler Kill-Switch für Wartung/Manuell

actions:
  - choose:
      # --- PRIORITÄT 1: SCHLECHTE AUSSENLUFT (ANLAGE AUS) ---
      # Logik: Verhindert das Ansaugen von Schadstoffen.
      - conditions:
          - condition: or
            conditions:
              - condition: template
                value_template: >-
                  {# Variablen definieren #}
                  {% set hum = states('sensor.airgradient_luftfeuchtigkeit')|float(0) %}
                  {% set nox = states('sensor.airgradient_nox_index')|float(0) %}
                  {% set pm = states('sensor.airgradient_pm25')|float(0) %}

                  {# TÜR-KORREKTUR: VOC-Spitzen durch offene Terrassentür filtern #}
                  {# Verhindert, dass austretende Innenluft als schlechte Außenluft interpretiert wird #}
                  {% set tuer_offen = not is_state('sensor.terrassentur_state', 'closed') %}
                  {% set tuer_frisch_zu = (now() - states.sensor.terrassentur_state.last_changed).total_seconds() < 180 %}
                  {% if tuer_offen or tuer_frisch_zu %}
                    {% set voc = 100 %} {# Neutraler VOC-Referenzwert während Türöffnung #}
                  {% else %}
                    {% set voc = states('sensor.airgradient_voc_index')|float(100) %}
                  {% endif %}

                  {# HYGROSKOPIE-KOMPENSATION: PM2.5 Schwellenwert dynamisch anpassen #}
                  {# Bei RH > 85% quellen Partikel auf. Wir fordern dann eine Bestätigung durch VOC oder NOx (Verbrennungsgase) #}
                  {% if hum > 85 %}
                    {% set pm_limit = 20 if (voc > 150 or nox > 20) else 60 %}
                  {% else %}
                    {% set pm_limit = 15 %} {# Standard-Schwelle bei trockenem Wetter #}
                  {% endif %}

                  {# Finale Auswertung: Abschalten wenn PM, VOC oder NOx (Abgas-Veto) zu hoch #}
                  {{ pm > pm_limit or nox > 50 or voc > 200 }}
        sequence:
          - action: script.turn_off
            target:
              entity_id: script.hausluftung_0_1_intervallbetrieb
          - action: fan.turn_off
            target:
              entity_id: fan.haus_ventilation

      # --- PRIORITÄT 2: HYSTERESE FÜR SCHLECHTE LUFT ---
      # Verhindert "Flimmern" der Anlage bei Werten nahe der Grenzschwelle
      - conditions:
          - condition: or
            conditions:
              - condition: template
                value_template: >-
                  {# Identische Logik wie oben, aber mit niedrigeren Einschalt-Schwellen #}
                  {% set hum = states('sensor.airgradient_luftfeuchtigkeit')|float(0) %}
                  {% set nox = states('sensor.airgradient_nox_index')|float(0) %}
                  {% set pm = states('sensor.airgradient_pm25')|float(0) %}
                  {% set tuer_offen = not is_state('sensor.terrassentur_state', 'closed') %}
                  {% set tuer_frisch_zu = (now() - states.sensor.terrassentur_state.last_changed).total_seconds() < 180 %}
                  {% if tuer_offen or tuer_frisch_zu %}
                    {% set voc = 100 %}
                  {% else %}
                    {% set voc = states('sensor.airgradient_voc_index')|float(100) %}
                  {% endif %}

                  {% if hum > 85 %}
                    {% set pm_limit = 15 if (voc > 130 or nox > 15) else 40 %}
                  {% else %}
                    {% set pm_limit = 12 %}
                  {% endif %}
                  {{ pm > pm_limit or nox > 30 or voc > 150 }}
          - condition: numeric_state
            entity_id: input_number.hausluftung_normallevel
            below: 1 # Greift nur, wenn die Anlage bereits im Zustand "AUS" ist
        sequence:
          - action: script.turn_off
            target:
              entity_id: script.hausluftung_0_1_intervallbetrieb
          - action: fan.turn_off
            target:
              entity_id: fan.haus_ventilation

      # --- PRIORITÄT 3: ABWESENHEITS-MODUS (ENERGIESPAREN) ---
      # Bei leerem Haus wird nur im Intervall (z.B. 15min An / 45min Aus) gelüftet
      - conditions:
          - condition: state
            entity_id: calendar.abwesend
            state: "on"
        sequence:
          - condition: state
            entity_id: script.hausluftung_0_1_intervallbetrieb
            state: "off"
          - action: script.turn_on # Startet das externe Intervall-Skript
            target:
              entity_id: script.hausluftung_0_1_intervallbetrieb

      # --- PRIORITÄT 4: SONDERLASTEN / FEUCHTESCHUTZ / SOLAR (100% POWER) ---
      # Boost-Modus für Dunstabzug, hohe Innenfeuchte oder Gratis-Strom bei Solar-Überschuss
      - conditions:
          - condition: or
            conditions:
              - condition: state
                entity_id: timer.schnellluftung
                state: active
              - condition: numeric_state
                entity_id: sensor.dunstabzugshaube_power
                above: 8
              - condition: state
                entity_id: calendar.quarantane
                state: "on"
              - condition: numeric_state
                entity_id: sensor.kuche_luftsensor_voc
                above: 200
              - condition: and # Entfeuchtung: Nur lüften wenn Außenluft trockener als Innenluft
                conditions:
                  - condition: numeric_state
                    entity_id: sensor.luftfeuchte_indoor_hochstwert
                    above: 64
                  - condition: template
                    value_template: "{{ states('sensor.luftfeuchte_indoor_hochstwert')|float(0) > states('sensor.airgradient_luftfeuchtigkeit')|float(0) }}"
              - condition: and # Solar-Kühlung im Sommer (Gratis-Lüftung bei PV-Überschuss)
                conditions:
                  - condition: numeric_state
                    entity_id: sensor.temperatur_indoor_mittelwert
                    above: 21
                  - condition: numeric_state
                    entity_id: sensor.stromzahler_power_curr
                    below: -70
                  - condition: template
                    value_template: "{{ states('sensor.heizung_aussentemperatur')|float(0) < (states('sensor.temperatur_indoor_mittelwert')|float(0) - 2) }}"
        sequence:
          - action: script.turn_off # Intervall stoppen falls aktiv
            target:
              entity_id: script.hausluftung_0_1_intervallbetrieb
          - action: fan.set_percentage
            target:
              entity_id: fan.haus_ventilation
            data:
              percentage: 100

      # --- PRIORITÄT 5: BESUCHER-MODUS (66% POWER) ---
      - conditions:
          - condition: state
            entity_id: calendar.besuch
            state: "on"
          - condition: numeric_state
            entity_id: input_number.anwesenheitsindikator_1_schaltungen_ohne_pixel_manipulation
            above: 0
        sequence:
          - action: script.turn_off
            target:
              entity_id: script.hausluftung_0_1_intervallbetrieb
          - action: fan.set_percentage
            target:
              entity_id: fan.haus_ventilation
            data:
              percentage: 66

    # --- DEFAULT: NORMALBETRIEB (33% POWER) ---
    # Wenn keine Sonderbedingungen erfüllt sind und die Außenluft sauber ist.
    default:
      - action: script.turn_off
        target:
          entity_id: script.hausluftung_0_1_intervallbetrieb
      - action: fan.set_percentage
        target:
          entity_id: fan.haus_ventilation
        data:
          percentage: 33

mode: restart # Wichtig: Automation bricht bei neuem Trigger ab und berechnet sofort neu.