Generic Thermostat - cycles if both tolerances are zero
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.
Anyone?
Anyone? 😄
Just preventing this going stale.
Thoughts?
Please don't go stale
Still an issue
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
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 What would be your proposed solution?
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.
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
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):
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.
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.
Fundamentally, there is an error in the state machine for this integration in that it does not account for the state of just_right.
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.
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.
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.
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.
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.
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 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.
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 😄
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.