diff --git a/custom_components/localthings/binary_sensor.py b/custom_components/localthings/binary_sensor.py index e390a59..42eb927 100644 --- a/custom_components/localthings/binary_sensor.py +++ b/custom_components/localthings/binary_sensor.py @@ -10,7 +10,7 @@ from .ocf.registry.entities import BinarySensorDesc from .const import DOMAIN from .coordinator import LocalThingsCoordinator -from .entity import LocalThingsEntity +from .entity import LocalThingsEntity, _is_included async def async_setup_entry( @@ -22,7 +22,7 @@ async def async_setup_entry( async_add_entities( LocalThingsBinarySensor(coordinator, b) for b in coordinator.bound - if isinstance(b.desc, BinarySensorDesc) + if isinstance(b.desc, BinarySensorDesc) and _is_included(b, coordinator) ) diff --git a/custom_components/localthings/button.py b/custom_components/localthings/button.py index c95dfd4..1283441 100644 --- a/custom_components/localthings/button.py +++ b/custom_components/localthings/button.py @@ -10,7 +10,7 @@ from .ocf.registry.entities import ButtonDesc from .const import DOMAIN from .coordinator import LocalThingsCoordinator -from .entity import LocalThingsEntity +from .entity import LocalThingsEntity, _is_included async def async_setup_entry( @@ -22,7 +22,7 @@ async def async_setup_entry( async_add_entities( LocalThingsButton(coordinator, b) for b in coordinator.bound - if isinstance(b.desc, ButtonDesc) + if isinstance(b.desc, ButtonDesc) and _is_included(b, coordinator) ) diff --git a/custom_components/localthings/entity.py b/custom_components/localthings/entity.py index 26d7a2c..4536473 100644 --- a/custom_components/localthings/entity.py +++ b/custom_components/localthings/entity.py @@ -14,6 +14,21 @@ from .const import DOMAIN from .coordinator import LocalThingsCoordinator +def _is_included(bound: BoundEntity, coordinator: 'LocalThingsCoordinator') -> bool: + """Return False if the entity should not be registered for this device. + + Explicit exists_fn takes priority. Otherwise, if the entity has a field, + require that field to be present in the resource rep so that optional + fields on shared resources don't create phantom entities. + """ + rep = coordinator.last_resources.get(bound.href) or {} + if bound.desc.exists_fn is not None: + return bound.desc.exists_fn(rep) + if bound.desc.field: + return bound.desc.field in rep + return True # rep_fn or no-field entities (ButtonDesc) are always included + + def _derive_name(state_key: str) -> str: """Turn a snake_case state key into a title-cased display name. diff --git a/custom_components/localthings/number.py b/custom_components/localthings/number.py index 0c1126b..28a87e3 100644 --- a/custom_components/localthings/number.py +++ b/custom_components/localthings/number.py @@ -10,7 +10,7 @@ from .ocf.registry.entities import NumberDesc from .const import DOMAIN from .coordinator import LocalThingsCoordinator -from .entity import LocalThingsEntity +from .entity import LocalThingsEntity, _is_included async def async_setup_entry( @@ -22,7 +22,7 @@ async def async_setup_entry( async_add_entities( LocalThingsNumber(coordinator, b) for b in coordinator.bound - if isinstance(b.desc, NumberDesc) + if isinstance(b.desc, NumberDesc) and _is_included(b, coordinator) ) diff --git a/custom_components/localthings/select.py b/custom_components/localthings/select.py index dbe637d..bb4440d 100644 --- a/custom_components/localthings/select.py +++ b/custom_components/localthings/select.py @@ -10,7 +10,7 @@ from .ocf.registry.entities import SelectDesc from .const import DOMAIN from .coordinator import LocalThingsCoordinator -from .entity import LocalThingsEntity +from .entity import LocalThingsEntity, _is_included async def async_setup_entry( @@ -19,21 +19,10 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: coordinator: LocalThingsCoordinator = hass.data[DOMAIN][entry.entry_id] - - def _include(b) -> bool: - if not isinstance(b.desc, SelectDesc): - return False - # Skip at registration time if exists_fn says the entity isn't present - if b.desc.exists_fn is not None: - rep = coordinator.last_resources.get(b.href) or {} - if not b.desc.exists_fn(rep): - return False - return True - async_add_entities( LocalThingsSelect(coordinator, b) for b in coordinator.bound - if _include(b) + if isinstance(b.desc, SelectDesc) and _is_included(b, coordinator) ) diff --git a/custom_components/localthings/sensor.py b/custom_components/localthings/sensor.py index b9c6dde..e9804b6 100644 --- a/custom_components/localthings/sensor.py +++ b/custom_components/localthings/sensor.py @@ -10,7 +10,7 @@ from .ocf.registry.entities import SensorDesc from .const import DOMAIN from .coordinator import LocalThingsCoordinator -from .entity import LocalThingsEntity +from .entity import LocalThingsEntity, _is_included async def async_setup_entry( @@ -22,7 +22,7 @@ async def async_setup_entry( async_add_entities( LocalThingsSensor(coordinator, b) for b in coordinator.bound - if isinstance(b.desc, SensorDesc) + if isinstance(b.desc, SensorDesc) and _is_included(b, coordinator) ) diff --git a/custom_components/localthings/switch.py b/custom_components/localthings/switch.py index 173d546..258333c 100644 --- a/custom_components/localthings/switch.py +++ b/custom_components/localthings/switch.py @@ -10,7 +10,7 @@ from .ocf.registry.entities import SwitchDesc from .const import DOMAIN from .coordinator import LocalThingsCoordinator -from .entity import LocalThingsEntity +from .entity import LocalThingsEntity, _is_included async def async_setup_entry( @@ -22,7 +22,7 @@ async def async_setup_entry( async_add_entities( LocalThingsSwitch(coordinator, b) for b in coordinator.bound - if isinstance(b.desc, SwitchDesc) + if isinstance(b.desc, SwitchDesc) and _is_included(b, coordinator) ) diff --git a/custom_components/localthings/time.py b/custom_components/localthings/time.py index 01831b6..c00a58f 100644 --- a/custom_components/localthings/time.py +++ b/custom_components/localthings/time.py @@ -12,7 +12,7 @@ from .ocf.registry.entities import TimeDesc from .const import DOMAIN from .coordinator import LocalThingsCoordinator -from .entity import LocalThingsEntity +from .entity import LocalThingsEntity, _is_included async def async_setup_entry( @@ -24,7 +24,7 @@ async def async_setup_entry( async_add_entities( LocalThingsTime(coordinator, b) for b in coordinator.bound - if isinstance(b.desc, TimeDesc) + if isinstance(b.desc, TimeDesc) and _is_included(b, coordinator) )