mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Check supported features in calls to vacuum services (#95833)
* Check supported features in vacuum services * Update tests * Add comment
This commit is contained in:
parent
7dc03ef301
commit
96c71b214f
@ -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
|
||||
|
@ -37,8 +37,8 @@ VALID_STATES_STATE = {
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_IDLE,
|
||||
STATE_RETURNING,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 (
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user