-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Overkiz support for AtlanticPassAPCHeatingAndCoolingZone widget
- Loading branch information
Showing
8 changed files
with
248 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
228 changes: 228 additions & 0 deletions
228
...sistant/components/overkiz/climate_entities/atlantic_pass_apc_heating_and_cooling_zone.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
"""Support for Atlantic Pass APC Heating Control.""" | ||
from __future__ import annotations | ||
|
||
from typing import Any, cast | ||
|
||
from pyoverkiz.enums import OverkizCommand, OverkizCommandParam, OverkizState | ||
|
||
from homeassistant.components.climate import ClimateEntityFeature, HVACMode | ||
from homeassistant.components.climate.const import PRESET_NONE | ||
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature | ||
|
||
from ..const import DOMAIN | ||
from ..coordinator import OverkizDataUpdateCoordinator | ||
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" | ||
|
||
OVERKIZ_MODE_TO_PRESET_MODES: dict[str, str] = { | ||
OverkizCommandParam.MANU: PRESET_MANUAL, | ||
OverkizCommandParam.INTERNAL_SCHEDULING: PRESET_SCHEDULE, | ||
} | ||
|
||
PRESET_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_MODE_TO_PRESET_MODES.items()} | ||
|
||
# Those device depends on a main probe that choose the operating mode (heating, cooling, ...) | ||
class AtlanticPassAPCHeatingAndCoolingZone(AtlanticPassAPCHeatingZone): | ||
"""Representation of Atlantic Pass APC Heating And Cooling Zone Control.""" | ||
|
||
# Modes are not configurable, they will follow current HVAC Mode of Zone Control. | ||
_attr_hvac_modes = [] | ||
|
||
# Those are available and tested presets on Shogun. | ||
_attr_preset_modes = [*PRESET_MODES_TO_OVERKIZ] | ||
|
||
# Thermostat internalScheduling stop manu eco | ||
|
||
_attr_supported_features = ( | ||
ClimateEntityFeature.TARGET_TEMPERATURE | ||
| ClimateEntityFeature.PRESET_MODE | ||
| ClimateEntityFeature.TURN_OFF | ||
| ClimateEntityFeature.TURN_ON | ||
) | ||
_attr_temperature_unit = UnitOfTemperature.CELSIUS | ||
_attr_translation_key = DOMAIN | ||
_enable_turn_on_off_backwards_compatibility = False | ||
|
||
def __init__( | ||
self, device_url: str, coordinator: OverkizDataUpdateCoordinator | ||
) -> None: | ||
"""Init method.""" | ||
super().__init__(device_url, coordinator) | ||
|
||
# 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(1) | ||
|
||
@property | ||
def zone_control_hvac_mode(self) -> HVACMode: | ||
"""Return hvac operation ie. heat, cool, dry, off mode.""" | ||
|
||
return OVERKIZ_TO_HVAC_MODE[ | ||
self.zone_control_device.states[ | ||
OverkizState.IO_PASS_APC_OPERATING_MODE | ||
].value_as_str | ||
] | ||
|
||
@property | ||
def hvac_mode(self) -> HVACMode: | ||
"""Return hvac operation ie. heat, cool, dry, off mode.""" | ||
|
||
zone_control_hvac_mode = self.zone_control_hvac_mode | ||
|
||
# Should be same, because either thermostat or this integration change both. | ||
on_off_state = cast( | ||
str, | ||
self.executor.select_state( | ||
OverkizState.CORE_COOLING_ON_OFF | ||
if zone_control_hvac_mode == HVACMode.COOL | ||
else OverkizState.CORE_HEATING_ON_OFF | ||
), | ||
) | ||
|
||
# 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 | ||
|
||
# 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 | ||
|
||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: | ||
"""Set new target hvac mode.""" | ||
|
||
# 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, | ||
) | ||
|
||
await self.async_refresh_modes() | ||
|
||
@property | ||
def preset_mode(self) -> str: | ||
"""Return the current preset mode, e.g., schedule, manual.""" | ||
|
||
mode = OVERKIZ_MODE_TO_PRESET_MODES[ | ||
cast( | ||
str, | ||
self.executor.select_state( | ||
OverkizState.IO_PASS_APC_HEATING_MODE | ||
if self.zone_control_hvac_mode == HVACMode.COOL | ||
else OverkizState.IO_PASS_APC_COOLING_MODE | ||
), | ||
) | ||
] | ||
|
||
return mode if mode is not None else PRESET_NONE | ||
|
||
async def async_set_preset_mode(self, preset_mode: str) -> None: | ||
"""Set new preset mode.""" | ||
|
||
mode = PRESET_MODES_TO_OVERKIZ[preset_mode] | ||
|
||
# For consistency, it is better both are synced like on the Thermostat. | ||
await self.executor.async_execute_command( | ||
OverkizCommand.SET_PASS_APC_HEATING_MODE, mode | ||
) | ||
await self.executor.async_execute_command( | ||
OverkizCommand.SET_PASS_APC_COOLING_MODE, mode | ||
) | ||
|
||
await self.async_refresh_modes() | ||
|
||
@property | ||
def target_temperature(self) -> float: | ||
"""Return hvac target temperature.""" | ||
|
||
if self.zone_control_hvac_mode == HVACMode.COOL: | ||
return cast( | ||
float, | ||
self.executor.select_state( | ||
OverkizState.CORE_COOLING_TARGET_TEMPERATURE | ||
), | ||
) | ||
|
||
if self.zone_control_hvac_mode == HVACMode.HEAT: | ||
return cast( | ||
float, | ||
self.executor.select_state( | ||
OverkizState.CORE_HEATING_TARGET_TEMPERATURE | ||
), | ||
) | ||
|
||
# Not sure this temperature is relevant. | ||
return cast( | ||
float, self.executor.select_state(OverkizState.CORE_TARGET_TEMPERATURE) | ||
) | ||
|
||
async def async_set_temperature(self, **kwargs: Any) -> None: | ||
"""Set new temperature.""" | ||
|
||
temperature = kwargs[ATTR_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, | ||
) | ||
|
||
# Target temperature may take up to 1 minute to get refreshed. | ||
await self.executor.async_execute_command( | ||
OverkizCommand.REFRESH_TARGET_TEMPERATURE | ||
) | ||
|
||
async def async_refresh_modes(self) -> None: | ||
"""Refresh the device modes to have new states.""" | ||
|
||
await self.executor.async_execute_command( | ||
OverkizCommand.REFRESH_PASS_APC_HEATING_MODE | ||
) | ||
|
||
await self.executor.async_execute_command( | ||
OverkizCommand.REFRESH_PASS_APC_HEATING_PROFILE | ||
) | ||
|
||
await self.executor.async_execute_command( | ||
OverkizCommand.REFRESH_PASS_APC_COOLING_MODE | ||
) | ||
|
||
await self.executor.async_execute_command( | ||
OverkizCommand.REFRESH_PASS_APC_COOLING_PROFILE | ||
) | ||
|
||
await self.executor.async_execute_command( | ||
OverkizCommand.REFRESH_TARGET_TEMPERATURE | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters