<commit_before>"""Plugwise Climate component for Home Assistant."""
from typing import Any

from plugwise.exceptions import PlugwiseException

from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
    CURRENT_HVAC_COOL,
    CURRENT_HVAC_HEAT,
    CURRENT_HVAC_IDLE,
    HVAC_MODE_AUTO,
    HVAC_MODE_COOL,
    HVAC_MODE_HEAT,
    HVAC_MODE_OFF,
    SUPPORT_PRESET_MODE,
    SUPPORT_TARGET_TEMPERATURE,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import (
    DEFAULT_MAX_TEMP,
    DEFAULT_MIN_TEMP,
    DOMAIN,
    LOGGER,
    SCHEDULE_OFF,
    SCHEDULE_ON,
)
from .coordinator import PlugwiseDataUpdateCoordinator
from .entity import PlugwiseEntity

HVAC_MODES_HEAT_ONLY = [HVAC_MODE_HEAT, HVAC_MODE_AUTO, HVAC_MODE_OFF]
HVAC_MODES_HEAT_COOL = [HVAC_MODE_HEAT, HVAC_MODE_COOL, HVAC_MODE_AUTO, HVAC_MODE_OFF]
THERMOSTAT_CLASSES = ["thermostat", "zone_thermostat", "thermostatic_radiator_valve"]


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up the Smile Thermostats from a config entry."""
    coordinator = hass.data[DOMAIN][config_entry.entry_id]
    async_add_entities(
        PlugwiseClimateEntity(coordinator, device_id)
        for device_id, device in coordinator.data.devices.items()
        if device["class"] in THERMOSTAT_CLASSES
    )


class PlugwiseClimateEntity(PlugwiseEntity, ClimateEntity):
    """Representation of an Plugwise thermostat."""

    _attr_hvac_mode = HVAC_MODE_HEAT
    _attr_max_temp = DEFAULT_MAX_TEMP
    _attr_min_temp = DEFAULT_MIN_TEMP
    _attr_preset_mode = None
    _attr_preset_modes = None
    _attr_supported_features = SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE
    _attr_temperature_unit = TEMP_CELSIUS
    _attr_hvac_modes = HVAC_MODES_HEAT_ONLY
    _attr_hvac_mode = HVAC_MODE_HEAT

    def __init__(
        self,
        coordinator: PlugwiseDataUpdateCoordinator,
        device_id: str,
    ) -> None:
        """Set up the Plugwise API."""
        super().__init__(coordinator, device_id)
        self._attr_extra_state_attributes = {}
        self._attr_unique_id = f"{device_id}-climate"
        self._attr_name = coordinator.data.devices[device_id].get("name")

        self._loc_id = coordinator.data.devices[device_id]["location"]

        self._presets = None

    async def async_set_temperature(self, **kwargs: Any) -> None:
        """Set new target temperature."""
        temperature = kwargs.get(ATTR_TEMPERATURE)
        if (temperature is not None) and (
            self._attr_min_temp < temperature < self._attr_max_temp
        ):
            try:
                await self.coordinator.api.set_temperature(self._loc_id, temperature)
                self._attr_target_temperature = temperature
                self.async_write_ha_state()
            except PlugwiseException:
                LOGGER.error("Error while communicating to device")
        else:
            LOGGER.error("Invalid temperature requested")

    async def async_set_hvac_mode(self, hvac_mode: str) -> None:
        """Set the hvac mode."""
        state = SCHEDULE_OFF
        climate_data = self.coordinator.data.devices[self._dev_id]

        if hvac_mode == HVAC_MODE_AUTO:
            state = SCHEDULE_ON
            try:
                await self.coordinator.api.set_temperature(
                    self._loc_id, climate_data.get("schedule_temperature")
                )
                self._attr_target_temperature = climate_data.get("schedule_temperature")
            except PlugwiseException:
                LOGGER.error("Error while communicating to device")

        try:
            await self.coordinator.api.set_schedule_state(
                self._loc_id, climate_data.get("last_used"), state
            )
            self._attr_hvac_mode = hvac_mode
            self.async_write_ha_state()
        except PlugwiseException:
            LOGGER.error("Error while communicating to device")

    async def async_set_preset_mode(self, preset_mode: str) -> None:
        """Set the preset mode."""
        if self._presets is None:
            raise ValueError("No presets available")

        try:
            await self.coordinator.api.set_preset(self._loc_id, preset_mode)
            self._attr_preset_mode = preset_mode
            self._attr_target_temperature = self._presets.get(preset_mode, "none")[0]
            self.async_write_ha_state()
        except PlugwiseException:
            LOGGER.error("Error while communicating to device")

    @callback
    def _handle_coordinator_update(self) -> None:
        """Handle updated data from the coordinator."""
        data = self.coordinator.data.devices[self._dev_id]
        heater_central_data = self.coordinator.data.devices[
            self.coordinator.data.gateway["heater_id"]
        ]

        # Current & set temperatures
        if setpoint := data["sensors"].get("setpoint"):
            self._attr_target_temperature = setpoint
        if temperature := data["sensors"].get("temperature"):
            self._attr_current_temperature = temperature

        # Presets handling
        self._attr_preset_mode = data.get("active_preset")
        if presets := data.get("presets"):
            self._presets = presets
            self._attr_preset_modes = list(presets)
        else:
            self._presets = None
            self._attr_preset_mode = None<commit_msg>Clean up unneeded preset variable in Plugwise climate (#66151)<commit_after>"""Plugwise Climate component for Home Assistant."""
from typing import Any

from plugwise.exceptions import PlugwiseException

from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
    CURRENT_HVAC_COOL,
    CURRENT_HVAC_HEAT,
    CURRENT_HVAC_IDLE,
    HVAC_MODE_AUTO,
    HVAC_MODE_COOL,
    HVAC_MODE_HEAT,
    HVAC_MODE_OFF,
    SUPPORT_PRESET_MODE,
    SUPPORT_TARGET_TEMPERATURE,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import (
    DEFAULT_MAX_TEMP,
    DEFAULT_MIN_TEMP,
    DOMAIN,
    LOGGER,
    SCHEDULE_OFF,
    SCHEDULE_ON,
)
from .coordinator import PlugwiseDataUpdateCoordinator
from .entity import PlugwiseEntity

HVAC_MODES_HEAT_ONLY = [HVAC_MODE_HEAT, HVAC_MODE_AUTO, HVAC_MODE_OFF]
HVAC_MODES_HEAT_COOL = [HVAC_MODE_HEAT, HVAC_MODE_COOL, HVAC_MODE_AUTO, HVAC_MODE_OFF]
THERMOSTAT_CLASSES = ["thermostat", "zone_thermostat", "thermostatic_radiator_valve"]


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up the Smile Thermostats from a config entry."""
    coordinator = hass.data[DOMAIN][config_entry.entry_id]
    async_add_entities(
        PlugwiseClimateEntity(coordinator, device_id)
        for device_id, device in coordinator.data.devices.items()
        if device["class"] in THERMOSTAT_CLASSES
    )


class PlugwiseClimateEntity(PlugwiseEntity, ClimateEntity):
    """Representation of an Plugwise thermostat."""

    _attr_hvac_mode = HVAC_MODE_HEAT
    _attr_max_temp = DEFAULT_MAX_TEMP
    _attr_min_temp = DEFAULT_MIN_TEMP
    _attr_preset_mode = None
    _attr_preset_modes = None
    _attr_supported_features = SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE
    _attr_temperature_unit = TEMP_CELSIUS
    _attr_hvac_modes = HVAC_MODES_HEAT_ONLY
    _attr_hvac_mode = HVAC_MODE_HEAT

    def __init__(
        self,
        coordinator: PlugwiseDataUpdateCoordinator,
        device_id: str,
    ) -> None:
        """Set up the Plugwise API."""
        super().__init__(coordinator, device_id)
        self._attr_extra_state_attributes = {}
        self._attr_unique_id = f"{device_id}-climate"
        self._attr_name = coordinator.data.devices[device_id].get("name")

        self._loc_id = coordinator.data.devices[device_id]["location"]

    async def async_set_temperature(self, **kwargs: Any) -> None:
        """Set new target temperature."""
        temperature = kwargs.get(ATTR_TEMPERATURE)
        if (temperature is not None) and (
            self._attr_min_temp < temperature < self._attr_max_temp
        ):
            try:
                await self.coordinator.api.set_temperature(self._loc_id, temperature)
                self._attr_target_temperature = temperature
                self.async_write_ha_state()
            except PlugwiseException:
                LOGGER.error("Error while communicating to device")
        else:
            LOGGER.error("Invalid temperature requested")

    async def async_set_hvac_mode(self, hvac_mode: str) -> None:
        """Set the hvac mode."""
        state = SCHEDULE_OFF
        climate_data = self.coordinator.data.devices[self._dev_id]

        if hvac_mode == HVAC_MODE_AUTO:
            state = SCHEDULE_ON
            try:
                await self.coordinator.api.set_temperature(
                    self._loc_id, climate_data.get("schedule_temperature")
                )
                self._attr_target_temperature = climate_data.get("schedule_temperature")
            except PlugwiseException:
                LOGGER.error("Error while communicating to device")

        try:
            await self.coordinator.api.set_schedule_state(
                self._loc_id, climate_data.get("last_used"), state
            )
            self._attr_hvac_mode = hvac_mode
            self.async_write_ha_state()
        except PlugwiseException:
            LOGGER.error("Error while communicating to device")

    async def async_set_preset_mode(self, preset_mode: str) -> None:
        """Set the preset mode."""
        if not (presets := self.coordinator.data.devices[self._dev_id].get("presets")):
            raise ValueError("No presets available")

        try:
            await self.coordinator.api.set_preset(self._loc_id, preset_mode)
            self._attr_preset_mode = preset_mode
            self._attr_target_temperature = presets.get(preset_mode, "none")[0]
            self.async_write_ha_state()
        except PlugwiseException:
            LOGGER.error("Error while communicating to device")

    @callback
    def _handle_coordinator_update(self) -> None:
        """Handle updated data from the coordinator."""
        data = self.coordinator.data.devices[self._dev_id]
        heater_central_data = self.coordinator.data.devices[
            self.coordinator.data.gateway["heater_id"]
        ]

        # Current & set temperatures
        if setpoint := data["sensors"].get("setpoint"):
            self._attr_target_temperature = setpoint
        if temperature := data["sensors"].get("temperature"):
            self._attr_current_temperature = temperature

        # Presets handling
        self._attr_preset_mode = data.get("active_preset")
        if presets := data.get("presets"):
            self._attr_preset_modes = list(presets)
        else:
            self._attr_preset_mode = None
{'fraction_non_alphanumeric': 0.08106207139089151, 'fraction_numerical': 0.0006154387198874626, 'mean_word_length': 2.9551460361613353, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6636784', 'n_tokens_mistral': 3560, 'n_tokens_neox': 3387, 'n_words': 659}