Tim's blah blah blah

Optimizing Itho HRU 350 control via MQTT and Home Assistant

I have an Itho HRU 350 in my home, which is CO₂ controlled, but unfortunately it’s a very crude & noisy control algorithm. Here I document my approach to improve this.

Current situation & goal

Out of the box, the Itho HRU 350 (and other ventilation boxes) run at low speed (~700 rpm in my case) until the CO₂ level gets too high (>1200 ppm in my case), when it spins up to a rather noisy ~3300 rpm. When CO₂ is below 1000 ppm it slows down again. This is a rather blunt scheme that we can easily improve.

Goal: get more gradual control on the ventilation box, specifically:

  1. CO₂ <500ppm: run at auto setting (~700 rpm)
  2. CO₂ 500-800ppm: run at medium settinfg (~1400 rpm)
  3. CO₂ 800-1100ppm: run at autonight setting (~1800 rpm)
  4. CO₂ >1100ppm: run at high setting (~2900 rpm)

Hardware

I got a pre-built ESP8266 board from Arjen Hiemstra at NRG.watch (nrgwatch.nl). I tried to solder on the CC1101 myself and failed, so would recommend to save the frustration and spend 5 EUR to have it pre-soldered.

Connecting the board to the Itho HRU was done with a 15cm straight 8p UTP cable.

Software

I got the software from Arjen Hiemstra’s IthoWifi (github.com) and combining it with Home Assistant as documented on the Non-CVE units (github.com), MQTT integration (github.com), and Home Assistant (github.com) wiki pages.

Configure module

On the module’s config page:

  1. Set ‘Home Assistant MQTT Discovery’ to off
  2. Set ‘Normalize keys’ to on
  3. Set up virtual remote. It’s important to set this up in order for the module to send the right commands. See details on remote types here (github.com).

Configure Itho

On the ‘Itho settings’ page you can query the >100 settings and try to optimize the unit yourself. I haven’t found any documentation, and setting names are quite cryptic, but I did find:

  1. Increase ‘autonight’ speed - this is useful because autonight also triggers higher speed on high CO₂
    1. Set ‘80 - Number of floors (floor)’ to max of 2.
    2. Set ‘81 - Inhabitants (inhab)’ to max of 3.
  2. Tweak high/low CO₂ threshold
    1. Set ‘78 - PoorCo2Quality (ppm)’ to lowest value 1501
    2. Set ‘79 - GoodCo2Quality (ppm)’ to mid value 1000

Configure Home Assistant

Add config to Home Assistant. Ensure you merge this config with existing mqtt/sensor configuration (e.g. you should only have one ‘mqtt’ key, Home Assistant will give an error if you don’t.)

mqtt:
  sensor:
    - name: "itho_hru_co2"
      unique_id: "itho_hru_co2"
      state_topic: "itho/ithostatus"
      value_template: "{{ value_json['highest-received-co2-value_ppm'] }}"
      unit_of_measurement: "ppm"
      device_class: carbon_dioxide 
      state_class: 'measurement' 
      device: { identifiers: ["mqtt", "nrg-itho-28ac"] }
    - name: "itho_hru_exhaust_fan_actual"
      unique_id: "itho_hru_exhaust_fan_actual"
      state_topic: "itho/ithostatus"
      unit_of_measurement: "rpm"
      value_template: "{{ value_json['exhaust-fan-actual_rpm'] }}"
      device: { identifiers: ["mqtt", "nrg-itho-28ac"] }
    - name: "itho_hru_supply_fan_actual"
      unique_id: "itho_hru_supply_fan_actual"
      state_topic: "itho/ithostatus"
      unit_of_measurement: "rpm"
      value_template: "{{ value_json['supply-fan-actual_rpm'] }}"
      device: { identifiers: ["mqtt", "nrg-itho-28ac"] }
    - name: "itho_hru_exhaust_temp"
      unique_id: "itho_hru_exhaust_temp"
      state_topic: "itho/ithostatus"
      unit_of_measurement: "°C"
      device_class: temperature
      value_template: "{{ value_json['exhaust-temp_c'] }}"
      device: { identifiers: ["mqtt", "nrg-itho-28ac"] }
    - name: "itho_hru_supply_temp"
      unique_id: "itho_hru_supply_temp"
      state_topic: "itho/ithostatus"
      unit_of_measurement: "°C"
      device_class: temperature
      value_template: "{{ value_json['supply-temp_c'] }}"
      device: { identifiers: ["mqtt", "nrg-itho-28ac"] }
  binary_sensor:
    - name: "itho_hru_bypass"
      unique_id: "itho_hru_bypass"
      state_topic: "itho/ithostatus"
      value_template: "{{ value_json['bypass-position'] }}"
      payload_off: 0
      payload_on: 1
      device_class: opening
      device: { identifiers: ["mqtt", "nrg-itho-28ac"] }
  fan:
    - name: "itho_hru_fan"
      device:
        identifiers: ["mqtt", "nrg-itho-28ac"]
        model: ITHO Wifi Add-on
        name: itho_hru_fan_device
          #availability_topic: itho/state          
      unique_id: itho_hru_fan
      state_topic: itho/lwt
      payload_on: "online"
      payload_off: "offline"
        #state_value_template: '{% if value == "online" %}ON{% else %}OFF{% endif %}'
        #      json_attributes_topic: itho/ithostatus
      command_topic: "itho/cmd"
      preset_mode_state_topic: "itho/ithostatus"
      preset_mode_command_template: "{ vremote: '{{ value }}'}"
      preset_mode_value_template: >
       {% set am = value_json['actual-mode'] | int %}
         {% if am == 1 %}
           low
         {% elif am == 2 %}
           medium
         {% elif am == 3 %}
           high
         {% elif am == 13 %}
            timer
         {% elif am == 24 %}
           auto
         {% elif am == 25 %}
           autonight
         {% else %}
           {{ am }}
         {% endif %}       
      preset_mode_command_topic: "itho/cmd"
      preset_modes:
       - "low"
       - "medium"
       - "high"
       - "auto"
       - "autonight"
       - "timer1"
       - "timer2"
       - "timer3"

Test via Home Assistant Developer tools -> Services

  1. fan.set_preset_mode ‘high’ - works
  2. fan.set_preset_mode ‘medium’ - works
  3. fan.set_preset_mode ’low’ - works
  4. fan.set_preset_mode ‘autonight’ - works

Automate controls

Goal

Now that we can control the Itho unit, it’s time to implement our improved control algorithm:

Goal:

  1. Ensure that time-average CO₂ stays as close to outdoor level as possible at comfortable ventilation
    1. Ensure that CO₂ never exceeds 1000 ppm for long
    2. Ensure quiet operation of ventilator –> max rpm ~2500

Algorithm:

  1. CO₂ <500ppm: run at auto setting (~700 rpm)
  2. CO₂ 500-800ppm: run at medium settinfg (~1400 rpm)
  3. CO₂ 800-1100ppm: run at autonight setting (~1800 rpm)
  4. CO₂ >1100ppm: run at high setting (~2900 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 states.fan.itho_hru_350.attributes.preset_mode != timer1/timer2/timer3

Hardware

My ventilator box runs at the following speeds & power consumption levels before calibration:

Itho HRU 350 rpm-power response

Because the power goes with the cube of speed (engineeringtoolbox.com), it can be worthwhile to see what maximum speed you need. In my case I reduced the highest setting a bit using the potentio meter on the box.

Itho HRU 350 controls are on the left lower side of the unit.

Itho HRU 350 controls are on the left lower side of the unit.

Itho HRU 350 controls have two potentiometers labeled I and II to set the low and high fan speeds respectively.

Itho HRU 350 controls have two potentiometers labeled I and II to set the low and high fan speeds respectively.

After calibration:

Home Assistant implementation

There’s a few approaches that could work:

  1. Set up timer job, check every 5 min and set mode according to CO₂ - Pro: easy Con: no ’low pass filter’ / could trigger at spiky value
  2. Run automation on CO₂ level and change when it crosses a boundary (i.e. platform: numeric_state) - Pro: can use ‘for’ setting to prevent spurious triggers.
  3. Use value_template to check from_state & to_state. Pro: triggers only on threshold crossing. Con: does not have ’low pass filter’ / could trigger at spiky value
  4. Use wait_for_trigger to return to low speed when ventilation is done. Pro: works nicely for 2 levels. Con: only for 2 levels?
  5. Use filter integration (home-assistant.io) to filter the underlying sensor value, combine with timer automation? Pro: easy, works, robust Con: sends commands more than necessary, overrides user setting

In the end I used option 2 from above, which has now been running well for a few weeks. I split the automation into 4 levels which gives me more fine-grained control (continuous control would still be better but somehow Itho decided against this for the HRU 350).

alias: Itho control override
description: ""
trigger:
  - id: auto
    platform: numeric_state
    entity_id: sensor.max_co2
    for:
      hours: 0
      minutes: 10
      seconds: 0
    below: 500
  - id: medium
    platform: numeric_state
    entity_id: sensor.max_co2
    for:
      hours: 0
      minutes: 10
      seconds: 0
    above: 500
    below: 800
  - id: autonight
    platform: numeric_state
    entity_id: sensor.max_co2
    for:
      hours: 0
      minutes: 10
      seconds: 0
    above: 800
    below: 1100
  - id: high
    platform: numeric_state
    entity_id: sensor.max_co2
    for:
      hours: 0
      minutes: 10
      seconds: 0
    above: 1100
condition:
  - condition: not
    conditions:
      - condition: state
        entity_id: fan.itho_hru_350
        attribute: preset_mode
        state:
          - timer1
          - timer2
          - timer3
action:
  - service: fan.set_preset_mode
    data:
      preset_mode: "{{ trigger.id }}"
    target:
      entity_id: fan.itho_hru_350
mode: single

#Diy #ESP8266 #Home-Assistant #Home-Improvement #Smarthome