How to control ventilation speed depending on multiple thresholds of CO2?

I want to improve the silly off/max control algorithm in my Itho HRU ventilator box. The goal is:

  1. Run at auto mode when CO2 <600ppm (~700 rpm)
  2. Run at autonight mode when max CO2 800-1000ppm (~1600 rpm)
  3. Run at high mode when CO2 >1000ppm (~3000 rpm)

Boundary conditions:

  1. Don’t change speed unnecessarily → only trigger when level changed for more than X minutes
  2. Don’t override timer functions used for e.g. getting rid of humidity → use != timer1/timer2/timer3

I considered a several options, only one that meets above requirements:

  1. Use automation with value_template to check from_state & to_state combined with a filter integration on the underlying sensor value to smoothen it. Use condition to check that is OK.

Other options I considered:

  1. Set up timer job, check every 5 min and set mode according to CO2 - Pro: easy Con: trigger too often
  2. Run automation on CO2 level and change when it crosses a boundary (i.e. platform: numeric_state) - Pro: can use ‘for’ setting to prevent spurious triggers. Con: need multiple automations? Triggers multiple times?
  3. Use wait_for_trigger to return to low speed when ventilation is done (E.g. here). Pro: works nicely for 2 levels. Con: not sure how to expand to three levels.

Somehow I feel there might be a more elegant solution (e.g. not requiring editing configuration.yaml manually & leveraging the for option in value automations), does anyone have a suggestion?

Should be easy enough with just numeric state triggers.

  - id: auto
    platform: numeric_state
    entity_id: sensor.co2_ppm
    below: 600
      minutes: 5
  - id: autonight
    platform: numeric_state
    entity_id: sensor.co2_ppm
    below: 1000
    above: 800
      minutes: 5
  - id: high
    platform: numeric_state
    entity_id: sensor.co2_ppm
    above: 1000
      minutes: 5

Use a state or template condition to detect this and prevent the actions occurring.


  - condition: not
      - condition: state
          - timer1
          - timer2
          - timer3

Then use {{ }} in your actions to set the mode.

    - service: fan.set_preset_mode
        entity_id: fan.itho_hru_350
        preset_mode: "{{ }}"

Thanks for your reply. I didn’t know about using as action parameter, that’s an elegant approach.

Still a question: I had something like that in mind, but won’t trigger this continuously if the value is stable at a certain value? e.g. It will trigger at 10:00, then again at 10:05 because the value was again X for 5min, and again at 10:10, etc. In that case I could also use a timer?

No, that is not how numeric state triggers work. Lets take the simplest example:

  - id: auto
    platform: numeric_state
    entity_id: sensor.co2_ppm
    below: 600
      minutes: 5

For this trigger to occur the sensor value must cross from above 600 to below 600 and stay there for 5 minutes.

It will not trigger again unless the sensor value goes above 600 then back to below 600 and stay there for 5 minutes.

So if your sensor is flapping about going above and below 600 you get no triggers.

If your sensor goes below 600 and stays there for 5 minutes you get one trigger. If it stays below 600 until the heat death of the universe you still only get that one trigger at the 5 minute mark.

This catches people out all the time. Instead of “numeric_state” it should really be called “numeric_threshold”. But it’s far too late for that now.

Thanks for the explanation @tom_l! I RTFM and indeed it says

“Fires when the numeric value of an entity’s state ([…]) crosses a given threshold”

Apologies for assuming I understood numeric_state, I’ll try to help spread the gospel of numeric_threshold :wink:

1 Like