mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-04-19 18:57:16 +00:00
Hardware interface for UI (#116)
* Init hardware object * Update API * Update hardware list * fix api description * fix lint * add hardware to API * fix lint * fix wrong * fix view
This commit is contained in:
parent
fa687e982e
commit
1155ee07e5
18
API.md
18
API.md
@ -226,6 +226,24 @@ Optional:
|
||||
}
|
||||
```
|
||||
|
||||
- GET `/host/hardware`
|
||||
```json
|
||||
{
|
||||
"serial": ["/dev/xy"],
|
||||
"input": ["Input device name"],
|
||||
"disk": ["/dev/sdax"],
|
||||
"audio": {
|
||||
"CARD_ID": {
|
||||
"name": "xy",
|
||||
"type": "microphone",
|
||||
"devices": {
|
||||
"DEV_ID": "type of device"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Network
|
||||
|
||||
- GET `/network/info`
|
||||
|
@ -28,11 +28,12 @@ class RestAPI(object):
|
||||
self._handler = None
|
||||
self.server = None
|
||||
|
||||
def register_host(self, host_control):
|
||||
def register_host(self, host_control, hardware):
|
||||
"""Register hostcontrol function."""
|
||||
api_host = APIHost(self.config, self.loop, host_control)
|
||||
api_host = APIHost(self.config, self.loop, host_control, hardware)
|
||||
|
||||
self.webapp.router.add_get('/host/info', api_host.info)
|
||||
self.webapp.router.add_get('/host/hardware', api_host.hardware)
|
||||
self.webapp.router.add_post('/host/reboot', api_host.reboot)
|
||||
self.webapp.router.add_post('/host/shutdown', api_host.shutdown)
|
||||
self.webapp.router.add_post('/host/update', api_host.update)
|
||||
|
@ -7,7 +7,7 @@ import voluptuous as vol
|
||||
from .util 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_OS, ATTR_SERIAL, ATTR_INPUT, ATTR_DISK, ATTR_AUDIO)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -19,11 +19,12 @@ SCHEMA_VERSION = vol.Schema({
|
||||
class APIHost(object):
|
||||
"""Handle rest api for host functions."""
|
||||
|
||||
def __init__(self, config, loop, host_control):
|
||||
def __init__(self, config, loop, host_control, hardware):
|
||||
"""Initialize host rest api part."""
|
||||
self.config = config
|
||||
self.loop = loop
|
||||
self.host_control = host_control
|
||||
self.local_hw = hardware
|
||||
|
||||
@api_process
|
||||
async def info(self, request):
|
||||
@ -58,3 +59,13 @@ class APIHost(object):
|
||||
|
||||
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: self.local_hw.serial_devices,
|
||||
ATTR_INPUT: self.local_hw.input_devices,
|
||||
ATTR_DISK: self.local_hw.disk_devices,
|
||||
ATTR_AUDIO: self.local_hw.audio_devices,
|
||||
}
|
||||
|
@ -101,6 +101,10 @@ ATTR_TYPE = 'type'
|
||||
ATTR_TIMEOUT = 'timeout'
|
||||
ATTR_AUTO_UPDATE = 'auto_update'
|
||||
ATTR_CUSTOM = 'custom'
|
||||
ATTR_AUDIO = 'audio'
|
||||
ATTR_INPUT = 'input'
|
||||
ATTR_DISK = 'disk'
|
||||
ATTR_SERIAL = 'serial'
|
||||
|
||||
STARTUP_INITIALIZE = 'initialize'
|
||||
STARTUP_SYSTEM = 'system'
|
||||
|
@ -14,6 +14,7 @@ from .const import (
|
||||
RUN_CLEANUP_API_SESSIONS, STARTUP_SYSTEM, STARTUP_SERVICES,
|
||||
STARTUP_APPLICATION, STARTUP_INITIALIZE, RUN_RELOAD_SNAPSHOTS_TASKS,
|
||||
RUN_UPDATE_ADDONS_TASKS)
|
||||
from .hardware import Hardware
|
||||
from .homeassistant import HomeAssistant
|
||||
from .scheduler import Scheduler
|
||||
from .dock.supervisor import DockerSupervisor
|
||||
@ -36,6 +37,7 @@ class HassIO(object):
|
||||
self.websession = aiohttp.ClientSession(loop=loop)
|
||||
self.scheduler = Scheduler(loop)
|
||||
self.api = RestAPI(config, loop)
|
||||
self.hardware = Hardware()
|
||||
self.dock = docker.DockerClient(
|
||||
base_url="unix:/{}".format(str(SOCKET_DOCKER)), version='auto')
|
||||
|
||||
@ -81,7 +83,7 @@ class HassIO(object):
|
||||
self.host_control.load, RUN_UPDATE_INFO_TASKS)
|
||||
|
||||
# rest api views
|
||||
self.api.register_host(self.host_control)
|
||||
self.api.register_host(self.host_control, self.hardware)
|
||||
self.api.register_network(self.host_control)
|
||||
self.api.register_supervisor(
|
||||
self.supervisor, self.snapshots, self.addons, self.host_control,
|
||||
|
87
hassio/hardware.py
Normal file
87
hassio/hardware.py
Normal file
@ -0,0 +1,87 @@
|
||||
"""Read hardware info from system."""
|
||||
import logging
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
import pyudev
|
||||
|
||||
from .const import ATTR_NAME, ATTR_TYPE, ATTR_DEVICES
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ASOUND_CARDS = Path("/proc/asound/cards")
|
||||
RE_CARDS = re.compile(r"(\d+) \[(\w*) *\]: (.*\w)")
|
||||
|
||||
ASOUND_DEVICES = Path("/proc/asound/devices")
|
||||
RE_DEVICES = re.compile(r"\[.*(\d+)- (\d+).*\]: ([\w ]*)")
|
||||
|
||||
|
||||
class Hardware(object):
|
||||
"""Represent a interface to procfs, sysfs and udev."""
|
||||
|
||||
def __init__(self):
|
||||
"""Init hardware object."""
|
||||
self.context = pyudev.Context()
|
||||
|
||||
@property
|
||||
def serial_devices(self):
|
||||
"""Return all serial and connected devices."""
|
||||
dev_list = set()
|
||||
for device in self.context.list_devices(subsystem='tty'):
|
||||
if 'ID_VENDOR' in device:
|
||||
dev_list.add(device.device_node)
|
||||
|
||||
return list(dev_list)
|
||||
|
||||
@property
|
||||
def input_devices(self):
|
||||
"""Return all input devices."""
|
||||
dev_list = set()
|
||||
for device in self.context.list_devices(subsystem='input'):
|
||||
if 'NAME' in device:
|
||||
dev_list.add(device['NAME'].replace('"', ''))
|
||||
|
||||
return list(dev_list)
|
||||
|
||||
@property
|
||||
def disk_devices(self):
|
||||
"""Return all disk devices."""
|
||||
dev_list = set()
|
||||
for device in self.context.list_devices(subsystem='block'):
|
||||
if 'ID_VENDOR' in device:
|
||||
dev_list.add(device.device_node)
|
||||
|
||||
return list(dev_list)
|
||||
|
||||
@property
|
||||
def audio_devices(self):
|
||||
"""Return all available audio interfaces."""
|
||||
try:
|
||||
with ASOUND_CARDS.open('r') as cards_file:
|
||||
cards = cards_file.read()
|
||||
with ASOUND_DEVICES.open('r') as devices_file:
|
||||
devices = devices_file.read()
|
||||
except OSError as err:
|
||||
_LOGGER.error("Can't read asound data -> %s", err)
|
||||
return
|
||||
|
||||
audio_list = {}
|
||||
|
||||
# parse cards
|
||||
for match in RE_CARDS.finditer(cards):
|
||||
audio_list[match.group(1)] = {
|
||||
ATTR_NAME: match.group(3),
|
||||
ATTR_TYPE: match.group(2),
|
||||
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)
|
||||
except KeyError:
|
||||
_LOGGER.warning("Wrong audio device found %s", match.group(0))
|
||||
continue
|
||||
|
||||
return audio_list
|
@ -1 +1 @@
|
||||
Subproject commit 1aa387a72f2a8b0c26a005afbba9a8a9fc095e06
|
||||
Subproject commit 0c428134dfb6374b4a120cb729396242b4c2f2d7
|
Loading…
x
Reference in New Issue
Block a user