Remove KNX yaml config from hass.data (#124050)

* Remove KNX yaml config from `hass.data`

* Use HassKey
This commit is contained in:
Matthias Alphart 2024-09-09 09:01:21 +02:00 committed by GitHub
parent 17ab45da43
commit 713689491b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 124 additions and 132 deletions

View File

@ -5,6 +5,7 @@ from __future__ import annotations
import contextlib import contextlib
import logging import logging
from pathlib import Path from pathlib import Path
from typing import Final
import voluptuous as vol import voluptuous as vol
from xknx import XKNX from xknx import XKNX
@ -59,9 +60,9 @@ from .const import (
CONF_KNX_TUNNELING_TCP, CONF_KNX_TUNNELING_TCP,
CONF_KNX_TUNNELING_TCP_SECURE, CONF_KNX_TUNNELING_TCP_SECURE,
DATA_HASS_CONFIG, DATA_HASS_CONFIG,
DATA_KNX_CONFIG,
DOMAIN, DOMAIN,
KNX_ADDRESS, KNX_ADDRESS,
KNX_MODULE_KEY,
SUPPORTED_PLATFORMS_UI, SUPPORTED_PLATFORMS_UI,
SUPPORTED_PLATFORMS_YAML, SUPPORTED_PLATFORMS_YAML,
TELEGRAM_LOG_DEFAULT, TELEGRAM_LOG_DEFAULT,
@ -97,6 +98,7 @@ from .websocket import register_panel
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
_KNX_YAML_CONFIG: Final = "knx_yaml_config"
CONFIG_SCHEMA = vol.Schema( CONFIG_SCHEMA = vol.Schema(
{ {
@ -148,7 +150,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Start the KNX integration.""" """Start the KNX integration."""
hass.data[DATA_HASS_CONFIG] = config hass.data[DATA_HASS_CONFIG] = config
if (conf := config.get(DOMAIN)) is not None: if (conf := config.get(DOMAIN)) is not None:
hass.data[DATA_KNX_CONFIG] = dict(conf) hass.data[_KNX_YAML_CONFIG] = dict(conf)
register_knx_services(hass) register_knx_services(hass)
return True return True
@ -156,16 +158,12 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Load a config entry.""" """Load a config entry."""
# `config` is None when reloading the integration # `_KNX_YAML_CONFIG` is only set in async_setup.
# or no `knx` key in configuration.yaml # It's None when reloading the integration or no `knx` key in configuration.yaml
if (config := hass.data.get(DATA_KNX_CONFIG)) is None: config = hass.data.pop(_KNX_YAML_CONFIG, None)
if config is None:
_conf = await async_integration_yaml_config(hass, DOMAIN) _conf = await async_integration_yaml_config(hass, DOMAIN)
if not _conf or DOMAIN not in _conf: if not _conf or DOMAIN not in _conf:
_LOGGER.warning(
"No `knx:` key found in configuration.yaml. See "
"https://www.home-assistant.io/integrations/knx/ "
"for KNX entity configuration documentation"
)
# generate defaults # generate defaults
config = CONFIG_SCHEMA({DOMAIN: {}})[DOMAIN] config = CONFIG_SCHEMA({DOMAIN: {}})[DOMAIN]
else: else:
@ -176,22 +174,22 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
except XKNXException as ex: except XKNXException as ex:
raise ConfigEntryNotReady from ex raise ConfigEntryNotReady from ex
hass.data[DATA_KNX_CONFIG] = config hass.data[KNX_MODULE_KEY] = knx_module
hass.data[DOMAIN] = knx_module
if CONF_KNX_EXPOSE in config: if CONF_KNX_EXPOSE in config:
for expose_config in config[CONF_KNX_EXPOSE]: for expose_config in config[CONF_KNX_EXPOSE]:
knx_module.exposures.append( knx_module.exposures.append(
create_knx_exposure(hass, knx_module.xknx, expose_config) create_knx_exposure(hass, knx_module.xknx, expose_config)
) )
configured_platforms_yaml = {
platform for platform in SUPPORTED_PLATFORMS_YAML if platform in config
}
await hass.config_entries.async_forward_entry_setups( await hass.config_entries.async_forward_entry_setups(
entry, entry,
{ {
Platform.SENSOR, # always forward sensor for system entities (telegram counter, etc.) Platform.SENSOR, # always forward sensor for system entities (telegram counter, etc.)
*SUPPORTED_PLATFORMS_UI, # forward all platforms that support UI entity management *SUPPORTED_PLATFORMS_UI, # forward all platforms that support UI entity management
*{ # forward yaml-only managed platforms on demand *configured_platforms_yaml, # forward yaml-only managed platforms on demand,
platform for platform in SUPPORTED_PLATFORMS_YAML if platform in config
},
}, },
) )
@ -210,30 +208,30 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unloading the KNX platforms.""" """Unloading the KNX platforms."""
# if not loaded directly return knx_module = hass.data.get(KNX_MODULE_KEY)
if not hass.data.get(DOMAIN): if not knx_module:
# if not loaded directly return
return True return True
knx_module: KNXModule = hass.data[DOMAIN]
for exposure in knx_module.exposures: for exposure in knx_module.exposures:
exposure.async_remove() exposure.async_remove()
configured_platforms_yaml = {
platform
for platform in SUPPORTED_PLATFORMS_YAML
if platform in knx_module.config_yaml
}
unload_ok = await hass.config_entries.async_unload_platforms( unload_ok = await hass.config_entries.async_unload_platforms(
entry, entry,
{ {
Platform.SENSOR, # always unload system entities (telegram counter, etc.) Platform.SENSOR, # always unload system entities (telegram counter, etc.)
*SUPPORTED_PLATFORMS_UI, # unload all platforms that support UI entity management *SUPPORTED_PLATFORMS_UI, # unload all platforms that support UI entity management
*{ # unload yaml-only managed platforms if configured *configured_platforms_yaml, # unload yaml-only managed platforms if configured,
platform
for platform in SUPPORTED_PLATFORMS_YAML
if platform in hass.data[DATA_KNX_CONFIG]
},
}, },
) )
if unload_ok: if unload_ok:
await knx_module.stop() await knx_module.stop()
hass.data.pop(DOMAIN) hass.data.pop(DOMAIN)
hass.data.pop(DATA_KNX_CONFIG)
return unload_ok return unload_ok
@ -267,7 +265,7 @@ async def async_remove_config_entry_device(
hass: HomeAssistant, config_entry: ConfigEntry, device_entry: DeviceEntry hass: HomeAssistant, config_entry: ConfigEntry, device_entry: DeviceEntry
) -> bool: ) -> bool:
"""Remove a config entry from a device.""" """Remove a config entry from a device."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
if not device_entry.identifiers.isdisjoint( if not device_entry.identifiers.isdisjoint(
knx_module.interface_device.device_info["identifiers"] knx_module.interface_device.device_info["identifiers"]
): ):
@ -287,7 +285,7 @@ class KNXModule:
) -> None: ) -> None:
"""Initialize KNX module.""" """Initialize KNX module."""
self.hass = hass self.hass = hass
self.config = config self.config_yaml = config
self.connected = False self.connected = False
self.exposures: list[KNXExposeSensor | KNXExposeTime] = [] self.exposures: list[KNXExposeSensor | KNXExposeTime] = []
self.service_exposures: dict[str, KNXExposeSensor | KNXExposeTime] = {} self.service_exposures: dict[str, KNXExposeSensor | KNXExposeTime] = {}
@ -489,7 +487,7 @@ class KNXModule:
def register_event_callback(self) -> TelegramQueue.Callback: def register_event_callback(self) -> TelegramQueue.Callback:
"""Register callback for knx_event within XKNX TelegramQueue.""" """Register callback for knx_event within XKNX TelegramQueue."""
address_filters = [] address_filters = []
for filter_set in self.config[CONF_EVENT]: for filter_set in self.config_yaml[CONF_EVENT]:
_filters = list(map(AddressFilter, filter_set[KNX_ADDRESS])) _filters = list(map(AddressFilter, filter_set[KNX_ADDRESS]))
address_filters.extend(_filters) address_filters.extend(_filters)
if (dpt := filter_set.get(CONF_TYPE)) and ( if (dpt := filter_set.get(CONF_TYPE)) and (

View File

@ -23,7 +23,7 @@ from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import KNXModule from . import KNXModule
from .const import ATTR_COUNTER, ATTR_SOURCE, DATA_KNX_CONFIG, DOMAIN from .const import ATTR_COUNTER, ATTR_SOURCE, KNX_MODULE_KEY
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
from .schema import BinarySensorSchema from .schema import BinarySensorSchema
@ -34,12 +34,11 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the KNX binary sensor platform.""" """Set up the KNX binary sensor platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: ConfigType = hass.data[DATA_KNX_CONFIG] config: list[ConfigType] = knx_module.config_yaml[Platform.BINARY_SENSOR]
async_add_entities( async_add_entities(
KNXBinarySensor(knx_module, entity_config) KNXBinarySensor(knx_module, entity_config) for entity_config in config
for entity_config in config[Platform.BINARY_SENSOR]
) )

View File

@ -12,7 +12,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import KNXModule from . import KNXModule
from .const import CONF_PAYLOAD_LENGTH, DATA_KNX_CONFIG, DOMAIN, KNX_ADDRESS from .const import CONF_PAYLOAD_LENGTH, KNX_ADDRESS, KNX_MODULE_KEY
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
@ -22,13 +22,10 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the KNX binary sensor platform.""" """Set up the KNX binary sensor platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: ConfigType = hass.data[DATA_KNX_CONFIG] config: list[ConfigType] = knx_module.config_yaml[Platform.BUTTON]
async_add_entities( async_add_entities(KNXButton(knx_module, entity_config) for entity_config in config)
KNXButton(knx_module, entity_config)
for entity_config in config[Platform.BUTTON]
)
class KNXButton(KnxYamlEntity, ButtonEntity): class KNXButton(KnxYamlEntity, ButtonEntity):

View File

@ -31,7 +31,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import KNXModule from . import KNXModule
from .const import CONTROLLER_MODES, CURRENT_HVAC_ACTIONS, DATA_KNX_CONFIG, DOMAIN from .const import CONTROLLER_MODES, CURRENT_HVAC_ACTIONS, KNX_MODULE_KEY
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
from .schema import ClimateSchema from .schema import ClimateSchema
@ -45,8 +45,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up climate(s) for KNX platform.""" """Set up climate(s) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.CLIMATE] config: list[ConfigType] = knx_module.config_yaml[Platform.CLIMATE]
async_add_entities( async_add_entities(
KNXClimate(knx_module, entity_config) for entity_config in config KNXClimate(knx_module, entity_config) for entity_config in config

View File

@ -58,6 +58,7 @@ from .const import (
CONF_KNX_TUNNELING_TCP_SECURE, CONF_KNX_TUNNELING_TCP_SECURE,
DEFAULT_ROUTING_IA, DEFAULT_ROUTING_IA,
DOMAIN, DOMAIN,
KNX_MODULE_KEY,
TELEGRAM_LOG_DEFAULT, TELEGRAM_LOG_DEFAULT,
TELEGRAM_LOG_MAX, TELEGRAM_LOG_MAX,
KNXConfigEntryData, KNXConfigEntryData,
@ -182,7 +183,9 @@ class KNXCommonFlow(ABC, ConfigEntryBaseFlow):
CONF_KNX_ROUTING: CONF_KNX_ROUTING.capitalize(), CONF_KNX_ROUTING: CONF_KNX_ROUTING.capitalize(),
} }
if isinstance(self, OptionsFlow) and (knx_module := self.hass.data.get(DOMAIN)): if isinstance(self, OptionsFlow) and (
knx_module := self.hass.data.get(KNX_MODULE_KEY)
):
xknx = knx_module.xknx xknx = knx_module.xknx
else: else:
xknx = XKNX() xknx = XKNX()

View File

@ -4,15 +4,20 @@ from __future__ import annotations
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from enum import Enum from enum import Enum
from typing import Final, TypedDict from typing import TYPE_CHECKING, Final, TypedDict
from xknx.dpt.dpt_20 import HVACControllerMode from xknx.dpt.dpt_20 import HVACControllerMode
from xknx.telegram import Telegram from xknx.telegram import Telegram
from homeassistant.components.climate import HVACAction, HVACMode from homeassistant.components.climate import HVACAction, HVACMode
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.util.hass_dict import HassKey
if TYPE_CHECKING:
from . import KNXModule
DOMAIN: Final = "knx" DOMAIN: Final = "knx"
KNX_MODULE_KEY: HassKey[KNXModule] = HassKey(DOMAIN)
# Address is used for configuration and services by the same functions so the key has to match # Address is used for configuration and services by the same functions so the key has to match
KNX_ADDRESS: Final = "address" KNX_ADDRESS: Final = "address"
@ -68,8 +73,6 @@ CONF_RESPOND_TO_READ: Final = "respond_to_read"
CONF_STATE_ADDRESS: Final = "state_address" CONF_STATE_ADDRESS: Final = "state_address"
CONF_SYNC_STATE: Final = "sync_state" CONF_SYNC_STATE: Final = "sync_state"
# yaml config merged with config entry data
DATA_KNX_CONFIG: Final = "knx_config"
# original hass yaml config # original hass yaml config
DATA_HASS_CONFIG: Final = "knx_hass_config" DATA_HASS_CONFIG: Final = "knx_hass_config"

View File

@ -26,7 +26,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import KNXModule from . import KNXModule
from .const import DATA_KNX_CONFIG, DOMAIN from .const import KNX_MODULE_KEY
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
from .schema import CoverSchema from .schema import CoverSchema
@ -37,8 +37,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up cover(s) for KNX platform.""" """Set up cover(s) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.COVER] config: list[ConfigType] = knx_module.config_yaml[Platform.COVER]
async_add_entities(KNXCover(knx_module, entity_config) for entity_config in config) async_add_entities(KNXCover(knx_module, entity_config) for entity_config in config)

View File

@ -27,9 +27,8 @@ from .const import (
CONF_RESPOND_TO_READ, CONF_RESPOND_TO_READ,
CONF_STATE_ADDRESS, CONF_STATE_ADDRESS,
CONF_SYNC_STATE, CONF_SYNC_STATE,
DATA_KNX_CONFIG,
DOMAIN,
KNX_ADDRESS, KNX_ADDRESS,
KNX_MODULE_KEY,
) )
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
@ -40,8 +39,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up entities for KNX platform.""" """Set up entities for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.DATE] config: list[ConfigType] = knx_module.config_yaml[Platform.DATE]
async_add_entities( async_add_entities(
KNXDateEntity(knx_module, entity_config) for entity_config in config KNXDateEntity(knx_module, entity_config) for entity_config in config

View File

@ -28,9 +28,8 @@ from .const import (
CONF_RESPOND_TO_READ, CONF_RESPOND_TO_READ,
CONF_STATE_ADDRESS, CONF_STATE_ADDRESS,
CONF_SYNC_STATE, CONF_SYNC_STATE,
DATA_KNX_CONFIG,
DOMAIN,
KNX_ADDRESS, KNX_ADDRESS,
KNX_MODULE_KEY,
) )
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
@ -41,8 +40,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up entities for KNX platform.""" """Set up entities for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.DATETIME] config: list[ConfigType] = knx_module.config_yaml[Platform.DATETIME]
async_add_entities( async_add_entities(
KNXDateTimeEntity(knx_module, entity_config) for entity_config in config KNXDateTimeEntity(knx_module, entity_config) for entity_config in config

View File

@ -16,9 +16,8 @@ from homeassistant.helpers import selector
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import KNXModule, trigger from . import trigger
from .const import DOMAIN from .const import DOMAIN, KNX_MODULE_KEY
from .project import KNXProject
from .trigger import ( from .trigger import (
CONF_KNX_DESTINATION, CONF_KNX_DESTINATION,
CONF_KNX_GROUP_VALUE_READ, CONF_KNX_GROUP_VALUE_READ,
@ -47,7 +46,7 @@ async def async_get_triggers(
"""List device triggers for KNX devices.""" """List device triggers for KNX devices."""
triggers = [] triggers = []
knx: KNXModule = hass.data[DOMAIN] knx = hass.data[KNX_MODULE_KEY]
if knx.interface_device.device.id == device_id: if knx.interface_device.device.id == device_id:
# Add trigger for KNX telegrams to interface device # Add trigger for KNX telegrams to interface device
triggers.append( triggers.append(
@ -67,7 +66,7 @@ async def async_get_trigger_capabilities(
hass: HomeAssistant, config: ConfigType hass: HomeAssistant, config: ConfigType
) -> dict[str, vol.Schema]: ) -> dict[str, vol.Schema]:
"""List trigger capabilities.""" """List trigger capabilities."""
project: KNXProject = hass.data[DOMAIN].project project = hass.data[KNX_MODULE_KEY].project
options = [ options = [
selector.SelectOptionDict(value=ga.address, label=f"{ga.address} - {ga.name}") selector.SelectOptionDict(value=ga.address, label=f"{ga.address} - {ga.name}")
for ga in project.group_addresses.values() for ga in project.group_addresses.values()

View File

@ -18,6 +18,7 @@ from .const import (
CONF_KNX_SECURE_DEVICE_AUTHENTICATION, CONF_KNX_SECURE_DEVICE_AUTHENTICATION,
CONF_KNX_SECURE_USER_PASSWORD, CONF_KNX_SECURE_USER_PASSWORD,
DOMAIN, DOMAIN,
KNX_MODULE_KEY,
) )
TO_REDACT = { TO_REDACT = {
@ -33,7 +34,7 @@ async def async_get_config_entry_diagnostics(
) -> dict[str, Any]: ) -> dict[str, Any]:
"""Return diagnostics for a config entry.""" """Return diagnostics for a config entry."""
diag: dict[str, Any] = {} diag: dict[str, Any] = {}
knx_module = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
diag["xknx"] = { diag["xknx"] = {
"version": knx_module.xknx.version, "version": knx_module.xknx.version,
"current_address": str(knx_module.xknx.current_address), "current_address": str(knx_module.xknx.current_address),

View File

@ -20,7 +20,7 @@ from homeassistant.util.percentage import (
from homeassistant.util.scaling import int_states_in_range from homeassistant.util.scaling import int_states_in_range
from . import KNXModule from . import KNXModule
from .const import DATA_KNX_CONFIG, DOMAIN, KNX_ADDRESS from .const import KNX_ADDRESS, KNX_MODULE_KEY
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
from .schema import FanSchema from .schema import FanSchema
@ -33,8 +33,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up fan(s) for KNX platform.""" """Set up fan(s) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.FAN] config: list[ConfigType] = knx_module.config_yaml[Platform.FAN]
async_add_entities(KNXFan(knx_module, entity_config) for entity_config in config) async_add_entities(KNXFan(knx_module, entity_config) for entity_config in config)

View File

@ -29,7 +29,7 @@ from homeassistant.helpers.typing import ConfigType
import homeassistant.util.color as color_util import homeassistant.util.color as color_util
from . import KNXModule from . import KNXModule
from .const import CONF_SYNC_STATE, DATA_KNX_CONFIG, DOMAIN, KNX_ADDRESS, ColorTempModes from .const import CONF_SYNC_STATE, DOMAIN, KNX_ADDRESS, KNX_MODULE_KEY, ColorTempModes
from .knx_entity import KnxUiEntity, KnxUiEntityPlatformController, KnxYamlEntity from .knx_entity import KnxUiEntity, KnxUiEntityPlatformController, KnxYamlEntity
from .schema import LightSchema from .schema import LightSchema
from .storage.const import ( from .storage.const import (
@ -65,7 +65,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up light(s) for KNX platform.""" """Set up light(s) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
platform = async_get_current_platform() platform = async_get_current_platform()
knx_module.config_store.add_platform( knx_module.config_store.add_platform(
platform=Platform.LIGHT, platform=Platform.LIGHT,
@ -77,7 +77,7 @@ async def async_setup_entry(
) )
entities: list[KnxYamlEntity | KnxUiEntity] = [] entities: list[KnxYamlEntity | KnxUiEntity] = []
if yaml_platform_config := hass.data[DATA_KNX_CONFIG].get(Platform.LIGHT): if yaml_platform_config := knx_module.config_yaml.get(Platform.LIGHT):
entities.extend( entities.extend(
KnxYamlLight(knx_module, entity_config) KnxYamlLight(knx_module, entity_config)
for entity_config in yaml_platform_config for entity_config in yaml_platform_config

View File

@ -19,7 +19,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import KNXModule from . import KNXModule
from .const import DATA_KNX_CONFIG, DOMAIN, KNX_ADDRESS from .const import DOMAIN, KNX_ADDRESS, KNX_MODULE_KEY
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
@ -32,8 +32,9 @@ async def async_get_service(
if discovery_info is None: if discovery_info is None:
return None return None
if platform_config := hass.data[DATA_KNX_CONFIG].get(Platform.NOTIFY): knx_module = hass.data[KNX_MODULE_KEY]
xknx: XKNX = hass.data[DOMAIN].xknx if platform_config := knx_module.config_yaml.get(Platform.NOTIFY):
xknx: XKNX = hass.data[KNX_MODULE_KEY].xknx
notification_devices = [ notification_devices = [
_create_notification_instance(xknx, device_config) _create_notification_instance(xknx, device_config)
@ -87,8 +88,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up notify(s) for KNX platform.""" """Set up notify(s) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.NOTIFY] config: list[ConfigType] = knx_module.config_yaml[Platform.NOTIFY]
async_add_entities(KNXNotify(knx_module, entity_config) for entity_config in config) async_add_entities(KNXNotify(knx_module, entity_config) for entity_config in config)

View File

@ -23,13 +23,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import KNXModule from . import KNXModule
from .const import ( from .const import CONF_RESPOND_TO_READ, CONF_STATE_ADDRESS, KNX_ADDRESS, KNX_MODULE_KEY
CONF_RESPOND_TO_READ,
CONF_STATE_ADDRESS,
DATA_KNX_CONFIG,
DOMAIN,
KNX_ADDRESS,
)
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
from .schema import NumberSchema from .schema import NumberSchema
@ -40,8 +34,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up number(s) for KNX platform.""" """Set up number(s) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.NUMBER] config: list[ConfigType] = knx_module.config_yaml[Platform.NUMBER]
async_add_entities(KNXNumber(knx_module, entity_config) for entity_config in config) async_add_entities(KNXNumber(knx_module, entity_config) for entity_config in config)

View File

@ -14,7 +14,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import KNXModule from . import KNXModule
from .const import DATA_KNX_CONFIG, DOMAIN, KNX_ADDRESS from .const import KNX_ADDRESS, KNX_MODULE_KEY
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
from .schema import SceneSchema from .schema import SceneSchema
@ -25,8 +25,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up scene(s) for KNX platform.""" """Set up scene(s) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.SCENE] config: list[ConfigType] = knx_module.config_yaml[Platform.SCENE]
async_add_entities(KNXScene(knx_module, entity_config) for entity_config in config) async_add_entities(KNXScene(knx_module, entity_config) for entity_config in config)

View File

@ -26,9 +26,8 @@ from .const import (
CONF_RESPOND_TO_READ, CONF_RESPOND_TO_READ,
CONF_STATE_ADDRESS, CONF_STATE_ADDRESS,
CONF_SYNC_STATE, CONF_SYNC_STATE,
DATA_KNX_CONFIG,
DOMAIN,
KNX_ADDRESS, KNX_ADDRESS,
KNX_MODULE_KEY,
) )
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
from .schema import SelectSchema from .schema import SelectSchema
@ -40,8 +39,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up select(s) for KNX platform.""" """Set up select(s) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.SELECT] config: list[ConfigType] = knx_module.config_yaml[Platform.SELECT]
async_add_entities(KNXSelect(knx_module, entity_config) for entity_config in config) async_add_entities(KNXSelect(knx_module, entity_config) for entity_config in config)

View File

@ -34,7 +34,7 @@ from homeassistant.helpers.typing import ConfigType, StateType
from homeassistant.util.enum import try_parse_enum from homeassistant.util.enum import try_parse_enum
from . import KNXModule from . import KNXModule
from .const import ATTR_SOURCE, DATA_KNX_CONFIG, DOMAIN from .const import ATTR_SOURCE, KNX_MODULE_KEY
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
from .schema import SensorSchema from .schema import SensorSchema
@ -115,13 +115,13 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up sensor(s) for KNX platform.""" """Set up sensor(s) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
entities: list[SensorEntity] = [] entities: list[SensorEntity] = []
entities.extend( entities.extend(
KNXSystemSensor(knx_module, description) KNXSystemSensor(knx_module, description)
for description in SYSTEM_ENTITY_DESCRIPTIONS for description in SYSTEM_ENTITY_DESCRIPTIONS
) )
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG].get(Platform.SENSOR) config: list[ConfigType] | None = knx_module.config_yaml.get(Platform.SENSOR)
if config: if config:
entities.extend( entities.extend(
KNXSensor(knx_module, entity_config) for entity_config in config KNXSensor(knx_module, entity_config) for entity_config in config

View File

@ -22,6 +22,7 @@ from homeassistant.helpers.service import async_register_admin_service
from .const import ( from .const import (
DOMAIN, DOMAIN,
KNX_ADDRESS, KNX_ADDRESS,
KNX_MODULE_KEY,
SERVICE_KNX_ATTR_PAYLOAD, SERVICE_KNX_ATTR_PAYLOAD,
SERVICE_KNX_ATTR_REMOVE, SERVICE_KNX_ATTR_REMOVE,
SERVICE_KNX_ATTR_RESPONSE, SERVICE_KNX_ATTR_RESPONSE,
@ -85,7 +86,7 @@ def register_knx_services(hass: HomeAssistant) -> None:
def get_knx_module(hass: HomeAssistant) -> KNXModule: def get_knx_module(hass: HomeAssistant) -> KNXModule:
"""Return KNXModule instance.""" """Return KNXModule instance."""
try: try:
return hass.data[DOMAIN] # type: ignore[no-any-return] return hass.data[KNX_MODULE_KEY]
except KeyError as err: except KeyError as err:
raise HomeAssistantError("KNX entry not loaded") from err raise HomeAssistantError("KNX entry not loaded") from err

View File

@ -31,9 +31,9 @@ from .const import (
CONF_INVERT, CONF_INVERT,
CONF_RESPOND_TO_READ, CONF_RESPOND_TO_READ,
CONF_SYNC_STATE, CONF_SYNC_STATE,
DATA_KNX_CONFIG,
DOMAIN, DOMAIN,
KNX_ADDRESS, KNX_ADDRESS,
KNX_MODULE_KEY,
) )
from .knx_entity import KnxUiEntity, KnxUiEntityPlatformController, KnxYamlEntity from .knx_entity import KnxUiEntity, KnxUiEntityPlatformController, KnxYamlEntity
from .schema import SwitchSchema from .schema import SwitchSchema
@ -53,7 +53,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up switch(es) for KNX platform.""" """Set up switch(es) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
platform = async_get_current_platform() platform = async_get_current_platform()
knx_module.config_store.add_platform( knx_module.config_store.add_platform(
platform=Platform.SWITCH, platform=Platform.SWITCH,
@ -65,7 +65,7 @@ async def async_setup_entry(
) )
entities: list[KnxYamlEntity | KnxUiEntity] = [] entities: list[KnxYamlEntity | KnxUiEntity] = []
if yaml_platform_config := hass.data[DATA_KNX_CONFIG].get(Platform.SWITCH): if yaml_platform_config := knx_module.config_yaml.get(Platform.SWITCH):
entities.extend( entities.extend(
KnxYamlSwitch(knx_module, entity_config) KnxYamlSwitch(knx_module, entity_config)
for entity_config in yaml_platform_config for entity_config in yaml_platform_config

View File

@ -23,13 +23,7 @@ from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import KNXModule from . import KNXModule
from .const import ( from .const import CONF_RESPOND_TO_READ, CONF_STATE_ADDRESS, KNX_ADDRESS, KNX_MODULE_KEY
CONF_RESPOND_TO_READ,
CONF_STATE_ADDRESS,
DATA_KNX_CONFIG,
DOMAIN,
KNX_ADDRESS,
)
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
@ -39,8 +33,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up sensor(s) for KNX platform.""" """Set up sensor(s) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.TEXT] config: list[ConfigType] = knx_module.config_yaml[Platform.TEXT]
async_add_entities(KNXText(knx_module, entity_config) for entity_config in config) async_add_entities(KNXText(knx_module, entity_config) for entity_config in config)

View File

@ -27,9 +27,8 @@ from .const import (
CONF_RESPOND_TO_READ, CONF_RESPOND_TO_READ,
CONF_STATE_ADDRESS, CONF_STATE_ADDRESS,
CONF_SYNC_STATE, CONF_SYNC_STATE,
DATA_KNX_CONFIG,
DOMAIN,
KNX_ADDRESS, KNX_ADDRESS,
KNX_MODULE_KEY,
) )
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
@ -40,8 +39,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up entities for KNX platform.""" """Set up entities for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.TIME] config: list[ConfigType] = knx_module.config_yaml[Platform.TIME]
async_add_entities( async_add_entities(
KNXTimeEntity(knx_module, entity_config) for entity_config in config KNXTimeEntity(knx_module, entity_config) for entity_config in config

View File

@ -20,7 +20,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from . import KNXModule from . import KNXModule
from .const import DATA_KNX_CONFIG, DOMAIN from .const import KNX_MODULE_KEY
from .knx_entity import KnxYamlEntity from .knx_entity import KnxYamlEntity
from .schema import WeatherSchema from .schema import WeatherSchema
@ -31,8 +31,8 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up switch(es) for KNX platform.""" """Set up switch(es) for KNX platform."""
knx_module: KNXModule = hass.data[DOMAIN] knx_module = hass.data[KNX_MODULE_KEY]
config: list[ConfigType] = hass.data[DATA_KNX_CONFIG][Platform.WEATHER] config: list[ConfigType] = knx_module.config_yaml[Platform.WEATHER]
async_add_entities( async_add_entities(
KNXWeather(knx_module, entity_config) for entity_config in config KNXWeather(knx_module, entity_config) for entity_config in config

View File

@ -21,7 +21,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.typing import UNDEFINED from homeassistant.helpers.typing import UNDEFINED
from homeassistant.util.ulid import ulid_now from homeassistant.util.ulid import ulid_now
from .const import DOMAIN from .const import DOMAIN, KNX_MODULE_KEY
from .storage.config_store import ConfigStoreException from .storage.config_store import ConfigStoreException
from .storage.const import CONF_DATA from .storage.const import CONF_DATA
from .storage.entity_store_schema import ( from .storage.entity_store_schema import (
@ -38,7 +38,6 @@ from .telegrams import SIGNAL_KNX_TELEGRAM, TelegramDict
if TYPE_CHECKING: if TYPE_CHECKING:
from . import KNXModule from . import KNXModule
URL_BASE: Final = "/knx_static" URL_BASE: Final = "/knx_static"
@ -126,7 +125,7 @@ def provide_knx(
) -> None: ) -> None:
"""Add KNX Module to call function.""" """Add KNX Module to call function."""
try: try:
knx: KNXModule = hass.data[DOMAIN] knx = hass.data[KNX_MODULE_KEY]
except KeyError: except KeyError:
_send_not_loaded_error(connection, msg["id"]) _send_not_loaded_error(connection, msg["id"])
return return
@ -142,7 +141,7 @@ def provide_knx(
) -> None: ) -> None:
"""Add KNX Module to call function.""" """Add KNX Module to call function."""
try: try:
knx: KNXModule = hass.data[DOMAIN] knx = hass.data[KNX_MODULE_KEY]
except KeyError: except KeyError:
_send_not_loaded_error(connection, msg["id"]) _send_not_loaded_error(connection, msg["id"])
return return

View File

@ -6,7 +6,11 @@ import logging
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
import pytest import pytest
from homeassistant.components.knx.const import CONF_PAYLOAD_LENGTH, DOMAIN, KNX_ADDRESS from homeassistant.components.knx.const import (
CONF_PAYLOAD_LENGTH,
KNX_ADDRESS,
KNX_MODULE_KEY,
)
from homeassistant.components.knx.schema import ButtonSchema from homeassistant.components.knx.schema import ButtonSchema
from homeassistant.const import CONF_NAME, CONF_PAYLOAD, CONF_TYPE from homeassistant.const import CONF_NAME, CONF_PAYLOAD, CONF_TYPE
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -134,4 +138,4 @@ async def test_button_invalid(
assert record.levelname == "ERROR" assert record.levelname == "ERROR"
assert "Setup failed for 'knx': Invalid config." in record.message assert "Setup failed for 'knx': Invalid config." in record.message
assert hass.states.get("button.test") is None assert hass.states.get("button.test") is None
assert hass.data.get(DOMAIN) is None assert hass.data.get(KNX_MODULE_KEY) is None

View File

@ -6,8 +6,10 @@ from typing import Any
import pytest import pytest
from homeassistant.components.knx import DOMAIN from homeassistant.components.knx.const import (
from homeassistant.components.knx.const import CONF_KNX_TELEGRAM_LOG_SIZE CONF_KNX_TELEGRAM_LOG_SIZE,
KNX_MODULE_KEY,
)
from homeassistant.components.knx.telegrams import TelegramDict from homeassistant.components.knx.telegrams import TelegramDict
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -76,7 +78,7 @@ async def test_store_telegam_history(
) )
await knx.assert_write("2/2/2", (1, 2, 3, 4)) await knx.assert_write("2/2/2", (1, 2, 3, 4))
assert len(hass.data[DOMAIN].telegrams.recent_telegrams) == 2 assert len(hass.data[KNX_MODULE_KEY].telegrams.recent_telegrams) == 2
with pytest.raises(KeyError): with pytest.raises(KeyError):
hass_storage["knx/telegrams_history.json"] hass_storage["knx/telegrams_history.json"]
@ -93,7 +95,7 @@ async def test_load_telegam_history(
"""Test telegram history restoration.""" """Test telegram history restoration."""
hass_storage["knx/telegrams_history.json"] = {"version": 1, "data": MOCK_TELEGRAMS} hass_storage["knx/telegrams_history.json"] = {"version": 1, "data": MOCK_TELEGRAMS}
await knx.setup_integration({}) await knx.setup_integration({})
loaded_telegrams = hass.data[DOMAIN].telegrams.recent_telegrams loaded_telegrams = hass.data[KNX_MODULE_KEY].telegrams.recent_telegrams
assert assert_telegram_history(loaded_telegrams) assert assert_telegram_history(loaded_telegrams)
# TelegramDict "payload" is a tuple, this shall be restored when loading from JSON # TelegramDict "payload" is a tuple, this shall be restored when loading from JSON
assert isinstance(loaded_telegrams[1]["payload"], tuple) assert isinstance(loaded_telegrams[1]["payload"], tuple)
@ -114,4 +116,4 @@ async def test_remove_telegam_history(
await knx.setup_integration({}, add_entry_to_hass=False) await knx.setup_integration({}, add_entry_to_hass=False)
# Store.async_remove() is mocked by hass_storage - check that data was removed. # Store.async_remove() is mocked by hass_storage - check that data was removed.
assert "knx/telegrams_history.json" not in hass_storage assert "knx/telegrams_history.json" not in hass_storage
assert not hass.data[DOMAIN].telegrams.recent_telegrams assert not hass.data[KNX_MODULE_KEY].telegrams.recent_telegrams

View File

@ -5,8 +5,9 @@ from unittest.mock import patch
import pytest import pytest
from homeassistant.components.knx import DOMAIN, KNX_ADDRESS, SwitchSchema from homeassistant.components.knx.const import KNX_ADDRESS, KNX_MODULE_KEY
from homeassistant.components.knx.project import STORAGE_KEY as KNX_PROJECT_STORAGE_KEY from homeassistant.components.knx.project import STORAGE_KEY as KNX_PROJECT_STORAGE_KEY
from homeassistant.components.knx.schema import SwitchSchema
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -66,7 +67,7 @@ async def test_knx_project_file_process(
await knx.setup_integration({}) await knx.setup_integration({})
client = await hass_ws_client(hass) client = await hass_ws_client(hass)
assert not hass.data[DOMAIN].project.loaded assert not hass.data[KNX_MODULE_KEY].project.loaded
await client.send_json( await client.send_json(
{ {
@ -89,7 +90,7 @@ async def test_knx_project_file_process(
parse_mock.assert_called_once_with() parse_mock.assert_called_once_with()
assert res["success"], res assert res["success"], res
assert hass.data[DOMAIN].project.loaded assert hass.data[KNX_MODULE_KEY].project.loaded
assert hass_storage[KNX_PROJECT_STORAGE_KEY]["data"] == _parse_result assert hass_storage[KNX_PROJECT_STORAGE_KEY]["data"] == _parse_result
@ -101,7 +102,7 @@ async def test_knx_project_file_process_error(
"""Test knx/project_file_process exception handling.""" """Test knx/project_file_process exception handling."""
await knx.setup_integration({}) await knx.setup_integration({})
client = await hass_ws_client(hass) client = await hass_ws_client(hass)
assert not hass.data[DOMAIN].project.loaded assert not hass.data[KNX_MODULE_KEY].project.loaded
await client.send_json( await client.send_json(
{ {
@ -122,7 +123,7 @@ async def test_knx_project_file_process_error(
parse_mock.assert_called_once_with() parse_mock.assert_called_once_with()
assert res["error"], res assert res["error"], res
assert not hass.data[DOMAIN].project.loaded assert not hass.data[KNX_MODULE_KEY].project.loaded
async def test_knx_project_file_remove( async def test_knx_project_file_remove(
@ -136,13 +137,13 @@ async def test_knx_project_file_remove(
await knx.setup_integration({}) await knx.setup_integration({})
assert hass_storage[KNX_PROJECT_STORAGE_KEY] assert hass_storage[KNX_PROJECT_STORAGE_KEY]
client = await hass_ws_client(hass) client = await hass_ws_client(hass)
assert hass.data[DOMAIN].project.loaded assert hass.data[KNX_MODULE_KEY].project.loaded
await client.send_json({"id": 6, "type": "knx/project_file_remove"}) await client.send_json({"id": 6, "type": "knx/project_file_remove"})
res = await client.receive_json() res = await client.receive_json()
assert res["success"], res assert res["success"], res
assert not hass.data[DOMAIN].project.loaded assert not hass.data[KNX_MODULE_KEY].project.loaded
assert not hass_storage.get(KNX_PROJECT_STORAGE_KEY) assert not hass_storage.get(KNX_PROJECT_STORAGE_KEY)
@ -155,7 +156,7 @@ async def test_knx_get_project(
"""Test retrieval of kxnproject from store.""" """Test retrieval of kxnproject from store."""
await knx.setup_integration({}) await knx.setup_integration({})
client = await hass_ws_client(hass) client = await hass_ws_client(hass)
assert hass.data[DOMAIN].project.loaded assert hass.data[KNX_MODULE_KEY].project.loaded
await client.send_json({"id": 3, "type": "knx/get_knx_project"}) await client.send_json({"id": 3, "type": "knx/get_knx_project"})
res = await client.receive_json() res = await client.receive_json()