From 247df5874b9fa054e4cb362e17be24da2cf6a48e Mon Sep 17 00:00:00 2001 From: Jonas Thuresson Date: Tue, 23 Jun 2020 01:37:05 +0200 Subject: [PATCH] Xiaomii miio vaccum clean segment service (#36801) --- homeassistant/components/xiaomi_miio/const.py | 1 + .../components/xiaomi_miio/services.yaml | 10 ++ .../components/xiaomi_miio/vacuum.py | 17 +++ tests/components/xiaomi_miio/test_vacuum.py | 119 ++++++++---------- 4 files changed, 80 insertions(+), 67 deletions(-) diff --git a/homeassistant/components/xiaomi_miio/const.py b/homeassistant/components/xiaomi_miio/const.py index 370244d3015..1e8e7de9ef9 100644 --- a/homeassistant/components/xiaomi_miio/const.py +++ b/homeassistant/components/xiaomi_miio/const.py @@ -48,6 +48,7 @@ SERVICE_MOVE_REMOTE_CONTROL = "vacuum_remote_control_move" SERVICE_MOVE_REMOTE_CONTROL_STEP = "vacuum_remote_control_move_step" SERVICE_START_REMOTE_CONTROL = "vacuum_remote_control_start" SERVICE_STOP_REMOTE_CONTROL = "vacuum_remote_control_stop" +SERVICE_CLEAN_SEGMENT = "vacuum_clean_segment" SERVICE_CLEAN_ZONE = "vacuum_clean_zone" SERVICE_GOTO = "vacuum_goto" diff --git a/homeassistant/components/xiaomi_miio/services.yaml b/homeassistant/components/xiaomi_miio/services.yaml index 8883efc8a9b..c61b7f37f22 100644 --- a/homeassistant/components/xiaomi_miio/services.yaml +++ b/homeassistant/components/xiaomi_miio/services.yaml @@ -343,3 +343,13 @@ vacuum_goto: y_coord: description: y-coordinate. example: 32000 + +vacuum_clean_segment: + description: Start cleaning of the specified segment(s). + fields: + entity_id: + description: Name of the vacuum entity. + example: "vacuum.xiaomi_vacuum_cleaner" + segments: + description: Segments. + example: "[1,2]" diff --git a/homeassistant/components/xiaomi_miio/vacuum.py b/homeassistant/components/xiaomi_miio/vacuum.py index ed8dbbb2510..106e8f9dfc4 100644 --- a/homeassistant/components/xiaomi_miio/vacuum.py +++ b/homeassistant/components/xiaomi_miio/vacuum.py @@ -31,6 +31,7 @@ from homeassistant.helpers import config_validation as cv, entity_platform from homeassistant.util.dt import as_utc from .const import ( + SERVICE_CLEAN_SEGMENT, SERVICE_CLEAN_ZONE, SERVICE_GOTO, SERVICE_MOVE_REMOTE_CONTROL, @@ -198,6 +199,11 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= }, MiroboVacuum.async_goto.__name__, ) + platform.async_register_entity_service( + SERVICE_CLEAN_SEGMENT, + {vol.Required("segments"): vol.Any(vol.Coerce(int), [vol.Coerce(int)])}, + MiroboVacuum.async_clean_segment.__name__, + ) class MiroboVacuum(StateVacuumEntity): @@ -447,6 +453,17 @@ class MiroboVacuum(StateVacuumEntity): y_coord=y_coord, ) + async def async_clean_segment(self, segments): + """Clean the specified segments(s).""" + if isinstance(segments, int): + segments = [segments] + + await self._try_command( + "Unable to start cleaning of the specified segments: %s", + self._vacuum.segment_clean, + segments=segments, + ) + def update(self): """Fetch state from the device.""" try: diff --git a/tests/components/xiaomi_miio/test_vacuum.py b/tests/components/xiaomi_miio/test_vacuum.py index 6c13edb9d30..3b1234622ad 100644 --- a/tests/components/xiaomi_miio/test_vacuum.py +++ b/tests/components/xiaomi_miio/test_vacuum.py @@ -38,6 +38,7 @@ from homeassistant.components.xiaomi_miio.vacuum import ( CONF_HOST, CONF_NAME, CONF_TOKEN, + SERVICE_CLEAN_SEGMENT, SERVICE_CLEAN_ZONE, SERVICE_GOTO, SERVICE_MOVE_REMOTE_CONTROL, @@ -209,21 +210,9 @@ def mirobo_errors_fixture(): async def test_xiaomi_exceptions(hass, caplog, mock_mirobo_errors): """Test vacuum supported features.""" entity_name = "test_vacuum_cleaner_error" - await async_setup_component( - hass, - DOMAIN, - { - DOMAIN: { - CONF_PLATFORM: PLATFORM, - CONF_HOST: "127.0.0.1", - CONF_NAME: entity_name, - CONF_TOKEN: "12345678901234567890123456789012", - } - }, - ) - await hass.async_block_till_done() + await setup_component(hass, entity_name) - assert "Initializing with host 127.0.0.1 (token 12345...)" in caplog.text + assert "Initializing with host 192.168.1.100 (token 12345...)" in caplog.text assert mock_mirobo_errors.status.call_count == 1 assert "ERROR" in caplog.text assert "Got OSError while fetching the state" in caplog.text @@ -232,23 +221,9 @@ async def test_xiaomi_exceptions(hass, caplog, mock_mirobo_errors): async def test_xiaomi_vacuum_services(hass, caplog, mock_mirobo_is_got_error): """Test vacuum supported features.""" entity_name = "test_vacuum_cleaner_1" - entity_id = f"{DOMAIN}.{entity_name}" + entity_id = await setup_component(hass, entity_name) - await async_setup_component( - hass, - DOMAIN, - { - DOMAIN: { - CONF_PLATFORM: PLATFORM, - CONF_HOST: "127.0.0.1", - CONF_NAME: entity_name, - CONF_TOKEN: "12345678901234567890123456789012", - } - }, - ) - await hass.async_block_till_done() - - assert "Initializing with host 127.0.0.1 (token 12345...)" in caplog.text + assert "Initializing with host 192.168.1.100 (token 12345...)" in caplog.text # Check state attributes state = hass.states.get(entity_id) @@ -347,21 +322,7 @@ async def test_xiaomi_vacuum_services(hass, caplog, mock_mirobo_is_got_error): async def test_xiaomi_specific_services(hass, caplog, mock_mirobo_is_on): """Test vacuum supported features.""" entity_name = "test_vacuum_cleaner_2" - entity_id = f"{DOMAIN}.{entity_name}" - - await async_setup_component( - hass, - DOMAIN, - { - DOMAIN: { - CONF_PLATFORM: PLATFORM, - CONF_HOST: "192.168.1.100", - CONF_NAME: entity_name, - CONF_TOKEN: "12345678901234567890123456789012", - } - }, - ) - await hass.async_block_till_done() + entity_id = await setup_component(hass, entity_name) assert "Initializing with host 192.168.1.100 (token 12345" in caplog.text @@ -458,21 +419,7 @@ async def test_xiaomi_specific_services(hass, caplog, mock_mirobo_is_on): async def test_xiaomi_vacuum_fanspeeds(hass, caplog, mock_mirobo_fanspeeds): """Test Xiaomi vacuum fanspeeds.""" entity_name = "test_vacuum_cleaner_2" - entity_id = f"{DOMAIN}.{entity_name}" - - await async_setup_component( - hass, - DOMAIN, - { - DOMAIN: { - CONF_PLATFORM: PLATFORM, - CONF_HOST: "192.168.1.100", - CONF_NAME: entity_name, - CONF_TOKEN: "12345678901234567890123456789012", - } - }, - ) - await hass.async_block_till_done() + entity_id = await setup_component(hass, entity_name) assert "Initializing with host 192.168.1.100 (token 12345" in caplog.text @@ -522,6 +469,50 @@ async def test_xiaomi_vacuum_fanspeeds(hass, caplog, mock_mirobo_fanspeeds): async def test_xiaomi_vacuum_goto_service(hass, caplog, mock_mirobo_is_on): """Test vacuum supported features.""" entity_name = "test_vacuum_cleaner_2" + entity_id = await setup_component(hass, entity_name) + + data = {"entity_id": entity_id, "x_coord": 25500, "y_coord": 25500} + await hass.services.async_call(XIAOMI_DOMAIN, SERVICE_GOTO, data, blocking=True) + mock_mirobo_is_on.goto.assert_has_calls( + [mock.call(x_coord=data["x_coord"], y_coord=data["y_coord"])], any_order=True + ) + mock_mirobo_is_on.assert_has_calls(STATUS_CALLS, any_order=True) + + +async def test_xiaomi_vacuum_clean_segment_service(hass, caplog, mock_mirobo_is_on): + """Test vacuum supported features.""" + entity_name = "test_vacuum_cleaner_2" + entity_id = await setup_component(hass, entity_name) + + data = {"entity_id": entity_id, "segments": ["1", "2"]} + await hass.services.async_call( + XIAOMI_DOMAIN, SERVICE_CLEAN_SEGMENT, data, blocking=True + ) + mock_mirobo_is_on.segment_clean.assert_has_calls( + [mock.call(segments=[int(i) for i in data["segments"]])], any_order=True + ) + mock_mirobo_is_on.assert_has_calls(STATUS_CALLS, any_order=True) + + +async def test_xiaomi_vacuum_clean_segment_service_single_segment( + hass, caplog, mock_mirobo_is_on +): + """Test vacuum supported features.""" + entity_name = "test_vacuum_cleaner_2" + entity_id = await setup_component(hass, entity_name) + + data = {"entity_id": entity_id, "segments": 1} + await hass.services.async_call( + XIAOMI_DOMAIN, SERVICE_CLEAN_SEGMENT, data, blocking=True + ) + mock_mirobo_is_on.segment_clean.assert_has_calls( + [mock.call(segments=[data["segments"]])], any_order=True + ) + mock_mirobo_is_on.assert_has_calls(STATUS_CALLS, any_order=True) + + +async def setup_component(hass, entity_name): + """Set up vacuum component.""" entity_id = f"{DOMAIN}.{entity_name}" await async_setup_component( @@ -537,10 +528,4 @@ async def test_xiaomi_vacuum_goto_service(hass, caplog, mock_mirobo_is_on): }, ) await hass.async_block_till_done() - - data = {"entity_id": entity_id, "x_coord": 25500, "y_coord": 25500} - await hass.services.async_call(XIAOMI_DOMAIN, SERVICE_GOTO, data, blocking=True) - mock_mirobo_is_on.goto.assert_has_calls( - [mock.call(x_coord=data["x_coord"], y_coord=data["y_coord"])], any_order=True - ) - mock_mirobo_is_on.assert_has_calls(STATUS_CALLS, any_order=True) + return entity_id