Skip to content

Quirks v2: no way to disable binding of a cluster (e.g. IasZone) #781

Description

@zigpy-review-bot

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions