mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 17:27:10 +00:00
Use runtime data for hyperion (#143461)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
parent
0b2e5cd253
commit
2d20df37b1
@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
from collections.abc import Callable
|
||||
from contextlib import suppress
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
from typing import Any, cast
|
||||
|
||||
@ -22,9 +23,6 @@ from homeassistant.helpers.dispatcher import (
|
||||
)
|
||||
|
||||
from .const import (
|
||||
CONF_INSTANCE_CLIENTS,
|
||||
CONF_ON_UNLOAD,
|
||||
CONF_ROOT_CLIENT,
|
||||
DEFAULT_NAME,
|
||||
DOMAIN,
|
||||
HYPERION_RELEASES_URL,
|
||||
@ -52,15 +50,15 @@ _LOGGER = logging.getLogger(__name__)
|
||||
# The get_hyperion_unique_id method will create a per-entity unique id when given the
|
||||
# server id, an instance number and a name.
|
||||
|
||||
# hass.data format
|
||||
# ================
|
||||
#
|
||||
# hass.data[DOMAIN] = {
|
||||
# <config_entry.entry_id>: {
|
||||
# "ROOT_CLIENT": <Hyperion Client>,
|
||||
# "ON_UNLOAD": [<callable>, ...],
|
||||
# }
|
||||
# }
|
||||
type HyperionConfigEntry = ConfigEntry[HyperionData]
|
||||
|
||||
|
||||
@dataclass
|
||||
class HyperionData:
|
||||
"""Hyperion runtime data."""
|
||||
|
||||
root_client: client.HyperionClient
|
||||
instance_clients: dict[int, client.HyperionClient]
|
||||
|
||||
|
||||
def get_hyperion_unique_id(server_id: str, instance: int, name: str) -> str:
|
||||
@ -107,29 +105,29 @@ async def async_create_connect_hyperion_client(
|
||||
@callback
|
||||
def listen_for_instance_updates(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
add_func: Callable,
|
||||
remove_func: Callable,
|
||||
entry: HyperionConfigEntry,
|
||||
add_func: Callable[[int, str], None],
|
||||
remove_func: Callable[[int], None],
|
||||
) -> None:
|
||||
"""Listen for instance additions/removals."""
|
||||
|
||||
hass.data[DOMAIN][config_entry.entry_id][CONF_ON_UNLOAD].extend(
|
||||
[
|
||||
async_dispatcher_connect(
|
||||
hass,
|
||||
SIGNAL_INSTANCE_ADD.format(config_entry.entry_id),
|
||||
add_func,
|
||||
),
|
||||
async_dispatcher_connect(
|
||||
hass,
|
||||
SIGNAL_INSTANCE_REMOVE.format(config_entry.entry_id),
|
||||
remove_func,
|
||||
),
|
||||
]
|
||||
entry.async_on_unload(
|
||||
async_dispatcher_connect(
|
||||
hass,
|
||||
SIGNAL_INSTANCE_ADD.format(entry.entry_id),
|
||||
add_func,
|
||||
)
|
||||
)
|
||||
entry.async_on_unload(
|
||||
async_dispatcher_connect(
|
||||
hass,
|
||||
SIGNAL_INSTANCE_REMOVE.format(entry.entry_id),
|
||||
remove_func,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: HyperionConfigEntry) -> bool:
|
||||
"""Set up Hyperion from a config entry."""
|
||||
host = entry.data[CONF_HOST]
|
||||
port = entry.data[CONF_PORT]
|
||||
@ -185,12 +183,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
# We need 1 root client (to manage instances being removed/added) and then 1 client
|
||||
# per Hyperion server instance which is shared for all entities associated with
|
||||
# that instance.
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
hass.data[DOMAIN][entry.entry_id] = {
|
||||
CONF_ROOT_CLIENT: hyperion_client,
|
||||
CONF_INSTANCE_CLIENTS: {},
|
||||
CONF_ON_UNLOAD: [],
|
||||
}
|
||||
entry.runtime_data = HyperionData(
|
||||
root_client=hyperion_client,
|
||||
instance_clients={},
|
||||
)
|
||||
|
||||
async def async_instances_to_clients(response: dict[str, Any]) -> None:
|
||||
"""Convert instances to Hyperion clients."""
|
||||
@ -203,7 +199,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
device_registry = dr.async_get(hass)
|
||||
running_instances: set[int] = set()
|
||||
stopped_instances: set[int] = set()
|
||||
existing_instances = hass.data[DOMAIN][entry.entry_id][CONF_INSTANCE_CLIENTS]
|
||||
existing_instances = entry.runtime_data.instance_clients
|
||||
server_id = cast(str, entry.unique_id)
|
||||
|
||||
# In practice, an instance can be in 3 states as seen by this function:
|
||||
@ -270,39 +266,29 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
assert hyperion_client
|
||||
if hyperion_client.instances is not None:
|
||||
await async_instances_to_clients_raw(hyperion_client.instances)
|
||||
hass.data[DOMAIN][entry.entry_id][CONF_ON_UNLOAD].append(
|
||||
entry.add_update_listener(_async_entry_updated)
|
||||
)
|
||||
entry.async_on_unload(entry.add_update_listener(_async_entry_updated))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def _async_entry_updated(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
||||
async def _async_entry_updated(hass: HomeAssistant, entry: HyperionConfigEntry) -> None:
|
||||
"""Handle entry updates."""
|
||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||
await hass.config_entries.async_reload(entry.entry_id)
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: HyperionConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(
|
||||
config_entry, PLATFORMS
|
||||
)
|
||||
if unload_ok and config_entry.entry_id in hass.data[DOMAIN]:
|
||||
config_data = hass.data[DOMAIN].pop(config_entry.entry_id)
|
||||
for func in config_data[CONF_ON_UNLOAD]:
|
||||
func()
|
||||
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
if unload_ok:
|
||||
# Disconnect the shared instance clients.
|
||||
await asyncio.gather(
|
||||
*(
|
||||
config_data[CONF_INSTANCE_CLIENTS][
|
||||
instance_num
|
||||
].async_client_disconnect()
|
||||
for instance_num in config_data[CONF_INSTANCE_CLIENTS]
|
||||
inst.async_client_disconnect()
|
||||
for inst in entry.runtime_data.instance_clients.values()
|
||||
)
|
||||
)
|
||||
|
||||
# Disconnect the root client.
|
||||
root_client = config_data[CONF_ROOT_CLIENT]
|
||||
root_client = entry.runtime_data.root_client
|
||||
await root_client.async_client_disconnect()
|
||||
return unload_ok
|
||||
|
@ -25,7 +25,6 @@ from homeassistant.components.camera import (
|
||||
Camera,
|
||||
async_get_still_stream,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
@ -35,12 +34,12 @@ from homeassistant.helpers.dispatcher import (
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import (
|
||||
HyperionConfigEntry,
|
||||
get_hyperion_device_id,
|
||||
get_hyperion_unique_id,
|
||||
listen_for_instance_updates,
|
||||
)
|
||||
from .const import (
|
||||
CONF_INSTANCE_CLIENTS,
|
||||
DOMAIN,
|
||||
HYPERION_MANUFACTURER_NAME,
|
||||
HYPERION_MODEL_NAME,
|
||||
@ -53,12 +52,11 @@ IMAGE_STREAM_JPG_SENTINEL = "data:image/jpg;base64,"
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
entry: HyperionConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a Hyperion platform from config entry."""
|
||||
entry_data = hass.data[DOMAIN][config_entry.entry_id]
|
||||
server_id = config_entry.unique_id
|
||||
server_id = entry.unique_id
|
||||
|
||||
def camera_unique_id(instance_num: int) -> str:
|
||||
"""Return the camera unique_id."""
|
||||
@ -75,7 +73,7 @@ async def async_setup_entry(
|
||||
server_id,
|
||||
instance_num,
|
||||
instance_name,
|
||||
entry_data[CONF_INSTANCE_CLIENTS][instance_num],
|
||||
entry.runtime_data.instance_clients[instance_num],
|
||||
)
|
||||
]
|
||||
)
|
||||
@ -91,7 +89,7 @@ async def async_setup_entry(
|
||||
),
|
||||
)
|
||||
|
||||
listen_for_instance_updates(hass, config_entry, instance_add, instance_remove)
|
||||
listen_for_instance_updates(hass, entry, instance_add, instance_remove)
|
||||
|
||||
|
||||
# A note on Hyperion streaming semantics:
|
||||
|
@ -3,10 +3,7 @@
|
||||
CONF_AUTH_ID = "auth_id"
|
||||
CONF_CREATE_TOKEN = "create_token"
|
||||
CONF_INSTANCE = "instance"
|
||||
CONF_INSTANCE_CLIENTS = "INSTANCE_CLIENTS"
|
||||
CONF_ON_UNLOAD = "ON_UNLOAD"
|
||||
CONF_PRIORITY = "priority"
|
||||
CONF_ROOT_CLIENT = "ROOT_CLIENT"
|
||||
CONF_EFFECT_HIDE_LIST = "effect_hide_list"
|
||||
CONF_EFFECT_SHOW_LIST = "effect_show_list"
|
||||
|
||||
|
@ -17,7 +17,6 @@ from homeassistant.components.light import (
|
||||
LightEntity,
|
||||
LightEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
@ -28,13 +27,13 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util import color as color_util
|
||||
|
||||
from . import (
|
||||
HyperionConfigEntry,
|
||||
get_hyperion_device_id,
|
||||
get_hyperion_unique_id,
|
||||
listen_for_instance_updates,
|
||||
)
|
||||
from .const import (
|
||||
CONF_EFFECT_HIDE_LIST,
|
||||
CONF_INSTANCE_CLIENTS,
|
||||
CONF_PRIORITY,
|
||||
DEFAULT_ORIGIN,
|
||||
DEFAULT_PRIORITY,
|
||||
@ -74,28 +73,26 @@ ICON_EFFECT = "mdi:lava-lamp"
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
entry: HyperionConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a Hyperion platform from config entry."""
|
||||
|
||||
entry_data = hass.data[DOMAIN][config_entry.entry_id]
|
||||
server_id = config_entry.unique_id
|
||||
server_id = entry.unique_id
|
||||
|
||||
@callback
|
||||
def instance_add(instance_num: int, instance_name: str) -> None:
|
||||
"""Add entities for a new Hyperion instance."""
|
||||
assert server_id
|
||||
args = (
|
||||
server_id,
|
||||
instance_num,
|
||||
instance_name,
|
||||
config_entry.options,
|
||||
entry_data[CONF_INSTANCE_CLIENTS][instance_num],
|
||||
)
|
||||
async_add_entities(
|
||||
[
|
||||
HyperionLight(*args),
|
||||
HyperionLight(
|
||||
server_id,
|
||||
instance_num,
|
||||
instance_name,
|
||||
entry.options,
|
||||
entry.runtime_data.instance_clients[instance_num],
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
@ -110,7 +107,7 @@ async def async_setup_entry(
|
||||
),
|
||||
)
|
||||
|
||||
listen_for_instance_updates(hass, config_entry, instance_add, instance_remove)
|
||||
listen_for_instance_updates(hass, entry, instance_add, instance_remove)
|
||||
|
||||
|
||||
class HyperionLight(LightEntity):
|
||||
|
@ -19,7 +19,6 @@ from hyperion.const import (
|
||||
)
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.dispatcher import (
|
||||
@ -29,12 +28,12 @@ from homeassistant.helpers.dispatcher import (
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import (
|
||||
HyperionConfigEntry,
|
||||
get_hyperion_device_id,
|
||||
get_hyperion_unique_id,
|
||||
listen_for_instance_updates,
|
||||
)
|
||||
from .const import (
|
||||
CONF_INSTANCE_CLIENTS,
|
||||
DOMAIN,
|
||||
HYPERION_MANUFACTURER_NAME,
|
||||
HYPERION_MODEL_NAME,
|
||||
@ -62,12 +61,11 @@ def _sensor_unique_id(server_id: str, instance_num: int, suffix: str) -> str:
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
entry: HyperionConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a Hyperion platform from config entry."""
|
||||
entry_data = hass.data[DOMAIN][config_entry.entry_id]
|
||||
server_id = config_entry.unique_id
|
||||
server_id = entry.unique_id
|
||||
|
||||
@callback
|
||||
def instance_add(instance_num: int, instance_name: str) -> None:
|
||||
@ -78,7 +76,7 @@ async def async_setup_entry(
|
||||
server_id,
|
||||
instance_num,
|
||||
instance_name,
|
||||
entry_data[CONF_INSTANCE_CLIENTS][instance_num],
|
||||
entry.runtime_data.instance_clients[instance_num],
|
||||
PRIORITY_SENSOR_DESCRIPTION,
|
||||
)
|
||||
]
|
||||
@ -98,7 +96,7 @@ async def async_setup_entry(
|
||||
),
|
||||
)
|
||||
|
||||
listen_for_instance_updates(hass, config_entry, instance_add, instance_remove)
|
||||
listen_for_instance_updates(hass, entry, instance_add, instance_remove)
|
||||
|
||||
|
||||
class HyperionSensor(SensorEntity):
|
||||
|
@ -26,7 +26,6 @@ from hyperion.const import (
|
||||
)
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
@ -38,12 +37,12 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import (
|
||||
HyperionConfigEntry,
|
||||
get_hyperion_device_id,
|
||||
get_hyperion_unique_id,
|
||||
listen_for_instance_updates,
|
||||
)
|
||||
from .const import (
|
||||
CONF_INSTANCE_CLIENTS,
|
||||
DOMAIN,
|
||||
HYPERION_MANUFACTURER_NAME,
|
||||
HYPERION_MODEL_NAME,
|
||||
@ -89,12 +88,11 @@ def _component_to_translation_key(component: str) -> str:
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
entry: HyperionConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a Hyperion platform from config entry."""
|
||||
entry_data = hass.data[DOMAIN][config_entry.entry_id]
|
||||
server_id = config_entry.unique_id
|
||||
server_id = entry.unique_id
|
||||
|
||||
@callback
|
||||
def instance_add(instance_num: int, instance_name: str) -> None:
|
||||
@ -106,7 +104,7 @@ async def async_setup_entry(
|
||||
instance_num,
|
||||
instance_name,
|
||||
component,
|
||||
entry_data[CONF_INSTANCE_CLIENTS][instance_num],
|
||||
entry.runtime_data.instance_clients[instance_num],
|
||||
)
|
||||
for component in COMPONENT_SWITCHES
|
||||
)
|
||||
@ -123,7 +121,7 @@ async def async_setup_entry(
|
||||
),
|
||||
)
|
||||
|
||||
listen_for_instance_updates(hass, config_entry, instance_add, instance_remove)
|
||||
listen_for_instance_updates(hass, entry, instance_add, instance_remove)
|
||||
|
||||
|
||||
class HyperionComponentSwitch(SwitchEntity):
|
||||
|
Loading…
x
Reference in New Issue
Block a user