diff --git a/API.md b/API.md
index aac11806b..58e5d136c 100644
--- a/API.md
+++ b/API.md
@@ -236,15 +236,6 @@ return:
}
```
-- POST `/host/options`
-
-```json
-{
- "audio_input": "0,0",
- "audio_output": "0,0"
-}
-```
-
- POST `/host/update`
Optional:
@@ -255,7 +246,11 @@ Optional:
}
```
-- GET `/host/hardware`
+- POST `/host/reload`
+
+### Hardware
+
+- GET `/hardware/info`
```json
{
"serial": ["/dev/xy"],
@@ -274,7 +269,20 @@ Optional:
}
```
-- POST `/host/reload`
+- GET `/hardware/audio`
+```json
+{
+ "audio": {
+ "input": {
+ "0,0": "Mic"
+ },
+ "output": {
+ "1,0": "Jack",
+ "1,1": "HDMI"
+ }
+ }
+}
+```
### Network
@@ -410,6 +418,7 @@ Get all available addons.
```json
{
"name": "xy bla",
+ "slug": "xdssd_xybla",
"description": "description",
"long_description": "null|markdown",
"auto_update": "bool",
diff --git a/hassio/addons/addon.py b/hassio/addons/addon.py
index b3d6660d8..e17f3f7a5 100644
--- a/hassio/addons/addon.py
+++ b/hassio/addons/addon.py
@@ -1,4 +1,5 @@
"""Init file for HassIO addons."""
+from contextlib import suppress
from copy import deepcopy
import logging
import json
@@ -372,15 +373,14 @@ class Addon(CoreSysAttributes):
if not self.with_audio:
return None
- setting = self._config.audio_output
if self.is_installed and \
ATTR_AUDIO_OUTPUT in self._data.user[self._id]:
- setting = self._data.user[self._id][ATTR_AUDIO_OUTPUT]
- return setting
+ return self._data.user[self._id][ATTR_AUDIO_OUTPUT]
+ return self._alsa.default.output
@audio_output.setter
def audio_output(self, value):
- """Set/remove custom audio output settings."""
+ """Set/reset audio output settings."""
if value is None:
self._data.user[self._id].pop(ATTR_AUDIO_OUTPUT, None)
else:
@@ -392,14 +392,13 @@ class Addon(CoreSysAttributes):
if not self.with_audio:
return None
- setting = self._config.audio_input
if self.is_installed and ATTR_AUDIO_INPUT in self._data.user[self._id]:
- setting = self._data.user[self._id][ATTR_AUDIO_INPUT]
- return setting
+ return self._data.user[self._id][ATTR_AUDIO_INPUT]
+ return self._alsa.default.input
@audio_input.setter
def audio_input(self, value):
- """Set/remove custom audio input settings."""
+ """Set/reset audio input settings."""
if value is None:
self._data.user[self._id].pop(ATTR_AUDIO_INPUT, None)
else:
@@ -504,6 +503,16 @@ class Addon(CoreSysAttributes):
"""Return path to custom AppArmor profile."""
return Path(self.path_location, 'apparmor')
+ @property
+ def path_asound(self):
+ """Return path to asound config."""
+ return Path(self._config.path_tmp, f"{self.slug}_asound")
+
+ @property
+ def path_extern_asound(self):
+ """Return path to asound config for docker."""
+ return Path(self._config.path_extern_tmp, f"{self.slug}_asound")
+
def save_data(self):
"""Save data of addon."""
self._addons.data.save_data()
@@ -526,6 +535,20 @@ class Addon(CoreSysAttributes):
return False
+ def write_asound(self):
+ """Write asound config to file and return True on success."""
+ asound_config = self._alsa.asound(
+ alsa_input=self.audio_input, alsa_output=self.audio_output)
+
+ try:
+ with self.path_asound.open('w') as config_file:
+ config_file.write(asound_config)
+ except OSError as err:
+ _LOGGER.error("Addon %s can't write asound: %s", self._id, err)
+ return False
+
+ return True
+
@property
def schema(self):
"""Create a schema for addon options."""
@@ -598,6 +621,11 @@ class Addon(CoreSysAttributes):
"Remove Home-Assistant addon data folder %s", self.path_data)
shutil.rmtree(str(self.path_data))
+ # Cleanup audio settings
+ if self.path_asound.exists():
+ with suppress(OSError):
+ self.path_asound.unlink()
+
self._set_uninstall()
return True
@@ -613,9 +641,14 @@ class Addon(CoreSysAttributes):
@check_installed
async def start(self):
"""Set options and start addon."""
+ # Options
if not self.write_options():
return False
+ # Sound
+ if self.with_audio and not self.write_asound():
+ return False
+
return await self.instance.run()
@check_installed
diff --git a/hassio/addons/validate.py b/hassio/addons/validate.py
index c5ed81d28..cc0fde405 100644
--- a/hassio/addons/validate.py
+++ b/hassio/addons/validate.py
@@ -19,7 +19,7 @@ from ..const import (
ATTR_ARGS, ATTR_GPIO, ATTR_HOMEASSISTANT_API, ATTR_STDIN, ATTR_LEGACY,
ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_SERVICES, ATTR_DISCOVERY,
ATTR_SECCOMP, ATTR_APPARMOR)
-from ..validate import NETWORK_PORT, DOCKER_PORTS, ALSA_CHANNEL
+from ..validate import NETWORK_PORT, DOCKER_PORTS, ALSA_DEVICE
_LOGGER = logging.getLogger(__name__)
@@ -165,8 +165,8 @@ SCHEMA_ADDON_USER = vol.Schema({
vol.Optional(ATTR_BOOT):
vol.In([BOOT_AUTO, BOOT_MANUAL]),
vol.Optional(ATTR_NETWORK): DOCKER_PORTS,
- vol.Optional(ATTR_AUDIO_OUTPUT): ALSA_CHANNEL,
- vol.Optional(ATTR_AUDIO_INPUT): ALSA_CHANNEL,
+ vol.Optional(ATTR_AUDIO_OUTPUT): ALSA_DEVICE,
+ vol.Optional(ATTR_AUDIO_INPUT): ALSA_DEVICE,
}, extra=vol.REMOVE_EXTRA)
diff --git a/hassio/api/__init__.py b/hassio/api/__init__.py
index c3d878751..b91d79485 100644
--- a/hassio/api/__init__.py
+++ b/hassio/api/__init__.py
@@ -7,6 +7,7 @@ from aiohttp import web
from .addons import APIAddons
from .discovery import APIDiscovery
from .homeassistant import APIHomeAssistant
+from .hardware import APIHardware
from .host import APIHost
from .network import APINetwork
from .proxy import APIProxy
@@ -37,6 +38,7 @@ class RestAPI(CoreSysAttributes):
"""Register REST API Calls."""
self._register_supervisor()
self._register_host()
+ self._register_hardware()
self._register_homeassistant()
self._register_proxy()
self._register_panel()
@@ -53,11 +55,9 @@ class RestAPI(CoreSysAttributes):
self.webapp.add_routes([
web.get('/host/info', api_host.info),
- web.get('/host/hardware', api_host.hardware),
web.post('/host/reboot', api_host.reboot),
web.post('/host/shutdown', api_host.shutdown),
web.post('/host/update', api_host.update),
- web.post('/host/options', api_host.options),
web.post('/host/reload', api_host.reload),
])
@@ -71,6 +71,16 @@ class RestAPI(CoreSysAttributes):
web.post('/network/options', api_net.options),
])
+ def _register_hardware(self):
+ """Register hardware function."""
+ api_hardware = APIHardware()
+ api_hardware.coresys = self.coresys
+
+ self.webapp.add_routes([
+ web.get('/hardware/info', api_hardware.info),
+ web.get('/hardware/audio', api_hardware.audio),
+ ])
+
def _register_supervisor(self):
"""Register supervisor function."""
api_supervisor = APISupervisor()
diff --git a/hassio/api/addons.py b/hassio/api/addons.py
index bb00750e2..a4d5b4593 100644
--- a/hassio/api/addons.py
+++ b/hassio/api/addons.py
@@ -20,7 +20,7 @@ from ..const import (
ATTR_DISCOVERY, ATTR_SECCOMP, ATTR_APPARMOR,
CONTENT_TYPE_PNG, CONTENT_TYPE_BINARY, CONTENT_TYPE_TEXT)
from ..coresys import CoreSysAttributes
-from ..validate import DOCKER_PORTS
+from ..validate import DOCKER_PORTS, ALSA_DEVICE
_LOGGER = logging.getLogger(__name__)
@@ -33,6 +33,8 @@ SCHEMA_OPTIONS = vol.Schema({
vol.Optional(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]),
vol.Optional(ATTR_NETWORK): vol.Any(None, DOCKER_PORTS),
vol.Optional(ATTR_AUTO_UPDATE): vol.Boolean(),
+ vol.Optional(ATTR_AUDIO_OUTPUT): ALSA_DEVICE,
+ vol.Optional(ATTR_AUDIO_INPUT): ALSA_DEVICE,
})
@@ -106,6 +108,7 @@ class APIAddons(CoreSysAttributes):
return {
ATTR_NAME: addon.name,
+ ATTR_SLUG: addon.slug,
ATTR_DESCRIPTON: addon.description,
ATTR_LONG_DESCRIPTION: addon.long_description,
ATTR_VERSION: addon.version_installed,
diff --git a/hassio/api/hardware.py b/hassio/api/hardware.py
new file mode 100644
index 000000000..e5e22a35f
--- /dev/null
+++ b/hassio/api/hardware.py
@@ -0,0 +1,34 @@
+"""Init file for HassIO hardware rest api."""
+import logging
+
+from .utils import api_process
+from ..const import (
+ ATTR_SERIAL, ATTR_DISK, ATTR_GPIO, ATTR_AUDIO, ATTR_INPUT, ATTR_OUTPUT)
+from ..coresys import CoreSysAttributes
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class APIHardware(CoreSysAttributes):
+ """Handle rest api for hardware functions."""
+
+ @api_process
+ async def info(self, request):
+ """Show hardware info."""
+ return {
+ ATTR_SERIAL: list(self._hardware.serial_devices),
+ ATTR_INPUT: list(self._hardware.input_devices),
+ ATTR_DISK: list(self._hardware.disk_devices),
+ ATTR_GPIO: list(self._hardware.gpio_devices),
+ ATTR_AUDIO: self._hardware.audio_devices,
+ }
+
+ @api_process
+ async def audio(self, request):
+ """Show ALSA audio devices."""
+ return {
+ ATTR_AUDIO: {
+ ATTR_INPUT: self._alsa.input_devices,
+ ATTR_OUTPUT: self._alsa.output_devices,
+ }
+ }
diff --git a/hassio/api/host.py b/hassio/api/host.py
index 7bc69826e..a0b63f2c9 100644
--- a/hassio/api/host.py
+++ b/hassio/api/host.py
@@ -7,10 +7,8 @@ import voluptuous as vol
from .utils import api_process_hostcontrol, api_process, api_validate
from ..const import (
ATTR_VERSION, ATTR_LAST_VERSION, ATTR_TYPE, ATTR_HOSTNAME, ATTR_FEATURES,
- ATTR_OS, ATTR_SERIAL, ATTR_INPUT, ATTR_DISK, ATTR_AUDIO, ATTR_AUDIO_INPUT,
- ATTR_AUDIO_OUTPUT, ATTR_GPIO)
+ ATTR_OS)
from ..coresys import CoreSysAttributes
-from ..validate import ALSA_CHANNEL
_LOGGER = logging.getLogger(__name__)
@@ -18,11 +16,6 @@ SCHEMA_VERSION = vol.Schema({
vol.Optional(ATTR_VERSION): vol.Coerce(str),
})
-SCHEMA_OPTIONS = vol.Schema({
- vol.Optional(ATTR_AUDIO_OUTPUT): ALSA_CHANNEL,
- vol.Optional(ATTR_AUDIO_INPUT): ALSA_CHANNEL,
-})
-
class APIHost(CoreSysAttributes):
"""Handle rest api for host functions."""
@@ -39,19 +32,6 @@ class APIHost(CoreSysAttributes):
ATTR_OS: self._host_control.os_info,
}
- @api_process
- async def options(self, request):
- """Process host options."""
- body = await api_validate(SCHEMA_OPTIONS, request)
-
- if ATTR_AUDIO_OUTPUT in body:
- self._config.audio_output = body[ATTR_AUDIO_OUTPUT]
- if ATTR_AUDIO_INPUT in body:
- self._config.audio_input = body[ATTR_AUDIO_INPUT]
-
- self._config.save_data()
- return True
-
@api_process_hostcontrol
def reboot(self, request):
"""Reboot host."""
@@ -79,14 +59,3 @@ class APIHost(CoreSysAttributes):
return await asyncio.shield(
self._host_control.update(version=version), loop=self._loop)
-
- @api_process
- async def hardware(self, request):
- """Return local hardware infos."""
- return {
- ATTR_SERIAL: list(self._hardware.serial_devices),
- ATTR_INPUT: list(self._hardware.input_devices),
- ATTR_DISK: list(self._hardware.disk_devices),
- ATTR_GPIO: list(self._hardware.gpio_devices),
- ATTR_AUDIO: self._hardware.audio_devices,
- }
diff --git a/hassio/api/panel/hassio-app.html b/hassio/api/panel/hassio-app.html
index 98e25dc83..f1d3192ae 100644
--- a/hassio/api/panel/hassio-app.html
+++ b/hassio/api/panel/hassio-app.html
@@ -1,4 +1,4 @@
-
![]()
![]()
Add-ons
You don't have any add-ons installed yet. Head over to
the add-on store to get started!
[[_text]]
[[_charCounterStr]]Add-ons
You don't have any add-ons installed yet. Head over to
the add-on store to get started!
[[_text]]
[[_charCounterStr]]
[[errorMessage]]
[[errorMessage]]
Create snapshot
Snapshots allow you to easily backup and restore all data of your Hass.io instance.
Type:
Full snapshotPartial snapshotFolders:[[item.name]]Add-ons:[[item.name]]Security:
Password protection[[error]]
Available snapshots
You don't have any snapshots yet.
Create snapshot
Snapshots allow you to easily backup and restore all data of your Hass.io instance.
Type:
Full snapshotPartial snapshotFolders:[[item.name]]Add-ons:[[item.name]]Security:
Password protection[[error]]
Available snapshots
You don't have any snapshots yet.
[[_computeName(snapshot)]]
[[_computeType(snapshot.type)]] ([[_computeSize(snapshot.size)]])
[[_formatDatetime(snapshot.date)]]
Home Assistant:
Home Assistant [[snapshot.homeassistant]]Folders:
[[item.name]]Add-ons:
[[item.name]] ([[item.version]])Error: [[error]]
Repositories
Configure which add-on repositories to fetch data from:
Remove
Add
Host system
Version | [[data.version]] |
Latest version | [[data.last_version]] |
Type | [[data.type]] ([[data.os]]) |
Show hardwareError: [[errors]]
RebootShutdownUpdate
Hass.io supervisor
Version | [[data.version]] |
Latest version | [[data.last_version]] |
Channel | [[data.channel]] |
Error: [[errors]]
ReloadUpdateLeave beta channelJoin beta channel [[title]]
Hass.io
DashboardSnapshotsAdd-on storeSystem
[[error]]
Container | Host |
---|
[[item.container]] | |
[[_computeName(snapshot)]]
[[_computeType(snapshot.type)]] ([[_computeSize(snapshot.size)]])
[[_formatDatetime(snapshot.date)]]
Home Assistant:
Home Assistant [[snapshot.homeassistant]]Folders:
[[item.name]]Add-ons:
[[item.name]] ([[item.version]])Error: [[error]]
Repositories
Configure which add-on repositories to fetch data from:
Remove
Add
Host system
Version | [[data.version]] |
Latest version | [[data.last_version]] |
Type | [[data.type]] ([[data.os]]) |
Show hardwareError: [[errors]]
RebootShutdownUpdate
Hass.io supervisor
Version | [[data.version]] |
Latest version | [[data.last_version]] |
Channel | [[data.channel]] |
Error: [[errors]]
ReloadUpdateLeave beta channelJoin beta channel [[title]]
Hass.io
DashboardSnapshotsAdd-on storeSystem
[[error]]
[[item.name]][[item.name]][[error]]
Container | Host |
---|
[[item.container]] | |
Hass.io: add-on details
\ No newline at end of file
+ hassio-addon-audio,
+ hassio-addon-config{margin-bottom:24px;}Hass.io: add-on details