This commit is contained in:
Pascal Vizeli 2018-04-23 15:32:23 +02:00
parent 42dd4d9557
commit b486883ff6
13 changed files with 132 additions and 56 deletions

View File

@ -5,7 +5,6 @@ import logging
import sys import sys
import hassio.bootstrap as bootstrap import hassio.bootstrap as bootstrap
import hassio.core as core
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -34,14 +33,13 @@ if __name__ == "__main__":
_LOGGER.info("Initialize Hassio setup") _LOGGER.info("Initialize Hassio setup")
coresys = bootstrap.initialize_coresys(loop) coresys = bootstrap.initialize_coresys(loop)
hassio = core.HassIO(coresys)
bootstrap.migrate_system_env(coresys) bootstrap.migrate_system_env(coresys)
_LOGGER.info("Setup HassIO") _LOGGER.info("Setup HassIO")
loop.run_until_complete(hassio.setup()) loop.run_until_complete(coresys.core.setup())
loop.call_soon_threadsafe(loop.create_task, hassio.start()) loop.call_soon_threadsafe(loop.create_task, coresys.core.start())
loop.call_soon_threadsafe(bootstrap.reg_signal, loop) loop.call_soon_threadsafe(bootstrap.reg_signal, loop)
try: try:
@ -49,7 +47,7 @@ if __name__ == "__main__":
loop.run_forever() loop.run_forever()
finally: finally:
_LOGGER.info("Stopping HassIO") _LOGGER.info("Stopping HassIO")
loop.run_until_complete(hassio.stop()) loop.run_until_complete(coresys.core.stop())
executor.shutdown(wait=False) executor.shutdown(wait=False)
loop.close() loop.close()

View File

@ -376,7 +376,7 @@ class Addon(CoreSysAttributes):
if self.is_installed and \ if self.is_installed and \
ATTR_AUDIO_OUTPUT in self._data.user[self._id]: ATTR_AUDIO_OUTPUT in self._data.user[self._id]:
return self._data.user[self._id][ATTR_AUDIO_OUTPUT] return self._data.user[self._id][ATTR_AUDIO_OUTPUT]
return self.sys_alsa.default.output return self.sys_host.alsa.default.output
@audio_output.setter @audio_output.setter
def audio_output(self, value): def audio_output(self, value):
@ -394,7 +394,7 @@ class Addon(CoreSysAttributes):
if self.is_installed and ATTR_AUDIO_INPUT in self._data.user[self._id]: if self.is_installed and ATTR_AUDIO_INPUT in self._data.user[self._id]:
return self._data.user[self._id][ATTR_AUDIO_INPUT] return self._data.user[self._id][ATTR_AUDIO_INPUT]
return self.sys_alsa.default.input return self.sys_host.alsa.default.input
@audio_input.setter @audio_input.setter
def audio_input(self, value): def audio_input(self, value):
@ -537,7 +537,7 @@ class Addon(CoreSysAttributes):
def write_asound(self): def write_asound(self):
"""Write asound config to file and return True on success.""" """Write asound config to file and return True on success."""
asound_config = self.sys_alsa.asound( asound_config = self.sys_host.alsa.asound(
alsa_input=self.audio_input, alsa_output=self.audio_output) alsa_input=self.audio_input, alsa_output=self.audio_output)
try: try:

View File

@ -28,7 +28,7 @@ class APIHardware(CoreSysAttributes):
"""Show ALSA audio devices.""" """Show ALSA audio devices."""
return { return {
ATTR_AUDIO: { ATTR_AUDIO: {
ATTR_INPUT: self.sys_alsa.input_devices, ATTR_INPUT: self.sys_host.alsa.input_devices,
ATTR_OUTPUT: self.sys_alsa.output_devices, ATTR_OUTPUT: self.sys_host.alsa.output_devices,
} }
} }

View File

@ -7,6 +7,7 @@ from pathlib import Path
from colorlog import ColoredFormatter from colorlog import ColoredFormatter
from .core import HassIO
from .addons import AddonManager from .addons import AddonManager
from .api import RestAPI from .api import RestAPI
from .const import SOCKET_DOCKER from .const import SOCKET_DOCKER
@ -18,7 +19,6 @@ from .tasks import Tasks
from .updater import Updater from .updater import Updater
from .services import ServiceManager from .services import ServiceManager
from .services import Discovery from .services import Discovery
from .host import AlsaAudio
from .host import HostManager from .host import HostManager
from .dbus import DBusManager from .dbus import DBusManager
@ -30,9 +30,9 @@ def initialize_coresys(loop):
coresys = CoreSys(loop) coresys = CoreSys(loop)
# Initialize core objects # Initialize core objects
coresys.core = HassIO(coresys)
coresys.updater = Updater(coresys) coresys.updater = Updater(coresys)
coresys.api = RestAPI(coresys) coresys.api = RestAPI(coresys)
coresys.alsa = AlsaAudio(coresys)
coresys.supervisor = Supervisor(coresys) coresys.supervisor = Supervisor(coresys)
coresys.homeassistant = HomeAssistant(coresys) coresys.homeassistant = HomeAssistant(coresys)
coresys.addons = AddonManager(coresys) coresys.addons = AddonManager(coresys)
@ -154,7 +154,12 @@ def check_environment():
# check socat exec # check socat exec
if not shutil.which('socat'): if not shutil.which('socat'):
_LOGGER.fatal("Can0t find socat program!") _LOGGER.fatal("Can't find socat program!")
return False
# check socat exec
if not shutil.which('gdbus'):
_LOGGER.fatal("Can't find gdbus program!")
return False return False
return True return True

View File

@ -18,7 +18,6 @@ FILE_HASSIO_UPDATER = Path(HASSIO_DATA, "updater.json")
FILE_HASSIO_SERVICES = Path(HASSIO_DATA, "services.json") FILE_HASSIO_SERVICES = Path(HASSIO_DATA, "services.json")
SOCKET_DOCKER = Path("/var/run/docker.sock") SOCKET_DOCKER = Path("/var/run/docker.sock")
SOCKET_HC = Path("/var/run/hassio-hc.sock")
DOCKER_NETWORK = 'hassio' DOCKER_NETWORK = 'hassio'
DOCKER_NETWORK_MASK = ip_network('172.30.32.0/23') DOCKER_NETWORK_MASK = ip_network('172.30.32.0/23')

View File

@ -23,16 +23,19 @@ class HassIO(CoreSysAttributes):
if self.sys_config.timezone == 'UTC': if self.sys_config.timezone == 'UTC':
self.sys_config.timezone = await fetch_timezone(self._websession) self.sys_config.timezone = await fetch_timezone(self._websession)
# supervisor # Load DBus
await self.sys_dbus.load()
# Load Host
await self.sys_host.load()
# Load Supervisor
await self.sys_supervisor.load() await self.sys_supervisor.load()
# hostcontrol # Load Home Assistant
await self._host_control.load()
# Load homeassistant
await self.sys_homeassistant.load() await self.sys_homeassistant.load()
# Load addons # Load Add-ons
await self.sys_addons.load() await self.sys_addons.load()
# rest api views # rest api views
@ -50,9 +53,6 @@ class HassIO(CoreSysAttributes):
# start dns forwarding # start dns forwarding
self.sys_create_task(self.sys_dns.start()) self.sys_create_task(self.sys_dns.start())
# start addon mark as initialize
await self.sys_addons.auto_boot(STARTUP_INITIALIZE)
async def start(self): async def start(self):
"""Start HassIO orchestration.""" """Start HassIO orchestration."""
# on release channel, try update itself # on release channel, try update itself
@ -67,6 +67,9 @@ class HassIO(CoreSysAttributes):
await self.sys_api.start() await self.sys_api.start()
_LOGGER.info("Start API on %s", self.sys_docker.network.supervisor) _LOGGER.info("Start API on %s", self.sys_docker.network.supervisor)
# start addon mark as initialize
await self.sys_addons.auto_boot(STARTUP_INITIALIZE)
try: try:
# HomeAssistant is already running / supervisor have only reboot # HomeAssistant is already running / supervisor have only reboot
if self.sys_hardware.last_boot == self.sys_config.last_boot: if self.sys_hardware.last_boot == self.sys_config.last_boot:

View File

@ -32,6 +32,7 @@ class CoreSys:
self._dns = DNSForward(loop=loop) self._dns = DNSForward(loop=loop)
# Internal objects pointers # Internal objects pointers
self._core = None
self._homeassistant = None self._homeassistant = None
self._supervisor = None self._supervisor = None
self._addons = None self._addons = None
@ -40,9 +41,9 @@ class CoreSys:
self._snapshots = None self._snapshots = None
self._tasks = None self._tasks = None
self._host = None self._host = None
self._dbus = None
self._services = None self._services = None
self._discovery = None self._discovery = None
self._alsa = None
@property @property
def arch(self): def arch(self):
@ -104,9 +105,16 @@ class CoreSys:
return self._dns return self._dns
@property @property
def systemd(self): def core(self):
"""Return systemd object.""" """Return HassIO object."""
return self._systemd return self._core
@core.setter
def core(self, value):
"""Set a HassIO object."""
if self._core:
raise RuntimeError("HassIO already set!")
self._core = value
@property @property
def homeassistant(self): def homeassistant(self):
@ -217,16 +225,16 @@ class CoreSys:
self._discovery = value self._discovery = value
@property @property
def alsa(self): def dbus(self):
"""Return ALSA Audio object.""" """Return DBusManager object."""
return self._alsa return self._dbus
@alsa.setter @dbus.setter
def alsa(self, value): def dbus(self, value):
"""Set a ALSA Audio object.""" """Set a DBusManager object."""
if self._alsa: if self._dbus:
raise RuntimeError("ALSA already set!") raise RuntimeError("DBusManager already set!")
self._alsa = value self._dbus = value
@property @property
def host(self): def host(self):

View File

@ -7,8 +7,9 @@ from ..coresys import CoreSysAttributes
class DBusManager(CoreSysAttributes): class DBusManager(CoreSysAttributes):
"""DBus Interface handler.""" """DBus Interface handler."""
def __init__(self): def __init__(self, coresys):
"""Initialize DBus Interface.""" """Initialize DBus Interface."""
self.coresys = coresys
self._systemd = Systemd() self._systemd = Systemd()
@property @property

1
hassio/dbus/hostname.py Normal file
View File

@ -0,0 +1 @@
"""DBus interface for hostname."""

View File

@ -1,8 +1,9 @@
"""Interface to Systemd over dbus.""" """Interface to Systemd over dbus."""
import logging import logging
from ..exceptions import HassioInternalError from .utils import dbus_connected
from ..utils.gdbus import DBus, DBusError from ..exceptions import DBusError
from ..utils.gdbus import DBus
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -29,18 +30,18 @@ class Systemd:
except DBusError: except DBusError:
_LOGGER.warning("Can't connect to systemd") _LOGGER.warning("Can't connect to systemd")
async def reboot(self): @dbus_connected
"""Reboot host computer.""" def reboot(self):
try: """Reboot host computer.
await self.dbus.Manager.Reboot()
except DBusError:
_LOGGER.error("Can't reboot host")
raise HassioInternalError() from None
async def shutdown(self): Return a coroutine.
"""Shutdown host computer.""" """
try: return self.dbus.Manager.Reboot()
await self.dbus.Manager.PowerOff()
except DBusError: @dbus_connected
_LOGGER.error("Can't PowerOff host") def shutdown(self):
raise HassioInternalError() from None """Shutdown host computer.
Return a coroutine.
"""
return self.dbus.Manager.PowerOff()

14
hassio/dbus/utils.py Normal file
View File

@ -0,0 +1,14 @@
"""Utils for dbus."""
from ..exceptions import HassioNotSupportedError
def dbus_connected(method):
"""Wrapper for check if dbus is connected."""
def wrap_dbus(self, *args, **kwargs):
"""Check if dbus is connected before call a method."""
if self.dbus is None:
raise HassioNotSupportedError(f"{self!s} not connected to dbus!")
return self.method(*args, **kwargs)
return wrap_dbus

View File

@ -1,6 +1,7 @@
"""Host function like audio/dbus/systemd.""" """Host function like audio/dbus/systemd."""
from .alsa import AlsaAudio # noqa from .alsa import AlsaAudio
from .power import PowerControl
from ..const import FEATURES_REBOOT, FEATURES_SHUTDOWN from ..const import FEATURES_REBOOT, FEATURES_SHUTDOWN
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
@ -11,13 +12,25 @@ class HostManager(CoreSysAttributes):
def __init__(self, coresys): def __init__(self, coresys):
"""Initialize Host manager.""" """Initialize Host manager."""
self.coresys = coresys self.coresys = coresys
self._alsa = AlsaAudio(coresys)
self._power = PowerControl(coresys)
@property
def alsa(self):
"""Return host ALSA handler."""
return self._alsa
@property
def power(self):
"""Return host power handler."""
return self._power
@property @property
def supperted_features(self): def supperted_features(self):
"""Return a list of supported host features.""" """Return a list of supported host features."""
features = [] features = []
if self.sys_systemd.is_connected: if self.sys_dbus.systemd.is_connected:
features.extend([ features.extend([
FEATURES_REBOOT, FEATURES_REBOOT,
FEATURES_SHUTDOWN, FEATURES_SHUTDOWN,
@ -27,4 +40,4 @@ class HostManager(CoreSysAttributes):
async def load(self): async def load(self):
"""Load host functions.""" """Load host functions."""
await self.sys_systemd.connect() pass

33
hassio/host/power.py Normal file
View File

@ -0,0 +1,33 @@
"""Power control for host."""
from ..coresys import CoreSysAttributes
from ..exceptions import HassioNotSupportedError
class PowerControl(CoreSysAttributes):
"""Handle host power controls."""
def __init__(self, coresys):
"""Initialize host power handling."""
self.coresys = coresys
def _check_systemd(self):
"""Check if systemd is connect or raise error."""
if not self.sys_dbus.systemd.is_connected:
raise HassioNotSupportedError("No systemd connections")
async def reboot(self):
"""Reboot host system."""
self._check_systemd()
try:
await self.sys_core.shutdown()
finally:
await self.sys_dbus.systemd.reboot()
async def shutdown(self):
"""Shutdown host system."""
self._check_systemd()
try:
await self.sys_core.shutdown()
finally:
await self.sys_dbus.systemd.shutdown()