From b72d30424d3aa32602f68d1b18b1440442771639 Mon Sep 17 00:00:00 2001 From: TheJulianJES Date: Thu, 6 Aug 2026 04:35:34 +0200 Subject: [PATCH 1/2] Exclude weight-0 entities from primary entity election Entities opt into primary candidacy via a non-zero primary weight. This makes it impossible for weight-0 entities (e.g. diagnostic/config entities) to win the election as the sole enabled candidate. This also ensures counter entities are actually excluded, as the comment already claimed before. --- zha/zigbee/device.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/zha/zigbee/device.py b/zha/zigbee/device.py index 51f8895b3..90dfd4547 100644 --- a/zha/zigbee/device.py +++ b/zha/zigbee/device.py @@ -1625,9 +1625,13 @@ def _compute_primary_entity(self, entities: Sequence[PlatformEntity]) -> None: # It should not be possible for there to be more than one assert not explicitly_primary - # For weight matching, only consider non-counter entities and entities which are - # not explicitly marked as not primary - candidates = [e for e in entities if e.enabled and e._attr_primary is not False] + # For weight matching, only consider entities with a non-zero primary weight + # which are not explicitly marked as not primary + candidates = [ + e + for e in entities + if e.enabled and e._attr_primary is not False and e.primary_weight > 0 + ] candidates.sort(reverse=True, key=lambda e: e.primary_weight) if not candidates: From 16cc246cbef39582c9ee76782c86f110da1b6d02 Mon Sep 17 00:00:00 2001 From: TheJulianJES Date: Thu, 6 Aug 2026 05:10:04 +0200 Subject: [PATCH 2/2] Add test for weight-0 primary entity election exclusion --- tests/test_device.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/test_device.py b/tests/test_device.py index 843db9a83..0275082a1 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -49,7 +49,7 @@ from zha.application.platforms import PlatformEntity from zha.application.platforms.binary_sensor import IASZone from zha.application.platforms.light import Light -from zha.application.platforms.sensor import LQISensor, RSSISensor +from zha.application.platforms.sensor import Battery, LQISensor, RSSISensor from zha.application.platforms.sensor.device_class import ( SensorDeviceClass, SensorStateClass, @@ -948,6 +948,31 @@ async def test_primary_entity_computation( ] +async def test_primary_entity_weight_0_not_elected(zha_gateway: Gateway) -> None: + """Test a weight-0 entity is not elected primary, even as the sole candidate.""" + + # Without the `Basic` cluster, no LQI/RSSI entities are created, so the + # battery entity is the only entity of this device + zigpy_dev = create_mock_zigpy_device( + zha_gateway, + { + 1: { + SIG_EP_INPUT: [general.PowerConfiguration.cluster_id], + SIG_EP_OUTPUT: [], + SIG_EP_TYPE: zigpy.profiles.zha.DeviceType.SIMPLE_SENSOR, + SIG_EP_PROFILE: zigpy.profiles.zha.PROFILE_ID, + } + }, + ) + zha_device = await join_zigpy_device(zha_gateway, zigpy_dev) + + battery = get_entity(zha_device, Platform.SENSOR, entity_type=Battery) + assert list(zha_device.platform_entities.values()) == [battery] + + # The weight-0 battery entity is not elected as the primary entity + assert not battery.primary + + async def test_quirks_v2_primary_entity(zha_gateway: Gateway) -> None: """Test quirks v2 primary entity.""" registry = DeviceRegistry()