From 4d49fe6b931facea60a13cc65a2e020f42f83674 Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Fri, 1 May 2020 00:05:45 -0400 Subject: [PATCH 01/15] Don't attempt to set Vizio is_volume_muted property if Vizio API doesn't provide muted state (#34782) --- .../components/vizio/media_player.py | 15 +++++++----- tests/components/vizio/test_media_player.py | 23 +++++++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/vizio/media_player.py b/homeassistant/components/vizio/media_player.py index bb7ae3f75b0..022a5ea35f1 100644 --- a/homeassistant/components/vizio/media_player.py +++ b/homeassistant/components/vizio/media_player.py @@ -132,7 +132,7 @@ class VizioDevice(MediaPlayerDevice): self._state = None self._volume_level = None self._volume_step = config_entry.options[CONF_VOLUME_STEP] - self._is_muted = None + self._is_volume_muted = None self._current_input = None self._current_app = None self._current_app_config = None @@ -190,7 +190,7 @@ class VizioDevice(MediaPlayerDevice): if not is_on: self._state = STATE_OFF self._volume_level = None - self._is_muted = None + self._is_volume_muted = None self._current_input = None self._available_inputs = None self._current_app = None @@ -207,7 +207,10 @@ class VizioDevice(MediaPlayerDevice): ) if audio_settings is not None: self._volume_level = float(audio_settings["volume"]) / self._max_volume - self._is_muted = audio_settings["mute"].lower() == "on" + if "mute" in audio_settings: + self._is_volume_muted = audio_settings["mute"].lower() == "on" + else: + self._is_volume_muted = None if VIZIO_SOUND_MODE in audio_settings: self._supported_commands |= SUPPORT_SELECT_SOUND_MODE @@ -324,7 +327,7 @@ class VizioDevice(MediaPlayerDevice): @property def is_volume_muted(self): """Boolean if volume is currently muted.""" - return self._is_muted + return self._is_volume_muted @property def source(self) -> str: @@ -428,10 +431,10 @@ class VizioDevice(MediaPlayerDevice): """Mute the volume.""" if mute: await self._device.mute_on() - self._is_muted = True + self._is_volume_muted = True else: await self._device.mute_off() - self._is_muted = False + self._is_volume_muted = False async def async_media_previous_track(self) -> None: """Send previous channel command.""" diff --git a/tests/components/vizio/test_media_player.py b/tests/components/vizio/test_media_player.py index 1f6abf10563..b823241ef59 100644 --- a/tests/components/vizio/test_media_player.py +++ b/tests/components/vizio/test_media_player.py @@ -621,3 +621,26 @@ async def test_setup_with_no_running_app( assert attr["source"] == "CAST" assert "app_id" not in attr assert "app_name" not in attr + + +async def test_setup_tv_without_mute( + hass: HomeAssistantType, + vizio_connect: pytest.fixture, + vizio_update: pytest.fixture, +) -> None: + """Test Vizio TV entity setup when mute property isn't returned by Vizio API.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + data=vol.Schema(VIZIO_SCHEMA)(MOCK_USER_VALID_TV_CONFIG), + unique_id=UNIQUE_ID, + ) + + async with _cm_for_test_setup_without_apps( + {"volume": int(MAX_VOLUME[VIZIO_DEVICE_CLASS_TV] / 2)}, STATE_ON, + ): + await _add_config_entry_to_hass(hass, config_entry) + + attr = _get_attr_and_assert_base_attr(hass, DEVICE_CLASS_TV, STATE_ON) + _assert_sources_and_volume(attr, VIZIO_DEVICE_CLASS_TV) + assert "sound_mode" not in attr + assert "is_volume_muted" not in attr From 9ccd56c01920d5a3cd477dafdbd37e4d268d8904 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Thu, 30 Apr 2020 15:43:02 +0200 Subject: [PATCH 02/15] Bump brother to 0.1.14 (#34930) --- homeassistant/components/brother/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/brother/manifest.json b/homeassistant/components/brother/manifest.json index 48df788c93a..7f59aaa9c2c 100644 --- a/homeassistant/components/brother/manifest.json +++ b/homeassistant/components/brother/manifest.json @@ -3,7 +3,7 @@ "name": "Brother Printer", "documentation": "https://www.home-assistant.io/integrations/brother", "codeowners": ["@bieniu"], - "requirements": ["brother==0.1.13"], + "requirements": ["brother==0.1.14"], "zeroconf": ["_printer._tcp.local."], "config_flow": true, "quality_scale": "platinum" diff --git a/requirements_all.txt b/requirements_all.txt index 066f6de6fd0..9c6eddf3196 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -365,7 +365,7 @@ bravia-tv==1.0.2 broadlink==0.13.2 # homeassistant.components.brother -brother==0.1.13 +brother==0.1.14 # homeassistant.components.brottsplatskartan brottsplatskartan==0.0.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index fb622f5640b..215fafcd467 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -147,7 +147,7 @@ bravia-tv==1.0.2 broadlink==0.13.2 # homeassistant.components.brother -brother==0.1.13 +brother==0.1.14 # homeassistant.components.buienradar buienradar==1.0.4 From b68228c7e888f2508d1bafd62bbfbaa7669f6a78 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 1 May 2020 07:34:44 +0200 Subject: [PATCH 03/15] Fix MQTT debug info for same topic (#34952) --- homeassistant/components/mqtt/debug_info.py | 25 ++++-- tests/components/mqtt/test_init.py | 93 ++++++++++++++++++++- 2 files changed, 109 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/mqtt/debug_info.py b/homeassistant/components/mqtt/debug_info.py index 2a216366bb1..86850c61638 100644 --- a/homeassistant/components/mqtt/debug_info.py +++ b/homeassistant/components/mqtt/debug_info.py @@ -23,7 +23,7 @@ def log_messages(hass: HomeAssistantType, entity_id: str) -> MessageCallbackType debug_info = hass.data[DATA_MQTT_DEBUG_INFO] messages = debug_info["entities"][entity_id]["subscriptions"][ msg.subscribed_topic - ] + ]["messages"] if msg not in messages: messages.append(msg) @@ -50,16 +50,27 @@ def add_subscription(hass, message_callback, subscription): entity_info = debug_info["entities"].setdefault( entity_id, {"subscriptions": {}, "discovery_data": {}} ) - entity_info["subscriptions"][subscription] = deque([], STORED_MESSAGES) + if subscription not in entity_info["subscriptions"]: + entity_info["subscriptions"][subscription] = { + "count": 0, + "messages": deque([], STORED_MESSAGES), + } + entity_info["subscriptions"][subscription]["count"] += 1 def remove_subscription(hass, message_callback, subscription): - """Remove debug data for subscription.""" + """Remove debug data for subscription if it exists.""" entity_id = getattr(message_callback, "__entity_id", None) if entity_id and entity_id in hass.data[DATA_MQTT_DEBUG_INFO]["entities"]: - hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"].pop( + hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"][ subscription - ) + ]["count"] -= 1 + if not hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"][ + subscription + ]["count"]: + hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"].pop( + subscription + ) def add_entity_discovery_data(hass, discovery_data, entity_id): @@ -127,10 +138,10 @@ async def info_for_device(hass, device_id): "topic": topic, "messages": [ {"payload": msg.payload, "time": msg.timestamp, "topic": msg.topic} - for msg in list(messages) + for msg in list(subscription["messages"]) ], } - for topic, messages in entity_info["subscriptions"].items() + for topic, subscription in entity_info["subscriptions"].items() ] discovery_data = { "topic": entity_info["discovery_data"].get(ATTR_DISCOVERY_TOPIC, ""), diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index 290b70953af..24b51414944 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -960,6 +960,42 @@ async def test_mqtt_ws_remove_discovered_device_twice( assert response["error"]["code"] == websocket_api.const.ERR_NOT_FOUND +async def test_mqtt_ws_remove_discovered_device_same_topic( + hass, device_reg, hass_ws_client, mqtt_mock +): + """Test MQTT websocket device removal.""" + config_entry = MockConfigEntry(domain=mqtt.DOMAIN) + config_entry.add_to_hass(hass) + await async_start(hass, "homeassistant", {}, config_entry) + + data = ( + '{ "device":{"identifiers":["0AFFD2"]},' + ' "state_topic": "foobar/sensor",' + ' "availability_topic": "foobar/sensor",' + ' "unique_id": "unique" }' + ) + + async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data) + await hass.async_block_till_done() + + device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")}, set()) + assert device_entry is not None + + client = await hass_ws_client(hass) + await client.send_json( + {"id": 5, "type": "mqtt/device/remove", "device_id": device_entry.id} + ) + response = await client.receive_json() + assert response["success"] + + await client.send_json( + {"id": 6, "type": "mqtt/device/remove", "device_id": device_entry.id} + ) + response = await client.receive_json() + assert not response["success"] + assert response["error"]["code"] == websocket_api.const.ERR_NOT_FOUND + + async def test_mqtt_ws_remove_non_mqtt_device( hass, device_reg, hass_ws_client, mqtt_mock ): @@ -1306,7 +1342,60 @@ async def test_debug_info_filter_same(hass, mqtt_mock): assert { "topic": "sensor/#", "messages": [ - {"topic": "sensor/abc", "payload": "123", "time": dt1}, - {"topic": "sensor/abc", "payload": "123", "time": dt2}, + {"payload": "123", "time": dt1, "topic": "sensor/abc"}, + {"payload": "123", "time": dt2, "topic": "sensor/abc"}, ], } == debug_info_data["entities"][0]["subscriptions"][0] + + +async def test_debug_info_same_topic(hass, mqtt_mock): + """Test debug info.""" + config = { + "device": {"identifiers": ["helloworld"]}, + "platform": "mqtt", + "name": "test", + "state_topic": "sensor/status", + "availability_topic": "sensor/status", + "unique_id": "veryunique", + } + + entry = MockConfigEntry(domain=mqtt.DOMAIN) + entry.add_to_hass(hass) + await async_start(hass, "homeassistant", {}, entry) + registry = await hass.helpers.device_registry.async_get_registry() + + data = json.dumps(config) + async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data) + await hass.async_block_till_done() + + device = registry.async_get_device({("mqtt", "helloworld")}, set()) + assert device is not None + + debug_info_data = await debug_info.info_for_device(hass, device.id) + assert len(debug_info_data["entities"][0]["subscriptions"]) >= 1 + assert {"topic": "sensor/status", "messages": []} in debug_info_data["entities"][0][ + "subscriptions" + ] + + start_dt = datetime(2019, 1, 1, 0, 0, 0) + with patch("homeassistant.util.dt.utcnow") as dt_utcnow: + dt_utcnow.return_value = start_dt + async_fire_mqtt_message(hass, "sensor/status", "123", qos=0, retain=False) + + debug_info_data = await debug_info.info_for_device(hass, device.id) + assert len(debug_info_data["entities"][0]["subscriptions"]) == 1 + assert { + "payload": "123", + "time": start_dt, + "topic": "sensor/status", + } in debug_info_data["entities"][0]["subscriptions"][0]["messages"] + + config["availability_topic"] = "sensor/availability" + data = json.dumps(config) + async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data) + await hass.async_block_till_done() + + start_dt = datetime(2019, 1, 1, 0, 0, 0) + with patch("homeassistant.util.dt.utcnow") as dt_utcnow: + dt_utcnow.return_value = start_dt + async_fire_mqtt_message(hass, "sensor/status", "123", qos=0, retain=False) From de18207ca392950e190811acdee7d50dfb461aea Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 30 Apr 2020 13:34:25 -0500 Subject: [PATCH 04/15] Fix preservation of homekit fan speed on toggle (#34971) --- homeassistant/components/homekit/type_fans.py | 4 ++- homeassistant/components/homekit/util.py | 2 +- tests/components/homekit/test_type_fans.py | 26 +++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/homekit/type_fans.py b/homeassistant/components/homekit/type_fans.py index b7208b1746c..291b3ffed90 100644 --- a/homeassistant/components/homekit/type_fans.py +++ b/homeassistant/components/homekit/type_fans.py @@ -165,7 +165,9 @@ class Fan(HomeAccessory): self.char_direction.set_value(hk_direction) # Handle Speed - if self.char_speed is not None: + if self.char_speed is not None and state != STATE_OFF: + # We do not change the homekit speed when turning off + # as it will clear the restore state speed = new_state.attributes.get(ATTR_SPEED) hk_speed_value = self.speed_mapping.speed_to_homekit(speed) if hk_speed_value is not None and self.char_speed.value != hk_speed_value: diff --git a/homeassistant/components/homekit/util.py b/homeassistant/components/homekit/util.py index 0295440df49..b8d98ad2304 100644 --- a/homeassistant/components/homekit/util.py +++ b/homeassistant/components/homekit/util.py @@ -200,7 +200,7 @@ class HomeKitSpeedMapping: if speed is None: return None speed_range = self.speed_ranges[speed] - return speed_range.target + return round(speed_range.target) def speed_to_states(self, speed): """Map HomeKit speed to Home Assistant speed state.""" diff --git a/tests/components/homekit/test_type_fans.py b/tests/components/homekit/test_type_fans.py index ca6e03217f3..4d2ace24eab 100644 --- a/tests/components/homekit/test_type_fans.py +++ b/tests/components/homekit/test_type_fans.py @@ -304,6 +304,7 @@ async def test_fan_speed(hass, hk_driver, cls, events): call_set_speed = async_mock_service(hass, DOMAIN, "set_speed") char_speed_iid = acc.char_speed.to_HAP()[HAP_REPR_IID] + char_active_iid = acc.char_active.to_HAP()[HAP_REPR_IID] hk_driver.set_characteristics( { @@ -320,12 +321,37 @@ async def test_fan_speed(hass, hk_driver, cls, events): await hass.async_add_executor_job(acc.char_speed.client_update_value, 42) await hass.async_block_till_done() acc.speed_mapping.speed_to_states.assert_called_with(42) + assert acc.char_speed.value == 42 + assert acc.char_active.value == 1 + assert call_set_speed[0] assert call_set_speed[0].data[ATTR_ENTITY_ID] == entity_id assert call_set_speed[0].data[ATTR_SPEED] == "ludicrous" assert len(events) == 1 assert events[-1].data[ATTR_VALUE] == "ludicrous" + # Verify speed is preserved from off to on + hass.states.async_set(entity_id, STATE_OFF, {ATTR_SPEED: SPEED_OFF}) + await hass.async_block_till_done() + assert acc.char_speed.value == 42 + assert acc.char_active.value == 0 + + hk_driver.set_characteristics( + { + HAP_REPR_CHARS: [ + { + HAP_REPR_AID: acc.aid, + HAP_REPR_IID: char_active_iid, + HAP_REPR_VALUE: 1, + }, + ] + }, + "mock_addr", + ) + await hass.async_block_till_done() + assert acc.char_speed.value == 42 + assert acc.char_active.value == 1 + async def test_fan_set_all_one_shot(hass, hk_driver, cls, events): """Test fan with speed.""" From 42dd3ba748c0d525ec1202b4e64ab50ef82435e9 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 1 May 2020 00:36:01 -0500 Subject: [PATCH 05/15] Fix restoring isy994 brightness with no previous state (#34972) --- CODEOWNERS | 1 + homeassistant/components/isy994/light.py | 29 +++++++++++++++++-- homeassistant/components/isy994/manifest.json | 2 +- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 815f1b6b85a..5f1bb3a7773 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -195,6 +195,7 @@ homeassistant/components/ipp/* @ctalkington homeassistant/components/iqvia/* @bachya homeassistant/components/irish_rail_transport/* @ttroy50 homeassistant/components/islamic_prayer_times/* @engrbm87 +homeassistant/components/isy994/* @bdraco homeassistant/components/izone/* @Swamp-Ig homeassistant/components/jewish_calendar/* @tsvi homeassistant/components/juicenet/* @jesserockz diff --git a/homeassistant/components/isy994/light.py b/homeassistant/components/isy994/light.py index a8c30220637..39392ae062a 100644 --- a/homeassistant/components/isy994/light.py +++ b/homeassistant/components/isy994/light.py @@ -3,12 +3,15 @@ import logging from typing import Callable from homeassistant.components.light import DOMAIN, SUPPORT_BRIGHTNESS, Light +from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.typing import ConfigType from . import ISY994_NODES, ISYDevice _LOGGER = logging.getLogger(__name__) +ATTR_LAST_BRIGHTNESS = "last_brightness" + def setup_platform( hass, config: ConfigType, add_entities: Callable[[list], None], discovery_info=None @@ -21,13 +24,13 @@ def setup_platform( add_entities(devices) -class ISYLightDevice(ISYDevice, Light): +class ISYLightDevice(ISYDevice, Light, RestoreEntity): """Representation of an ISY994 light device.""" def __init__(self, node) -> None: """Initialize the ISY994 light device.""" super().__init__(node) - self._last_brightness = self.brightness + self._last_brightness = None @property def is_on(self) -> bool: @@ -56,7 +59,7 @@ class ISYLightDevice(ISYDevice, Light): # pylint: disable=arguments-differ def turn_on(self, brightness=None, **kwargs) -> None: """Send the turn on command to the ISY994 light device.""" - if brightness is None and self._last_brightness is not None: + if brightness is None and self._last_brightness: brightness = self._last_brightness if not self._node.on(val=brightness): _LOGGER.debug("Unable to turn on light") @@ -65,3 +68,23 @@ class ISYLightDevice(ISYDevice, Light): def supported_features(self): """Flag supported features.""" return SUPPORT_BRIGHTNESS + + @property + def device_state_attributes(self): + """Return the light attributes.""" + return {ATTR_LAST_BRIGHTNESS: self._last_brightness} + + async def async_added_to_hass(self) -> None: + """Restore last_brightness on restart.""" + await super().async_added_to_hass() + + self._last_brightness = self.brightness or 255 + last_state = await self.async_get_last_state() + if not last_state: + return + + if ( + ATTR_LAST_BRIGHTNESS in last_state.attributes + and last_state.attributes[ATTR_LAST_BRIGHTNESS] + ): + self._last_brightness = last_state.attributes[ATTR_LAST_BRIGHTNESS] diff --git a/homeassistant/components/isy994/manifest.json b/homeassistant/components/isy994/manifest.json index 0b48528335d..083f25808fb 100644 --- a/homeassistant/components/isy994/manifest.json +++ b/homeassistant/components/isy994/manifest.json @@ -3,5 +3,5 @@ "name": "Universal Devices ISY994", "documentation": "https://www.home-assistant.io/integrations/isy994", "requirements": ["PyISY==1.1.2"], - "codeowners": [] + "codeowners": ["@bdraco"] } From 3a4b8625bdbf9cd3542c54074622063ebad3c9bb Mon Sep 17 00:00:00 2001 From: Chris Talkington Date: Thu, 30 Apr 2020 23:08:32 -0500 Subject: [PATCH 06/15] Support num_repeats for roku remote (#34981) --- homeassistant/components/roku/remote.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/roku/remote.py b/homeassistant/components/roku/remote.py index 999747c9a27..9a61ec8d5d8 100644 --- a/homeassistant/components/roku/remote.py +++ b/homeassistant/components/roku/remote.py @@ -7,7 +7,7 @@ from requests.exceptions import ( ) from roku import RokuException -from homeassistant.components.remote import RemoteDevice +from homeassistant.components.remote import ATTR_NUM_REPEATS, RemoteDevice from homeassistant.config_entries import ConfigEntry from homeassistant.helpers.typing import HomeAssistantType @@ -84,8 +84,11 @@ class RokuRemote(RemoteDevice): def send_command(self, command, **kwargs): """Send a command to one device.""" - for single_command in command: - if not hasattr(self.roku, single_command): - continue + num_repeats = kwargs[ATTR_NUM_REPEATS] - getattr(self.roku, single_command)() + for _ in range(num_repeats): + for single_command in command: + if not hasattr(self.roku, single_command): + continue + + getattr(self.roku, single_command)() From 12119f89e5bd30a83b2e08745c4a94006d410fd6 Mon Sep 17 00:00:00 2001 From: Chris Talkington Date: Thu, 30 Apr 2020 23:08:15 -0500 Subject: [PATCH 07/15] Support num_repeats for directv remote (#34982) --- homeassistant/components/directv/remote.py | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/directv/remote.py b/homeassistant/components/directv/remote.py index 8bc7c220833..e8137ace711 100644 --- a/homeassistant/components/directv/remote.py +++ b/homeassistant/components/directv/remote.py @@ -5,7 +5,7 @@ from typing import Any, Callable, Iterable, List from directv import DIRECTV, DIRECTVError -from homeassistant.components.remote import RemoteDevice +from homeassistant.components.remote import ATTR_NUM_REPEATS, RemoteDevice from homeassistant.config_entries import ConfigEntry from homeassistant.helpers.typing import HomeAssistantType @@ -95,12 +95,15 @@ class DIRECTVRemote(DIRECTVEntity, RemoteDevice): blue, chanup, chandown, prev, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, dash, enter """ - for single_command in command: - try: - await self.dtv.remote(single_command, self._address) - except DIRECTVError: - _LOGGER.exception( - "Sending command %s to device %s failed", - single_command, - self._device_id, - ) + num_repeats = kwargs[ATTR_NUM_REPEATS] + + for _ in range(num_repeats): + for single_command in command: + try: + await self.dtv.remote(single_command, self._address) + except DIRECTVError: + _LOGGER.exception( + "Sending command %s to device %s failed", + single_command, + self._device_id, + ) From 77d89d13b670cc72d9bce730bb8e52483a102f6d Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 1 May 2020 06:06:16 +0200 Subject: [PATCH 08/15] UniFi - Disconnected clients wrongfully marked as wired not created (#34986) --- homeassistant/components/unifi/device_tracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/unifi/device_tracker.py b/homeassistant/components/unifi/device_tracker.py index 2ac516fac55..b56fe117ef7 100644 --- a/homeassistant/components/unifi/device_tracker.py +++ b/homeassistant/components/unifi/device_tracker.py @@ -101,7 +101,7 @@ def add_entities(controller, async_add_entities): if tracker_class is UniFiClientTracker: - if item.is_wired: + if mac not in controller.wireless_clients: if not controller.option_track_wired_clients: continue else: From b8070567bf516a8dd92969b332129aadb59558b9 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 30 Apr 2020 19:41:24 -0500 Subject: [PATCH 09/15] Log the rachio webhook url (#34992) --- homeassistant/components/rachio/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/rachio/__init__.py b/homeassistant/components/rachio/__init__.py index a5c9f5ab0a9..b84ccb8fa5d 100644 --- a/homeassistant/components/rachio/__init__.py +++ b/homeassistant/components/rachio/__init__.py @@ -123,7 +123,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): if not person.controllers: _LOGGER.error("No Rachio devices found in account %s", person.username) return False - _LOGGER.info("%d Rachio device(s) found", len(person.controllers)) + _LOGGER.info( + "%d Rachio device(s) found; The url %s must be accessible from the internet in order to receive updates", + len(person.controllers), + webhook_url, + ) # Enable component hass.data[DOMAIN][entry.entry_id] = person From b01131ab9deb0e9a262b89ec5082d55b0a5da90d Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Thu, 30 Apr 2020 18:35:32 -0700 Subject: [PATCH 10/15] Add allow extra to totalconnect config schema (#34993) --- homeassistant/components/totalconnect/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index fce67f71b24..25b1141bd9b 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -24,7 +24,8 @@ CONFIG_SCHEMA = vol.Schema( vol.Required(CONF_PASSWORD): cv.string, } ) - } + }, + extra=vol.ALLOW_EXTRA, ) From bc9125666f84398cc5b950220b6e2859088cab43 Mon Sep 17 00:00:00 2001 From: Xiaonan Shen Date: Thu, 30 Apr 2020 21:13:45 -0700 Subject: [PATCH 11/15] Fix roomba not reporting error (#34996) --- homeassistant/components/roomba/irobot_base.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/roomba/irobot_base.py b/homeassistant/components/roomba/irobot_base.py index a62ad4fdd96..1f55ab48d06 100644 --- a/homeassistant/components/roomba/irobot_base.py +++ b/homeassistant/components/roomba/irobot_base.py @@ -3,6 +3,7 @@ import asyncio import logging from homeassistant.components.vacuum import ( + ATTR_STATUS, STATE_CLEANING, STATE_DOCKED, STATE_ERROR, @@ -16,6 +17,7 @@ from homeassistant.components.vacuum import ( SUPPORT_SEND_COMMAND, SUPPORT_START, SUPPORT_STATE, + SUPPORT_STATUS, SUPPORT_STOP, StateVacuumDevice, ) @@ -40,6 +42,7 @@ SUPPORT_IROBOT = ( | SUPPORT_SEND_COMMAND | SUPPORT_START | SUPPORT_STATE + | SUPPORT_STATUS | SUPPORT_STOP | SUPPORT_LOCATE ) @@ -143,7 +146,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumDevice): state = STATE_MAP[phase] except KeyError: return STATE_ERROR - if cycle != "none" and state != STATE_CLEANING and state != STATE_RETURNING: + if cycle != "none" and (state == STATE_IDLE or state == STATE_DOCKED): state = STATE_PAUSED return state @@ -173,6 +176,9 @@ class IRobotVacuum(IRobotEntity, StateVacuumDevice): # Set properties that are to appear in the GUI state_attrs = {ATTR_SOFTWARE_VERSION: software_version} + # Set legacy status to avoid break changes + state_attrs[ATTR_STATUS] = self.vacuum.current_state + # Only add cleaning time and cleaned area attrs when the vacuum is # currently on if self.state == STATE_CLEANING: From af5cdc1f65c04d2fe1c0008dd59dcd974d20d3ca Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 30 Apr 2020 22:27:34 -0700 Subject: [PATCH 12/15] Lint roomba (#35000) --- homeassistant/components/roomba/irobot_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/roomba/irobot_base.py b/homeassistant/components/roomba/irobot_base.py index 1f55ab48d06..4ebe580e7b2 100644 --- a/homeassistant/components/roomba/irobot_base.py +++ b/homeassistant/components/roomba/irobot_base.py @@ -146,7 +146,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumDevice): state = STATE_MAP[phase] except KeyError: return STATE_ERROR - if cycle != "none" and (state == STATE_IDLE or state == STATE_DOCKED): + if cycle != "none" and state in (STATE_IDLE, STATE_DOCKED): state = STATE_PAUSED return state From 837b1384af9e74a5f8c4d7fed81ec3898ba75fe5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 30 Apr 2020 22:41:44 -0700 Subject: [PATCH 13/15] Bumped version to 0.109.2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 2d0212f2a31..9e3be432dfa 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 109 -PATCH_VERSION = "1" +PATCH_VERSION = "2" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 0) From 7e47481676fe013b7dbcc29bc4c5cdda1cf3aa56 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 30 Apr 2020 22:55:59 -0700 Subject: [PATCH 14/15] Fix MQTT test --- tests/components/mqtt/test_init.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index 24b51414944..fa7d49482c8 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -1378,7 +1378,7 @@ async def test_debug_info_same_topic(hass, mqtt_mock): ] start_dt = datetime(2019, 1, 1, 0, 0, 0) - with patch("homeassistant.util.dt.utcnow") as dt_utcnow: + with mock.patch("homeassistant.util.dt.utcnow") as dt_utcnow: dt_utcnow.return_value = start_dt async_fire_mqtt_message(hass, "sensor/status", "123", qos=0, retain=False) @@ -1396,6 +1396,6 @@ async def test_debug_info_same_topic(hass, mqtt_mock): await hass.async_block_till_done() start_dt = datetime(2019, 1, 1, 0, 0, 0) - with patch("homeassistant.util.dt.utcnow") as dt_utcnow: + with mock.patch("homeassistant.util.dt.utcnow") as dt_utcnow: dt_utcnow.return_value = start_dt async_fire_mqtt_message(hass, "sensor/status", "123", qos=0, retain=False) From 421ebb087b0beca0ace258ab7bfab580a56c35ab Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 30 Apr 2020 23:50:16 -0700 Subject: [PATCH 15/15] Fix pylint CI --- azure-pipelines-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/azure-pipelines-ci.yml b/azure-pipelines-ci.yml index af323ecde1a..5322360f1c3 100644 --- a/azure-pipelines-ci.yml +++ b/azure-pipelines-ci.yml @@ -190,6 +190,9 @@ stages: pip install -U pip setuptools wheel pip install -r requirements_all.txt -c homeassistant/package_constraints.txt pip install -r requirements_test.txt -c homeassistant/package_constraints.txt + # This is a TEMP. Eventually we should make sure our 4 dependencies drop typing. + # Find offending deps with `pipdeptree -r -p typing` + pip uninstall -y typing - script: | . venv/bin/activate pip install -e .