# pylint: disable=line-too-long, disable=unused-import """Constants for the Versatile Thermostat integration.""" import logging import math from typing import Literal from datetime import datetime from enum import Enum from homeassistant.const import STATE_UNKNOWN, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant from homeassistant.const import CONF_NAME, Platform from homeassistant.components.climate.const import ClimateEntityFeature # pylint: disable=unused-import from homeassistant.exceptions import HomeAssistantError from homeassistant.util import dt as dt_util from vtherm_api.const import DOMAIN, VTHERM_API_NAME, DEVICE_MANUFACTURER, DEVICE_MODEL, get_tz, NowClass, EventType from vtherm_api.log_collector import get_vtherm_logger PROPORTIONAL_FUNCTION_TPI = "tpi" from .vtherm_preset import VThermPreset, VThermPresetWithAC, VThermPresetWithAway, VThermPresetWithACAway, PRESET_TEMP_SUFFIX, PRESET_AWAY_SUFFIX # pylint: disable=unused-import from .vtherm_hvac_mode import ( VThermHvacMode, VThermHvacMode_COOL, VThermHvacMode_HEAT, VThermHvacMode_DRY, VThermHvacMode_OFF, VThermHvacMode_HEAT_COOL, VThermHvacMode_SLEEP, VThermHvacMode_AUTO, VThermHvacMode_FAN_ONLY, to_ha_hvac_mode, from_ha_hvac_mode, ) # pylint: disable=unused-import from .vtherm_state import VThermState # pylint: disable=unused-import _LOGGER = get_vtherm_logger(__name__) CONFIG_VERSION = 2 CONFIG_MINOR_VERSION = 3 DEVICE_MANUFACTURER = "JMCOLLIN" DEVICE_MODEL = "Versatile Thermostat" DOMAIN = "versatile_thermostat" # The order is important. PLATFORMS: list[Platform] = [ Platform.SELECT, Platform.CLIMATE, Platform.SENSOR, # Number should be after CLIMATE Platform.NUMBER, Platform.BINARY_SENSOR, Platform.SWITCH, ] CONF_UNDERLYING_LIST = "underlying_entity_ids" CONF_HEATER_KEEP_ALIVE = "heater_keep_alive" CONF_TEMP_SENSOR = "temperature_sensor_entity_id" CONF_LAST_SEEN_TEMP_SENSOR = "last_seen_temperature_sensor_entity_id" CONF_EXTERNAL_TEMP_SENSOR = "external_temperature_sensor_entity_id" CONF_POWER_SENSOR = "power_sensor_entity_id" CONF_MAX_POWER_SENSOR = "max_power_sensor_entity_id" CONF_WINDOW_SENSOR = "window_sensor_entity_id" CONF_MOTION_SENSOR = "motion_sensor_entity_id" CONF_DEVICE_POWER = "device_power" CONF_CYCLE_MIN = "cycle_min" CONF_PROP_FUNCTION = "proportional_function" CONF_WINDOW_DELAY = "window_delay" CONF_WINDOW_OFF_DELAY = "window_off_delay" CONF_MOTION_DELAY = "motion_delay" CONF_MOTION_OFF_DELAY = "motion_off_delay" CONF_MOTION_PRESET = "motion_preset" CONF_NO_MOTION_PRESET = "no_motion_preset" CONF_TPI_COEF_INT = "tpi_coef_int" CONF_TPI_COEF_EXT = "tpi_coef_ext" CONF_TPI_THRESHOLD_LOW = "tpi_threshold_low" CONF_TPI_THRESHOLD_HIGH = "tpi_threshold_high" CONF_PRESENCE_SENSOR = "presence_sensor_entity_id" CONF_PRESET_POWER = "power_temp" CONF_MINIMAL_ACTIVATION_DELAY = "minimal_activation_delay" CONF_MINIMAL_DEACTIVATION_DELAY = "minimal_deactivation_delay" CONF_TEMP_MIN = "temp_min" CONF_TEMP_MAX = "temp_max" CONF_SAFETY_DELAY_MIN = "safety_delay_min" CONF_SAFETY_MIN_ON_PERCENT = "safety_min_on_percent" CONF_SAFETY_DEFAULT_ON_PERCENT = "safety_default_on_percent" CONF_THERMOSTAT_TYPE = "thermostat_type" CONF_THERMOSTAT_CENTRAL_CONFIG = "thermostat_central_config" CONF_THERMOSTAT_SWITCH = "thermostat_over_switch" CONF_THERMOSTAT_CLIMATE = "thermostat_over_climate" CONF_THERMOSTAT_VALVE = "thermostat_over_valve" CONF_USE_WINDOW_FEATURE = "use_window_feature" CONF_USE_MOTION_FEATURE = "use_motion_feature" CONF_USE_PRESENCE_FEATURE = "use_presence_feature" CONF_USE_POWER_FEATURE = "use_power_feature" CONF_USE_CENTRAL_BOILER_FEATURE = "use_central_boiler_feature" CONF_USE_AUTO_START_STOP_FEATURE = "use_auto_start_stop_feature" CONF_AC_MODE = "ac_mode" CONF_WINDOW_AUTO_OPEN_THRESHOLD = "window_auto_open_threshold" CONF_WINDOW_AUTO_CLOSE_THRESHOLD = "window_auto_close_threshold" CONF_WINDOW_AUTO_MAX_DURATION = "window_auto_max_duration" CONF_AUTO_REGULATION_MODE = "auto_regulation_mode" CONF_AUTO_REGULATION_NONE = "auto_regulation_none" CONF_AUTO_REGULATION_VALVE = "auto_regulation_valve" CONF_AUTO_REGULATION_SLOW = "auto_regulation_slow" CONF_AUTO_REGULATION_LIGHT = "auto_regulation_light" CONF_AUTO_REGULATION_MEDIUM = "auto_regulation_medium" CONF_AUTO_REGULATION_STRONG = "auto_regulation_strong" CONF_AUTO_REGULATION_EXPERT = "auto_regulation_expert" CONF_AUTO_REGULATION_DTEMP = "auto_regulation_dtemp" CONF_AUTO_REGULATION_PERIOD_MIN = "auto_regulation_periode_min" CONF_AUTO_REGULATION_USE_DEVICE_TEMP = "auto_regulation_use_device_temp" CONF_INVERSE_SWITCH = "inverse_switch_command" CONF_AUTO_FAN_MODE = "auto_fan_mode" CONF_AUTO_FAN_NONE = "auto_fan_none" CONF_AUTO_FAN_LOW = "auto_fan_low" CONF_AUTO_FAN_MEDIUM = "auto_fan_medium" CONF_AUTO_FAN_HIGH = "auto_fan_high" CONF_AUTO_FAN_TURBO = "auto_fan_turbo" CONF_STEP_TEMPERATURE = "step_temperature" CONF_OFFSET_CALIBRATION_LIST = "offset_calibration_entity_ids" CONF_OPENING_DEGREE_LIST = "opening_degree_entity_ids" CONF_CLOSING_DEGREE_LIST = "closing_degree_entity_ids" CONF_MIN_OPENING_DEGREES = "min_opening_degrees" CONF_MAX_OPENING_DEGREES = "max_opening_degrees" CONF_MAX_CLOSING_DEGREE = "max_closing_degree" CONF_OPENING_THRESHOLD_DEGREE = "opening_threshold_degree" CONF_SYNC_DEVICE_INTERNAL_TEMP = "sync_device_internal_temp" CONF_SYNC_WITH_CALIBRATION = "sync_with_calibration" CONF_SYNC_ENTITY_LIST = "sync_entity_ids" CONF_USE_HEATING_FAILURE_DETECTION_FEATURE = "use_heating_failure_detection_feature" CONF_USE_HEATING_FAILURE_DETECTION_CENTRAL_CONFIG = "use_heating_failure_detection_central_config" CONF_HEATING_FAILURE_THRESHOLD = "heating_failure_threshold" CONF_COOLING_FAILURE_THRESHOLD = "cooling_failure_threshold" CONF_HEATING_FAILURE_DETECTION_DELAY = "heating_failure_detection_delay" CONF_TEMPERATURE_CHANGE_TOLERANCE = "temperature_change_tolerance" CONF_FAILURE_DETECTION_ENABLE_TEMPLATE = "failure_detection_enable_template" CONF_LOCK_CODE = "lock_code" CONF_LOCK_USERS = "lock_users" CONF_LOCK_AUTOMATIONS = "lock_automations" CONF_AUTO_RELOCK_SEC = "auto_relock_sec" CONF_REPAIR_INCORRECT_STATE = "repair_incorrect_state" CONF_VSWITCH_ON_CMD_LIST = "vswitch_on_command" CONF_VSWITCH_OFF_CMD_LIST = "vswitch_off_command" # Deprecated CONF_HEATER = "heater_entity_id" CONF_HEATER_2 = "heater_entity2_id" CONF_HEATER_3 = "heater_entity3_id" CONF_HEATER_4 = "heater_entity4_id" CONF_CLIMATE = "climate_entity_id" CONF_CLIMATE_2 = "climate_entity2_id" CONF_CLIMATE_3 = "climate_entity3_id" CONF_CLIMATE_4 = "climate_entity4_id" CONF_VALVE = "valve_entity_id" CONF_VALVE_2 = "valve_entity2_id" CONF_VALVE_3 = "valve_entity3_id" CONF_VALVE_4 = "valve_entity4_id" CONF_AUTO_TPI_MODE = "auto_tpi_mode" CONF_AUTO_TPI_LEARNING_TYPE = "auto_tpi_learning_type" AUTO_TPI_LEARNING_TYPE_DISCOVERY = "discovery" AUTO_TPI_LEARNING_TYPE_FINE_TUNING = "fine_tuning" CONF_AUTO_TPI_LEARNING_TYPES = [ AUTO_TPI_LEARNING_TYPE_DISCOVERY, AUTO_TPI_LEARNING_TYPE_FINE_TUNING, ] CONF_AUTO_TPI_ENABLE_ADVANCED_SETTINGS = "auto_tpi_enable_advanced_settings" CONF_AUTO_TPI_HEATER_HEATING_TIME = "heater_heating_time" CONF_AUTO_TPI_HEATER_COOLING_TIME = "heater_cooling_time" CONF_AUTO_TPI_CALCULATION_METHOD = "auto_tpi_calculation_method" AUTO_TPI_METHOD_AVG = "average" AUTO_TPI_METHOD_EMA = "ema" CONF_AUTO_TPI_CALCULATION_METHODS = [AUTO_TPI_METHOD_AVG, AUTO_TPI_METHOD_EMA] CONF_AUTO_TPI_EMA_ALPHA = "auto_tpi_ema_alpha" CONF_AUTO_TPI_AVG_INITIAL_WEIGHT = "auto_tpi_avg_initial_weight" CONF_AUTO_TPI_HEATING_POWER = "auto_tpi_heating_rate" CONF_AUTO_TPI_COOLING_POWER = "auto_tpi_cooling_rate" CONF_AUTO_TPI_AGGRESSIVENESS = "auto_tpi_aggressiveness" CONF_AUTO_TPI_EMA_DECAY_RATE = "auto_tpi_ema_decay_rate" CONF_AUTO_TPI_CONTINUOUS_KEXT = "auto_tpi_continuous_kext" CONF_AUTO_TPI_CONTINUOUS_KEXT_ALPHA = "auto_tpi_continuous_kext_alpha" # Global params into configuration.yaml CONF_SHORT_EMA_PARAMS = "short_ema_params" CONF_SAFETY_MODE = "safety_mode" CONF_MAX_ON_PERCENT = "max_on_percent" CONF_LOG_BUFFER_MAX_AGE_HOURS = "log_buffer_max_age_hours" CONF_USE_MAIN_CENTRAL_CONFIG = "use_main_central_config" CONF_USE_TPI_CENTRAL_CONFIG = "use_tpi_central_config" CONF_USE_WINDOW_CENTRAL_CONFIG = "use_window_central_config" CONF_USE_MOTION_CENTRAL_CONFIG = "use_motion_central_config" CONF_USE_POWER_CENTRAL_CONFIG = "use_power_central_config" CONF_USE_PRESENCE_CENTRAL_CONFIG = "use_presence_central_config" CONF_USE_PRESETS_CENTRAL_CONFIG = "use_presets_central_config" CONF_USE_ADVANCED_CENTRAL_CONFIG = "use_advanced_central_config" CONF_USE_LOCK_CENTRAL_CONFIG = "use_lock_central_config" CONF_USE_CENTRAL_MODE = "use_central_mode" CONF_CENTRAL_BOILER_ACTIVATION_SRV = "central_boiler_activation_service" CONF_CENTRAL_BOILER_DEACTIVATION_SRV = "central_boiler_deactivation_service" CONF_CENTRAL_BOILER_ACTIVATION_DELAY_SEC = "central_boiler_activation_delay_sec" CONF_KEEP_ALIVE_BOILER_DELAY_SEC = "keep_alive_boiler_delay_sec" CONF_USED_BY_CENTRAL_BOILER = "used_by_controls_central_boiler" CONF_WINDOW_ACTION = "window_action" CONF_AUTO_START_STOP_LEVEL = "auto_start_stop_level" AUTO_START_STOP_LEVEL_NONE = "auto_start_stop_none" AUTO_START_STOP_LEVEL_VERY_SLOW = "auto_start_stop_very_slow" AUTO_START_STOP_LEVEL_SLOW = "auto_start_stop_slow" AUTO_START_STOP_LEVEL_MEDIUM = "auto_start_stop_medium" AUTO_START_STOP_LEVEL_FAST = "auto_start_stop_fast" CONF_AUTO_START_STOP_LEVELS = [ AUTO_START_STOP_LEVEL_NONE, AUTO_START_STOP_LEVEL_VERY_SLOW, AUTO_START_STOP_LEVEL_SLOW, AUTO_START_STOP_LEVEL_MEDIUM, AUTO_START_STOP_LEVEL_FAST, ] # For explicit typing purpose only TYPE_AUTO_START_STOP_LEVELS = Literal[ # pylint: disable=invalid-name AUTO_START_STOP_LEVEL_FAST, AUTO_START_STOP_LEVEL_MEDIUM, AUTO_START_STOP_LEVEL_SLOW, AUTO_START_STOP_LEVEL_VERY_SLOW, AUTO_START_STOP_LEVEL_NONE, ] HVAC_OFF_REASON_NAME = "hvac_off_reason" HVAC_OFF_REASON_MANUAL = "hvac_off_manual" HVAC_OFF_REASON_AUTO_START_STOP = "hvac_off_auto_start_stop" HVAC_OFF_REASON_WINDOW_DETECTION = "hvac_off_window_detection" HVAC_OFF_REASON_SLEEP_MODE = "hvac_off_sleep_mode" HVAC_OFF_REASON_SAFETY = "hvac_off_safety_detection" HVAC_OFF_REASON_CENTRAL_MODE = "hvac_off_central_mode" HVAC_OFF_REASONS = Literal[ # pylint: disable=invalid-name HVAC_OFF_REASON_MANUAL, HVAC_OFF_REASON_AUTO_START_STOP, HVAC_OFF_REASON_WINDOW_DETECTION, HVAC_OFF_REASON_SLEEP_MODE, HVAC_OFF_REASON_SAFETY ] DEFAULT_SHORT_EMA_PARAMS = { "max_alpha": 0.5, # In sec "halflife_sec": 300, "precision": 2, } CONF_PRESETS = { p: f"{p}{PRESET_TEMP_SUFFIX}" for p in ( VThermPreset.FROST, VThermPreset.ECO, VThermPreset.COMFORT, VThermPreset.BOOST, ) } CONF_PRESETS_WITH_AC = { p: f"{p}{PRESET_TEMP_SUFFIX}" for p in ( VThermPreset.FROST, VThermPreset.ECO, VThermPreset.COMFORT, VThermPreset.BOOST, VThermPresetWithAC.ECO, VThermPresetWithAC.COMFORT, VThermPresetWithAC.BOOST, ) } CONF_PRESETS_AWAY = { p: f"{p}{PRESET_TEMP_SUFFIX}" for p in ( VThermPresetWithAway.FROST, VThermPresetWithAway.ECO, VThermPresetWithAway.COMFORT, VThermPresetWithAway.BOOST, ) } CONF_PRESETS_AWAY_WITH_AC = { p: f"{p}{PRESET_TEMP_SUFFIX}" for p in ( VThermPresetWithAway.FROST, VThermPresetWithAway.ECO, VThermPresetWithAway.COMFORT, VThermPresetWithAway.BOOST, VThermPresetWithACAway.ECO, VThermPresetWithACAway.COMFORT, VThermPresetWithACAway.BOOST, ) } CONF_PRESETS_SELECTIONABLE = [ VThermPreset.FROST, VThermPreset.ECO, VThermPreset.COMFORT, VThermPreset.BOOST, ] CONF_PRESETS_VALUES = list(CONF_PRESETS.values()) CONF_PRESETS_AWAY_VALUES = list(CONF_PRESETS_AWAY.values()) CONF_PRESETS_WITH_AC_VALUES = list(CONF_PRESETS_WITH_AC.values()) CONF_PRESETS_AWAY_WITH_AC_VALUES = list(CONF_PRESETS_AWAY_WITH_AC.values()) ALL_CONF = ( [ CONF_NAME, CONF_HEATER_KEEP_ALIVE, CONF_TEMP_SENSOR, CONF_EXTERNAL_TEMP_SENSOR, CONF_POWER_SENSOR, CONF_MAX_POWER_SENSOR, CONF_WINDOW_SENSOR, CONF_WINDOW_DELAY, CONF_WINDOW_OFF_DELAY, CONF_WINDOW_AUTO_OPEN_THRESHOLD, CONF_WINDOW_AUTO_CLOSE_THRESHOLD, CONF_WINDOW_AUTO_MAX_DURATION, CONF_MOTION_SENSOR, CONF_MOTION_DELAY, CONF_MOTION_PRESET, CONF_NO_MOTION_PRESET, CONF_DEVICE_POWER, CONF_CYCLE_MIN, CONF_PROP_FUNCTION, CONF_TPI_COEF_INT, CONF_TPI_COEF_EXT, CONF_TPI_THRESHOLD_LOW, CONF_TPI_THRESHOLD_HIGH, CONF_AUTO_TPI_HEATER_HEATING_TIME, CONF_AUTO_TPI_HEATER_COOLING_TIME, CONF_PRESENCE_SENSOR, CONF_MINIMAL_ACTIVATION_DELAY, CONF_MINIMAL_DEACTIVATION_DELAY, CONF_TEMP_MIN, CONF_TEMP_MAX, CONF_SAFETY_DELAY_MIN, CONF_SAFETY_MIN_ON_PERCENT, CONF_SAFETY_DEFAULT_ON_PERCENT, CONF_THERMOSTAT_TYPE, CONF_THERMOSTAT_SWITCH, CONF_THERMOSTAT_CLIMATE, CONF_USE_WINDOW_FEATURE, CONF_USE_MOTION_FEATURE, CONF_USE_PRESENCE_FEATURE, CONF_USE_POWER_FEATURE, CONF_USE_CENTRAL_BOILER_FEATURE, CONF_AC_MODE, CONF_AUTO_REGULATION_MODE, CONF_AUTO_REGULATION_DTEMP, CONF_AUTO_REGULATION_PERIOD_MIN, CONF_AUTO_REGULATION_USE_DEVICE_TEMP, CONF_INVERSE_SWITCH, CONF_AUTO_FAN_MODE, CONF_USE_MAIN_CENTRAL_CONFIG, CONF_USE_TPI_CENTRAL_CONFIG, CONF_USE_PRESETS_CENTRAL_CONFIG, CONF_USE_WINDOW_CENTRAL_CONFIG, CONF_USE_MOTION_CENTRAL_CONFIG, CONF_USE_POWER_CENTRAL_CONFIG, CONF_USE_PRESENCE_CENTRAL_CONFIG, CONF_USE_ADVANCED_CENTRAL_CONFIG, CONF_USE_CENTRAL_MODE, CONF_USED_BY_CENTRAL_BOILER, CONF_CENTRAL_BOILER_ACTIVATION_SRV, CONF_CENTRAL_BOILER_DEACTIVATION_SRV, CONF_CENTRAL_BOILER_ACTIVATION_DELAY_SEC, CONF_KEEP_ALIVE_BOILER_DELAY_SEC, CONF_WINDOW_ACTION, CONF_STEP_TEMPERATURE, CONF_MIN_OPENING_DEGREES, CONF_MAX_OPENING_DEGREES, CONF_MAX_CLOSING_DEGREE, CONF_OPENING_THRESHOLD_DEGREE, CONF_AUTO_TPI_CALCULATION_METHOD, CONF_AUTO_TPI_EMA_ALPHA, CONF_AUTO_TPI_AVG_INITIAL_WEIGHT, CONF_AUTO_TPI_HEATING_POWER, CONF_AUTO_TPI_COOLING_POWER, CONF_AUTO_TPI_EMA_DECAY_RATE, CONF_AUTO_TPI_CONTINUOUS_KEXT, CONF_AUTO_TPI_CONTINUOUS_KEXT_ALPHA, CONF_AUTO_TPI_LEARNING_TYPE, CONF_AUTO_TPI_ENABLE_ADVANCED_SETTINGS, CONF_SYNC_DEVICE_INTERNAL_TEMP, CONF_SYNC_WITH_CALIBRATION, CONF_USE_HEATING_FAILURE_DETECTION_FEATURE, CONF_USE_HEATING_FAILURE_DETECTION_CENTRAL_CONFIG, CONF_HEATING_FAILURE_THRESHOLD, CONF_COOLING_FAILURE_THRESHOLD, CONF_HEATING_FAILURE_DETECTION_DELAY, CONF_TEMPERATURE_CHANGE_TOLERANCE, CONF_FAILURE_DETECTION_ENABLE_TEMPLATE, CONF_REPAIR_INCORRECT_STATE, ] + CONF_PRESETS_VALUES + CONF_PRESETS_AWAY_VALUES + CONF_PRESETS_WITH_AC_VALUES + CONF_PRESETS_AWAY_WITH_AC_VALUES, ) CONF_FUNCTIONS = [ PROPORTIONAL_FUNCTION_TPI, ] CONF_AUTO_REGULATION_MODES = [ CONF_AUTO_REGULATION_NONE, CONF_AUTO_REGULATION_VALVE, CONF_AUTO_REGULATION_LIGHT, CONF_AUTO_REGULATION_MEDIUM, CONF_AUTO_REGULATION_STRONG, CONF_AUTO_REGULATION_SLOW, CONF_AUTO_REGULATION_EXPERT, ] CONF_THERMOSTAT_TYPES = [ CONF_THERMOSTAT_CENTRAL_CONFIG, CONF_THERMOSTAT_SWITCH, CONF_THERMOSTAT_CLIMATE, CONF_THERMOSTAT_VALVE, ] CONF_AUTO_FAN_MODES = [ CONF_AUTO_FAN_NONE, CONF_AUTO_FAN_LOW, CONF_AUTO_FAN_MEDIUM, CONF_AUTO_FAN_HIGH, CONF_AUTO_FAN_TURBO, ] CONF_WINDOW_TURN_OFF = "window_turn_off" CONF_WINDOW_FAN_ONLY = "window_fan_only" CONF_WINDOW_FROST_TEMP = "window_frost_temp" CONF_WINDOW_ECO_TEMP = "window_eco_temp" CONF_WINDOW_ACTIONS = [ CONF_WINDOW_TURN_OFF, CONF_WINDOW_FAN_ONLY, CONF_WINDOW_FROST_TEMP, CONF_WINDOW_ECO_TEMP, ] SUPPORT_FLAGS = ( ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON ) SERVICE_SET_PRESENCE = "set_presence" SERVICE_SET_SAFETY = "set_safety" SERVICE_SET_WINDOW_BYPASS = "set_window_bypass" SERVICE_SET_AUTO_REGULATION_MODE = "set_auto_regulation_mode" SERVICE_SET_AUTO_FAN_MODE = "set_auto_fan_mode" SERVICE_SET_HVAC_MODE_SLEEP = "set_hvac_mode_sleep" SERVICE_LOCK = "lock" SERVICE_UNLOCK = "unlock" SERVICE_SET_TPI_PARAMETERS = "set_tpi_parameters" SERVICE_SET_AUTO_TPI_MODE = "set_auto_tpi_mode" SERVICE_AUTO_TPI_CALIBRATE_CAPACITY = "auto_tpi_calibrate_capacity" AUTO_TPI_EVENT = "versatile_thermostat_auto_tpi_event" SERVICE_SET_TIMED_PRESET = "set_timed_preset" SERVICE_CANCEL_TIMED_PRESET = "cancel_timed_preset" SERVICE_RECALIBRATE_VALVES = "recalibrate_valves" SERVICE_DOWNLOAD_LOGS = "download_logs" DEFAULT_SAFETY_MIN_ON_PERCENT = 0.5 DEFAULT_SAFETY_DEFAULT_ON_PERCENT = 0.1 # Repair incorrect state defaults DEFAULT_REPAIR_INCORRECT_STATE = False REPAIR_MAX_ATTEMPTS = 5 REPAIR_MIN_DELAY_AFTER_INIT_SEC = 30 # Central boiler keep-alive defaults DEFAULT_KEEP_ALIVE_BOILER_DELAY_SEC = 0 # Heating failure detection defaults DEFAULT_HEATING_FAILURE_THRESHOLD = 0.9 # 90% DEFAULT_COOLING_FAILURE_THRESHOLD = 0.0 # 0% DEFAULT_HEATING_FAILURE_DETECTION_DELAY = 15 # 15 minutes DEFAULT_TEMPERATURE_CHANGE_TOLERANCE = 0.5 # 0.5°C ATTR_TOTAL_ENERGY = "total_energy" ATTR_MEAN_POWER_CYCLE = "mean_cycle_power" AUTO_FAN_DTEMP_THRESHOLD = 2 AUTO_FAN_DEACTIVATED_MODES = ["mute", "quiet", "low", "quiet", "1", "auto"] CENTRAL_CONFIG_NAME = "Central configuration" CENTRAL_MODE_AUTO = "Auto" CENTRAL_MODE_STOPPED = "Stopped" CENTRAL_MODE_HEAT_ONLY = "Heat only" CENTRAL_MODE_COOL_ONLY = "Cool only" CENTRAL_MODE_FROST_PROTECTION = "Frost protection" CENTRAL_MODES = [ CENTRAL_MODE_AUTO, CENTRAL_MODE_STOPPED, CENTRAL_MODE_HEAT_ONLY, CENTRAL_MODE_COOL_ONLY, CENTRAL_MODE_FROST_PROTECTION, ] ATTR_CURRENT_STATE = "current_state" ATTR_REQUESTED_STATE = "requested_state" MSG_OVERPOWERING_DETECTED = "overpowering_detected" MSG_SAFETY_DETECTED = "safety_detected" MSG_TARGET_TEMP_WINDOW_ECO = "target_temp_window_eco" MSG_TARGET_TEMP_WINDOW_FROST = "target_temp_window_frost" MSG_TARGET_TEMP_POWER = "target_temp_power" MSG_TARGET_TEMP_CENTRAL_MODE = "target_temp_central_mode" MSG_TARGET_TEMP_ACTIVITY_DETECTED = "target_temp_activity_detected" MSG_TARGET_TEMP_ACTIVITY_NOT_DETECTED = "target_temp_activity_not_detected" MSG_TARGET_TEMP_ABSENCE_DETECTED = "target_temp_absence_detected" MSG_TARGET_TEMP_TIMED_PRESET = "target_temp_timed_preset" MSG_NOT_INITIALIZED = "not_initialized" # A special regulation parameter suggested by @Maia here: https://github.com/jmcollin78/versatile_thermostat/discussions/154 class RegulationParamSlow: """Light parameters for slow latency regulation""" kp: float = ( 0.2 # 20% of the current internal regulation offset are caused by the current difference of target temperature and room temperature ) ki: float = ( 0.8 / 288.0 ) # 80% of the current internal regulation offset are caused by the average offset of the past 24 hours k_ext: float = ( 1.0 / 25.0 ) # this will add 1°C to the offset when it's 25°C colder outdoor than indoor offset_max: float = 2.0 # limit to a final offset of -2°C to +2°C accumulated_error_threshold: float = ( 2.0 * 288 ) # this allows up to 2°C long term offset in both directions overheat_protection: bool = True class RegulationParamLight: """Light parameters for regulation""" kp: float = 0.2 ki: float = 0.05 k_ext: float = 0.05 offset_max: float = 1.5 accumulated_error_threshold: float = 10 overheat_protection: bool = True class RegulationParamMedium: """Light parameters for regulation""" kp: float = 0.3 ki: float = 0.05 k_ext: float = 0.1 offset_max: float = 2 accumulated_error_threshold: float = 20 overheat_protection: bool = True class RegulationParamStrong: """Strong parameters for regulation A set of parameters which doesn't take into account the external temp and concentrate to internal temp error + accumulated error. This should work for cold external conditions which else generates high external_offset""" kp: float = 0.4 ki: float = 0.08 k_ext: float = 0.0 offset_max: float = 5 accumulated_error_threshold: float = 50 overheat_protection: bool = True # Not used now class RegulationParamVeryStrong: """Strong parameters for regulation""" kp: float = 0.6 ki: float = 0.1 k_ext: float = 0.2 offset_max: float = 8 accumulated_error_threshold: float = 80 overheat_protection: bool = True def send_vtherm_event(hass, event_type: EventType, entity, data: dict): """Send an event""" _LOGGER.info("%s - Sending event %s with data: %s", entity, event_type, data) data["entity_id"] = entity.entity_id data["name"] = entity.name data["state_attributes"] = entity.state_attributes hass.bus.fire(event_type.value, data) def get_safe_float(hass, entity_id: str): """Get a safe float state value for an entity. Return None if entity is not available""" if entity_id is None or not (state := hass.states.get(entity_id)) or state.state in [None, "None", STATE_UNAVAILABLE, STATE_UNKNOWN]: return None return get_safe_float_value(state.state) def get_safe_float_value(value): """Get a safe float value. Return None if value is not a valid float""" try: float_val = float(value) return None if math.isinf(float_val) or not math.isfinite(float_val) else float_val except (ValueError, TypeError): return None class UnknownEntity(HomeAssistantError): """Error to indicate there is an unknown entity_id given.""" class WindowOpenDetectionMethod(HomeAssistantError): """Error to indicate there is an error in the window open detection method given.""" class NoCentralConfig(HomeAssistantError): """Error to indicate that we try to use a central configuration but no VTherm of type CENTRAL CONFIGURATION has been found""" class ServiceConfigurationError(HomeAssistantError): """Error in the service configuration to control the central boiler""" class ConfigurationNotCompleteError(HomeAssistantError): """Error the configuration is not complete""" class ValveRegulationNbEntitiesIncorrect(HomeAssistantError): """Error to indicate there is an error in the configuration of the TRV with valve regulation. The number of specific entities is incorrect.""" class SyncDeviceInternalTempNbEntitiesIncorrect(HomeAssistantError): """Error to indicate there is an error in the configuration of the TRV with synchronize device internal temperature. The number of specific entities is incorrect.""" class ValveRegulationMinOpeningDegreesIncorrect(HomeAssistantError): """Error to indicate that the minimal opening degrees is not a list of int separated by coma""" class ValveRegulationMaxOpeningDegreesIncorrect(HomeAssistantError): """Error to indicate that the maximal opening degrees is not a list of int separated by coma""" class ValveRegulationMinMaxOpeningDegreesIncorrect(HomeAssistantError): """Error to indicate that max_opening_degrees must be greater than min_opening_degrees for each underlying""" class VirtualSwitchConfigurationIncorrect(HomeAssistantError): """Error when a virtual switch is not configured correctly""" class LockCodeIncorrect(HomeAssistantError): """Error when a lock code is not configured correctly""" class overrides: # pylint: disable=invalid-name """An annotation to inform overrides""" def __init__(self, func): self.func = func def __get__(self, instance, owner): return self.func.__get__(instance, owner) def __call__(self, *args, **kwargs): raise RuntimeError(f"Method {self.func.__name__} should have been overridden")