mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Add clima support to Comelit integration (#108858)
* Add clima support to Comelit integration * address first part of review comments * applied more review comments * remove old multiplier * removed preset modes (not always configured) * small tweak * apply StrEnum class
This commit is contained in:
parent
f2100f80c4
commit
f413ff2837
@ -182,6 +182,7 @@ omit =
|
|||||||
homeassistant/components/comed_hourly_pricing/sensor.py
|
homeassistant/components/comed_hourly_pricing/sensor.py
|
||||||
homeassistant/components/comelit/__init__.py
|
homeassistant/components/comelit/__init__.py
|
||||||
homeassistant/components/comelit/alarm_control_panel.py
|
homeassistant/components/comelit/alarm_control_panel.py
|
||||||
|
homeassistant/components/comelit/climate.py
|
||||||
homeassistant/components/comelit/const.py
|
homeassistant/components/comelit/const.py
|
||||||
homeassistant/components/comelit/cover.py
|
homeassistant/components/comelit/cover.py
|
||||||
homeassistant/components/comelit/coordinator.py
|
homeassistant/components/comelit/coordinator.py
|
||||||
|
@ -11,6 +11,7 @@ from .const import DEFAULT_PORT, DOMAIN
|
|||||||
from .coordinator import ComelitBaseCoordinator, ComelitSerialBridge, ComelitVedoSystem
|
from .coordinator import ComelitBaseCoordinator, ComelitSerialBridge, ComelitVedoSystem
|
||||||
|
|
||||||
BRIDGE_PLATFORMS = [
|
BRIDGE_PLATFORMS = [
|
||||||
|
Platform.CLIMATE,
|
||||||
Platform.COVER,
|
Platform.COVER,
|
||||||
Platform.LIGHT,
|
Platform.LIGHT,
|
||||||
Platform.SENSOR,
|
Platform.SENSOR,
|
||||||
|
206
homeassistant/components/comelit/climate.py
Normal file
206
homeassistant/components/comelit/climate.py
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
"""Support for climates."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from enum import StrEnum
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from aiocomelit import ComelitSerialBridgeObject
|
||||||
|
from aiocomelit.const import CLIMATE, SLEEP_BETWEEN_CALLS
|
||||||
|
|
||||||
|
from homeassistant.components.climate import (
|
||||||
|
ClimateEntity,
|
||||||
|
ClimateEntityFeature,
|
||||||
|
HVACAction,
|
||||||
|
HVACMode,
|
||||||
|
UnitOfTemperature,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_TENTHS
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
|
from .const import _LOGGER, DOMAIN
|
||||||
|
from .coordinator import ComelitSerialBridge
|
||||||
|
|
||||||
|
|
||||||
|
class ClimaMode(StrEnum):
|
||||||
|
"""Serial Bridge clima modes."""
|
||||||
|
|
||||||
|
AUTO = "A"
|
||||||
|
OFF = "O"
|
||||||
|
LOWER = "L"
|
||||||
|
UPPER = "U"
|
||||||
|
|
||||||
|
|
||||||
|
class ClimaAction(StrEnum):
|
||||||
|
"""Serial Bridge clima actions."""
|
||||||
|
|
||||||
|
OFF = "off"
|
||||||
|
ON = "on"
|
||||||
|
MANUAL = "man"
|
||||||
|
SET = "set"
|
||||||
|
AUTO = "auto"
|
||||||
|
|
||||||
|
|
||||||
|
API_STATUS: dict[str, dict[str, Any]] = {
|
||||||
|
ClimaMode.OFF: {
|
||||||
|
"action": "off",
|
||||||
|
"hvac_mode": HVACMode.OFF,
|
||||||
|
"hvac_action": HVACAction.OFF,
|
||||||
|
},
|
||||||
|
ClimaMode.LOWER: {
|
||||||
|
"action": "lower",
|
||||||
|
"hvac_mode": HVACMode.COOL,
|
||||||
|
"hvac_action": HVACAction.COOLING,
|
||||||
|
},
|
||||||
|
ClimaMode.UPPER: {
|
||||||
|
"action": "upper",
|
||||||
|
"hvac_mode": HVACMode.HEAT,
|
||||||
|
"hvac_action": HVACAction.HEATING,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
MODE_TO_ACTION: dict[HVACMode, ClimaAction] = {
|
||||||
|
HVACMode.OFF: ClimaAction.OFF,
|
||||||
|
HVACMode.AUTO: ClimaAction.AUTO,
|
||||||
|
HVACMode.COOL: ClimaAction.MANUAL,
|
||||||
|
HVACMode.HEAT: ClimaAction.MANUAL,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up Comelit climates."""
|
||||||
|
|
||||||
|
coordinator: ComelitSerialBridge = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
|
|
||||||
|
async_add_entities(
|
||||||
|
ComelitClimateEntity(coordinator, device, config_entry.entry_id)
|
||||||
|
for device in coordinator.data[CLIMATE].values()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ComelitClimateEntity(CoordinatorEntity[ComelitSerialBridge], ClimateEntity):
|
||||||
|
"""Climate device."""
|
||||||
|
|
||||||
|
_attr_hvac_modes = [HVACMode.AUTO, HVACMode.COOL, HVACMode.HEAT, HVACMode.OFF]
|
||||||
|
_attr_max_temp = 30
|
||||||
|
_attr_min_temp = 5
|
||||||
|
_attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE
|
||||||
|
_attr_target_temperature_step = PRECISION_TENTHS
|
||||||
|
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
_attr_name = None
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: ComelitSerialBridge,
|
||||||
|
device: ComelitSerialBridgeObject,
|
||||||
|
config_entry_entry_id: str,
|
||||||
|
) -> None:
|
||||||
|
"""Init light entity."""
|
||||||
|
self._api = coordinator.api
|
||||||
|
self._device = device
|
||||||
|
super().__init__(coordinator)
|
||||||
|
# Use config_entry.entry_id as base for unique_id
|
||||||
|
# because no serial number or mac is available
|
||||||
|
self._attr_unique_id = f"{config_entry_entry_id}-{device.index}"
|
||||||
|
self._attr_device_info = coordinator.platform_device_info(device, device.type)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _clima(self) -> list[Any]:
|
||||||
|
"""Return clima device data."""
|
||||||
|
# CLIMATE has 2 turple:
|
||||||
|
# - first for Clima
|
||||||
|
# - second for Humidifier
|
||||||
|
return self.coordinator.data[CLIMATE][self._device.index].val[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _api_mode(self) -> str:
|
||||||
|
"""Return device mode."""
|
||||||
|
# Values from API: "O", "L", "U"
|
||||||
|
return self._clima[2]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _api_active(self) -> bool:
|
||||||
|
"Return device active/idle."
|
||||||
|
return self._clima[1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _api_automatic(self) -> bool:
|
||||||
|
"""Return device in automatic/manual mode."""
|
||||||
|
return self._clima[3] == ClimaMode.AUTO
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_temperature(self) -> float:
|
||||||
|
"""Set target temperature."""
|
||||||
|
return self._clima[4] / 10
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_temperature(self) -> float:
|
||||||
|
"""Return current temperature."""
|
||||||
|
return self._clima[0] / 10
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hvac_mode(self) -> HVACMode | None:
|
||||||
|
"""HVAC current mode."""
|
||||||
|
|
||||||
|
if self._api_mode == ClimaMode.OFF:
|
||||||
|
return HVACMode.OFF
|
||||||
|
|
||||||
|
if self._api_automatic:
|
||||||
|
return HVACMode.AUTO
|
||||||
|
|
||||||
|
if self._api_mode in API_STATUS:
|
||||||
|
return API_STATUS[self._api_mode]["hvac_mode"]
|
||||||
|
|
||||||
|
_LOGGER.warning("Unknown API mode '%s' in hvac_mode", self._api_mode)
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hvac_action(self) -> HVACAction | None:
|
||||||
|
"""HVAC current action."""
|
||||||
|
|
||||||
|
if self._api_mode == ClimaMode.OFF:
|
||||||
|
return HVACAction.OFF
|
||||||
|
|
||||||
|
if not self._api_active:
|
||||||
|
return HVACAction.IDLE
|
||||||
|
|
||||||
|
if self._api_mode in API_STATUS:
|
||||||
|
return API_STATUS[self._api_mode]["hvac_action"]
|
||||||
|
|
||||||
|
_LOGGER.warning("Unknown API mode '%s' in hvac_action", self._api_mode)
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||||
|
"""Set new target temperature."""
|
||||||
|
if (
|
||||||
|
target_temp := kwargs.get(ATTR_TEMPERATURE)
|
||||||
|
) is None or self.hvac_mode == HVACMode.OFF:
|
||||||
|
return
|
||||||
|
|
||||||
|
await self.coordinator.api.set_clima_status(
|
||||||
|
self._device.index, ClimaAction.MANUAL
|
||||||
|
)
|
||||||
|
await asyncio.sleep(SLEEP_BETWEEN_CALLS)
|
||||||
|
await self.coordinator.api.set_clima_status(
|
||||||
|
self._device.index, ClimaAction.SET, target_temp
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||||
|
"""Set hvac mode."""
|
||||||
|
|
||||||
|
if hvac_mode != HVACMode.OFF:
|
||||||
|
await self.coordinator.api.set_clima_status(
|
||||||
|
self._device.index, ClimaAction.ON
|
||||||
|
)
|
||||||
|
await asyncio.sleep(SLEEP_BETWEEN_CALLS)
|
||||||
|
await self.coordinator.api.set_clima_status(
|
||||||
|
self._device.index, MODE_TO_ACTION[hvac_mode]
|
||||||
|
)
|
Loading…
x
Reference in New Issue
Block a user