### Thermostat Cycle Start Logic Overview Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/cycle_scheduler.md This outlines the sequence of operations for starting a thermostat cycle, including calculations, updates, and mode-specific execution. Note that internal state variables are updated before early return checks. ```text start_cycle(hvac_mode, on_percent, force=False) │ ├── calculate_cycle_times(on_percent, cycle_min, │ min_activation_delay, min_deactivation_delay) │ → on_time_sec, off_time_sec │ ├── update thermostat._on_time_sec / _off_time_sec ← always, even before early return │ ├── if cycle running AND force=False │ ├── if current on_time > 0 → update stored params, return (non-disruptive update) │ └── if current on_time == 0 → cancel idle cycle, fall through │ ├── cancel_cycle() ← always cancel before (re)starting ├── store current params ├── fire cycle_start callbacks │ ├── if valve mode → _start_cycle_valve() └── if switch mode → _start_cycle_switch() ├── if HVAC_OFF or on_time=0 → turn off all, schedule cycle end ├── if on_time >= cycle_duration → turn on all, schedule cycle end └── else → _init_cycle() → _tick(initial=True) + schedule cycle end ``` -------------------------------- ### Extreme Regulation Parameters Example Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/en/self-regulation.md Example configuration for 'Extreme regulation' in Expert mode, to be placed in configuration.yaml. This mode uses high values for most parameters. ```yaml versatile_thermostat: auto_regulation_expert: kp: 0.6 ki: 0.1 k_ext: 0.0 offset_max: 10 accumulated_error_threshold: 80 overheat_protection: true ``` -------------------------------- ### Central Boiler Control Configuration Examples Source: https://context7.com/jmcollin78/versatile_thermostat/llms.txt Examples illustrating how to configure central boiler activation and deactivation services, either through UI-configured services or switch-controlled pumps. It also details the conditions for boiler activation based on device count or power usage. ```yaml # Boiler activation/deactivation services configured via UI # Format: entity_id/service_id[/attribute:value] # Examples for boiler control: # Activation: climate.boiler/climate.set_hvac_mode/hvac_mode:heat # Deactivation: climate.boiler/climate.set_hvac_mode/hvac_mode:off # Or for switch-controlled boiler pump: # Activation: switch.boiler_pump/switch.turn_on # Deactivation: switch.boiler_pump/switch.turn_off # Boiler activates when either threshold is exceeded: # - nb_active_device_for_boiler >= boiler_activation_threshold # - total_power_active_for_boiler >= power_activation_threshold # Entities created: # - binary_sensor.central_configuration_central_boiler (boiler state) # - number.boiler_activation_threshold (device count threshold) # - number.boiler_power_activation_threshold (power threshold) # - sensor.nb_device_active_for_boiler (current active devices) # - sensor.total_power_active_for_boiler (current active power) ``` -------------------------------- ### Startup Underlying Entities Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Demonstrates how to initialize and start up different types of underlying entities, such as climate and valve entities, by calling their respective startup methods. ```python # ThermostatOverClimateValve manages both climate and valve for under in self._underlyings: # Climate entities under.startup() for under_valve in self._underlyings_valve_regulation: # Valve entities under_valve.startup() ``` -------------------------------- ### Cycle Start Callback Signature Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/cycle_scheduler.md Defines the signature for cycle start callbacks. The `on_percent` parameter represents the realized fraction after timing constraints. ```python async def callback( on_time_sec: float, off_time_sec: float, on_percent: float, # realized fraction 0.0–1.0 (timing-constrained) hvac_mode: VThermHvacMode, ) -> None: ... ``` -------------------------------- ### UnderlyingSwitch - Cycle Control Example Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Illustrates a typical on/off cycle for the switch based on calculated on-time percentage. ```APIDOC ## Cycle Control Example ``` VTherm ON, Proportional Algorithm calculates: on_percent=70% start_cycle(hvac_mode=HEAT, on_time_sec=42, off_time_sec=18, on_percent=70) ↓ _turn_on_later(0 seconds) ↓ Switch turns ON ← (42 seconds ON period) ↓ _turn_off_later(42 seconds elapsed) ↓ Switch turns OFF ← (18 seconds OFF period) ↓ _turn_on_later(18 seconds elapsed) ↓ [Cycle repeats every 60 seconds] ``` ``` -------------------------------- ### Set Presence State Automation Example Source: https://context7.com/jmcollin78/versatile_thermostat/llms.txt An automation example that sets the thermostat's presence to 'off' when the alarm control panel state changes to 'armed_away'. ```yaml # Automation example - Set absence when alarm armed automation: - alias: "Set VTherm absence on alarm arm" trigger: - platform: state entity_id: alarm_control_panel.home to: "armed_away" action: - service: versatile_thermostat.set_presence data: presence: "off" target: entity_id: climate.living_room_thermostat ``` -------------------------------- ### Register Cycle Start Callback Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/base-classes.md Registers a callback function to be executed when a control cycle starts. This allows for custom actions at the beginning of each cycle. ```python def add_cycle_start_listener() # Register cycle callback ``` -------------------------------- ### Circular Wrap-Around Example Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/cycle_scheduler.md Illustrates how 'off_t' wraps around the cycle duration when 'on_t + on_time > cycle_duration'. This example shows the calculation for R2's 'off_t' and its resulting ON period. ```text R2 | 300s | 360s | 360s | (300+360)%600=60s | 300–600s then 0–60s | ``` -------------------------------- ### UnderlyingStateManager Usage Example Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Demonstrates how to initialize and use the UnderlyingStateManager within an entity's lifecycle. It shows setting up the manager, adding entities, and how the callback is triggered by state changes. ```python # In UnderlyingEntity.__init__ self._state_manager = UnderlyingStateManager( self._hass, on_change=self._underlying_changed ) # In UnderlyingEntity.startup() self._state_manager.add_underlying_entities([self._entity_id]) # When state changes in Home Assistant, _underlying_changed() is called ``` -------------------------------- ### BaseThermostat Lifecycle Methods Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/base-classes.md These methods are part of the lifecycle of the BaseThermostat component in Home Assistant. They handle adding the component to Home Assistant, initialization after construction, and starting the thermostat service. ```python async def async_added_to_hass() # Add to Home Assistant ``` ```python async def post_init() # Initialize after construction ``` ```python async def startup() # Start the thermostat ``` -------------------------------- ### Start TPI Cycle for UnderlyingSwitch Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/base-classes.md Initiates a Time Proportional Integral (TPI) cycle for an `UnderlyingSwitch` with specified ON/OFF percentages and durations. ```python async def start_cycle(on_percent, off_percent, on_time_sec, off_time_sec) # Start a TPI cycle with calculated durations ``` -------------------------------- ### UnderlyingSwitch Cycle Control Example Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Illustrates a typical on/off cycle for a switch controlled by the Proportional Algorithm. The cycle repeats every 60 seconds, with a 42-second ON period and an 18-second OFF period. ```text VTherm ON, Proportional Algorithm calculates: on_percent=70% start_cycle(hvac_mode=HEAT, on_time_sec=42, off_time_sec=18, on_percent=70) ↓ _turn_on_later(0 seconds) ↓ Switch turns ON ← (42 seconds ON period) ↓ _turn_off_later(42 seconds elapsed) ↓ Switch turns OFF ← (18 seconds OFF period) ↓ _turn_on_later(18 seconds elapsed) ↓ [Cycle repeats every 60 seconds] ``` -------------------------------- ### Auto TPI Learning Session Cycle Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/en/feature-autotpi.md This diagram illustrates the Auto TPI learning session cycle, from start to completion, including calibration, bootstrap, and active learning phases. ```mermaid graph LR %% Flat Design Palette classDef startEnd fill:#f1f8e9,stroke:#558b2f,stroke-width:2px,color:#33691e classDef decision fill:#e3f2fd,stroke:#1565c0,stroke-width:2px,color:#0d47a1 classDef process fill:#eceff1,stroke:#455a64,stroke-width:1px,color:#263238 classDef bootstrap fill:#fff9c4,stroke:#fbc02d,stroke-width:2px,color:#f57f17 A([Session start]) --> B{Rate = 0?} B -- "Yes" --> C[Calibration] B -- "No" --> D["Learning (min 50 cycles)"] C --> E{Sufficient history?} E -- "Yes" --> D E -- "No" --> F[Bootstrap] F -->|3 cycles| D D --> G{Session finished?} G -- "No" --> D G -- "Yes" --> H([Session complete]) class A,H startEnd class B,E,G decision class C,D process class F bootstrap ``` -------------------------------- ### Start Listening to Entity State Changes Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/base-classes.md Initiates the process of listening to state changes for an underlying entity. This is crucial for the thermostat to react to external modifications. ```python async def startup() # Start listening to entity ``` -------------------------------- ### UnderlyingSwitch start_cycle Method Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Initiates an on/off cycle for a switch entity. Use force=True to cancel any ongoing cycle and start a new one immediately. Otherwise, the new cycle will queue after the current one finishes. ```python async def start_cycle( hvac_mode: VThermHvacMode, on_time_sec: int, off_time_sec: int, on_percent: int, force: bool = False ) -> None # Start a new on/off cycle with specified timing # If force=True: cancel existing cycle and start new one # If force=False: queue cycle to start after current cycle ends # Set on_time_sec and off_time_sec for this cycle # Call _turn_on_later() after initial delay if appropriate ``` -------------------------------- ### Unit Test Underlying Climate Initialization Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Tests the correct initialization of the UnderlyingClimate class. It sets up an initial state for a climate entity, creates the thermostat and underlying object, starts it up, and verifies its initial properties. ```python async def test_underlying_climate_initialization(hass): """Test that UnderlyingClimate initializes correctly""" # Setup initial state hass.states.async_set("climate.bedroom", "heat", { "current_temperature": 20, "target_temperature": 21, "hvac_action": "heating" }) # Create thermostat and underlying thermostat = create_test_thermostat(hass) underlying = UnderlyingClimate( hass=hass, thermostat=thermostat, climate_entity_id="climate.bedroom" ) # Startup underlying.startup() await hass.async_block_till_done() # Verify initialization assert underlying.is_initialized assert underlying.hvac_mode == "heat" assert underlying.underlying_current_temperature == 20 ``` -------------------------------- ### Circular Offset Computation Algorithm Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/cycle_scheduler.md Details the principle and examples of the circular offset computation algorithm used for distributing cycle start times evenly across the cycle duration for switch mode. ```APIDOC ## Circular Offset Computation Algorithm ### Principle For switch mode, the scheduler distributes cycle start times of each underlying evenly across the cycle duration using **circular offsets**. The offset determines the cycle start shift for each underlying. `offset = (cycle_duration / n) * index` Edge case: `n <= 1`: returns `[0.0]` ### Examples **5 underlyings, 5-minute cycle (300s):** | Underlying | Index | Offset | | ---------- | ----- | --------------------- | | R1 | 0 | (300 / 5) × 0 = 0s | | R2 | 1 | (300 / 5) × 1 = 60s | | R3 | 2 | (300 / 5) × 2 = 120s | | R4 | 3 | (300 / 5) × 3 = 180s | | R5 | 4 | (300 / 5) × 4 = 240s | **2 underlyings, 600s cycle:** | Underlying | Index | Offset | | ---------- | ----- | ---------------------- | | R1 | 0 | (600 / 2) × 0 = 0s | | R2 | 1 | (600 / 2) × 1 = 300s | Offsets are independent of `on_percent`. The distribution is fixed and circular — each underlying starts its activation at a regularly spaced point in the cycle, with wrap-around to the beginning of the cycle if `on_t + on_time` exceeds the cycle duration. ### Method N/A (Algorithm Description) ### Endpoint N/A (Algorithm Description) ### Parameters N/A ### Request Example N/A ### Response N/A ``` -------------------------------- ### Initialization Sequence Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/vtherm-overclimate-valve.md Describes the step-by-step process for initializing the thermostat and its underlying entities. ```APIDOC ## Interaction Flow: Initialization Sequence ### Description Details the initialization process from object instantiation to entities being ready to receive commands and states. ### Steps 1. **ThermostatOverClimateValve.__init__()** - Initialize `_underlyings` list (will be populated). - Initialize `_underlyings_valve_regulation` list. - Set valve-related attributes. 2. **post_init()** - Call parent `ThermostatOverClimate.post_init()`. - Load valve configuration (min/max opening degrees, thresholds). - Create `UnderlyingClimate` for each underlying entity. - Create `UnderlyingValveRegulation` for each opening degree entity. - Load TPI algorithm parameters. 3. **async_startup()** - Call parent `ThermostatOverClimate.async_startup()`. - Start `UnderlyingClimate` entities. - Start `UnderlyingValveRegulation` entities. - Register listeners for state changes. 4. **Entities are ready** - Receive initial temperature. - First `control_heating` cycle triggers. ``` -------------------------------- ### Thermostat Lifecycle and Callback Flow Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/cycle_scheduler.md Illustrates the sequence of events from thermostat initialization through scheduler binding and callback registration, culminating in callbacks firing at cycle boundaries. ```text Lifecycle: ThermostatProp.post_init() └─ _bind_scheduler(CycleScheduler(...)) ├─ self._cycle_scheduler = scheduler └─ algo_handler.on_scheduler_ready(scheduler) ├─ scheduler.register_cycle_start_callback(algo.on_cycle_started) └─ scheduler.register_cycle_end_callback(algo.on_cycle_completed) At each master cycle boundary: - on_cycle_started(on_time_sec, off_time_sec, realized_on_percent, hvac_mode) fires → algo stores params, updates power feedback - on_cycle_completed(e_eff) fires → algo reads stored params, runs learning ``` -------------------------------- ### Turn On Valve Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Opens the valve by calling the set_valve_open_percent method. ```python async def turn_on() -> None # Open valve by calling set_valve_open_percent() ``` -------------------------------- ### Notify on Heating Failure Start Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/en/feature-heating-failure-detection.md This automation triggers a persistent notification when a heating failure start event is detected. It filters for the 'heating_failure_start' event type. ```yaml alias: "Heating failure alert" description: "Creates a persistent notification when heating failure is detected" trigger: - platform: event event_type: versatile_thermostat_heating_failure_event condition: - condition: template value_template: "{{ trigger.event.data.type == 'heating_failure_start' }}" action: - service: persistent_notification.create data: title: "🔥 Heating failure detected" message: > The thermostat **{{ trigger.event.data.name }}** has detected a heating failure. 📊 **Details:** - Power requested: {{ (trigger.event.data.on_percent * 100) | round(0) }}% - Current temperature: {{ trigger.event.data.current_temp }}°C - Target temperature: {{ trigger.event.data.target_temp }}°C - Temperature change: {{ trigger.event.data.temperature_difference | round(2) }}°C ⚠️ The heating is running at full power but the temperature is not increasing. Check that the radiator is working properly. notification_id: "heating_failure_{{ trigger.event.data.entity_id }}" ``` -------------------------------- ### State Manager Usage Example Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/base-classes.md Demonstrates how to interact with the state manager to set a requested HVAC mode and then compute the resulting effective state. Note that the actual state might differ due to active constraints like an open window. ```python # User sets heating mode state_manager._requested_state.hvac_mode = HVAC_MODE_HEAT # Compute effective state state_manager.compute_current_state_from_requested() # If window is open, current state may be OFF despite request current_hvac = state_manager._current_state.hvac_mode # May be OFF ``` -------------------------------- ### Thermostat Initialization Sequence Diagram Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Visualizes the sequence of events during the thermostat's startup and initialization process, from Home Assistant initiating startup to underlying entities becoming ready. ```mermaid sequenceDiagram participant HA as Home Assistant participant VT as BaseThermostat participant UE as UnderlyingEntity participant USM as UnderlyingStateManager participant HA2 as HA State Registry HA->>VT: async_startup(config) Note over VT: _is_startup_done = False
is_ready = False VT->>VT: start listening to managers VT->>UE: startup() for each underlying UE->>USM: add_underlying_entities([entity_id]) USM->>HA2: fetch initial state from hass.states USM->>USM: cache state in _states list USM->>USM: register _state_changed callback via async_track_state_change_event alt Initial State Exists USM->>UE: schedule on_change callback (async_create_task) UE->>UE: _underlying_changed(entity_id, initial_state, None) end UE->>UE: check is_all_states_initialized? alt All Entities Initialized UE->>UE: _is_initialized = True Note over UE: is_initialized = True
is_ready = False UE->>UE: await check_initial_state() UE->>VT: await init_underlyings_completed(entity_id) else Not Yet Initialized UE->>UE: log: waiting for other underlyings... end VT->>VT: _is_startup_done = True Note over VT: is_initialized = True
is_ready = True ✓ VT->>VT: update_states(force=True) VT->>VT: recalculate() HA2->>USM: HA state changes USM->>USM: _state_changed(event) USM->>UE: _underlying_changed(entity_id, new_state, old_state) UE->>VT: underlying_changed(change_details) VT->>VT: update thermostat state ``` -------------------------------- ### Notify on Heating or Cooling Failure Start Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/en/feature-heating-failure-detection.md This automation handles notifications for both heating and cooling failure start events. It uses a template condition to check if the event type is either 'heating_failure_start' or 'cooling_failure_start'. ```yaml alias: "Heating anomaly alert" description: "Notification for all types of heating failures" trigger: - platform: event event_type: versatile_thermostat_heating_failure_event condition: - condition: template value_template: "{{ trigger.event.data.type in ['heating_failure_start', 'cooling_failure_start'] }}" action: - service: persistent_notification.create data: title: > {% if trigger.event.data.failure_type == 'heating' %} 🔥 Heating failure detected {% else %} ❄️ Cooling failure detected {% endif %} message: > The thermostat **{{ trigger.event.data.name }}** has detected an anomaly. 📊 **Details:** - Failure type: {{ trigger.event.data.failure_type }} - Power requested: {{ (trigger.event.data.on_percent * 100) | round(0) }}% - Current temperature: {{ trigger.event.data.current_temp }}°C - Target temperature: {{ trigger.event.data.target_temp }}°C - Temperature change: {{ trigger.event.data.temperature_difference | round(2) }}°C {% if trigger.event.data.failure_type == 'heating' %} ⚠️ The heating is running at {{ (trigger.event.data.on_percent * 100) | round(0) }}% but the temperature is not increasing. Check that the radiator is working properly. {% else %} ⚠️ The heating is off but the temperature keeps rising. Check that the radiator turns off properly. {% endif %} notification_id: "heating_failure_{{ trigger.event.data.entity_id }}" ``` -------------------------------- ### Start or Stop Auto TPI Mode Service Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/en/feature-autotpi.md Call this service from the developer tools to manually start or stop an Auto TPI learning session. Ensure Auto TPI is enabled and configured before use. ```yaml service: set_auto_tpi_mode ``` -------------------------------- ### UnderlyingValveRegulation Methods Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Key methods for managing valve state, initialization, and sending commands. Note that `startup` directly manages entities without calling the superclass method. ```python async def check_initial_state() -> None # Initialize valve min/max opening from entity attributes # Compare should_device_be_active with is_device_active # If mismatch: send appropriate opening/closing command ``` ```python def startup() -> None # Register both opening_degree and closing_degree entities with state manager # Add entities to monitoring list # (Note: does not call super().startup() - manages entities directly) ``` ```python async def send_percent_open(fixed_value: int = None) -> None # Calculate opening/closing degree values from percentage # Call OpeningClosingDegreeCalculation.calculate_opening_closing_degree() # Send opening_degree via super().send_percent_open() # Send closing_degree to closing entity if present ``` ```python async def turn_off() -> None # Set valve to OFF # Set percent_open = 0 # Send opening/closing degrees # Set underlying climate to OFF ``` -------------------------------- ### Setting is_ready in BaseThermostat Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md The `is_ready` state is set to True in `BaseThermostat.async_startup()` after all initialization steps are completed. This flag is used to guard critical operations. ```python # In BaseThermostat.async_startup() # ... all initialization steps ... self._is_startup_done = True # ← Sets is_ready=True ``` -------------------------------- ### Get Underlying Target Temperature Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Retrieves the target temperature set on the underlying climate entity. ```python @property def underlying_target_temperature() -> Optional[float] # Return target temperature from underlying ``` -------------------------------- ### Get Underlying Current Temperature Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Retrieves the current temperature reading from the underlying climate entity. ```python @property def underlying_current_temperature() -> Optional[float] # Return current temperature from underlying ``` -------------------------------- ### Central Boiler Configuration Example Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/en/reference.md This YAML configuration demonstrates the various attributes for central boiler management, including its state, readiness, and service details for activation and deactivation. It also includes device class and icon information. ```yaml central_boiler_state: "off" is_central_boiler_configured: true is_central_boiler_ready: true central_boiler_manager: is_on: false activation_scheduled: false delayed_activation_sec: 10 nb_active_device_for_boiler: 1 nb_active_device_for_boiler_threshold: 3 total_power_active_for_boiler: 50 total_power_active_for_boiler_threshold: 500 service_activate: service_domain: switch service_name: turn_on entity_domain: switch entity_name: controle_chaudiere entity_id: switch.controle_chaudiere data: {} service_deactivate: service_domain: switch service_name: turn_off entity_domain: switch entity_name: controle_chaudiere entity_id: switch.controle_chaudiere data: {} device_class: running icon: mdi:water-boiler-off friendly_name: Central boiler ``` -------------------------------- ### Get Supported HVAC Modes Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Retrieves a list of HVAC modes that are supported by the underlying climate entity. ```python @property def hvac_modes() -> List[VThermHvacMode] # Return list of HVAC modes supported by underlying ``` -------------------------------- ### UnderlyingValveRegulation Initialization Flow Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Diagram illustrating the sequence of calls during the initialization and startup process for UnderlyingValveRegulation, highlighting entity registration and state synchronization. ```text ThermostatOverClimateValve.async_startup() ↓ Call parent ThermostatOverClimate.async_startup() ↓ Register UnderlyingClimate entities and startup() ↓ Register UnderlyingValveRegulation entities and startup() ↓ Each UnderlyingValveRegulation.startup() registers: - opening_degree_entity_id - closing_degree_entity_id (if configured) ↓ UnderlyingStateManager listens to both entities ↓ When both entities receive initial states: ↓ _is_initialized = True ↓ check_initial_state() validates synchronization ``` -------------------------------- ### Get Last Sent Temperature Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Retrieves the last temperature value that was sent to the underlying climate entity. ```python @property def last_sent_temperature() -> Optional[float] # Return last temperature sent to underlying ``` -------------------------------- ### Get Current Humidity from Climate Entity Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Retrieves the current humidity level from the underlying climate entity. ```python @property def current_humidity() -> Optional[float] # Return current humidity from underlying ``` -------------------------------- ### Include Templates in Configuration Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/en/troubleshooting.md This configuration snippet shows how to include your custom templates, such as the presence sensor, into your Home Assistant configuration. Ensure 'templates.yaml' exists and contains your sensor definitions. ```yaml ... template: !include templates.yaml ... ``` -------------------------------- ### Initialize and Add Entities to State Manager Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/base-classes.md Instantiate the `UnderlyingStateManager` with a callback and add entities to begin monitoring their states. ```python self._underlying_state_manager = UnderlyingStateManager( hass, self.entity_state_changed # Callback ) await self._underlying_state_manager.add_entities([entity_id]) ``` -------------------------------- ### Get Fan Mode from Climate Entity Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Retrieves the current fan mode from the underlying climate entity. ```python @property def fan_mode() -> Optional[str] # Return current fan mode from underlying climate ``` -------------------------------- ### Configure Frontend Theme for Thermostat Sensors Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/cs/reference.md Add these lines to your configuration.yaml to customize sensor colors in the frontend. Select the 'versatile_thermostat_theme' in your panel configuration. ```yaml frontend: themes: versatile_thermostat_theme: state-binary_sensor-safety-on-color: "#FF0B0B" state-binary_sensor-power-on-color: "#FF0B0B" state-binary_sensor-window-on-color: "rgb(156, 39, 176)" state-binary_sensor-motion-on-color: "rgb(156, 39, 176)" state-binary_sensor-presence-on-color: "lightgreen" state-binary_sensor-running-on-color: "orange" ``` -------------------------------- ### Get HVAC Mode from Climate Entity Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Retrieves the current HVAC mode from the underlying climate entity. ```python @property def hvac_mode() -> Optional[VThermHvacMode] # Return current HVAC mode from underlying climate ``` -------------------------------- ### Service Call Response Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/en/feature-recalibrate-valves.md The service returns immediately with a confirmation message indicating that the recalibration process has started in the background. ```json {"message": "calibrage en cours"} ``` -------------------------------- ### Cycle Initialization (_init_cycle) Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/cycle_scheduler.md Describes the cycle initialization process, which occurs once per cycle at startup, resetting underlying states and the global penalty. ```APIDOC ## Cycle Initialization (_init_cycle) ### Principle This step occurs once per cycle, at startup. It resets the states of each underlying and the global penalty. ### Initialized Variables **Global:** - `penalty = 0.0` — counter of heating time added or removed for the `e_eff` computation at cycle end. **Per underlying (`UnderlyingCycleState`):** | Variable | Formula | Description | | --------- | ---------------------------------------------- | -------------------------------------------------- | | `on_t` | `offset` | Time at which the underlying should turn on | | `on_time` | `cycle_duration × on_percent` | Operating duration of the underlying | | `off_t` | `(on_t + on_time) % cycle_duration` | Time at which the underlying should turn off | ```python on_t = offset on_time = cycle_duration_sec * on_percent off_t = (on_t + on_time) % cycle_duration_sec ``` ### Method N/A (Internal Function) ### Endpoint N/A (Internal Function) ### Parameters N/A ### Request Example N/A ### Response N/A ``` -------------------------------- ### Get Supported Climate Features Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Retrieves the feature flags indicating the capabilities supported by the underlying climate entity. ```python @property def supported_features() -> ClimateEntityFeature # Return feature flags from underlying climate ``` -------------------------------- ### UnderlyingStateManager Get Cached State Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/base-classes.md Retrieves the last known state of a specific entity from the manager's cache. ```python def get_state(entity_id) -> State # Get cached state for an entity ``` -------------------------------- ### Initialize Valve State Min/Max Open Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Extracts min/max opening values from valve entity attributes and sets internal variables. Defaults to 0-100 if no min/max is specified. ```python def init_valve_state_min_max_open() -> None # Extract min/max opening values from valve entity attributes # Set _min_open, _max_open from entity attributes # Default to 0-100 if no min/max specified ``` -------------------------------- ### Get Current Valve Opening Percentage Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/base-classes.md Retrieves the current valve opening percentage. Returns 0 if the thermostat is OFF. ```python @property def valve_open_percent() -> int # Current valve opening (0 if OFF) ``` -------------------------------- ### Log File Entry Example Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/en/feature-logs-collector.md Individual log entries within the file include timestamp, log level, Python module, and the message. These entries are crucial for detailed analysis of thermostat operations and potential issues. ```text 2025-03-14 08:25:12.456 INFO [base_thermostat ] Living Room - Current temperature is 20.5°C 2025-03-14 08:30:00.001 INFO [prop_algo_tpi ] Living Room - TPI calculated on_percent=0.45 2025-03-14 08:30:00.123 WARNING [safety_manager ] Living Room - No temperature update for 35 min ``` -------------------------------- ### Theme Configuration Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/cs/reference.md Configuration for coloring thermostat sensors in the frontend. ```APIDOC ## Theme Configuration To color the sensors, add the following lines to your `configuration.yaml` and customize as needed: ```yaml frontend: themes: versatile_thermostat_theme: state-binary_sensor-safety-on-color: "#FF0B0B" state-binary_sensor-power-on-color: "#FF0B0B" state-binary_sensor-window-on-color: "rgb(156, 39, 176)" state-binary_sensor-motion-on-color: "rgb(156, 39, 176)" state-binary_sensor-presence-on-color: "lightgreen" state-binary_sensor-running-on-color: "orange" ``` Then select the `versatile_thermostat_theme` in the panel configuration. ``` -------------------------------- ### UnderlyingEntity Register Cycle Callback Utility Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/underlyings.md Registers a callback function to be invoked whenever a control cycle starts. The callback should be a callable. ```python def register_cycle_callback(callback: Callable) -> None # Register callback to be called when control cycle starts ``` -------------------------------- ### UnderlyingStateManager Initialization Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/base-classes.md Initializes the state manager with the Home Assistant instance and a callback function to be executed when entity states change. ```python def __init__(hass, on_state_changed_cb) # Initialize manager with callback ``` -------------------------------- ### Start Control Cycle Source: https://github.com/jmcollin78/versatile_thermostat/blob/main/documentation/tech-docs/base-classes.md Initiates a control cycle for an underlying entity. This is often used in conjunction with timing mechanisms like TPI. ```python async def start_cycle() # Start a control cycle ```