"""The test for the sensibo climate platform.""" from datetime import datetime, timedelta from unittest.mock import MagicMock from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion from voluptuous import MultipleInvalid from homeassistant.components.climate import ( ATTR_FAN_MODE, ATTR_HVAC_MODE, ATTR_SWING_HORIZONTAL_MODE, ATTR_SWING_MODE, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW, DOMAIN as CLIMATE_DOMAIN, SERVICE_SET_FAN_MODE, SERVICE_SET_HVAC_MODE, SERVICE_SET_SWING_HORIZONTAL_MODE, SERVICE_SET_SWING_MODE, SERVICE_SET_TEMPERATURE, HVACMode, ) from homeassistant.components.sensibo.climate import _find_valid_target_temp from homeassistant.components.sensibo.const import DOMAIN from homeassistant.components.sensibo.services import ( ATTR_AC_INTEGRATION, ATTR_GEO_INTEGRATION, ATTR_HIGH_TEMPERATURE_STATE, ATTR_HIGH_TEMPERATURE_THRESHOLD, ATTR_HORIZONTAL_SWING_MODE, ATTR_INDOOR_INTEGRATION, ATTR_LIGHT, ATTR_LOW_TEMPERATURE_STATE, ATTR_LOW_TEMPERATURE_THRESHOLD, ATTR_MINUTES, ATTR_OUTDOOR_INTEGRATION, ATTR_SENSITIVITY, ATTR_SMART_TYPE, ATTR_TARGET_TEMPERATURE, SERVICE_ASSUME_STATE, SERVICE_ENABLE_CLIMATE_REACT, SERVICE_ENABLE_PURE_BOOST, SERVICE_ENABLE_TIMER, SERVICE_FULL_STATE, SERVICE_GET_DEVICE_CAPABILITIES, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_MODE, ATTR_STATE, ATTR_TEMPERATURE, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_OFF, STATE_ON, STATE_UNKNOWN, Platform, ) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from homeassistant.helpers import entity_registry as er from homeassistant.util import dt as dt_util from tests.common import async_fire_time_changed, snapshot_platform async def test_climate_find_valid_targets() -> None: """Test function to return temperature from valid targets.""" valid_targets = [10, 16, 17, 18, 19, 20] assert _find_valid_target_temp(7, valid_targets) == 10 assert _find_valid_target_temp(10, valid_targets) == 10 assert _find_valid_target_temp(11, valid_targets) == 16 assert _find_valid_target_temp(15, valid_targets) == 16 assert _find_valid_target_temp(16, valid_targets) == 16 assert _find_valid_target_temp(18.5, valid_targets) == 19 assert _find_valid_target_temp(20, valid_targets) == 20 assert _find_valid_target_temp(25, valid_targets) == 20 @pytest.mark.parametrize( "load_platforms", [[Platform.CLIMATE]], ) async def test_climate( hass: HomeAssistant, caplog: pytest.LogCaptureFixture, load_int: ConfigEntry, entity_registry: er.EntityRegistry, snapshot: SnapshotAssertion, ) -> None: """Test the Sensibo climate.""" await snapshot_platform(hass, entity_registry, snapshot, load_int.entry_id) logs = caplog.get_records("setup") assert "Device Bedroom not correctly registered with remote on Sensibo cloud." in [ log.message for log in logs ] async def test_climate_fan( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate fan service.""" state = hass.states.get("climate.hallway") assert state.attributes["fan_mode"] == "high" mock_client.async_get_devices_data.return_value.parsed["ABC999111"].fan_modes = [ "quiet", "low", "medium", "not_in_ha", ] mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].fan_modes_translated = { "low": "low", "medium": "medium", "quiet": "quiet", "not_in_ha": "not_in_ha", } with pytest.raises( HomeAssistantError, match="Climate fan mode not_in_ha is not supported by the integration", ): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_FAN_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_FAN_MODE: "not_in_ha"}, blocking=True, ) mock_client.async_set_ac_state_property.return_value = { "result": {"status": "Success"} } await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_FAN_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_FAN_MODE: "low"}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.attributes["fan_mode"] == "low" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].active_features = [ "timestamp", "on", "mode", "swing", "targetTemperature", "horizontalSwing", "light", ] freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() with pytest.raises(HomeAssistantError) as err: await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_FAN_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_FAN_MODE: "low"}, blocking=True, ) assert err.value.translation_key == "service_not_supported" state = hass.states.get("climate.hallway") assert "fan_mode" not in state.attributes async def test_climate_swing( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate swing service.""" state = hass.states.get("climate.hallway") assert state.attributes["swing_mode"] == "stopped" mock_client.async_get_devices_data.return_value.parsed["ABC999111"].swing_modes = [ "stopped", "fixedtop", "fixedmiddletop", "not_in_ha", ] mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].swing_modes_translated = { "fixedmiddletop": "fixedMiddleTop", "fixedtop": "fixedTop", "stopped": "stopped", "not_in_ha": "not_in_ha", } freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() with pytest.raises( HomeAssistantError, match="Climate swing mode not_in_ha is not supported by the integration", ): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_SWING_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_SWING_MODE: "not_in_ha"}, blocking=True, ) mock_client.async_set_ac_state_property.return_value = { "result": {"status": "Success"} } await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_SWING_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_SWING_MODE: "fixedtop"}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.attributes["swing_mode"] == "fixedtop" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].active_features = [ "timestamp", "on", "mode", "targetTemperature", "horizontalSwing", "light", ] freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() with pytest.raises(HomeAssistantError) as err: await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_SWING_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_SWING_MODE: "fixedtop"}, blocking=True, ) assert err.value.translation_key == "service_not_supported" state = hass.states.get("climate.hallway") assert "swing_mode" not in state.attributes async def test_climate_horizontal_swing( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate horizontal swing service.""" state = hass.states.get("climate.hallway") assert state.attributes["swing_horizontal_mode"] == "stopped" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].horizontal_swing_modes = [ "stopped", "fixedleft", "fixedcenter", "fixedright", "not_in_ha", ] mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].swing_modes_translated = { "stopped": "stopped", "fixedleft": "fixedLeft", "fixedcenter": "fixedCenter", "fixedright": "fixedRight", "not_in_ha": "not_in_ha", } freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() with pytest.raises( HomeAssistantError, match="Climate horizontal swing mode not_in_ha is not supported by the integration", ): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_SWING_HORIZONTAL_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_SWING_HORIZONTAL_MODE: "not_in_ha"}, blocking=True, ) mock_client.async_set_ac_state_property.return_value = { "result": {"status": "Success"} } await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_SWING_HORIZONTAL_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_SWING_HORIZONTAL_MODE: "fixedleft"}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.attributes["swing_horizontal_mode"] == "fixedleft" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].active_features = [ "timestamp", "on", "mode", "targetTemperature", "swing", "light", ] freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() with pytest.raises(HomeAssistantError) as err: await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_SWING_HORIZONTAL_MODE, { ATTR_ENTITY_ID: state.entity_id, ATTR_SWING_HORIZONTAL_MODE: "fixedcenter", }, blocking=True, ) assert err.value.translation_key == "service_not_supported" state = hass.states.get("climate.hallway") assert "swing_horizontal_mode" not in state.attributes async def test_climate_temperatures( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate temperature service.""" state = hass.states.get("climate.hallway") assert state.attributes["temperature"] == 25 mock_client.async_set_ac_state_property.return_value = { "result": {"status": "Success"} } await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: state.entity_id, ATTR_TEMPERATURE: 20}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.attributes["temperature"] == 20 mock_client.async_set_ac_state_property.reset_mock() await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: state.entity_id, ATTR_TEMPERATURE: 20}, blocking=True, ) assert not mock_client.async_set_ac_state_property.called mock_client.async_set_ac_state_property.return_value = { "result": {"status": "Success"} } await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: state.entity_id, ATTR_TEMPERATURE: 15}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.attributes["temperature"] == 16 await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: state.entity_id, ATTR_TEMPERATURE: 18.5}, blocking=True, ) state2 = hass.states.get("climate.hallway") assert state2.attributes["temperature"] == 19 with pytest.raises( ServiceValidationError, match="Provided temperature 24.0 is not valid. Accepted range is 10 to 20", ): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: state.entity_id, ATTR_TEMPERATURE: 24}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.attributes["temperature"] == 19 await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: state.entity_id, ATTR_TEMPERATURE: 20}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.attributes["temperature"] == 20 with pytest.raises(MultipleInvalid): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: state.entity_id}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.attributes["temperature"] == 20 mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].active_features = [ "timestamp", "on", "mode", "swing", "horizontalSwing", "light", ] freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() with pytest.raises(HomeAssistantError) as err: await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: state.entity_id, ATTR_TEMPERATURE: 20}, blocking=True, ) assert err.value.translation_key == "service_not_supported" state = hass.states.get("climate.hallway") assert "temperature" not in state.attributes async def test_climate_temperature_is_none( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate temperature service no temperature provided.""" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].active_features = [ "timestamp", "on", "mode", "fanLevel", "targetTemperature", "swing", "horizontalSwing", "light", ] mock_client.async_get_devices_data.return_value.parsed["ABC999111"].target_temp = 25 freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") assert state.attributes["temperature"] == 25 with pytest.raises(ServiceValidationError): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, { ATTR_ENTITY_ID: state.entity_id, ATTR_TARGET_TEMP_HIGH: 30, ATTR_TARGET_TEMP_LOW: 20, }, blocking=True, ) state = hass.states.get("climate.hallway") assert state.attributes["temperature"] == 25 async def test_climate_hvac_mode( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate hvac mode service.""" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].active_features = [ "timestamp", "on", "mode", "fanLevel", "targetTemperature", "swing", "horizontalSwing", "light", ] freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") assert state.state == HVACMode.HEAT mock_client.async_set_ac_state_property.return_value = { "result": {"status": "Success"} } await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_HVAC_MODE: "off"}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.state == HVACMode.OFF mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].device_on = False freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_HVAC_MODE: "heat"}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.state == HVACMode.HEAT async def test_climate_on_off( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate on/off service.""" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].hvac_mode = "heat" mock_client.async_get_devices_data.return_value.parsed["ABC999111"].device_on = True freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") assert state.state == HVACMode.HEAT mock_client.async_set_ac_state_property.return_value = { "result": {"status": "Success"} } await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: state.entity_id}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.state == HVACMode.OFF await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: state.entity_id}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.state == HVACMode.HEAT async def test_climate_service_failed( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate service failed.""" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].hvac_mode = "heat" mock_client.async_get_devices_data.return_value.parsed["ABC999111"].device_on = True freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") assert state.state == HVACMode.HEAT mock_client.async_set_ac_state_property.return_value = { "result": {"status": "Error", "failureReason": "Did not work"} } with pytest.raises(HomeAssistantError): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: state.entity_id}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.state == HVACMode.HEAT async def test_climate_assumed_state( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate assumed state service.""" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].hvac_mode = "heat" mock_client.async_get_devices_data.return_value.parsed["ABC999111"].device_on = True freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") assert state.state == HVACMode.HEAT mock_client.async_set_ac_state_property.return_value = { "result": {"status": "Success"} } await hass.services.async_call( DOMAIN, SERVICE_ASSUME_STATE, {ATTR_ENTITY_ID: state.entity_id, ATTR_STATE: "off"}, blocking=True, ) state = hass.states.get("climate.hallway") assert state.state == HVACMode.OFF async def test_climate_no_fan_no_swing( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate fan.""" state = hass.states.get("climate.hallway") assert state.attributes["fan_mode"] == "high" assert state.attributes["swing_mode"] == "stopped" mock_client.async_get_devices_data.return_value.parsed["ABC999111"].fan_mode = None mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].swing_mode = None mock_client.async_get_devices_data.return_value.parsed["ABC999111"].fan_modes = None mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].swing_modes = None freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") assert state.attributes["fan_mode"] is None assert state.attributes["swing_mode"] is None assert state.attributes["fan_modes"] is None assert state.attributes["swing_modes"] is None @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_climate_set_timer( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate Set Timer service.""" freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") assert hass.states.get("sensor.hallway_timer_end_time").state == STATE_UNKNOWN mock_client.async_set_timer.return_value = {"status": "failure"} with pytest.raises(MultipleInvalid): await hass.services.async_call( DOMAIN, SERVICE_ENABLE_TIMER, { ATTR_ENTITY_ID: state.entity_id, }, blocking=True, ) with pytest.raises(HomeAssistantError): await hass.services.async_call( DOMAIN, SERVICE_ENABLE_TIMER, { ATTR_ENTITY_ID: state.entity_id, ATTR_MINUTES: 30, }, blocking=True, ) mock_client.async_set_timer.return_value = { "status": "success", "result": {"id": "SzTGE4oZ4D"}, } await hass.services.async_call( DOMAIN, SERVICE_ENABLE_TIMER, { ATTR_ENTITY_ID: state.entity_id, ATTR_MINUTES: 30, }, blocking=True, ) mock_client.async_get_devices_data.return_value.parsed["ABC999111"].timer_on = True mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].timer_id = "SzTGE4oZ4D" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].timer_state_on = False mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].timer_time = datetime(2022, 6, 6, 12, 00, 00, tzinfo=dt_util.UTC) freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() assert ( hass.states.get("sensor.hallway_timer_end_time").state == "2022-06-06T12:00:00+00:00" ) @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_climate_pure_boost( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate pure boost service.""" freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.kitchen") state2 = hass.states.get("switch.kitchen_pure_boost") assert state2.state == STATE_OFF with pytest.raises( MultipleInvalid, ): await hass.services.async_call( DOMAIN, SERVICE_ENABLE_PURE_BOOST, { ATTR_ENTITY_ID: state.entity_id, ATTR_INDOOR_INTEGRATION: True, ATTR_OUTDOOR_INTEGRATION: True, ATTR_SENSITIVITY: "sensitive", }, blocking=True, ) mock_client.async_set_pureboost.return_value = { "status": "success", "result": { "enabled": True, "sensitivity": "S", "measurements_integration": True, "ac_integration": False, "geo_integration": False, "prime_integration": True, }, } await hass.services.async_call( DOMAIN, SERVICE_ENABLE_PURE_BOOST, { ATTR_ENTITY_ID: state.entity_id, ATTR_AC_INTEGRATION: False, ATTR_GEO_INTEGRATION: False, ATTR_INDOOR_INTEGRATION: True, ATTR_OUTDOOR_INTEGRATION: True, ATTR_SENSITIVITY: "sensitive", }, blocking=True, ) mock_client.async_get_devices_data.return_value.parsed[ "AAZZAAZZ" ].pure_boost_enabled = True mock_client.async_get_devices_data.return_value.parsed[ "AAZZAAZZ" ].pure_sensitivity = "s" mock_client.async_get_devices_data.return_value.parsed[ "AAZZAAZZ" ].pure_measure_integration = True mock_client.async_get_devices_data.return_value.parsed[ "AAZZAAZZ" ].pure_prime_integration = True freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() assert hass.states.get("switch.kitchen_pure_boost").state == STATE_ON assert ( hass.states.get( "binary_sensor.kitchen_pure_boost_linked_with_indoor_air_quality" ).state == STATE_ON ) assert ( hass.states.get( "binary_sensor.kitchen_pure_boost_linked_with_outdoor_air_quality" ).state == STATE_ON ) assert hass.states.get("sensor.kitchen_pure_sensitivity").state == "s" @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_climate_climate_react( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate react custom service.""" freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state_climate = hass.states.get("climate.hallway") with pytest.raises( MultipleInvalid, ): await hass.services.async_call( DOMAIN, SERVICE_ENABLE_PURE_BOOST, { ATTR_ENTITY_ID: state_climate.entity_id, ATTR_LOW_TEMPERATURE_THRESHOLD: 0.2, ATTR_HIGH_TEMPERATURE_THRESHOLD: 30.3, ATTR_SMART_TYPE: "temperature", }, blocking=True, ) mock_client.async_set_climate_react.return_value = { "status": "success", "result": { "enabled": True, "deviceUid": "ABC999111", "highTemperatureState": { "on": True, "targetTemperature": 15, "temperatureUnit": "C", "mode": "cool", "fanLevel": "high", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", }, "highTemperatureThreshold": 30.5, "lowTemperatureState": { "on": True, "targetTemperature": 25, "temperatureUnit": "C", "mode": "heat", "fanLevel": "low", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", }, "lowTemperatureThreshold": 5.5, "type": "feelsLike", }, } await hass.services.async_call( DOMAIN, SERVICE_ENABLE_CLIMATE_REACT, { ATTR_ENTITY_ID: state_climate.entity_id, ATTR_LOW_TEMPERATURE_THRESHOLD: 5.5, ATTR_HIGH_TEMPERATURE_THRESHOLD: 30.5, ATTR_LOW_TEMPERATURE_STATE: { "on": True, "targetTemperature": 25, "temperatureUnit": "C", "mode": "heat", "fanLevel": "low", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", }, ATTR_HIGH_TEMPERATURE_STATE: { "on": True, "targetTemperature": 15, "temperatureUnit": "C", "mode": "cool", "fanLevel": "high", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", }, ATTR_SMART_TYPE: "feelslike", }, blocking=True, ) mock_client.async_get_devices_data.return_value.parsed["ABC999111"].smart_on = True mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].smart_type = "feelsLike" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].smart_low_temp_threshold = 5.5 mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].smart_high_temp_threshold = 30.5 mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].smart_low_state = { "on": True, "targetTemperature": 25, "temperatureUnit": "C", "mode": "heat", "fanLevel": "low", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", } mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].smart_high_state = { "on": True, "targetTemperature": 15, "temperatureUnit": "C", "mode": "cool", "fanLevel": "high", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", } freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() assert hass.states.get("switch.hallway_climate_react").state == STATE_ON assert ( hass.states.get("sensor.hallway_climate_react_low_temperature_threshold").state == "5.5" ) assert ( hass.states.get("sensor.hallway_climate_react_high_temperature_threshold").state == "30.5" ) assert hass.states.get("sensor.hallway_climate_react_type").state == "feelslike" @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_climate_climate_react_fahrenheit( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate react custom service with fahrenheit.""" freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") mock_client.async_set_climate_react.return_value = { "status": "success", "result": { "enabled": True, "deviceUid": "ABC999111", "highTemperatureState": { "on": True, "targetTemperature": 65, "temperatureUnit": "F", "mode": "cool", "fanLevel": "high", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", }, "highTemperatureThreshold": 77, "lowTemperatureState": { "on": True, "targetTemperature": 85, "temperatureUnit": "F", "mode": "heat", "fanLevel": "low", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", }, "lowTemperatureThreshold": 32, "type": "temperature", }, } await hass.services.async_call( DOMAIN, SERVICE_ENABLE_CLIMATE_REACT, { ATTR_ENTITY_ID: state.entity_id, ATTR_LOW_TEMPERATURE_THRESHOLD: 32.0, ATTR_HIGH_TEMPERATURE_THRESHOLD: 77.0, ATTR_LOW_TEMPERATURE_STATE: { "on": True, "targetTemperature": 85, "temperatureUnit": "F", "mode": "heat", "fanLevel": "low", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", }, ATTR_HIGH_TEMPERATURE_STATE: { "on": True, "targetTemperature": 65, "temperatureUnit": "F", "mode": "cool", "fanLevel": "high", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", }, ATTR_SMART_TYPE: "temperature", }, blocking=True, ) mock_client.async_get_devices_data.return_value.parsed["ABC999111"].smart_on = True mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].smart_type = "temperature" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].smart_low_temp_threshold = 0 mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].smart_high_temp_threshold = 25 mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].smart_low_state = { "on": True, "targetTemperature": 85, "temperatureUnit": "F", "mode": "heat", "fanLevel": "low", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", } mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].smart_high_state = { "on": True, "targetTemperature": 65, "temperatureUnit": "F", "mode": "cool", "fanLevel": "high", "swing": "stopped", "horizontalSwing": "stopped", "light": "on", } freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() assert hass.states.get("switch.hallway_climate_react").state == STATE_ON assert ( hass.states.get("sensor.hallway_climate_react_low_temperature_threshold").state == "0" ) assert ( hass.states.get("sensor.hallway_climate_react_high_temperature_threshold").state == "25" ) assert hass.states.get("sensor.hallway_climate_react_type").state == "temperature" @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_climate_full_ac_state( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate Full AC state service.""" freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") assert state.state == HVACMode.HEAT with pytest.raises( MultipleInvalid, ): await hass.services.async_call( DOMAIN, SERVICE_FULL_STATE, { ATTR_ENTITY_ID: state.entity_id, ATTR_TARGET_TEMPERATURE: 22, }, blocking=True, ) mock_client.async_set_ac_states.return_value = {"result": {"status": "Success"}} await hass.services.async_call( DOMAIN, SERVICE_FULL_STATE, { ATTR_ENTITY_ID: state.entity_id, ATTR_MODE: "cool", ATTR_TARGET_TEMPERATURE: 22, ATTR_FAN_MODE: "high", ATTR_SWING_MODE: "stopped", ATTR_HORIZONTAL_SWING_MODE: "stopped", ATTR_LIGHT: "on", }, blocking=True, ) mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].hvac_mode = "cool" mock_client.async_get_devices_data.return_value.parsed["ABC999111"].device_on = True mock_client.async_get_devices_data.return_value.parsed["ABC999111"].target_temp = 22 mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].fan_mode = "high" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].swing_mode = "stopped" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].horizontal_swing_mode = "stopped" mock_client.async_get_devices_data.return_value.parsed[ "ABC999111" ].light_mode = "on" freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") assert state.state == HVACMode.COOL assert state.attributes["temperature"] == 22 async def test_climate_fan_mode_and_swing_mode_not_supported( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, ) -> None: """Test the Sensibo climate fan_mode and swing_mode not supported is raising error.""" state = hass.states.get("climate.hallway") assert state.attributes["fan_mode"] == "high" assert state.attributes["swing_mode"] == "stopped" with pytest.raises(ServiceValidationError): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_SWING_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_SWING_MODE: "faulty_swing_mode"}, blocking=True, ) with pytest.raises(ServiceValidationError): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_FAN_MODE, {ATTR_ENTITY_ID: state.entity_id, ATTR_FAN_MODE: "faulty_fan_mode"}, blocking=True, ) freezer.tick(timedelta(minutes=5)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.hallway") assert state.attributes["fan_mode"] == "high" assert state.attributes["swing_mode"] == "stopped" async def test_climate_get_device_capabilities( hass: HomeAssistant, load_int: ConfigEntry, mock_client: MagicMock, freezer: FrozenDateTimeFactory, snapshot: SnapshotAssertion, ) -> None: """Test the Sensibo climate Get device capabilitites service.""" response = await hass.services.async_call( DOMAIN, SERVICE_GET_DEVICE_CAPABILITIES, {ATTR_ENTITY_ID: "climate.hallway", ATTR_HVAC_MODE: "heat"}, blocking=True, return_response=True, ) assert response == snapshot with pytest.raises( ServiceValidationError, match="The entity does not support the chosen mode" ): await hass.services.async_call( DOMAIN, SERVICE_GET_DEVICE_CAPABILITIES, {ATTR_ENTITY_ID: "climate.hallway", ATTR_HVAC_MODE: "heat_cool"}, blocking=True, return_response=True, )