### 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
```