Ventilation: Shelly 2.5 with 3-level switch

Hi,

I’ve created a yaml config file for the following config:

  • Venitlation unit (in my case a Storkair WHR 930), controlled via a Perilex Plug
  • Old-fashioned 3-level switch to control the ventilation unit
  • Shelly 2.5 to controll/influence the 3-level switch

These ventilation units are controlled relatively simple:
-when L1 is live/hot, the ventilation unit goes to medium
-when L2 is live/hot, the ventilation unit goed to high
-when L1 and L2 are not live, the ventilation unit goes to low
-it is not possible to have both L1 and L2 live/hot, the 3-level switch prevents that (middle position = both L1 and L2 are disconnected).

You simply connect output 1 and 2 of the 3-level switch to switch 1 and switch 2 of the Shelly 2.5. The outputs of the Shelly (L1 and L2) go to your ventilation unit.

Main features of the esphome solution below:

  • It creates an user-friendly select entity to Home Assistant. This select-entity shows the values low. medium and high and the end-user can easily switch between them. This is much more intuitive than stuff like “switching switch 1 off and switching switch 2 on”.
  • On power loss->restore, the Shelly will automatically switch the mode (low, medium or high) as is already set by the 3-level switch
  • Protection: it is impossible to have both switch 1 on and switch 2 on at the same time
  • Protection: overheating protection (both switches will be turned off if that happens).
substitutions:
  devicename: ventilation
  max_temp: "85.0"

esphome:
  name: ${devicename}
  friendly_name: Ventilation
  platform: ESP8266
  board: esp01_1m
  comment: Shelly 2.5
  # Ensures that, after a reboot, the ventilation will go to the state reflected by the physical knob. Since the relais go off first during the boot, the default value is already "Low" and does not need to be defined anymore.
  on_boot:
    if:
      condition:
        binary_sensor.is_on: switch_medium
      then:
        - select.set:
            id: balansventilatie
            option: "Medium"   
      else:
        if:
          condition:
            binary_sensor.is_on: switch_high
          then:
            - select.set:
                id: balansventilatie
                option: "High"   
# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "your_encryption_key"

ota:
  password: "your_password"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "your_hotspot_name"
    password: "your_hotspot_password"

captive_portal:

i2c:
  sda: GPIO12
  scl: GPIO14

sensor:
  - platform: ade7953
    irq_pin: GPIO16 # Prevent overheating by setting this
    voltage:
      name: ${devicename} Voltage
    # On the Shelly 2.5 channels are mixed ch1=B ch2=A
    current_a:
      name: ${devicename} Current B
    current_b:
      name: ${devicename} Current A
    active_power_a:
      name: ${devicename} Active Power B
      # active_power_a is normal, so don't multiply by -1
    active_power_b:
      name: ${devicename} Active Power A
      # active_power_b is inverted, so take the absolute value
      filters:
        - lambda: return abs(x);
    update_interval: 60s

  # NTC Temperature
  - platform: ntc
    sensor: temp_resistance_reading
    name: ${devicename} Temperature
    unit_of_measurement: "°C"
    accuracy_decimals: 1
    icon: "mdi:thermometer"
    calibration:
      b_constant: 3350
      reference_resistance: 10kOhm
      reference_temperature: 298.15K
    on_value_range:
      - above: ${max_temp}
        then:
          - switch.turn_off: Relay_Medium
          - switch.turn_off: Relay_High
          - homeassistant.service:
              service: persistent_notification.create
              data:
                title: Message from ${devicename}
              data_template:
                message: Switch turned off because temperature exceeded ${max_temp}°C
  - platform: resistance
    id: temp_resistance_reading
    sensor: temp_analog_reading
    configuration: DOWNSTREAM
    resistor: 32kOhm
  - platform: adc
    id: temp_analog_reading
    pin: A0

status_led:
  pin:
    number: GPIO0
    inverted: yes

switch:
  - platform: gpio
    id: Relay_Medium
    name: ${devicename} Relay Medium
    pin: GPIO4
    icon: "mdi:electric-switch"
    restore_mode: always_off
    # Ensure only one switch at a time is on (https://esphome.io/components/switch/gpio.html#interlocking)
    interlock: &interlock_group [Relay_Medium, Relay_High]
    on_turn_on:
      then:
        - select.set:
            id: balansventilatie
            option: "Medium"      
    on_turn_off:
      then:
        - select.set:
            id: balansventilatie
            option: "Low" 
  - platform: gpio
    id: Relay_High
    name: ${devicename} Relay High
    pin: GPIO15
    icon: "mdi:electric-switch"
    restore_mode: always_off
    interlock: *interlock_group
    on_turn_on:
      then:
        - select.set:
            id: balansventilatie
            option: "High"      
    on_turn_off:
      then:
        - select.set:
            id: balansventilatie
            option: "Low" 

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO13
    name: ${devicename} Switch Medium
    id: switch_medium
    publish_initial_state: false
    on_press:
      then:
        - select.set:
            id: balansventilatie
            option: "Medium"
    on_release:
      then:
        - select.set:
            id: balansventilatie
            option: "Low"
  - platform: gpio
    pin:
      number: GPIO5
    name: ${devicename} Switch High
    id: switch_high
    publish_initial_state: false
    on_press:
      then:
        - select.set:
            id: balansventilatie
            option: "High"
    on_release:
      then:
        - select.set:
            id: balansventilatie
            option: "Low"

select:
  - platform: template
    name: Balansventilatie
    id: balansventilatie
    options:
     - "Low"
     - "Medium"
     - "High"
    restore_value:  false
    optimistic: true
    on_value:
      then:
        - lambda: |-
            if (id(balansventilatie).state == "Low") {
            id(Relay_Medium).turn_off();
            id(Relay_High).turn_off();
            } else if (id(balansventilatie).state == "Medium") {
              id(Relay_Medium).turn_on();
            } else if (id(balansventilatie).state == "High") {
              id(Relay_High).turn_on();
            }

End-result in Home Assistant:

I hope this helps others.

1 Like

Looks great! Does the physical button (3 steps) still work in this solution?

And is this only possible with a Shelly 2.5, or can other models work as well?

Thanks! The physical button still works in this solution. This solution fully depends on the availibitly of two relays and two inputs (one for each relais, so they can be controlled via the physical button), plus the ability to flash epshome.

As per my knowlegde, the Shelly 2.5 is the only model from Shelly that meets those requirements.

1 Like

Super, thanks! I figured out I don’t have a neutral wire behind my 3 steps level switch, thus that would be my first challenge. :-). Will have a look if I can add it within my ventilation unit (instead of adding it behind the switch).

Does it also work without the 3-level switch, just only connect the shelly 2.5?

Yes it does work without the 3-level switch.