Merge pull request #118 from home-assistant/dev

Release 0.49
This commit is contained in:
Pascal Vizeli 2017-07-29 00:03:00 +02:00 committed by GitHub
commit d98b4f039f
12 changed files with 179 additions and 30 deletions

79
API.md
View File

@ -1,10 +1,11 @@
# HassIO Server
# Hass.io Server
## HassIO REST API
## Hass.io RESTful API
Interface for Home Assistant to control things from supervisor.
On error:
```json
{
"result": "error",
@ -12,7 +13,8 @@ On error:
}
```
On success
On success:
```json
{
"result": "ok",
@ -20,10 +22,9 @@ On success
}
```
### HassIO
### Hass.io
- GET `/supervisor/ping`
- GET `/supervisor/info`
The addons from `addons` are only installed one.
@ -54,7 +55,9 @@ The addons from `addons` are only installed one.
```
- POST `/supervisor/update`
Optional:
```json
{
"version": "VERSION"
@ -62,6 +65,7 @@ Optional:
```
- POST `/supervisor/options`
```json
{
"beta_channel": "true|false",
@ -78,11 +82,12 @@ Reload addons/version.
- GET `/supervisor/logs`
Output the raw docker log
Output is the raw docker log.
### Security
- GET `/security/info`
```json
{
"initialize": "bool",
@ -91,6 +96,7 @@ Output the raw docker log
```
- POST `/security/options`
```json
{
"password": "xy"
@ -98,6 +104,7 @@ Output the raw docker log
```
- POST `/security/totp`
```json
{
"password": "xy"
@ -117,6 +124,7 @@ Return QR-Code
### Backup/Snapshot
- GET `/snapshots`
```json
{
"snapshots": [
@ -132,6 +140,7 @@ Return QR-Code
- POST `/snapshots/reload`
- POST `/snapshots/new/full`
```json
{
"name": "Optional"
@ -139,6 +148,7 @@ Return QR-Code
```
- POST `/snapshots/new/partial`
```json
{
"name": "Optional",
@ -150,6 +160,7 @@ Return QR-Code
- POST `/snapshots/reload`
- GET `/snapshots/{slug}/info`
```json
{
"slug": "SNAPSHOT ID",
@ -174,10 +185,9 @@ Return QR-Code
```
- POST `/snapshots/{slug}/remove`
- POST `/snapshots/{slug}/restore/full`
- POST `/snapshots/{slug}/restore/partial`
```json
{
"homeassistant": "bool",
@ -187,14 +197,14 @@ Return QR-Code
```
### Host
- POST `/host/reload`
- POST `/host/shutdown`
- POST `/host/reboot`
- GET `/host/info`
See HostControl info command.
```json
{
"type": "",
@ -207,16 +217,37 @@ See HostControl info command.
```
- POST `/host/update`
Optional:
```json
{
"version": "VERSION"
}
```
- 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`
```json
{
"hostname": ""
@ -224,6 +255,7 @@ Optional:
```
- POST `/network/options`
```json
{
"hostname": "",
@ -250,7 +282,9 @@ Optional:
```
- POST `/homeassistant/update`
Optional:
```json
{
"version": "VERSION"
@ -259,11 +293,11 @@ Optional:
- GET `/homeassistant/logs`
Output the raw docker log
Output is the raw Docker log.
- POST `/homeassistant/restart`
- POST `/homeassistant/options`
```json
{
"devices": [],
@ -274,11 +308,11 @@ Output the raw docker log
Image with `null` and last_version with `null` reset this options.
### REST API addons
### RESTful for API addons
- GET `/addons`
Get all available addons
Get all available addons.
```json
{
@ -312,8 +346,8 @@ Get all available addons
```
- POST `/addons/reload`
- GET `/addons/{addon}/info`
```json
{
"name": "xy bla",
@ -340,6 +374,7 @@ Get all available addons
- GET `/addons/{addon}/logo`
- POST `/addons/{addon}/options`
```json
{
"boot": "auto|manual",
@ -358,7 +393,9 @@ For reset custom network settings, set it `null`.
- POST `/addons/{addon}/stop`
- POST `/addons/{addon}/install`
Optional:
```json
{
"version": "VERSION"
@ -368,7 +405,9 @@ Optional:
- POST `/addons/{addon}/uninstall`
- POST `/addons/{addon}/update`
Optional:
```json
{
"version": "VERSION"
@ -377,15 +416,16 @@ Optional:
- GET `/addons/{addon}/logs`
Output the raw docker log
Output is the raw Docker log.
- POST `/addons/{addon}/restart`
## Host Control
Communicate over unix socket with a host daemon.
Communicate over UNIX socket with a host daemon.
- commands
```
# info
-> {'type', 'version', 'last_version', 'features', 'hostname'}
@ -404,7 +444,8 @@ Communicate over unix socket with a host daemon.
# network int route xy
```
features:
Features:
- shutdown
- reboot
- update

View File

@ -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)

View File

@ -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,
}

View File

@ -1,7 +1,7 @@
"""Const file for HassIO."""
from pathlib import Path
HASSIO_VERSION = '0.48'
HASSIO_VERSION = '0.49'
URL_HASSIO_VERSION = ('https://raw.githubusercontent.com/home-assistant/'
'hassio/master/version.json')
@ -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'

View File

@ -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,

View File

@ -107,6 +107,7 @@ class DockerAddon(DockerBase):
self.dock.containers.run(
self.image,
name=self.name,
hostname=self.name,
detach=True,
network_mode=self.addon.network_mode,
ports=self.addon.ports,

View File

@ -50,6 +50,7 @@ class DockerHomeAssistant(DockerBase):
self.dock.containers.run(
self.image,
name=self.name,
hostname=self.name,
detach=True,
privileged=True,
devices=self.devices,

87
hassio/hardware.py Normal file
View 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

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -46,6 +46,7 @@ setup(
'gitpython',
'pyotp',
'pyqrcode',
'pytz'
'pytz',
'pyudev'
]
)

View File

@ -1,5 +1,5 @@
{
"hassio": "0.48",
"hassio": "0.49",
"homeassistant": "0.49.1",
"resinos": "1.0",
"resinhup": "0.3",