mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 23:41:48 -05:00
Add MySensors config entry runtime_data (#180993)
This commit is contained in:
@@ -1,36 +1,23 @@
|
||||
"""Connect to a MySensors gateway via pymysensors API."""
|
||||
# pylint: disable=home-assistant-use-runtime-data # Uses legacy hass.data[DOMAIN] pattern
|
||||
|
||||
from collections.abc import Callable, Mapping
|
||||
from collections.abc import Mapping
|
||||
import logging
|
||||
|
||||
from mysensors import BaseAsyncGateway
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import AnyDeviceEntry, DeviceEntry
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import (
|
||||
ATTR_DEVICES,
|
||||
DOMAIN,
|
||||
MYSENSORS_DISCOVERED_NODES,
|
||||
MYSENSORS_GATEWAYS,
|
||||
PLATFORMS,
|
||||
DevId,
|
||||
DiscoveryInfo,
|
||||
SensorType,
|
||||
)
|
||||
from .const import ATTR_DEVICES, DOMAIN, PLATFORMS, DevId, DiscoveryInfo, SensorType
|
||||
from .entity import MySensorsChildEntity
|
||||
from .gateway import finish_setup, gw_stop, setup_gateway
|
||||
from .helpers import get_discovered_dev_ids, remove_gateway_dev_ids, remove_node_dev_ids
|
||||
from .helpers import remove_node_dev_ids
|
||||
from .models import MySensorsConfigEntry, MySensorsData
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DATA_HASS_CONFIG = "hass_config"
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: MySensorsConfigEntry) -> bool:
|
||||
"""Set up an instance of the MySensors integration.
|
||||
|
||||
Every instance has a connection to exactly one Gateway.
|
||||
@@ -41,44 +28,34 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
_LOGGER.error("Gateway setup failed for %s", entry.data)
|
||||
return False
|
||||
|
||||
mysensors_data = hass.data.setdefault(DOMAIN, {})
|
||||
if MYSENSORS_GATEWAYS not in mysensors_data:
|
||||
mysensors_data[MYSENSORS_GATEWAYS] = {}
|
||||
mysensors_data[MYSENSORS_GATEWAYS][entry.entry_id] = gateway
|
||||
entry.runtime_data = MySensorsData(gateway=gateway)
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
await finish_setup(hass, entry, gateway)
|
||||
await finish_setup(hass, entry)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: MySensorsConfigEntry) -> bool:
|
||||
"""Remove an instance of the MySensors integration."""
|
||||
|
||||
gateway: BaseAsyncGateway = hass.data[DOMAIN][MYSENSORS_GATEWAYS][entry.entry_id]
|
||||
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
if not unload_ok:
|
||||
return False
|
||||
|
||||
del hass.data[DOMAIN][MYSENSORS_GATEWAYS][entry.entry_id]
|
||||
hass.data[DOMAIN].pop(MYSENSORS_DISCOVERED_NODES.format(entry.entry_id), None)
|
||||
remove_gateway_dev_ids(hass, entry.entry_id)
|
||||
|
||||
await gw_stop(hass, entry, gateway)
|
||||
await gw_stop(entry)
|
||||
return True
|
||||
|
||||
|
||||
async def async_remove_config_entry_device(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry, device_entry: AnyDeviceEntry
|
||||
hass: HomeAssistant,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
device_entry: AnyDeviceEntry,
|
||||
) -> bool:
|
||||
"""Remove a MySensors config entry from a device."""
|
||||
if not isinstance(device_entry, DeviceEntry):
|
||||
# This integration does not create child devices.
|
||||
return False
|
||||
gateway: BaseAsyncGateway = hass.data[DOMAIN][MYSENSORS_GATEWAYS][
|
||||
config_entry.entry_id
|
||||
]
|
||||
gateway = config_entry.runtime_data.gateway
|
||||
device_id = next(
|
||||
device_id for domain, device_id in device_entry.identifiers if domain == DOMAIN
|
||||
)
|
||||
@@ -87,42 +64,26 @@ async def async_remove_config_entry_device(
|
||||
gateway.tasks.persistence.need_save = True
|
||||
|
||||
# remove node from discovered nodes
|
||||
hass.data[DOMAIN].setdefault(
|
||||
MYSENSORS_DISCOVERED_NODES.format(config_entry.entry_id), set()
|
||||
).discard(node_id)
|
||||
remove_node_dev_ids(hass, config_entry.entry_id, node_id)
|
||||
config_entry.runtime_data.discovered_nodes.discard(node_id)
|
||||
remove_node_dev_ids(config_entry, node_id)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@callback
|
||||
def setup_mysensors_platform(
|
||||
hass: HomeAssistant,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
domain: Platform, # hass platform name
|
||||
discovery_info: DiscoveryInfo,
|
||||
device_class: type[MySensorsChildEntity]
|
||||
| Mapping[SensorType, type[MySensorsChildEntity]],
|
||||
device_args: (
|
||||
tuple | None
|
||||
) = None, # extra arguments that will be given to the entity constructor
|
||||
async_add_entities: Callable | None = None,
|
||||
) -> list[MySensorsChildEntity] | None:
|
||||
"""Set up a MySensors platform.
|
||||
|
||||
Sets up a bunch of instances of a single platform that is supported by this
|
||||
integration.
|
||||
|
||||
The function is given a list of device ids, each one describing an instance
|
||||
to set up. The function is also given a class.
|
||||
|
||||
A new instance of the class is created for every device id, and the device
|
||||
id is given to the constructor of the class.
|
||||
"""
|
||||
if device_args is None:
|
||||
device_args = ()
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up entities for newly discovered devices on a MySensors platform."""
|
||||
new_devices: list[MySensorsChildEntity] = []
|
||||
new_dev_ids: list[DevId] = discovery_info[ATTR_DEVICES]
|
||||
dev_ids = get_discovered_dev_ids(hass, domain)
|
||||
dev_ids = config_entry.runtime_data.discovered_dev_ids[domain]
|
||||
gateway = config_entry.runtime_data.gateway
|
||||
for dev_id in new_dev_ids:
|
||||
if dev_id in dev_ids:
|
||||
_LOGGER.debug(
|
||||
@@ -131,8 +92,7 @@ def setup_mysensors_platform(
|
||||
domain,
|
||||
)
|
||||
continue
|
||||
gateway_id, node_id, child_id, value_type = dev_id
|
||||
gateway: BaseAsyncGateway = hass.data[DOMAIN][MYSENSORS_GATEWAYS][gateway_id]
|
||||
_gateway_id, node_id, child_id, value_type = dev_id
|
||||
|
||||
if isinstance(device_class, dict):
|
||||
child = gateway.sensors[node_id].children[child_id]
|
||||
@@ -141,11 +101,10 @@ def setup_mysensors_platform(
|
||||
else:
|
||||
device_class_copy = device_class
|
||||
|
||||
args_copy = (*device_args, gateway_id, gateway, node_id, child_id, value_type)
|
||||
dev_ids.add(dev_id)
|
||||
new_devices.append(device_class_copy(*args_copy))
|
||||
new_devices.append(
|
||||
device_class_copy(config_entry, node_id, child_id, value_type)
|
||||
)
|
||||
if new_devices:
|
||||
_LOGGER.debug("Adding new devices: %s", new_devices)
|
||||
if async_add_entities is not None:
|
||||
async_add_entities(new_devices)
|
||||
return new_devices
|
||||
async_add_entities(new_devices)
|
||||
|
||||
@@ -9,7 +9,6 @@ from homeassistant.components.binary_sensor import (
|
||||
BinarySensorEntity,
|
||||
BinarySensorEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
@@ -18,6 +17,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from . import setup_mysensors_platform
|
||||
from .const import MYSENSORS_DISCOVERY, DiscoveryInfo
|
||||
from .entity import MySensorsChildEntity
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -67,7 +67,7 @@ SENSORS: dict[str, MySensorsBinarySensorDescription] = {
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
|
||||
@@ -76,11 +76,11 @@ async def async_setup_entry(
|
||||
def async_discover(discovery_info: DiscoveryInfo) -> None:
|
||||
"""Discover and add a MySensors binary_sensor."""
|
||||
setup_mysensors_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
Platform.BINARY_SENSOR,
|
||||
discovery_info,
|
||||
MySensorsBinarySensor,
|
||||
async_add_entities=async_add_entities,
|
||||
async_add_entities,
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(
|
||||
|
||||
@@ -9,7 +9,6 @@ from homeassistant.components.climate import (
|
||||
ClimateEntityFeature,
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_TEMPERATURE, Platform, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
@@ -19,6 +18,7 @@ from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||
from . import setup_mysensors_platform
|
||||
from .const import MYSENSORS_DISCOVERY, DiscoveryInfo
|
||||
from .entity import MySensorsChildEntity
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
DICT_HA_TO_MYS = {
|
||||
HVACMode.AUTO: "AutoChangeOver",
|
||||
@@ -39,7 +39,7 @@ OPERATION_LIST = [HVACMode.OFF, HVACMode.AUTO, HVACMode.COOL, HVACMode.HEAT]
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
|
||||
@@ -47,11 +47,11 @@ async def async_setup_entry(
|
||||
async def async_discover(discovery_info: DiscoveryInfo) -> None:
|
||||
"""Discover and add a MySensors climate."""
|
||||
setup_mysensors_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
Platform.CLIMATE,
|
||||
discovery_info,
|
||||
MySensorsHVAC,
|
||||
async_add_entities=async_add_entities,
|
||||
async_add_entities,
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(
|
||||
|
||||
@@ -23,10 +23,6 @@ CONF_GATEWAY_TYPE_TCP: ConfGatewayType = "TCP"
|
||||
CONF_GATEWAY_TYPE_MQTT: ConfGatewayType = "MQTT"
|
||||
|
||||
DOMAIN: Final = "mysensors"
|
||||
MYSENSORS_GATEWAY_START_TASK: str = "mysensors_gateway_start_task_{}"
|
||||
MYSENSORS_GATEWAYS: Final = "mysensors_gateways"
|
||||
MYSENSORS_DISCOVERED_NODES: Final = "mysensors_discovered_nodes_{}"
|
||||
MYSENSORS_DISCOVERED_DEV_IDS: Final = "mysensors_discovered_dev_ids_{}"
|
||||
PLATFORM: Final = "platform"
|
||||
SCHEMA: Final = "schema"
|
||||
CHILD_CALLBACK: str = "mysensors_child_callback_{}_{}_{}_{}"
|
||||
|
||||
@@ -8,7 +8,6 @@ from homeassistant.components.cover import (
|
||||
ATTR_TILT_POSITION,
|
||||
CoverEntity,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_ON, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
@@ -17,6 +16,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from . import setup_mysensors_platform
|
||||
from .const import MYSENSORS_DISCOVERY, DiscoveryInfo
|
||||
from .entity import MySensorsChildEntity
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
|
||||
@unique
|
||||
@@ -31,7 +31,7 @@ class CoverState(Enum):
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
|
||||
@@ -39,11 +39,11 @@ async def async_setup_entry(
|
||||
async def async_discover(discovery_info: DiscoveryInfo) -> None:
|
||||
"""Discover and add a MySensors cover."""
|
||||
setup_mysensors_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
Platform.COVER,
|
||||
discovery_info,
|
||||
MySensorsCover,
|
||||
async_add_entities=async_add_entities,
|
||||
async_add_entities,
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from typing import override
|
||||
|
||||
from homeassistant.components.device_tracker import TrackerEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
@@ -12,11 +11,12 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from . import setup_mysensors_platform
|
||||
from .const import MYSENSORS_DISCOVERY, DiscoveryInfo
|
||||
from .entity import MySensorsChildEntity
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
|
||||
@@ -25,11 +25,11 @@ async def async_setup_entry(
|
||||
def async_discover(discovery_info: DiscoveryInfo) -> None:
|
||||
"""Discover and add a MySensors device tracker."""
|
||||
setup_mysensors_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
Platform.DEVICE_TRACKER,
|
||||
discovery_info,
|
||||
MySensorsDeviceTracker,
|
||||
async_add_entities=async_add_entities,
|
||||
async_add_entities,
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(
|
||||
|
||||
@@ -15,6 +15,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import CHILD_CALLBACK, DOMAIN, NODE_CALLBACK, UPDATE_DELAY, DevId, GatewayId
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -30,12 +31,11 @@ class MySensorNodeEntity(Entity):
|
||||
|
||||
hass: HomeAssistant
|
||||
|
||||
def __init__(
|
||||
self, gateway_id: GatewayId, gateway: BaseAsyncGateway, node_id: int
|
||||
) -> None:
|
||||
def __init__(self, config_entry: MySensorsConfigEntry, node_id: int) -> None:
|
||||
"""Set up the MySensors node entity."""
|
||||
self.gateway_id: GatewayId = gateway_id
|
||||
self.gateway: BaseAsyncGateway = gateway
|
||||
self.config_entry = config_entry
|
||||
self.gateway_id: GatewayId = config_entry.entry_id
|
||||
self.gateway: BaseAsyncGateway = config_entry.runtime_data.gateway
|
||||
self.node_id: int = node_id
|
||||
self._debouncer: Debouncer | None = None
|
||||
|
||||
@@ -127,14 +127,13 @@ class MySensorsChildEntity(MySensorNodeEntity):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
gateway_id: GatewayId,
|
||||
gateway: BaseAsyncGateway,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
node_id: int,
|
||||
child_id: int,
|
||||
value_type: int,
|
||||
) -> None:
|
||||
"""Set up the MySensors child entity."""
|
||||
super().__init__(gateway_id, gateway, node_id)
|
||||
super().__init__(config_entry, node_id)
|
||||
self.child_id: int = child_id
|
||||
# value_type as int. string variant can be looked up in gateway consts
|
||||
self.value_type: int = value_type
|
||||
@@ -181,8 +180,7 @@ class MySensorsChildEntity(MySensorNodeEntity):
|
||||
"""Return entity and device specific state attributes."""
|
||||
attr = super().extra_state_attributes
|
||||
|
||||
assert self.platform.config_entry
|
||||
attr[ATTR_DEVICE] = self.platform.config_entry.data[CONF_DEVICE]
|
||||
attr[ATTR_DEVICE] = self.config_entry.data[CONF_DEVICE]
|
||||
|
||||
attr[ATTR_CHILD_ID] = self.child_id
|
||||
attr[ATTR_DESCRIPTION] = self._child.description
|
||||
|
||||
@@ -17,7 +17,6 @@ from homeassistant.components.mqtt import (
|
||||
async_publish,
|
||||
async_subscribe,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_DEVICE, EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import Event, HomeAssistant, callback
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
@@ -36,10 +35,7 @@ from .const import (
|
||||
CONF_TOPIC_IN_PREFIX,
|
||||
CONF_TOPIC_OUT_PREFIX,
|
||||
CONF_VERSION,
|
||||
DOMAIN,
|
||||
MYSENSORS_GATEWAY_START_TASK,
|
||||
ConfGatewayType,
|
||||
GatewayId,
|
||||
)
|
||||
from .handler import HANDLERS
|
||||
from .helpers import (
|
||||
@@ -48,6 +44,7 @@ from .helpers import (
|
||||
validate_child,
|
||||
validate_node,
|
||||
)
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -123,7 +120,7 @@ async def try_connect(
|
||||
|
||||
|
||||
async def setup_gateway(
|
||||
hass: HomeAssistant, entry: ConfigEntry
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry
|
||||
) -> BaseAsyncGateway | None:
|
||||
"""Set up the Gateway for the given ConfigEntry."""
|
||||
|
||||
@@ -132,7 +129,7 @@ async def setup_gateway(
|
||||
gateway_type=entry.data[CONF_GATEWAY_TYPE],
|
||||
device=entry.data[CONF_DEVICE],
|
||||
version=entry.data[CONF_VERSION],
|
||||
event_callback=_gw_callback_factory(hass, entry.entry_id),
|
||||
event_callback=_gw_callback_factory(hass, entry),
|
||||
persistence_file=entry.data.get(
|
||||
CONF_PERSISTENCE_FILE, f"mysensors_{entry.entry_id}.json"
|
||||
),
|
||||
@@ -231,23 +228,22 @@ async def _get_gateway(
|
||||
return gateway
|
||||
|
||||
|
||||
async def finish_setup(
|
||||
hass: HomeAssistant, entry: ConfigEntry, gateway: BaseAsyncGateway
|
||||
) -> None:
|
||||
async def finish_setup(hass: HomeAssistant, entry: MySensorsConfigEntry) -> None:
|
||||
"""Load any persistent devices and platforms and start gateway."""
|
||||
await _discover_persistent_devices(hass, entry, gateway)
|
||||
await _gw_start(hass, entry, gateway)
|
||||
await _discover_persistent_devices(hass, entry)
|
||||
await _gw_start(hass, entry)
|
||||
|
||||
|
||||
async def _discover_persistent_devices(
|
||||
hass: HomeAssistant, entry: ConfigEntry, gateway: BaseAsyncGateway
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry
|
||||
) -> None:
|
||||
"""Discover platforms for devices loaded via persistence file."""
|
||||
gateway = entry.runtime_data.gateway
|
||||
new_devices = defaultdict(list)
|
||||
for node_id in gateway.sensors:
|
||||
if not validate_node(gateway, node_id):
|
||||
continue
|
||||
discover_mysensors_node(hass, entry.entry_id, node_id)
|
||||
discover_mysensors_node(hass, entry, node_id)
|
||||
node: Sensor = gateway.sensors[node_id]
|
||||
for child in node.children.values(): # child is of type ChildSensor
|
||||
validated = validate_child(entry.entry_id, gateway, node_id, child)
|
||||
@@ -258,22 +254,18 @@ async def _discover_persistent_devices(
|
||||
discover_mysensors_platform(hass, entry.entry_id, platform, dev_ids)
|
||||
|
||||
|
||||
async def gw_stop(
|
||||
hass: HomeAssistant, entry: ConfigEntry, gateway: BaseAsyncGateway
|
||||
) -> None:
|
||||
async def gw_stop(entry: MySensorsConfigEntry) -> None:
|
||||
"""Stop the gateway."""
|
||||
connect_task = hass.data[DOMAIN].pop(
|
||||
MYSENSORS_GATEWAY_START_TASK.format(entry.entry_id), None
|
||||
)
|
||||
connect_task = entry.runtime_data.gateway_start_task
|
||||
entry.runtime_data.gateway_start_task = None
|
||||
if connect_task is not None and not connect_task.done():
|
||||
connect_task.cancel()
|
||||
await gateway.stop()
|
||||
await entry.runtime_data.gateway.stop()
|
||||
|
||||
|
||||
async def _gw_start(
|
||||
hass: HomeAssistant, entry: ConfigEntry, gateway: BaseAsyncGateway
|
||||
) -> None:
|
||||
async def _gw_start(hass: HomeAssistant, entry: MySensorsConfigEntry) -> None:
|
||||
"""Start the gateway."""
|
||||
gateway = entry.runtime_data.gateway
|
||||
gateway_ready = asyncio.Event()
|
||||
|
||||
def gateway_connected(_: BaseAsyncGateway) -> None:
|
||||
@@ -282,15 +274,11 @@ async def _gw_start(
|
||||
|
||||
gateway.on_conn_made = gateway_connected
|
||||
# Don't use hass.async_create_task to avoid holding up setup indefinitely.
|
||||
# Uses legacy hass.data[DOMAIN] pattern
|
||||
# pylint: disable-next=home-assistant-use-runtime-data
|
||||
hass.data[DOMAIN][MYSENSORS_GATEWAY_START_TASK.format(entry.entry_id)] = (
|
||||
asyncio.create_task(gateway.start())
|
||||
) # store the connect task so it can be cancelled in gw_stop
|
||||
entry.runtime_data.gateway_start_task = asyncio.create_task(gateway.start())
|
||||
|
||||
async def stop_this_gw(_: Event) -> None:
|
||||
"""Stop the gateway."""
|
||||
await gw_stop(hass, entry, gateway)
|
||||
await gw_stop(entry)
|
||||
|
||||
entry.async_on_unload(
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_this_gw),
|
||||
@@ -311,7 +299,7 @@ async def _gw_start(
|
||||
|
||||
|
||||
def _gw_callback_factory(
|
||||
hass: HomeAssistant, gateway_id: GatewayId
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry
|
||||
) -> Callable[[Message], None]:
|
||||
"""Return a new callback for the gateway."""
|
||||
|
||||
@@ -330,6 +318,6 @@ def _gw_callback_factory(
|
||||
if msg_handler is None:
|
||||
return
|
||||
|
||||
msg_handler(hass, gateway_id, msg)
|
||||
msg_handler(hass, entry, msg)
|
||||
|
||||
return mysensors_callback
|
||||
|
||||
@@ -10,84 +10,90 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.util import decorator
|
||||
|
||||
from .const import CHILD_CALLBACK, NODE_CALLBACK, DevId, GatewayId
|
||||
from .const import CHILD_CALLBACK, NODE_CALLBACK, DevId
|
||||
from .helpers import (
|
||||
discover_mysensors_node,
|
||||
discover_mysensors_platform,
|
||||
get_discovered_dev_ids,
|
||||
validate_set_msg,
|
||||
)
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
HANDLERS: decorator.Registry[
|
||||
str, Callable[[HomeAssistant, GatewayId, Message], None]
|
||||
str, Callable[[HomeAssistant, MySensorsConfigEntry, Message], None]
|
||||
] = decorator.Registry()
|
||||
|
||||
|
||||
@HANDLERS.register("set")
|
||||
@callback
|
||||
def handle_set(hass: HomeAssistant, gateway_id: GatewayId, msg: Message) -> None:
|
||||
def handle_set(hass: HomeAssistant, entry: MySensorsConfigEntry, msg: Message) -> None:
|
||||
"""Handle a mysensors set message."""
|
||||
validated = validate_set_msg(gateway_id, msg)
|
||||
_handle_child_update(hass, gateway_id, validated)
|
||||
validated = validate_set_msg(entry.entry_id, msg)
|
||||
_handle_child_update(hass, entry, validated)
|
||||
|
||||
|
||||
@HANDLERS.register("internal")
|
||||
@callback
|
||||
def handle_internal(hass: HomeAssistant, gateway_id: GatewayId, msg: Message) -> None:
|
||||
def handle_internal(
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry, msg: Message
|
||||
) -> None:
|
||||
"""Handle a mysensors internal message."""
|
||||
internal = msg.gateway.const.Internal(msg.sub_type)
|
||||
if (handler := HANDLERS.get(internal.name)) is None:
|
||||
return
|
||||
handler(hass, gateway_id, msg)
|
||||
handler(hass, entry, msg)
|
||||
|
||||
|
||||
@HANDLERS.register("I_BATTERY_LEVEL")
|
||||
@callback
|
||||
def handle_battery_level(
|
||||
hass: HomeAssistant, gateway_id: GatewayId, msg: Message
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry, msg: Message
|
||||
) -> None:
|
||||
"""Handle an internal battery level message."""
|
||||
_handle_node_update(hass, gateway_id, msg)
|
||||
_handle_node_update(hass, entry, msg)
|
||||
|
||||
|
||||
@HANDLERS.register("I_HEARTBEAT_RESPONSE")
|
||||
@callback
|
||||
def handle_heartbeat(hass: HomeAssistant, gateway_id: GatewayId, msg: Message) -> None:
|
||||
def handle_heartbeat(
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry, msg: Message
|
||||
) -> None:
|
||||
"""Handle an heartbeat."""
|
||||
_handle_node_update(hass, gateway_id, msg)
|
||||
_handle_node_update(hass, entry, msg)
|
||||
|
||||
|
||||
@HANDLERS.register("I_SKETCH_NAME")
|
||||
@callback
|
||||
def handle_sketch_name(
|
||||
hass: HomeAssistant, gateway_id: GatewayId, msg: Message
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry, msg: Message
|
||||
) -> None:
|
||||
"""Handle an internal sketch name message."""
|
||||
_handle_node_update(hass, gateway_id, msg)
|
||||
_handle_node_update(hass, entry, msg)
|
||||
|
||||
|
||||
@HANDLERS.register("I_SKETCH_VERSION")
|
||||
@callback
|
||||
def handle_sketch_version(
|
||||
hass: HomeAssistant, gateway_id: GatewayId, msg: Message
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry, msg: Message
|
||||
) -> None:
|
||||
"""Handle an internal sketch version message."""
|
||||
_handle_node_update(hass, gateway_id, msg)
|
||||
_handle_node_update(hass, entry, msg)
|
||||
|
||||
|
||||
@HANDLERS.register("presentation")
|
||||
@callback
|
||||
def handle_presentation(
|
||||
hass: HomeAssistant, gateway_id: GatewayId, msg: Message
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry, msg: Message
|
||||
) -> None:
|
||||
"""Handle an internal presentation message."""
|
||||
if msg.child_id == SYSTEM_CHILD_ID:
|
||||
discover_mysensors_node(hass, gateway_id, msg.node_id)
|
||||
discover_mysensors_node(hass, entry, msg.node_id)
|
||||
|
||||
|
||||
@callback
|
||||
def _handle_child_update(
|
||||
hass: HomeAssistant, gateway_id: GatewayId, validated: dict[Platform, list[DevId]]
|
||||
hass: HomeAssistant,
|
||||
entry: MySensorsConfigEntry,
|
||||
validated: dict[Platform, list[DevId]],
|
||||
) -> None:
|
||||
"""Handle a child update."""
|
||||
signals: list[str] = []
|
||||
@@ -95,7 +101,7 @@ def _handle_child_update(
|
||||
# Update all platforms for the device via dispatcher.
|
||||
# Add/update entity for validated children.
|
||||
for platform, dev_ids in validated.items():
|
||||
discovered_dev_ids = get_discovered_dev_ids(hass, platform)
|
||||
discovered_dev_ids = entry.runtime_data.discovered_dev_ids[platform]
|
||||
new_dev_ids: list[DevId] = []
|
||||
for dev_id in dev_ids:
|
||||
if dev_id in discovered_dev_ids:
|
||||
@@ -103,7 +109,7 @@ def _handle_child_update(
|
||||
else:
|
||||
new_dev_ids.append(dev_id)
|
||||
if new_dev_ids:
|
||||
discover_mysensors_platform(hass, gateway_id, platform, new_dev_ids)
|
||||
discover_mysensors_platform(hass, entry.entry_id, platform, new_dev_ids)
|
||||
for signal in set(signals):
|
||||
# Only one signal per device is needed.
|
||||
# A device can have multiple platforms, ie multiple schemas.
|
||||
@@ -112,8 +118,8 @@ def _handle_child_update(
|
||||
|
||||
@callback
|
||||
def _handle_node_update(
|
||||
hass: HomeAssistant, gateway_id: GatewayId, msg: Message
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry, msg: Message
|
||||
) -> None:
|
||||
"""Handle a node update."""
|
||||
signal = NODE_CALLBACK.format(gateway_id, msg.node_id)
|
||||
signal = NODE_CALLBACK.format(entry.entry_id, msg.node_id)
|
||||
async_dispatcher_send(hass, signal)
|
||||
|
||||
@@ -22,17 +22,15 @@ from .const import (
|
||||
ATTR_NODE_ID,
|
||||
DOMAIN,
|
||||
FLAT_PLATFORM_TYPES,
|
||||
MYSENSORS_DISCOVERED_DEV_IDS,
|
||||
MYSENSORS_DISCOVERED_NODES,
|
||||
MYSENSORS_DISCOVERY,
|
||||
MYSENSORS_NODE_DISCOVERY,
|
||||
PLATFORM_TYPES,
|
||||
TYPE_TO_PLATFORMS,
|
||||
DevId,
|
||||
GatewayId,
|
||||
SensorType,
|
||||
ValueType,
|
||||
)
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
SCHEMAS: Registry[
|
||||
@@ -59,61 +57,29 @@ def discover_mysensors_platform(
|
||||
|
||||
@callback
|
||||
def discover_mysensors_node(
|
||||
hass: HomeAssistant, gateway_id: GatewayId, node_id: int
|
||||
hass: HomeAssistant, entry: MySensorsConfigEntry, node_id: int
|
||||
) -> None:
|
||||
"""Discover a MySensors node."""
|
||||
# Uses legacy hass.data[DOMAIN] pattern
|
||||
# pylint: disable-next=home-assistant-use-runtime-data
|
||||
discovered_nodes = hass.data[DOMAIN].setdefault(
|
||||
MYSENSORS_DISCOVERED_NODES.format(gateway_id), set()
|
||||
)
|
||||
discovered_nodes = entry.runtime_data.discovered_nodes
|
||||
|
||||
if node_id not in discovered_nodes:
|
||||
discovered_nodes.add(node_id)
|
||||
async_dispatcher_send(
|
||||
hass,
|
||||
MYSENSORS_NODE_DISCOVERY.format(gateway_id),
|
||||
MYSENSORS_NODE_DISCOVERY.format(entry.entry_id),
|
||||
{
|
||||
ATTR_GATEWAY_ID: gateway_id,
|
||||
ATTR_GATEWAY_ID: entry.entry_id,
|
||||
ATTR_NODE_ID: node_id,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def get_discovered_dev_ids(hass: HomeAssistant, platform: Platform) -> set[DevId]:
|
||||
"""Return the dev ids that have been set up for a hass platform."""
|
||||
# Uses legacy hass.data[DOMAIN] pattern
|
||||
# pylint: disable-next=home-assistant-use-runtime-data
|
||||
dev_ids = hass.data[DOMAIN].setdefault(
|
||||
MYSENSORS_DISCOVERED_DEV_IDS.format(platform), set()
|
||||
)
|
||||
return cast(set[DevId], dev_ids)
|
||||
|
||||
|
||||
@callback
|
||||
def remove_gateway_dev_ids(hass: HomeAssistant, gateway_id: GatewayId) -> None:
|
||||
"""Remove all discovered dev ids belonging to a gateway."""
|
||||
for platform in PLATFORM_TYPES:
|
||||
dev_ids = get_discovered_dev_ids(hass, platform)
|
||||
dev_ids.difference_update(
|
||||
{dev_id for dev_id in dev_ids if dev_id[0] == gateway_id}
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def remove_node_dev_ids(
|
||||
hass: HomeAssistant, gateway_id: GatewayId, node_id: int
|
||||
) -> None:
|
||||
def remove_node_dev_ids(entry: MySensorsConfigEntry, node_id: int) -> None:
|
||||
"""Remove all discovered dev ids belonging to a node."""
|
||||
for platform in PLATFORM_TYPES:
|
||||
dev_ids = get_discovered_dev_ids(hass, platform)
|
||||
for dev_ids in entry.runtime_data.discovered_dev_ids.values():
|
||||
dev_ids.difference_update(
|
||||
{
|
||||
dev_id
|
||||
for dev_id in dev_ids
|
||||
if dev_id[0] == gateway_id and dev_id[1] == node_id
|
||||
}
|
||||
{dev_id for dev_id in dev_ids if dev_id[1] == node_id}
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ from homeassistant.components.light import (
|
||||
ColorMode,
|
||||
LightEntity,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_ON, Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
@@ -19,11 +18,12 @@ from homeassistant.util.color import rgb_hex_to_rgb_list
|
||||
from . import setup_mysensors_platform
|
||||
from .const import MYSENSORS_DISCOVERY, DiscoveryInfo, SensorType
|
||||
from .entity import MySensorsChildEntity
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
|
||||
@@ -36,11 +36,11 @@ async def async_setup_entry(
|
||||
async def async_discover(discovery_info: DiscoveryInfo) -> None:
|
||||
"""Discover and add a MySensors light."""
|
||||
setup_mysensors_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
Platform.LIGHT,
|
||||
discovery_info,
|
||||
device_class_map,
|
||||
async_add_entities=async_add_entities,
|
||||
async_add_entities,
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
"""Models for the MySensors integration."""
|
||||
|
||||
from asyncio import Task
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from mysensors import BaseAsyncGateway
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
|
||||
from .const import DevId
|
||||
|
||||
type MySensorsConfigEntry = ConfigEntry[MySensorsData]
|
||||
|
||||
|
||||
@dataclass
|
||||
class MySensorsData:
|
||||
"""Runtime data for a MySensors gateway."""
|
||||
|
||||
gateway: BaseAsyncGateway
|
||||
discovered_nodes: set[int] = field(default_factory=set)
|
||||
discovered_dev_ids: defaultdict[Platform, set[DevId]] = field(
|
||||
default_factory=lambda: defaultdict(set)
|
||||
)
|
||||
gateway_start_task: Task[None] | None = None
|
||||
@@ -8,7 +8,6 @@ from homeassistant.components.remote import (
|
||||
RemoteEntity,
|
||||
RemoteEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
@@ -17,11 +16,12 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from . import setup_mysensors_platform
|
||||
from .const import MYSENSORS_DISCOVERY, DiscoveryInfo
|
||||
from .entity import MySensorsChildEntity
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
|
||||
@@ -30,11 +30,11 @@ async def async_setup_entry(
|
||||
def async_discover(discovery_info: DiscoveryInfo) -> None:
|
||||
"""Discover and add a MySensors remote."""
|
||||
setup_mysensors_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
Platform.REMOTE,
|
||||
discovery_info,
|
||||
MySensorsRemote,
|
||||
async_add_entities=async_add_entities,
|
||||
async_add_entities,
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from typing import Any, override
|
||||
|
||||
from awesomeversion import AwesomeVersion
|
||||
from mysensors import BaseAsyncGateway
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
@@ -11,7 +10,6 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
DEGREE,
|
||||
LIGHT_LUX,
|
||||
@@ -38,16 +36,14 @@ from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||
|
||||
from . import setup_mysensors_platform
|
||||
from .const import (
|
||||
ATTR_GATEWAY_ID,
|
||||
ATTR_NODE_ID,
|
||||
DOMAIN,
|
||||
MYSENSORS_DISCOVERY,
|
||||
MYSENSORS_GATEWAYS,
|
||||
MYSENSORS_NODE_DISCOVERY,
|
||||
DiscoveryInfo,
|
||||
NodeDiscoveryInfo,
|
||||
)
|
||||
from .entity import MySensorNodeEntity, MySensorsChildEntity
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
SENSORS: dict[str, SensorEntityDescription] = {
|
||||
"V_TEMP": SensorEntityDescription(
|
||||
@@ -208,7 +204,7 @@ SENSORS: dict[str, SensorEntityDescription] = {
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
|
||||
@@ -216,22 +212,18 @@ async def async_setup_entry(
|
||||
async def async_discover(discovery_info: DiscoveryInfo) -> None:
|
||||
"""Discover and add a MySensors sensor."""
|
||||
setup_mysensors_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
Platform.SENSOR,
|
||||
discovery_info,
|
||||
MySensorsSensor,
|
||||
async_add_entities=async_add_entities,
|
||||
async_add_entities,
|
||||
)
|
||||
|
||||
@callback
|
||||
def async_node_discover(discovery_info: NodeDiscoveryInfo) -> None:
|
||||
"""Add battery sensor for each MySensors node."""
|
||||
gateway_id = discovery_info[ATTR_GATEWAY_ID]
|
||||
node_id = discovery_info[ATTR_NODE_ID]
|
||||
# Uses legacy hass.data[DOMAIN] pattern
|
||||
# pylint: disable-next=home-assistant-use-runtime-data
|
||||
gateway: BaseAsyncGateway = hass.data[DOMAIN][MYSENSORS_GATEWAYS][gateway_id]
|
||||
async_add_entities([MyBatterySensor(gateway_id, gateway, node_id)])
|
||||
async_add_entities([MyBatterySensor(config_entry, node_id)])
|
||||
|
||||
config_entry.async_on_unload(
|
||||
async_dispatcher_connect(
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from typing import Any, override
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_ON, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
@@ -12,11 +11,12 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from . import setup_mysensors_platform
|
||||
from .const import MYSENSORS_DISCOVERY, DiscoveryInfo, SensorType
|
||||
from .entity import MySensorsChildEntity
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
|
||||
@@ -38,11 +38,11 @@ async def async_setup_entry(
|
||||
async def async_discover(discovery_info: DiscoveryInfo) -> None:
|
||||
"""Discover and add a MySensors switch."""
|
||||
setup_mysensors_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
Platform.SWITCH,
|
||||
discovery_info,
|
||||
device_class_map,
|
||||
async_add_entities=async_add_entities,
|
||||
async_add_entities,
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from typing import override
|
||||
|
||||
from homeassistant.components.text import TextEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
@@ -12,11 +11,12 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from . import setup_mysensors_platform
|
||||
from .const import MYSENSORS_DISCOVERY, DiscoveryInfo
|
||||
from .entity import MySensorsChildEntity
|
||||
from .models import MySensorsConfigEntry
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: MySensorsConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up this platform for a specific ConfigEntry(==Gateway)."""
|
||||
@@ -25,11 +25,11 @@ async def async_setup_entry(
|
||||
def async_discover(discovery_info: DiscoveryInfo) -> None:
|
||||
"""Discover and add a MySensors text entity."""
|
||||
setup_mysensors_platform(
|
||||
hass,
|
||||
config_entry,
|
||||
Platform.TEXT,
|
||||
discovery_info,
|
||||
MySensorsText,
|
||||
async_add_entities=async_add_entities,
|
||||
async_add_entities,
|
||||
)
|
||||
|
||||
config_entry.async_on_unload(
|
||||
|
||||
Reference in New Issue
Block a user