Hvac automation not working correctly any longer (had worked before) pls help

Hi everybody,

below is my automation for automatically switching thermostats depending on window open/closed state. They used to work just fine until recently (there was no update in Home Assistant, but I did upgrade zigbee2mqtt in between - not sure if this is related), but now they don’t do what they used to.

  • Home Assistant 0.103.4
  • Zigbee2mqtt Version 1.9.0
  • coordinator {'type': 'zStack3x0', 'meta': {'transportrev': 2, 'product': 1, 'majorrel': 2, 'minorrel': 7, 'maintrel': 1, 'revision': 20191106}} (Hardware Texas Instruments CC1352P-2)
  • Thermostat Eurotronic SPZB0001

Originally, they would trigger whenever either a thermostat was set to a different temperature or when I window state toggled. When a window opened, it would set hvac_mode: off, otherwise (= window shut again) it would set hvac_mode: heat. Example:

  • window closed
  • thermostat on 17.5°C
  • window then opened
  • thermostat set to off (= 5°C)
  • window closed again
  • thermostat set to heat (= back to whatever degrees it had been before, in this case 17.5)

Now this automation causes my thermostats to constantly be at 30°C, which seems to be “on” mode. I can not manually turn them down, as they are triggered by any change in temperature, which will cause them to revert to 30°C.

This automation is currently deactivated; however, this also means the thermostats will not change when windows change their status.

Another problem that has existed previously as well, but also needs to be fixed, is this: when an automation (below as well) changes the temperature, the automation above will not trigger. So let’s say I open a window at night. This would set hvac_mode: off; however, if the automation turns up the heat at 6am (while the window is still open, the automation responsible for this will not turn it right back to hvac_mode: off, but rather just set it to whatever the automation set it at 6am (even though the window is still open!)

automation for controlling thermostats depending on window state

automation:
  - alias: "[Heizungen] Auto On/Off"
    trigger:
      - platform: state
        entity_id:
          - binary_sensor.arbeitszimmer_fenster_contact
          - binary_sensor.kueche_fenster_contact
    action:
      - service: climate.set_hvac_mode
        data_template:
          entity_id: >
            {% set zimmer = trigger.to_state.object_id.split('_')[0] %}
            climate.{{zimmer}}_heizung_climate
          hvac_mode: >
            {% if trigger.to_state.state == "on" %}
            off
            {%elif trigger.to_state.state == "off" %}
            heat
            {% endif %}

  - alias: "[Heizungen Fenstercheck]"
    trigger:
      - platform: state
        entity_id: 
          - climate.arbeitszimmer_heizung_climate
          - climate.jonna_heizung_climate
    action:
      - service: climate.set_hvac_mode
        data_template:
          entity_id: >
            {% set raum = trigger.to_state.object_id.split('_')[0] %}
            climate.{{raum}}_heizung_climate
          hvac_mode: >
            {% set fenster = 'binary_sensor.' ~ trigger.to_state.object_id.split('_')[0] ~ '_fenster_contact' %}
            {% if states(fenster) == "on" %}
            off
            {% elif states(fenster) == "off" %}
            heat
            {% endif %}
          # {{ 'off' if is_state(fenster, 'on') else 'heat' }}

automation for changing thermostats at certain times

input_number:
  az_morgens:
    name: "AZ 08:30"
    initial: 18
    <<: &input_template
      min: 5
      max: 30
      step: 0.5
      icon: mdi:radiator
      unit_of_measurement: "°C"
  az_abends:
    name: "AZ 19:25"
    initial: 15
    <<: *input_template

automation:
  # Arbeitszimmer {{{
  - id: "heizung_az_morgens"
    alias: "[Heizung] AZ 08:30"
    trigger:
      - platform: time
        at: "08:30:00"
    action:
      - service: climate.set_temperature
        data_template:
          entity_id: climate.arbeitszimmer_heizung_climate
          temperature: "{{ states('input_number.az_morgens') | float }}"
  - id: "heizung_az_abends"
    alias: "[Heizung] AZ 19:25"
    trigger:
      - platform: time
        at: "19:25:00"
    action:
      - service: climate.set_temperature
        data_template:
          entity_id: climate.arbeitszimmer_heizung_climate
          temperature: "{{ states('input_number.az_abends') | float }}"
  # }}}

Would anybody please help me fix this? Currently it is as if I had regular (“non-smart”) thermostats. If a window gets opened, the corresponding thermostat has to be turned off manually. And because the second automation will set thermostats to other values even if their corresponding window(s) are open, I cannot reliably set temperatures at specific times.

Thank you for your input :slight_smile:

Looking at the service templates you provided, they could be failing because there is not an else statement. I would change that first then see if it reacts differently.

    action:
      - service: climate.set_hvac_mode
        data_template:
          entity_id: >
            {% set zimmer = trigger.to_state.object_id.split('_')[0] %}
            climate.{{zimmer}}_heizung_climate
          hvac_mode: >
            {% if trigger.to_state.state == "on" %}
            off
            {% else %}
            heat
            {% endif %}
    action:
      - service: climate.set_hvac_mode
        data_template:
          entity_id: >
            {% set raum = trigger.to_state.object_id.split('_')[0] %}
            climate.{{raum}}_heizung_climate
          hvac_mode: >
            {% set fenster = 'binary_sensor.' ~ trigger.to_state.object_id.split('_')[0] ~ '_fenster_contact' %}
            {% if states(fenster) == "on" %}
            off
            {% else %}
            heat
            {% endif %}
          # {{ 'off' if is_state(fenster, 'on') else 'heat' }}```

Thank you @walrus_parka unfortunately this did not make a difference.

  • thermostat on 17°C, window closed
  • window opens
  • thermostat “off” (5°C)
  • window closes
  • thermostat “on” (30°C)

At the point where it switches to “on”, it previously always reverted to whatever value had been set before. But now it doesn’t. I am currently trying to switch heat with auto. Will update this post if it works.

update

Yeah, changing heat to auto seems to work (it did not, but I only checked one thermostat so far). But I hope this solved that problem… so I don’t believe the else was really the issue. I tried both versions (the one @walrus_parka suggested and the one I had previously used), and it seems like they both work.

so

now there is only the other automation left to fix. I cannot even reproduce the problem. When I change temperature (either manually on the thermostat itself, or via Home Assistant lovelace), it works. Example

  • window is open
  • thermostat is at 5°C / off
  • I change temperature to 12°C
  • after a few seconds (when the change has been registered by Home Assistant), it will be set back to 5°C / off

However!!:

  • window is open
  • thermostat at 5°C
  • temperature changes via the automation above
  • other automation (the first from above) will not trigger, so thermostat will be left at whatever the second automation has set it to
  • when I then manually change the temperature (or close and re-open the window), it will be set to 5°C / off

So I don’t understand why, but it seems like the automation changing the temperature does not work as a trigger for the other automation, but any manual interaction will…

Hello again prankousky.
Walrus_parka is correct : -
‘if’ there’s an ‘if’ there’s ‘always’ an ‘else’
It ‘may’ not have made a difference here as you were testing a binary condition, but it’s bad programming practice and will trip you up in other circumstances, causing further actions not to evaluate in that automation or script.

I assume you have a climate control (thermostat) for each room ?
And the output (heater:) is the radiator valve?
And that if you see any valve open (on) the boiler runs ?
I have found that external thermostats are temperamental and/or that calling to them increases battery usage. Just leave them to themselves and they will update the temp after a set time or if it changes by a certain amount.
Also changing the ‘heat mode’ of the generic thermostat sometimes (with the recent updates) leaves it not knowing what to do.
The best way I’ve found to deal with it is to leave it on ‘heat’ permanently.
Just change the set points.
A room set to heat to 4°C is effectively off anyway, or it’s protecting your pipes from freezing.
So feed the temperature sensor direct to the generic_thermostat and adjust your room setpoint according to : - door/window open 4, house unoccupied 14, room unoccupied 14, day 18, evening 19 and night 16 (or whatever)

Give me 10 mins, ill post my script fot the value as an example : -
When this value changes it triggers an automation to update the generic thermostat (also below)

NOTE : The door/window open step is currently just a place holder (not got them all set up yet)
The above suggestion about room occupancy is to cater for a guest bedroom or perhaps a child away at university or similar, remove/add as requied

script:
## resets temperature following any pattern change
  sc_heat_reset_value:
    alias: Heating Reset Value
    sequence:
    - service: input_number.set_value
      data_template:
        entity_id: input_number.in_heat_temp_control_val
        value: >
          {% if false and not is_state('binary_sensor.bs_door_open', 'on') %}
            {{ '4' | float }}
          {% elif not is_state('binary_sensor.bs_occupied', 'on') %}
            {{ states('input_number.in_heat_temp_away_val') | float }}
          {% elif  is_state('binary_sensor.bs_heat_night_active', 'on') %}
            {{ states('input_number.in_heat_temp_night_val') | float }}
          {% elif is_state('binary_sensor.bs_heat_day_active', 'on') %}
            {{ states('input_number.in_heat_temp_day_val') | float }}
          {% else %}
            {{ states('input_number.in_heat_temp_evening_val') | float }}
          {% endif %}
#### end of template

#different day periods
binary_sensor:
  - platform: template
    sensors:
      ## used to doors open
      bs_heat_door_open:
        # entity_id: 
        value_template: >
          {% set fdoor = is_state('front_door', 'open') %}
          {% set kdoor = is_state('kitchen_door', 'open') %}
          {{ fdoor or kdoor }}
        icon_template: "{{ 'mdi:door-open' if is_state('binary_sensor.bs_heat_door_open', 'on') else 'mdi:door' }}"
        friendly_name: Heating, Doors Open
      ## used to indicate day slot
      bs_heat_day_active:
        entity_id: sensor.time, input_datetime.id_heat_day_on, input_datetime.id_heat_evening_on
        value_template: >
          {% set time = states('sensor.time') %}
          {% set slt1start = states('input_datetime.id_heat_day_on') [0:5] %}
          {% set slt1stop = states('input_datetime.id_heat_evening_on') [0:5] %}
          {% set slt1on = (slt1start <= time < slt1stop) if (slt1start < slt1stop) else (slt1start <= time or time < slt1stop) %}
          {{ slt1on }}
        icon_template: "{{ 'mdi:shovel' if is_state('binary_sensor.bs_heat_day_active', 'on') else 'mdi:timer-sand' }}"
        friendly_name: Day Heat Slot Active
      ## used to indicate evening slot
      bs_heat_evening_active:
        entity_id: sensor.time, input_datetime.id_heat_night_on, input_datetime.id_heat_evening_on
        value_template: >
          {% set time = states('sensor.time') %}
          {% set slt1start = states('input_datetime.id_heat_evening_on') [0:5] %}
          {% set slt1stop = states('input_datetime.id_heat_night_on') [0:5] %}
          {% set slt1on = (slt1start <= time < slt1stop) if (slt1start < slt1stop) else (slt1start <= time or time < slt1stop) %}
          {{ slt1on }}
        icon_template: "{{ 'mdi:glass-cocktail' if is_state('binary_sensor.bs_heat_evening_active', 'on') else 'mdi:timer-sand' }}"
        friendly_name: Evening Heat Slot Active
      ## used to indicate night slot
      bs_heat_night_active:
        entity_id: sensor.time, input_datetime.id_heat_night_on, input_datetime.id_heat_day_on
        value_template: >
          {% set time = states('sensor.time') %}
          {% set slt1start = states('input_datetime.id_heat_night_on') [0:5] %}
          {% set slt1stop = states('input_datetime.id_heat_day_on') [0:5] %}
          {% set slt1on = (slt1start <= time < slt1stop) if (slt1start < slt1stop) else (slt1start <= time or time < slt1stop) %}
          {{ slt1on }}
        icon_template: "{{ 'mdi:sleep' if is_state('binary_sensor.bs_heat_night_active', 'on') else 'mdi:timer-sand' }}"
        friendly_name: Night Heat Slot Active

automation:
#name: Heat Temperature Set Value
  - alias: au_heat_temperature_set_value
    trigger:
      - platform: state
        entity_id: binary_sensor.bs_occupied
      - platform: state
        entity_id: binary_sensor.bs_door_open
      - platform: state
        entity_id: binary_sensor.bs_heat_day_active
      - platform: state
        entity_id: binary_sensor.bs_heat_evening_active
      - platform: state
        entity_id: binary_sensor.bs_heat_night_active
    action:
      - service: script.sc_heat_reset_value
# name: Heat Temperature Set
  - alias: au_heat_temperature_set
    trigger:
      - platform: state
        entity_id: input_number.in_heat_temp_control_val
    action:
      - service: climate.set_temperature
        data_template:
          entity_id: climate.house_heat
          temperature: "{{ states('input_number.in_heat_temp_control_val') | float }}"

Thank you for your code. I will look into it in the afternoon and see if I can apply it to my automation.

Yes. I live in Germany, where unfortunately we usually do not have central AC. So there is a radiator in each room, and one smart thermostat on each radiator valve.

The thermostats I use work like this: there is a temperature sensor build into the thermostat. I can set my wish temperature and it will regulate the valve accordingly. While I do also have Xiaomi temperature sensors, I do not use them with this. The internal thermostat temperature sensors seems to be pretty accurate when I compare it to the Xiaomi sensor (the Xiaomi sensors are not directly next to the thermostat, so there is always a slight difference, but I expected that).

I am trying to do this via time trigger; however, the reason I revert to the previous temperature when closing the window is that we also manually (via Home Assistant) control these thermostats. Sometimes 19°C is too warm in the evening, so we set them at 17.5; when we then open a window, and later close it again, I want the thermostat to be at whatever it had been manually set to (17.5), not what it automatically would be at this time (19). There is a profile per room as you described. But in case manually adjustments are made, they should be permanent until the next time trigger applies, not “reset” any manually set value because a window binary_sensor toggles. Hopefully I explained this understandably; I am not a native speaker so if this is not clear, please let me know and I’ll try to rephrase.

Okay, you have the tools, you have the intelligence (I’ve seen you about here) and you can ask most any of us for help, so good look luck (sorry, autocorrect or sheer laziness :smiley: ) .

But…
Can I ask some further questions ?
It would be fairly easy to have an input number store the last ‘change’ be it manual or automated.
Though you’d have to remove the window sensor from the triggers/reset script
And have then in a service template that chooses the ‘change’ value or a window open value.
But I’m not following why an occupant would need to change the value, if it was okay on Monday, Tuesday and Wednesday. Why is it not okay on Thursday ?
If it’s not okay on any day then change the profile ?

From what you have said, I gather that you are using ‘something like’ the fibaro trv with its temperature sensor (thermostat) .
You say that it keeps reverting to 30 degrees because you try to set it as a thermostat, so why keep using it as a thermostat and not just as a plain sensor ?

It doesn’t matter if you answer the above the important thing is just to consider it

It would be fairly easy to have an input number store the last ‘change’ be it manual or automated.

First thing that comes to mind would be mqtt; however, I feel like that is an extra step. If I turn hvac_mode: off, the current temperature is already still there, but the thermostat will turn itself off, therefore not using that temperature (instead 5°C, which is this thermostats minimum setting)

These are two separate automations.

automation1 => either window state changes (on to off or off to on) or temperature changes => if window open = hvac_mode off, else hvac_mode auto

automation2 => at [5am, 11am, 4pm] turn thermostat [x,y,z] to [10, 15, 19] degrees

automation2 will set the same temperature every day. This is an actual example for the kitchen: 14°C at 9pm - 22.5°C at 7.30am - 18°C at 9.30am. It is the same every day. An occupant would manually change this (NOT the automation, just the current temperature via climate entity) if they are in a room that feels to warm/cold for them at the time. If I am done making coffee at 8.15, the kitchen doesn’t need to be at 22.5°C any longer, so I’ll manually turn it down.

Currently, automation1 works fine. I do not have to change anything any longer. If a window changes from closed to open, the thermostat in that room will be turn to hvac_mode off. If the same window closes, it will set the termostat to hvac_mode auto, thus reverting to whatever temperature had been previously set to this thermostat.

However, when automation2 is executed, automation1 will not be triggered. So if the kitchen window is currently open (= thermostat hvac_mode off) and automation2 changes the temperature, what should happen is automation1 being triggered (because the temperature has been changed, which is a trigger in automation1) and therefore keep hvac_mode off; but it does not. It changes the temperature and even though the window is opened, will turn on the heat.

I am using Eurotronic SPZB0001 zigbee thermostats. Each of those are connected to a radiator’s valve; so instead of turning the valve from 0 - 5, I can set it to, for example, 17.5 degrees. The sensor will measure every so often, the change the valve accordingly.

Reverting to 30°C has been fixed. When I changed hvac_mode: on to hvac_mode: auto, it would not longer do this. This must have been a change in either Home Assistant or zigbee2mqtt (I assume the latter, as I only updated this before the problem started occurring). But it is fine now.

What I still need to fix is that automation1 still has to be triggered, even when changing temperature via automation2. As I said before, this is very hard to debug, as it works just fine when I manually (via Home Assistant climate entity, or directly on the thermostat) change the temperature. Only when triggered via automation2 (so automatically, without me doing anything) at a specific time, it feels like automation2 overrides automation1, so even though a window is still open, the radiator will not be turned off.

A huge problem here is zigbee2mqtt, too. I had been using the CC2531 and CC2530 combination, which was always buggy, then switched to the CC1352P-2, but devices will still disconnect randomly. Currently, one of my living room windows will not report its status correctly (or rather: not at all). The sensor is dead until I manually re-pair it with zigbee2mqtt; same with one particular thermostat, it will always disconnect, sometimes still transmitting its status, but not receiving temperature changes I try to set. So besides working on these automations I am working on an ESPHome prototype multisensor for things like windows, temperature, light, etc., so that I will not have to rely on zigbee so much in the future. It makes things much harder than they need to be.