Skip to content

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

@zigpy-review-bot

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions