Mixing valves / central heating / 3-way mixers / floor heating

intro:
i had my water-based wall heating’s temperatures regulated by node red over mqtt/tasmota the last couple of years, but as this setup started acting up and HA got more established in my home lately i figured i should reconsider doing this in esphome/HA directly.

the chicken coop incident

in europe most motorized 3-way mixing valves like this or this seem to work similar. they have 2 AC lines in - one driving the motor to one direction, the other to the opposite, an internal endstop seems to turn off the motor and it doesn’t explode or anything if you happen to have both lines live at a time (at least for a short period of time). most common seem to be a running time of 120s for the full 90° angle.

there are several threads in here asking about how to use these 3 way mixing valves with esphome, mostly concentrating on the aspect of using it with the thermostat/climate component - which is meant to be a simple on or off of a heating or cooling device to achieve a certain temperature. but actually the challenge most (like myself) face is how to best implement these timings and switches and ideally get a position … then i remembered my chicken coop door …

and so it struck me: the valve is a cover!

specifically a time based cover as we know the time it takes for fully opening and closing and have no endstops. it might also be possible with a template cover, but so far i found no need for it.

so i went on flashing my sonoff 4ch with esphome.
in my installation the first relay switches the circulating pump, the second turns the mixer left (‘closing’ / letting less hot water in), the third one to the right (/‘opening’), the fourth unused till now.

switch:
- platform: gpio
  name: "heating 4chR1"
  pin: GPIO12
  id: relay_1
- platform: gpio
  name: "heating 4chR2"
  pin: GPIO5
  id: relay_2
- platform: gpio
  name: "heating 4chR3"
  pin: GPIO4
  id: relay_3
- platform: gpio
  name: "heating 4chR4"
  pin: GPIO15
  id: relay_4

so the magic for getting this controlled follows:

cover:
  - platform: time_based
    name: "Mixer"

    open_action:
      - switch.turn_on: relay_3
    open_duration: 120sec

    close_action:
      - switch.turn_on: relay_2
    close_duration: 120sec

    stop_action:
      - switch.turn_off: relay_3
      - switch.turn_off: relay_2

and that’s actually it for esphome

(unless you want to also make the physical buttons on the 4ch useable)
binary_sensor:
- platform: gpio
  pin:
    number: GPIO0
    mode:
      input: true
      pullup: true
    inverted: true
  name: "heating 4chB1"
  on_press:
    - switch.toggle: relay_1
- platform: gpio
  pin:
    number: GPIO9
    mode:
      input: true
      pullup: true
    inverted: true
  name: "heating 4chB2"
  on_press:
    - switch.toggle: relay_2
- platform: gpio
  pin:
    number: GPIO10
    mode:
      input: true
      pullup: true
    inverted: true
  name: "heating 4chB3"
  on_press:
    - switch.toggle: relay_3
- platform: gpio
  pin:
    number: GPIO14
    mode:
      input: true
      pullup: true
    inverted: true
  name: "heating 4chB4"
  on_press:
    - switch.toggle: relay_4
- platform: status
  name: "heating 4CH Status"

on to home assistant, to get the basics going for testing i set up a dashboard with an entity card of the four relays and one for the mixer:

image

whereas the position isn’t usually part of a mixer’s entity card. for that i installed the great lovelace-slider-entity-row which gives a controllable visual feedback of the cover’s state. very cool.

with that, the card’s code looks like that:

type: entities
entities:
  - entity: cover.heating_sonoff4ch_mixer
    name: Mixer
    icon: mdi:valve
  - type: custom:slider-entity-row
    entity: cover.heating_sonoff4ch_mixer
    name: Position
    icon: none

… and it just works.

now on we go, trying to get the cover’s actions implemented in a climate component - not sure yet if in HA or esphome directly, as the sensor data comes from another device…

hope this helps someone at some point.

That’s a really nice idea and solution!
For robustness you could implement a full close or open cycle after restart (or power failure), since the device might loose sync.
Maybe even every x hours.

Hi, great approach. I’m still struggling with how to set the desired temperature effectively. How do you manage it, for example, if you want the automation to aim for 30°C? My solution isn’t working well—it opens the valve, waits until the temperature reaches 31°C, then slowly closes the valve, but by then the temperature rises to 33°C. After a delay, it drops back to 30°C, and the cycle repeats. Hoping I can adopt your approach. Thanks for sharing your work and thank you for your help.

1 Like

this is how things work for this kind of ‘delayed’ systems - on average it should result in the temperature you set. one could implement a PID controller, but that’s usually overkill (assuming we’re talking about central heating)

Alright, thanks. Overkill sounds good. Maybe I’ll make a PID-thing my next project.

Hi
I’m pretty new into this stuff. I want to implement this into my central heating using same device. Could you provide more information, perhaps for temp sensor, I saw can be added also to sonoff 4ch. How you actually set and controll your target temperature? I am now waiting all necessary hardware to arrive in order to flash esphome and start playing :slight_smile:

script:
#RADIKA3T
  - id: radikakolmteekraanlahti
    then: 
    - repeat:
        count: 200
        then:
    
        - switch.turn_on: radika3tlahti
        - delay: 800ms
        - switch.turn_off: radika3tlahti
        - delay: 12s

  - id: radikakolmteekraankinni
    then:
    - repeat:
        count: 200
        then:
        - switch.turn_on: radika3tkinni
        - delay: 800ms
        - switch.turn_off: radika3tkinni
        - delay: 12s

and climat :

climate:
  #RADIKAKLIIMA 
  - platform: thermostat
    name: Radikakontuur
    id: radikakontuur
    icon: mdi:heater
    visual:
      min_temperature: 20 °C
      max_temperature: 75 °C
      temperature_step: 0.1 °C
    min_idle_time: 2s
    min_heating_run_time: 2s
    min_cooling_run_time: 2s
    min_heating_off_time: 2s
    min_cooling_off_time: 2s
    heat_overrun: 0.0
    heat_deadband: 0.0
    cool_overrun: 0.0
    cool_deadband: 0.0
    sensor: pealevool
    
    heat_action:
      - script.execute: radikakolmteekraanlahti
      - switch.turn_off: radika3tkinni
    cool_action:
      - script.execute: radikakolmteekraankinni
      - switch.turn_off: radika3tlahti
    idle_action:
      - script.stop: radikakolmteekraanlahti
      - script.stop: radikakolmteekraankinni
      - switch.turn_off: radika3tkinni
      - switch.turn_off: radika3tlahti

position is not visible,but works perfectly.