Add bitmap-bit mask support to ConfigurableAttributeSwitch#814
Add bitmap-bit mask support to ConfigurableAttributeSwitch#814TheJulianJES wants to merge 2 commits into
Conversation
A masked configurable switch toggles only the bit(s) in `mask` of a bitmap attribute, reading the current (shared) cluster cache value to preserve the other bits. This lets quirks expose individual bits of a real ZCL bitmap as switches without synthesizing per-bit shadow attributes on a local cluster. Migrate the existing `DanfossAdaptationRunSettings` (a bitmap using only its first bit) onto `_mask` as the first in-tree consumer.
There was a problem hiding this comment.
Pull request overview
This PR adds optional bitmap bitmask behavior to ConfigurableAttributeSwitch, enabling a switch entity to toggle only specific bit(s) of a bitmap attribute while preserving other bits via the cluster cache. It also migrates the in-tree DanfossAdaptationRunSettings switch to use the new _mask capability and adds a regression test around the new behavior.
Changes:
- Add
_mask/masksupport toConfigurableAttributeSwitchfor read-modify-write updates of bitmap attributes. - Update
DanfossAdaptationRunSettingsto use_mask = 0x01instead of treating the bitmap as a plain boolean. - Add a unit test validating that masked toggling preserves other bits.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| zha/application/platforms/switch.py | Introduces optional bitmap mask support in ConfigurableAttributeSwitch and updates Danfoss adaptation switch to toggle only bit 0x01. |
| tests/test_switch.py | Adds coverage for masked bitmap toggling to ensure non-masked bits are preserved across on/off operations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if mask is not None: | ||
| self._mask = mask |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #814 +/- ##
=======================================
Coverage 97.29% 97.29%
=======================================
Files 55 55
Lines 10933 10945 +12
=======================================
+ Hits 10637 10649 +12
Misses 296 296 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Reject a zero `mask` (it would make the switch a permanent no-op), and extend the test to build a switch via the `mask=` constructor argument — the path quirks v2 discovery uses — so that path and the zero-mask guard are covered.
Related quirks PR: zigpy/zha-device-handlers#5141
Summary
Adds an optional
masktoConfigurableAttributeSwitchso a config switch can target individual bit(s) of a bitmap attribute instead of the whole attribute.When
maskis set:is_onisbool(cluster.get(attribute) & mask)current | mask, turning off writescurrent & ~maskThe current value is read from the (shared) cluster attribute cache before each write, so only the masked bit(s) change and the other bits are preserved. Sibling switches that target different bits of the same attribute share that cluster cache, so their bits accumulate correctly across sequential writes.
This lets quirks v2 expose bitmap bits as switches without synthesizing per-bit shadow attributes on a local cluster (see the quirks PR, which uses it to delete the Sonoff ZBM5 shadow cluster). It also generalizes a pattern that previously had to be hand-rolled per device.
Changes
ConfigurableAttributeSwitchgains amaskinit argument /_maskclass attribute and the read-modify-write behavior above.DanfossAdaptationRunSettingsis migrated onto_mask = 0x01as the first in-tree consumer — its docstring already noted it is "a bitmap, but only the first bit is used". Single-bit behavior is unchanged, but other bits are no longer clobbered on write.Why
maskis not onConfigurableAttributeSwitchInfomaskis intentionally kept as instance state and not added to the serialized info dataclass. Adding a field there would change the diagnostics JSON for every config switch, forcing a regeneration of all ~87 device snapshots (thetest_devices_from_filestest asserts full diagnostics equality) — pure noise for a behavior-only change. The behavior is driven entirely by_mask.Relationship to existing bitmap-bit switches
WindowCoveringInversionSwitchandDanfossAdaptationRunSettingsalready open-coded single-bit bitmap handling. This adds a reusable, declarative way to do it.WindowCoveringInversionSwitchis left alone — it reads one attribute (config_status) but writes a different one (window_covering_mode), which the single-attributemaskdoesn't model.DanfossAdaptationRunSettingsfits the mask exactly and is migrated.Tests
test_switch_configurable_bitmap_maskverifies that toggling a masked switch sets/clears only its bit and preserves the others (via the Danfoss adaptation-run entity).Coupled release
The quirks-side counterpart (zigpy/zha-device-handlers#5141) depends on this change, so this should land/release first.