186 files

This commit is contained in:
Home Assistant Version Control
2026-09-14 12:56:59 +00:00
parent 6be1e92941
commit bd8280defe
186 changed files with 14904 additions and 1087 deletions
@@ -158,6 +158,24 @@ class CycleScheduler:
UnderlyingEntityType.VALVE_REGULATION,
)
def _resolve_valve_on_percent(
self,
on_percent: float,
force: bool = False,
) -> float:
"""Return the valve command retained by the thermostat."""
requested = max(0.0, min(1.0, float(on_percent)))
resolver = getattr(
type(self._thermostat),
"apply_valve_command_percent",
None,
)
if resolver is None:
return requested
retained = resolver(self._thermostat, requested, force=force)
return max(0.0, min(1.0, float(retained)))
def register_cycle_start_callback(self, callback: Callable):
"""Register a callback to be called at the start of each master cycle.
@@ -232,6 +250,9 @@ class CycleScheduler:
force: If True, cancel any running cycle and restart immediately.
_from_cycle_end: Internal flag — True when called from _on_master_cycle_end.
"""
if self._is_valve_mode:
on_percent = self._resolve_valve_on_percent(on_percent, force=force)
cycle_min = self._cycle_duration_sec / 60
on_time_sec, off_time_sec, _ = calculate_cycle_times(
on_percent,
@@ -239,7 +260,15 @@ class CycleScheduler:
self.min_activation_delay,
self.min_deactivation_delay,
)
realized_on_percent = on_time_sec / self._cycle_duration_sec if self._cycle_duration_sec > 0 else 0.0
# A valve applies the retained position directly. Converting it back
# from integer cycle seconds would quantize it a second time and feed a
# different command into the next automatic cycle restart.
if self._is_valve_mode:
realized_on_percent = on_percent
elif self._cycle_duration_sec > 0:
realized_on_percent = on_time_sec / self._cycle_duration_sec
else:
realized_on_percent = 0.0
# Always update thermostat timing attributes immediately so sensors
# reflect the latest computed value, even when the cycle returns early.
@@ -336,6 +365,7 @@ class CycleScheduler:
if not self._is_valve_mode:
return
on_percent = self._resolve_valve_on_percent(on_percent)
cycle_min = self._cycle_duration_sec / 60
on_time_sec, off_time_sec, _ = calculate_cycle_times(
on_percent,
@@ -343,7 +373,9 @@ class CycleScheduler:
self.min_activation_delay,
self.min_deactivation_delay,
)
realized_on_percent = on_time_sec / self._cycle_duration_sec if self._cycle_duration_sec > 0 else 0.0
# Valve mode is direct-position control: cycle seconds are diagnostic
# timing data, not the source of the applied valve percentage.
realized_on_percent = on_percent
self._thermostat._on_time_sec = on_time_sec
self._thermostat._off_time_sec = off_time_sec