Compare commits

..

8 Commits

Author SHA1 Message Date
Jean-Marc Collin
3d977c4981 Failure to initialize #39 2023-02-01 10:43:21 +01:00
Jean-Marc Collin
115df52f67 Issue#36 - Error at initialisation
Issue#32 - Error with Fan Modes on thermostat over climate type
2023-01-31 22:19:43 +01:00
Jean-Marc Collin
3371197594 Fix issue#32 Error with Fan Modes on thermostat over climate type 2023-01-31 09:35:27 +01:00
Jean-Marc Collin
7e63c9aa79 Heater can restart after HVAC_MODE_OFF 2023-01-30 07:09:43 +01:00
Jean-Marc Collin
100cfaeac9 Add binary sensors for window sensors 2023-01-30 06:49:39 +01:00
Jean-Marc Collin
77631e94d9 FIX feature selection 2023-01-29 23:21:51 +01:00
Jean-Marc Collin
49c85eeb2b Try to fix const import 2023-01-29 22:01:05 +01:00
Jean-Marc Collin
bb2c1d328b FIX selectors 2023-01-29 21:39:08 +01:00
6 changed files with 333 additions and 128 deletions

View File

@@ -111,3 +111,10 @@ recorder:
- switch - switch
- climate - climate
- sensor - sensor
template:
- binary_sensor:
- name: maison_occupee
unique_id: maison_occupee
state: "{{is_state('person.jmc', 'home') }}"
device_class: occupancy

View File

@@ -34,17 +34,15 @@ from homeassistant.helpers import (
entity_platform, entity_platform,
) # , config_validation as cv ) # , config_validation as cv
from homeassistant.components.climate.const import ( from homeassistant.components.climate import (
DOMAIN as CLIMATE_DOMAIN, DOMAIN as CLIMATE_DOMAIN,
ATTR_PRESET_MODE, ATTR_PRESET_MODE,
# ATTR_FAN_MODE, # ATTR_FAN_MODE,
CURRENT_HVAC_COOL, HVACMode,
CURRENT_HVAC_HEAT, HVACAction,
CURRENT_HVAC_IDLE, # HVAC_MODE_COOL,
CURRENT_HVAC_OFF, # HVAC_MODE_HEAT,
HVAC_MODE_COOL, # HVAC_MODE_OFF,
HVAC_MODE_HEAT,
HVAC_MODE_OFF,
PRESET_ACTIVITY, PRESET_ACTIVITY,
# PRESET_AWAY, # PRESET_AWAY,
PRESET_BOOST, PRESET_BOOST,
@@ -53,7 +51,8 @@ from homeassistant.components.climate.const import (
# PRESET_HOME, # PRESET_HOME,
PRESET_NONE, PRESET_NONE,
# PRESET_SLEEP, # PRESET_SLEEP,
SUPPORT_PRESET_MODE, ClimateEntityFeature,
# ClimateEntityFeature.PRESET_MODE,
# SUPPORT_TARGET_TEMPERATURE, # SUPPORT_TARGET_TEMPERATURE,
SERVICE_SET_FAN_MODE, SERVICE_SET_FAN_MODE,
SERVICE_SET_HUMIDITY, SERVICE_SET_HUMIDITY,
@@ -63,6 +62,13 @@ from homeassistant.components.climate.const import (
SERVICE_SET_TEMPERATURE, SERVICE_SET_TEMPERATURE,
) )
# from homeassistant.components.climate import (
# CURRENT_HVAC_HEAT,
# HVACAction.IDLE,
# HVACAction.OFF,
# HVACAction.COOLING,
# )
from homeassistant.const import ( from homeassistant.const import (
# UnitOfTemperature, # UnitOfTemperature,
ATTR_TEMPERATURE, ATTR_TEMPERATURE,
@@ -220,6 +226,8 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
self._is_over_climate = False self._is_over_climate = False
self._underlying_climate = None self._underlying_climate = None
self._attr_translation_key = "versatile_thermostat"
self.post_init(entry_infos) self.post_init(entry_infos)
def post_init(self, entry_infos): def post_init(self, entry_infos):
@@ -297,7 +305,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
# TODO if self.ac_mode: # TODO if self.ac_mode:
# self.hvac_list = [HVAC_MODE_COOL, HVAC_MODE_OFF] # self.hvac_list = [HVAC_MODE_COOL, HVAC_MODE_OFF]
# else: # else:
self._hvac_list = [HVAC_MODE_HEAT, HVAC_MODE_OFF] self._hvac_list = [HVACMode.HEAT, HVACMode.OFF]
self._unit = UnitOfTemperature.CELSIUS self._unit = UnitOfTemperature.CELSIUS
# Will be restored if possible # Will be restored if possible
self._hvac_mode = None # HVAC_MODE_OFF self._hvac_mode = None # HVAC_MODE_OFF
@@ -383,7 +391,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
# Calculate all possible presets # Calculate all possible presets
self._attr_preset_modes = [PRESET_NONE] self._attr_preset_modes = [PRESET_NONE]
if len(presets): if len(presets):
self._support_flags = SUPPORT_FLAGS | SUPPORT_PRESET_MODE self._support_flags = SUPPORT_FLAGS | ClimateEntityFeature.PRESET_MODE
for key, val in presets.items(): for key, val in presets.items():
if val != 0.0: if val != 0.0:
@@ -741,7 +749,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
# Set default state to off # Set default state to off
if not self._hvac_mode: if not self._hvac_mode:
self._hvac_mode = HVAC_MODE_OFF self._hvac_mode = HVACMode.OFF
_LOGGER.info( _LOGGER.info(
"%s - restored state is target_temp=%.1f, preset_mode=%s, hvac_mode=%s", "%s - restored state is target_temp=%.1f, preset_mode=%s, hvac_mode=%s",
@@ -774,6 +782,50 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
return self._hvac_list return self._hvac_list
@property
def fan_mode(self) -> str | None:
"""Return the fan setting.
Requires ClimateEntityFeature.FAN_MODE.
"""
if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.fan_mode
return None
@property
def fan_modes(self) -> list[str] | None:
"""Return the list of available fan modes.
Requires ClimateEntityFeature.FAN_MODE.
"""
if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.fan_modes
return []
@property
def swing_mode(self) -> str | None:
"""Return the swing setting.
Requires ClimateEntityFeature.SWING_MODE.
"""
if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.swing_mode
return None
@property
def swing_modes(self) -> list[str] | None:
"""Return the list of available swing modes.
Requires ClimateEntityFeature.SWING_MODE.
"""
if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.swing_modes
return None
@property @property
def temperature_unit(self): def temperature_unit(self):
"""Return the unit of measurement.""" """Return the unit of measurement."""
@@ -796,13 +848,13 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
if self._is_over_climate and self._underlying_climate: if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.hvac_action return self._underlying_climate.hvac_action
if self._hvac_mode == HVAC_MODE_OFF: if self._hvac_mode == HVACMode.OFF:
return CURRENT_HVAC_OFF return HVACAction.OFF
if not self._is_device_active: if not self._is_device_active:
return CURRENT_HVAC_IDLE return HVACAction.IDLE
if self._ac_mode: if self._ac_mode:
return CURRENT_HVAC_COOL return HVACAction.COOLING
return CURRENT_HVAC_HEAT return HVACAction.HEATING
@property @property
def target_temperature(self): def target_temperature(self):
@@ -820,20 +872,114 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
@property @property
def _is_device_active(self): def _is_device_active(self):
"""If the toggleable device is currently active.""" """If the toggleable device is currently active."""
if self._is_over_climate or not self.hass.states.get(self._heater_entity_id): if self._is_over_climate:
return None if self._underlying_climate:
return self._underlying_climate.hvac_action not in [
return self.hass.states.is_state(self._heater_entity_id, STATE_ON) HVACAction.IDLE,
HVACAction.OFF,
]
else:
return None
else:
return self.hass.states.is_state(self._heater_entity_id, STATE_ON)
@property @property
def current_temperature(self): def current_temperature(self):
"""Return the sensor temperature.""" """Return the sensor temperature."""
return self._cur_temp return self._cur_temp
@property
def target_temperature_step(self) -> float | None:
"""Return the supported step of target temperature."""
if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.target_temperature_step
return None
@property
def target_temperature_high(self) -> float | None:
"""Return the highbound target temperature we try to reach.
Requires ClimateEntityFeature.TARGET_TEMPERATURE_RANGE.
"""
if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.target_temperature_high
return None
@property
def target_temperature_low(self) -> float | None:
"""Return the lowbound target temperature we try to reach.
Requires ClimateEntityFeature.TARGET_TEMPERATURE_RANGE.
"""
if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.target_temperature_low
return None
@property
def is_aux_heat(self) -> bool | None:
"""Return true if aux heater.
Requires ClimateEntityFeature.AUX_HEAT.
"""
if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.is_aux_heat
return None
def turn_aux_heat_on(self) -> None:
"""Turn auxiliary heater on."""
if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.turn_aux_heat_on()
raise NotImplementedError()
async def async_turn_aux_heat_on(self) -> None:
"""Turn auxiliary heater on."""
if self._is_over_climate and self._underlying_climate:
await self._underlying_climate.async_turn_aux_heat_on()
raise NotImplementedError()
def turn_aux_heat_off(self) -> None:
"""Turn auxiliary heater off."""
if self._is_over_climate and self._underlying_climate:
return self._underlying_climate.turn_aux_heat_off()
raise NotImplementedError()
async def async_turn_aux_heat_off(self) -> None:
"""Turn auxiliary heater off."""
if self._is_over_climate and self._underlying_climate:
await self._underlying_climate.async_turn_aux_heat_off()
raise NotImplementedError()
@property
def preset_mode(self) -> str | None:
"""Return the current preset mode, e.g., home, away, temp.
Requires ClimateEntityFeature.PRESET_MODE.
"""
return self._attr_preset_mode
@property
def preset_modes(self) -> list[str] | None:
"""Return a list of available preset modes.
Requires ClimateEntityFeature.PRESET_MODE.
"""
return self._attr_preset_modes
async def async_set_hvac_mode(self, hvac_mode): async def async_set_hvac_mode(self, hvac_mode):
"""Set new target hvac mode.""" """Set new target hvac mode."""
_LOGGER.info("%s - Set hvac mode: %s", self, hvac_mode) _LOGGER.info("%s - Set hvac mode: %s", self, hvac_mode)
if hvac_mode is None:
return
if self._is_over_climate and self._underlying_climate: if self._is_over_climate and self._underlying_climate:
data = {ATTR_ENTITY_ID: self._climate_entity_id, "hvac_mode": hvac_mode} data = {ATTR_ENTITY_ID: self._climate_entity_id, "hvac_mode": hvac_mode}
await self.hass.services.async_call( await self.hass.services.async_call(
@@ -842,14 +988,14 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
# await self._underlying_climate.async_set_hvac_mode(hvac_mode) # await self._underlying_climate.async_set_hvac_mode(hvac_mode)
self._hvac_mode = hvac_mode # self._underlying_climate.hvac_mode self._hvac_mode = hvac_mode # self._underlying_climate.hvac_mode
else: else:
if hvac_mode == HVAC_MODE_HEAT: if hvac_mode == HVACMode.HEAT:
self._hvac_mode = HVAC_MODE_HEAT self._hvac_mode = HVACMode.HEAT
await self._async_control_heating(force=True) await self._async_control_heating(force=True)
elif hvac_mode == HVAC_MODE_COOL: elif hvac_mode == HVACMode.COOL:
self._hvac_mode = HVAC_MODE_COOL self._hvac_mode = HVACMode.COOL
await self._async_control_heating(force=True) await self._async_control_heating(force=True)
elif hvac_mode == HVAC_MODE_OFF: elif hvac_mode == HVACMode.OFF:
self._hvac_mode = HVAC_MODE_OFF self._hvac_mode = HVACMode.OFF
if self._is_device_active: if self._is_device_active:
await self._async_underlying_entity_turn_off() await self._async_underlying_entity_turn_off()
await self._async_control_heating(force=True) await self._async_control_heating(force=True)
@@ -1080,10 +1226,10 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
await self.restore_hvac_mode() await self.restore_hvac_mode()
elif self._window_state == STATE_ON: elif self._window_state == STATE_ON:
_LOGGER.info( _LOGGER.info(
"%s - Window is open. Set hvac_mode to '%s'", self, HVAC_MODE_OFF "%s - Window is open. Set hvac_mode to '%s'", self, HVACMode.OFF
) )
self.save_hvac_mode() self.save_hvac_mode()
await self.async_set_hvac_mode(HVAC_MODE_OFF) await self.async_set_hvac_mode(HVACMode.OFF)
self.update_custom_attributes() self.update_custom_attributes()
if self._window_call_cancel: if self._window_call_cancel:
@@ -1155,7 +1301,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
async def _check_switch_initial_state(self): async def _check_switch_initial_state(self):
"""Prevent the device from keep running if HVAC_MODE_OFF.""" """Prevent the device from keep running if HVAC_MODE_OFF."""
_LOGGER.debug("%s - Calling _check_switch_initial_state", self) _LOGGER.debug("%s - Calling _check_switch_initial_state", self)
if self._hvac_mode == HVAC_MODE_OFF and self._is_device_active: if self._hvac_mode == HVACMode.OFF and self._is_device_active:
_LOGGER.warning( _LOGGER.warning(
"The climate mode is OFF, but the switch device is ON. Turning off device %s", "The climate mode is OFF, but the switch device is ON. Turning off device %s",
self._heater_entity_id, self._heater_entity_id,
@@ -1185,9 +1331,9 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
) )
# old_state = event.data.get("old_state") # old_state = event.data.get("old_state")
if new_state is None or new_state.state not in [ if new_state is None or new_state.state not in [
HVAC_MODE_COOL, HVACMode.OFF,
HVAC_MODE_HEAT, HVACMode.HEAT,
HVAC_MODE_OFF, HVACMode.COOL,
]: ]:
return return
self._hvac_mode = new_state.state self._hvac_mode = new_state.state
@@ -1377,11 +1523,17 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
async def _async_underlying_entity_turn_off(self): async def _async_underlying_entity_turn_off(self):
"""Turn heater toggleable device off.""" """Turn heater toggleable device off."""
if not self._is_over_climate: if not self._is_over_climate:
_LOGGER.debug(
"%s - Stopping underlying switch %s", self, self._heater_entity_id
)
data = {ATTR_ENTITY_ID: self._heater_entity_id} data = {ATTR_ENTITY_ID: self._heater_entity_id}
await self.hass.services.async_call( await self.hass.services.async_call(
HA_DOMAIN, SERVICE_TURN_OFF, data, context=self._context HA_DOMAIN, SERVICE_TURN_OFF, data, context=self._context
) )
else: else:
_LOGGER.debug(
"%s - Stopping underlying switch %s", self, self._climate_entity_id
)
data = {ATTR_ENTITY_ID: self._climate_entity_id} data = {ATTR_ENTITY_ID: self._climate_entity_id}
await self.hass.services.async_call( await self.hass.services.async_call(
HA_DOMAIN, SERVICE_TURN_OFF, data, context=self._context HA_DOMAIN, SERVICE_TURN_OFF, data, context=self._context
@@ -1443,11 +1595,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
self._device_power, self._device_power,
) )
ret = self._current_power + self._device_power >= self._current_power_max ret = self._current_power + self._device_power >= self._current_power_max
if ( if not self._overpowering_state and ret and not self._hvac_mode == HVACMode.OFF:
not self._overpowering_state
and ret
and not self._hvac_mode == HVAC_MODE_OFF
):
_LOGGER.warning( _LOGGER.warning(
"%s - overpowering is detected. Heater preset will be set to 'power'", "%s - overpowering is detected. Heater preset will be set to 'power'",
self, self,
@@ -1495,8 +1643,8 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
or delta_ext_temp > self._security_delay_min or delta_ext_temp > self._security_delay_min
) )
climate_cond: bool = self._is_over_climate and self.hvac_action not in [ climate_cond: bool = self._is_over_climate and self.hvac_action not in [
CURRENT_HVAC_COOL, HVACAction.COOLING,
CURRENT_HVAC_IDLE, HVACAction.IDLE,
] ]
switch_cond: bool = ( switch_cond: bool = (
not self._is_over_climate not self._is_over_climate
@@ -1534,7 +1682,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
self.save_hvac_mode() self.save_hvac_mode()
self.save_preset_mode() self.save_preset_mode()
await self._async_set_preset_mode_internal(PRESET_SECURITY) await self._async_set_preset_mode_internal(PRESET_SECURITY)
await self.async_set_hvac_mode(HVAC_MODE_OFF) await self.async_set_hvac_mode(HVACMode.OFF)
if ( if (
self._security_state self._security_state
@@ -1567,16 +1715,19 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
# Check overpowering condition # Check overpowering condition
overpowering: bool = await self.check_overpowering() overpowering: bool = await self.check_overpowering()
if overpowering: if overpowering:
_LOGGER.debug("%s - End of cycle (0)", self) _LOGGER.debug("%s - End of cycle (overpowering)", self)
return return
security: bool = await self.check_security() security: bool = await self.check_security()
if security: if security:
_LOGGER.debug("%s - End of cycle (1)", self) _LOGGER.debug("%s - End of cycle (security)", self)
return return
# Stop here if we are off # Stop here if we are off
if self._hvac_mode == HVAC_MODE_OFF: if self._hvac_mode == HVACMode.OFF:
_LOGGER.debug("%s - End of cycle (HVAC_MODE_OFF)", self)
if self._is_device_active:
await self._async_underlying_entity_turn_off()
return return
if not self._is_over_climate: if not self._is_over_climate:
@@ -1606,7 +1757,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
_LOGGER.debug("%s - End of cycle (2)", self) _LOGGER.debug("%s - End of cycle (2)", self)
return return
if self._hvac_mode == HVAC_MODE_HEAT and on_time_sec > 0: if self._hvac_mode == HVACMode.HEAT and on_time_sec > 0:
async def _turn_on_off_later( async def _turn_on_off_later(
on: bool, time, heater_action, next_cycle_action on: bool, time, heater_action, next_cycle_action
@@ -1616,6 +1767,12 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
self._async_cancel_cycle = None self._async_cancel_cycle = None
_LOGGER.debug("%s - Stopping cycle during calculation", self) _LOGGER.debug("%s - Stopping cycle during calculation", self)
if self._hvac_mode == HVACMode.OFF:
_LOGGER.debug("%s - End of cycle (HVAC_MODE_OFF - 2)", self)
if self._is_device_active:
await self._async_underlying_entity_turn_off()
return
if on: if on:
security = ( security = (
await self.check_security() await self.check_security()

View File

@@ -27,19 +27,19 @@ from homeassistant.helpers.entity_registry import (
RegistryEntry, RegistryEntry,
async_get, async_get,
) )
from homeassistant.components.climate.const import DOMAIN as CLIMATE_DOMAIN from homeassistant.components.climate import ClimateEntity, DOMAIN as CLIMATE_DOMAIN
from homeassistant.components.climate import ClimateEntity from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.components.switch.const import DOMAIN as SWITCH_DOMAIN
from homeassistant.components.input_boolean import ( from homeassistant.components.input_boolean import (
DOMAIN as INPUT_BOOLEAN_DOMAIN, DOMAIN as INPUT_BOOLEAN_DOMAIN,
) )
from homeassistant.components.sensor.const import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.input_number import ( from homeassistant.components.input_number import (
DOMAIN as INPUT_NUMBER_DOMAIN, DOMAIN as INPUT_NUMBER_DOMAIN,
) )
from homeassistant.components.person import DOMAIN as PERSON_DOMAIN from homeassistant.components.person import DOMAIN as PERSON_DOMAIN
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
from .const import ( from .const import (
@@ -167,6 +167,22 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
super().__init__() super().__init__()
_LOGGER.debug("CTOR BaseConfigFlow infos: %s", infos) _LOGGER.debug("CTOR BaseConfigFlow infos: %s", infos)
self._infos = infos self._infos = infos
is_empty: bool = not bool(infos)
# Fix features selection depending to infos
self._infos[CONF_USE_WINDOW_FEATURE] = (
is_empty or self._infos.get(CONF_WINDOW_SENSOR) is not None
)
self._infos[CONF_USE_MOTION_FEATURE] = (
is_empty or self._infos.get(CONF_MOTION_SENSOR) is not None
)
self._infos[CONF_USE_POWER_FEATURE] = is_empty or (
self._infos.get(CONF_POWER_SENSOR) is not None
and self._infos.get(CONF_MAX_POWER_SENSOR) is not None
)
self._infos[CONF_USE_PRESENCE_FEATURE] = (
is_empty or self._infos.get(CONF_PRESENCE_SENSOR) is not None
)
self.hass = async_get_hass() self.hass = async_get_hass()
ent_reg = async_get(hass=self.hass) ent_reg = async_get(hass=self.hass)
@@ -199,8 +215,8 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
_LOGGER.debug("Presence sensor !") _LOGGER.debug("Presence sensor !")
presence_sensors.append(k) presence_sensors.append(k)
# window sensor # window sensor and presence
if k.startswith(INPUT_BOOLEAN_DOMAIN): if k.startswith(INPUT_BOOLEAN_DOMAIN) or k.startswith(BINARY_SENSOR_DOMAIN):
_LOGGER.debug("Window or presence sensor !") _LOGGER.debug("Window or presence sensor !")
window_sensors.append(k) window_sensors.append(k)
presence_sensors.append(k) presence_sensors.append(k)
@@ -602,8 +618,18 @@ class VersatileThermostatOptionsFlowHandler(
"Into OptionsFlowHandler.async_step_presets user_input=%s", user_input "Into OptionsFlowHandler.async_step_presets user_input=%s", user_input
) )
next_step = self.async_step_advanced
if self._infos[CONF_USE_WINDOW_FEATURE]:
next_step = self.async_step_window
elif self._infos[CONF_USE_MOTION_FEATURE]:
next_step = self.async_step_motion
elif self._infos[CONF_USE_POWER_FEATURE]:
next_step = self.async_step_power
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step( return await self.generic_step(
"presets", self.STEP_PRESETS_DATA_SCHEMA, user_input, self.async_step_window "presets", self.STEP_PRESETS_DATA_SCHEMA, user_input, next_step
) )
async def async_step_window(self, user_input: dict | None = None) -> FlowResult: async def async_step_window(self, user_input: dict | None = None) -> FlowResult:
@@ -612,8 +638,15 @@ class VersatileThermostatOptionsFlowHandler(
"Into OptionsFlowHandler.async_step_window user_input=%s", user_input "Into OptionsFlowHandler.async_step_window user_input=%s", user_input
) )
next_step = self.async_step_advanced
if self._infos[CONF_USE_MOTION_FEATURE]:
next_step = self.async_step_motion
elif self._infos[CONF_USE_POWER_FEATURE]:
next_step = self.async_step_power
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step( return await self.generic_step(
"window", self.STEP_WINDOW_DATA_SCHEMA, user_input, self.async_step_motion "window", self.STEP_WINDOW_DATA_SCHEMA, user_input, next_step
) )
async def async_step_motion(self, user_input: dict | None = None) -> FlowResult: async def async_step_motion(self, user_input: dict | None = None) -> FlowResult:
@@ -622,8 +655,14 @@ class VersatileThermostatOptionsFlowHandler(
"Into OptionsFlowHandler.async_step_motion user_input=%s", user_input "Into OptionsFlowHandler.async_step_motion user_input=%s", user_input
) )
next_step = self.async_step_advanced
if self._infos[CONF_USE_POWER_FEATURE]:
next_step = self.async_step_power
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step( return await self.generic_step(
"motion", self.STEP_MOTION_DATA_SCHEMA, user_input, self.async_step_power "motion", self.STEP_MOTION_DATA_SCHEMA, user_input, next_step
) )
async def async_step_power(self, user_input: dict | None = None) -> FlowResult: async def async_step_power(self, user_input: dict | None = None) -> FlowResult:
@@ -632,11 +671,15 @@ class VersatileThermostatOptionsFlowHandler(
"Into OptionsFlowHandler.async_step_power user_input=%s", user_input "Into OptionsFlowHandler.async_step_power user_input=%s", user_input
) )
next_step = self.async_step_advanced
if self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step( return await self.generic_step(
"power", "power",
self.STEP_POWER_DATA_SCHEMA, self.STEP_POWER_DATA_SCHEMA,
user_input, user_input,
self.async_step_presence, next_step,
) )
async def async_step_presence(self, user_input: dict | None = None) -> FlowResult: async def async_step_presence(self, user_input: dict | None = None) -> FlowResult:
@@ -667,34 +710,20 @@ class VersatileThermostatOptionsFlowHandler(
async def async_end(self): async def async_end(self):
"""Finalization of the ConfigEntry creation""" """Finalization of the ConfigEntry creation"""
_LOGGER.debug( if not self._infos[CONF_USE_WINDOW_FEATURE]:
"ConfigFlow.async_finalize - updating entry with: %s", self._infos self._infos[CONF_WINDOW_SENSOR] = None
) if not self._infos[CONF_USE_MOTION_FEATURE]:
# Find eventual existing entity to update it self._infos[CONF_MOTION_SENSOR] = None
# removing entities from registry (they will be recreated) if not self._infos[CONF_USE_POWER_FEATURE]:
self._infos[CONF_POWER_SENSOR] = None
self._infos[CONF_MAX_POWER_SENSOR] = None
if not self._infos[CONF_USE_PRESENCE_FEATURE]:
self._infos[CONF_PRESENCE_SENSOR] = None
# No need to do that. Only the update_listener on __init__.py is necessary
# ent_reg = entity_registry.async_get(self.hass)
# for entry in entity_registry.async_entries_for_config_entry(
# ent_reg, self.config_entry.entry_id
# ):
# _LOGGER.info(
# "Removing entity %s due to configuration change", entry.entity_id
# )
# ent_reg.async_remove(entry.entity_id)
# _LOGGER.debug(
# "We have found entities to update: %s", self.config_entry.entry_id
# )
# await VersatileThermostat.update_entity(self.config_entry.entry_id, self._infos)
# for entity_id in reg_entities.values():
# ent_reg.async_remove(entity_id)
#
_LOGGER.info( _LOGGER.info(
"Recreating entry %s due to configuration change", "Recreating entry %s due to configuration change. New config is now: %s",
self.config_entry.entry_id, self.config_entry.entry_id,
self._infos,
) )
self.hass.config_entries.async_update_entry(self.config_entry, data=self._infos) self.hass.config_entries.async_update_entry(self.config_entry, data=self._infos)
return self.async_create_entry(title=None, data=None) return self.async_create_entry(title=None, data=None)

View File

@@ -93,14 +93,6 @@
} }
} }
}, },
"selectors": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat over a switch",
"thermostat_over_climate": "Thermostat over another thermostat"
}
}
},
"error": { "error": {
"unknown": "Unexpected error", "unknown": "Unexpected error",
"unknown_entity": "Unknown entity id" "unknown_entity": "Unknown entity id"
@@ -202,14 +194,6 @@
} }
} }
}, },
"selectors": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat over a switch",
"thermostat_over_climate": "Thermostat over another thermostat"
}
}
},
"error": { "error": {
"unknown": "Unexpected error", "unknown": "Unexpected error",
"unknown_entity": "Unknown entity id" "unknown_entity": "Unknown entity id"
@@ -217,5 +201,25 @@
"abort": { "abort": {
"already_configured": "Device is already configured" "already_configured": "Device is already configured"
} }
},
"selector": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat over a switch",
"thermostat_over_climate": "Thermostat over another thermostat"
}
}
},
"entity": {
"climate": {
"versatile_thermostat": {
"states_attributes": {
"preset_mode": {
"power": "Shedding",
"security": "Security"
}
}
}
}
} }
} }

View File

@@ -93,14 +93,6 @@
} }
} }
}, },
"selectors": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat over a switch",
"thermostat_over_climate": "Thermostat over another thermostat"
}
}
},
"error": { "error": {
"unknown": "Unexpected error", "unknown": "Unexpected error",
"unknown_entity": "Unknown entity id" "unknown_entity": "Unknown entity id"
@@ -202,14 +194,6 @@
} }
} }
}, },
"selectors": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat over a switch",
"thermostat_over_climate": "Thermostat over another thermostat"
}
}
},
"error": { "error": {
"unknown": "Unexpected error", "unknown": "Unexpected error",
"unknown_entity": "Unknown entity id" "unknown_entity": "Unknown entity id"
@@ -217,5 +201,25 @@
"abort": { "abort": {
"already_configured": "Device is already configured" "already_configured": "Device is already configured"
} }
},
"selector": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat over a switch",
"thermostat_over_climate": "Thermostat over another thermostat"
}
}
},
"entity": {
"climate": {
"versatile_thermostat": {
"states_attributes": {
"preset_mode": {
"power": "Shedding",
"security": "Security"
}
}
}
}
} }
} }

View File

@@ -92,14 +92,6 @@
} }
} }
}, },
"selectors": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat sur un switch",
"thermostat_over_climate": "Thermostat sur un autre thermostat"
}
}
},
"error": { "error": {
"unknown": "Erreur inattendue", "unknown": "Erreur inattendue",
"unknown_entity": "entity id inconnu" "unknown_entity": "entity id inconnu"
@@ -202,14 +194,6 @@
} }
} }
}, },
"selectors": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat sur un switch",
"thermostat_over_climate": "Thermostat sur un autre thermostat"
}
}
},
"error": { "error": {
"unknown": "Erreur inattendue", "unknown": "Erreur inattendue",
"unknown_entity": "entity id inconnu" "unknown_entity": "entity id inconnu"
@@ -217,5 +201,25 @@
"abort": { "abort": {
"already_configured": "Le device est déjà configuré" "already_configured": "Le device est déjà configuré"
} }
},
"selector": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat sur un switch",
"thermostat_over_climate": "Thermostat sur un autre thermostat"
}
}
},
"entity": {
"climate": {
"versatile_thermostat": {
"states_attributes": {
"preset_mode": {
"power": "Délestage",
"security": "Sécurité"
}
}
}
}
} }
} }