diff --git a/homeassistant/components/plugwise/select.py b/homeassistant/components/plugwise/select.py index 5748da37833a..1cd7b7e5b314 100644 --- a/homeassistant/components/plugwise/select.py +++ b/homeassistant/components/plugwise/select.py @@ -9,6 +9,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .const import ( + LOCATION, SELECT_DHW_MODE, SELECT_GATEWAY_MODE, SELECT_REGULATION_MODE, @@ -106,9 +107,12 @@ class PlugwiseSelectEntity(PlugwiseEntity, SelectEntity): self._attr_unique_id = f"{device_id}-{entity_description.key}" self.entity_description = entity_description - self._location = device_id - if (location := self.device.get("location")) is not None: - self._location = location + self._device_or_location = device_id + if ( + self.entity_description.key in (SELECT_SCHEDULE, SELECT_ZONE_PROFILE) + and (location := self.device.get(LOCATION)) is not None + ): + self._device_or_location = location @property @override @@ -127,8 +131,10 @@ class PlugwiseSelectEntity(PlugwiseEntity, SelectEntity): async def async_select_option(self, option: str) -> None: """Change to the selected entity option. - self._location and STATE_ON are required for the thermostat-schedule select. + The appliance ID (= device_id) is required for the dhw_mode select. + The location ID is required for the thermostat schedule and zone_profile selects. + STATE_ON is required for the thermostat schedule select. """ await self.coordinator.api.set_select( - self.entity_description.key, self._location, option, STATE_ON + self.entity_description.key, self._device_or_location, option, STATE_ON ) diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index 040bf596ea1c..0176fc0e4678 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -268,6 +268,34 @@ def mock_smile_anna(chosen_env: str, cooling_present: bool) -> Generator[MagicMo yield api +@pytest.fixture +def mock_smile_anna_loria() -> Generator[MagicMock]: + """Create a Mock Anna-connected-to-Loria-heatpump type for testing.""" + chosen_env = "anna_loria_cooling_active" + data = _read_json(chosen_env, "data") + with patch( + "homeassistant.components.plugwise.coordinator.Smile", autospec=True + ) as api_mock: + api = api_mock.return_value + + api.async_update.return_value = data + api.connect.return_value = Version("4.3.8") + api.cooling_present = True + api.gateway_id = "9ff0569b4984459fb243af64c0901894" + api.heater_id = "bfb5ee0a88e14e5f97bfa725a760cc49" + api.reboot = True + api.smile = build_smile( + hostname="smile98765", + model="Gateway", + model_id="smile_thermo", + name="Smile Anna", + type="thermostat", + version="4.3.8", + ) + + yield api + + @pytest.fixture def mock_smile_anna_p1() -> Generator[MagicMock]: """Create a Mock Anna-P1 type for testing.""" diff --git a/tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json b/tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json new file mode 100644 index 000000000000..8b6c7341e3f7 --- /dev/null +++ b/tests/components/plugwise/fixtures/anna_loria_cooling_active/data.json @@ -0,0 +1,96 @@ +{ + "582dfbdace4d4aeb832923ce7d1ddda0": { + "active_preset": "home", + "available_schedules": ["Winter", "Test ", "off"], + "climate_mode": "auto", + "control_state": "cooling", + "dev_class": "thermostat", + "firmware": "2018-02-08T11:15:53+01:00", + "hardware": "6539-1301-5002", + "location": "15da035090b847e7a21f93e08c015ebc", + "model": "ThermoTouch", + "name": "Anna", + "preset_modes": ["away", "vacation", "no_frost", "home", "asleep"], + "select_schedule": "Winter", + "sensors": { + "illuminance": 45.0, + "setpoint_high": 23.5, + "setpoint_low": 4.0, + "temperature": 24.1 + }, + "temperature_offset": { + "lower_bound": -2.0, + "resolution": 0.1, + "setpoint": 0.0, + "upper_bound": 2.0 + }, + "thermostat": { + "lower_bound": 4.0, + "resolution": 0.1, + "setpoint_high": 23.5, + "setpoint_low": 4.0, + "upper_bound": 30.0 + }, + "vendor": "Plugwise" + }, + "9ff0569b4984459fb243af64c0901894": { + "binary_sensors": { + "plugwise_notification": false + }, + "dev_class": "gateway", + "firmware": "4.3.8", + "hardware": "AME Smile 2.0 board", + "location": "674b657c138a41a291d315d7471deb06", + "mac_address": "C493000278E2", + "model": "Gateway", + "model_id": "smile_thermo", + "name": "Smile Anna", + "notifications": {}, + "sensors": { + "outdoor_temperature": 15.5 + }, + "vendor": "Plugwise" + }, + "bfb5ee0a88e14e5f97bfa725a760cc49": { + "available": true, + "binary_sensors": { + "cooling_enabled": true, + "cooling_state": true, + "dhw_state": false, + "flame_state": false, + "heating_state": false + }, + "dev_class": "heater_central", + "dhw_modes": ["off", "auto", "boost", "eco", "comfort"], + "location": "674b657c138a41a291d315d7471deb06", + "max_dhw_temperature": { + "lower_bound": 35.0, + "resolution": 0.01, + "setpoint": 53.0, + "upper_bound": 60.0 + }, + "maximum_boiler_temperature": { + "lower_bound": 25.0, + "resolution": 0.01, + "setpoint": 40.0, + "upper_bound": 45.0 + }, + "model": "Generic heater/cooler", + "model_id": "173", + "name": "OpenTherm", + "select_dhw_mode": "auto", + "sensors": { + "dhw_temperature": 52.9, + "intended_boiler_temperature": 0.0, + "modulation_level": 100, + "outdoor_air_temperature": 17.2, + "return_temperature": 26.3, + "water_temperature": 25.3 + }, + "switches": { + "cooling_ena_switch": true, + "dhw_cm_switch": true + }, + "vendor": "Atlantic" + } +} diff --git a/tests/components/plugwise/snapshots/test_select.ambr b/tests/components/plugwise/snapshots/test_select.ambr index e480b2268632..98fbdafc7f5f 100644 --- a/tests/components/plugwise/snapshots/test_select.ambr +++ b/tests/components/plugwise/snapshots/test_select.ambr @@ -645,3 +645,129 @@ 'state': 'GF7 Woonkamer', }) # --- +# name: test_anna_entities_with_dhw_mode_select[platforms0-True-anna_loria_cooling_active][select.anna_thermostat_schedule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : list([ + 'Winter', + 'Test ', + 'off', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'select', + 'entity_category': None, + 'entity_id': 'select.anna_thermostat_schedule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Thermostat schedule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Thermostat schedule', + 'platform': 'plugwise', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'select_schedule', + 'unique_id': '582dfbdace4d4aeb832923ce7d1ddda0-select_schedule', + 'unit_of_measurement': None, + }) +# --- +# name: test_anna_entities_with_dhw_mode_select[platforms0-True-anna_loria_cooling_active][select.anna_thermostat_schedule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'Anna Thermostat schedule', + : list([ + 'Winter', + 'Test ', + 'off', + ]), + }), + 'context': , + 'entity_id': 'select.anna_thermostat_schedule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'Winter', + }) +# --- +# name: test_anna_entities_with_dhw_mode_select[platforms0-True-anna_loria_cooling_active][select.opentherm_dhw_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : list([ + 'off', + 'auto', + 'boost', + 'eco', + 'comfort', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'select', + 'entity_category': , + 'entity_id': 'select.opentherm_dhw_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DHW mode', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'DHW mode', + 'platform': 'plugwise', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'select_dhw_mode', + 'unique_id': 'bfb5ee0a88e14e5f97bfa725a760cc49-select_dhw_mode', + 'unit_of_measurement': None, + }) +# --- +# name: test_anna_entities_with_dhw_mode_select[platforms0-True-anna_loria_cooling_active][select.opentherm_dhw_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'OpenTherm DHW mode', + : list([ + 'off', + 'auto', + 'boost', + 'eco', + 'comfort', + ]), + }), + 'context': , + 'entity_id': 'select.opentherm_dhw_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'auto', + }) +# --- diff --git a/tests/components/plugwise/test_select.py b/tests/components/plugwise/test_select.py index 75981e7badd4..a6fc57ac6272 100644 --- a/tests/components/plugwise/test_select.py +++ b/tests/components/plugwise/test_select.py @@ -6,6 +6,8 @@ import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.components.plugwise.const import ( + SELECT_DHW_MODE, + SELECT_GATEWAY_MODE, SELECT_REGULATION_MODE, SELECT_SCHEDULE, SELECT_ZONE_PROFILE, @@ -97,11 +99,28 @@ async def test_adam_select_regulation_mode( assert mock_smile_adam_heat_cool.set_select.call_count == 1 mock_smile_adam_heat_cool.set_select.assert_called_with( SELECT_REGULATION_MODE, - "bc93488efab249e5bc54fd7e175a6f91", + "da224107914542988a88561b4452b0f6", "heating", "on", ) + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: "select.adam_gateway_mode", + ATTR_OPTION: "vacation", + }, + blocking=True, + ) + assert mock_smile_adam_heat_cool.set_select.call_count == 2 + mock_smile_adam_heat_cool.set_select.assert_called_with( + SELECT_GATEWAY_MODE, + "da224107914542988a88561b4452b0f6", + "vacation", + "on", + ) + @pytest.mark.parametrize("chosen_env", ["m_adam_heating"], indirect=True) @pytest.mark.parametrize("cooling_present", [True], indirect=True) @@ -155,3 +174,42 @@ async def test_anna_select_unavailable_schedule_mode( }, blocking=True, ) + + +@pytest.mark.parametrize("chosen_env", ["anna_loria_cooling_active"], indirect=True) +@pytest.mark.parametrize("cooling_present", [True], indirect=True) +@pytest.mark.parametrize("platforms", [(SELECT_DOMAIN,)]) +@pytest.mark.usefixtures("entity_registry_enabled_by_default") +async def test_anna_entities_with_dhw_mode_select( + hass: HomeAssistant, + mock_smile_anna: MagicMock, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + setup_platform: MockConfigEntry, +) -> None: + """Test Anna select snapshot with multiple dhw_modes.""" + await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id) + + +async def test_anna_select_dhw_mode( + hass: HomeAssistant, + mock_smile_anna_loria: MagicMock, + init_integration: MockConfigEntry, +) -> None: + """Test changing the dhw_mode select.""" + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: "select.opentherm_dhw_mode", + ATTR_OPTION: "boost", + }, + blocking=True, + ) + assert mock_smile_anna_loria.set_select.call_count == 1 + mock_smile_anna_loria.set_select.assert_called_with( + SELECT_DHW_MODE, + "bfb5ee0a88e14e5f97bfa725a760cc49", + "boost", + "on", + )