Files
HomeAssistantVS/custom_components/intelligent_heating_pilot/domain/entities/heating_pilot.py
T
2026-07-08 10:43:39 -04:00

97 lines
3.3 KiB
Python

"""Heating pilot - the aggregate root for heating decisions."""
from __future__ import annotations
import logging
from ..interfaces import IDecisionStrategy, ISchedulerCommander
from ..value_objects import (
EnvironmentState,
HeatingDecision,
)
_LOGGER = logging.getLogger(__name__)
class HeatingPilot:
"""Coordinates heating decisions for a single VTherm.
This is the aggregate root that orchestrates all domain logic
for intelligent heating control. It delegates decision-making to
a configurable strategy, allowing users to choose between:
- Simple rule-based decisions (no ML required)
- ML-powered decisions (requires IHP-ML-Models add-on)
This design follows the Strategy pattern, making the pilot
independent of the decision algorithm complexity.
Attributes:
_decision_strategy: Strategy for making heating decisions
_scheduler_commander: Interface to control scheduler actions
"""
def __init__(
self,
decision_strategy: IDecisionStrategy,
scheduler_commander: ISchedulerCommander,
) -> None:
"""Initialize the heating pilot.
Args:
decision_strategy: Strategy for making heating decisions
(simple rules or ML-based)
scheduler_commander: Implementation of scheduler control interface
"""
_LOGGER.debug("Initializing HeatingPilot")
self._decision_strategy = decision_strategy
self._scheduler_commander = scheduler_commander
_LOGGER.info(f"HeatingPilot initialized with strategy: {type(decision_strategy).__name__}")
async def decide_heating_action(
self,
environment: EnvironmentState,
) -> HeatingDecision:
"""Decide what heating action to take based on current conditions.
This method delegates the decision to the configured strategy,
which can be either simple rule-based or ML-powered.
Args:
environment: Current environmental conditions
Returns:
A heating decision with the action to take
"""
_LOGGER.debug("HeatingPilot.decide_heating_action called")
_LOGGER.debug(f"Delegating decision to {type(self._decision_strategy).__name__}")
decision = await self._decision_strategy.decide_heating_action(environment)
_LOGGER.info(f"HeatingPilot decision: {decision.action.value}")
return decision
async def check_overshoot_risk(
self,
environment: EnvironmentState,
current_slope: float,
) -> HeatingDecision:
"""Check if heating should stop to prevent overshooting target.
This method delegates the overshoot check to the configured strategy.
Args:
environment: Current environmental conditions
current_slope: Current heating rate in °C/hour
Returns:
Decision to stop heating if overshoot is detected
"""
_LOGGER.debug("HeatingPilot.check_overshoot_risk called")
_LOGGER.debug(f"Delegating overshoot check to {type(self._decision_strategy).__name__}")
decision = await self._decision_strategy.check_overshoot_risk(environment, current_slope)
_LOGGER.info(f"HeatingPilot overshoot check: {decision.action.value}")
return decision