mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-15 05:06:30 +00:00
HassOS support (#522)
* Add support for hassos * Name command * Update host.py * Create hassos.py * Update const.py * Update host.py * Update API.md * Update const.py * Update __init__.py * Update hassos.py * Update hassos.py * Update hassos.py * Update hassos.py * Update const.py * Update API.md * Update hassos.py * Update hassos.py * Update API.md * Update const.py * Update hassos.py * Update __init__.py * fix lint * Fix lint v2 * remove old function * fix attribute error * inittialize hassos * Fix link * fix error handling * Fix handling
This commit is contained in:
parent
408d6eafcc
commit
a0c9e5ad26
41
API.md
41
API.md
@ -227,14 +227,12 @@ return:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"hostname": "hostname|null",
|
"hostname": "hostname|null",
|
||||||
"features": ["shutdown", "reboot", "update", "hostname", "services"],
|
"features": ["shutdown", "reboot", "hostname", "services", "hassos"],
|
||||||
"operating_system": "Hass.io-OS XY|Ubuntu 16.4|null",
|
"operating_system": "HassOS XY|Ubuntu 16.4|null",
|
||||||
"kernel": "4.15.7|null",
|
"kernel": "4.15.7|null",
|
||||||
"chassis": "specific|null",
|
"chassis": "specific|null",
|
||||||
"type": "Hass.io-OS Type|null",
|
|
||||||
"deployment": "stable|beta|dev|null",
|
"deployment": "stable|beta|dev|null",
|
||||||
"version": "xy|null",
|
"cpe": "xy|null",
|
||||||
"last_version": "xy|null",
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -246,17 +244,6 @@ return:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
- POST `/host/update`
|
|
||||||
|
|
||||||
Optional:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"version": "VERSION"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- POST `/host/reload`
|
- POST `/host/reload`
|
||||||
|
|
||||||
#### Services
|
#### Services
|
||||||
@ -280,6 +267,28 @@ Optional:
|
|||||||
|
|
||||||
- POST `/host/service/{unit}/reload`
|
- POST `/host/service/{unit}/reload`
|
||||||
|
|
||||||
|
### HassOS
|
||||||
|
|
||||||
|
- GET `/hassos/info`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "2.3",
|
||||||
|
"version_latest": "2.4",
|
||||||
|
"board": "ova|rpi"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- POST `/hassos/update`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "optional"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- POST `/hassos/config/sync`
|
||||||
|
|
||||||
|
Load host configs from a USB stick.
|
||||||
|
|
||||||
### Hardware
|
### Hardware
|
||||||
|
|
||||||
- GET `/hardware/info`
|
- GET `/hardware/info`
|
||||||
|
@ -9,6 +9,7 @@ from .discovery import APIDiscovery
|
|||||||
from .homeassistant import APIHomeAssistant
|
from .homeassistant import APIHomeAssistant
|
||||||
from .hardware import APIHardware
|
from .hardware import APIHardware
|
||||||
from .host import APIHost
|
from .host import APIHost
|
||||||
|
from .hassos import APIHassOS
|
||||||
from .proxy import APIProxy
|
from .proxy import APIProxy
|
||||||
from .supervisor import APISupervisor
|
from .supervisor import APISupervisor
|
||||||
from .snapshots import APISnapshots
|
from .snapshots import APISnapshots
|
||||||
@ -37,6 +38,7 @@ class RestAPI(CoreSysAttributes):
|
|||||||
"""Register REST API Calls."""
|
"""Register REST API Calls."""
|
||||||
self._register_supervisor()
|
self._register_supervisor()
|
||||||
self._register_host()
|
self._register_host()
|
||||||
|
self._register_hassos()
|
||||||
self._register_hardware()
|
self._register_hardware()
|
||||||
self._register_homeassistant()
|
self._register_homeassistant()
|
||||||
self._register_proxy()
|
self._register_proxy()
|
||||||
@ -55,7 +57,6 @@ class RestAPI(CoreSysAttributes):
|
|||||||
web.get('/host/info', api_host.info),
|
web.get('/host/info', api_host.info),
|
||||||
web.post('/host/reboot', api_host.reboot),
|
web.post('/host/reboot', api_host.reboot),
|
||||||
web.post('/host/shutdown', api_host.shutdown),
|
web.post('/host/shutdown', api_host.shutdown),
|
||||||
web.post('/host/update', api_host.update),
|
|
||||||
web.post('/host/reload', api_host.reload),
|
web.post('/host/reload', api_host.reload),
|
||||||
web.get('/host/services', api_host.services),
|
web.get('/host/services', api_host.services),
|
||||||
web.post('/host/services/{service}/stop', api_host.service_stop),
|
web.post('/host/services/{service}/stop', api_host.service_stop),
|
||||||
@ -66,6 +67,16 @@ class RestAPI(CoreSysAttributes):
|
|||||||
'/host/services/{service}/reload', api_host.service_reload),
|
'/host/services/{service}/reload', api_host.service_reload),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def _register_hassos(self):
|
||||||
|
"""Register hassos function."""
|
||||||
|
api_hassos = APIHassOS()
|
||||||
|
api_hassos.coresys = self.coresys
|
||||||
|
|
||||||
|
self.webapp.add_routes([
|
||||||
|
web.get('/hassos/info', api_hassos.info),
|
||||||
|
web.post('/hassos/config/sync', api_hassos.config_sync),
|
||||||
|
])
|
||||||
|
|
||||||
def _register_hardware(self):
|
def _register_hardware(self):
|
||||||
"""Register hardware function."""
|
"""Register hardware function."""
|
||||||
api_hardware = APIHardware()
|
api_hardware = APIHardware()
|
||||||
|
33
hassio/api/hassos.py
Normal file
33
hassio/api/hassos.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
"""Init file for Hass.io hassos rest api."""
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from .utils import api_process
|
||||||
|
from ..const import ATTR_VERSION, ATTR_BOARD, ATTR_VERSION_LATEST
|
||||||
|
from ..coresys import CoreSysAttributes
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
SCHEMA_VERSION = vol.Schema({
|
||||||
|
vol.Optional(ATTR_VERSION): vol.Coerce(str),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class APIHassOS(CoreSysAttributes):
|
||||||
|
"""Handle rest api for hassos functions."""
|
||||||
|
|
||||||
|
@api_process
|
||||||
|
async def info(self, request):
|
||||||
|
"""Return hassos information."""
|
||||||
|
return {
|
||||||
|
ATTR_VERSION: self.sys_hassos.version,
|
||||||
|
ATTR_VERSION_LATEST: self.sys_hassos.version,
|
||||||
|
ATTR_BOARD: self.sys_hassos.board,
|
||||||
|
}
|
||||||
|
|
||||||
|
@api_process
|
||||||
|
def config_sync(self, request):
|
||||||
|
"""Trigger config reload on HassOS."""
|
||||||
|
return asyncio.shield(self.sys_hassos.config_sync())
|
@ -6,19 +6,15 @@ import voluptuous as vol
|
|||||||
|
|
||||||
from .utils import api_process, api_validate
|
from .utils import api_process, api_validate
|
||||||
from ..const import (
|
from ..const import (
|
||||||
ATTR_VERSION, ATTR_LAST_VERSION, ATTR_HOSTNAME, ATTR_FEATURES, ATTR_KERNEL,
|
ATTR_HOSTNAME, ATTR_FEATURES, ATTR_KERNEL, ATTR_OPERATING_SYSTEM,
|
||||||
ATTR_TYPE, ATTR_OPERATING_SYSTEM, ATTR_CHASSIS, ATTR_DEPLOYMENT,
|
ATTR_CHASSIS, ATTR_DEPLOYMENT, ATTR_STATE, ATTR_NAME, ATTR_DESCRIPTON,
|
||||||
ATTR_STATE, ATTR_NAME, ATTR_DESCRIPTON, ATTR_SERVICES)
|
ATTR_SERVICES, ATTR_CPE)
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
SERVICE = 'service'
|
SERVICE = 'service'
|
||||||
|
|
||||||
SCHEMA_VERSION = vol.Schema({
|
|
||||||
vol.Optional(ATTR_VERSION): vol.Coerce(str),
|
|
||||||
})
|
|
||||||
|
|
||||||
SCHEMA_OPTIONS = vol.Schema({
|
SCHEMA_OPTIONS = vol.Schema({
|
||||||
vol.Optional(ATTR_HOSTNAME): vol.Coerce(str),
|
vol.Optional(ATTR_HOSTNAME): vol.Coerce(str),
|
||||||
})
|
})
|
||||||
@ -32,9 +28,7 @@ class APIHost(CoreSysAttributes):
|
|||||||
"""Return host information."""
|
"""Return host information."""
|
||||||
return {
|
return {
|
||||||
ATTR_CHASSIS: self.sys_host.info.chassis,
|
ATTR_CHASSIS: self.sys_host.info.chassis,
|
||||||
ATTR_VERSION: None,
|
ATTR_CPE: self.sys_host.info.cpe,
|
||||||
ATTR_LAST_VERSION: None,
|
|
||||||
ATTR_TYPE: None,
|
|
||||||
ATTR_FEATURES: self.sys_host.supperted_features,
|
ATTR_FEATURES: self.sys_host.supperted_features,
|
||||||
ATTR_HOSTNAME: self.sys_host.info.hostname,
|
ATTR_HOSTNAME: self.sys_host.info.hostname,
|
||||||
ATTR_OPERATING_SYSTEM: self.sys_host.info.operating_system,
|
ATTR_OPERATING_SYSTEM: self.sys_host.info.operating_system,
|
||||||
@ -67,13 +61,6 @@ class APIHost(CoreSysAttributes):
|
|||||||
"""Reload host data."""
|
"""Reload host data."""
|
||||||
return asyncio.shield(self.sys_host.reload())
|
return asyncio.shield(self.sys_host.reload())
|
||||||
|
|
||||||
@api_process
|
|
||||||
async def update(self, request):
|
|
||||||
"""Update host OS."""
|
|
||||||
pass
|
|
||||||
# body = await api_validate(SCHEMA_VERSION, request)
|
|
||||||
# version = body.get(ATTR_VERSION, self.sys_host.last_version)
|
|
||||||
|
|
||||||
@api_process
|
@api_process
|
||||||
async def services(self, request):
|
async def services(self, request):
|
||||||
"""Return list of available services."""
|
"""Return list of available services."""
|
||||||
|
@ -21,6 +21,7 @@ from .services import ServiceManager
|
|||||||
from .services import Discovery
|
from .services import Discovery
|
||||||
from .host import HostManager
|
from .host import HostManager
|
||||||
from .dbus import DBusManager
|
from .dbus import DBusManager
|
||||||
|
from .hassos import HassOS
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ def initialize_coresys(loop):
|
|||||||
coresys.services = ServiceManager(coresys)
|
coresys.services = ServiceManager(coresys)
|
||||||
coresys.discovery = Discovery(coresys)
|
coresys.discovery = Discovery(coresys)
|
||||||
coresys.dbus = DBusManager(coresys)
|
coresys.dbus = DBusManager(coresys)
|
||||||
|
coresys.hassos = HassOS(coresys)
|
||||||
|
|
||||||
# bootstrap config
|
# bootstrap config
|
||||||
initialize_system_data(coresys)
|
initialize_system_data(coresys)
|
||||||
|
@ -71,6 +71,7 @@ ATTR_SOURCE = 'source'
|
|||||||
ATTR_FEATURES = 'features'
|
ATTR_FEATURES = 'features'
|
||||||
ATTR_ADDONS = 'addons'
|
ATTR_ADDONS = 'addons'
|
||||||
ATTR_VERSION = 'version'
|
ATTR_VERSION = 'version'
|
||||||
|
ATTR_VERSION_LATEST = 'version_latest'
|
||||||
ATTR_AUTO_UART = 'auto_uart'
|
ATTR_AUTO_UART = 'auto_uart'
|
||||||
ATTR_LAST_BOOT = 'last_boot'
|
ATTR_LAST_BOOT = 'last_boot'
|
||||||
ATTR_LAST_VERSION = 'last_version'
|
ATTR_LAST_VERSION = 'last_version'
|
||||||
@ -166,6 +167,8 @@ ATTR_BRANCH = 'branch'
|
|||||||
ATTR_KERNEL = 'kernel'
|
ATTR_KERNEL = 'kernel'
|
||||||
ATTR_APPARMOR = 'apparmor'
|
ATTR_APPARMOR = 'apparmor'
|
||||||
ATTR_DEVICETREE = 'devicetree'
|
ATTR_DEVICETREE = 'devicetree'
|
||||||
|
ATTR_CPE = 'cpe'
|
||||||
|
ATTR_BOARD = 'board'
|
||||||
|
|
||||||
SERVICE_MQTT = 'mqtt'
|
SERVICE_MQTT = 'mqtt'
|
||||||
|
|
||||||
@ -216,6 +219,6 @@ SECURITY_DISABLE = 'disable'
|
|||||||
|
|
||||||
FEATURES_SHUTDOWN = 'shutdown'
|
FEATURES_SHUTDOWN = 'shutdown'
|
||||||
FEATURES_REBOOT = 'reboot'
|
FEATURES_REBOOT = 'reboot'
|
||||||
FEATURES_UPDATE = 'update'
|
FEATURES_HASSOS = 'hassos'
|
||||||
FEATURES_HOSTNAME = 'hostname'
|
FEATURES_HOSTNAME = 'hostname'
|
||||||
FEATURES_SERVICES = 'services'
|
FEATURES_SERVICES = 'services'
|
||||||
|
@ -32,6 +32,9 @@ class HassIO(CoreSysAttributes):
|
|||||||
# Load Host
|
# Load Host
|
||||||
await self.sys_host.load()
|
await self.sys_host.load()
|
||||||
|
|
||||||
|
# Load HassOS
|
||||||
|
await self.sys_hassos.load()
|
||||||
|
|
||||||
# Load Supervisor
|
# Load Supervisor
|
||||||
await self.sys_supervisor.load()
|
await self.sys_supervisor.load()
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ class CoreSys:
|
|||||||
self._tasks = None
|
self._tasks = None
|
||||||
self._host = None
|
self._host = None
|
||||||
self._dbus = None
|
self._dbus = None
|
||||||
|
self._hassos = None
|
||||||
self._services = None
|
self._services = None
|
||||||
self._discovery = None
|
self._discovery = None
|
||||||
|
|
||||||
@ -249,6 +250,18 @@ class CoreSys:
|
|||||||
raise RuntimeError("HostManager already set!")
|
raise RuntimeError("HostManager already set!")
|
||||||
self._host = value
|
self._host = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hassos(self):
|
||||||
|
"""Return HassOS object."""
|
||||||
|
return self._hassos
|
||||||
|
|
||||||
|
@hassos.setter
|
||||||
|
def hassos(self, value):
|
||||||
|
"""Set a HassOS object."""
|
||||||
|
if self._hassos:
|
||||||
|
raise RuntimeError("HassOS already set!")
|
||||||
|
self._hassos = value
|
||||||
|
|
||||||
def run_in_executor(self, funct, *args):
|
def run_in_executor(self, funct, *args):
|
||||||
"""Wrapper for executor pool."""
|
"""Wrapper for executor pool."""
|
||||||
return self._loop.run_in_executor(None, funct, *args)
|
return self._loop.run_in_executor(None, funct, *args)
|
||||||
|
65
hassio/hassos.py
Normal file
65
hassio/hassos.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
"""HassOS support on supervisor."""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from cpe import CPE
|
||||||
|
|
||||||
|
from .coresys import CoreSysAttributes
|
||||||
|
from .exceptions import HassioNotSupportedError
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class HassOS(CoreSysAttributes):
|
||||||
|
"""HassOS interface inside HassIO."""
|
||||||
|
|
||||||
|
def __init__(self, coresys):
|
||||||
|
"""Initialize HassOS handler."""
|
||||||
|
self.coresys = coresys
|
||||||
|
self._available = False
|
||||||
|
self._version = None
|
||||||
|
self._board = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self):
|
||||||
|
"""Return True, if HassOS on host."""
|
||||||
|
return self._available
|
||||||
|
|
||||||
|
@property
|
||||||
|
def version(self):
|
||||||
|
"""Return version of HassOS."""
|
||||||
|
return self._version
|
||||||
|
|
||||||
|
@property
|
||||||
|
def board(self):
|
||||||
|
"""Return board name."""
|
||||||
|
return self._board
|
||||||
|
|
||||||
|
def _check_host(self):
|
||||||
|
"""Check if HassOS is availabe."""
|
||||||
|
if not self.available:
|
||||||
|
_LOGGER.error("No HassOS availabe")
|
||||||
|
raise HassioNotSupportedError()
|
||||||
|
|
||||||
|
async def load(self):
|
||||||
|
"""Load HassOS data."""
|
||||||
|
try:
|
||||||
|
assert self.sys_host.info.cpe is not None
|
||||||
|
cpe = CPE(self.sys_host.info.cpe)
|
||||||
|
assert cpe.get_product()[0] == 'hassos'
|
||||||
|
except (NotImplementedError, IndexError, AssertionError):
|
||||||
|
_LOGGER.info("Can't detect HassOS")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Store meta data
|
||||||
|
self._available = True
|
||||||
|
self._version = cpe.get_version()[0]
|
||||||
|
self._board = cpe.get_target_hardware()[0]
|
||||||
|
|
||||||
|
_LOGGER.info("Detect HassOS %s on host system", self.version)
|
||||||
|
|
||||||
|
def config_sync(self):
|
||||||
|
"""Trigger a host config reload from usb."""
|
||||||
|
self._check_host()
|
||||||
|
|
||||||
|
_LOGGER.info("Sync config from USB on HassOS.")
|
||||||
|
return self.sys_host.services.restart('hassos-config.service')
|
@ -8,7 +8,8 @@ from .control import SystemControl
|
|||||||
from .info import InfoCenter
|
from .info import InfoCenter
|
||||||
from .services import ServiceManager
|
from .services import ServiceManager
|
||||||
from ..const import (
|
from ..const import (
|
||||||
FEATURES_REBOOT, FEATURES_SHUTDOWN, FEATURES_HOSTNAME, FEATURES_SERVICES)
|
FEATURES_REBOOT, FEATURES_SHUTDOWN, FEATURES_HOSTNAME, FEATURES_SERVICES,
|
||||||
|
FEATURES_HASSOS)
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
from ..exceptions import HassioError
|
from ..exceptions import HassioError
|
||||||
|
|
||||||
@ -67,6 +68,9 @@ class HostManager(CoreSysAttributes):
|
|||||||
if self.sys_dbus.hostname.is_connected:
|
if self.sys_dbus.hostname.is_connected:
|
||||||
features.append(FEATURES_HOSTNAME)
|
features.append(FEATURES_HOSTNAME)
|
||||||
|
|
||||||
|
if self.sys_hassos.available:
|
||||||
|
features.append(FEATURES_HASSOS)
|
||||||
|
|
||||||
return features
|
return features
|
||||||
|
|
||||||
async def reload(self):
|
async def reload(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user