Follow real AtlanticPassAPCZoneControlZone physical mode on Overkiz (HEAT, COOL or HEAT_COOL) (#111830)
* Support HEAT_COOL when mode is Auto on overkiz AtlanticPassAPCZoneControlZone * Refactor ZoneControlZone to simplify usic by only using a single hvac mode * Fix linting issues * Makes more sense to use halves there * Fix PR feedbackpull/114764/head
parent
612988cf3e
commit
b8a2c14813
|
@ -7,6 +7,7 @@ from typing import cast
|
|||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import HomeAssistantOverkizData
|
||||
|
@ -27,15 +28,16 @@ async def async_setup_entry(
|
|||
"""Set up the Overkiz climate from a config entry."""
|
||||
data: HomeAssistantOverkizData = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
async_add_entities(
|
||||
# Match devices based on the widget.
|
||||
entities_based_on_widget: list[Entity] = [
|
||||
WIDGET_TO_CLIMATE_ENTITY[device.widget](device.device_url, data.coordinator)
|
||||
for device in data.platforms[Platform.CLIMATE]
|
||||
if device.widget in WIDGET_TO_CLIMATE_ENTITY
|
||||
)
|
||||
]
|
||||
|
||||
# Match devices based on the widget and controllableName
|
||||
# This is for example used for Atlantic APC, where devices with different functionality share the same uiClass and widget.
|
||||
async_add_entities(
|
||||
# Match devices based on the widget and controllableName.
|
||||
# ie Atlantic APC
|
||||
entities_based_on_widget_and_controllable: list[Entity] = [
|
||||
WIDGET_AND_CONTROLLABLE_TO_CLIMATE_ENTITY[device.widget][
|
||||
cast(Controllable, device.controllable_name)
|
||||
](device.device_url, data.coordinator)
|
||||
|
@ -43,14 +45,21 @@ async def async_setup_entry(
|
|||
if device.widget in WIDGET_AND_CONTROLLABLE_TO_CLIMATE_ENTITY
|
||||
and device.controllable_name
|
||||
in WIDGET_AND_CONTROLLABLE_TO_CLIMATE_ENTITY[device.widget]
|
||||
)
|
||||
]
|
||||
|
||||
# Hitachi Air To Air Heat Pumps
|
||||
async_add_entities(
|
||||
# Match devices based on the widget and protocol.
|
||||
# #ie Hitachi Air To Air Heat Pumps
|
||||
entities_based_on_widget_and_protocol: list[Entity] = [
|
||||
WIDGET_AND_PROTOCOL_TO_CLIMATE_ENTITY[device.widget][device.protocol](
|
||||
device.device_url, data.coordinator
|
||||
)
|
||||
for device in data.platforms[Platform.CLIMATE]
|
||||
if device.widget in WIDGET_AND_PROTOCOL_TO_CLIMATE_ENTITY
|
||||
and device.protocol in WIDGET_AND_PROTOCOL_TO_CLIMATE_ENTITY[device.widget]
|
||||
]
|
||||
|
||||
async_add_entities(
|
||||
entities_based_on_widget
|
||||
+ entities_based_on_widget_and_controllable
|
||||
+ entities_based_on_widget_and_protocol
|
||||
)
|
||||
|
|
|
@ -159,7 +159,7 @@ class AtlanticPassAPCHeatingZone(OverkizEntity, ClimateEntity):
|
|||
await self.async_set_heating_mode(PRESET_MODES_TO_OVERKIZ[preset_mode])
|
||||
|
||||
@property
|
||||
def preset_mode(self) -> str:
|
||||
def preset_mode(self) -> str | None:
|
||||
"""Return the current preset mode, e.g., home, away, temp."""
|
||||
heating_mode = cast(
|
||||
str, self.executor.select_state(OverkizState.IO_PASS_APC_HEATING_MODE)
|
||||
|
@ -179,7 +179,7 @@ class AtlanticPassAPCHeatingZone(OverkizEntity, ClimateEntity):
|
|||
return OVERKIZ_TO_PRESET_MODES[heating_mode]
|
||||
|
||||
@property
|
||||
def target_temperature(self) -> float:
|
||||
def target_temperature(self) -> float | None:
|
||||
"""Return hvac target temperature."""
|
||||
current_heating_profile = self.current_heating_profile
|
||||
if current_heating_profile in OVERKIZ_TEMPERATURE_STATE_BY_PROFILE:
|
||||
|
|
|
@ -3,16 +3,24 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from asyncio import sleep
|
||||
from functools import cached_property
|
||||
from typing import Any, cast
|
||||
|
||||
from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState
|
||||
|
||||
from homeassistant.components.climate import PRESET_NONE, HVACMode
|
||||
from homeassistant.const import ATTR_TEMPERATURE
|
||||
from homeassistant.components.climate import (
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
PRESET_NONE,
|
||||
ClimateEntityFeature,
|
||||
HVACAction,
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_HALVES
|
||||
|
||||
from ..coordinator import OverkizDataUpdateCoordinator
|
||||
from ..executor import OverkizExecutor
|
||||
from .atlantic_pass_apc_heating_zone import AtlanticPassAPCHeatingZone
|
||||
from .atlantic_pass_apc_zone_control import OVERKIZ_TO_HVAC_MODE
|
||||
|
||||
PRESET_SCHEDULE = "schedule"
|
||||
PRESET_MANUAL = "manual"
|
||||
|
@ -24,32 +32,127 @@ OVERKIZ_MODE_TO_PRESET_MODES: dict[str, str] = {
|
|||
|
||||
PRESET_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_MODE_TO_PRESET_MODES.items()}
|
||||
|
||||
TEMPERATURE_ZONECONTROL_DEVICE_INDEX = 20
|
||||
# Maps the HVAC current ZoneControl system operating mode.
|
||||
OVERKIZ_TO_HVAC_ACTION: dict[str, HVACAction] = {
|
||||
OverkizCommandParam.COOLING: HVACAction.COOLING,
|
||||
OverkizCommandParam.DRYING: HVACAction.DRYING,
|
||||
OverkizCommandParam.HEATING: HVACAction.HEATING,
|
||||
# There is no known way to differentiate OFF from Idle.
|
||||
OverkizCommandParam.STOP: HVACAction.OFF,
|
||||
}
|
||||
|
||||
HVAC_ACTION_TO_OVERKIZ_PROFILE_STATE: dict[HVACAction, OverkizState] = {
|
||||
HVACAction.COOLING: OverkizState.IO_PASS_APC_COOLING_PROFILE,
|
||||
HVACAction.HEATING: OverkizState.IO_PASS_APC_HEATING_PROFILE,
|
||||
}
|
||||
|
||||
HVAC_ACTION_TO_OVERKIZ_MODE_STATE: dict[HVACAction, OverkizState] = {
|
||||
HVACAction.COOLING: OverkizState.IO_PASS_APC_COOLING_MODE,
|
||||
HVACAction.HEATING: OverkizState.IO_PASS_APC_HEATING_MODE,
|
||||
}
|
||||
|
||||
TEMPERATURE_ZONECONTROL_DEVICE_INDEX = 1
|
||||
|
||||
SUPPORTED_FEATURES: ClimateEntityFeature = (
|
||||
ClimateEntityFeature.PRESET_MODE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
)
|
||||
|
||||
OVERKIZ_THERMAL_CONFIGURATION_TO_HVAC_MODE: dict[
|
||||
OverkizCommandParam, tuple[HVACMode, ClimateEntityFeature]
|
||||
] = {
|
||||
OverkizCommandParam.COOLING: (
|
||||
HVACMode.COOL,
|
||||
SUPPORTED_FEATURES | ClimateEntityFeature.TARGET_TEMPERATURE,
|
||||
),
|
||||
OverkizCommandParam.HEATING: (
|
||||
HVACMode.HEAT,
|
||||
SUPPORTED_FEATURES | ClimateEntityFeature.TARGET_TEMPERATURE,
|
||||
),
|
||||
OverkizCommandParam.HEATING_AND_COOLING: (
|
||||
HVACMode.HEAT_COOL,
|
||||
SUPPORTED_FEATURES | ClimateEntityFeature.TARGET_TEMPERATURE_RANGE,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
# Those device depends on a main probe that choose the operating mode (heating, cooling, ...)
|
||||
# Those device depends on a main probe that choose the operating mode (heating, cooling, ...).
|
||||
class AtlanticPassAPCZoneControlZone(AtlanticPassAPCHeatingZone):
|
||||
"""Representation of Atlantic Pass APC Heating And Cooling Zone Control."""
|
||||
|
||||
_attr_target_temperature_step = PRECISION_HALVES
|
||||
|
||||
def __init__(
|
||||
self, device_url: str, coordinator: OverkizDataUpdateCoordinator
|
||||
) -> None:
|
||||
"""Init method."""
|
||||
super().__init__(device_url, coordinator)
|
||||
|
||||
# There is less supported functions, because they depend on the ZoneControl.
|
||||
if not self.is_using_derogated_temperature_fallback:
|
||||
# Modes are not configurable, they will follow current HVAC Mode of Zone Control.
|
||||
self._attr_hvac_modes = []
|
||||
# When using derogated temperature, we fallback to legacy behavior.
|
||||
if self.is_using_derogated_temperature_fallback:
|
||||
return
|
||||
|
||||
# Those are available and tested presets on Shogun.
|
||||
self._attr_preset_modes = [*PRESET_MODES_TO_OVERKIZ]
|
||||
self._attr_hvac_modes = []
|
||||
self._attr_supported_features = ClimateEntityFeature(0)
|
||||
|
||||
# Modes depends on device capabilities.
|
||||
if (thermal_configuration := self.thermal_configuration) is not None:
|
||||
(
|
||||
device_hvac_mode,
|
||||
climate_entity_feature,
|
||||
) = thermal_configuration
|
||||
self._attr_hvac_modes = [device_hvac_mode, HVACMode.OFF]
|
||||
self._attr_supported_features = climate_entity_feature
|
||||
|
||||
# Those are available and tested presets on Shogun.
|
||||
self._attr_preset_modes = [*PRESET_MODES_TO_OVERKIZ]
|
||||
|
||||
# Those APC Heating and Cooling probes depends on the zone control device (main probe).
|
||||
# Only the base device (#1) can be used to get/set some states.
|
||||
# Like to retrieve and set the current operating mode (heating, cooling, drying, off).
|
||||
self.zone_control_device = self.executor.linked_device(
|
||||
TEMPERATURE_ZONECONTROL_DEVICE_INDEX
|
||||
|
||||
self.zone_control_executor: OverkizExecutor | None = None
|
||||
|
||||
if (
|
||||
zone_control_device := self.executor.linked_device(
|
||||
TEMPERATURE_ZONECONTROL_DEVICE_INDEX
|
||||
)
|
||||
) is not None:
|
||||
self.zone_control_executor = OverkizExecutor(
|
||||
zone_control_device.device_url,
|
||||
coordinator,
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def thermal_configuration(self) -> tuple[HVACMode, ClimateEntityFeature] | None:
|
||||
"""Retrieve thermal configuration for this devices."""
|
||||
|
||||
if (
|
||||
(
|
||||
state_thermal_configuration := cast(
|
||||
OverkizCommandParam | None,
|
||||
self.executor.select_state(OverkizState.CORE_THERMAL_CONFIGURATION),
|
||||
)
|
||||
)
|
||||
is not None
|
||||
and state_thermal_configuration
|
||||
in OVERKIZ_THERMAL_CONFIGURATION_TO_HVAC_MODE
|
||||
):
|
||||
return OVERKIZ_THERMAL_CONFIGURATION_TO_HVAC_MODE[
|
||||
state_thermal_configuration
|
||||
]
|
||||
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def device_hvac_mode(self) -> HVACMode | None:
|
||||
"""ZoneControlZone device has a single possible mode."""
|
||||
|
||||
return (
|
||||
None
|
||||
if self.thermal_configuration is None
|
||||
else self.thermal_configuration[0]
|
||||
)
|
||||
|
||||
@property
|
||||
|
@ -61,21 +164,37 @@ class AtlanticPassAPCZoneControlZone(AtlanticPassAPCHeatingZone):
|
|||
)
|
||||
|
||||
@property
|
||||
def zone_control_hvac_mode(self) -> HVACMode:
|
||||
def zone_control_hvac_action(self) -> HVACAction:
|
||||
"""Return hvac operation ie. heat, cool, dry, off mode."""
|
||||
|
||||
if (
|
||||
self.zone_control_device is not None
|
||||
and (
|
||||
state := self.zone_control_device.states[
|
||||
if self.zone_control_executor is not None and (
|
||||
(
|
||||
state := self.zone_control_executor.select_state(
|
||||
OverkizState.IO_PASS_APC_OPERATING_MODE
|
||||
]
|
||||
)
|
||||
)
|
||||
is not None
|
||||
and (value := state.value_as_str) is not None
|
||||
):
|
||||
return OVERKIZ_TO_HVAC_MODE[value]
|
||||
return HVACMode.OFF
|
||||
return OVERKIZ_TO_HVAC_ACTION[cast(str, state)]
|
||||
|
||||
return HVACAction.OFF
|
||||
|
||||
@property
|
||||
def hvac_action(self) -> HVACAction | None:
|
||||
"""Return the current running hvac operation."""
|
||||
|
||||
# When ZoneControl action is heating/cooling but Zone is stopped, means the zone is idle.
|
||||
if (
|
||||
hvac_action := self.zone_control_hvac_action
|
||||
) in HVAC_ACTION_TO_OVERKIZ_PROFILE_STATE and cast(
|
||||
str,
|
||||
self.executor.select_state(
|
||||
HVAC_ACTION_TO_OVERKIZ_PROFILE_STATE[hvac_action]
|
||||
),
|
||||
) == OverkizCommandParam.STOP:
|
||||
return HVACAction.IDLE
|
||||
|
||||
return hvac_action
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> HVACMode:
|
||||
|
@ -84,30 +203,32 @@ class AtlanticPassAPCZoneControlZone(AtlanticPassAPCHeatingZone):
|
|||
if self.is_using_derogated_temperature_fallback:
|
||||
return super().hvac_mode
|
||||
|
||||
zone_control_hvac_mode = self.zone_control_hvac_mode
|
||||
if (device_hvac_mode := self.device_hvac_mode) is None:
|
||||
return HVACMode.OFF
|
||||
|
||||
# Should be same, because either thermostat or this integration change both.
|
||||
on_off_state = cast(
|
||||
cooling_is_off = cast(
|
||||
str,
|
||||
self.executor.select_state(
|
||||
OverkizState.CORE_COOLING_ON_OFF
|
||||
if zone_control_hvac_mode == HVACMode.COOL
|
||||
else OverkizState.CORE_HEATING_ON_OFF
|
||||
),
|
||||
)
|
||||
self.executor.select_state(OverkizState.CORE_COOLING_ON_OFF),
|
||||
) in (OverkizCommandParam.OFF, None)
|
||||
|
||||
heating_is_off = cast(
|
||||
str,
|
||||
self.executor.select_state(OverkizState.CORE_HEATING_ON_OFF),
|
||||
) in (OverkizCommandParam.OFF, None)
|
||||
|
||||
# Device is Stopped, it means the air flux is flowing but its venting door is closed.
|
||||
if on_off_state == OverkizCommandParam.OFF:
|
||||
hvac_mode = HVACMode.OFF
|
||||
else:
|
||||
hvac_mode = zone_control_hvac_mode
|
||||
if (
|
||||
(device_hvac_mode == HVACMode.COOL and cooling_is_off)
|
||||
or (device_hvac_mode == HVACMode.HEAT and heating_is_off)
|
||||
or (
|
||||
device_hvac_mode == HVACMode.HEAT_COOL
|
||||
and cooling_is_off
|
||||
and heating_is_off
|
||||
)
|
||||
):
|
||||
return HVACMode.OFF
|
||||
|
||||
# It helps keep it consistent with the Zone Control, within the interface.
|
||||
if self._attr_hvac_modes != [zone_control_hvac_mode, HVACMode.OFF]:
|
||||
self._attr_hvac_modes = [zone_control_hvac_mode, HVACMode.OFF]
|
||||
self.async_write_ha_state()
|
||||
|
||||
return hvac_mode
|
||||
return device_hvac_mode
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set new target hvac mode."""
|
||||
|
@ -118,46 +239,49 @@ class AtlanticPassAPCZoneControlZone(AtlanticPassAPCHeatingZone):
|
|||
# They are mainly managed by the Zone Control device
|
||||
# However, it make sense to map the OFF Mode to the Overkiz STOP Preset
|
||||
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_COOLING_ON_OFF,
|
||||
OverkizCommandParam.OFF,
|
||||
)
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_HEATING_ON_OFF,
|
||||
OverkizCommandParam.OFF,
|
||||
)
|
||||
else:
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_COOLING_ON_OFF,
|
||||
OverkizCommandParam.ON,
|
||||
)
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_HEATING_ON_OFF,
|
||||
OverkizCommandParam.ON,
|
||||
)
|
||||
on_off_target_command_param = (
|
||||
OverkizCommandParam.OFF
|
||||
if hvac_mode == HVACMode.OFF
|
||||
else OverkizCommandParam.ON
|
||||
)
|
||||
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_COOLING_ON_OFF,
|
||||
on_off_target_command_param,
|
||||
)
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_HEATING_ON_OFF,
|
||||
on_off_target_command_param,
|
||||
)
|
||||
|
||||
await self.async_refresh_modes()
|
||||
|
||||
@property
|
||||
def preset_mode(self) -> str:
|
||||
def preset_mode(self) -> str | None:
|
||||
"""Return the current preset mode, e.g., schedule, manual."""
|
||||
|
||||
if self.is_using_derogated_temperature_fallback:
|
||||
return super().preset_mode
|
||||
|
||||
mode = OVERKIZ_MODE_TO_PRESET_MODES[
|
||||
cast(
|
||||
str,
|
||||
self.executor.select_state(
|
||||
OverkizState.IO_PASS_APC_COOLING_MODE
|
||||
if self.zone_control_hvac_mode == HVACMode.COOL
|
||||
else OverkizState.IO_PASS_APC_HEATING_MODE
|
||||
),
|
||||
if (
|
||||
self.zone_control_hvac_action in HVAC_ACTION_TO_OVERKIZ_MODE_STATE
|
||||
and (
|
||||
mode_state := HVAC_ACTION_TO_OVERKIZ_MODE_STATE[
|
||||
self.zone_control_hvac_action
|
||||
]
|
||||
)
|
||||
]
|
||||
and (
|
||||
(
|
||||
mode := OVERKIZ_MODE_TO_PRESET_MODES[
|
||||
cast(str, self.executor.select_state(mode_state))
|
||||
]
|
||||
)
|
||||
is not None
|
||||
)
|
||||
):
|
||||
return mode
|
||||
|
||||
return mode if mode is not None else PRESET_NONE
|
||||
return PRESET_NONE
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set new preset mode."""
|
||||
|
@ -178,13 +302,18 @@ class AtlanticPassAPCZoneControlZone(AtlanticPassAPCHeatingZone):
|
|||
await self.async_refresh_modes()
|
||||
|
||||
@property
|
||||
def target_temperature(self) -> float:
|
||||
def target_temperature(self) -> float | None:
|
||||
"""Return hvac target temperature."""
|
||||
|
||||
if self.is_using_derogated_temperature_fallback:
|
||||
return super().target_temperature
|
||||
|
||||
if self.zone_control_hvac_mode == HVACMode.COOL:
|
||||
device_hvac_mode = self.device_hvac_mode
|
||||
|
||||
if device_hvac_mode == HVACMode.HEAT_COOL:
|
||||
return None
|
||||
|
||||
if device_hvac_mode == HVACMode.COOL:
|
||||
return cast(
|
||||
float,
|
||||
self.executor.select_state(
|
||||
|
@ -192,7 +321,7 @@ class AtlanticPassAPCZoneControlZone(AtlanticPassAPCHeatingZone):
|
|||
),
|
||||
)
|
||||
|
||||
if self.zone_control_hvac_mode == HVACMode.HEAT:
|
||||
if device_hvac_mode == HVACMode.HEAT:
|
||||
return cast(
|
||||
float,
|
||||
self.executor.select_state(
|
||||
|
@ -204,32 +333,73 @@ class AtlanticPassAPCZoneControlZone(AtlanticPassAPCHeatingZone):
|
|||
float, self.executor.select_state(OverkizState.CORE_TARGET_TEMPERATURE)
|
||||
)
|
||||
|
||||
@property
|
||||
def target_temperature_high(self) -> float | None:
|
||||
"""Return the highbound target temperature we try to reach (cooling)."""
|
||||
|
||||
if self.device_hvac_mode != HVACMode.HEAT_COOL:
|
||||
return None
|
||||
|
||||
return cast(
|
||||
float,
|
||||
self.executor.select_state(OverkizState.CORE_COOLING_TARGET_TEMPERATURE),
|
||||
)
|
||||
|
||||
@property
|
||||
def target_temperature_low(self) -> float | None:
|
||||
"""Return the lowbound target temperature we try to reach (heating)."""
|
||||
|
||||
if self.device_hvac_mode != HVACMode.HEAT_COOL:
|
||||
return None
|
||||
|
||||
return cast(
|
||||
float,
|
||||
self.executor.select_state(OverkizState.CORE_HEATING_TARGET_TEMPERATURE),
|
||||
)
|
||||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new temperature."""
|
||||
|
||||
if self.is_using_derogated_temperature_fallback:
|
||||
return await super().async_set_temperature(**kwargs)
|
||||
|
||||
temperature = kwargs[ATTR_TEMPERATURE]
|
||||
target_temperature = kwargs.get(ATTR_TEMPERATURE)
|
||||
target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW)
|
||||
target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH)
|
||||
hvac_mode = self.hvac_mode
|
||||
|
||||
if hvac_mode == HVACMode.HEAT_COOL:
|
||||
if target_temp_low is not None:
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_HEATING_TARGET_TEMPERATURE,
|
||||
target_temp_low,
|
||||
)
|
||||
|
||||
if target_temp_high is not None:
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_COOLING_TARGET_TEMPERATURE,
|
||||
target_temp_high,
|
||||
)
|
||||
|
||||
elif target_temperature is not None:
|
||||
if hvac_mode == HVACMode.HEAT:
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_HEATING_TARGET_TEMPERATURE,
|
||||
target_temperature,
|
||||
)
|
||||
|
||||
elif hvac_mode == HVACMode.COOL:
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_COOLING_TARGET_TEMPERATURE,
|
||||
target_temperature,
|
||||
)
|
||||
|
||||
# Change both (heating/cooling) temperature is a good way to have consistency
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_HEATING_TARGET_TEMPERATURE,
|
||||
temperature,
|
||||
)
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_COOLING_TARGET_TEMPERATURE,
|
||||
temperature,
|
||||
)
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.SET_DEROGATION_ON_OFF_STATE,
|
||||
OverkizCommandParam.OFF,
|
||||
OverkizCommandParam.ON,
|
||||
)
|
||||
|
||||
# Target temperature may take up to 1 minute to get refreshed.
|
||||
await self.executor.async_execute_command(
|
||||
OverkizCommand.REFRESH_TARGET_TEMPERATURE
|
||||
)
|
||||
await self.async_refresh_modes()
|
||||
|
||||
async def async_refresh_modes(self) -> None:
|
||||
"""Refresh the device modes to have new states."""
|
||||
|
@ -256,3 +426,51 @@ class AtlanticPassAPCZoneControlZone(AtlanticPassAPCHeatingZone):
|
|||
await self.executor.async_execute_command(
|
||||
OverkizCommand.REFRESH_TARGET_TEMPERATURE
|
||||
)
|
||||
|
||||
@property
|
||||
def min_temp(self) -> float:
|
||||
"""Return Minimum Temperature for AC of this group."""
|
||||
|
||||
device_hvac_mode = self.device_hvac_mode
|
||||
|
||||
if device_hvac_mode in (HVACMode.HEAT, HVACMode.HEAT_COOL):
|
||||
return cast(
|
||||
float,
|
||||
self.executor.select_state(
|
||||
OverkizState.CORE_MINIMUM_HEATING_TARGET_TEMPERATURE
|
||||
),
|
||||
)
|
||||
|
||||
if device_hvac_mode == HVACMode.COOL:
|
||||
return cast(
|
||||
float,
|
||||
self.executor.select_state(
|
||||
OverkizState.CORE_MINIMUM_COOLING_TARGET_TEMPERATURE
|
||||
),
|
||||
)
|
||||
|
||||
return super().min_temp
|
||||
|
||||
@property
|
||||
def max_temp(self) -> float:
|
||||
"""Return Max Temperature for AC of this group."""
|
||||
|
||||
device_hvac_mode = self.device_hvac_mode
|
||||
|
||||
if device_hvac_mode == HVACMode.HEAT:
|
||||
return cast(
|
||||
float,
|
||||
self.executor.select_state(
|
||||
OverkizState.CORE_MAXIMUM_HEATING_TARGET_TEMPERATURE
|
||||
),
|
||||
)
|
||||
|
||||
if device_hvac_mode in (HVACMode.COOL, HVACMode.HEAT_COOL):
|
||||
return cast(
|
||||
float,
|
||||
self.executor.select_state(
|
||||
OverkizState.CORE_MAXIMUM_COOLING_TARGET_TEMPERATURE
|
||||
),
|
||||
)
|
||||
|
||||
return super().max_temp
|
||||
|
|
Loading…
Reference in New Issue