Ingress panel support (#1047)

* Ingress Panel support

* Fix lists

* Allow to set the value

* fix panels

* Update ha realtime

* Fix url

* Fix update
This commit is contained in:
Pascal Vizeli 2019-04-23 11:18:04 +02:00 committed by GitHub
parent e10fe16f21
commit decf254e5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 121 additions and 7 deletions

23
API.md
View File

@ -516,7 +516,8 @@ Get all available addons.
"ingress": "bool",
"ingress_entry": "null|/api/hassio_ingress/slug",
"ingress_url": "null|/api/hassio_ingress/slug/entry.html",
"ingress_port": "null|int"
"ingress_port": "null|int",
"ingress_panel": "null|bool"
}
```
@ -537,7 +538,8 @@ Get all available addons.
},
"options": {},
"audio_output": "null|0,0",
"audio_input": "null|0,0"
"audio_input": "null|0,0",
"ingress_panel": "bool"
}
```
@ -602,6 +604,23 @@ Create a new Session for access to ingress service.
}
```
- GET `/ingress/panels`
Return a list of enabled panels.
```json
{
"panels": {
"addon_slug": {
"enable": "boolean",
"icon": "mdi:...",
"title": "title",
"admin": "boolean"
}
}
}
```
- VIEW `/ingress/{token}`
Ingress WebUI for this Add-on. The addon need support HASS Auth!

View File

@ -47,6 +47,10 @@ from ..const import (
ATTR_INGRESS_ENTRY,
ATTR_INGRESS_PORT,
ATTR_INGRESS_TOKEN,
ATTR_INGRESS_PANEL,
ATTR_INGRESS_PANEL_ADMIN,
ATTR_INGRESS_PANEL_ICON,
ATTR_INGRESS_PANEL_TITLE,
ATTR_KERNEL_MODULES,
ATTR_LEGACY,
ATTR_LOCATON,
@ -449,6 +453,21 @@ class Addon(CoreSysAttributes):
return self.sys_ingress.get_dynamic_port(self.slug)
return port
@property
def ingress_icon(self) -> str:
"""Return panel icon for Ingress frame."""
return self._mesh[ATTR_INGRESS_PANEL_ICON]
@property
def ingress_title(self) -> str:
"""Return panel icon for Ingress frame."""
return self._mesh.get(ATTR_INGRESS_PANEL_TITLE, self.name)
@property
def ingress_admin(self) -> str:
"""Return panel icon for Ingress frame."""
return self._mesh[ATTR_INGRESS_PANEL_ADMIN]
@property
def host_network(self):
"""Return True if add-on run on host network."""
@ -538,6 +557,18 @@ class Addon(CoreSysAttributes):
"""Return True if the add-on access support ingress."""
return self._mesh[ATTR_INGRESS]
@property
def ingress_panel(self) -> Optional[bool]:
"""Return True if the add-on access support ingress."""
if self.is_installed:
return self._data.user[self._id][ATTR_INGRESS_PANEL]
return None
@ingress_panel.setter
def ingress_panel(self, value: bool):
"""Return True if the add-on access support ingress."""
self._data.user[self._id][ATTR_INGRESS_PANEL] = value
@property
def with_gpio(self):
"""Return True if the add-on access to GPIO interface."""

View File

@ -41,6 +41,10 @@ from ..const import (
ATTR_INGRESS_ENTRY,
ATTR_INGRESS_PORT,
ATTR_INGRESS_TOKEN,
ATTR_INGRESS_PANEL,
ATTR_INGRESS_PANEL_ADMIN,
ATTR_INGRESS_PANEL_ICON,
ATTR_INGRESS_PANEL_TITLE,
ATTR_KERNEL_MODULES,
ATTR_LEGACY,
ATTR_LOCATON,
@ -159,6 +163,9 @@ SCHEMA_ADDON_CONFIG = vol.Schema({
vol.Optional(ATTR_INGRESS, default=False): vol.Boolean(),
vol.Optional(ATTR_INGRESS_PORT, default=8099): vol.Any(NETWORK_PORT, vol.Equal(0)),
vol.Optional(ATTR_INGRESS_ENTRY): vol.Coerce(str),
vol.Optional(ATTR_INGRESS_PANEL_ICON, default="mdi:puzzle"): vol.Coerce(str),
vol.Optional(ATTR_INGRESS_PANEL_TITLE): vol.Coerce(str),
vol.Optional(ATTR_INGRESS_PANEL_ADMIN, default=True): vol.Boolean(),
vol.Optional(ATTR_HOMEASSISTANT): vol.Maybe(vol.Coerce(str)),
vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(),
vol.Optional(ATTR_HOST_PID, default=False): vol.Boolean(),
@ -239,6 +246,7 @@ SCHEMA_ADDON_USER = vol.Schema({
vol.Optional(ATTR_AUDIO_OUTPUT): ALSA_DEVICE,
vol.Optional(ATTR_AUDIO_INPUT): ALSA_DEVICE,
vol.Optional(ATTR_PROTECTED, default=True): vol.Boolean(),
vol.Optional(ATTR_INGRESS_PANEL, default=False): vol.Boolean(),
}, extra=vol.REMOVE_EXTRA)

View File

@ -195,6 +195,7 @@ class RestAPI(CoreSysAttributes):
self.webapp.add_routes([
web.post('/ingress/session', api_ingress.create_session),
web.get('/ingress/panels', api_ingress.panels),
web.view('/ingress/{token}/{path:.*}', api_ingress.handler),
])

View File

@ -46,6 +46,7 @@ from ..const import (
ATTR_INGRESS_ENTRY,
ATTR_INGRESS_PORT,
ATTR_INGRESS_URL,
ATTR_INGRESS_PANEL,
ATTR_INSTALLED,
ATTR_IP_ADDRESS,
ATTR_KERNEL_MODULES,
@ -100,6 +101,7 @@ SCHEMA_OPTIONS = vol.Schema({
vol.Optional(ATTR_AUTO_UPDATE): vol.Boolean(),
vol.Optional(ATTR_AUDIO_OUTPUT): ALSA_DEVICE,
vol.Optional(ATTR_AUDIO_INPUT): ALSA_DEVICE,
vol.Optional(ATTR_INGRESS_PANEL): vol.Boolean(),
})
# pylint: disable=no-value-for-parameter
@ -227,6 +229,7 @@ class APIAddons(CoreSysAttributes):
ATTR_INGRESS_ENTRY: addon.ingress_entry,
ATTR_INGRESS_URL: addon.ingress_url,
ATTR_INGRESS_PORT: addon.ingress_port,
ATTR_INGRESS_PANEL: addon.ingress_panel,
}
@api_process
@ -251,6 +254,9 @@ class APIAddons(CoreSysAttributes):
addon.audio_input = body[ATTR_AUDIO_INPUT]
if ATTR_AUDIO_OUTPUT in body:
addon.audio_output = body[ATTR_AUDIO_OUTPUT]
if ATTR_INGRESS_PANEL in body:
addon.ingress_panel = body[ATTR_INGRESS_PANEL]
await self.sys_ingress.update_hass_panel(addon)
addon.save_data()

View File

@ -14,7 +14,17 @@ from aiohttp.web_exceptions import (
from multidict import CIMultiDict, istr
from ..addons.addon import Addon
from ..const import ATTR_SESSION, HEADER_TOKEN, REQUEST_FROM, COOKIE_INGRESS
from ..const import (
ATTR_ADMIN,
ATTR_ICON,
ATTR_SESSION,
ATTR_TITLE,
ATTR_PANELS,
ATTR_ENABLE,
COOKIE_INGRESS,
HEADER_TOKEN,
REQUEST_FROM,
)
from ..coresys import CoreSysAttributes
from .utils import api_process
@ -45,6 +55,20 @@ class APIIngress(CoreSysAttributes):
"""Create URL to container."""
return f"http://{addon.ip_address}:{addon.ingress_port}/{path}"
@api_process
async def panels(self, request: web.Request) -> Dict[str, Any]:
"""Create a list of panel data."""
addons = {}
for addon in self.sys_ingress.addons:
addons[addon.slug] = {
ATTR_TITLE: addon.ingress_title,
ATTR_ICON: addon.ingress_icon,
ATTR_ADMIN: addon.ingress_admin,
ATTR_ENABLE: addon.ingress_panel,
}
return {ATTR_PANELS: addons}
@api_process
async def create_session(self, request: web.Request) -> Dict[str, Any]:
"""Create a new session."""

View File

@ -198,8 +198,16 @@ ATTR_INGRESS_PORT = "ingress_port"
ATTR_INGRESS_ENTRY = "ingress_entry"
ATTR_INGRESS_TOKEN = "ingress_token"
ATTR_INGRESS_URL = "ingress_url"
ATTR_INGRESS_PANEL = "ingress_panel"
ATTR_INGRESS_PANEL_ICON = "ingress_panel_icon"
ATTR_INGRESS_PANEL_TITLE = "ingress_panel_title"
ATTR_INGRESS_PANEL_ADMIN = "ingress_panel_admin"
ATTR_TITLE = "title"
ATTR_ENABLE = "enable"
ATTR_IP_ADDRESS = "ip_address"
ATTR_SESSION = "session"
ATTR_ADMIN = "admin"
ATTR_PANELS = "panels"
PROVIDE_SERVICE = "provide"
NEED_SERVICE = "need"

View File

@ -3,7 +3,7 @@ from datetime import timedelta
import logging
import random
import secrets
from typing import Dict, Optional
from typing import Dict, List, Optional
from .addons.addon import Addon
from .const import ATTR_PORTS, ATTR_SESSION, FILE_HASSIO_INGRESS
@ -40,6 +40,16 @@ class Ingress(JsonConfig, CoreSysAttributes):
"""Return list of dynamic ports."""
return self._data[ATTR_PORTS]
@property
def addons(self) -> List[Addon]:
"""Return list of ingress Add-ons."""
addons = []
for addon in self.sys_addons.list_installed:
if not addon.with_ingress:
continue
addons.append(addon)
return addons
async def load(self) -> None:
"""Update internal data."""
self._update_token_list()
@ -77,9 +87,7 @@ class Ingress(JsonConfig, CoreSysAttributes):
self.tokens.clear()
# Read all ingress token and build a map
for addon in self.sys_addons.list_installed:
if not addon.with_ingress:
continue
for addon in self.addons:
self.tokens[addon.ingress_token] = addon.slug
def create_session(self) -> str:
@ -118,3 +126,12 @@ class Ingress(JsonConfig, CoreSysAttributes):
self.ports[addon_slug] = port
self.save_data()
return port
async def update_hass_panel(self, addon: Addon):
"""Return True if Home Assistant up and running."""
method = "post" if addon.ingress_panel else "delete"
async with self.sys_homeassistant.make_request(method, f"api/hassio_push/panel/{addon.slug}") as resp:
if resp.status in (200, 201):
_LOGGER.info("Update Ingress as panel for %s", addon.slug)
else:
_LOGGER.warning("Fails Ingress panel for %s with %i", addon.slug, resp.status)