"""BleBox climate entities tests.""" import logging from unittest.mock import AsyncMock, PropertyMock import blebox_uniapi import pytest from homeassistant.components.climate import ( ATTR_CURRENT_TEMPERATURE, ATTR_HVAC_ACTION, ATTR_HVAC_MODE, ATTR_HVAC_MODES, ATTR_MAX_TEMP, ATTR_MIN_TEMP, SERVICE_SET_HVAC_MODE, SERVICE_SET_TEMPERATURE, ClimateEntityFeature, HVACAction, HVACMode, ) from homeassistant.config_entries import ConfigEntryState from homeassistant.const import ( ATTR_DEVICE_CLASS, ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, ATTR_TEMPERATURE, STATE_UNKNOWN, ) from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr from .conftest import async_setup_config_entry, async_setup_entity, mock_feature from tests.common import MockConfigEntry @pytest.fixture(name="saunabox") def saunabox_fixture(): """Return a default climate entity mock.""" feature = mock_feature( "climates", blebox_uniapi.climate.Climate, unique_id="BleBox-saunaBox-1afe34db9437-thermostat", full_name="saunaBox-thermostat", device_class=None, is_on=None, desired=None, current=None, min_temp=-54.3, max_temp=124.3, mode=None, hvac_action=None, ) product = feature.product type(product).name = PropertyMock(return_value="My sauna") type(product).model = PropertyMock(return_value="saunaBox") return (feature, "climate.my_sauna") @pytest.fixture(name="thermobox") def thermobox_fixture(): """Return a default climate entity mock.""" feature = mock_feature( "climates", blebox_uniapi.climate.Climate, unique_id="BleBox-thermoBox-1afe34db9437-thermostat", full_name="thermoBox-thermostat", device_class=None, is_on=None, desired=None, current=None, min_temp=-54.3, max_temp=124.3, mode=2, hvac_action=1, ) product = feature.product type(product).name = PropertyMock(return_value="My thermo") type(product).model = PropertyMock(return_value="thermoBox") return (feature, "climate.my_thermo") async def test_init( saunabox, hass: HomeAssistant, device_registry: dr.DeviceRegistry ) -> None: """Test default state.""" _, entity_id = saunabox entry = await async_setup_entity(hass, entity_id) assert entry.unique_id == "BleBox-saunaBox-1afe34db9437-thermostat" state = hass.states.get(entity_id) assert state.name == "My sauna" supported_features = state.attributes[ATTR_SUPPORTED_FEATURES] assert supported_features & ClimateEntityFeature.TARGET_TEMPERATURE assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.OFF] assert ATTR_DEVICE_CLASS not in state.attributes assert ATTR_HVAC_MODE not in state.attributes assert ATTR_HVAC_ACTION not in state.attributes assert state.attributes[ATTR_MIN_TEMP] == -54.3 assert state.attributes[ATTR_MAX_TEMP] == 124.3 assert state.attributes[ATTR_TEMPERATURE] is None assert state.attributes[ATTR_CURRENT_TEMPERATURE] is None assert state.state == STATE_UNKNOWN device = device_registry.async_get(entry.device_id) assert device.name == "My sauna" assert device.identifiers == {("blebox", "abcd0123ef5678")} assert device.manufacturer == "BleBox" assert device.model == "saunaBox" assert device.sw_version == "1.23" async def test_update(saunabox, hass: HomeAssistant, config) -> None: """Test updating.""" feature_mock, entity_id = saunabox feature_mock.is_on = False feature_mock.desired = 64.3 feature_mock.current = 40.9 await async_setup_entity(hass, entity_id) state = hass.states.get(entity_id) assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.OFF assert state.attributes[ATTR_TEMPERATURE] == 64.3 assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 40.9 assert state.state == HVACMode.OFF async def test_set_hvac_mode_heat(saunabox, hass: HomeAssistant) -> None: """Test that setting HVAC mode to heat calls async_on.""" feature_mock, entity_id = saunabox feature_mock.mode = 1 await async_setup_entity(hass, entity_id) await hass.services.async_call( "climate", SERVICE_SET_HVAC_MODE, {ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: HVACMode.HEAT}, blocking=True, ) feature_mock.async_on.assert_called_once_with() feature_mock.async_off.assert_not_called() async def test_set_hvac_mode_off(saunabox, hass: HomeAssistant) -> None: """Test that setting HVAC mode to off calls async_off.""" feature_mock, entity_id = saunabox await async_setup_entity(hass, entity_id) await hass.services.async_call( "climate", SERVICE_SET_HVAC_MODE, {"entity_id": entity_id, ATTR_HVAC_MODE: HVACMode.OFF}, blocking=True, ) feature_mock.async_off.assert_called_once_with() feature_mock.async_on.assert_not_called() async def test_set_thermo(saunabox, hass: HomeAssistant) -> None: """Test that setting the temperature calls async_set_temperature.""" feature_mock, entity_id = saunabox await async_setup_entity(hass, entity_id) await hass.services.async_call( "climate", SERVICE_SET_TEMPERATURE, {"entity_id": entity_id, ATTR_TEMPERATURE: 43.21}, blocking=True, ) feature_mock.async_set_temperature.assert_called_once_with(43.21) async def test_update_failure( saunabox, hass: HomeAssistant, config_entry: MockConfigEntry, caplog: pytest.LogCaptureFixture, ) -> None: """Test that update failures cause config entry setup retry.""" caplog.set_level(logging.ERROR) feature_mock, _entity_id = saunabox feature_mock.product.async_update_data = AsyncMock( side_effect=blebox_uniapi.error.ClientError ) await async_setup_config_entry(hass, config_entry) feature_mock.product.async_update_data.assert_called() assert config_entry.state is ConfigEntryState.SETUP_RETRY async def test_hvac_action_heating(saunabox, hass: HomeAssistant) -> None: """Test hvac_action reflects a heating device state.""" feature_mock, entity_id = saunabox feature_mock.is_on = True feature_mock.hvac_action = 1 feature_mock.mode = 1 await async_setup_entity(hass, entity_id) state = hass.states.get(entity_id) assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.OFF, HVACMode.HEAT] async def test_hvac_action_off(thermobox, hass: HomeAssistant) -> None: """Test hvac_action reflects a device that is off.""" feature_mock, entity_id = thermobox feature_mock.is_on = False feature_mock.hvac_action = 0 await async_setup_entity(hass, entity_id) state = hass.states.get(entity_id) assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.OFF assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.OFF, HVACMode.COOL]