147 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
"""EHEIM Digital climate."""
 | 
						|
 | 
						|
from typing import Any
 | 
						|
 | 
						|
from eheimdigital.device import EheimDigitalDevice
 | 
						|
from eheimdigital.heater import EheimDigitalHeater
 | 
						|
from eheimdigital.types import EheimDigitalClientError, HeaterMode, HeaterUnit
 | 
						|
 | 
						|
from homeassistant.components.climate import (
 | 
						|
    PRESET_NONE,
 | 
						|
    ClimateEntity,
 | 
						|
    ClimateEntityFeature,
 | 
						|
    HVACAction,
 | 
						|
    HVACMode,
 | 
						|
)
 | 
						|
from homeassistant.const import (
 | 
						|
    ATTR_TEMPERATURE,
 | 
						|
    PRECISION_HALVES,
 | 
						|
    PRECISION_TENTHS,
 | 
						|
    UnitOfTemperature,
 | 
						|
)
 | 
						|
from homeassistant.core import HomeAssistant
 | 
						|
from homeassistant.exceptions import HomeAssistantError
 | 
						|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
 | 
						|
 | 
						|
from .const import HEATER_BIO_MODE, HEATER_PRESET_TO_HEATER_MODE, HEATER_SMART_MODE
 | 
						|
from .coordinator import EheimDigitalConfigEntry, EheimDigitalUpdateCoordinator
 | 
						|
from .entity import EheimDigitalEntity
 | 
						|
 | 
						|
# Coordinator is used to centralize the data updates
 | 
						|
PARALLEL_UPDATES = 0
 | 
						|
 | 
						|
 | 
						|
async def async_setup_entry(
 | 
						|
    hass: HomeAssistant,
 | 
						|
    entry: EheimDigitalConfigEntry,
 | 
						|
    async_add_entities: AddConfigEntryEntitiesCallback,
 | 
						|
) -> None:
 | 
						|
    """Set up the callbacks for the coordinator so climate entities can be added as devices are found."""
 | 
						|
    coordinator = entry.runtime_data
 | 
						|
 | 
						|
    def async_setup_device_entities(
 | 
						|
        device_address: str | dict[str, EheimDigitalDevice],
 | 
						|
    ) -> None:
 | 
						|
        """Set up the climate entities for one or multiple devices."""
 | 
						|
        entities: list[EheimDigitalHeaterClimate] = []
 | 
						|
        if isinstance(device_address, str):
 | 
						|
            device_address = {device_address: coordinator.hub.devices[device_address]}
 | 
						|
        for device in device_address.values():
 | 
						|
            if isinstance(device, EheimDigitalHeater):
 | 
						|
                entities.append(EheimDigitalHeaterClimate(coordinator, device))
 | 
						|
                coordinator.known_devices.add(device.mac_address)
 | 
						|
 | 
						|
        async_add_entities(entities)
 | 
						|
 | 
						|
    coordinator.add_platform_callback(async_setup_device_entities)
 | 
						|
 | 
						|
    async_setup_device_entities(coordinator.hub.devices)
 | 
						|
 | 
						|
 | 
						|
class EheimDigitalHeaterClimate(EheimDigitalEntity[EheimDigitalHeater], ClimateEntity):
 | 
						|
    """Represent an EHEIM Digital heater."""
 | 
						|
 | 
						|
    _attr_hvac_modes = [HVACMode.OFF, HVACMode.AUTO]
 | 
						|
    _attr_hvac_mode = HVACMode.OFF
 | 
						|
    _attr_precision = PRECISION_TENTHS
 | 
						|
    _attr_supported_features = (
 | 
						|
        ClimateEntityFeature.TARGET_TEMPERATURE
 | 
						|
        | ClimateEntityFeature.TURN_ON
 | 
						|
        | ClimateEntityFeature.TURN_OFF
 | 
						|
        | ClimateEntityFeature.PRESET_MODE
 | 
						|
    )
 | 
						|
    _attr_target_temperature_step = PRECISION_HALVES
 | 
						|
    _attr_preset_modes = [PRESET_NONE, HEATER_BIO_MODE, HEATER_SMART_MODE]
 | 
						|
    _attr_temperature_unit = UnitOfTemperature.CELSIUS
 | 
						|
    _attr_preset_mode = PRESET_NONE
 | 
						|
    _attr_translation_key = "heater"
 | 
						|
    _attr_name = None
 | 
						|
 | 
						|
    def __init__(
 | 
						|
        self, coordinator: EheimDigitalUpdateCoordinator, device: EheimDigitalHeater
 | 
						|
    ) -> None:
 | 
						|
        """Initialize an EHEIM Digital thermocontrol climate entity."""
 | 
						|
        super().__init__(coordinator, device)
 | 
						|
        self._attr_unique_id = self._device_address
 | 
						|
        self._async_update_attrs()
 | 
						|
 | 
						|
    async def async_set_preset_mode(self, preset_mode: str) -> None:
 | 
						|
        """Set the preset mode."""
 | 
						|
        try:
 | 
						|
            if preset_mode in HEATER_PRESET_TO_HEATER_MODE:
 | 
						|
                await self._device.set_operation_mode(
 | 
						|
                    HEATER_PRESET_TO_HEATER_MODE[preset_mode]
 | 
						|
                )
 | 
						|
        except EheimDigitalClientError as err:
 | 
						|
            raise HomeAssistantError from err
 | 
						|
 | 
						|
    async def async_set_temperature(self, **kwargs: Any) -> None:
 | 
						|
        """Set a new temperature."""
 | 
						|
        try:
 | 
						|
            if ATTR_TEMPERATURE in kwargs:
 | 
						|
                await self._device.set_target_temperature(kwargs[ATTR_TEMPERATURE])
 | 
						|
        except EheimDigitalClientError as err:
 | 
						|
            raise HomeAssistantError from err
 | 
						|
 | 
						|
    async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
 | 
						|
        """Set the heating mode."""
 | 
						|
        try:
 | 
						|
            match hvac_mode:
 | 
						|
                case HVACMode.OFF:
 | 
						|
                    await self._device.set_active(active=False)
 | 
						|
                case HVACMode.AUTO:
 | 
						|
                    await self._device.set_active(active=True)
 | 
						|
        except EheimDigitalClientError as err:
 | 
						|
            raise HomeAssistantError from err
 | 
						|
 | 
						|
    def _async_update_attrs(self) -> None:
 | 
						|
        if self._device.temperature_unit == HeaterUnit.CELSIUS:
 | 
						|
            self._attr_min_temp = 18
 | 
						|
            self._attr_max_temp = 32
 | 
						|
            self._attr_temperature_unit = UnitOfTemperature.CELSIUS
 | 
						|
        elif self._device.temperature_unit == HeaterUnit.FAHRENHEIT:
 | 
						|
            self._attr_min_temp = 64
 | 
						|
            self._attr_max_temp = 90
 | 
						|
            self._attr_temperature_unit = UnitOfTemperature.FAHRENHEIT
 | 
						|
 | 
						|
        self._attr_current_temperature = self._device.current_temperature
 | 
						|
        self._attr_target_temperature = self._device.target_temperature
 | 
						|
 | 
						|
        if self._device.is_heating:
 | 
						|
            self._attr_hvac_action = HVACAction.HEATING
 | 
						|
            self._attr_hvac_mode = HVACMode.AUTO
 | 
						|
        elif self._device.is_active:
 | 
						|
            self._attr_hvac_action = HVACAction.IDLE
 | 
						|
            self._attr_hvac_mode = HVACMode.AUTO
 | 
						|
        else:
 | 
						|
            self._attr_hvac_action = HVACAction.OFF
 | 
						|
            self._attr_hvac_mode = HVACMode.OFF
 | 
						|
 | 
						|
        match self._device.operation_mode:
 | 
						|
            case HeaterMode.MANUAL:
 | 
						|
                self._attr_preset_mode = PRESET_NONE
 | 
						|
            case HeaterMode.BIO:
 | 
						|
                self._attr_preset_mode = HEATER_BIO_MODE
 | 
						|
            case HeaterMode.SMART:
 | 
						|
                self._attr_preset_mode = HEATER_SMART_MODE
 |