"""Tests for the Plugwise Climate integration.""" from datetime import timedelta from unittest.mock import MagicMock, patch from freezegun.api import FrozenDateTimeFactory from plugwise.exceptions import PlugwiseError 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, ATTR_PRESET_MODE, ATTR_PRESET_MODES, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_STEP, DOMAIN as CLIMATE_DOMAIN, PRESET_AWAY, PRESET_HOME, SERVICE_SET_HVAC_MODE, SERVICE_SET_PRESET_MODE, SERVICE_SET_TEMPERATURE, HVACAction, HVACMode, ) from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, ATTR_TEMPERATURE, ) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from tests.common import MockConfigEntry, async_fire_time_changed HA_PLUGWISE_SMILE_ASYNC_UPDATE = ( "homeassistant.components.plugwise.coordinator.Smile.async_update" ) async def test_adam_climate_entity_attributes( hass: HomeAssistant, mock_smile_adam: MagicMock, init_integration: MockConfigEntry ) -> None: """Test creation of adam climate device environment.""" state = hass.states.get("climate.woonkamer") assert state assert state.state == HVACMode.AUTO assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.AUTO, HVACMode.HEAT] assert ATTR_PRESET_MODES in state.attributes assert "no_frost" in state.attributes[ATTR_PRESET_MODES] assert PRESET_HOME in state.attributes[ATTR_PRESET_MODES] assert state.attributes[ATTR_PRESET_MODE] == PRESET_HOME assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 20.9 assert state.attributes[ATTR_SUPPORTED_FEATURES] == 17 assert state.attributes[ATTR_TEMPERATURE] == 21.5 assert state.attributes[ATTR_MIN_TEMP] == 0.0 assert state.attributes[ATTR_MAX_TEMP] == 35.0 assert state.attributes[ATTR_TARGET_TEMP_STEP] == 0.1 state = hass.states.get("climate.jessie") assert state assert state.state == HVACMode.AUTO assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.AUTO, HVACMode.HEAT] assert ATTR_PRESET_MODES in state.attributes assert "no_frost" in state.attributes[ATTR_PRESET_MODES] assert PRESET_HOME in state.attributes[ATTR_PRESET_MODES] assert state.attributes[ATTR_PRESET_MODE] == "asleep" assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 17.2 assert state.attributes[ATTR_TEMPERATURE] == 15.0 assert state.attributes[ATTR_MIN_TEMP] == 0.0 assert state.attributes[ATTR_MAX_TEMP] == 35.0 assert state.attributes[ATTR_TARGET_TEMP_STEP] == 0.1 async def test_adam_2_climate_entity_attributes( hass: HomeAssistant, mock_smile_adam_2: MagicMock, init_integration: MockConfigEntry ) -> None: """Test creation of adam climate device environment.""" state = hass.states.get("climate.living_room") assert state assert state.state == HVACMode.HEAT assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.PREHEATING assert state.attributes[ATTR_HVAC_MODES] == [ HVACMode.OFF, HVACMode.AUTO, HVACMode.HEAT, ] state = hass.states.get("climate.bathroom") assert state assert state.state == HVACMode.AUTO assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE assert state.attributes[ATTR_HVAC_MODES] == [ HVACMode.OFF, HVACMode.AUTO, HVACMode.HEAT, ] async def test_adam_3_climate_entity_attributes( hass: HomeAssistant, mock_smile_adam_3: MagicMock, init_integration: MockConfigEntry, freezer: FrozenDateTimeFactory, ) -> None: """Test creation of adam climate device environment.""" state = hass.states.get("climate.living_room") assert state assert state.state == HVACMode.COOL assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.COOLING assert state.attributes[ATTR_HVAC_MODES] == [ HVACMode.OFF, HVACMode.AUTO, HVACMode.COOL, ] data = mock_smile_adam_3.async_update.return_value data.devices["da224107914542988a88561b4452b0f6"]["select_regulation_mode"] = ( "heating" ) data.devices["f2bf9048bef64cc5b6d5110154e33c81"]["control_state"] = ( HVACAction.HEATING ) data.devices["056ee145a816487eaa69243c3280f8bf"]["binary_sensors"][ "cooling_state" ] = False data.devices["056ee145a816487eaa69243c3280f8bf"]["binary_sensors"][ "heating_state" ] = True with patch(HA_PLUGWISE_SMILE_ASYNC_UPDATE, return_value=data): freezer.tick(timedelta(minutes=1)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.living_room") assert state assert state.state == HVACMode.HEAT assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING assert state.attributes[ATTR_HVAC_MODES] == [ HVACMode.OFF, HVACMode.AUTO, HVACMode.HEAT, ] data = mock_smile_adam_3.async_update.return_value data.devices["da224107914542988a88561b4452b0f6"]["select_regulation_mode"] = ( "cooling" ) data.devices["f2bf9048bef64cc5b6d5110154e33c81"]["control_state"] = ( HVACAction.COOLING ) data.devices["056ee145a816487eaa69243c3280f8bf"]["binary_sensors"][ "cooling_state" ] = True data.devices["056ee145a816487eaa69243c3280f8bf"]["binary_sensors"][ "heating_state" ] = False with patch(HA_PLUGWISE_SMILE_ASYNC_UPDATE, return_value=data): freezer.tick(timedelta(minutes=1)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.living_room") assert state assert state.state == HVACMode.COOL assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.COOLING assert state.attributes[ATTR_HVAC_MODES] == [ HVACMode.OFF, HVACMode.AUTO, HVACMode.COOL, ] async def test_adam_climate_adjust_negative_testing( hass: HomeAssistant, mock_smile_adam: MagicMock, init_integration: MockConfigEntry ) -> None: """Test PlugwiseError exception.""" mock_smile_adam.set_temperature.side_effect = PlugwiseError with pytest.raises(HomeAssistantError): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: "climate.woonkamer", ATTR_TEMPERATURE: 25}, blocking=True, ) async def test_adam_climate_entity_climate_changes( hass: HomeAssistant, mock_smile_adam: MagicMock, init_integration: MockConfigEntry ) -> None: """Test handling of user requests in adam climate device environment.""" await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: "climate.woonkamer", ATTR_TEMPERATURE: 25}, blocking=True, ) assert mock_smile_adam.set_temperature.call_count == 1 mock_smile_adam.set_temperature.assert_called_with( "c50f167537524366a5af7aa3942feb1e", {"setpoint": 25.0} ) await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, { ATTR_ENTITY_ID: "climate.woonkamer", ATTR_HVAC_MODE: HVACMode.HEAT, ATTR_TEMPERATURE: 25, }, blocking=True, ) assert mock_smile_adam.set_temperature.call_count == 2 mock_smile_adam.set_temperature.assert_called_with( "c50f167537524366a5af7aa3942feb1e", {"setpoint": 25.0} ) with pytest.raises(ServiceValidationError, match="Accepted range"): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, {ATTR_ENTITY_ID: "climate.woonkamer", ATTR_TEMPERATURE: 150}, blocking=True, ) await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_PRESET_MODE, {ATTR_ENTITY_ID: "climate.woonkamer", ATTR_PRESET_MODE: PRESET_AWAY}, blocking=True, ) assert mock_smile_adam.set_preset.call_count == 1 mock_smile_adam.set_preset.assert_called_with( "c50f167537524366a5af7aa3942feb1e", PRESET_AWAY ) await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, {ATTR_ENTITY_ID: "climate.woonkamer", ATTR_HVAC_MODE: HVACMode.HEAT}, blocking=True, ) assert mock_smile_adam.set_schedule_state.call_count == 2 mock_smile_adam.set_schedule_state.assert_called_with( "c50f167537524366a5af7aa3942feb1e", HVACMode.OFF ) with pytest.raises(ServiceValidationError, match="valid modes are"): await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, { ATTR_ENTITY_ID: "climate.jessie", ATTR_HVAC_MODE: HVACMode.DRY, }, blocking=True, ) async def test_adam_climate_off_mode_change( hass: HomeAssistant, mock_smile_adam_4: MagicMock, init_integration: MockConfigEntry, ) -> None: """Test handling of user requests in adam climate device environment.""" state = hass.states.get("climate.slaapkamer") assert state assert state.state == HVACMode.OFF await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, { ATTR_ENTITY_ID: "climate.slaapkamer", ATTR_HVAC_MODE: HVACMode.HEAT, }, blocking=True, ) assert mock_smile_adam_4.set_schedule_state.call_count == 1 assert mock_smile_adam_4.set_regulation_mode.call_count == 1 mock_smile_adam_4.set_regulation_mode.assert_called_with("heating") state = hass.states.get("climate.kinderkamer") assert state assert state.state == HVACMode.HEAT await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, { ATTR_ENTITY_ID: "climate.kinderkamer", ATTR_HVAC_MODE: HVACMode.OFF, }, blocking=True, ) assert mock_smile_adam_4.set_schedule_state.call_count == 1 assert mock_smile_adam_4.set_regulation_mode.call_count == 2 mock_smile_adam_4.set_regulation_mode.assert_called_with("off") state = hass.states.get("climate.logeerkamer") assert state assert state.state == HVACMode.HEAT await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, { ATTR_ENTITY_ID: "climate.logeerkamer", ATTR_HVAC_MODE: HVACMode.HEAT, }, blocking=True, ) assert mock_smile_adam_4.set_schedule_state.call_count == 1 assert mock_smile_adam_4.set_regulation_mode.call_count == 2 async def test_anna_climate_entity_attributes( hass: HomeAssistant, mock_smile_anna: MagicMock, init_integration: MockConfigEntry, ) -> None: """Test creation of anna climate device environment.""" state = hass.states.get("climate.anna") assert state assert state.state == HVACMode.AUTO assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.AUTO, HVACMode.HEAT_COOL] assert "no_frost" in state.attributes[ATTR_PRESET_MODES] assert PRESET_HOME in state.attributes[ATTR_PRESET_MODES] assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 19.3 assert state.attributes[ATTR_PRESET_MODE] == PRESET_HOME assert state.attributes[ATTR_SUPPORTED_FEATURES] == 18 assert state.attributes[ATTR_TARGET_TEMP_HIGH] == 30 assert state.attributes[ATTR_TARGET_TEMP_LOW] == 20.5 assert state.attributes[ATTR_MIN_TEMP] == 4 assert state.attributes[ATTR_MAX_TEMP] == 30 assert state.attributes[ATTR_TARGET_TEMP_STEP] == 0.1 async def test_anna_2_climate_entity_attributes( hass: HomeAssistant, mock_smile_anna_2: MagicMock, init_integration: MockConfigEntry, ) -> None: """Test creation of anna climate device environment.""" state = hass.states.get("climate.anna") assert state assert state.state == HVACMode.AUTO assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.COOLING assert state.attributes[ATTR_HVAC_MODES] == [ HVACMode.AUTO, HVACMode.HEAT_COOL, ] assert state.attributes[ATTR_SUPPORTED_FEATURES] == 18 assert state.attributes[ATTR_TARGET_TEMP_HIGH] == 30 assert state.attributes[ATTR_TARGET_TEMP_LOW] == 20.5 async def test_anna_3_climate_entity_attributes( hass: HomeAssistant, mock_smile_anna_3: MagicMock, init_integration: MockConfigEntry, ) -> None: """Test creation of anna climate device environment.""" state = hass.states.get("climate.anna") assert state assert state.state == HVACMode.AUTO assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE assert state.attributes[ATTR_HVAC_MODES] == [ HVACMode.AUTO, HVACMode.HEAT_COOL, ] async def test_anna_climate_entity_climate_changes( hass: HomeAssistant, mock_smile_anna: MagicMock, init_integration: MockConfigEntry, freezer: FrozenDateTimeFactory, ) -> None: """Test handling of user requests in anna climate device environment.""" await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, { ATTR_ENTITY_ID: "climate.anna", ATTR_TARGET_TEMP_HIGH: 30, ATTR_TARGET_TEMP_LOW: 20, }, blocking=True, ) assert mock_smile_anna.set_temperature.call_count == 1 mock_smile_anna.set_temperature.assert_called_with( "c784ee9fdab44e1395b8dee7d7a497d5", {"setpoint_high": 30.0, "setpoint_low": 20.0}, ) await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_PRESET_MODE, {ATTR_ENTITY_ID: "climate.anna", ATTR_PRESET_MODE: PRESET_AWAY}, blocking=True, ) assert mock_smile_anna.set_preset.call_count == 1 mock_smile_anna.set_preset.assert_called_with( "c784ee9fdab44e1395b8dee7d7a497d5", PRESET_AWAY ) await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, {ATTR_ENTITY_ID: "climate.anna", ATTR_HVAC_MODE: HVACMode.AUTO}, blocking=True, ) # hvac_mode is already auto so not called. assert mock_smile_anna.set_schedule_state.call_count == 0 await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, {ATTR_ENTITY_ID: "climate.anna", ATTR_HVAC_MODE: HVACMode.HEAT_COOL}, blocking=True, ) assert mock_smile_anna.set_schedule_state.call_count == 1 mock_smile_anna.set_schedule_state.assert_called_with( "c784ee9fdab44e1395b8dee7d7a497d5", HVACMode.OFF ) data = mock_smile_anna.async_update.return_value data.devices["3cb70739631c4d17a86b8b12e8a5161b"].pop("available_schedules") with patch(HA_PLUGWISE_SMILE_ASYNC_UPDATE, return_value=data): freezer.tick(timedelta(minutes=1)) async_fire_time_changed(hass) await hass.async_block_till_done() state = hass.states.get("climate.anna") assert state.state == HVACMode.HEAT assert state.attributes[ATTR_HVAC_MODES] == [HVACMode.HEAT_COOL]