diff --git a/API.md b/API.md index 854fd9271..01062d984 100644 --- a/API.md +++ b/API.md @@ -415,7 +415,7 @@ Proxy to real websocket instance. ### RESTful for API addons -If a add-on will call itself, you can use `/addons/self/...`. +If an add-on will call itself, you can use `/addons/self/...`. - GET `/addons` diff --git a/hassio/addons/addon.py b/hassio/addons/addon.py index 78723574d..273c4b4f7 100644 --- a/hassio/addons/addon.py +++ b/hassio/addons/addon.py @@ -674,7 +674,8 @@ class Addon(CoreSysAttributes): """Install an add-on.""" if not self.available: _LOGGER.error( - "Add-on %s not supported on %s", self._id, self.sys_arch) + "Add-on %s not supported on %s with %s architecture", + self._id, self.sys_machine, self.sys_arch) return False if self.is_installed: diff --git a/hassio/api/auth.py b/hassio/api/auth.py index bb03cea87..62a86308d 100644 --- a/hassio/api/auth.py +++ b/hassio/api/auth.py @@ -2,12 +2,13 @@ import logging from aiohttp import BasicAuth -from aiohttp.hdrs import CONTENT_TYPE, AUTHORIZATION +from aiohttp.web_exceptions import HTTPUnauthorized +from aiohttp.hdrs import CONTENT_TYPE, AUTHORIZATION, WWW_AUTHENTICATE from .utils import api_process from ..const import REQUEST_FROM, CONTENT_TYPE_JSON, CONTENT_TYPE_URL from ..coresys import CoreSysAttributes -from ..exceptions import APIError, APIForbidden +from ..exceptions import APIForbidden _LOGGER = logging.getLogger(__name__) @@ -55,4 +56,6 @@ class APIAuth(CoreSysAttributes): data = await request.post() return await self._process_dict(request, addon, data) - raise APIError("Auth method not detected!") + raise HTTPUnauthorized(headers={ + WWW_AUTHENTICATE: "Basic realm=\"Hass.io Authentication\"" + }) diff --git a/hassio/api/proxy.py b/hassio/api/proxy.py index f67a1adc5..424c4affa 100644 --- a/hassio/api/proxy.py +++ b/hassio/api/proxy.py @@ -153,7 +153,7 @@ class APIProxy(CoreSysAttributes): except (RuntimeError, ValueError, ClientConnectorError) as err: _LOGGER.error("Client error on WebSocket API %s.", err) - except HomeAssistantAuthError as err: + except HomeAssistantAuthError: _LOGGER.error("Failed authentication to Home Assistant WebSocket") raise APIError() diff --git a/hassio/const.py b/hassio/const.py index 7bb2bfcfa..a7304524a 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -2,7 +2,7 @@ from pathlib import Path from ipaddress import ip_network -HASSIO_VERSION = '138' +HASSIO_VERSION = '139' URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons" URL_HASSIO_VERSION = \ @@ -259,3 +259,6 @@ ROLE_HOMEASSISTANT = 'homeassistant' ROLE_BACKUP = 'backup' ROLE_MANAGER = 'manager' ROLE_ADMIN = 'admin' + +CHAN_ID = 'chan_id' +CHAN_TYPE = 'chan_type' diff --git a/hassio/discovery.py b/hassio/discovery.py index 8d0632b37..27b9a25e7 100644 --- a/hassio/discovery.py +++ b/hassio/discovery.py @@ -36,6 +36,7 @@ class Discovery(CoreSysAttributes, JsonConfig): discovery = Message(**message) messages[discovery.uuid] = discovery + _LOGGER.info("Load %d messages", len(messages)) self.message_obj = messages def save(self): @@ -60,7 +61,7 @@ class Discovery(CoreSysAttributes, JsonConfig): def send(self, addon, service, config): """Send a discovery message to Home Assistant.""" try: - DISCOVERY_SERVICES[service](config) + config = DISCOVERY_SERVICES[service](config) except vol.Invalid as err: _LOGGER.error( "Invalid discovery %s config", humanize_error(config, err)) @@ -115,7 +116,7 @@ class Discovery(CoreSysAttributes, JsonConfig): @attr.s class Message: """Represent a single Discovery message.""" - uuid = attr.ib(factory=lambda: uuid4().hex, cmp=False, init=False) addon = attr.ib() service = attr.ib() config = attr.ib(cmp=False) + uuid = attr.ib(factory=lambda: uuid4().hex, cmp=False) diff --git a/hassio/hassos.py b/hassio/hassos.py index 05c36dcb4..6a25bd543 100644 --- a/hassio/hassos.py +++ b/hassio/hassos.py @@ -66,7 +66,7 @@ class HassOS(CoreSysAttributes): return self._board def _check_host(self): - """Check if HassOS is availabe.""" + """Check if HassOS is available.""" if not self.available: _LOGGER.error("No HassOS available") raise HassOSNotSupportedError() diff --git a/hassio/homeassistant.py b/hassio/homeassistant.py index b6afc8d99..a4b8e57fb 100644 --- a/hassio/homeassistant.py +++ b/hassio/homeassistant.py @@ -191,7 +191,7 @@ class HomeAssistant(JsonConfig, CoreSysAttributes): @property def hassio_token(self): - """Return a access token for the Hass.io API.""" + """Return an access token for the Hass.io API.""" return self._data.get(ATTR_ACCESS_TOKEN) @property @@ -260,7 +260,7 @@ class HomeAssistant(JsonConfig, CoreSysAttributes): _LOGGER.warning("Version %s is already installed", version) return HomeAssistantUpdateError() - # process a update + # process an update async def _update(to_version): """Run Home Assistant update.""" try: diff --git a/hassio/host/alsa.py b/hassio/host/alsa.py index e6210e1a6..749105539 100644 --- a/hassio/host/alsa.py +++ b/hassio/host/alsa.py @@ -6,7 +6,8 @@ from string import Template import attr -from ..const import ATTR_INPUT, ATTR_OUTPUT, ATTR_DEVICES, ATTR_NAME +from ..const import ( + ATTR_INPUT, ATTR_OUTPUT, ATTR_DEVICES, ATTR_NAME, CHAN_ID, CHAN_TYPE) from ..coresys import CoreSysAttributes _LOGGER = logging.getLogger(__name__) @@ -58,7 +59,9 @@ class AlsaAudio(CoreSysAttributes): # Process devices for dev_id, dev_data in self.sys_hardware.audio_devices.items(): - for chan_id, chan_type in dev_data[ATTR_DEVICES].items(): + for chan_info in dev_data[ATTR_DEVICES]: + chan_id = chan_info[CHAN_ID] + chan_type = chan_info[CHAN_TYPE] alsa_id = f"{dev_id},{chan_id}" dev_name = dev_data[ATTR_NAME] diff --git a/hassio/misc/hardware.py b/hassio/misc/hardware.py index 2e205a691..0183fb0fe 100644 --- a/hassio/misc/hardware.py +++ b/hassio/misc/hardware.py @@ -6,7 +6,7 @@ import re import pyudev -from ..const import ATTR_NAME, ATTR_TYPE, ATTR_DEVICES +from ..const import ATTR_NAME, ATTR_TYPE, ATTR_DEVICES, CHAN_ID, CHAN_TYPE _LOGGER = logging.getLogger(__name__) @@ -87,14 +87,16 @@ class Hardware: audio_list[match.group(1)] = { ATTR_NAME: match.group(3), ATTR_TYPE: match.group(2), - ATTR_DEVICES: {}, + ATTR_DEVICES: [], } # parse devices for match in RE_DEVICES.finditer(devices): try: - audio_list[match.group(1)][ATTR_DEVICES][match.group(2)] = \ - match.group(3) + audio_list[match.group(1)][ATTR_DEVICES].append({ + CHAN_ID: match.group(2), + CHAN_TYPE: match.group(3) + }) except KeyError: _LOGGER.warning("Wrong audio device found %s", match.group(0)) continue diff --git a/hassio/snapshots/__init__.py b/hassio/snapshots/__init__.py index f7f6c322f..8440e2164 100644 --- a/hassio/snapshots/__init__.py +++ b/hassio/snapshots/__init__.py @@ -118,7 +118,7 @@ class SnapshotManager(CoreSysAttributes): async def do_snapshot_full(self, name="", password=None): """Create a full snapshot.""" if self.lock.locked(): - _LOGGER.error("It is already a snapshot/restore process running") + _LOGGER.error("A snapshot/restore process is already running") return None snapshot = self._create_snapshot(name, SNAPSHOT_FULL, password) @@ -153,7 +153,7 @@ class SnapshotManager(CoreSysAttributes): password=None): """Create a partial snapshot.""" if self.lock.locked(): - _LOGGER.error("It is already a snapshot/restore process running") + _LOGGER.error("A snapshot/restore process is already running") return None addons = addons or [] @@ -201,7 +201,7 @@ class SnapshotManager(CoreSysAttributes): async def do_restore_full(self, snapshot, password=None): """Restore a snapshot.""" if self.lock.locked(): - _LOGGER.error("It is already a snapshot/restore process running") + _LOGGER.error("A snapshot/restore process is already running") return False if snapshot.sys_type != SNAPSHOT_FULL: @@ -274,7 +274,7 @@ class SnapshotManager(CoreSysAttributes): addons=None, folders=None, password=None): """Restore a snapshot.""" if self.lock.locked(): - _LOGGER.error("It is already a snapshot/restore process running") + _LOGGER.error("A snapshot/restore process is already running") return False if snapshot.protected and not snapshot.set_password(password): diff --git a/hassio/tasks.py b/hassio/tasks.py index 9ffd6eaed..a4da05c7a 100644 --- a/hassio/tasks.py +++ b/hassio/tasks.py @@ -3,6 +3,7 @@ import asyncio import logging from .coresys import CoreSysAttributes +from .exceptions import HomeAssistantError _LOGGER = logging.getLogger(__name__) @@ -104,7 +105,10 @@ class Tasks(CoreSysAttributes): return _LOGGER.warning("Watchdog found a problem with Home Assistant Docker!") - await self.sys_homeassistant.start() + try: + await self.sys_homeassistant.start() + except HomeAssistantError: + _LOGGER.error("Watchdog Home Assistant reanimation fails!") async def _watchdog_homeassistant_api(self): """Create scheduler task for monitoring running state of API. @@ -136,6 +140,8 @@ class Tasks(CoreSysAttributes): _LOGGER.error("Watchdog found a problem with Home Assistant API!") try: await self.sys_homeassistant.restart() + except HomeAssistantError: + _LOGGER.error("Watchdog Home Assistant reanimation fails!") finally: self._cache[HASS_WATCHDOG_API] = 0 diff --git a/requirements.txt b/requirements.txt index 4cd773e76..6be677b2e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -attr==0.3.1 +attrs==18.2.0 async_timeout==3.0.1 aiohttp==3.4.4 docker==3.5.0 diff --git a/tox.ini b/tox.ini index 23310edf9..16c09e69f 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ envlist = lint [testenv] deps = - flake8==3.5.0 + flake8==3.6.0 pylint==2.1.1 -r{toxinidir}/requirements.txt