diff --git a/homeassistant/components/xiaomi_miio/manifest.json b/homeassistant/components/xiaomi_miio/manifest.json index e1ead8d966c..c9e948a1300 100644 --- a/homeassistant/components/xiaomi_miio/manifest.json +++ b/homeassistant/components/xiaomi_miio/manifest.json @@ -3,7 +3,7 @@ "name": "Xiaomi Miio", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/xiaomi_miio", - "requirements": ["construct==2.9.45", "python-miio==0.5.0.1"], + "requirements": ["construct==2.9.45", "python-miio==0.5.1"], "codeowners": ["@rytilahti", "@syssi"], "zeroconf": ["_miio._udp.local."] } diff --git a/homeassistant/components/xiaomi_miio/vacuum.py b/homeassistant/components/xiaomi_miio/vacuum.py index ef07b5f4741..ed8dbbb2510 100644 --- a/homeassistant/components/xiaomi_miio/vacuum.py +++ b/homeassistant/components/xiaomi_miio/vacuum.py @@ -28,6 +28,7 @@ from homeassistant.components.vacuum import ( ) from homeassistant.const import CONF_HOST, CONF_NAME, CONF_TOKEN, STATE_OFF, STATE_ON from homeassistant.helpers import config_validation as cv, entity_platform +from homeassistant.util.dt import as_utc from .const import ( SERVICE_CLEAN_ZONE, @@ -72,6 +73,7 @@ ATTR_RC_VELOCITY = "velocity" ATTR_STATUS = "status" ATTR_ZONE_ARRAY = "zone" ATTR_ZONE_REPEATER = "repeats" +ATTR_TIMERS = "timers" SUPPORT_XIAOMI = ( SUPPORT_STATE @@ -216,6 +218,8 @@ class MiroboVacuum(StateVacuumEntity): self._fan_speeds = None self._fan_speeds_reverse = None + self._timers = None + @property def name(self): """Return the name of the device.""" @@ -262,6 +266,18 @@ class MiroboVacuum(StateVacuumEntity): """Get the list of available fan speed steps of the vacuum cleaner.""" return list(self._fan_speeds) if self._fan_speeds else [] + @property + def timers(self): + """Get the list of added timers of the vacuum cleaner.""" + return [ + { + "enabled": timer.enabled, + "cron": timer.cron, + "next_schedule": as_utc(timer.next_schedule), + } + for timer in self._timers + ] + @property def device_state_attributes(self): """Return the specific state attributes of this vacuum cleaner.""" @@ -307,6 +323,9 @@ class MiroboVacuum(StateVacuumEntity): if self.vacuum_state.got_error: attrs[ATTR_ERROR] = self.vacuum_state.error + + if self.timers: + attrs[ATTR_TIMERS] = self.timers return attrs @property @@ -442,6 +461,8 @@ class MiroboVacuum(StateVacuumEntity): self.last_clean = self._vacuum.last_clean_details() self.dnd_state = self._vacuum.dnd_status() + self._timers = self._vacuum.timer() + self._available = True except OSError as exc: _LOGGER.error("Got OSError while fetching the state: %s", exc) diff --git a/requirements_all.txt b/requirements_all.txt index e7bd62d30b5..57ac50fa0e5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1702,7 +1702,7 @@ python-juicenet==1.0.1 # python-lirc==1.2.3 # homeassistant.components.xiaomi_miio -python-miio==0.5.0.1 +python-miio==0.5.1 # homeassistant.components.mpd python-mpd2==1.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 401843765e4..4950e9b2af1 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -717,7 +717,7 @@ python-izone==1.1.2 python-juicenet==1.0.1 # homeassistant.components.xiaomi_miio -python-miio==0.5.0.1 +python-miio==0.5.1 # homeassistant.components.nest python-nest==4.1.0 diff --git a/tests/components/xiaomi_miio/test_vacuum.py b/tests/components/xiaomi_miio/test_vacuum.py index 3949c548844..6c13edb9d30 100644 --- a/tests/components/xiaomi_miio/test_vacuum.py +++ b/tests/components/xiaomi_miio/test_vacuum.py @@ -1,8 +1,9 @@ """The tests for the Xiaomi vacuum platform.""" -from datetime import time, timedelta +from datetime import datetime, time, timedelta from unittest import mock import pytest +from pytz import utc from homeassistant.components.vacuum import ( ATTR_BATTERY_ICON, @@ -33,6 +34,7 @@ from homeassistant.components.xiaomi_miio.vacuum import ( ATTR_FILTER_LEFT, ATTR_MAIN_BRUSH_LEFT, ATTR_SIDE_BRUSH_LEFT, + ATTR_TIMERS, CONF_HOST, CONF_NAME, CONF_TOKEN, @@ -60,6 +62,7 @@ STATUS_CALLS = [ mock.call.consumable_status(), mock.call.clean_history(), mock.call.dnd_status(), + mock.call.timer(), ] @@ -94,6 +97,18 @@ def mirobo_is_got_error_fixture(): mock_vacuum.dnd_status().start = time(hour=22, minute=0) mock_vacuum.dnd_status().end = time(hour=6, minute=0) + mock_timer_1 = mock.MagicMock() + mock_timer_1.enabled = True + mock_timer_1.cron = "5 5 1 8 1" + mock_timer_1.next_schedule = datetime(2020, 5, 23, 13, 21, 10, tzinfo=utc) + + mock_timer_2 = mock.MagicMock() + mock_timer_2.enabled = False + mock_timer_2.cron = "5 5 1 8 2" + mock_timer_2.next_schedule = datetime(2020, 5, 23, 13, 21, 10, tzinfo=utc) + + mock_vacuum.timer.return_value = [mock_timer_1, mock_timer_2] + with mock.patch( "homeassistant.components.xiaomi_miio.vacuum.Vacuum" ) as mock_vaccum_cls: @@ -160,6 +175,18 @@ def mirobo_is_on_fixture(): mock_vacuum.status().state_code = 5 mock_vacuum.dnd_status().enabled = False + mock_timer_1 = mock.MagicMock() + mock_timer_1.enabled = True + mock_timer_1.cron = "5 5 1 8 1" + mock_timer_1.next_schedule = datetime(2020, 5, 23, 13, 21, 10, tzinfo=utc) + + mock_timer_2 = mock.MagicMock() + mock_timer_2.enabled = False + mock_timer_2.cron = "5 5 1 8 2" + mock_timer_2.next_schedule = datetime(2020, 5, 23, 13, 21, 10, tzinfo=utc) + + mock_vacuum.timer.return_value = [mock_timer_1, mock_timer_2] + with mock.patch( "homeassistant.components.xiaomi_miio.vacuum.Vacuum" ) as mock_vaccum_cls: @@ -241,6 +268,18 @@ async def test_xiaomi_vacuum_services(hass, caplog, mock_mirobo_is_got_error): assert state.attributes.get(ATTR_CLEANING_COUNT) == 35 assert state.attributes.get(ATTR_CLEANED_TOTAL_AREA) == 123 assert state.attributes.get(ATTR_CLEANING_TOTAL_TIME) == 695 + assert state.attributes.get(ATTR_TIMERS) == [ + { + "enabled": True, + "cron": "5 5 1 8 1", + "next_schedule": datetime(2020, 5, 23, 13, 21, 10, tzinfo=utc), + }, + { + "enabled": False, + "cron": "5 5 1 8 2", + "next_schedule": datetime(2020, 5, 23, 13, 21, 10, tzinfo=utc), + }, + ] # Call services await hass.services.async_call( @@ -341,6 +380,18 @@ async def test_xiaomi_specific_services(hass, caplog, mock_mirobo_is_on): assert state.attributes.get(ATTR_CLEANING_COUNT) == 41 assert state.attributes.get(ATTR_CLEANED_TOTAL_AREA) == 323 assert state.attributes.get(ATTR_CLEANING_TOTAL_TIME) == 675 + assert state.attributes.get(ATTR_TIMERS) == [ + { + "enabled": True, + "cron": "5 5 1 8 1", + "next_schedule": datetime(2020, 5, 23, 13, 21, 10, tzinfo=utc), + }, + { + "enabled": False, + "cron": "5 5 1 8 2", + "next_schedule": datetime(2020, 5, 23, 13, 21, 10, tzinfo=utc), + }, + ] # Xiaomi vacuum specific services: await hass.services.async_call(