Auto heating control - not easy :)

Hello. Please help. I tried to read many posts before but seems like nobody discussed about such way before.

Facts:
10 rooms
10 temperature sensors - 1 in every room (Philips HUE motion sensor with temp ability)
10 thermoelectric actuators (installed on floor heating valves) - single for every room
1 electric heater
1 fireplace (with water heating)

Idea:
In every room is a temperature sensor. Using HA GUI we can decide what is desired temperature in this room. Based on this (real temperature over or under) switch (tasmota) for thermoelectric actuator will turn On or OFF the floor water heating into this room.
Only selected rooms has right to decide whether heating in house will be Enabled or Disabled. LetĀ“s call them Room1, Room2 and Room3.
In those rooms are temp sensors A, B and C.

Solution:
I think I could use standard Generic Thermostat for all rooms to open/close thermoelectric actuators of floor heating into those rooms.
BUT how to create the part where some of those rooms are able to decide if heater will turn on?
To create automation? Or is there some other tool?
I thought I could check state of all those valve switches which belongs to the rooms 1,2 and3 which has right to Enable/Disable heating. If any of those switches will be in state ON= turn heating ON. If none of those switches will be in status ON then turn heating OFF. How to do it?

This picture shows what I need. Just to TURN ON/OFF heater (in fact some automation switch because heater in my concept means to tun on electric heater (switch tasmota) and repositioning of water circuit valve (switch tasmota) or choosing heating from fireplace if water collected in tank is over 50Ā°C - another 2switches) - but this is another automation :slight_smile:

1 Like

I like to use template binary sensors and/or automations with multiple trigger that set booleans for this sort of thing, subsequently using the output of the binary_sensor/boolean to control the device.

Example, I have some LEDā€™s running along the kick-boards in the kitchen that light up the floor, but I only want them on if itā€™s dark, if the living room light is on, and ā€˜movie modeā€™ isnā€™t on. So for that I use:

binary_sensor:
  platform: template
  sensors:
    floor_light_control:
      value_template: >
        {{ is_state('light.livingroom' , 'on')
          and is_state('input_boolean.dark' , 'on' )
          and is_state('switch.movie_mode' , 'off') }}

automation:
  - alias: Lighting - Floor light control
    trigger:
      platform: state
      entity_id: binary_sensor.floor_light_control
    action:
      service_template: "homeassistant.turn_{{ states('binary_sensor.floor_light_control') }}"
      entity_id: light.floor_lights

I decide itā€™s dark based on light levels going below 20, itā€™s then light again above 40, so I use:

automation:
  - alias: Lighting - Darkness monitor
    trigger:
      - platform: numeric_state
        entity_id: sensor.average_light_level
        below: 20
      - platform: numeric_state
        entity_id: sensor.average_light_level
        above: 40
    action:
      service_template: >
        {% if states('sensor.average_light_level')|int < 21 %} homeassistant.turn_on
        {% else %} homeassistant.turn_off {% endif %}
      entity_id: input_boolean.dark

As for the heating in your scenario, you just need to convert your flow chart in to the booleans and sensors. Mine is nowhere near as complicated as itā€™s just one boiler, switching on/off based on occupancy, time of day and average temperatureā€¦

sensor:
  - platform: template
    sensors:
      average_temperature:
        friendly_name: Average Temperature
        device_class: temperature
        unit_of_measurement: Ā°C
        value_template: >
          {{ (( states('sensor.bathroom_temperature')|float + states('sensor.attic_temperature')|float +
            states('sensor.landing_temperature')|float + states('sensor.hall_temperature')|float +
            states('sensor.kitchen_temperature')|float ) / 5 )|round(2) }}

automation:
  - alias: Heating - Thermostat timer
    trigger:
      - platform: state
        entity_id: input_boolean.boost_heating
      - platform: time
        at: '06:00:00'
      - platform: time
        at: '09:00:00'
      - platform: time
        at: '15:00:00'
      - platform: time
        at: '21:00:00'
      - platform: homeassistant
        event: start
      - platform: state
        entity_id: sensor.home_status
      - platform: numeric_state
        entity_id: sensor.average_temperature
        below: 16.1
      - platform: numeric_state
        entity_id: sensor.average_temperature
        above: 17.0
    action:
      service_template: >
        {% if is_state('input_boolean.boost_heating' , 'on') or
          ( is_state('sensor.home_status' , 'Occupied') and now().hour
          in [6 , 7 , 8 , 15 , 16 , 17 , 18 , 19 , 20] and
          states('sensor.average_temperature')|float <= 16.0 ) %} homeassistant.turn_on
        {% else %} homeassistant.turn_off {% endif %}
      entity_id: switch.thermostat

I actually found that the generic thermostat component didnā€™t work very well. It either wouldnā€™t switch on or wouldnā€™t switch off when it should. This works perfectly, and in the event we need a ā€˜boostā€™ I just have (as you can see) an input boolean that overrides all the timings and temperatures. A separate automation turns the boolean off automatically after an hour.

Hope this helps.

Oh, thanks @anon43302295. Could you please explain what this does?
value_template: > {{ (( states('sensor.bathroom_temperature')|float + states('sensor.attic_temperature')|float + states('sensor.landing_temperature')|float + states('sensor.hall_temperature')|float + states('sensor.kitchen_temperature')|float ) / 5 )|round(2) }}

Yeah, adds the current temperature of all the temperature sensors together, divides them by the number there are (5) to get the average temperature of the house, gives the result with 2 decimal points :slightly_smiling_face:

Oh nono. This is not my concept :). I donĀ“t need this. I need to have every room separate to control their floor heating valve. But only few of those rooms are able to run central heating (to pump heat water into floor).

Indeed. I wasnā€™t suggesting you copy my homework, I was suggesting you be inspired by it as a potential option and generate a configuration that worked for you based on similar principles.

1 Like

I think itā€™s a very bad idea to offer money for a solution, you should learn to use Home Assistant and do this yourself. The community will be happy to help you if you try yourself, post your non-working code and get to your goal on an iterative basis.

I try to understand your request, please correct me if Iā€™m wrong.

Room 1, 2 and 3:

Temperature sensor A, B or C < threshold temperature -> Turn heating in the house ON

Temperature sensor A, B or C > threshold temperature -> Turn heating in the house OFF

Rooms 4 - 10:

Temperature sensor of the respective room < threshold temperature -> Turn heating in this room ON

Temperature sensor of the respective room > threshold temperature -> Turn heating in this room OFF

Questions:

What should happen if e.g. the temperature in Room 1 is below the threshold and the temperature in Room 2 is above threshold, should the heating be ON or OFF?

3 Likes

Thank you @Burningstone you are right, it is better to learn as V.I.Lenin said :).

So, let me please do some correction:
Room 1, 2 and 3:
Temperature sensor of the respective room < threshold temperature -> Turn heating in this room ON AND Temperature sensor A, B or C < threshold temperature -> Turn heating in the house ON
Temperature sensor of the respective room < threshold temperature -> Turn heating in this room OFF AND Temperature sensor A, B or C > threshold temperature -> Turn heating in the house OFF
Rooms 4 - 10:
Temperature sensor of the respective room < threshold temperature -> Turn heating in this room ON
Temperature sensor of the respective room > threshold temperature -> Turn heating in this room OFF

Questions:
What should happen if e.g. the temperature in Room 1 is below the threshold and the temperature in Room 2 is above threshold, should the heating be ON or OFF? In case of turning heating in respective room it just turns heating in its room (opens water valve). Just like any others. BUT if we are talking about HOUSE HEATING (central source of heat water for all rooms)) it will TURN OFF if NONE of rooms 1,2 or 3 will need to heat and will TURN ON if ANY of rooms 1,2 or 3 will need heat.

Other rooms just must wait for central heat source (for rooms 1,2 or 3) to run even if they need to heat. Those other rooms just opens their water valves but the water will not flow until room 1,2 or 3 will give command to central heater (and also opens their water valves).

Hope it is clear now :slight_smile: sorry for my bad english.

I will not write the code for you, but Iā€™ll help you if you try it yourself :wink:

Read about automations here:


and here

Some examples:

Read these pages, and then try with the below info to do your automations.

You need these two automations to turn on/off the central heating.

Turn on heating house

Trigger:
Sensor A < temperature threshold OR
Sensor B < temperature threshold OR
Sensor C < temperature threshold
Action:
Turn House Heating ON

Turn off heating house

Trigger:
Sensor A > temperature threshold OR
Sensor B > temperature threshold OR
Sensor C > temperature threshold
Condition:
Sensor A > temperature threshold AND
Sensor B > temperature threshold AND
Sensor C > temperature threshold
Action:
Turn House Heating OFF

And then for each room one automation for turning ON and one for turning OFF the room specific heating.

Turn on heating room
Trigger:
Sensor Room < temperature threshold
Action:
Turn room specific heating ON

Turn off heating room
Trigger:
Sensor Room > temperature threshold
Action:
Turn room specific heating OFF

4 Likes

Yes I know automations. I use them. My HA does quite a lot things using them including simple heating control right now. But I need an advice if I should use generic thermostat (some people says that doesnā€™t work well, sometimes forget to turn on/off etc.) or if I should use automation scripts only or Schedy or ā€¦ But automation will be not so sexy regarding to GUI as generic thermostat has temp setting directly in GUI, away mode etc. I just need to show proper way to do it the best way with future problem elimination. This automation will work with heating which could be quite dangerous in some cases so I need something really solid.

So maybe I could use simple generic termostat to control every roomā€™s water valve opening - goal 1 done. And also use automation which will check if any of predefined valves (of those 1,2,3 rooms) is opened = turn ON heating or all closed=turn OFF heating. Goal 2 done. I think this could be the simplest way. But is generic termostat and automation the best way? In near future I will also need to do some simple temp schedules for day/night or home/away. Thank you.

Wow. I just did this for myself this past week. I have some infra-red controllable heat pumps that I wanted to automate, so I wrote a way-too-complex series of automations to implement an MQTT climate component. I can share the YAML if you like.

Thanks, please share. Just for inspiration. I think I will use generic thermostat component because I need some kind of GUI but will gladly check your work. Thanks.

I have a GUI for mineā€¦I use the lovelace thermostat card. I only used the MQTT stuff because I couldnā€™t figure out how to use the generic thermostat! Maybe itā€™s way simpler, but I was mystified by it.

The basics of my implementation were that I added some input_number and input_select entities to hold the values for the ā€œthermostatā€ so it could persist across restarts, and then had the climate component send certain MQTT messages to communicate changes in temperature, mode, etc. Automations then picked up those MQTT messages and stored the values to the input entities, and sent out another MQTT status message which simulated an actual device responding.

I have a couple of other automations to activate or shut off the heat pump depending on what mode I have it set to, and a range of temperature based on high and low bounds. I have to clean up the YAML a bit, but Iā€™ll post it when I do.

Hereā€™s the YAML. Hopefully itā€™s readable to somebody else. Feel free to ask questions, Iā€™m sure there are things I havenā€™t explained well ā€“ but everything has a purpose and a reason :slight_smile:

image
Iā€™m using the ā€˜simple thermostat cardā€™.

First the actual climate entity and the backing input entities:

climate:
  - platform: mqtt
    name: recroom
    current_temperature_topic: stat/NodeMCU04/STATUS8
    current_temperature_template: '{{ states.sensor.recroom_data.attributes.StatusSNS.DHT11.Temperature | float }}'
    action_topic: climate/recroom/stat
    action_template: '{{ value_json.action }}'
    mode_command_topic: climate/recroom/MODE
    mode_state_topic: climate/recroom/stat
    mode_state_template: '{{ value_json.mode }}'
    modes: ['off', 'cool', 'dry', 'heat']
    temperature_command_topic: climate/recroom/TEMP
    temperature_state_topic: climate/recroom/stat
    temperature_state_template: '{{ value_json.temp }}'
    fan_mode_command_topic: climate/recroom/FAN
    fan_mode_state_topic: climate/recroom/stat
    fan_mode_state_template: '{{ value_json.fan }}'
    fan_modes: ['auto', 'low', 'medium', 'high']
    min_temp: 17
    max_temp: 30
    temp_step: 0.1

input_text:
  # this stores the parameter for the command line that I use to send the IR command to the heat pump
  livingroom_heatpump_command:
    name: livingroom_heatpump_command
    
input_number:
  # How far the temp can dip below the set point before the heating/cooling turns on.
  livingroom_temperature_range_low:
    min: 0
    max: 5
    mode: box
    unit_of_measurement: 'Ā°C'

  # How far the temp can rise above the set point before the heating/cooling turns off
  livingroom_temperature_range_high:
    min: 0
    max: 5
    mode: box
    unit_of_measurement: 'Ā°C'

  # The temperature set point for the thermostat
  livingroom_heatpump_temp:
    min: 17
    max: 30
    step: 0.1
    mode: slider
    icon: mdi:thermometer
    unit_of_measurement: 'Ā°C'

input_select:
  # The 'mode' of the thermostat
  livingroom_heatpump_mode:
    icon: mdi:air-conditioner
    options:
      - 'off'
      - 'heat'
      - 'cool'
      - 'dry'
      - 'fan'

  # The fan speed for the heat pump
  livingroom_heatpump_fanspeed:
    icon: mdi:fan
    options:
      - 'auto'
      - 'low'
      - 'medium'
      - 'high'

Next, I have a few template sensors to detect how far off the temperature is from the set point: The first one is the difference. Normally, if the temp is hotter than the set point, itā€™s positive, but I have a multiplier in there so that if weā€™re cooling the ā€œhighā€ value (which will actually be negative) comes out to be positive as well. If the mode is set to ā€˜offā€™, the multiplier is set to 0, so the ā€˜highā€™ and ā€˜lowā€™ sensors will always be 0, and wonā€™t try to activate the heating/cooling.

sensor:
  - platform: template
    sensors:
      recroom_temperature_diff:
        entity_id:
          - input_select.recroom_heatpump_mode
          - input_number.recroom_heatpump_temp
          - sensor.recroom_temperature_statistics
        unit_of_measurement: 'Ā°C'
        value_template: >
          {%- set area = 'recroom' -%}
          {%- set diff = states('sensor.' + area + '_temperature_statistics')|float - states('input_number.' + area + '_heatpump_temp')|float -%}
          {%- set multiplier = 1 -%}
          {%- if is_state('input_select.' + area + '_heatpump_mode', 'cool' ) -%}
            {%- set multiplier = -1 -%}
          {%- elif is_state('input_select.' + area + '_heatpump_mode', 'off') -%}
            {%- set multiplier = 0 -%}
          {%- endif -%}
          {{ (diff * multiplier) | round(1) }}

binary_sensor:
  - platform: template
    sensors:
      livingroom_temperature_diff_high:
        entity_id:
          - sensor.livingroom_temperature_diff
          - input_number.livingroom_temperature_range_high
        value_template: >
          {{ (states('sensor.livingroom_temperature_diff') | float) 
              > (states('input_number.livingroom_temperature_range_high') | float) }}

      livingroom_temperature_diff_low:
        entity_id:
          - sensor.livingroom_temperature_diff
          - input_number.livingroom_temperature_range_low
        value_template: >
          {{ (states('sensor.livingroom_temperature_diff') | float) 
              < (states('input_number.livingroom_temperature_range_low') | float * -1) }}

Now we have the MQTT automations. The climate entity will send MQTT messages whenever you call one of the climate services (or you change one of the settings on the lovelace card). These automations, just listen for those messages, and store the payload in the input entities we defined earlier.

automation:
  - alias: livingroom_heatpump_mode
    trigger:
      - platform: mqtt
        topic: 'climate/livingroom/MODE'
    action:
      - service: input_select.select_option
        data_template:
          entity_id: input_select.livingroom_heatpump_mode
          option: >
            {{ trigger.payload }}

  - alias: livingroom_heatpump_fanspeed
    trigger:
      - platform: mqtt
        topic: 'climate/livingroom/FAN'
    action:
      - service: input_select.select_option
        data_template:
          entity_id: input_select.livingroom_heatpump_fanspeed
          option: >
            {{ trigger.payload }}

  - alias: livingroom_heatpump_temp
    trigger:
      - platform: mqtt
        topic: 'climate/livingroom/TEMP'
    action:
      - service: input_number.set_value
        data_template:
          entity_id: input_number.livingroom_heatpump_temp
          value: >
            {{ trigger.payload }}

Hereā€™s where it gets a little crazy. I use the sensors above to to maintain an input_text of the command line parameter I need to use to control the actual heat pump, but because everything affects everything else, I found that I ran into a race condition, where if I called a service to set both the temperature and the mode together, the climate component would sent two separate MQTT messages. Then because various sensors and automations are triggered by both the mode and temp changes, I wasnā€™t getting the correct status in the end, because some automations were triggering before all the changes had taken effect.

I introduced a 1 second timer so I could effectively wait for the value of input_text.livingroom_heatpump_command to ā€˜stabilizeā€™, i.e., remain unchanged for at least 1 second. Unfortunately, you canā€™t use the for attribute of the state trigger unless you also specify the from or to attribute, neither of which I would know.

timer:
  livingroom_heatpump_command:
    duration: '00:00:01'

automation:
  - alias: livingroom_heatpump_status_changed
    trigger:
      - platform: state
        entity_id: input_text.livingroom_heatpump_command
    condition:
      - condition: template
        value_template: >
          {{ trigger.from_state.state
            and (trigger.from_state.state not in ['', 'unknown', 'undefined'])
            and (trigger.from_state.state != trigger.to_state.state) }}
    action:
      - service: script.livingroom_climate_stat
        data_template:
          area: 'livingroom'
          send_command: false
      - service: timer.start
        data:
          entity_id: timer.livingroom_heatpump_command

  - alias: livingroom_heatpump_status_stable
    trigger:
      - platform: event
        event_type: timer.finished
        event_data:
          entity_id: timer.livingroom_heatpump_command
    condition:
      - condition: template
        value_template: >
          {{ not is_state('input_text.livingroom_heatpump_command', '') }}
    action:
      - service: script.livingroom_climate_stat
        data_template:
          area: 'livingroom'
      - service: mqtt.publish
        data_template:
          topic: climate/livingroom/COMMAND
          payload: "/home/hass/config/ircommand.sh --command LivingroomHeatPump,{{ states('input_text.livingroom_heatpump_command').split('_')[0] }}"
      - service: shell_command.livingroom_heatpump_command

Hereā€™s the script that publishes the MQTT status message back to the climate entity, simulating the device talking back to HA:

script:
  livingroom_climate_stat:
    sequence:
      - service: mqtt.publish
        data_template:
          topic: >
            climate/{{ area | lower }}/stat
          retain: true
          payload: >
            {%- set area = area | lower -%}
            {%- set mode = states('input_select.' + area + '_heatpump_mode') -%}
            {%- set action = 'idle' -%}
            {%- if (mode == 'off') -%}
              {%- set action = 'off' -%}
            {%- elif (states('input_text.' + area + '_heatpump_command') | lower).startswith(mode) -%}
              {%- set action = mode + 'ing' -%}
            {%- endif -%}
            {{
              {
                'mode': mode,
                'action': action,
                'temp': states('input_number.' + area + '_heatpump_temp'),
                'fan': states('input_select.' + area + '_heatpump_fanspeed'),
              } | to_json
            }}

Lastly, there is the automation used to fill out the command input_text, and the shell_command itself. This is where your implementation will almost certain differ from mine:

automation:
  - alias: livingroom_heatpump_command
    trigger:
      - platform: state
        entity_id:
          - input_number.livingroom_heatpump_temp
          - input_select.livingroom_heatpump_mode
          - input_select.livingroom_heatpump_fanspeed
          - binary_sensor.livingroom_temperature_diff_high
          - binary_sensor.livingroom_temperature_diff_low
    action:
      - service: input_text.set_value
        data_template:
          entity_id: input_text.livingroom_heatpump_command
          value: >
            {%- set area = 'livingroom' -%}
            {%- set entity = 'climate.' + (area | lower) -%}
            {%- set mode = states('input_select.' + area + '_heatpump_mode') | lower -%}
            {%- set temp = states('input_number.' + area + '_heatpump_temp') | float | round(1) -%}
            {%- set fanspeed = states('input_select.' + area + '_heatpump_fanspeed') | lower -%}
            {%- set sensorName = 'binary_sensor.' + (area | lower) + '_temperature_diff_' -%}

            {%- if (mode == 'off') or is_state(sensorName + 'high', 'on') -%}
              PowerOff_{{ temp }}
            {%- elif mode in ['heat', 'cool'] and is_state(sensorName + 'low', 'on') -%}
              {%- set heatpumpTemp = temp -%}
              {%- if is_state('input_select.' + area + '_heatpump_mode', 'heat') -%}
                {%- set heatpumpTemp = temp + 2.5 -%}
              {%- elif is_state('input_select.' + area + '_heatpump_mode', 'cool') -%}
                {%- set heatpumpTemp = temp - 2.5 -%}
              {%- endif -%}
              
              {%- if heatpumpTemp > state_attr(entity, 'max_temp') | float -%}
                {%- set heatpumpTemp = state_attr(entity, 'max_temp') | float -%}
              {%- elif heatpumpTemp < state_attr(entity, 'min_temp') | float -%}
                {%- set heatpumpTemp = state_attr(entity, 'min_temp') | float -%}
              {%- endif -%}

              {{ mode }}{{ heatpumpTemp | round(0) | int }}_{{ temp }}
            {%- else -%}
              {# If we don't have cause to change, then keep the sensor value the same as it was. #}
              {{ states('input_text.' + area + '_heatpump_command') }}
            {%- endif -%}

shell_command:
  livingroom_heatpump_command: /home/hass/config/ircommand.sh --command "LivingroomHeatPump,{{ states('input_text.livingroom_heatpump_command').split('_')[0] }}"

Edit: fixed typos.

4 Likes

The generic climate stuff used to work wellā€¦after they rehauled it, itā€™s been kinda poor.

1 Like

Thatā€™s a damn good spec to write an automation to, everything you need is right there. :+1:

1 Like

You mean automation only? Which will check every temp sensor like ā€¦ IF ā€¦ IF ā€¦ IF ā€¦THEN ā€¦

Thanks, is there some article about this?

Burning, I think there needs to be a House heating on condition in here
And in the latter another trigger if the House heating goes off (Or are you assuming some internal convection to get the last fews ergs out of it ??? )

"Jiran - Yes

Weā€™ve not seen any code youā€™ve written so far so we canā€™t help much more. :man_shrugging:

1 Like

You are right, I somehow didinā€™t think about it. Thanks for the pointer!