diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index cf82836cbec..0dc4d19ba36 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -77,19 +77,19 @@ DEFAULT_NAME = "Vacuum cleaner robot" class VacuumEntityFeature(IntFlag): """Supported features of the vacuum entity.""" - TURN_ON = 1 - TURN_OFF = 2 + TURN_ON = 1 # Deprecated, not supported by StateVacuumEntity + TURN_OFF = 2 # Deprecated, not supported by StateVacuumEntity PAUSE = 4 STOP = 8 RETURN_HOME = 16 FAN_SPEED = 32 BATTERY = 64 - STATUS = 128 + STATUS = 128 # Deprecated, not supported by StateVacuumEntity SEND_COMMAND = 256 LOCATE = 512 CLEAN_SPOT = 1024 MAP = 2048 - STATE = 4096 + STATE = 4096 # Must be set by vacuum platforms derived from StateVacuumEntity START = 8192 @@ -127,24 +127,73 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: await component.async_setup(config) - component.async_register_entity_service(SERVICE_TURN_ON, {}, "async_turn_on") - component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off") - component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle") component.async_register_entity_service( - SERVICE_START_PAUSE, {}, "async_start_pause" + SERVICE_TURN_ON, + {}, + "async_turn_on", + [VacuumEntityFeature.TURN_ON], ) - component.async_register_entity_service(SERVICE_START, {}, "async_start") - component.async_register_entity_service(SERVICE_PAUSE, {}, "async_pause") component.async_register_entity_service( - SERVICE_RETURN_TO_BASE, {}, "async_return_to_base" + SERVICE_TURN_OFF, + {}, + "async_turn_off", + [VacuumEntityFeature.TURN_OFF], + ) + component.async_register_entity_service( + SERVICE_TOGGLE, + {}, + "async_toggle", + [VacuumEntityFeature.TURN_OFF | VacuumEntityFeature.TURN_ON], + ) + # start_pause is a legacy service, only supported by VacuumEntity, and only needs + # VacuumEntityFeature.PAUSE + component.async_register_entity_service( + SERVICE_START_PAUSE, + {}, + "async_start_pause", + [VacuumEntityFeature.PAUSE], + ) + component.async_register_entity_service( + SERVICE_START, + {}, + "async_start", + [VacuumEntityFeature.START], + ) + component.async_register_entity_service( + SERVICE_PAUSE, + {}, + "async_pause", + [VacuumEntityFeature.PAUSE], + ) + component.async_register_entity_service( + SERVICE_RETURN_TO_BASE, + {}, + "async_return_to_base", + [VacuumEntityFeature.RETURN_HOME], + ) + component.async_register_entity_service( + SERVICE_CLEAN_SPOT, + {}, + "async_clean_spot", + [VacuumEntityFeature.CLEAN_SPOT], + ) + component.async_register_entity_service( + SERVICE_LOCATE, + {}, + "async_locate", + [VacuumEntityFeature.LOCATE], + ) + component.async_register_entity_service( + SERVICE_STOP, + {}, + "async_stop", + [VacuumEntityFeature.STOP], ) - component.async_register_entity_service(SERVICE_CLEAN_SPOT, {}, "async_clean_spot") - component.async_register_entity_service(SERVICE_LOCATE, {}, "async_locate") - component.async_register_entity_service(SERVICE_STOP, {}, "async_stop") component.async_register_entity_service( SERVICE_SET_FAN_SPEED, {vol.Required(ATTR_FAN_SPEED): cv.string}, "async_set_fan_speed", + [VacuumEntityFeature.FAN_SPEED], ) component.async_register_entity_service( SERVICE_SEND_COMMAND, @@ -153,6 +202,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: vol.Optional(ATTR_PARAMS): vol.Any(dict, cv.ensure_list), }, "async_send_command", + [VacuumEntityFeature.SEND_COMMAND], ) return True diff --git a/homeassistant/components/vacuum/reproduce_state.py b/homeassistant/components/vacuum/reproduce_state.py index fbcc97445c8..4d0d6b4b12c 100644 --- a/homeassistant/components/vacuum/reproduce_state.py +++ b/homeassistant/components/vacuum/reproduce_state.py @@ -37,8 +37,8 @@ VALID_STATES_STATE = { STATE_CLEANING, STATE_DOCKED, STATE_IDLE, - STATE_RETURNING, STATE_PAUSED, + STATE_RETURNING, } diff --git a/tests/components/demo/test_vacuum.py b/tests/components/demo/test_vacuum.py index bc003c6e27b..4f977436055 100644 --- a/tests/components/demo/test_vacuum.py +++ b/tests/components/demo/test_vacuum.py @@ -37,6 +37,7 @@ from homeassistant.const import ( STATE_ON, ) from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from homeassistant.setup import async_setup_component from homeassistant.util import dt as dt_util @@ -201,42 +202,39 @@ async def test_unsupported_methods(hass: HomeAssistant) -> None: await hass.async_block_till_done() assert vacuum.is_on(hass, ENTITY_VACUUM_NONE) - await common.async_turn_off(hass, ENTITY_VACUUM_NONE) - assert vacuum.is_on(hass, ENTITY_VACUUM_NONE) + with pytest.raises(HomeAssistantError): + await common.async_turn_off(hass, ENTITY_VACUUM_NONE) - await common.async_stop(hass, ENTITY_VACUUM_NONE) - assert vacuum.is_on(hass, ENTITY_VACUUM_NONE) + with pytest.raises(HomeAssistantError): + await common.async_stop(hass, ENTITY_VACUUM_NONE) hass.states.async_set(ENTITY_VACUUM_NONE, STATE_OFF) await hass.async_block_till_done() assert not vacuum.is_on(hass, ENTITY_VACUUM_NONE) - await common.async_turn_on(hass, ENTITY_VACUUM_NONE) - assert not vacuum.is_on(hass, ENTITY_VACUUM_NONE) + with pytest.raises(HomeAssistantError): + await common.async_turn_on(hass, ENTITY_VACUUM_NONE) - await common.async_toggle(hass, ENTITY_VACUUM_NONE) - assert not vacuum.is_on(hass, ENTITY_VACUUM_NONE) + with pytest.raises(HomeAssistantError): + await common.async_toggle(hass, ENTITY_VACUUM_NONE) # Non supported methods: - await common.async_start_pause(hass, ENTITY_VACUUM_NONE) - assert not vacuum.is_on(hass, ENTITY_VACUUM_NONE) + with pytest.raises(HomeAssistantError): + await common.async_start_pause(hass, ENTITY_VACUUM_NONE) - await common.async_locate(hass, ENTITY_VACUUM_NONE) - state = hass.states.get(ENTITY_VACUUM_NONE) - assert state.attributes.get(ATTR_STATUS) is None + with pytest.raises(HomeAssistantError): + await common.async_locate(hass, ENTITY_VACUUM_NONE) - await common.async_return_to_base(hass, ENTITY_VACUUM_NONE) - state = hass.states.get(ENTITY_VACUUM_NONE) - assert state.attributes.get(ATTR_STATUS) is None + with pytest.raises(HomeAssistantError): + await common.async_return_to_base(hass, ENTITY_VACUUM_NONE) - await common.async_set_fan_speed(hass, FAN_SPEEDS[-1], entity_id=ENTITY_VACUUM_NONE) - state = hass.states.get(ENTITY_VACUUM_NONE) - assert state.attributes.get(ATTR_FAN_SPEED) != FAN_SPEEDS[-1] + with pytest.raises(HomeAssistantError): + await common.async_set_fan_speed( + hass, FAN_SPEEDS[-1], entity_id=ENTITY_VACUUM_NONE + ) - await common.async_clean_spot(hass, entity_id=ENTITY_VACUUM_BASIC) - state = hass.states.get(ENTITY_VACUUM_BASIC) - assert "spot" not in state.attributes.get(ATTR_STATUS) - assert state.state == STATE_OFF + with pytest.raises(HomeAssistantError): + await common.async_clean_spot(hass, entity_id=ENTITY_VACUUM_BASIC) # VacuumEntity should not support start and pause methods. hass.states.async_set(ENTITY_VACUUM_COMPLETE, STATE_ON) @@ -250,21 +248,18 @@ async def test_unsupported_methods(hass: HomeAssistant) -> None: await hass.async_block_till_done() assert not vacuum.is_on(hass, ENTITY_VACUUM_COMPLETE) - await common.async_start(hass, ENTITY_VACUUM_COMPLETE) - assert not vacuum.is_on(hass, ENTITY_VACUUM_COMPLETE) + with pytest.raises(HomeAssistantError): + await common.async_start(hass, ENTITY_VACUUM_COMPLETE) # StateVacuumEntity does not support on/off - await common.async_turn_on(hass, entity_id=ENTITY_VACUUM_STATE) - state = hass.states.get(ENTITY_VACUUM_STATE) - assert state.state != STATE_CLEANING + with pytest.raises(HomeAssistantError): + await common.async_turn_on(hass, entity_id=ENTITY_VACUUM_STATE) - await common.async_turn_off(hass, entity_id=ENTITY_VACUUM_STATE) - state = hass.states.get(ENTITY_VACUUM_STATE) - assert state.state != STATE_RETURNING + with pytest.raises(HomeAssistantError): + await common.async_turn_off(hass, entity_id=ENTITY_VACUUM_STATE) - await common.async_toggle(hass, entity_id=ENTITY_VACUUM_STATE) - state = hass.states.get(ENTITY_VACUUM_STATE) - assert state.state != STATE_CLEANING + with pytest.raises(HomeAssistantError): + await common.async_toggle(hass, entity_id=ENTITY_VACUUM_STATE) async def test_services(hass: HomeAssistant) -> None: @@ -302,22 +297,15 @@ async def test_services(hass: HomeAssistant) -> None: async def test_set_fan_speed(hass: HomeAssistant) -> None: """Test vacuum service to set the fan speed.""" - group_vacuums = ",".join( - [ENTITY_VACUUM_BASIC, ENTITY_VACUUM_COMPLETE, ENTITY_VACUUM_STATE] - ) - old_state_basic = hass.states.get(ENTITY_VACUUM_BASIC) + group_vacuums = ",".join([ENTITY_VACUUM_COMPLETE, ENTITY_VACUUM_STATE]) old_state_complete = hass.states.get(ENTITY_VACUUM_COMPLETE) old_state_state = hass.states.get(ENTITY_VACUUM_STATE) await common.async_set_fan_speed(hass, FAN_SPEEDS[0], entity_id=group_vacuums) - new_state_basic = hass.states.get(ENTITY_VACUUM_BASIC) new_state_complete = hass.states.get(ENTITY_VACUUM_COMPLETE) new_state_state = hass.states.get(ENTITY_VACUUM_STATE) - assert old_state_basic == new_state_basic - assert ATTR_FAN_SPEED not in new_state_basic.attributes - assert old_state_complete != new_state_complete assert old_state_complete.attributes[ATTR_FAN_SPEED] == FAN_SPEEDS[1] assert new_state_complete.attributes[ATTR_FAN_SPEED] == FAN_SPEEDS[0] @@ -329,18 +317,15 @@ async def test_set_fan_speed(hass: HomeAssistant) -> None: async def test_send_command(hass: HomeAssistant) -> None: """Test vacuum service to send a command.""" - group_vacuums = ",".join([ENTITY_VACUUM_BASIC, ENTITY_VACUUM_COMPLETE]) - old_state_basic = hass.states.get(ENTITY_VACUUM_BASIC) + group_vacuums = ",".join([ENTITY_VACUUM_COMPLETE]) old_state_complete = hass.states.get(ENTITY_VACUUM_COMPLETE) await common.async_send_command( hass, "test_command", params={"p1": 3}, entity_id=group_vacuums ) - new_state_basic = hass.states.get(ENTITY_VACUUM_BASIC) new_state_complete = hass.states.get(ENTITY_VACUUM_COMPLETE) - assert old_state_basic == new_state_basic assert old_state_complete != new_state_complete assert new_state_complete.state == STATE_ON assert ( diff --git a/tests/components/mqtt/test_legacy_vacuum.py b/tests/components/mqtt/test_legacy_vacuum.py index 0297f4216c4..9a71c747e65 100644 --- a/tests/components/mqtt/test_legacy_vacuum.py +++ b/tests/components/mqtt/test_legacy_vacuum.py @@ -32,6 +32,7 @@ from homeassistant.components.vacuum import ( ) from homeassistant.const import CONF_NAME, STATE_OFF, STATE_ON, Platform from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.typing import ConfigType from .test_common import ( @@ -245,39 +246,48 @@ async def test_commands_without_supported_features( """Test commands which are not supported by the vacuum.""" mqtt_mock = await mqtt_mock_entry() - await common.async_turn_on(hass, "vacuum.mqtttest") + with pytest.raises(HomeAssistantError): + await common.async_turn_on(hass, "vacuum.mqtttest") mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await common.async_turn_off(hass, "vacuum.mqtttest") + with pytest.raises(HomeAssistantError): + await common.async_turn_off(hass, "vacuum.mqtttest") mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await common.async_stop(hass, "vacuum.mqtttest") + with pytest.raises(HomeAssistantError): + await common.async_stop(hass, "vacuum.mqtttest") mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await common.async_clean_spot(hass, "vacuum.mqtttest") + with pytest.raises(HomeAssistantError): + await common.async_clean_spot(hass, "vacuum.mqtttest") mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await common.async_locate(hass, "vacuum.mqtttest") + with pytest.raises(HomeAssistantError): + await common.async_locate(hass, "vacuum.mqtttest") mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await common.async_start_pause(hass, "vacuum.mqtttest") + with pytest.raises(HomeAssistantError): + await common.async_start_pause(hass, "vacuum.mqtttest") mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await common.async_return_to_base(hass, "vacuum.mqtttest") + with pytest.raises(HomeAssistantError): + await common.async_return_to_base(hass, "vacuum.mqtttest") mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await common.async_set_fan_speed(hass, "high", "vacuum.mqtttest") + with pytest.raises(HomeAssistantError): + await common.async_set_fan_speed(hass, "high", "vacuum.mqtttest") mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await common.async_send_command(hass, "44 FE 93", entity_id="vacuum.mqtttest") + with pytest.raises(HomeAssistantError): + await common.async_send_command(hass, "44 FE 93", entity_id="vacuum.mqtttest") mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() diff --git a/tests/components/mqtt/test_state_vacuum.py b/tests/components/mqtt/test_state_vacuum.py index dd15399f670..38baf591094 100644 --- a/tests/components/mqtt/test_state_vacuum.py +++ b/tests/components/mqtt/test_state_vacuum.py @@ -29,6 +29,7 @@ from homeassistant.components.vacuum import ( ) from homeassistant.const import CONF_NAME, ENTITY_MATCH_ALL, STATE_UNKNOWN, Platform from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from .test_common import ( help_custom_config, @@ -242,13 +243,15 @@ async def test_commands_without_supported_features( mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await common.async_set_fan_speed(hass, "medium", "vacuum.mqtttest") + with pytest.raises(HomeAssistantError): + await common.async_set_fan_speed(hass, "medium", "vacuum.mqtttest") mqtt_mock.async_publish.assert_not_called() mqtt_mock.async_publish.reset_mock() - await common.async_send_command( - hass, "44 FE 93", {"key": "value"}, entity_id="vacuum.mqtttest" - ) + with pytest.raises(HomeAssistantError): + await common.async_send_command( + hass, "44 FE 93", {"key": "value"}, entity_id="vacuum.mqtttest" + ) mqtt_mock.async_publish.assert_not_called() diff --git a/tests/components/template/test_vacuum.py b/tests/components/template/test_vacuum.py index 3a911a68416..e6850728450 100644 --- a/tests/components/template/test_vacuum.py +++ b/tests/components/template/test_vacuum.py @@ -12,6 +12,7 @@ from homeassistant.components.vacuum import ( ) from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, STATE_UNKNOWN from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_component import async_update_entity from tests.common import assert_setup_component @@ -317,31 +318,37 @@ async def test_unique_id(hass: HomeAssistant, start_ha) -> None: async def test_unused_services(hass: HomeAssistant) -> None: - """Test calling unused services should not crash.""" + """Test calling unused services raises.""" await _register_basic_vacuum(hass) # Pause vacuum - await common.async_pause(hass, _TEST_VACUUM) + with pytest.raises(HomeAssistantError): + await common.async_pause(hass, _TEST_VACUUM) await hass.async_block_till_done() # Stop vacuum - await common.async_stop(hass, _TEST_VACUUM) + with pytest.raises(HomeAssistantError): + await common.async_stop(hass, _TEST_VACUUM) await hass.async_block_till_done() # Return vacuum to base - await common.async_return_to_base(hass, _TEST_VACUUM) + with pytest.raises(HomeAssistantError): + await common.async_return_to_base(hass, _TEST_VACUUM) await hass.async_block_till_done() # Spot cleaning - await common.async_clean_spot(hass, _TEST_VACUUM) + with pytest.raises(HomeAssistantError): + await common.async_clean_spot(hass, _TEST_VACUUM) await hass.async_block_till_done() # Locate vacuum - await common.async_locate(hass, _TEST_VACUUM) + with pytest.raises(HomeAssistantError): + await common.async_locate(hass, _TEST_VACUUM) await hass.async_block_till_done() # Set fan's speed - await common.async_set_fan_speed(hass, "medium", _TEST_VACUUM) + with pytest.raises(HomeAssistantError): + await common.async_set_fan_speed(hass, "medium", _TEST_VACUUM) await hass.async_block_till_done() _verify(hass, STATE_UNKNOWN, None)