Summary
There is currently no quirks-v2 mechanism to opt a device out of binding a particular cluster (e.g. IasZone). The natural candidate, prevent_default_entity_creation(...), does not achieve this — by design it only suppresses HA entity registration and deliberately leaves the bind/reporting/cluster-config machinery untouched. This request is to add a first-class way for QuirkBuilder to disable a cluster bind (and ideally attribute reporting) for a device.
Found while answering a user question; analysis is against dev @ 3a884dc3.
Why prevent_default_entity_creation can't do this
After #657, binding/reporting/cluster-setup moved onto entities via _server_cluster_config / _client_cluster_config, and IAS Zone enrollment is now driven by the virtual entity IasZoneEnrollment, which declares the bind:
# zha/application/platforms/virtual.py
class IasZoneEnrollment(VirtualEntity):
_server_cluster_config = {
IasZone.cluster_id: ClusterConfig(bind=True, ...),
}
It fails on two independent grounds:
1. The prevent-filter is hardcoded to skip virtual entities. _is_entity_removed_by_quirk returns early for anything on the VIRTUAL platform:
# zha/zigbee/device.py
def _is_entity_removed_by_quirk(self, entity):
if self.quirk_metadata is None:
return False
if entity.PLATFORM == Platform.VIRTUAL:
return False
...
So no prevent_default_entity_creation clause — by cluster_id=0x0500, by unique_id_suffix="_ias_zone_enrollment", or by a function= predicate matching IasZoneEnrollment — can ever match it. (test_quirks_v2_prevent_default_entities asserts exactly this: it filters e.PLATFORM != Platform.VIRTUAL and the virtuals survive.)
2. Even for non-virtual entities, the prevent-filter doesn't stop binding anyway. In _discover_new_entities, the entity is appended to _discovered_entities before the prevent check, and the prevent check only skips on_add() + HA registration:
# zha/zigbee/device.py
for entity in new_entities:
self._discovered_entities.append(entity) # unconditional
if self._is_entity_removed_by_quirk(entity):
continue # only skips on_add + _pending_entities
...
self._pending_entities.append(entity)
Binding then aggregates over _discovered_entities (the full set), not the registered set:
# zha/zigbee/device.py
aggregated = aggregate_cluster_configs(self._discovered_entities)
with agg.bind = agg.bind or config.bind in aggregate_cluster_configs (zha/zigbee/cluster_config.py). So a "prevented" entity's bind=True still takes effect — the filter is purely cosmetic w.r.t. the Zigbee layer.
Note: whether binding should aggregate over _discovered_entities rather than _pending_entities is arguably a separate question. It's noted here as the mechanism behind point 2, not as a bug report — for non-virtual entities one could imagine wanting prevent_default_entity_creation to also drop the cluster-config contribution. I've kept it in this one issue since it's the same story; happy to split it out if maintainers prefer.
Proposed enhancement
A way for a quirk to suppress a cluster bind (and ideally reporting), independent of entity creation. Rough sketch — open to whatever shape fits the v2 API best:
- A
QuirkBuilder method, e.g. .prevent_cluster_bind(endpoint_id=..., cluster_id=..., cluster_type=...), recorded in quirk metadata; consulted in aggregate_cluster_configs/configure_cluster_configs so the matching (endpoint, cluster, side) entry is forced to bind=False (and/or reporting suppressed).
- This would need to apply to virtual-entity-driven configs too (the IAS Zone case), so it can't reuse the entity-removal path that skips
VIRTUAL.
Use case
Some devices misbehave when the coordinator binds a cluster they nominally expose (duplicate/unwanted reports, enrollment side-effects, devices that should be left to a different controller, etc.). Today a quirk author has no v2-native escape hatch for this; the only recourse is custom cluster subclasses. A declarative opt-out keeps it in the quirk where the device-specific knowledge lives.
cc @TheJulianJES
Summary
There is currently no quirks-v2 mechanism to opt a device out of binding a particular cluster (e.g.
IasZone). The natural candidate,prevent_default_entity_creation(...), does not achieve this — by design it only suppresses HA entity registration and deliberately leaves the bind/reporting/cluster-config machinery untouched. This request is to add a first-class way forQuirkBuilderto disable a cluster bind (and ideally attribute reporting) for a device.Found while answering a user question; analysis is against
dev@3a884dc3.Why
prevent_default_entity_creationcan't do thisAfter #657, binding/reporting/cluster-setup moved onto entities via
_server_cluster_config/_client_cluster_config, and IAS Zone enrollment is now driven by the virtual entityIasZoneEnrollment, which declares the bind:It fails on two independent grounds:
1. The prevent-filter is hardcoded to skip virtual entities.
_is_entity_removed_by_quirkreturns early for anything on theVIRTUALplatform:So no
prevent_default_entity_creationclause — bycluster_id=0x0500, byunique_id_suffix="_ias_zone_enrollment", or by afunction=predicate matchingIasZoneEnrollment— can ever match it. (test_quirks_v2_prevent_default_entitiesasserts exactly this: it filterse.PLATFORM != Platform.VIRTUALand the virtuals survive.)2. Even for non-virtual entities, the prevent-filter doesn't stop binding anyway. In
_discover_new_entities, the entity is appended to_discovered_entitiesbefore the prevent check, and the prevent check only skipson_add()+ HA registration:Binding then aggregates over
_discovered_entities(the full set), not the registered set:with
agg.bind = agg.bind or config.bindinaggregate_cluster_configs(zha/zigbee/cluster_config.py). So a "prevented" entity'sbind=Truestill takes effect — the filter is purely cosmetic w.r.t. the Zigbee layer.Proposed enhancement
A way for a quirk to suppress a cluster bind (and ideally reporting), independent of entity creation. Rough sketch — open to whatever shape fits the v2 API best:
QuirkBuildermethod, e.g..prevent_cluster_bind(endpoint_id=..., cluster_id=..., cluster_type=...), recorded in quirk metadata; consulted inaggregate_cluster_configs/configure_cluster_configsso the matching(endpoint, cluster, side)entry is forced tobind=False(and/or reporting suppressed).VIRTUAL.Use case
Some devices misbehave when the coordinator binds a cluster they nominally expose (duplicate/unwanted reports, enrollment side-effects, devices that should be left to a different controller, etc.). Today a quirk author has no v2-native escape hatch for this; the only recourse is custom cluster subclasses. A declarative opt-out keeps it in the quirk where the device-specific knowledge lives.
cc @TheJulianJES