* chore: Add tests for BSBLAN climate component * fix return types * fix MAC data * chore: Update BSBLAN climate component tests used setup from conftest added setup for farhenheit temp unit * chore: Update BSBLAN climate component tests use syrupy to compare results * add test for temp_unit * update climate tests set current_temperature to None in test case. Is this the correct way for testing? * chore: Update BSBLAN diagnostics to handle asynchronous data retrieval * chore: Refactor BSBLAN conftest.py to simplify fixture and patching * chore: Update BSBLAN climate component tests 100% test coverage * chore: Update BSBLAN diagnostics to handle asynchronous data retrieval * chore: Update snapshots * Fix BSBLAN climate test for async_set_preset_mode - Update test_async_set_preset_mode to correctly handle ServiceValidationError - Check for specific translation key instead of full error message - Ensure consistency between local tests and CI environment - Import ServiceValidationError explicitly for clarity * Update homeassistant/components/bsblan/entity.py Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * chore: Update BSBLAN conftest.py to simplify fixture and patching * chore: Update BSBLAN integration setup function parameter name * chore: removed set_static_value * refactor: Improve BSBLANClimate async_set_preset_mode method This commit refactors the async_set_preset_mode method in the BSBLANClimate class to improve code readability and maintainability. The method now checks if the HVAC mode is not set to AUTO and the preset mode is not NONE before raising a ServiceValidationError. Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com> * refactor: Improve tests test_celsius_fahrenheit test_climate_entity_properties test_async_set_hvac_mode test_async_set_preset_mode still broken. Not sure why hvac mode will not set. THis causes error with preset mode set * update snapshot * fix DOMAIN bsblan * refactor: Improve BSBLANClimate async_set_data method * refactor: fix last tests * refactor: Simplify async_get_config_entry_diagnostics method * refactor: Improve BSBLANClimate async_set_temperature method This commit improves the async_set_temperature method in the BSBLANClimate class. It removes the unnecessary parameter "expected_result" and simplifies the code by directly calling the service to set the temperature. The method now correctly asserts that the thermostat method is called with the correct temperature. * refactor: Add static data to async_get_config_entry_diagnostics * refactor: Add static data to async_get_config_entry_diagnostics right place * refactor: Improve error message for setting preset mode This commit updates the error message in the BSBLANClimate class when trying to set the preset mode. * refactor: Improve tests * Fix --------- Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
163 lines
5.3 KiB
Python
163 lines
5.3 KiB
Python
"""BSBLAN platform to control a compatible Climate Device."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from bsblan import BSBLANError
|
|
|
|
from homeassistant.components.climate import (
|
|
ATTR_HVAC_MODE,
|
|
ATTR_PRESET_MODE,
|
|
PRESET_ECO,
|
|
PRESET_NONE,
|
|
ClimateEntity,
|
|
ClimateEntityFeature,
|
|
HVACMode,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
|
from homeassistant.helpers.device_registry import format_mac
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
from homeassistant.util.enum import try_parse_enum
|
|
|
|
from . import BSBLanData
|
|
from .const import ATTR_TARGET_TEMPERATURE, DOMAIN
|
|
from .entity import BSBLanEntity
|
|
|
|
PARALLEL_UPDATES = 1
|
|
|
|
HVAC_MODES = [
|
|
HVACMode.AUTO,
|
|
HVACMode.HEAT,
|
|
HVACMode.OFF,
|
|
]
|
|
|
|
PRESET_MODES = [
|
|
PRESET_ECO,
|
|
PRESET_NONE,
|
|
]
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: ConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Set up BSBLAN device based on a config entry."""
|
|
data: BSBLanData = hass.data[DOMAIN][entry.entry_id]
|
|
async_add_entities(
|
|
[
|
|
BSBLANClimate(
|
|
data,
|
|
)
|
|
]
|
|
)
|
|
|
|
|
|
class BSBLANClimate(BSBLanEntity, ClimateEntity):
|
|
"""Defines a BSBLAN climate device."""
|
|
|
|
_attr_has_entity_name = True
|
|
_attr_name = None
|
|
# Determine preset modes
|
|
_attr_supported_features = (
|
|
ClimateEntityFeature.TARGET_TEMPERATURE
|
|
| ClimateEntityFeature.PRESET_MODE
|
|
| ClimateEntityFeature.TURN_OFF
|
|
| ClimateEntityFeature.TURN_ON
|
|
)
|
|
|
|
_attr_preset_modes = PRESET_MODES
|
|
_attr_hvac_modes = HVAC_MODES
|
|
_enable_turn_on_off_backwards_compatibility = False
|
|
|
|
def __init__(
|
|
self,
|
|
data: BSBLanData,
|
|
) -> None:
|
|
"""Initialize BSBLAN climate device."""
|
|
super().__init__(data.coordinator, data)
|
|
self._attr_unique_id = f"{format_mac(data.device.MAC)}-climate"
|
|
|
|
self._attr_min_temp = float(data.static.min_temp.value)
|
|
self._attr_max_temp = float(data.static.max_temp.value)
|
|
if data.static.min_temp.unit in ("°C", "°C"):
|
|
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
|
|
else:
|
|
self._attr_temperature_unit = UnitOfTemperature.FAHRENHEIT
|
|
|
|
@property
|
|
def current_temperature(self) -> float | None:
|
|
"""Return the current temperature."""
|
|
if self.coordinator.data.state.current_temperature.value == "---":
|
|
# device returns no current temperature
|
|
return None
|
|
|
|
return float(self.coordinator.data.state.current_temperature.value)
|
|
|
|
@property
|
|
def target_temperature(self) -> float | None:
|
|
"""Return the temperature we try to reach."""
|
|
return float(self.coordinator.data.state.target_temperature.value)
|
|
|
|
@property
|
|
def hvac_mode(self) -> HVACMode | None:
|
|
"""Return hvac operation ie. heat, cool mode."""
|
|
if self.coordinator.data.state.hvac_mode.value == PRESET_ECO:
|
|
return HVACMode.AUTO
|
|
return try_parse_enum(HVACMode, self.coordinator.data.state.hvac_mode.value)
|
|
|
|
@property
|
|
def preset_mode(self) -> str | None:
|
|
"""Return the current preset mode."""
|
|
if (
|
|
self.hvac_mode == HVACMode.AUTO
|
|
and self.coordinator.data.state.hvac_mode.value == PRESET_ECO
|
|
):
|
|
return PRESET_ECO
|
|
return PRESET_NONE
|
|
|
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
"""Set hvac mode."""
|
|
await self.async_set_data(hvac_mode=hvac_mode)
|
|
|
|
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
|
"""Set preset mode."""
|
|
if self.hvac_mode != HVACMode.AUTO and preset_mode != PRESET_NONE:
|
|
raise ServiceValidationError(
|
|
"Preset mode can only be set when HVAC mode is set to 'auto'",
|
|
translation_domain=DOMAIN,
|
|
translation_key="set_preset_mode_error",
|
|
translation_placeholders={"preset_mode": preset_mode},
|
|
)
|
|
await self.async_set_data(preset_mode=preset_mode)
|
|
|
|
async def async_set_temperature(self, **kwargs: Any) -> None:
|
|
"""Set new target temperatures."""
|
|
await self.async_set_data(**kwargs)
|
|
|
|
async def async_set_data(self, **kwargs: Any) -> None:
|
|
"""Set device settings using BSBLAN."""
|
|
data = {}
|
|
if ATTR_TEMPERATURE in kwargs:
|
|
data[ATTR_TARGET_TEMPERATURE] = kwargs[ATTR_TEMPERATURE]
|
|
if ATTR_HVAC_MODE in kwargs:
|
|
data[ATTR_HVAC_MODE] = kwargs[ATTR_HVAC_MODE]
|
|
if ATTR_PRESET_MODE in kwargs:
|
|
if kwargs[ATTR_PRESET_MODE] == PRESET_ECO:
|
|
data[ATTR_HVAC_MODE] = PRESET_ECO
|
|
elif kwargs[ATTR_PRESET_MODE] == PRESET_NONE:
|
|
data[ATTR_HVAC_MODE] = PRESET_NONE
|
|
|
|
try:
|
|
await self.coordinator.client.thermostat(**data)
|
|
except BSBLANError as err:
|
|
raise HomeAssistantError(
|
|
"An error occurred while updating the BSBLAN device",
|
|
translation_domain=DOMAIN,
|
|
translation_key="set_data_error",
|
|
) from err
|
|
await self.coordinator.async_request_refresh()
|