-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add experimental convector heater support
- Loading branch information
Linux User
committed
Dec 2, 2024
1 parent
fa9c029
commit 7e24432
Showing
6 changed files
with
335 additions
and
4 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
"""Platform for Eldom water heater integration.""" | ||
|
||
import logging | ||
from typing import Any | ||
|
||
from homeassistant.components.climate import ( | ||
ClimateEntity, | ||
ClimateEntityFeature, | ||
HVACMode, | ||
) | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import UnitOfTemperature | ||
from homeassistant.core import HomeAssistant, callback | ||
from homeassistant.exceptions import HomeAssistantError | ||
from homeassistant.helpers.device_registry import DeviceInfo | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
from homeassistant.helpers.update_coordinator import CoordinatorEntity | ||
|
||
from .const import ( | ||
DEVICE_TYPE_CONVECTOR_HEATER, | ||
DEVICE_TYPE_MAPPING, | ||
DOMAIN, | ||
MANUFACTURER_NAME, | ||
) | ||
from .coordinator import EldomCoordinator | ||
from .eldom_convector import EldomConvectorHeater | ||
from .models import EldomData | ||
|
||
SUPPORT_FLAGS_CLIMATE = ( | ||
ClimateEntityFeature.TARGET_TEMPERATURE, | ||
ClimateEntityFeature.TURN_ON, | ||
ClimateEntityFeature.TURN_OFF, | ||
) | ||
|
||
TEMP_UNIT = UnitOfTemperature.CELSIUS | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
async def async_setup_entry( | ||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback | ||
) -> None: | ||
"""Eldom convector heater setup.""" | ||
|
||
eldom_data: EldomData = hass.data[DOMAIN][entry.entry_id] | ||
|
||
await eldom_data.coordinator.async_config_entry_first_refresh() | ||
|
||
async_add_entities( | ||
EldomConvectorHeaterEntity(convector_heater, eldom_data.coordinator) | ||
for convector_heater in eldom_data.coordinator.data.get( | ||
DEVICE_TYPE_CONVECTOR_HEATER | ||
).values() | ||
) | ||
|
||
|
||
class EldomConvectorHeaterEntity(ClimateEntity, CoordinatorEntity): | ||
"""Representation of an Eldom convector heater. | ||
The CoordinatorEntity class provides: | ||
should_poll | ||
async_update | ||
async_added_to_hass | ||
available | ||
""" | ||
|
||
def __init__( | ||
self, convector_heater: EldomConvectorHeater, coordinator: EldomCoordinator | ||
) -> None: | ||
"""Initialize an Eldom water heater.""" | ||
super().__init__(coordinator) | ||
|
||
self._convector_heater = convector_heater | ||
|
||
@property | ||
def device_info(self) -> DeviceInfo: | ||
"""Return device information about this convector heater.""" | ||
return DeviceInfo( | ||
name=self._convector_heater.name, | ||
identifiers={(DOMAIN, self._convector_heater.device_id)}, | ||
manufacturer=MANUFACTURER_NAME, | ||
model=DEVICE_TYPE_MAPPING.get(self._convector_heater.type), | ||
sw_version=self._convector_heater.software_version, | ||
hw_version=self._convector_heater.hardware_version, | ||
) | ||
|
||
@property | ||
def unique_id(self) -> str: | ||
"""Return a unique ID.""" | ||
return self._convector_heater.device_id | ||
|
||
@property | ||
def name(self) -> str: | ||
"""Return the name of the convector heater.""" | ||
return self._convector_heater.name | ||
|
||
@property | ||
def supported_features(self) -> ClimateEntityFeature: | ||
"""Return the list of supported features.""" | ||
return SUPPORT_FLAGS_CLIMATE | ||
|
||
@property | ||
def temperature_unit(self) -> str: | ||
"""Return the unit of measurement.""" | ||
return TEMP_UNIT | ||
|
||
@property | ||
def max_temp(self) -> float: | ||
"""Return the maximum temperature.""" | ||
return self._convector_heater.max_temperature | ||
|
||
@property | ||
def min_temp(self) -> float: | ||
"""Return the minimum temperature.""" | ||
return self._convector_heater.min_temperature | ||
|
||
@property | ||
def current_temperature(self) -> float | None: | ||
"""Return the current temperature.""" | ||
return self._convector_heater.current_temperature | ||
|
||
@property | ||
def target_temperature(self) -> float | None: | ||
"""Return the temperature we try to reach.""" | ||
return self._convector_heater.target_temperature | ||
|
||
@property | ||
def hvac_mode(self) -> HVACMode | None: | ||
"""Return current operation ie. Off or Heating.""" | ||
return self._convector_heater.current_operation | ||
|
||
@property | ||
def hvac_modes(self) -> list[HVACMode]: | ||
"""Return the list of available operation modes.""" | ||
return self._convector_heater.operation_modes | ||
|
||
async def async_turn_on(self, **kwargs: Any) -> None: | ||
"""Turn the convector heater on.""" | ||
await self._convector_heater.turn_on() | ||
self.schedule_update_ha_state() | ||
await self.coordinator.async_request_refresh() | ||
|
||
async def async_turn_off(self, **kwargs: Any) -> None: | ||
"""Turn the convector heater off.""" | ||
await self._convector_heater.turn_off() | ||
self.schedule_update_ha_state() | ||
await self.coordinator.async_request_refresh() | ||
|
||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: | ||
"""Set new target operation mode.""" | ||
try: | ||
await self._convector_heater.set_operation_mode(hvac_mode) | ||
self.schedule_update_ha_state() | ||
await self.coordinator.async_request_refresh() | ||
except Exception as e: | ||
_LOGGER.error("Error while setting operation mode: %s", e) | ||
raise HomeAssistantError("Error while setting operation mode") from e | ||
|
||
async def async_set_temperature(self, **kwargs: Any) -> None: | ||
"""Set new target temperature.""" | ||
temperature = kwargs.get("temperature") | ||
await self._convector_heater.set_temperature(temperature) | ||
self.schedule_update_ha_state() | ||
await self.coordinator.async_request_refresh() | ||
|
||
@callback | ||
def _handle_coordinator_update(self) -> None: | ||
"""Handle updated data from the coordinator.""" | ||
self._convector_heater = self.coordinator.data.get( | ||
self._convector_heater.type | ||
).get(self._convector_heater.id) | ||
|
||
self.async_write_ha_state() |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
"""Eldom objects.""" | ||
"""Eldom boiler objects.""" | ||
|
||
from abc import ABC, abstractmethod | ||
import logging | ||
|
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,139 @@ | ||
"""Eldom convector heater objects.""" | ||
|
||
import logging | ||
|
||
from eldom.client import Client as EldomClient | ||
from eldom.models import ConvectorHeaterDetails | ||
|
||
from homeassistant.components.climate import HVACMode | ||
|
||
OPERATION_MODES = {0: HVACMode.OFF, 1: HVACMode.HEAT} | ||
|
||
MAX_TEMP = 35 | ||
MIN_TEMP = 5 | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
class EldomConvectorHeater: | ||
"""An Eldom convector heater representation object.""" | ||
|
||
def __init__( | ||
self, | ||
id: int, | ||
convector_heater_details: ConvectorHeaterDetails, | ||
eldom_client: EldomClient, | ||
) -> None: | ||
"""Initialize the heater.""" | ||
self._id = id | ||
self._convector_heater_details = convector_heater_details | ||
self._eldom_client = eldom_client | ||
|
||
@property | ||
def id(self) -> int: | ||
"""Retrieve the heater's ID.""" | ||
return self._id | ||
|
||
@property | ||
def device_id(self) -> str: | ||
"""Retrieve the heater's device ID.""" | ||
return self._convector_heater_details.DeviceID | ||
|
||
@property | ||
def name(self) -> str: | ||
"""Retrieve the heater's name.""" | ||
return f"Convector Heater ({self._convector_heater_details.DeviceID[-4:]})" | ||
|
||
@property | ||
def type(self) -> int: | ||
"""Retrieve the heater's type.""" | ||
return self._convector_heater_details.Type | ||
|
||
@property | ||
def software_version(self) -> str: | ||
"""Retrieve the heater's software version.""" | ||
return self._convector_heater_details.SoftwareVersion | ||
|
||
@property | ||
def hardware_version(self) -> str: | ||
"""Retrieve the heater's hardware version.""" | ||
return self._convector_heater_details.HardwareVersion | ||
|
||
@property | ||
def operation_modes(self) -> list[HVACMode]: | ||
"""Retrieve the heater's operation modes. Modes are: Off, Heat.""" | ||
return list(OPERATION_MODES.values()) | ||
|
||
@property | ||
def max_temperature(self) -> float: | ||
"""Retrieve the heater's maximum temperature.""" | ||
return MAX_TEMP | ||
|
||
@property | ||
def min_temperature(self) -> float: | ||
"""Retrieve the heater's minimum temperature.""" | ||
return MIN_TEMP | ||
|
||
@property | ||
def current_temperature(self) -> float: | ||
"""Retrieve the heater's current temperature.""" | ||
return self._convector_heater_details.AmbientTemp | ||
|
||
@property | ||
def target_temperature(self) -> float: | ||
"""Retrieve the heater's target temperature.""" | ||
return self._convector_heater_details.SetTemp | ||
|
||
@property | ||
def powerful_enabled(self) -> bool: | ||
"""Retrieve whether the heater's powerful mode is enabled.""" | ||
return self._convector_heater_details.BoostHeating | ||
|
||
@property | ||
def day_energy_consumption(self) -> float: | ||
"""Retrieve the heater's day energy consumption.""" | ||
return self._convector_heater_details.EnergyD | ||
|
||
@property | ||
def night_energy_consumption(self) -> float: | ||
"""Retrieve the heater's night energy consumption.""" | ||
return self._convector_heater_details.EnergyN | ||
|
||
@property | ||
def current_operation(self) -> HVACMode: | ||
"""Return current operation ie. Off or Heat.""" | ||
return OPERATION_MODES.get(self._convector_heater_details.State, "Unknown") | ||
|
||
@property | ||
def power_level(self) -> int: | ||
"""Retrieve the heating level of the heater.""" | ||
return self._convector_heater_details.Power | ||
|
||
async def turn_on(self) -> None: | ||
"""Turn the heater on.""" | ||
await self.set_operation_mode(HVACMode.HEAT) | ||
|
||
async def turn_off(self) -> None: | ||
"""Turn the heater off.""" | ||
await self.set_operation_mode(HVACMode.OFF) | ||
|
||
async def set_operation_mode(self, operation_mode: HVACMode) -> None: | ||
"""Set new target operation mode.""" | ||
if operation_mode not in OPERATION_MODES.values(): | ||
raise ValueError("Operation mode not supported") | ||
|
||
operation_mode_id = {v: k for k, v in OPERATION_MODES.items()}[operation_mode] | ||
|
||
self._convector_heater_details.State = operation_mode_id | ||
|
||
await self._eldom_client.set_convector_heater_state( | ||
self.device_id, operation_mode_id | ||
) | ||
|
||
async def set_temperature(self, temperature: float) -> None: | ||
"""Set the temperature of the heater.""" | ||
self._convector_heater_details.SetTemp = temperature | ||
|
||
await self._eldom_client.set_convector_heater_temperature( | ||
self.device_id, 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