core icon indicating copy to clipboard operation
core copied to clipboard

Generic Thermostat - cycles if both tolerances are zero

Open borpin opened this issue 3 years ago • 25 comments

The problem

Generic Thermostat - cycles if both tolerances are zero and the current temperature = target temperature.

I am using the Generic Thermostat to control my UFH. I want the thermostat to turn the heating off when at target temp, and turn it on when it falls below target temp by 0.1 degrees.

https://github.com/home-assistant/core/blob/41d2ab5b375564ccbc836736fa8896a758cffc2e/homeassistant/components/generic_thermostat/climate.py#L479-L480

If the hot and cold tolerances are 0 (zero), both too_cold and too_hot evaluate to True when current temp = target temp.

This results in the thermostat cycling (while current temp = target temp) at the min cycle rate.

https://github.com/home-assistant/core/blob/41d2ab5b375564ccbc836736fa8896a758cffc2e/homeassistant/components/generic_thermostat/climate.py#L482-L482

https://github.com/home-assistant/core/blob/41d2ab5b375564ccbc836736fa8896a758cffc2e/homeassistant/components/generic_thermostat/climate.py#L493-L493

Example: - if the room is currently at 20.5 with heating off and a schedule sets the target temperature to 20.5, the heating will needlessly come on.

What version of Home Assistant Core has the issue?

2022.9.7

What was the last working version of Home Assistant Core?

No response

What type of installation are you running?

Home Assistant OS

Integration causing the issue

Generic Thermostat

Link to integration documentation on our website

https://www.home-assistant.io/integrations/generic_thermostat/

Diagnostics information

No response

Example YAML snippet

- platform: generic_thermostat
  name: sunroom
  heater: switch.tasmota4
  target_sensor: sensor.sunroomtemp
  min_temp: 18
  max_temp: 22
  cold_tolerance: 0.0
  hot_tolerance: 0.0
  precision: 0.1
  min_cycle_duration:
    minutes: 10
  initial_hvac_mode : "heat"
  away_temp: 16

Anything in the logs that might be useful for us?

No response

Additional information

Solution: add an extra condition such that if both too_hot and too_cold are true, the device is always switched off or if already off no action.

borpin avatar Oct 05 '22 18:10 borpin

Anyone?

borpin avatar Oct 22 '22 15:10 borpin

Anyone? 😄

borpin avatar Oct 26 '22 08:10 borpin

Just preventing this going stale.

borpin avatar Oct 31 '22 07:10 borpin

Thoughts?

borpin avatar Nov 18 '22 09:11 borpin

Please don't go stale

borpin avatar Nov 24 '22 08:11 borpin

Still an issue

borpin avatar Feb 10 '23 22:02 borpin

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

Still an Issue

https://github.com/home-assistant/core/blob/e904edb12e7ff5b96ee86741fcb52bffd72fc498/homeassistant/components/generic_thermostat/climate.py#L484

borpin avatar May 12 '23 05:05 borpin

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

This is still an issue as it hasn't been fixed.

borpin avatar Aug 13 '23 19:08 borpin

@borpin What would be your proposed solution?

rrooggiieerr avatar Nov 04 '23 05:11 rrooggiieerr

What would be your proposed solution?

@rrooggiieerr, both too_hot and too_cold need to be false when target = curr and both tolerances are zero.

For compatibility (as I'm probably slightly edgecase having tolerances of 0) and excuse my pseudocode.

if self._cold_tolerance = 0.0 then
  too_cold = self._target_temp > self._cur_temp
else
  too_cold = self._target_temp => self._cur_temp + self._cold_tolerance 
end if

If self._hot_tolerance = 0.0 then
  too_hot = self._cur_temp > self._target_temp
else
  too_hot = self._cur_temp => self._target_temp + self._hot_tolerance
end if

If then a user adds a tolerance of 0.1 to either, the thermostat will trigger even if target = curr (with precision of 0.1), and equally, with a tolerance of 0 it will trigger as when target /= curr by 0.1.

However, when target = curr and tolerances are 0, both tool_cold and too_hot will be false (as it should be).

Anyone who had it set as zero and was quite happy potentially needs to add a minimum value at their precision. Chances are they had not noticed the cycling.

borpin avatar Nov 06 '23 07:11 borpin

Why not make the hot and cold tolerances 0.1 if they are 0.0?

if self._cold_tolerance == 0.0:
  self._cold_tolerance = 0.1
if self._hot_tolerance == 0.0:
  self._hot_tolerance = 0.1

rrooggiieerr avatar Nov 10 '23 07:11 rrooggiieerr

Had a big think about this 😄

Why not make the hot and cold tolerances 0.1 if they are 0.0?

Your solution does assume a step of 0.1 though and it would have to be heavily comment that to explain why it has been added, whereas the other code is more verbose so should be apparent why it is there. Seems too much of a kludge to me.

However, in running through the scenarios, I realised that I had missed a very important state - just_right 😄 This is where I came unstuck last time I tried to solve the cycling.

There is an implicit assumption in the code currently that a room is always either too_hot or too_cold (one is TRUE and the other is FALSE). This is a false assumption. There are a number of combinations (negative tolerances) where both can be true, i.e. the room is just_right.

Is this statement true - At just_right the device should always be off (heating or cooling)?

If it is (and I think it is), then the solution is that if both too_hot and too_cold are TRUE, then the device should be switched off. What the tolerances actually are is irrelevant.

If so, the solution is to test for this first, and if true then if the device is on, switch it off else do nothing.

https://github.com/home-assistant/core/blob/be2cee228cc50cd9558a80f7a56b1d5b515ec03b/homeassistant/components/generic_thermostat/climate.py#L495-L498

          if (too_cold and too_hot):
              if self._is_device_active: 
                _LOGGER.info("Turning off heater %s", self.heater_entity_id)
                await self._async_heater_turn_off()
          elif self._is_device_active:
              if (self.ac_mode and too_cold) or (not self.ac_mode and too_hot):

borpin avatar Nov 13 '23 21:11 borpin

I still have to think about your proposed solution, I agree that code should be self explanatory. But in the meantime I have one question for you. How often is it going to happen that the temperature is exactly right?

By the time you have powered on your heater there will be energy stored in whatever kind of medium your heater uses, water/air/oil/etc, and this energy will be released over time. Also when you have already powered off your heater. There will always be some under/over shoot. The whole idea of having this tolerance is to create a certain bandwidth wherein your heater operates. A tolerance of 0 is unrealistic.

rrooggiieerr avatar Nov 13 '23 22:11 rrooggiieerr

How often is it going to happen that the temperature is exactly right?

I have a near PassiveHaus standard build with a low temperature UFH system. The temperature is often very stable. A tolerance of 0 at a step of 0.1, means it will be triggered 'on' if the temp drops 0.1 degrees below target and go off again when the 2 temps match (fine so far). The issue is that, it should not then come on until the temp drops again. In fact, it comes on again because the temps are the same.

A graph of the cycling (target 21 min cycle 10 mins). The first on shouldn't happen as it has simply dropped to target. You can also see the cycling eventually pushes it above target - i.e. overheats. This is a good example as there was no one in the property at this time so no other factors except the UFH.

image

Fundamentally, there is an error in the state machine for this integration in that it does not account for the state of just_right.

borpin avatar Nov 14 '23 09:11 borpin

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

Still an issue that should be addressed.

borpin avatar Feb 12 '24 15:02 borpin

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

Still an issue. I have an automation to override the switch on when target temp has been reached.

borpin avatar May 15 '24 13:05 borpin

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

The logic is still not correct.

borpin avatar Aug 20 '24 06:08 borpin

Looking after another issue, I came across this one. Isn't what you want a hot_tolerance of 0 and a cold_tolerance of 0.1? This means heating until: ambient >= set temperature +0 . Then not heating until: set temperature >=(ambient + 0.1)

Besides: The fact that too_hot and too_cold are true at the same time doesn't matter, since the code also looks at wether you're in AC mode (cooling) So when (cooling and too_cold) OR (heating and too_hot): turn off cooler/heater etc.

wltng avatar Oct 05 '24 18:10 wltng

Isn't what you want a hot_tolerance of 0 and a cold_tolerance of 0.1?

No, because it only then changes when the temperature reaches 0.2 beyond the tolerance (if you do this hot or cold).

It is a bug - programmatically, the logic is flawed.

borpin avatar Oct 05 '24 20:10 borpin

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.

No this is still an issue so should be left open

borpin avatar Jan 06 '25 11:01 borpin

@borpin I just finished working on changes to the generic_thermostat (in a PR that's not yet accepted), and stumbled upon this issue; figured I'd give it a look since I have looked over most of the code for this integration already.

At first glance, a change to just the logic for too_hot and too_cold could solve the problem (plus I think for a bit more clarity I'd flip the variables around for too_cold so the formula is a bit more apparent it's actually comparing a colder temp):

            too_cold = self._cur_temp < self._target_temp - self._cold_tolerance
            too_hot = self._cur_temp > self._target_temp + self._hot_tolerance

This change would prevent it turning on when your target temp is reached, however it would now cause it to NOT turn off when your target temp is reached and run until you are your hot/cold tolerance BEYOND the target temp. I think instead that the fix is to embed the different comparisons directly in to the logic for turning on/off:

To determine if it's time to turn off: https://github.com/home-assistant/core/blob/85794568957c9e32c13b3206b79a53c4a078340a/homeassistant/components/generic_thermostat/climate.py#L542 should be changed to:

                if (self.ac_mode and self._cur_temp <= self._target_temp - self._cold_tolerance) or (not self.ac_mode and self._cur_temp >= self._target_temp + self._hot_tolerance):

and to determine if it's time to turn on: https://github.com/home-assistant/core/blob/85794568957c9e32c13b3206b79a53c4a078340a/homeassistant/components/generic_thermostat/climate.py#L552 should be changed to:

            elif (self.ac_mode and self._cur_temp > self._target_temp + self._hot_tolerance) or (not self.ac_mode and self._cur_temp < self._target_temp - self._cold_tolerance):

I believe this would correct the issue for you?

Side note: looking at the tolerance settings, I don't completely agree with how they function. The tolerances don't seem to create a range/dead-zone where it won't activate which is what a tolerance should do - but that's a separate fix/issue which I could also work on correcting.

esand avatar Feb 03 '25 13:02 esand

Excellent some work is being done on this.

I think the solution is simpler than your suggestion.

If you have the code below so removing the = (note this would be a significant change and should be clearly flagged)

too_cold = self._cur_temp < self._target_temp - self._cold_tolerance too_hot = self._cur_temp > self._target_temp + self._hot_tolerance

when the tolerances are zero, both conditions can then be false (if curr = target).

I think there should be a new condition in the if that if both too_hot and too_cold are false (in any mode), then stop doing whatever it is you are doing, either cooling or heating depending on mode, as you have reached the target temp.

Even easier is to leave above code as is and add in a condition when both are true (less of a change for others) to again stop what is being done (either heating or cooling) as the target temperature has been met. This was my suggestion earlier in this thread https://github.com/home-assistant/core/issues/79667#issuecomment-1809146735

You can argue that, strictly, the temp you want the system to stop doing what it is doing (heating or cooling) is when the curr_temp = (target_temp +/- tolerance). This it currently does but only if the tolerances are not zero 😄

borpin avatar Feb 04 '25 06:02 borpin

Sorry, didn't notice you had replied already and I edited my comment as I realized in hidden posts you had added more detail.

I don't think the fix is to simply remove the equals comparison, as that trades one problem for another as I mentioned. The code uses the too_cold variable to figure out if it should turn on, and too_hot to figure out if it should turn off. At every temp change event, it re-evaluates what should happen.

Basically, if the current temperature is below your target temp, including your tolerance (if any), it should turn on. If the current temp is above your target temp, including your tolerance (if any), it should turn off. I'll look at the code again, but from what I can recall, I think the only real issue is that it's doing an equals comparison when it's trying to decide if it should turn on which is wrong - if your current temp equals your set temp, why would you turn on? It should only turn on when it's beyond your set temp (incl. tolerance).

I think it's a relatively simple fix, and I think I was mistaken with needing to fix anything to do with the tolerance and how it works (I think I was confusing too_cold with being for A/C devices). As mentioned, when I get a bit of time this week I'll look at it and see if I can get a PR for this.

esand avatar Feb 04 '25 08:02 esand