diff --git a/homeassistant/components/alexa/smart_home.py b/homeassistant/components/alexa/smart_home.py index e16a1d45ab7..8a95f4702c7 100644 --- a/homeassistant/components/alexa/smart_home.py +++ b/homeassistant/components/alexa/smart_home.py @@ -911,13 +911,17 @@ class _MediaPlayerCapabilities(_AlexaEntity): return [_DisplayCategory.TV] def interfaces(self): - yield _AlexaPowerController(self.entity) yield _AlexaEndpointHealth(self.hass, self.entity) supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) if supported & media_player.const.SUPPORT_VOLUME_SET: yield _AlexaSpeaker(self.entity) + power_features = (media_player.SUPPORT_TURN_ON | + media_player.SUPPORT_TURN_OFF) + if supported & power_features: + yield _AlexaPowerController(self.entity) + step_volume_features = (media_player.const.SUPPORT_VOLUME_MUTE | media_player.const.SUPPORT_VOLUME_STEP) if supported & step_volume_features: diff --git a/homeassistant/components/auth/indieauth.py b/homeassistant/components/auth/indieauth.py index 1437685692b..a56671c9dcd 100644 --- a/homeassistant/components/auth/indieauth.py +++ b/homeassistant/components/auth/indieauth.py @@ -6,7 +6,6 @@ from html.parser import HTMLParser from urllib.parse import urlparse, urljoin import aiohttp -from aiohttp.client_exceptions import ClientError from homeassistant.util.network import is_local @@ -81,8 +80,22 @@ async def fetch_redirect_uris(hass, url): if chunks == 10: break - except (asyncio.TimeoutError, ClientError) as ex: - _LOGGER.error("Error while looking up redirect_uri %s: %s", url, ex) + except asyncio.TimeoutError: + _LOGGER.error("Timeout while looking up redirect_uri %s", url) + pass + except aiohttp.client_exceptions.ClientSSLError: + _LOGGER.error("SSL error while looking up redirect_uri %s", url) + pass + except aiohttp.client_exceptions.ClientOSError as ex: + _LOGGER.error("OS error while looking up redirect_uri %s: %s", url, + ex.strerror) + pass + except aiohttp.client_exceptions.ClientConnectionError: + _LOGGER.error(("Low level connection error while looking up " + "redirect_uri %s"), url) + pass + except aiohttp.client_exceptions.ClientError: + _LOGGER.error("Unknown error while looking up redirect_uri %s", url) pass # Authorization endpoints verifying that a redirect_uri is allowed for use diff --git a/homeassistant/components/cast/manifest.json b/homeassistant/components/cast/manifest.json index c506dba8cf1..dd189ac91e7 100644 --- a/homeassistant/components/cast/manifest.json +++ b/homeassistant/components/cast/manifest.json @@ -3,7 +3,7 @@ "name": "Cast", "documentation": "https://www.home-assistant.io/components/cast", "requirements": [ - "pychromecast==3.2.0" + "pychromecast==3.2.1" ], "dependencies": [], "codeowners": [] diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index 4b2972b0c00..35fe29809f8 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -659,7 +659,7 @@ class CastDevice(MediaPlayerDevice): self.entity_id, self._cast_info.friendly_name, self._cast_info.host, self._cast_info.port, cast_info) - self.async_del_dynamic_group() + await self.async_del_dynamic_group() self._dynamic_group_cast_info = cast_info # pylint: disable=protected-access diff --git a/homeassistant/components/cloud/__init__.py b/homeassistant/components/cloud/__init__.py index 1ad76c3d7aa..d4d443a692d 100644 --- a/homeassistant/components/cloud/__init__.py +++ b/homeassistant/components/cloud/__init__.py @@ -122,6 +122,9 @@ def async_remote_ui_url(hass) -> str: if not async_is_logged_in(hass): raise CloudNotAvailable + if not hass.data[DOMAIN].remote.instance_domain: + raise CloudNotAvailable + return "https://" + hass.data[DOMAIN].remote.instance_domain diff --git a/homeassistant/components/cloud/client.py b/homeassistant/components/cloud/client.py index 5bbd7bb48fa..f47eae74986 100644 --- a/homeassistant/components/cloud/client.py +++ b/homeassistant/components/cloud/client.py @@ -100,10 +100,13 @@ class CloudClient(Interface): return google_conf['filter'](entity.entity_id) + username = self._hass.data[DOMAIN].claims["cognito:username"] + self._google_config = ga_h.Config( should_expose=should_expose, secure_devices_pin=self._prefs.google_secure_devices_pin, entity_config=google_conf.get(CONF_ENTITY_CONFIG), + agent_user_id=username, ) # Set it to the latest. @@ -149,19 +152,10 @@ class CloudClient(Interface): if not self._prefs.google_enabled: return ga.turned_off_response(payload) - answer = await ga.async_handle_message( + return await ga.async_handle_message( self._hass, self.google_config, self.prefs.cloud_user, payload ) - # Fix AgentUserId - try: - cloud = self._hass.data[DOMAIN] - answer['payload']['agentUserId'] = cloud.claims['cognito:username'] - except (TypeError, KeyError): - return ga.turned_off_response(payload) - - return answer - async def async_webhook_message( self, payload: Dict[Any, Any]) -> Dict[Any, Any]: """Process cloud webhook message to client.""" diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index 608687610e4..0a82a36536f 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -3,7 +3,7 @@ "name": "Home Assistant Frontend", "documentation": "https://www.home-assistant.io/components/frontend", "requirements": [ - "home-assistant-frontend==20190424.0" + "home-assistant-frontend==20190427.0" ], "dependencies": [ "api", diff --git a/homeassistant/components/geniushub/manifest.json b/homeassistant/components/geniushub/manifest.json index 4546be8078b..78efeca7311 100644 --- a/homeassistant/components/geniushub/manifest.json +++ b/homeassistant/components/geniushub/manifest.json @@ -3,7 +3,7 @@ "name": "Genius Hub", "documentation": "https://www.home-assistant.io/components/geniushub", "requirements": [ - "geniushub-client==0.3.6" + "geniushub-client==0.4.5" ], "dependencies": [], "codeowners": [] diff --git a/homeassistant/components/google_assistant/helpers.py b/homeassistant/components/google_assistant/helpers.py index 71cce9de500..4d3f2855b31 100644 --- a/homeassistant/components/google_assistant/helpers.py +++ b/homeassistant/components/google_assistant/helpers.py @@ -20,12 +20,16 @@ class Config: """Hold the configuration for Google Assistant.""" def __init__(self, should_expose, - entity_config=None, secure_devices_pin=None): + entity_config=None, secure_devices_pin=None, + agent_user_id=None): """Initialize the configuration.""" self.should_expose = should_expose self.entity_config = entity_config or {} self.secure_devices_pin = secure_devices_pin + # Agent User Id to use for query responses + self.agent_user_id = agent_user_id + class RequestData: """Hold data associated with a particular request.""" diff --git a/homeassistant/components/google_assistant/smart_home.py b/homeassistant/components/google_assistant/smart_home.py index 37f35edf645..1ec47bbedd6 100644 --- a/homeassistant/components/google_assistant/smart_home.py +++ b/homeassistant/components/google_assistant/smart_home.py @@ -99,7 +99,7 @@ async def async_devices_sync(hass, data, payload): devices.append(serialized) response = { - 'agentUserId': data.context.user_id, + 'agentUserId': data.config.agent_user_id or data.context.user_id, 'devices': devices, } diff --git a/homeassistant/components/heos/__init__.py b/homeassistant/components/heos/__init__.py index 529ee27997e..334c2572e74 100644 --- a/homeassistant/components/heos/__init__.py +++ b/homeassistant/components/heos/__init__.py @@ -195,7 +195,7 @@ class SourceManager: exc_info=isinstance(error, CommandError)) return - async def update_sources(event): + async def update_sources(event, data): if event in (const.EVENT_SOURCES_CHANGED, const.EVENT_USER_CHANGED): sources = await get_sources() diff --git a/homeassistant/components/heos/manifest.json b/homeassistant/components/heos/manifest.json index 5b0a8e67893..3faa346988c 100644 --- a/homeassistant/components/heos/manifest.json +++ b/homeassistant/components/heos/manifest.json @@ -3,7 +3,7 @@ "name": "Heos", "documentation": "https://www.home-assistant.io/components/heos", "requirements": [ - "pyheos==0.4.1" + "pyheos==0.5.1" ], "dependencies": [], "codeowners": [ diff --git a/homeassistant/components/heos/media_player.py b/homeassistant/components/heos/media_player.py index e2a5b3177e0..739667f5834 100644 --- a/homeassistant/components/heos/media_player.py +++ b/homeassistant/components/heos/media_player.py @@ -78,7 +78,7 @@ class HeosMediaPlayer(MediaPlayerDevice): const.CONTROL_PLAY_NEXT: SUPPORT_NEXT_TRACK } - async def _controller_event(self, event): + async def _controller_event(self, event, data): """Handle controller event.""" from pyheos import const if event == const.EVENT_PLAYERS_CHANGED: diff --git a/homeassistant/components/hue/sensor.py b/homeassistant/components/hue/sensor.py index 30a439f92e9..7664bd38d97 100644 --- a/homeassistant/components/hue/sensor.py +++ b/homeassistant/components/hue/sensor.py @@ -32,6 +32,9 @@ class HueLightLevel(GenericHueGaugeSensorEntity): @property def state(self): """Return the state of the device.""" + if self.sensor.lightlevel is None: + return None + # https://developers.meethue.com/develop/hue-api/supported-devices/#clip_zll_lightlevel # Light level in 10000 log10 (lux) +1 measured by sensor. Logarithm # scale used because the human eye adjusts to light levels and small @@ -59,4 +62,7 @@ class HueTemperature(GenericHueGaugeSensorEntity): @property def state(self): """Return the state of the device.""" + if self.sensor.temperature is None: + return None + return self.sensor.temperature / 100 diff --git a/homeassistant/components/myq/manifest.json b/homeassistant/components/myq/manifest.json index c4057fecb25..b870ff66309 100644 --- a/homeassistant/components/myq/manifest.json +++ b/homeassistant/components/myq/manifest.json @@ -3,7 +3,7 @@ "name": "Myq", "documentation": "https://www.home-assistant.io/components/myq", "requirements": [ - "pymyq==1.2.0" + "pymyq==1.2.1" ], "dependencies": [], "codeowners": [] diff --git a/homeassistant/components/netatmo_public/sensor.py b/homeassistant/components/netatmo_public/sensor.py index 814675ca8b7..8295c0c0688 100644 --- a/homeassistant/components/netatmo_public/sensor.py +++ b/homeassistant/components/netatmo_public/sensor.py @@ -12,6 +12,8 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle +from homeassistant.components.netatmo.const import DATA_NETATMO_AUTH + _LOGGER = logging.getLogger(__name__) CONF_AREAS = 'areas' @@ -54,12 +56,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the access to Netatmo binary sensor.""" - netatmo = hass.components.netatmo + auth = hass.data[DATA_NETATMO_AUTH] sensors = [] areas = config.get(CONF_AREAS) for area_conf in areas: - data = NetatmoPublicData(netatmo.NETATMO_AUTH, + data = NetatmoPublicData(auth, lat_ne=area_conf.get(CONF_LAT_NE), lon_ne=area_conf.get(CONF_LON_NE), lat_sw=area_conf.get(CONF_LAT_SW), diff --git a/homeassistant/components/traccar/device_tracker.py b/homeassistant/components/traccar/device_tracker.py index 1600227bfe2..1fef18a6ae1 100644 --- a/homeassistant/components/traccar/device_tracker.py +++ b/homeassistant/components/traccar/device_tracker.py @@ -170,7 +170,7 @@ class TraccarScanner: if events is not None: for event in events: device_name = next(( - dev.get('name') for dev in self._api.devices() + dev.get('name') for dev in self._api.devices if dev.get('id') == event['deviceId']), None) self._hass.bus.async_fire( 'traccar_' + self._event_types.get(event["type"]), { diff --git a/homeassistant/components/upnp/sensor.py b/homeassistant/components/upnp/sensor.py index 411d529b33f..0527904a083 100644 --- a/homeassistant/components/upnp/sensor.py +++ b/homeassistant/components/upnp/sensor.py @@ -3,7 +3,6 @@ from datetime import datetime import logging from homeassistant.core import callback -from homeassistant.helpers import device_registry as dr from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity import Entity from homeassistant.helpers.typing import HomeAssistantType @@ -108,9 +107,6 @@ class UpnpSensor(Entity): 'identifiers': { (DOMAIN_UPNP, self.unique_id) }, - 'connections': { - (dr.CONNECTION_UPNP, self._device.udn) - }, 'name': self.name, 'manufacturer': self._device.manufacturer, } diff --git a/homeassistant/const.py b/homeassistant/const.py index f38b1496994..8c012fcac8e 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 92 -PATCH_VERSION = '1' +PATCH_VERSION = '2' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) diff --git a/requirements_all.txt b/requirements_all.txt index b522da9f9c2..c2a8f6b90d6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -459,7 +459,7 @@ gearbest_parser==1.0.7 geizhals==0.0.9 # homeassistant.components.geniushub -geniushub-client==0.3.6 +geniushub-client==0.4.5 # homeassistant.components.geo_json_events # homeassistant.components.nsw_rural_fire_service_feed @@ -548,7 +548,7 @@ hole==0.3.0 holidays==0.9.10 # homeassistant.components.frontend -home-assistant-frontend==20190424.0 +home-assistant-frontend==20190427.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.4 @@ -976,7 +976,7 @@ pycfdns==0.0.1 pychannels==1.0.0 # homeassistant.components.cast -pychromecast==3.2.0 +pychromecast==3.2.1 # homeassistant.components.cmus pycmus==0.1.1 @@ -1073,7 +1073,7 @@ pygtt==1.1.2 pyhaversion==2.2.1 # homeassistant.components.heos -pyheos==0.4.1 +pyheos==0.5.1 # homeassistant.components.hikvision pyhik==0.2.2 @@ -1166,7 +1166,7 @@ pymonoprice==0.3 pymusiccast==0.1.6 # homeassistant.components.myq -pymyq==1.2.0 +pymyq==1.2.1 # homeassistant.components.mysensors pymysensors==0.18.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 2c0f5d40f4a..dc1e770aa50 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -136,7 +136,7 @@ hdate==0.8.7 holidays==0.9.10 # homeassistant.components.frontend -home-assistant-frontend==20190424.0 +home-assistant-frontend==20190427.0 # homeassistant.components.homekit_controller homekit[IP]==0.13.0 @@ -217,7 +217,7 @@ pydeconz==54 pydispatcher==2.0.5 # homeassistant.components.heos -pyheos==0.4.1 +pyheos==0.5.1 # homeassistant.components.homematic pyhomematic==0.1.58 diff --git a/tests/components/alexa/test_smart_home.py b/tests/components/alexa/test_smart_home.py index 924a568dea2..20b4495cd1a 100644 --- a/tests/components/alexa/test_smart_home.py +++ b/tests/components/alexa/test_smart_home.py @@ -574,6 +574,32 @@ async def test_media_player(hass): payload={'volumeSteps': -20}) +async def test_media_player_power(hass): + """Test media player discovery with mapped on/off.""" + device = ( + 'media_player.test', + 'off', { + 'friendly_name': "Test media player", + 'supported_features': 0xfa3f, + 'volume_level': 0.75 + } + ) + appliance = await discovery_test(device, hass) + + assert appliance['endpointId'] == 'media_player#test' + assert appliance['displayCategories'][0] == "TV" + assert appliance['friendlyName'] == "Test media player" + + assert_endpoint_capabilities( + appliance, + 'Alexa.InputController', + 'Alexa.Speaker', + 'Alexa.StepSpeaker', + 'Alexa.PlaybackController', + 'Alexa.EndpointHealth', + ) + + async def test_alert(hass): """Test alert discovery.""" device = ('alert.test', 'off', {'friendly_name': "Test alert"}) diff --git a/tests/components/heos/test_init.py b/tests/components/heos/test_init.py index 408b2f7d088..2276f4ce2eb 100644 --- a/tests/components/heos/test_init.py +++ b/tests/components/heos/test_init.py @@ -161,7 +161,7 @@ async def test_update_sources_retry(hass, config_entry, config, controller, source_manager.max_retry_attempts = 1 controller.get_favorites.side_effect = CommandError("Test", "test", 0) controller.dispatcher.send( - const.SIGNAL_CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED) + const.SIGNAL_CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED, {}) # Wait until it's finished while "Unable to update sources" not in caplog.text: await asyncio.sleep(0.1) diff --git a/tests/components/heos/test_media_player.py b/tests/components/heos/test_media_player.py index 4888018af04..d2a1abf72f6 100644 --- a/tests/components/heos/test_media_player.py +++ b/tests/components/heos/test_media_player.py @@ -103,7 +103,7 @@ async def test_updates_start_from_signals( # Test controller player change updates player.available = False player.heos.dispatcher.send( - const.SIGNAL_CONTROLLER_EVENT, const.EVENT_PLAYERS_CHANGED) + const.SIGNAL_CONTROLLER_EVENT, const.EVENT_PLAYERS_CHANGED, {}) await hass.async_block_till_done() state = hass.states.get('media_player.test_player') assert state.state == STATE_UNAVAILABLE @@ -158,7 +158,7 @@ async def test_updates_from_sources_updated( input_sources.clear() player.heos.dispatcher.send( - const.SIGNAL_CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED) + const.SIGNAL_CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED, {}) await event.wait() source_list = hass.data[DOMAIN][DATA_SOURCE_MANAGER].source_list assert len(source_list) == 2 @@ -181,7 +181,7 @@ async def test_updates_from_user_changed( controller.is_signed_in = False controller.signed_in_username = None player.heos.dispatcher.send( - const.SIGNAL_CONTROLLER_EVENT, const.EVENT_USER_CHANGED) + const.SIGNAL_CONTROLLER_EVENT, const.EVENT_USER_CHANGED, None) await event.wait() source_list = hass.data[DOMAIN][DATA_SOURCE_MANAGER].source_list assert len(source_list) == 1