1
+ from datetime import datetime , timezone
1
2
import logging
2
3
from typing import Callable
3
4
@@ -126,53 +127,9 @@ async def async_control_hvac(self, time=None, force=False):
126
127
match self ._hvac_mode :
127
128
case HVACMode .COOL :
128
129
if self ._fan_on_with_cooler :
129
- await self .fan_device .async_control_hvac (time , force )
130
- await self .cooler_device .async_control_hvac (time , force )
131
- self .HVACActionReason = self .cooler_device .HVACActionReason
130
+ await self ._async_control_when_fan_on_with_cooler (time , force )
132
131
else :
133
-
134
- is_within_fan_tolerance = self .environment .is_within_fan_tolerance (
135
- self .fan_device .target_env_attr
136
- )
137
- is_warmer_outside = self .environment .is_warmer_outside
138
- is_fan_air_outside = self .fan_device .fan_air_surce_outside
139
-
140
- # If the fan_hot_tolerance is set, enforce the action for the fan or cooler device
141
- # to ignore cycles as we switch between the fan and cooler device
142
- # and we want to avoid idle time gaps between the devices
143
- force_override = (
144
- True
145
- if self .environment .fan_hot_tolerance is not None
146
- else force
147
- )
148
-
149
- if (
150
- self ._fan_hot_tolerance_on
151
- and is_within_fan_tolerance
152
- and not (is_fan_air_outside and is_warmer_outside )
153
- ):
154
- _LOGGER .debug ("within fan tolerance" )
155
- _LOGGER .debug (
156
- "fan_hot_tolerance_on: %s" , self ._fan_hot_tolerance_on
157
- )
158
- _LOGGER .debug ("force_override: %s" , force_override )
159
-
160
- self .fan_device .hvac_mode = HVACMode .FAN_ONLY
161
- await self .fan_device .async_control_hvac (time , force_override )
162
- await self .cooler_device .async_turn_off ()
163
- self .HVACActionReason = (
164
- HVACActionReason .TARGET_TEMP_NOT_REACHED_WITH_FAN
165
- )
166
- else :
167
- _LOGGER .debug ("outside fan tolerance" )
168
- _LOGGER .debug (
169
- "fan_hot_tolerance_on: %s" , self ._fan_hot_tolerance_on
170
- )
171
- await self .cooler_device .async_control_hvac (
172
- time , force_override
173
- )
174
- await self .fan_device .async_turn_off ()
175
- self .HVACActionReason = self .cooler_device .HVACActionReason
132
+ await self ._async_control_cooler (time , force )
176
133
177
134
case HVACMode .FAN_ONLY :
178
135
await self .cooler_device .async_turn_off ()
@@ -184,3 +141,54 @@ async def async_control_hvac(self, time=None, force=False):
184
141
case _:
185
142
if self ._hvac_mode is not None :
186
143
_LOGGER .warning ("Invalid HVAC mode: %s" , self ._hvac_mode )
144
+
145
+ async def _async_control_when_fan_on_with_cooler (self , time = None , force = False ):
146
+ await self .fan_device .async_control_hvac (time , force )
147
+ await self .cooler_device .async_control_hvac (time , force )
148
+ self .HVACActionReason = self .cooler_device .HVACActionReason
149
+
150
+ async def _async_control_cooler (self , time = None , force = False ):
151
+ is_within_fan_tolerance = self .environment .is_within_fan_tolerance (
152
+ self .fan_device .target_env_attr
153
+ )
154
+ is_warmer_outside = self .environment .is_warmer_outside
155
+ is_fan_air_outside = self .fan_device .fan_air_surce_outside
156
+
157
+ # If the fan_hot_tolerance is set, enforce the action for the fan or cooler device
158
+ # to ignore cycles as we switch between the fan and cooler device
159
+ # and we want to avoid idle time gaps between the devices
160
+ force_override = (
161
+ True if self .environment .fan_hot_tolerance is not None else force
162
+ )
163
+
164
+ has_cooler_run_long_enough = (
165
+ self .cooler_device .hvac_controller .ran_long_enough ()
166
+ )
167
+
168
+ if self .cooler_device .is_on and not has_cooler_run_long_enough :
169
+ _LOGGER .debug (
170
+ "Cooler has not run long enough at: %s" ,
171
+ datetime .now (timezone .utc ),
172
+ )
173
+ self .HVACActionReason = HVACActionReason .MIN_CYCLE_DURATION_NOT_REACHED
174
+ return
175
+
176
+ if (
177
+ self ._fan_hot_tolerance_on
178
+ and is_within_fan_tolerance
179
+ and not (is_fan_air_outside and is_warmer_outside )
180
+ ):
181
+ _LOGGER .debug ("within fan tolerance" )
182
+ _LOGGER .debug ("fan_hot_tolerance_on: %s" , self ._fan_hot_tolerance_on )
183
+ _LOGGER .debug ("force_override: %s" , force_override )
184
+
185
+ self .fan_device .hvac_mode = HVACMode .FAN_ONLY
186
+ await self .fan_device .async_control_hvac (time , force_override )
187
+ await self .cooler_device .async_turn_off ()
188
+ self .HVACActionReason = HVACActionReason .TARGET_TEMP_NOT_REACHED_WITH_FAN
189
+ else :
190
+ _LOGGER .debug ("outside fan tolerance" )
191
+ _LOGGER .debug ("fan_hot_tolerance_on: %s" , self ._fan_hot_tolerance_on )
192
+ await self .cooler_device .async_control_hvac (time , force_override )
193
+ await self .fan_device .async_turn_off ()
194
+ self .HVACActionReason = self .cooler_device .HVACActionReason
0 commit comments