Support basic video mapping (#1483)

* Support basic video mapping

* Fix regex
This commit is contained in:
Pascal Vizeli 2020-02-06 10:48:27 +01:00 committed by GitHub
parent a2f06b1553
commit dd603e1ec2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 59 additions and 2 deletions

3
API.md
View File

@ -52,7 +52,7 @@ The addons from `addons` are only installed one.
"slug": "xy", "slug": "xy",
"description": "description", "description": "description",
"repository": "12345678|null", "repository": "12345678|null",
"version": "LAST_VERSION", "version": "LATEST_VERSION",
"installed": "INSTALL_VERSION", "installed": "INSTALL_VERSION",
"icon": "bool", "icon": "bool",
"logo": "bool", "logo": "bool",
@ -537,6 +537,7 @@ Get all available addons.
"kernel_modules": "bool", "kernel_modules": "bool",
"devicetree": "bool", "devicetree": "bool",
"docker_api": "bool", "docker_api": "bool",
"video": "bool",
"audio": "bool", "audio": "bool",
"audio_input": "null|0,0", "audio_input": "null|0,0",
"audio_output": "null|0,0", "audio_output": "null|0,0",

View File

@ -57,6 +57,7 @@ from ..const import (
ATTR_UDEV, ATTR_UDEV,
ATTR_URL, ATTR_URL,
ATTR_VERSION, ATTR_VERSION,
ATTR_VIDEO,
ATTR_WEBUI, ATTR_WEBUI,
SECURITY_DEFAULT, SECURITY_DEFAULT,
SECURITY_DISABLE, SECURITY_DISABLE,
@ -393,6 +394,11 @@ class AddonModel(CoreSysAttributes):
"""Return True if the add-on access to audio.""" """Return True if the add-on access to audio."""
return self.data[ATTR_AUDIO] return self.data[ATTR_AUDIO]
@property
def with_video(self) -> bool:
"""Return True if the add-on access to video."""
return self.data[ATTR_VIDEO]
@property @property
def homeassistant_version(self) -> Optional[str]: def homeassistant_version(self) -> Optional[str]:
"""Return min Home Assistant version they needed by Add-on.""" """Return min Home Assistant version they needed by Add-on."""

View File

@ -77,6 +77,7 @@ from ..const import (
ATTR_USER, ATTR_USER,
ATTR_UUID, ATTR_UUID,
ATTR_VERSION, ATTR_VERSION,
ATTR_VIDEO,
ATTR_WEBUI, ATTR_WEBUI,
BOOT_AUTO, BOOT_AUTO,
BOOT_MANUAL, BOOT_MANUAL,
@ -219,6 +220,7 @@ SCHEMA_ADDON_CONFIG = vol.Schema(
vol.Optional(ATTR_APPARMOR, default=True): vol.Boolean(), vol.Optional(ATTR_APPARMOR, default=True): vol.Boolean(),
vol.Optional(ATTR_FULL_ACCESS, default=False): vol.Boolean(), vol.Optional(ATTR_FULL_ACCESS, default=False): vol.Boolean(),
vol.Optional(ATTR_AUDIO, default=False): vol.Boolean(), vol.Optional(ATTR_AUDIO, default=False): vol.Boolean(),
vol.Optional(ATTR_VIDEO, default=False): vol.Boolean(),
vol.Optional(ATTR_GPIO, default=False): vol.Boolean(), vol.Optional(ATTR_GPIO, default=False): vol.Boolean(),
vol.Optional(ATTR_DEVICETREE, default=False): vol.Boolean(), vol.Optional(ATTR_DEVICETREE, default=False): vol.Boolean(),
vol.Optional(ATTR_KERNEL_MODULES, default=False): vol.Boolean(), vol.Optional(ATTR_KERNEL_MODULES, default=False): vol.Boolean(),

View File

@ -82,6 +82,7 @@ from ..const import (
ATTR_UDEV, ATTR_UDEV,
ATTR_URL, ATTR_URL,
ATTR_VERSION, ATTR_VERSION,
ATTR_VIDEO,
ATTR_WEBUI, ATTR_WEBUI,
BOOT_AUTO, BOOT_AUTO,
BOOT_MANUAL, BOOT_MANUAL,
@ -238,6 +239,7 @@ class APIAddons(CoreSysAttributes):
ATTR_DEVICETREE: addon.with_devicetree, ATTR_DEVICETREE: addon.with_devicetree,
ATTR_UDEV: addon.with_udev, ATTR_UDEV: addon.with_udev,
ATTR_DOCKER_API: addon.access_docker_api, ATTR_DOCKER_API: addon.access_docker_api,
ATTR_VIDEO: addon.with_video,
ATTR_AUDIO: addon.with_audio, ATTR_AUDIO: addon.with_audio,
ATTR_AUDIO_INPUT: None, ATTR_AUDIO_INPUT: None,
ATTR_AUDIO_OUTPUT: None, ATTR_AUDIO_OUTPUT: None,

View File

@ -149,6 +149,7 @@ ATTR_TYPE = "type"
ATTR_TIMEOUT = "timeout" ATTR_TIMEOUT = "timeout"
ATTR_AUTO_UPDATE = "auto_update" ATTR_AUTO_UPDATE = "auto_update"
ATTR_CUSTOM = "custom" ATTR_CUSTOM = "custom"
ATTR_VIDEO = "video"
ATTR_AUDIO = "audio" ATTR_AUDIO = "audio"
ATTR_AUDIO_INPUT = "audio_input" ATTR_AUDIO_INPUT = "audio_input"
ATTR_AUDIO_OUTPUT = "audio_output" ATTR_AUDIO_OUTPUT = "audio_output"

View File

@ -147,6 +147,11 @@ class DockerAddon(DockerInterface):
for device in serial_devs: for device in serial_devs:
devices.append(f"{device}:{device}:rwm") devices.append(f"{device}:{device}:rwm")
# Use video devices
if self.addon.with_video:
for device in self.sys_hardware.video_devices:
devices.append(f"{device.path!s}:{device.path!s}:rwm")
# Return None if no devices is present # Return None if no devices is present
return devices or None return devices or None

View File

@ -4,13 +4,15 @@ from datetime import datetime
import logging import logging
from pathlib import Path from pathlib import Path
import re import re
from typing import Any, Dict, Optional, Set from typing import Any, Dict, List, Optional, Set
import attr
import pyudev import pyudev
from ..const import ATTR_DEVICES, ATTR_NAME, ATTR_TYPE, CHAN_ID, CHAN_TYPE from ..const import ATTR_DEVICES, ATTR_NAME, ATTR_TYPE, CHAN_ID, CHAN_TYPE
from ..exceptions import HardwareNotSupportedError from ..exceptions import HardwareNotSupportedError
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
ASOUND_CARDS: Path = Path("/proc/asound/cards") ASOUND_CARDS: Path = Path("/proc/asound/cards")
@ -26,6 +28,17 @@ GPIO_DEVICES: Path = Path("/sys/class/gpio")
SOC_DEVICES: Path = Path("/sys/devices/platform/soc") SOC_DEVICES: Path = Path("/sys/devices/platform/soc")
RE_TTY: re.Pattern = re.compile(r"tty[A-Z]+") RE_TTY: re.Pattern = re.compile(r"tty[A-Z]+")
RE_VIDEO_DEVICES = re.compile(r"^(?:vchiq|cec)")
@attr.s(frozen=True)
class Device:
"""Represent a device."""
name: str = attr.ib()
path: Path = attr.ib()
links: List[Path] = attr.ib()
class Hardware: class Hardware:
"""Representation of an interface to procfs, sysfs and udev.""" """Representation of an interface to procfs, sysfs and udev."""
@ -34,6 +47,33 @@ class Hardware:
"""Init hardware object.""" """Init hardware object."""
self.context = pyudev.Context() self.context = pyudev.Context()
@property
def devices(self) -> List[Device]:
"""Return a list of all available devices."""
dev_list: List[Device] = []
# Exctract all devices
for device in self.context.list_devices():
dev_list.append(
Device(device.sys_name),
Path(device.device_node),
[Path(node) for node in device.device_links],
)
return dev_list
@property
def video_devices(self) -> List[Device]:
"""Return all available video devices."""
dev_list: List[Device] = []
for device in self.devices:
if not RE_VIDEO_DEVICES.match(device.name):
continue
dev_list.append(device)
return dev_list
@property @property
def serial_devices(self) -> Set[str]: def serial_devices(self) -> Set[str]:
"""Return all serial and connected devices.""" """Return all serial and connected devices."""