Use KNX UI entity platform controller class (#123128)
parent
5b7fd29797
commit
f2d99cb059
|
@ -24,7 +24,7 @@ from homeassistant.helpers.typing import ConfigType
|
|||
|
||||
from . import KNXModule
|
||||
from .const import ATTR_COUNTER, ATTR_SOURCE, DATA_KNX_CONFIG, DOMAIN
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
from .schema import BinarySensorSchema
|
||||
|
||||
|
||||
|
@ -43,7 +43,7 @@ async def async_setup_entry(
|
|||
)
|
||||
|
||||
|
||||
class KNXBinarySensor(KnxEntity, BinarySensorEntity, RestoreEntity):
|
||||
class KNXBinarySensor(KnxYamlEntity, BinarySensorEntity, RestoreEntity):
|
||||
"""Representation of a KNX binary sensor."""
|
||||
|
||||
_device: XknxBinarySensor
|
||||
|
|
|
@ -13,7 +13,7 @@ from homeassistant.helpers.typing import ConfigType
|
|||
|
||||
from . import KNXModule
|
||||
from .const import CONF_PAYLOAD_LENGTH, DATA_KNX_CONFIG, DOMAIN, KNX_ADDRESS
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -31,7 +31,7 @@ async def async_setup_entry(
|
|||
)
|
||||
|
||||
|
||||
class KNXButton(KnxEntity, ButtonEntity):
|
||||
class KNXButton(KnxYamlEntity, ButtonEntity):
|
||||
"""Representation of a KNX button."""
|
||||
|
||||
_device: XknxRawValue
|
||||
|
|
|
@ -35,7 +35,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
PRESET_MODES,
|
||||
)
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
from .schema import ClimateSchema
|
||||
|
||||
ATTR_COMMAND_VALUE = "command_value"
|
||||
|
@ -133,7 +133,7 @@ def _create_climate(xknx: XKNX, config: ConfigType) -> XknxClimate:
|
|||
)
|
||||
|
||||
|
||||
class KNXClimate(KnxEntity, ClimateEntity):
|
||||
class KNXClimate(KnxYamlEntity, ClimateEntity):
|
||||
"""Representation of a KNX climate device."""
|
||||
|
||||
_device: XknxClimate
|
||||
|
|
|
@ -27,7 +27,7 @@ from homeassistant.helpers.typing import ConfigType
|
|||
|
||||
from . import KNXModule
|
||||
from .const import DATA_KNX_CONFIG, DOMAIN
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
from .schema import CoverSchema
|
||||
|
||||
|
||||
|
@ -43,7 +43,7 @@ async def async_setup_entry(
|
|||
async_add_entities(KNXCover(knx_module, entity_config) for entity_config in config)
|
||||
|
||||
|
||||
class KNXCover(KnxEntity, CoverEntity):
|
||||
class KNXCover(KnxYamlEntity, CoverEntity):
|
||||
"""Representation of a KNX cover."""
|
||||
|
||||
_device: XknxCover
|
||||
|
|
|
@ -31,7 +31,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
KNX_ADDRESS,
|
||||
)
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -61,7 +61,7 @@ def _create_xknx_device(xknx: XKNX, config: ConfigType) -> XknxDateDevice:
|
|||
)
|
||||
|
||||
|
||||
class KNXDateEntity(KnxEntity, DateEntity, RestoreEntity):
|
||||
class KNXDateEntity(KnxYamlEntity, DateEntity, RestoreEntity):
|
||||
"""Representation of a KNX date."""
|
||||
|
||||
_device: XknxDateDevice
|
||||
|
|
|
@ -32,7 +32,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
KNX_ADDRESS,
|
||||
)
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -62,7 +62,7 @@ def _create_xknx_device(xknx: XKNX, config: ConfigType) -> XknxDateTimeDevice:
|
|||
)
|
||||
|
||||
|
||||
class KNXDateTimeEntity(KnxEntity, DateTimeEntity, RestoreEntity):
|
||||
class KNXDateTimeEntity(KnxYamlEntity, DateTimeEntity, RestoreEntity):
|
||||
"""Representation of a KNX datetime."""
|
||||
|
||||
_device: XknxDateTimeDevice
|
||||
|
|
|
@ -21,7 +21,7 @@ from homeassistant.util.scaling import int_states_in_range
|
|||
|
||||
from . import KNXModule
|
||||
from .const import DATA_KNX_CONFIG, DOMAIN, KNX_ADDRESS
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
from .schema import FanSchema
|
||||
|
||||
DEFAULT_PERCENTAGE: Final = 50
|
||||
|
@ -39,7 +39,7 @@ async def async_setup_entry(
|
|||
async_add_entities(KNXFan(knx_module, entity_config) for entity_config in config)
|
||||
|
||||
|
||||
class KNXFan(KnxEntity, FanEntity):
|
||||
class KNXFan(KnxYamlEntity, FanEntity):
|
||||
"""Representation of a KNX fan."""
|
||||
|
||||
_device: XknxFan
|
||||
|
|
|
@ -2,30 +2,55 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from xknx.devices import Device as XknxDevice
|
||||
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import DOMAIN
|
||||
from homeassistant.helpers.entity_platform import EntityPlatform
|
||||
from homeassistant.helpers.entity_registry import RegistryEntry
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import KNXModule
|
||||
|
||||
SIGNAL_ENTITY_REMOVE = f"{DOMAIN}_entity_remove_signal.{{}}"
|
||||
from .storage.config_store import PlatformControllerBase
|
||||
|
||||
|
||||
class KnxEntity(Entity):
|
||||
class KnxUiEntityPlatformController(PlatformControllerBase):
|
||||
"""Class to manage dynamic adding and reloading of UI entities."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
knx_module: KNXModule,
|
||||
entity_platform: EntityPlatform,
|
||||
entity_class: type[KnxUiEntity],
|
||||
) -> None:
|
||||
"""Initialize the UI platform."""
|
||||
self._knx_module = knx_module
|
||||
self._entity_platform = entity_platform
|
||||
self._entity_class = entity_class
|
||||
|
||||
async def create_entity(self, unique_id: str, config: dict[str, Any]) -> None:
|
||||
"""Add a new UI entity."""
|
||||
await self._entity_platform.async_add_entities(
|
||||
[self._entity_class(self._knx_module, unique_id, config)]
|
||||
)
|
||||
|
||||
async def update_entity(
|
||||
self, entity_entry: RegistryEntry, config: dict[str, Any]
|
||||
) -> None:
|
||||
"""Update an existing UI entities configuration."""
|
||||
await self._entity_platform.async_remove_entity(entity_entry.entity_id)
|
||||
await self.create_entity(unique_id=entity_entry.unique_id, config=config)
|
||||
|
||||
|
||||
class _KnxEntityBase(Entity):
|
||||
"""Representation of a KNX entity."""
|
||||
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(self, knx_module: KNXModule, device: XknxDevice) -> None:
|
||||
"""Set up device."""
|
||||
self._knx_module = knx_module
|
||||
self._device = device
|
||||
_knx_module: KNXModule
|
||||
_device: XknxDevice
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
|
@ -49,7 +74,7 @@ class KnxEntity(Entity):
|
|||
"""Store register state change callback and start device object."""
|
||||
self._device.register_device_updated_cb(self.after_update_callback)
|
||||
self._device.xknx.devices.async_add(self._device)
|
||||
# super call needed to have methods of mulit-inherited classes called
|
||||
# super call needed to have methods of multi-inherited classes called
|
||||
# eg. for restoring state (like _KNXSwitch)
|
||||
await super().async_added_to_hass()
|
||||
|
||||
|
@ -59,19 +84,22 @@ class KnxEntity(Entity):
|
|||
self._device.xknx.devices.async_remove(self._device)
|
||||
|
||||
|
||||
class KnxUIEntity(KnxEntity):
|
||||
class KnxYamlEntity(_KnxEntityBase):
|
||||
"""Representation of a KNX entity configured from YAML."""
|
||||
|
||||
def __init__(self, knx_module: KNXModule, device: XknxDevice) -> None:
|
||||
"""Initialize the YAML entity."""
|
||||
self._knx_module = knx_module
|
||||
self._device = device
|
||||
|
||||
|
||||
class KnxUiEntity(_KnxEntityBase, ABC):
|
||||
"""Representation of a KNX UI entity."""
|
||||
|
||||
_attr_unique_id: str
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register callbacks when entity added to hass."""
|
||||
await super().async_added_to_hass()
|
||||
self._knx_module.config_store.entities.add(self._attr_unique_id)
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
SIGNAL_ENTITY_REMOVE.format(self._attr_unique_id),
|
||||
self.async_remove,
|
||||
)
|
||||
)
|
||||
@abstractmethod
|
||||
def __init__(
|
||||
self, knx_module: KNXModule, unique_id: str, config: dict[str, Any]
|
||||
) -> None:
|
||||
"""Initialize the UI entity."""
|
||||
|
|
|
@ -19,15 +19,18 @@ from homeassistant.components.light import (
|
|||
LightEntity,
|
||||
)
|
||||
from homeassistant.const import CONF_ENTITY_CATEGORY, CONF_NAME, Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddEntitiesCallback,
|
||||
async_get_current_platform,
|
||||
)
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
import homeassistant.util.color as color_util
|
||||
|
||||
from . import KNXModule
|
||||
from .const import CONF_SYNC_STATE, DATA_KNX_CONFIG, DOMAIN, KNX_ADDRESS, ColorTempModes
|
||||
from .knx_entity import KnxEntity, KnxUIEntity
|
||||
from .knx_entity import KnxUiEntity, KnxUiEntityPlatformController, KnxYamlEntity
|
||||
from .schema import LightSchema
|
||||
from .storage.const import (
|
||||
CONF_COLOR_TEMP_MAX,
|
||||
|
@ -63,8 +66,17 @@ async def async_setup_entry(
|
|||
) -> None:
|
||||
"""Set up light(s) for KNX platform."""
|
||||
knx_module: KNXModule = hass.data[DOMAIN]
|
||||
platform = async_get_current_platform()
|
||||
knx_module.config_store.add_platform(
|
||||
platform=Platform.LIGHT,
|
||||
controller=KnxUiEntityPlatformController(
|
||||
knx_module=knx_module,
|
||||
entity_platform=platform,
|
||||
entity_class=KnxUiLight,
|
||||
),
|
||||
)
|
||||
|
||||
entities: list[KnxEntity] = []
|
||||
entities: list[KnxYamlEntity | KnxUiEntity] = []
|
||||
if yaml_platform_config := hass.data[DATA_KNX_CONFIG].get(Platform.LIGHT):
|
||||
entities.extend(
|
||||
KnxYamlLight(knx_module, entity_config)
|
||||
|
@ -78,13 +90,6 @@ async def async_setup_entry(
|
|||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
@callback
|
||||
def add_new_ui_light(unique_id: str, config: dict[str, Any]) -> None:
|
||||
"""Add KNX entity at runtime."""
|
||||
async_add_entities([KnxUiLight(knx_module, unique_id, config)])
|
||||
|
||||
knx_module.config_store.async_add_entity[Platform.LIGHT] = add_new_ui_light
|
||||
|
||||
|
||||
def _create_yaml_light(xknx: XKNX, config: ConfigType) -> XknxLight:
|
||||
"""Return a KNX Light device to be used within XKNX."""
|
||||
|
@ -519,7 +524,7 @@ class _KnxLight(LightEntity):
|
|||
await self._device.set_off()
|
||||
|
||||
|
||||
class KnxYamlLight(_KnxLight, KnxEntity):
|
||||
class KnxYamlLight(_KnxLight, KnxYamlEntity):
|
||||
"""Representation of a KNX light."""
|
||||
|
||||
_device: XknxLight
|
||||
|
@ -546,7 +551,7 @@ class KnxYamlLight(_KnxLight, KnxEntity):
|
|||
)
|
||||
|
||||
|
||||
class KnxUiLight(_KnxLight, KnxUIEntity):
|
||||
class KnxUiLight(_KnxLight, KnxUiEntity):
|
||||
"""Representation of a KNX light."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
@ -556,11 +561,9 @@ class KnxUiLight(_KnxLight, KnxUIEntity):
|
|||
self, knx_module: KNXModule, unique_id: str, config: ConfigType
|
||||
) -> None:
|
||||
"""Initialize of KNX light."""
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
device=_create_ui_light(
|
||||
knx_module.xknx, config[DOMAIN], config[CONF_ENTITY][CONF_NAME]
|
||||
),
|
||||
self._knx_module = knx_module
|
||||
self._device = _create_ui_light(
|
||||
knx_module.xknx, config[DOMAIN], config[CONF_ENTITY][CONF_NAME]
|
||||
)
|
||||
self._attr_max_color_temp_kelvin: int = config[DOMAIN][CONF_COLOR_TEMP_MAX]
|
||||
self._attr_min_color_temp_kelvin: int = config[DOMAIN][CONF_COLOR_TEMP_MIN]
|
||||
|
|
|
@ -20,7 +20,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|||
|
||||
from . import KNXModule
|
||||
from .const import DATA_KNX_CONFIG, DOMAIN, KNX_ADDRESS
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
|
||||
|
||||
async def async_get_service(
|
||||
|
@ -103,7 +103,7 @@ def _create_notification_instance(xknx: XKNX, config: ConfigType) -> XknxNotific
|
|||
)
|
||||
|
||||
|
||||
class KNXNotify(KnxEntity, NotifyEntity):
|
||||
class KNXNotify(KnxYamlEntity, NotifyEntity):
|
||||
"""Representation of a KNX notification entity."""
|
||||
|
||||
_device: XknxNotification
|
||||
|
|
|
@ -30,7 +30,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
KNX_ADDRESS,
|
||||
)
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
from .schema import NumberSchema
|
||||
|
||||
|
||||
|
@ -58,7 +58,7 @@ def _create_numeric_value(xknx: XKNX, config: ConfigType) -> NumericValue:
|
|||
)
|
||||
|
||||
|
||||
class KNXNumber(KnxEntity, RestoreNumber):
|
||||
class KNXNumber(KnxYamlEntity, RestoreNumber):
|
||||
"""Representation of a KNX number."""
|
||||
|
||||
_device: NumericValue
|
||||
|
|
|
@ -15,7 +15,7 @@ from homeassistant.helpers.typing import ConfigType
|
|||
|
||||
from . import KNXModule
|
||||
from .const import DATA_KNX_CONFIG, DOMAIN, KNX_ADDRESS
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
from .schema import SceneSchema
|
||||
|
||||
|
||||
|
@ -31,7 +31,7 @@ async def async_setup_entry(
|
|||
async_add_entities(KNXScene(knx_module, entity_config) for entity_config in config)
|
||||
|
||||
|
||||
class KNXScene(KnxEntity, Scene):
|
||||
class KNXScene(KnxYamlEntity, Scene):
|
||||
"""Representation of a KNX scene."""
|
||||
|
||||
_device: XknxScene
|
||||
|
|
|
@ -30,7 +30,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
KNX_ADDRESS,
|
||||
)
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
from .schema import SelectSchema
|
||||
|
||||
|
||||
|
@ -59,7 +59,7 @@ def _create_raw_value(xknx: XKNX, config: ConfigType) -> RawValue:
|
|||
)
|
||||
|
||||
|
||||
class KNXSelect(KnxEntity, SelectEntity, RestoreEntity):
|
||||
class KNXSelect(KnxYamlEntity, SelectEntity, RestoreEntity):
|
||||
"""Representation of a KNX select."""
|
||||
|
||||
_device: RawValue
|
||||
|
|
|
@ -35,7 +35,7 @@ from homeassistant.util.enum import try_parse_enum
|
|||
|
||||
from . import KNXModule
|
||||
from .const import ATTR_SOURCE, DATA_KNX_CONFIG, DOMAIN
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
from .schema import SensorSchema
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=10)
|
||||
|
@ -141,7 +141,7 @@ def _create_sensor(xknx: XKNX, config: ConfigType) -> XknxSensor:
|
|||
)
|
||||
|
||||
|
||||
class KNXSensor(KnxEntity, SensorEntity):
|
||||
class KNXSensor(KnxYamlEntity, SensorEntity):
|
||||
"""Representation of a KNX sensor."""
|
||||
|
||||
_device: XknxSensor
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""KNX entity configuration store."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from abc import ABC, abstractmethod
|
||||
import logging
|
||||
from typing import Any, Final, TypedDict
|
||||
|
||||
|
@ -8,12 +8,10 @@ from homeassistant.config_entries import ConfigEntry
|
|||
from homeassistant.const import CONF_PLATFORM, Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.storage import Store
|
||||
from homeassistant.util.ulid import ulid_now
|
||||
|
||||
from ..const import DOMAIN
|
||||
from ..knx_entity import SIGNAL_ENTITY_REMOVE
|
||||
from .const import CONF_DATA
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -33,6 +31,20 @@ class KNXConfigStoreModel(TypedDict):
|
|||
entities: KNXEntityStoreModel
|
||||
|
||||
|
||||
class PlatformControllerBase(ABC):
|
||||
"""Entity platform controller base class."""
|
||||
|
||||
@abstractmethod
|
||||
async def create_entity(self, unique_id: str, config: dict[str, Any]) -> None:
|
||||
"""Create a new entity."""
|
||||
|
||||
@abstractmethod
|
||||
async def update_entity(
|
||||
self, entity_entry: er.RegistryEntry, config: dict[str, Any]
|
||||
) -> None:
|
||||
"""Update an existing entities configuration."""
|
||||
|
||||
|
||||
class KNXConfigStore:
|
||||
"""Manage KNX config store data."""
|
||||
|
||||
|
@ -46,12 +58,7 @@ class KNXConfigStore:
|
|||
self.config_entry = config_entry
|
||||
self._store = Store[KNXConfigStoreModel](hass, STORAGE_VERSION, STORAGE_KEY)
|
||||
self.data = KNXConfigStoreModel(entities={})
|
||||
|
||||
# entities and async_add_entity are filled by platform / entity setups
|
||||
self.entities: set[str] = set() # unique_id as values
|
||||
self.async_add_entity: dict[
|
||||
Platform, Callable[[str, dict[str, Any]], None]
|
||||
] = {}
|
||||
self._platform_controllers: dict[Platform, PlatformControllerBase] = {}
|
||||
|
||||
async def load_data(self) -> None:
|
||||
"""Load config store data from storage."""
|
||||
|
@ -62,14 +69,19 @@ class KNXConfigStore:
|
|||
len(self.data["entities"]),
|
||||
)
|
||||
|
||||
def add_platform(
|
||||
self, platform: Platform, controller: PlatformControllerBase
|
||||
) -> None:
|
||||
"""Add platform controller."""
|
||||
self._platform_controllers[platform] = controller
|
||||
|
||||
async def create_entity(
|
||||
self, platform: Platform, data: dict[str, Any]
|
||||
) -> str | None:
|
||||
"""Create a new entity."""
|
||||
if platform not in self.async_add_entity:
|
||||
raise ConfigStoreException(f"Entity platform not ready: {platform}")
|
||||
platform_controller = self._platform_controllers[platform]
|
||||
unique_id = f"knx_es_{ulid_now()}"
|
||||
self.async_add_entity[platform](unique_id, data)
|
||||
await platform_controller.create_entity(unique_id, data)
|
||||
# store data after entity was added to be sure config didn't raise exceptions
|
||||
self.data["entities"].setdefault(platform, {})[unique_id] = data
|
||||
await self._store.async_save(self.data)
|
||||
|
@ -95,8 +107,7 @@ class KNXConfigStore:
|
|||
self, platform: Platform, entity_id: str, data: dict[str, Any]
|
||||
) -> None:
|
||||
"""Update an existing entity."""
|
||||
if platform not in self.async_add_entity:
|
||||
raise ConfigStoreException(f"Entity platform not ready: {platform}")
|
||||
platform_controller = self._platform_controllers[platform]
|
||||
entity_registry = er.async_get(self.hass)
|
||||
if (entry := entity_registry.async_get(entity_id)) is None:
|
||||
raise ConfigStoreException(f"Entity not found: {entity_id}")
|
||||
|
@ -108,8 +119,7 @@ class KNXConfigStore:
|
|||
raise ConfigStoreException(
|
||||
f"Entity not found in storage: {entity_id} - {unique_id}"
|
||||
)
|
||||
async_dispatcher_send(self.hass, SIGNAL_ENTITY_REMOVE.format(unique_id))
|
||||
self.async_add_entity[platform](unique_id, data)
|
||||
await platform_controller.update_entity(entry, data)
|
||||
# store data after entity is added to make sure config doesn't raise exceptions
|
||||
self.data["entities"][platform][unique_id] = data
|
||||
await self._store.async_save(self.data)
|
||||
|
@ -125,23 +135,21 @@ class KNXConfigStore:
|
|||
raise ConfigStoreException(
|
||||
f"Entity not found in {entry.domain}: {entry.unique_id}"
|
||||
) from err
|
||||
try:
|
||||
self.entities.remove(entry.unique_id)
|
||||
except KeyError:
|
||||
_LOGGER.warning("Entity not initialized when deleted: %s", entity_id)
|
||||
entity_registry.async_remove(entity_id)
|
||||
await self._store.async_save(self.data)
|
||||
|
||||
def get_entity_entries(self) -> list[er.RegistryEntry]:
|
||||
"""Get entity_ids of all configured entities by platform."""
|
||||
"""Get entity_ids of all UI configured entities."""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
|
||||
unique_ids = {
|
||||
uid for platform in self.data["entities"].values() for uid in platform
|
||||
}
|
||||
return [
|
||||
registry_entry
|
||||
for registry_entry in er.async_entries_for_config_entry(
|
||||
entity_registry, self.config_entry.entry_id
|
||||
)
|
||||
if registry_entry.unique_id in self.entities
|
||||
if registry_entry.unique_id in unique_ids
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -17,9 +17,12 @@ from homeassistant.const import (
|
|||
STATE_UNKNOWN,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddEntitiesCallback,
|
||||
async_get_current_platform,
|
||||
)
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
|
@ -32,7 +35,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
KNX_ADDRESS,
|
||||
)
|
||||
from .knx_entity import KnxEntity, KnxUIEntity
|
||||
from .knx_entity import KnxUiEntity, KnxUiEntityPlatformController, KnxYamlEntity
|
||||
from .schema import SwitchSchema
|
||||
from .storage.const import (
|
||||
CONF_DEVICE_INFO,
|
||||
|
@ -51,8 +54,17 @@ async def async_setup_entry(
|
|||
) -> None:
|
||||
"""Set up switch(es) for KNX platform."""
|
||||
knx_module: KNXModule = hass.data[DOMAIN]
|
||||
platform = async_get_current_platform()
|
||||
knx_module.config_store.add_platform(
|
||||
platform=Platform.SWITCH,
|
||||
controller=KnxUiEntityPlatformController(
|
||||
knx_module=knx_module,
|
||||
entity_platform=platform,
|
||||
entity_class=KnxUiSwitch,
|
||||
),
|
||||
)
|
||||
|
||||
entities: list[KnxEntity] = []
|
||||
entities: list[KnxYamlEntity | KnxUiEntity] = []
|
||||
if yaml_platform_config := hass.data[DATA_KNX_CONFIG].get(Platform.SWITCH):
|
||||
entities.extend(
|
||||
KnxYamlSwitch(knx_module, entity_config)
|
||||
|
@ -66,13 +78,6 @@ async def async_setup_entry(
|
|||
if entities:
|
||||
async_add_entities(entities)
|
||||
|
||||
@callback
|
||||
def add_new_ui_switch(unique_id: str, config: dict[str, Any]) -> None:
|
||||
"""Add KNX entity at runtime."""
|
||||
async_add_entities([KnxUiSwitch(knx_module, unique_id, config)])
|
||||
|
||||
knx_module.config_store.async_add_entity[Platform.SWITCH] = add_new_ui_switch
|
||||
|
||||
|
||||
class _KnxSwitch(SwitchEntity, RestoreEntity):
|
||||
"""Base class for a KNX switch."""
|
||||
|
@ -102,7 +107,7 @@ class _KnxSwitch(SwitchEntity, RestoreEntity):
|
|||
await self._device.set_off()
|
||||
|
||||
|
||||
class KnxYamlSwitch(_KnxSwitch, KnxEntity):
|
||||
class KnxYamlSwitch(_KnxSwitch, KnxYamlEntity):
|
||||
"""Representation of a KNX switch configured from YAML."""
|
||||
|
||||
_device: XknxSwitch
|
||||
|
@ -125,7 +130,7 @@ class KnxYamlSwitch(_KnxSwitch, KnxEntity):
|
|||
self._attr_unique_id = str(self._device.switch.group_address)
|
||||
|
||||
|
||||
class KnxUiSwitch(_KnxSwitch, KnxUIEntity):
|
||||
class KnxUiSwitch(_KnxSwitch, KnxUiEntity):
|
||||
"""Representation of a KNX switch configured from UI."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
@ -134,21 +139,19 @@ class KnxUiSwitch(_KnxSwitch, KnxUIEntity):
|
|||
def __init__(
|
||||
self, knx_module: KNXModule, unique_id: str, config: dict[str, Any]
|
||||
) -> None:
|
||||
"""Initialize of KNX switch."""
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
device=XknxSwitch(
|
||||
knx_module.xknx,
|
||||
name=config[CONF_ENTITY][CONF_NAME],
|
||||
group_address=config[DOMAIN][CONF_GA_SWITCH][CONF_GA_WRITE],
|
||||
group_address_state=[
|
||||
config[DOMAIN][CONF_GA_SWITCH][CONF_GA_STATE],
|
||||
*config[DOMAIN][CONF_GA_SWITCH][CONF_GA_PASSIVE],
|
||||
],
|
||||
respond_to_read=config[DOMAIN][CONF_RESPOND_TO_READ],
|
||||
sync_state=config[DOMAIN][CONF_SYNC_STATE],
|
||||
invert=config[DOMAIN][CONF_INVERT],
|
||||
),
|
||||
"""Initialize KNX switch."""
|
||||
self._knx_module = knx_module
|
||||
self._device = XknxSwitch(
|
||||
knx_module.xknx,
|
||||
name=config[CONF_ENTITY][CONF_NAME],
|
||||
group_address=config[DOMAIN][CONF_GA_SWITCH][CONF_GA_WRITE],
|
||||
group_address_state=[
|
||||
config[DOMAIN][CONF_GA_SWITCH][CONF_GA_STATE],
|
||||
*config[DOMAIN][CONF_GA_SWITCH][CONF_GA_PASSIVE],
|
||||
],
|
||||
respond_to_read=config[DOMAIN][CONF_RESPOND_TO_READ],
|
||||
sync_state=config[DOMAIN][CONF_SYNC_STATE],
|
||||
invert=config[DOMAIN][CONF_INVERT],
|
||||
)
|
||||
self._attr_entity_category = config[CONF_ENTITY][CONF_ENTITY_CATEGORY]
|
||||
self._attr_unique_id = unique_id
|
||||
|
|
|
@ -30,7 +30,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
KNX_ADDRESS,
|
||||
)
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -57,7 +57,7 @@ def _create_notification(xknx: XKNX, config: ConfigType) -> XknxNotification:
|
|||
)
|
||||
|
||||
|
||||
class KNXText(KnxEntity, TextEntity, RestoreEntity):
|
||||
class KNXText(KnxYamlEntity, TextEntity, RestoreEntity):
|
||||
"""Representation of a KNX text."""
|
||||
|
||||
_device: XknxNotification
|
||||
|
|
|
@ -31,7 +31,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
KNX_ADDRESS,
|
||||
)
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -61,7 +61,7 @@ def _create_xknx_device(xknx: XKNX, config: ConfigType) -> XknxTimeDevice:
|
|||
)
|
||||
|
||||
|
||||
class KNXTimeEntity(KnxEntity, TimeEntity, RestoreEntity):
|
||||
class KNXTimeEntity(KnxYamlEntity, TimeEntity, RestoreEntity):
|
||||
"""Representation of a KNX time."""
|
||||
|
||||
_device: XknxTimeDevice
|
||||
|
|
|
@ -21,7 +21,7 @@ from homeassistant.helpers.typing import ConfigType
|
|||
|
||||
from . import KNXModule
|
||||
from .const import DATA_KNX_CONFIG, DOMAIN
|
||||
from .knx_entity import KnxEntity
|
||||
from .knx_entity import KnxYamlEntity
|
||||
from .schema import WeatherSchema
|
||||
|
||||
|
||||
|
@ -75,7 +75,7 @@ def _create_weather(xknx: XKNX, config: ConfigType) -> XknxWeather:
|
|||
)
|
||||
|
||||
|
||||
class KNXWeather(KnxEntity, WeatherEntity):
|
||||
class KNXWeather(KnxYamlEntity, WeatherEntity):
|
||||
"""Representation of a KNX weather device."""
|
||||
|
||||
_device: XknxWeather
|
||||
|
|
Loading…
Reference in New Issue