Skip to content

Commit

Permalink
Issue #223 - add auto_fan_mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Jean-Marc Collin committed Dec 9, 2023
1 parent f7c4e20 commit 7f63503
Show file tree
Hide file tree
Showing 16 changed files with 763 additions and 114 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,4 @@ __pycache__

config/**
custom_components/hacs
custom_components/localtuya
42 changes: 18 additions & 24 deletions custom_components/versatile_thermostat/base_thermostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@
CONF_TEMP_MIN,
HIDDEN_PRESETS,
CONF_AC_MODE,
UnknownEntity,
EventType,
ATTR_MEAN_POWER_CYCLE,
ATTR_TOTAL_ENERGY,
Expand Down Expand Up @@ -259,6 +258,8 @@ def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
self._ema_temp = None
self._ema_algo = None
self._now = None

self._attr_fan_mode = None
self.post_init(entry_infos)

def post_init(self, entry_infos):
Expand Down Expand Up @@ -555,11 +556,7 @@ async def async_added_to_hass(self):

self.async_on_remove(self.remove_thermostat)

try:
await self.async_startup()
except UnknownEntity:
# Ingore this error which is possible if underlying climate is not found temporary
pass
await self.async_startup()

def remove_thermostat(self):
"""Called when the thermostat will be removed"""
Expand All @@ -577,12 +574,7 @@ async def _async_startup_internal(*_):
need_write_state = False

# Initialize all UnderlyingEntities
for under in self._underlyings:
try:
under.startup()
except UnknownEntity:
# Not found, we will try later
pass
self.init_underlyings()

temperature_state = self.hass.states.get(self._temp_sensor_entity_id)
if temperature_state and temperature_state.state not in (
Expand Down Expand Up @@ -723,6 +715,9 @@ async def _async_startup_internal(*_):
EVENT_HOMEASSISTANT_START, _async_startup_internal
)

def init_underlyings(self):
"""Initialize all underlyings. Should be overriden if necessary"""

def restore_specific_previous_state(self, old_state):
"""Should be overriden in each specific thermostat
if a specific previous state or attribute should be
Expand Down Expand Up @@ -2089,6 +2084,13 @@ async def check_security(self) -> bool:

return shouldBeInSecurity

@property
def is_initialized(self) -> bool:
"""Check if all underlyings are initialized
This is usefull only for over_climate in which we
should have found the underlying climate to be operational"""
return True

async def async_control_heating(self, force=False, _=None):
"""The main function used to run the calculation at each cycle"""

Expand All @@ -2104,18 +2106,10 @@ async def async_control_heating(self, force=False, _=None):
await self._async_manage_window_auto(in_cycle=True)

# Issue 56 in over_climate mode, if the underlying climate is not initialized, try to initialize it
for under in self._underlyings:
if not under.is_initialized:
_LOGGER.info(
"%s - Underlying %s is not initialized. Try to initialize it",
self,
under.entity_id,
)
try:
under.startup()
except UnknownEntity:
# still not found, we an stop here
return False
if not self.is_initialized:
if not self.init_underlyings():
# still not found, we an stop here
return False

# Check overpowering condition
# Not necessary for switch because each switch is checking at startup
Expand Down
28 changes: 23 additions & 5 deletions custom_components/versatile_thermostat/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@

from homeassistant.helpers import entity_platform

from homeassistant.const import CONF_NAME, STATE_ON, STATE_OFF, STATE_HOME, STATE_NOT_HOME
from homeassistant.const import (
CONF_NAME,
STATE_ON,
STATE_OFF,
STATE_HOME,
STATE_NOT_HOME,
)

from .const import (
DOMAIN,
Expand All @@ -26,10 +32,11 @@
SERVICE_SET_SECURITY,
SERVICE_SET_WINDOW_BYPASS,
SERVICE_SET_AUTO_REGULATION_MODE,
SERVICE_SET_AUTO_FAN_MODE,
CONF_THERMOSTAT_TYPE,
CONF_THERMOSTAT_SWITCH,
CONF_THERMOSTAT_CLIMATE,
CONF_THERMOSTAT_VALVE
CONF_THERMOSTAT_VALVE,
)

from .thermostat_switch import ThermostatOverSwitch
Expand Down Expand Up @@ -102,16 +109,27 @@ async def async_setup_entry(
platform.async_register_entity_service(
SERVICE_SET_WINDOW_BYPASS,
{
vol.Required("window_bypass"): vol.In([True, False]
),
vol.Required("window_bypass"): vol.In([True, False]),
},
"service_set_window_bypass_state",
)

platform.async_register_entity_service(
SERVICE_SET_AUTO_REGULATION_MODE,
{
vol.Required("auto_regulation_mode"): vol.In(["None", "Light", "Medium", "Strong", "Slow"]),
vol.Required("auto_regulation_mode"): vol.In(
["None", "Light", "Medium", "Strong", "Slow"]
),
},
"service_set_auto_regulation_mode",
)

platform.async_register_entity_service(
SERVICE_SET_AUTO_FAN_MODE,
{
vol.Required("auto_fan_mode"): vol.In(
["None", "Low", "Medium", "High", "Turbo"]
),
},
"service_set_auto_fan_mode",
)
11 changes: 11 additions & 0 deletions custom_components/versatile_thermostat/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@
CONF_INVERSE_SWITCH,
UnknownEntity,
WindowOpenDetectionMethod,
CONF_AUTO_FAN_MODES,
CONF_AUTO_FAN_MODE,
CONF_AUTO_FAN_HIGH,
)

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -275,6 +278,14 @@ def __init__(self, infos) -> None:
vol.Optional(
CONF_AUTO_REGULATION_PERIOD_MIN, default=5
): cv.positive_int,
vol.Optional(
CONF_AUTO_FAN_MODE, default=CONF_AUTO_FAN_HIGH
): selector.SelectSelector(
selector.SelectSelectorConfig(
options=CONF_AUTO_FAN_MODES,
translation_key="auto_fan_mode",
)
),
}
)

Expand Down
18 changes: 18 additions & 0 deletions custom_components/versatile_thermostat/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@
CONF_AUTO_REGULATION_PERIOD_MIN = "auto_regulation_periode_min"
CONF_INVERSE_SWITCH = "inverse_switch_command"
CONF_SHORT_EMA_PARAMS = "short_ema_params"
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"

DEFAULT_SHORT_EMA_PARAMS = {
"max_alpha": 0.5,
Expand Down Expand Up @@ -233,20 +239,32 @@
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,
]

SUPPORT_FLAGS = ClimateEntityFeature.TARGET_TEMPERATURE

SERVICE_SET_PRESENCE = "set_presence"
SERVICE_SET_PRESET_TEMPERATURE = "set_preset_temperature"
SERVICE_SET_SECURITY = "set_security"
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"

DEFAULT_SECURITY_MIN_ON_PERCENT = 0.5
DEFAULT_SECURITY_DEFAULT_ON_PERCENT = 0.1

ATTR_TOTAL_ENERGY = "total_energy"
ATTR_MEAN_POWER_CYCLE = "mean_cycle_power"

AUTO_FAN_DTEMP_THRESHOLD = 2
AUTO_FAN_DEACTIVATED_MODES = ["mute", "silent", "auto", "low"]


# A special regulation parameter suggested by @Maia here: https://github.com/jmcollin78/versatile_thermostat/discussions/154
class RegulationParamSlow:
Expand Down
22 changes: 22 additions & 0 deletions custom_components/versatile_thermostat/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,25 @@ set_auto_regulation_mode:
- "Strong"
- "Slow"
- "Expert"

set_auto_fan_mode:
name: Set Auto Fan mode
description: Change the mode of auto-fan (only for VTherm over climate)
target:
entity:
integration: versatile_thermostat
fields:
auto_fan_mode:
name: Auto fan mode
description: Possible values
required: true
advanced: false
default: true
selector:
select:
options:
- "None"
- "Low"
- "Medium"
- "High"
- "Turbo"
Loading

0 comments on commit 7f63503

Please sign in to comment.