mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-27 19:16:29 +00:00
Add hostname function
This commit is contained in:
parent
2a81ced817
commit
0bb81136bb
38
API.md
38
API.md
@ -217,8 +217,11 @@ return:
|
|||||||
### Host
|
### Host
|
||||||
|
|
||||||
- POST `/host/reload`
|
- POST `/host/reload`
|
||||||
|
|
||||||
- POST `/host/shutdown`
|
- POST `/host/shutdown`
|
||||||
|
|
||||||
- POST `/host/reboot`
|
- POST `/host/reboot`
|
||||||
|
|
||||||
- GET `/host/info`
|
- GET `/host/info`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@ -228,14 +231,21 @@ return:
|
|||||||
"last_version": "",
|
"last_version": "",
|
||||||
"features": ["shutdown", "reboot", "update", "hostname", "network_info", "network_control"],
|
"features": ["shutdown", "reboot", "update", "hostname", "network_info", "network_control"],
|
||||||
"hostname": "",
|
"hostname": "",
|
||||||
"os": "",
|
"operating_system": "",
|
||||||
"audio": {
|
"kernel": "",
|
||||||
"input": "0,0",
|
"chassis": ""
|
||||||
"output": "0,0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- POST `/host/options`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"hostname": "",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
- POST `/host/update`
|
- POST `/host/update`
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
@ -284,24 +294,6 @@ Optional:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Network
|
|
||||||
|
|
||||||
- GET `/network/info`
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"hostname": ""
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- POST `/network/options`
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"hostname": "",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Home Assistant
|
### Home Assistant
|
||||||
|
|
||||||
- GET `/homeassistant/info`
|
- GET `/homeassistant/info`
|
||||||
|
@ -9,7 +9,6 @@ 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 .network import APINetwork
|
|
||||||
from .proxy import APIProxy
|
from .proxy import APIProxy
|
||||||
from .supervisor import APISupervisor
|
from .supervisor import APISupervisor
|
||||||
from .snapshots import APISnapshots
|
from .snapshots import APISnapshots
|
||||||
@ -44,7 +43,6 @@ class RestAPI(CoreSysAttributes):
|
|||||||
self._register_panel()
|
self._register_panel()
|
||||||
self._register_addons()
|
self._register_addons()
|
||||||
self._register_snapshots()
|
self._register_snapshots()
|
||||||
self._register_network()
|
|
||||||
self._register_discovery()
|
self._register_discovery()
|
||||||
self._register_services()
|
self._register_services()
|
||||||
|
|
||||||
@ -61,16 +59,6 @@ class RestAPI(CoreSysAttributes):
|
|||||||
web.post('/host/reload', api_host.reload),
|
web.post('/host/reload', api_host.reload),
|
||||||
])
|
])
|
||||||
|
|
||||||
def _register_network(self):
|
|
||||||
"""Register network function."""
|
|
||||||
api_net = APINetwork()
|
|
||||||
api_net.coresys = self.coresys
|
|
||||||
|
|
||||||
self.webapp.add_routes([
|
|
||||||
web.get('/network/info', api_net.info),
|
|
||||||
web.post('/network/options', api_net.options),
|
|
||||||
])
|
|
||||||
|
|
||||||
def _register_hardware(self):
|
def _register_hardware(self):
|
||||||
"""Register hardware function."""
|
"""Register hardware function."""
|
||||||
api_hardware = APIHardware()
|
api_hardware = APIHardware()
|
||||||
|
@ -7,7 +7,7 @@ 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_TYPE, ATTR_HOSTNAME, ATTR_FEATURES,
|
ATTR_VERSION, ATTR_LAST_VERSION, ATTR_TYPE, ATTR_HOSTNAME, ATTR_FEATURES,
|
||||||
ATTR_OS)
|
ATTR_OPERATING_SYSTEM, ATTR_KERNEL, ATTR_CHASSIS)
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -16,6 +16,10 @@ SCHEMA_VERSION = vol.Schema({
|
|||||||
vol.Optional(ATTR_VERSION): vol.Coerce(str),
|
vol.Optional(ATTR_VERSION): vol.Coerce(str),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
SCHEMA_OPTIONS = vol.Schema({
|
||||||
|
vol.Optional(ATTR_HOSTNAME): vol.Coerce(str),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
class APIHost(CoreSysAttributes):
|
class APIHost(CoreSysAttributes):
|
||||||
"""Handle rest api for host functions."""
|
"""Handle rest api for host functions."""
|
||||||
@ -24,14 +28,25 @@ class APIHost(CoreSysAttributes):
|
|||||||
async def info(self, request):
|
async def info(self, request):
|
||||||
"""Return host information."""
|
"""Return host information."""
|
||||||
return {
|
return {
|
||||||
ATTR_TYPE: ,
|
ATTR_TYPE: None,
|
||||||
ATTR_VERSION: ,
|
ATTR_CHASSIS: self.sys_host.local.chassis,
|
||||||
ATTR_LAST_VERSION: ,
|
ATTR_VERSION: None,
|
||||||
|
ATTR_LAST_VERSION: None,
|
||||||
ATTR_FEATURES: self.sys_host.features,
|
ATTR_FEATURES: self.sys_host.features,
|
||||||
ATTR_HOSTNAME: ,
|
ATTR_HOSTNAME: self.sys_host.local.hostname,
|
||||||
ATTR_OS: ,
|
ATTR_OPERATING_SYSTEM: self.sys_host.local.operating_system,
|
||||||
|
ATTR_KERNEL: self.sys_host.local.kernel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@api_process
|
||||||
|
async def options(self, request):
|
||||||
|
"""Edit host settings."""
|
||||||
|
body = await api_validate(SCHEMA_OPTIONS, request)
|
||||||
|
|
||||||
|
# hostname
|
||||||
|
if ATTR_HOSTNAME in body:
|
||||||
|
await self.sys_host.local.set_hostname(body[ATTR_HOSTNAME])
|
||||||
|
|
||||||
@api_process
|
@api_process
|
||||||
def reboot(self, request):
|
def reboot(self, request):
|
||||||
"""Reboot host."""
|
"""Reboot host."""
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
"""Init file for HassIO network rest api."""
|
|
||||||
import logging
|
|
||||||
|
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from .utils import api_process, api_process_hostcontrol, api_validate
|
|
||||||
from ..const import ATTR_HOSTNAME
|
|
||||||
from ..coresys import CoreSysAttributes
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
SCHEMA_OPTIONS = vol.Schema({
|
|
||||||
vol.Optional(ATTR_HOSTNAME): vol.Coerce(str),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
class APINetwork(CoreSysAttributes):
|
|
||||||
"""Handle rest api for network functions."""
|
|
||||||
|
|
||||||
@api_process
|
|
||||||
async def info(self, request):
|
|
||||||
"""Show network settings."""
|
|
||||||
return {
|
|
||||||
ATTR_HOSTNAME: self._host_control.hostname,
|
|
||||||
}
|
|
||||||
|
|
||||||
@api_process_hostcontrol
|
|
||||||
async def options(self, request):
|
|
||||||
"""Edit network settings."""
|
|
||||||
body = await api_validate(SCHEMA_OPTIONS, request)
|
|
||||||
|
|
||||||
# hostname
|
|
||||||
if ATTR_HOSTNAME in body:
|
|
||||||
if self._host_control.hostname != body[ATTR_HOSTNAME]:
|
|
||||||
await self._host_control.set_hostname(body[ATTR_HOSTNAME])
|
|
||||||
|
|
||||||
return True
|
|
@ -61,7 +61,8 @@ ATTR_LONG_DESCRIPTION = 'long_description'
|
|||||||
ATTR_HOSTNAME = 'hostname'
|
ATTR_HOSTNAME = 'hostname'
|
||||||
ATTR_TIMEZONE = 'timezone'
|
ATTR_TIMEZONE = 'timezone'
|
||||||
ATTR_ARGS = 'args'
|
ATTR_ARGS = 'args'
|
||||||
ATTR_OS = 'os'
|
ATTR_OPERATING_SYSTEM = 'operating_system'
|
||||||
|
ATTR_CHASSIS = 'chassis'
|
||||||
ATTR_TYPE = 'type'
|
ATTR_TYPE = 'type'
|
||||||
ATTR_SOURCE = 'source'
|
ATTR_SOURCE = 'source'
|
||||||
ATTR_FEATURES = 'features'
|
ATTR_FEATURES = 'features'
|
||||||
@ -159,6 +160,7 @@ ATTR_DISCOVERY = 'discovery'
|
|||||||
ATTR_PROTECTED = 'protected'
|
ATTR_PROTECTED = 'protected'
|
||||||
ATTR_CRYPTO = 'crypto'
|
ATTR_CRYPTO = 'crypto'
|
||||||
ATTR_BRANCH = 'branch'
|
ATTR_BRANCH = 'branch'
|
||||||
|
ATTR_KERNEL = 'kernel'
|
||||||
ATTR_SECCOMP = 'seccomp'
|
ATTR_SECCOMP = 'seccomp'
|
||||||
ATTR_APPARMOR = 'apparmor'
|
ATTR_APPARMOR = 'apparmor'
|
||||||
|
|
||||||
@ -213,5 +215,3 @@ FEATURES_SHUTDOWN = 'shutdown'
|
|||||||
FEATURES_REBOOT = 'reboot'
|
FEATURES_REBOOT = 'reboot'
|
||||||
FEATURES_UPDATE = 'update'
|
FEATURES_UPDATE = 'update'
|
||||||
FEATURES_HOSTNAME = 'hostname'
|
FEATURES_HOSTNAME = 'hostname'
|
||||||
FEATURES_NETWORK_INFO = 'network_info'
|
|
||||||
FEATURES_NETWORK_CONTROL = 'network_control'
|
|
||||||
|
@ -21,3 +21,19 @@ class Hostname(DBusInterface):
|
|||||||
self.dbus = await DBus.connect(DBUS_NAME, DBUS_OBJECT)
|
self.dbus = await DBus.connect(DBUS_NAME, DBUS_OBJECT)
|
||||||
except DBusError:
|
except DBusError:
|
||||||
_LOGGER.warning("Can't connect to hostname")
|
_LOGGER.warning("Can't connect to hostname")
|
||||||
|
|
||||||
|
@dbus_connected
|
||||||
|
def set_hostname(self, hostname):
|
||||||
|
"""Change local hostname.
|
||||||
|
|
||||||
|
Return a coroutine.
|
||||||
|
"""
|
||||||
|
return self.dbus.SetHostname(hostname)
|
||||||
|
|
||||||
|
@dbus_connected
|
||||||
|
def get_properties(self):
|
||||||
|
"""Return local host informations.
|
||||||
|
|
||||||
|
Return a coroutine.
|
||||||
|
"""
|
||||||
|
return self.dbus.get_properties(DBUS_NAME)
|
||||||
|
@ -1 +0,0 @@
|
|||||||
"""Interface to NetworkManager over dbus."""
|
|
@ -1 +0,0 @@
|
|||||||
"""Interface to Rauc OTA over dbus."""
|
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
from .alsa import AlsaAudio
|
from .alsa import AlsaAudio
|
||||||
from .power import PowerControl
|
from .power import PowerControl
|
||||||
from ..const import FEATURES_REBOOT, FEATURES_SHUTDOWN
|
from .local import LocalCenter
|
||||||
|
from ..const import FEATURES_REBOOT, FEATURES_SHUTDOWN, FEATURES_HOSTNAME
|
||||||
from ..coresys import CoreSysAttributes
|
from ..coresys import CoreSysAttributes
|
||||||
|
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ class HostManager(CoreSysAttributes):
|
|||||||
self.coresys = coresys
|
self.coresys = coresys
|
||||||
self._alsa = AlsaAudio(coresys)
|
self._alsa = AlsaAudio(coresys)
|
||||||
self._power = PowerControl(coresys)
|
self._power = PowerControl(coresys)
|
||||||
|
self._local = LocalCenter(coresys)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def alsa(self):
|
def alsa(self):
|
||||||
@ -25,6 +27,11 @@ class HostManager(CoreSysAttributes):
|
|||||||
"""Return host power handler."""
|
"""Return host power handler."""
|
||||||
return self._power
|
return self._power
|
||||||
|
|
||||||
|
@property
|
||||||
|
def local(self):
|
||||||
|
"""Return host local handler."""
|
||||||
|
return self._local
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supperted_features(self):
|
def supperted_features(self):
|
||||||
"""Return a list of supported host features."""
|
"""Return a list of supported host features."""
|
||||||
@ -36,12 +43,16 @@ class HostManager(CoreSysAttributes):
|
|||||||
FEATURES_SHUTDOWN,
|
FEATURES_SHUTDOWN,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
if self.sys_dbus.hostname.is_connected:
|
||||||
|
features.append(FEATURES_HOSTNAME)
|
||||||
|
|
||||||
return features
|
return features
|
||||||
|
|
||||||
async def load(self):
|
async def load(self):
|
||||||
"""Load host functions."""
|
"""Load host functions."""
|
||||||
pass
|
if self.sys_dbus.hostname.is_connected:
|
||||||
|
await self.local.update()
|
||||||
|
|
||||||
async def reload(self):
|
def reload(self):
|
||||||
"""Reload host information."""
|
"""Reload host information."""
|
||||||
pass
|
return self.load()
|
||||||
|
67
hassio/host/local.py
Normal file
67
hassio/host/local.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
"""Power control for host."""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from ..coresys import CoreSysAttributes
|
||||||
|
from ..exceptions import HassioError, HostNotSupportedError
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
UNKNOWN = 'Unknown'
|
||||||
|
|
||||||
|
|
||||||
|
class LocalCenter(CoreSysAttributes):
|
||||||
|
"""Handle local system information controls."""
|
||||||
|
|
||||||
|
def __init__(self, coresys):
|
||||||
|
"""Initialize system center handling."""
|
||||||
|
self.coresys = coresys
|
||||||
|
self._data = {}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hostname(self):
|
||||||
|
"""Return local hostname."""
|
||||||
|
return self._data.get('Hostname', UNKNOWN)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def chassis(self):
|
||||||
|
"""Return local chassis type."""
|
||||||
|
return self._data.get('Chassis', UNKNOWN)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def kernel(self):
|
||||||
|
"""Return local kernel version."""
|
||||||
|
return self._data.get('KernelRelease', UNKNOWN)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def operating_system(self):
|
||||||
|
"""Return local operating system."""
|
||||||
|
return self._data.get('OperatingSystemPrettyName', UNKNOWN)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cpe(self):
|
||||||
|
"""Return local CPE."""
|
||||||
|
return self._data.get('OperatingSystemCPEName', UNKNOWN)
|
||||||
|
|
||||||
|
def _check_dbus(self):
|
||||||
|
"""Check if systemd is connect or raise error."""
|
||||||
|
if not self.sys_dbus.hostname.is_connected:
|
||||||
|
_LOGGER.error("No hostname dbus connection available")
|
||||||
|
raise HostNotSupportedError()
|
||||||
|
|
||||||
|
async def update(self):
|
||||||
|
"""Update properties over dbus."""
|
||||||
|
self._check_dbus()
|
||||||
|
|
||||||
|
_LOGGER.info("Update local host information")
|
||||||
|
try:
|
||||||
|
self._data = await self.sys_dbus.hostname.get_properties()
|
||||||
|
except HassioError:
|
||||||
|
_LOGGER.warning("Can't update host system information!")
|
||||||
|
|
||||||
|
async def set_hostname(self, hostname):
|
||||||
|
"""Set local a new Hostname."""
|
||||||
|
self._check_dbus()
|
||||||
|
|
||||||
|
_LOGGER.info("Set Hostname %s", hostname)
|
||||||
|
await self.sys_dbus.hostname.set_hostname(hostname)
|
||||||
|
await self.update()
|
@ -14,7 +14,7 @@ class PowerControl(CoreSysAttributes):
|
|||||||
"""Initialize host power handling."""
|
"""Initialize host power handling."""
|
||||||
self.coresys = coresys
|
self.coresys = coresys
|
||||||
|
|
||||||
def _check_systemd(self):
|
def _check_dbus(self):
|
||||||
"""Check if systemd is connect or raise error."""
|
"""Check if systemd is connect or raise error."""
|
||||||
if not self.sys_dbus.systemd.is_connected:
|
if not self.sys_dbus.systemd.is_connected:
|
||||||
_LOGGER.error("No systemd dbus connection available")
|
_LOGGER.error("No systemd dbus connection available")
|
||||||
@ -22,7 +22,7 @@ class PowerControl(CoreSysAttributes):
|
|||||||
|
|
||||||
async def reboot(self):
|
async def reboot(self):
|
||||||
"""Reboot host system."""
|
"""Reboot host system."""
|
||||||
self._check_systemd()
|
self._check_dbus()
|
||||||
|
|
||||||
_LOGGER.info("Initialize host reboot over systemd")
|
_LOGGER.info("Initialize host reboot over systemd")
|
||||||
try:
|
try:
|
||||||
@ -32,7 +32,7 @@ class PowerControl(CoreSysAttributes):
|
|||||||
|
|
||||||
async def shutdown(self):
|
async def shutdown(self):
|
||||||
"""Shutdown host system."""
|
"""Shutdown host system."""
|
||||||
self._check_systemd()
|
self._check_dbus()
|
||||||
|
|
||||||
_LOGGER.info("Initialize host power off over systemd")
|
_LOGGER.info("Initialize host power off over systemd")
|
||||||
try:
|
try:
|
||||||
|
@ -10,15 +10,22 @@ from ..exceptions import DBusFatalError, DBusParseError
|
|||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Use to convert GVariant into json
|
||||||
|
RE_GVARIANT_TYPE = re.compile(
|
||||||
|
r"(?:boolean|byte|int16|uint16|int32|uint32|handle|int64|uint64|double|"
|
||||||
|
r"string|objectpath|signature) ")
|
||||||
RE_GVARIANT_TULPE = re.compile(r"^\((.*),\)$")
|
RE_GVARIANT_TULPE = re.compile(r"^\((.*),\)$")
|
||||||
RE_GVARIANT_VARIANT = re.compile(
|
RE_GVARIANT_VARIANT = re.compile(
|
||||||
r"(?<=(?: |{|\[))<((?:'|\").*?(?:'|\")|\d+(?:\.\d+)?)>(?=(?:|]|}|,))")
|
r"(?<=(?: |{|\[))<((?:'|\").*?(?:'|\")|\d+(?:\.\d+)?)>(?=(?:|]|}|,))")
|
||||||
RE_GVARIANT_STRING = re.compile(r"(?<=(?: |{|\[))'(.*?)'(?=(?:|]|}|,))")
|
RE_GVARIANT_STRING = re.compile(r"(?<=(?: |{|\[))'(.*?)'(?=(?:|]|}|,))")
|
||||||
|
|
||||||
|
# Commands for dbus
|
||||||
INTROSPECT = ("gdbus introspect --system --dest {bus} "
|
INTROSPECT = ("gdbus introspect --system --dest {bus} "
|
||||||
"--object-path {obj} --xml")
|
"--object-path {object} --xml")
|
||||||
CALL = ("gdbus call --system --dest {bus} --object-path {inf} "
|
CALL = ("gdbus call --system --dest {bus} --object-path {object} "
|
||||||
"--method {inf}.{method} {args}")
|
"--method {method} {args}")
|
||||||
|
|
||||||
|
DBUS_METHOD_GETALL = 'org.freedesktop.DBus.Properties.GetAll'
|
||||||
|
|
||||||
|
|
||||||
class DBus:
|
class DBus:
|
||||||
@ -28,7 +35,7 @@ class DBus:
|
|||||||
"""Initialize dbus object."""
|
"""Initialize dbus object."""
|
||||||
self.bus_name = bus_name
|
self.bus_name = bus_name
|
||||||
self.object_path = object_path
|
self.object_path = object_path
|
||||||
self.data = {}
|
self.methods = set()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def connect(bus_name, object_path):
|
async def connect(bus_name, object_path):
|
||||||
@ -36,14 +43,14 @@ class DBus:
|
|||||||
self = DBus(bus_name, object_path)
|
self = DBus(bus_name, object_path)
|
||||||
self._init_proxy() # pylint: disable=protected-access
|
self._init_proxy() # pylint: disable=protected-access
|
||||||
|
|
||||||
_LOGGER.info("Connect to dbus: %s", bus_name)
|
_LOGGER.info("Connect to dbus: %s - %s", bus_name, object_path)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
async def _init_proxy(self):
|
async def _init_proxy(self):
|
||||||
"""Read object data."""
|
"""Read interface data."""
|
||||||
command = shlex.split(INTROSPECT.format(
|
command = shlex.split(INTROSPECT.format(
|
||||||
bus=self.bus_name,
|
bus=self.bus_name,
|
||||||
obj=self.object_path
|
object=self.object_path
|
||||||
))
|
))
|
||||||
|
|
||||||
# Ask data
|
# Ask data
|
||||||
@ -59,14 +66,15 @@ class DBus:
|
|||||||
|
|
||||||
# Read available methods
|
# Read available methods
|
||||||
for interface in xml.findall("/node/interface"):
|
for interface in xml.findall("/node/interface"):
|
||||||
methods = set()
|
interface_name = interface.get('name')
|
||||||
for method in interface.findall("/method"):
|
for method in interface.findall("/method"):
|
||||||
methods.add(method.get('name'))
|
method_name = method.get('name')
|
||||||
self.data[interface.get('name')] = methods
|
self.methods.add(f"{interface_name}.{method_name}")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _gvariant(raw):
|
def _gvariant(raw):
|
||||||
"""Parse GVariant input to python."""
|
"""Parse GVariant input to python."""
|
||||||
|
raw = RE_GVARIANT_TYPE.sub("", raw)
|
||||||
raw = RE_GVARIANT_TULPE.sub(r"[\1]", raw)
|
raw = RE_GVARIANT_TULPE.sub(r"[\1]", raw)
|
||||||
raw = RE_GVARIANT_VARIANT.sub(r"\1", raw)
|
raw = RE_GVARIANT_VARIANT.sub(r"\1", raw)
|
||||||
raw = RE_GVARIANT_STRING.sub(r"\"\1\"", raw)
|
raw = RE_GVARIANT_STRING.sub(r"\"\1\"", raw)
|
||||||
@ -74,25 +82,32 @@ class DBus:
|
|||||||
try:
|
try:
|
||||||
return json.loads(raw)
|
return json.loads(raw)
|
||||||
except json.JSONDecodeError as err:
|
except json.JSONDecodeError as err:
|
||||||
_LOGGER.error("Can't parse '%s': %s", raw, err)
|
_LOGGER.error("Can't parse '%s': %s", raw, err)
|
||||||
raise DBusParseError() from None
|
raise DBusParseError() from None
|
||||||
|
|
||||||
async def call_dbus(self, interface, method, *args):
|
async def call_dbus(self, method, *args):
|
||||||
"""Call a dbus method."""
|
"""Call a dbus method."""
|
||||||
command = shlex.split(CALL.format(
|
command = shlex.split(CALL.format(
|
||||||
bus=self.bus_name,
|
bus=self.bus_name,
|
||||||
inf=interface,
|
object=self.object_path,
|
||||||
method=method,
|
method=method,
|
||||||
args=" ".join(map(str, args))
|
args=" ".join(map(str, args))
|
||||||
))
|
))
|
||||||
|
|
||||||
# Run command
|
# Run command
|
||||||
_LOGGER.info("Call %s no %s", method, interface)
|
_LOGGER.info("Call %s on %s", method, self.object_path)
|
||||||
data = await self._send(command)
|
data = await self._send(command)
|
||||||
|
|
||||||
# Parse and return data
|
# Parse and return data
|
||||||
return self._gvariant(data)
|
return self._gvariant(data)
|
||||||
|
|
||||||
|
def get_properties(self, interface):
|
||||||
|
"""Read all properties from interface.
|
||||||
|
|
||||||
|
Return a coroutine.
|
||||||
|
"""
|
||||||
|
return self.call_dbus(DBUS_METHOD_GETALL, interface)
|
||||||
|
|
||||||
async def _send(self, command):
|
async def _send(self, command):
|
||||||
"""Send command over dbus."""
|
"""Send command over dbus."""
|
||||||
# Run command
|
# Run command
|
||||||
@ -117,13 +132,9 @@ class DBus:
|
|||||||
# End
|
# End
|
||||||
return data.decode()
|
return data.decode()
|
||||||
|
|
||||||
def __getattr__(self, interface):
|
def __getattr__(self, name):
|
||||||
"""Mapping to dbus method."""
|
"""Mapping to dbus method."""
|
||||||
interface = f"{self.object_path}.{interface}"
|
return getattr(DBusCallWrapper(self, self.object_path), name)
|
||||||
if interface not in self.data:
|
|
||||||
raise AttributeError()
|
|
||||||
|
|
||||||
return DBusCallWrapper(self, interface)
|
|
||||||
|
|
||||||
|
|
||||||
class DBusCallWrapper:
|
class DBusCallWrapper:
|
||||||
@ -134,16 +145,23 @@ class DBusCallWrapper:
|
|||||||
self.dbus = dbus
|
self.dbus = dbus
|
||||||
self.interface = interface
|
self.interface = interface
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
"""Should never be called."""
|
||||||
|
_LOGGER.error("DBus method %s not exists!", self.interface)
|
||||||
|
raise DBusFatalError()
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
"""Mapping to dbus method."""
|
"""Mapping to dbus method."""
|
||||||
if name not in self.dbus.data[self.interface]:
|
interface = f"{self.interface}.{name}"
|
||||||
raise AttributeError()
|
|
||||||
|
if interface not in self.dbus.methods:
|
||||||
|
return DBusCallWrapper(self.dbus, interface)
|
||||||
|
|
||||||
def _method_wrapper(*args):
|
def _method_wrapper(*args):
|
||||||
"""Wrap method.
|
"""Wrap method.
|
||||||
|
|
||||||
Return a coroutine
|
Return a coroutine
|
||||||
"""
|
"""
|
||||||
return self.dbus.call_dbus(self.interface, self.name, *args)
|
return self.dbus.call_dbus(self.interface, *args)
|
||||||
|
|
||||||
return _method_wrapper
|
return _method_wrapper
|
||||||
|
Loading…
x
Reference in New Issue
Block a user