Issue #113 - Add multi thermostat over climate
This commit is contained in:
@@ -72,6 +72,18 @@ input_boolean:
|
||||
fake_heater_4switch4:
|
||||
name: Heater (multiswitch4)
|
||||
icon: mdi:radiator
|
||||
fake_heater_4climate1:
|
||||
name: Heater (multiclimate1)
|
||||
icon: mdi:radiator
|
||||
fake_heater_4climate2:
|
||||
name: Heater (multiclimate2)
|
||||
icon: mdi:radiator
|
||||
fake_heater_4climate3:
|
||||
name: Heater (multiclimate3)
|
||||
icon: mdi:radiator
|
||||
fake_heater_4climate4:
|
||||
name: Heater (multiclimate4)
|
||||
icon: mdi:radiator
|
||||
# input_boolean to simulate the motion sensor entity. Only for development environment.
|
||||
fake_motion_sensor1:
|
||||
name: Motion Sensor 1
|
||||
@@ -99,20 +111,20 @@ climate:
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat5
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
name: Underlying thermostat 4-1
|
||||
heater: input_boolean.fake_heater_4climate1
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat6
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
name: Underlying thermostat 4-2
|
||||
heater: input_boolean.fake_heater_4climate2
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat7
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
name: Underlying thermostat 4-3
|
||||
heater: input_boolean.fake_heater_4climate3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat8
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
name: Underlying thermostat 4-4
|
||||
heater: input_boolean.fake_heater_4climate4
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat9
|
||||
|
||||
@@ -129,6 +129,9 @@ from .const import (
|
||||
# CONF_THERMOSTAT_SWITCH,
|
||||
CONF_THERMOSTAT_CLIMATE,
|
||||
CONF_CLIMATE,
|
||||
CONF_CLIMATE_2,
|
||||
CONF_CLIMATE_3,
|
||||
CONF_CLIMATE_4,
|
||||
CONF_AC_MODE,
|
||||
UnknownEntity,
|
||||
EventType,
|
||||
@@ -328,16 +331,19 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
self._cycle_min = entry_infos.get(CONF_CYCLE_MIN)
|
||||
|
||||
# Initialize underlying entities
|
||||
self._underlyings = []
|
||||
self._thermostat_type = entry_infos.get(CONF_THERMOSTAT_TYPE)
|
||||
if self._thermostat_type == CONF_THERMOSTAT_CLIMATE:
|
||||
self._is_over_climate = True
|
||||
self._underlyings.append(
|
||||
UnderlyingClimate(
|
||||
hass=self._hass,
|
||||
thermostat=self,
|
||||
climate_entity_id=entry_infos.get(CONF_CLIMATE),
|
||||
)
|
||||
)
|
||||
for climate in [CONF_CLIMATE, CONF_CLIMATE_2, CONF_CLIMATE_3, CONF_CLIMATE_4]:
|
||||
if entry_infos.get(climate):
|
||||
self._underlyings.append(
|
||||
UnderlyingClimate(
|
||||
hass=self._hass,
|
||||
thermostat=self,
|
||||
climate_entity_id=entry_infos.get(climate),
|
||||
)
|
||||
)
|
||||
else:
|
||||
lst_switches = [entry_infos.get(CONF_HEATER)]
|
||||
if entry_infos.get(CONF_HEATER_2):
|
||||
@@ -348,7 +354,6 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
lst_switches.append(entry_infos.get(CONF_HEATER_4))
|
||||
|
||||
delta_cycle = self._cycle_min * 60 / len(lst_switches)
|
||||
self._underlyings = []
|
||||
for idx, switch in enumerate(lst_switches):
|
||||
self._underlyings.append(
|
||||
UnderlyingSwitch(
|
||||
@@ -1582,6 +1587,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
if not new_state:
|
||||
return
|
||||
|
||||
changes = False
|
||||
new_hvac_mode = new_state.state
|
||||
|
||||
old_state = event.data.get("old_state")
|
||||
@@ -1597,9 +1603,9 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
)
|
||||
|
||||
# Issue 99 - some AC turn hvac_mode=cool and hvac_action=idle when sending a HVACMode_OFF command
|
||||
if self._hvac_mode == HVACMode.OFF and new_hvac_action == HVACAction.IDLE:
|
||||
_LOGGER.debug("The underlying switch to idle instead of OFF. We will consider it as OFF")
|
||||
new_hvac_mode = HVACMode.OFF
|
||||
#if self._hvac_mode == HVACMode.OFF and new_hvac_mode == HVACMode.COOL and new_hvac_action == HVACAction.IDLE:
|
||||
# _LOGGER.debug("The underlying switch to idle instead of OFF. We will consider it as OFF")
|
||||
# new_hvac_mode = HVACMode.OFF
|
||||
|
||||
_LOGGER.info(
|
||||
"%s - Underlying climate changed. Event.new_hvac_mode is %s, current_hvac_mode=%s, new_hvac_action=%s, old_hvac_action=%s",
|
||||
@@ -1619,8 +1625,13 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
HVACMode.AUTO,
|
||||
HVACMode.FAN_ONLY,
|
||||
None
|
||||
]:
|
||||
] and self._hvac_mode != new_hvac_mode:
|
||||
changes = True
|
||||
self._hvac_mode = new_hvac_mode
|
||||
# Do not try to update all underlying state, else we will have a loop
|
||||
if self._is_over_climate:
|
||||
for under in self._underlyings:
|
||||
await under.set_hvac_mode(new_hvac_mode)
|
||||
|
||||
# Interpretation of hvac
|
||||
HVAC_ACTION_ON = [ # pylint: disable=invalid-name
|
||||
@@ -1638,6 +1649,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
self,
|
||||
self._underlying_climate_start_hvac_action_date.isoformat(),
|
||||
)
|
||||
changes = True
|
||||
|
||||
if old_hvac_action in HVAC_ACTION_ON and new_hvac_action not in HVAC_ACTION_ON:
|
||||
stop_power_date = self.get_last_updated_date_or_now(new_state)
|
||||
@@ -1658,14 +1670,20 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
stop_power_date.isoformat(),
|
||||
self._underlying_climate_delta_t,
|
||||
)
|
||||
changes = True
|
||||
|
||||
# Manage new target temperature set
|
||||
if self._is_over_climate and new_state.attributes and (new_target_temp := new_state.attributes.get("temperature")) and new_target_temp != self.target_temperature:
|
||||
_LOGGER.info("%s - Target temp have change to %s", self, new_target_temp)
|
||||
await self.async_set_temperature(temperature = new_target_temp)
|
||||
if not changes:
|
||||
# try to manage new target temperature set if state
|
||||
_LOGGER.debug("Do temperature check. temperature is %s, new_state.attributes is %s", self.target_temperature, new_state.attributes)
|
||||
if self._is_over_climate and new_state.attributes and (new_target_temp := new_state.attributes.get("temperature")) and new_target_temp != self.target_temperature:
|
||||
_LOGGER.info("%s - Target temp have change to %s", self, new_target_temp)
|
||||
await self.async_set_temperature(temperature = new_target_temp)
|
||||
changes = True
|
||||
|
||||
self.update_custom_attributes()
|
||||
await self._async_control_heating()
|
||||
if changes:
|
||||
self.async_write_ha_state()
|
||||
self.update_custom_attributes()
|
||||
await self._async_control_heating()
|
||||
|
||||
@callback
|
||||
async def _async_update_temp(self, state: State):
|
||||
@@ -2364,9 +2382,19 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
"window_auto_max_duration": self._window_auto_max_duration,
|
||||
}
|
||||
if self._is_over_climate:
|
||||
self._attr_extra_state_attributes["underlying_climate"] = self._underlyings[
|
||||
self._attr_extra_state_attributes["underlying_climate_1"] = self._underlyings[
|
||||
0
|
||||
].entity_id
|
||||
self._attr_extra_state_attributes["underlying_climate_1"] = self._underlyings[
|
||||
1
|
||||
].entity_id if len(self._underlyings) > 1 else None
|
||||
self._attr_extra_state_attributes["underlying_climate_2"] = self._underlyings[
|
||||
2
|
||||
].entity_id if len(self._underlyings) > 2 else None
|
||||
self._attr_extra_state_attributes["underlying_climate_3"] = self._underlyings[
|
||||
3
|
||||
].entity_id if len(self._underlyings) > 3 else None
|
||||
|
||||
self._attr_extra_state_attributes[
|
||||
"start_hvac_action_date"
|
||||
] = self._underlying_climate_start_hvac_action_date
|
||||
|
||||
@@ -81,6 +81,9 @@ from .const import (
|
||||
CONF_THERMOSTAT_TYPE,
|
||||
CONF_THERMOSTAT_SWITCH,
|
||||
CONF_CLIMATE,
|
||||
CONF_CLIMATE_2,
|
||||
CONF_CLIMATE_3,
|
||||
CONF_CLIMATE_4,
|
||||
CONF_USE_WINDOW_FEATURE,
|
||||
CONF_USE_MOTION_FEATURE,
|
||||
CONF_USE_PRESENCE_FEATURE,
|
||||
@@ -231,6 +234,15 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
||||
vol.Required(CONF_CLIMATE): selector.EntitySelector(
|
||||
selector.EntitySelectorConfig(domain=CLIMATE_DOMAIN),
|
||||
),
|
||||
vol.Optional(CONF_CLIMATE_2): selector.EntitySelector(
|
||||
selector.EntitySelectorConfig(domain=CLIMATE_DOMAIN),
|
||||
),
|
||||
vol.Optional(CONF_CLIMATE_3): selector.EntitySelector(
|
||||
selector.EntitySelectorConfig(domain=CLIMATE_DOMAIN),
|
||||
),
|
||||
vol.Optional(CONF_CLIMATE_4): selector.EntitySelector(
|
||||
selector.EntitySelectorConfig(domain=CLIMATE_DOMAIN),
|
||||
),
|
||||
vol.Optional(CONF_AC_MODE, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -65,6 +65,9 @@ CONF_THERMOSTAT_TYPE = "thermostat_type"
|
||||
CONF_THERMOSTAT_SWITCH = "thermostat_over_switch"
|
||||
CONF_THERMOSTAT_CLIMATE = "thermostat_over_climate"
|
||||
CONF_CLIMATE = "climate_entity_id"
|
||||
CONF_CLIMATE_2 = "climate_entity2_id"
|
||||
CONF_CLIMATE_3 = "climate_entity3_id"
|
||||
CONF_CLIMATE_4 = "climate_entity4_id"
|
||||
CONF_USE_WINDOW_FEATURE = "use_window_feature"
|
||||
CONF_USE_MOTION_FEATURE = "use_motion_feature"
|
||||
CONF_USE_PRESENCE_FEATURE = "use_presence_feature"
|
||||
@@ -130,6 +133,9 @@ ALL_CONF = (
|
||||
[
|
||||
CONF_NAME,
|
||||
CONF_HEATER,
|
||||
CONF_HEATER_2,
|
||||
CONF_HEATER_3,
|
||||
CONF_HEATER_4,
|
||||
CONF_TEMP_SENSOR,
|
||||
CONF_EXTERNAL_TEMP_SENSOR,
|
||||
CONF_POWER_SENSOR,
|
||||
@@ -159,6 +165,9 @@ ALL_CONF = (
|
||||
CONF_THERMOSTAT_SWITCH,
|
||||
CONF_THERMOSTAT_CLIMATE,
|
||||
CONF_CLIMATE,
|
||||
CONF_CLIMATE_2,
|
||||
CONF_CLIMATE_3,
|
||||
CONF_CLIMATE_4,
|
||||
CONF_USE_WINDOW_FEATURE,
|
||||
CONF_USE_MOTION_FEATURE,
|
||||
CONF_USE_PRESENCE_FEATURE,
|
||||
|
||||
@@ -26,11 +26,14 @@
|
||||
"description": "Linked entities attributes",
|
||||
"data": {
|
||||
"heater_entity_id": "Heater switch",
|
||||
"heater_entity2_id": "2nd Heater switch",
|
||||
"heater_entity3_id": "3rd Heater switch",
|
||||
"heater_entity4_id": "4th Heater switch",
|
||||
"heater_entity2_id": "2nd heater switch",
|
||||
"heater_entity3_id": "3rd heater switch",
|
||||
"heater_entity4_id": "4th heater switch",
|
||||
"proportional_function": "Algorithm",
|
||||
"climate_entity_id": "Underlying thermostat",
|
||||
"climate_entity_id": "Underlying climate",
|
||||
"climate_entity2_id": "2nd underlying climate",
|
||||
"climate_entity3_id": "3rd underlying climate",
|
||||
"climate_entity4_id": "4th underlying climate",
|
||||
"ac_mode": "AC mode"
|
||||
},
|
||||
"data_description": {
|
||||
@@ -40,6 +43,9 @@
|
||||
"heater_entity4_id": "Optional 4th Heater entity id. Leave empty if not used",
|
||||
"proportional_function": "Algorithm to use (TPI is the only one for now)",
|
||||
"climate_entity_id": "Underlying climate entity id",
|
||||
"climate_entity2_id": "2nd underlying climate entity id",
|
||||
"climate_entity3_id": "3rd underlying climate entity id",
|
||||
"climate_entity4_id": "4th underlying climate entity id",
|
||||
"ac_mode": "Use the Air Conditioning (AC) mode"
|
||||
}
|
||||
},
|
||||
@@ -170,6 +176,9 @@
|
||||
"heater_entity4_id": "4th Heater switch",
|
||||
"proportional_function": "Algorithm",
|
||||
"climate_entity_id": "Underlying thermostat",
|
||||
"climate_entity2_id": "2nd underlying climate",
|
||||
"climate_entity3_id": "3rd underlying climate",
|
||||
"climate_entity4_id": "4th underlying climate",
|
||||
"ac_mode": "AC mode"
|
||||
},
|
||||
"data_description": {
|
||||
@@ -179,6 +188,9 @@
|
||||
"heater_entity4_id": "Optional 4th Heater entity id. Leave empty if not used",
|
||||
"proportional_function": "Algorithm to use (TPI is the only one for now)",
|
||||
"climate_entity_id": "Underlying climate entity id",
|
||||
"climate_entity2_id": "2nd underlying climate entity id",
|
||||
"climate_entity3_id": "3rd underlying climate entity id",
|
||||
"climate_entity4_id": "4th underlying climate entity id",
|
||||
"ac_mode": "Use the Air Conditioning (AC) mode"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -26,11 +26,14 @@
|
||||
"description": "Linked entities attributes",
|
||||
"data": {
|
||||
"heater_entity_id": "Heater switch",
|
||||
"heater_entity2_id": "2nd Heater switch",
|
||||
"heater_entity3_id": "3rd Heater switch",
|
||||
"heater_entity4_id": "4th Heater switch",
|
||||
"heater_entity2_id": "2nd heater switch",
|
||||
"heater_entity3_id": "3rd heater switch",
|
||||
"heater_entity4_id": "4th heater switch",
|
||||
"proportional_function": "Algorithm",
|
||||
"climate_entity_id": "Underlying thermostat",
|
||||
"climate_entity_id": "Underlying climate",
|
||||
"climate_entity2_id": "2nd underlying climate",
|
||||
"climate_entity3_id": "3rd underlying climate",
|
||||
"climate_entity4_id": "4th underlying climate",
|
||||
"ac_mode": "AC mode"
|
||||
},
|
||||
"data_description": {
|
||||
@@ -40,6 +43,9 @@
|
||||
"heater_entity4_id": "Optional 4th Heater entity id. Leave empty if not used",
|
||||
"proportional_function": "Algorithm to use (TPI is the only one for now)",
|
||||
"climate_entity_id": "Underlying climate entity id",
|
||||
"climate_entity2_id": "2nd underlying climate entity id",
|
||||
"climate_entity3_id": "3rd underlying climate entity id",
|
||||
"climate_entity4_id": "4th underlying climate entity id",
|
||||
"ac_mode": "Use the Air Conditioning (AC) mode"
|
||||
}
|
||||
},
|
||||
@@ -170,6 +176,9 @@
|
||||
"heater_entity4_id": "4th Heater switch",
|
||||
"proportional_function": "Algorithm",
|
||||
"climate_entity_id": "Underlying thermostat",
|
||||
"climate_entity2_id": "2nd underlying climate",
|
||||
"climate_entity3_id": "3rd underlying climate",
|
||||
"climate_entity4_id": "4th underlying climate",
|
||||
"ac_mode": "AC mode"
|
||||
},
|
||||
"data_description": {
|
||||
@@ -179,6 +188,9 @@
|
||||
"heater_entity4_id": "Optional 4th Heater entity id. Leave empty if not used",
|
||||
"proportional_function": "Algorithm to use (TPI is the only one for now)",
|
||||
"climate_entity_id": "Underlying climate entity id",
|
||||
"climate_entity2_id": "2nd underlying climate entity id",
|
||||
"climate_entity3_id": "3rd underlying climate entity id",
|
||||
"climate_entity4_id": "4th underlying climate entity id",
|
||||
"ac_mode": "Use the Air Conditioning (AC) mode"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
"heater_entity4_id": "4ème radiateur",
|
||||
"proportional_function": "Algorithme",
|
||||
"climate_entity_id": "Thermostat sous-jacent",
|
||||
"climate_entity2_id": "2ème thermostat sous-jacent",
|
||||
"climate_entity3_id": "3ème thermostat sous-jacent",
|
||||
"climate_entity4_id": "4ème thermostat sous-jacent",
|
||||
"ac_mode": "AC mode ?"
|
||||
},
|
||||
"data_description": {
|
||||
@@ -39,6 +42,9 @@
|
||||
"heater_entity4_id": "Optionnel entity id du 4ème radiateur",
|
||||
"proportional_function": "Algorithme à utiliser (Seul TPI est disponible pour l'instant)",
|
||||
"climate_entity_id": "Entity id du thermostat sous-jacent",
|
||||
"climate_entity2_id": "Entity id du 2ème thermostat sous-jacent",
|
||||
"climate_entity3_id": "Entity id du 3ème thermostat sous-jacent",
|
||||
"climate_entity4_id": "Entity id du 4ème thermostat sous-jacent",
|
||||
"ac_mode": "Utilisation du mode Air Conditionné (AC)"
|
||||
}
|
||||
},
|
||||
@@ -170,6 +176,9 @@
|
||||
"heater_entity4_id": "4ème radiateur",
|
||||
"proportional_function": "Algorithme",
|
||||
"climate_entity_id": "Thermostat sous-jacent",
|
||||
"climate_entity2_id": "2ème thermostat sous-jacent",
|
||||
"climate_entity3_id": "3ème thermostat sous-jacent",
|
||||
"climate_entity4_id": "4ème thermostat sous-jacent",
|
||||
"ac_mode": "AC mode ?"
|
||||
},
|
||||
"data_description": {
|
||||
@@ -179,6 +188,9 @@
|
||||
"heater_entity4_id": "Optionnel entity id du 4ème radiateur",
|
||||
"proportional_function": "Algorithme à utiliser (Seul TPI est disponible pour l'instant)",
|
||||
"climate_entity_id": "Entity id du thermostat sous-jacent",
|
||||
"climate_entity2_id": "Entity id du 2ème thermostat sous-jacent",
|
||||
"climate_entity3_id": "Entity id du 3ème thermostat sous-jacent",
|
||||
"climate_entity4_id": "Entity id du 4ème thermostat sous-jacent",
|
||||
"ac_mode": "Utilisation du mode Air Conditionné (AC)"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
"heater_entity4_id": "Quarto riscaldatore",
|
||||
"proportional_function": "Algoritmo",
|
||||
"climate_entity_id": "Termostato sottostante",
|
||||
"climate_entity2_id": "Secundo termostato sottostante",
|
||||
"climate_entity3_id": "Terzo termostato sottostante",
|
||||
"climate_entity4_id": "Quarto termostato sottostante",
|
||||
"ac_mode": "AC mode ?"
|
||||
},
|
||||
"data_description": {
|
||||
@@ -40,6 +43,9 @@
|
||||
"heater_entity4_id": "Entity id del quarto riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
||||
"proportional_function": "Algoritmo da utilizzare (il TPI per adesso è l'unico)",
|
||||
"climate_entity_id": "Entity id del termostato sottostante",
|
||||
"climate_entity2_id": "Entity id del secundo termostato sottostante",
|
||||
"climate_entity3_id": "Entity id del terzo termostato sottostante",
|
||||
"climate_entity4_id": "Entity id del quarto termostato sottostante",
|
||||
"ac_mode": "Utilizzare la modalità AC (Air Conditioned) ?"
|
||||
}
|
||||
},
|
||||
@@ -170,6 +176,9 @@
|
||||
"heater_entity4_id": "Quarto interruttore riscaldatore",
|
||||
"proportional_function": "Algoritmo",
|
||||
"climate_entity_id": "Termostato sottostante",
|
||||
"climate_entity2_id": "Secundo termostato sottostante",
|
||||
"climate_entity3_id": "Terzo termostato sottostante",
|
||||
"climate_entity4_id": "Quarto termostato sottostante",
|
||||
"ac_mode": "AC mode ?"
|
||||
},
|
||||
"data_description": {
|
||||
@@ -179,6 +188,9 @@
|
||||
"heater_entity4_id": "Entity id del quarto riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
||||
"proportional_function": "Algoritmo da utilizzare (il TPI per adesso è l'unico)",
|
||||
"climate_entity_id": "Entity id del termostato sottostante",
|
||||
"climate_entity2_id": "Entity id del secundo termostato sottostante",
|
||||
"climate_entity3_id": "Entity id del terzo termostato sottostante",
|
||||
"climate_entity4_id": "Entity id del quarto termostato sottostante",
|
||||
"ac_mode": "Utilizzare la modalità AC (Air Conditioned) ?"
|
||||
}
|
||||
},
|
||||
@@ -301,4 +313,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user