diff --git a/homeassistant/components/smartthings/button.py b/homeassistant/components/smartthings/button.py index e052569c3c6..61aaeab13f6 100644 --- a/homeassistant/components/smartthings/button.py +++ b/homeassistant/components/smartthings/button.py @@ -3,16 +3,18 @@ from __future__ import annotations from dataclasses import dataclass +from typing import Any -from pysmartthings import Capability, Command, SmartThings +from pysmartthings import Attribute, Capability, Category, Command, SmartThings from homeassistant.components.button import ButtonEntity, ButtonEntityDescription from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from . import FullDevice, SmartThingsConfigEntry -from .const import MAIN +from .const import DOMAIN, MAIN from .entity import SmartThingsEntity @@ -22,7 +24,11 @@ class SmartThingsButtonDescription(ButtonEntityDescription): key: Capability command: Command + command_identifier: str | None = None components: list[str] | None = None + argument: int | str | list[Any] | dict[str, Any] | None = None + requires_remote_control_status: bool = False + requires_dishwasher_machine_state: set[str] | None = None CAPABILITIES_TO_BUTTONS: dict[Capability | str, SmartThingsButtonDescription] = { @@ -53,6 +59,50 @@ CAPABILITIES_TO_BUTTONS: dict[Capability | str, SmartThingsButtonDescription] = } +DISHWASHER_OPERATION_COMMANDS_TO_BUTTONS: dict[ + Command | str, SmartThingsButtonDescription +] = { + Command.CANCEL: SmartThingsButtonDescription( + key=Capability.SAMSUNG_CE_DISHWASHER_OPERATION, + translation_key="cancel", + command_identifier="drain", + command=Command.CANCEL, + argument=[True], + requires_remote_control_status=True, + ), + Command.PAUSE: SmartThingsButtonDescription( + key=Capability.SAMSUNG_CE_DISHWASHER_OPERATION, + translation_key="pause", + command=Command.PAUSE, + requires_remote_control_status=True, + requires_dishwasher_machine_state={"run"}, + ), + Command.RESUME: SmartThingsButtonDescription( + key=Capability.SAMSUNG_CE_DISHWASHER_OPERATION, + translation_key="resume", + command=Command.RESUME, + requires_remote_control_status=True, + requires_dishwasher_machine_state={"pause"}, + ), + Command.START: SmartThingsButtonDescription( + key=Capability.SAMSUNG_CE_DISHWASHER_OPERATION, + translation_key="start", + command=Command.START, + requires_remote_control_status=True, + requires_dishwasher_machine_state={"stop"}, + ), +} + +DISHWASHER_CANCEL_AND_DRAIN_BUTTON = SmartThingsButtonDescription( + key=Capability.CUSTOM_SUPPORTED_OPTIONS, + translation_key="cancel_and_drain", + command_identifier="89", + command=Command.SET_COURSE, + argument="89", + requires_remote_control_status=True, +) + + async def async_setup_entry( hass: HomeAssistant, entry: SmartThingsConfigEntry, @@ -60,13 +110,41 @@ async def async_setup_entry( ) -> None: """Add button entities for a config entry.""" entry_data = entry.runtime_data - async_add_entities( - SmartThingsButtonEntity(entry_data.client, device, description, component) + entities: list[SmartThingsEntity] = [] + entities.extend( + SmartThingsButtonEntity( + entry_data.client, device, description, Capability(capability), component + ) for capability, description in CAPABILITIES_TO_BUTTONS.items() for device in entry_data.devices.values() for component in description.components or [MAIN] if component in device.status and capability in device.status[component] ) + entities.extend( + SmartThingsButtonEntity( + entry_data.client, + device, + description, + Capability.SAMSUNG_CE_DISHWASHER_OPERATION, + ) + for device in entry_data.devices.values() + if Capability.SAMSUNG_CE_DISHWASHER_OPERATION in device.status[MAIN] + for description in DISHWASHER_OPERATION_COMMANDS_TO_BUTTONS.values() + ) + entities.extend( + SmartThingsButtonEntity( + entry_data.client, + device, + DISHWASHER_CANCEL_AND_DRAIN_BUTTON, + Capability.CUSTOM_SUPPORTED_OPTIONS, + ) + for device in entry_data.devices.values() + if ( + device.device.components[MAIN].manufacturer_category == Category.DISHWASHER + and Capability.CUSTOM_SUPPORTED_OPTIONS in device.status[MAIN] + ) + ) + async_add_entities(entities) class SmartThingsButtonEntity(SmartThingsEntity, ButtonEntity): @@ -79,16 +157,53 @@ class SmartThingsButtonEntity(SmartThingsEntity, ButtonEntity): client: SmartThings, device: FullDevice, entity_description: SmartThingsButtonDescription, - component: str, + capability: Capability, + component: str = MAIN, ) -> None: """Initialize the instance.""" - super().__init__(client, device, set(), component=component) + capabilities = set() + if entity_description.requires_remote_control_status: + capabilities.add(Capability.REMOTE_CONTROL_STATUS) + if entity_description.requires_dishwasher_machine_state: + capabilities.add(Capability.DISHWASHER_OPERATING_STATE) + super().__init__(client, device, capabilities) self.entity_description = entity_description + self.button_capability = capability self._attr_unique_id = f"{device.device.device_id}_{component}_{entity_description.key}_{entity_description.command}" + if entity_description.command_identifier is not None: + self._attr_unique_id += f"_{entity_description.command_identifier}" async def async_press(self) -> None: """Press the button.""" + self._validate_before_execute() await self.execute_device_command( - self.entity_description.key, + self.button_capability, self.entity_description.command, + self.entity_description.argument, ) + + def _validate_before_execute(self) -> None: + """Validate that the command can be executed.""" + if ( + self.entity_description.requires_remote_control_status + and self.get_attribute_value( + Capability.REMOTE_CONTROL_STATUS, Attribute.REMOTE_CONTROL_ENABLED + ) + == "false" + ): + raise ServiceValidationError( + translation_domain=DOMAIN, translation_key="remote_control_status" + ) + if ( + self.entity_description.requires_dishwasher_machine_state + and self.get_attribute_value( + Capability.DISHWASHER_OPERATING_STATE, Attribute.MACHINE_STATE + ) + not in self.entity_description.requires_dishwasher_machine_state + ): + state_list = " or ".join( + self.entity_description.requires_dishwasher_machine_state + ) + raise ServiceValidationError( + f"Can only be updated when dishwasher machine state is {state_list}" + ) diff --git a/homeassistant/components/smartthings/icons.json b/homeassistant/components/smartthings/icons.json index 40939b6750e..29754f1cbed 100644 --- a/homeassistant/components/smartthings/icons.json +++ b/homeassistant/components/smartthings/icons.json @@ -27,12 +27,27 @@ } }, "button": { + "cancel": { + "default": "mdi:stop" + }, + "cancel_and_drain": { + "default": "mdi:stop" + }, + "pause": { + "default": "mdi:pause" + }, "reset_hepa_filter": { "default": "mdi:air-filter" }, "reset_water_filter": { "default": "mdi:reload" }, + "resume": { + "default": "mdi:play" + }, + "start": { + "default": "mdi:play" + }, "stop": { "default": "mdi:stop" } diff --git a/homeassistant/components/smartthings/strings.json b/homeassistant/components/smartthings/strings.json index 6629b8c0ac4..3ed558aa5af 100644 --- a/homeassistant/components/smartthings/strings.json +++ b/homeassistant/components/smartthings/strings.json @@ -93,6 +93,15 @@ } }, "button": { + "cancel": { + "name": "Cancel" + }, + "cancel_and_drain": { + "name": "Cancel and drain" + }, + "pause": { + "name": "[%key:common::action::pause%]" + }, "reset_hepa_filter": { "name": "Reset HEPA filter" }, @@ -102,6 +111,12 @@ "reset_water_filter": { "name": "Reset water filter" }, + "resume": { + "name": "Resume" + }, + "start": { + "name": "[%key:common::action::start%]" + }, "stop": { "name": "[%key:common::action::stop%]" } @@ -1009,6 +1024,9 @@ "exceptions": { "oauth2_implementation_unavailable": { "message": "[%key:common::exceptions::oauth2_implementation_unavailable::message%]" + }, + "remote_control_status": { + "message": "Can only be changed when remote control is enabled" } }, "issues": { diff --git a/tests/components/smartthings/snapshots/test_button.ambr b/tests/components/smartthings/snapshots/test_button.ambr index b6e7d64f2e2..e6ff9593013 100644 --- a/tests/components/smartthings/snapshots/test_button.ambr +++ b/tests/components/smartthings/snapshots/test_button.ambr @@ -549,6 +549,506 @@ 'state': 'unknown', }) # --- +# name: test_all_entities[da_wm_dw_000001][button.dishwasher_cancel-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.dishwasher_cancel', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Cancel', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Cancel', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'cancel', + 'unique_id': 'f36dc7ce-cac0-0667-dc14-a3704eb5e676_main_samsungce.dishwasherOperation_cancel_drain', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[da_wm_dw_000001][button.dishwasher_cancel-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Dishwasher Cancel', + }), + 'context': , + 'entity_id': 'button.dishwasher_cancel', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_all_entities[da_wm_dw_000001][button.dishwasher_cancel_and_drain-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.dishwasher_cancel_and_drain', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Cancel and drain', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Cancel and drain', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'cancel_and_drain', + 'unique_id': 'f36dc7ce-cac0-0667-dc14-a3704eb5e676_main_custom.supportedOptions_setCourse_89', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[da_wm_dw_000001][button.dishwasher_cancel_and_drain-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Dishwasher Cancel and drain', + }), + 'context': , + 'entity_id': 'button.dishwasher_cancel_and_drain', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_all_entities[da_wm_dw_000001][button.dishwasher_pause-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.dishwasher_pause', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Pause', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Pause', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'pause', + 'unique_id': 'f36dc7ce-cac0-0667-dc14-a3704eb5e676_main_samsungce.dishwasherOperation_pause', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[da_wm_dw_000001][button.dishwasher_pause-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Dishwasher Pause', + }), + 'context': , + 'entity_id': 'button.dishwasher_pause', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_all_entities[da_wm_dw_000001][button.dishwasher_resume-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.dishwasher_resume', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Resume', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Resume', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'resume', + 'unique_id': 'f36dc7ce-cac0-0667-dc14-a3704eb5e676_main_samsungce.dishwasherOperation_resume', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[da_wm_dw_000001][button.dishwasher_resume-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Dishwasher Resume', + }), + 'context': , + 'entity_id': 'button.dishwasher_resume', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_all_entities[da_wm_dw_000001][button.dishwasher_start-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.dishwasher_start', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Start', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Start', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'start', + 'unique_id': 'f36dc7ce-cac0-0667-dc14-a3704eb5e676_main_samsungce.dishwasherOperation_start', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[da_wm_dw_000001][button.dishwasher_start-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Dishwasher Start', + }), + 'context': , + 'entity_id': 'button.dishwasher_start', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_all_entities[da_wm_dw_01011][button.dishwasher_1_cancel-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.dishwasher_1_cancel', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Cancel', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Cancel', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'cancel', + 'unique_id': '7ff318f3-3772-524d-3c9f-72fcd26413ed_main_samsungce.dishwasherOperation_cancel_drain', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[da_wm_dw_01011][button.dishwasher_1_cancel-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Dishwasher 1 Cancel', + }), + 'context': , + 'entity_id': 'button.dishwasher_1_cancel', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_all_entities[da_wm_dw_01011][button.dishwasher_1_cancel_and_drain-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.dishwasher_1_cancel_and_drain', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Cancel and drain', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Cancel and drain', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'cancel_and_drain', + 'unique_id': '7ff318f3-3772-524d-3c9f-72fcd26413ed_main_custom.supportedOptions_setCourse_89', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[da_wm_dw_01011][button.dishwasher_1_cancel_and_drain-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Dishwasher 1 Cancel and drain', + }), + 'context': , + 'entity_id': 'button.dishwasher_1_cancel_and_drain', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_all_entities[da_wm_dw_01011][button.dishwasher_1_pause-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.dishwasher_1_pause', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Pause', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Pause', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'pause', + 'unique_id': '7ff318f3-3772-524d-3c9f-72fcd26413ed_main_samsungce.dishwasherOperation_pause', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[da_wm_dw_01011][button.dishwasher_1_pause-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Dishwasher 1 Pause', + }), + 'context': , + 'entity_id': 'button.dishwasher_1_pause', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_all_entities[da_wm_dw_01011][button.dishwasher_1_resume-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.dishwasher_1_resume', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Resume', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Resume', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'resume', + 'unique_id': '7ff318f3-3772-524d-3c9f-72fcd26413ed_main_samsungce.dishwasherOperation_resume', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[da_wm_dw_01011][button.dishwasher_1_resume-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Dishwasher 1 Resume', + }), + 'context': , + 'entity_id': 'button.dishwasher_1_resume', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_all_entities[da_wm_dw_01011][button.dishwasher_1_start-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': None, + 'entity_id': 'button.dishwasher_1_start', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Start', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Start', + 'platform': 'smartthings', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'start', + 'unique_id': '7ff318f3-3772-524d-3c9f-72fcd26413ed_main_samsungce.dishwasherOperation_start', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[da_wm_dw_01011][button.dishwasher_1_start-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Dishwasher 1 Start', + }), + 'context': , + 'entity_id': 'button.dishwasher_1_start', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- # name: test_all_entities[da_wm_mf_01001][button.filtro_in_microfibra_reset_water_filter-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/smartthings/test_button.py b/tests/components/smartthings/test_button.py index daacee7def1..065d6d7349d 100644 --- a/tests/components/smartthings/test_button.py +++ b/tests/components/smartthings/test_button.py @@ -3,7 +3,7 @@ from unittest.mock import AsyncMock from freezegun.api import FrozenDateTimeFactory -from pysmartthings import Capability, Command +from pysmartthings import Attribute, Capability, Command from pysmartthings.models import HealthStatus import pytest from syrupy.assertion import SnapshotAssertion @@ -17,9 +17,15 @@ from homeassistant.const import ( Platform, ) from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers import entity_registry as er -from . import setup_integration, snapshot_smartthings_entities, trigger_health_update +from . import ( + set_attribute_value, + setup_integration, + snapshot_smartthings_entities, + trigger_health_update, +) from tests.common import MockConfigEntry @@ -95,3 +101,65 @@ async def test_availability_at_start( """Test unavailable at boot.""" await setup_integration(hass, mock_config_entry) assert hass.states.get("button.microwave_stop").state == STATE_UNAVAILABLE + + +@pytest.mark.parametrize("device_fixture", ["da_wm_dw_01011"]) +async def test_turn_on_without_remote_control( + hass: HomeAssistant, + devices: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test state update.""" + set_attribute_value( + devices, + Capability.REMOTE_CONTROL_STATUS, + Attribute.REMOTE_CONTROL_ENABLED, + "false", + ) + await setup_integration(hass, mock_config_entry) + + with pytest.raises( + ServiceValidationError, + match="Can only be changed when remote control is enabled", + ): + await hass.services.async_call( + BUTTON_DOMAIN, + SERVICE_PRESS, + {ATTR_ENTITY_ID: "button.dishwasher_1_start"}, + blocking=True, + ) + devices.execute_device_command.assert_not_called() + + +@pytest.mark.parametrize("device_fixture", ["da_wm_dw_01011"]) +async def test_turn_on_with_wrong_dishwasher_machine_state( + hass: HomeAssistant, + devices: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test state update.""" + set_attribute_value( + devices, + Capability.REMOTE_CONTROL_STATUS, + Attribute.REMOTE_CONTROL_ENABLED, + "true", + ) + set_attribute_value( + devices, + Capability.DISHWASHER_OPERATING_STATE, + Attribute.MACHINE_STATE, + "run", + ) + await setup_integration(hass, mock_config_entry) + + with pytest.raises( + ServiceValidationError, + match="Can only be updated when dishwasher machine state is stop", + ): + await hass.services.async_call( + BUTTON_DOMAIN, + SERVICE_PRESS, + {ATTR_ENTITY_ID: "button.dishwasher_1_start"}, + blocking=True, + ) + devices.execute_device_command.assert_not_called()