Summary
When a quirk defines a manufacturer-specific attribute that reuses the same attribute ID as a standard ZCL attribute (distinguished only by manufacturer_code), the device-diagnostics snapshot for that device can no longer round-trip: tests/test_discover.py::test_devices_from_files fails its assert loaded_device_data == device_data check. This affects both newly regenerated snapshots and existing ones once the quirk becomes active.
Concrete example
zigpy/zha-device-handlers#5082 (Parse manufacturer-framed metering reports on Innr SP 120) adds, on the smartenergy_metering cluster (0x0702):
class AttributeDefs(Metering.AttributeDefs):
# standard ZCL current_summ_delivered is id=0x0000 (no manufacturer code)
current_summ_delivered_mfg = ZCLAttributeDef(
id=0x0000, # same ID as ZCL current_summ_delivered
type=t.uint48_t,
manufacturer_code=0x1166,
)
The quirk mirrors the manufacturer-framed report onto the standard current_summ_delivered (also id 0x0000).
What happens
Regenerating tests/data/devices/innr-sp-120.json with this quirk installed produces a snapshot where:
- the
summation_delivered sensor's serialized state is 145.26 (the mirrored value), but
- the metering cluster's serialized cached attributes contain no
0x0000 entry at all — the source value is dropped.
Reloading that snapshot therefore can't reproduce the state (the mirror has no source value to copy → None), so the round-trip assertion fails:
assert loaded_device_data == device_data
# zha_lib_entities ... summation_delivered: state None != state 145.26
This is not a regen artifact — dev's existing innr-sp-120.json also fails the round-trip once the quirk is installed. So when zha bumps zha-quirks to a version including the PR, this snapshot's test breaks regardless of regeneration.
Root cause
The attribute cache and its (de)serialization are keyed by attribute ID, so two attributes sharing id 0x0000 (one ZCL, one manufacturer-specific) collapse to a single slot that can't be faithfully represented or restored. Relevant code paths:
- round-trip assertion —
tests/test_discover.py (assert loaded_device_data == device_data)
- rebuild from snapshot —
tests/common.py zigpy_device_from_device_data → real_cluster.find_attribute(attr_name)
- name/ID resolution — zigpy
zigpy/zcl/__init__.py find_attributes (cls.attributes_by_name[name_or_id])
(The same ID/name resolution fragility surfaces elsewhere as KeyErrors during regeneration when an attribute name on a quirked cluster no longer matches a cached name.)
Impact
Any quirk that legitimately models a manufacturer-framed variant of a standard attribute at the same ID currently can't have a valid diagnostics snapshot, which blocks CI coverage for such devices.
Possible directions
- Key the diagnostics attribute serialization by (ID, manufacturer_code) rather than ID alone, so co-located attributes round-trip.
- Or have the serializer/round-trip tolerate derived state whose source is a manufacturer-specific attribute at a shared ID.
Context PR: zigpy/zha-device-handlers#5082
Summary
When a quirk defines a manufacturer-specific attribute that reuses the same attribute ID as a standard ZCL attribute (distinguished only by
manufacturer_code), the device-diagnostics snapshot for that device can no longer round-trip:tests/test_discover.py::test_devices_from_filesfails itsassert loaded_device_data == device_datacheck. This affects both newly regenerated snapshots and existing ones once the quirk becomes active.Concrete example
zigpy/zha-device-handlers#5082(Parse manufacturer-framed metering reports on Innr SP 120) adds, on thesmartenergy_meteringcluster (0x0702):The quirk mirrors the manufacturer-framed report onto the standard
current_summ_delivered(also id0x0000).What happens
Regenerating
tests/data/devices/innr-sp-120.jsonwith this quirk installed produces a snapshot where:summation_deliveredsensor's serialized state is145.26(the mirrored value), but0x0000entry at all — the source value is dropped.Reloading that snapshot therefore can't reproduce the state (the mirror has no source value to copy →
None), so the round-trip assertion fails:This is not a regen artifact — dev's existing
innr-sp-120.jsonalso fails the round-trip once the quirk is installed. So when zha bumpszha-quirksto a version including the PR, this snapshot's test breaks regardless of regeneration.Root cause
The attribute cache and its (de)serialization are keyed by attribute ID, so two attributes sharing id
0x0000(one ZCL, one manufacturer-specific) collapse to a single slot that can't be faithfully represented or restored. Relevant code paths:tests/test_discover.py(assert loaded_device_data == device_data)tests/common.pyzigpy_device_from_device_data→real_cluster.find_attribute(attr_name)zigpy/zcl/__init__.pyfind_attributes(cls.attributes_by_name[name_or_id])(The same ID/name resolution fragility surfaces elsewhere as
KeyErrors during regeneration when an attribute name on a quirked cluster no longer matches a cached name.)Impact
Any quirk that legitimately models a manufacturer-framed variant of a standard attribute at the same ID currently can't have a valid diagnostics snapshot, which blocks CI coverage for such devices.
Possible directions
Context PR: zigpy/zha-device-handlers#5082