Skip to content

Boolean State Configuration (0x0080): sensitivity state + Set Sensitivity action#87

Merged
simons-plugins merged 3 commits into
mainfrom
feat/issue-85-sensitivity-0x0080
Jul 6, 2026
Merged

Boolean State Configuration (0x0080): sensitivity state + Set Sensitivity action#87
simons-plugins merged 3 commits into
mainfrom
feat/issue-85-sensitivity-0x0080

Conversation

@simons-plugins

@simons-plugins simons-plugins commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #85. First live catch of the #81 leftover-cluster diagnostic, now implemented: sensors with Matter 1.3 Boolean State Configuration (Aqara FP300 presence on the house fabric — node 0x2D ep1, co-located with OccupancySensing) get a sensitivityLevel state and a Set Sensitivity Level device action (the plugin's first custom action).

  • Merge-only BooleanStateConfigHandler (electrical.py shape, endpoint-scoped) — attr 0x0000 → sensitivityLevel on the endpoint's sensor device; declared on matterMotionSensor + matterContactSensor (spec pairs 0x0080 with BooleanState; Aqara pairs it with occupancy — both covered).
  • Action menu reads the device's live SupportedSensitivityLevels (cached per reconcile, lock-guarded): 3 levels → Low/Standard/High labels; otherwise generic. Level semantics treated as opaque ordinals — the spec text for which end is 'most sensitive' isn't publicly verifiable; to be confirmed empirically on the FP300.
  • Write goes through the existing MatterWrite path (thermostat-proven); optimistic state echo only after matter-server confirms the RPC (_send_matter_command now returns bool — verified genuine confirmation, not fire-and-forget).
  • Registering the handler retires the 0x0080 leftover-cluster log.

Review

Single code-reviewer pass (proportionate): no findings; bool-return semantics, cache thread-safety, and test genuineness all positively verified.

Open live-verification items (pre-merge, on jarvis)

  • deviceFilter="self.matterMotionSensor, self.matterContactSensor" comma-list — no workspace precedent; if the action doesn't appear on the FP300 motion device, fall back to deviceFilter="self" (callbacks already guard).
  • Set sensitivity on the FP300 and confirm state echo + report.

Tests / version

868 passing (40 new: handler unit, device_sync priming/live/log-retirement, zoo fixture, menu + action callbacks). 2026.4.2 → 2026.5.0 (user-visible feature).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z

Summary by CodeRabbit

  • New Features

    • Added support for viewing and changing sensor sensitivity levels for compatible motion/contact devices.
    • Sensitivity options now show clearer labels, with generic levels used when exact support isn’t known.
  • Bug Fixes

    • Improved handling of combined sensor devices so sensitivity updates appear in the right device view.
    • Fixed syncing so sensitivity state updates and supported levels refresh correctly after device reconciliation.
  • Chores

    • Updated the plugin version.

…action (closes #85)

Aqara FP300-class sensors expose a writable sensitivity level via
Matter 1.3's Boolean State Configuration cluster. New merge-only
BooleanStateConfigHandler maps CurrentSensitivityLevel (0x0000) onto a
sensitivityLevel state on the endpoint's sensor device (motion +
contact types), primed at creation and updated live. New
'Set Sensitivity Level' device action — the plugin's first custom
action — with a dynamic level menu driven by the device's live
SupportedSensitivityLevels (friendly Low/Standard/High labels when 3),
writing via the existing MatterWrite path with an optimistic echo
gated on the server's RPC confirmation. Registering the handler also
retires the 0x0080 leftover-cluster log from #81.

868 tests (40 new). Version 2026.5.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@simons-plugins, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 43 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b3398558-a3b8-40ad-b0b3-088ca678b794

📥 Commits

Reviewing files that changed from the base of the PR and between 4ec9065 and d577ef4.

📒 Files selected for processing (3)
  • indigo-matter.indigoPlugin/Contents/Server Plugin/Actions.xml
  • indigo-matter.indigoPlugin/Contents/Server Plugin/plugin.py
  • tests/test_plugin_module.py
📝 Walkthrough

Walkthrough

Adds Matter BooleanStateConfiguration (0x0080) cluster support: a new non-primary handler surfaces CurrentSensitivityLevel into existing motion/contact sensor devices, DeviceSync caches SupportedSensitivityLevels per endpoint, and a new plugin action with a dynamic picker lets users set sensitivity level via Matter attribute writes. Includes XML config updates, tests, and a version bump.

Changes

Sensitivity Level Feature

Layer / File(s) Summary
BooleanStateConfig cluster handler and registry wiring
.../matter_handlers/boolean_state_config.py, .../matter_handlers/registry.py, tests/test_boolean_state_config.py
New handler parses CurrentSensitivityLevel, updates the sensitivityLevel Indigo state only when declared, is registered as non-primary in default handlers, and is covered by parsing, contract, and registry integration tests.
DeviceSync sensitivity level caching
.../device_sync.py, tests/test_device_sync.py, tests/test_device_zoo.py
Adds a per-endpoint cache for SupportedSensitivityLevels, populates it during device creation, exposes sensitivity_levels_supported, and adds tests for priming, live updates, and reconcile refresh plus a device-zoo fixture.
Plugin action, picker, and XML wiring
.../plugin.py, .../Actions.xml, .../Devices.xml, tests/test_plugin_module.py
Adds getSensitivityLevels picker and actionSetSensitivityLevel action to write the Matter attribute and echo state, changes _send_matter_command to return a boolean, adds the setSensitivityLevel action config UI, updates device state definitions/comments, and adds plugin-level tests.
Plugin version bump
Info.plist
Bumps PluginVersion from 2026.4.2 to 2026.5.0.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Plugin
  participant DeviceSync
  participant MatterWrite
  participant IndigoDevice

  User->>Plugin: actionSetSensitivityLevel(action, dev)
  Plugin->>DeviceSync: sensitivity_levels_supported(node_id, endpoint_id)
  Plugin->>Plugin: validate level against supported range
  Plugin->>MatterWrite: write CurrentSensitivityLevel attribute
  Plugin->>Plugin: _send_matter_command(action, dev)
  alt write succeeds
    Plugin->>IndigoDevice: updateStateOnServer(sensitivityLevel, level)
  else write fails
    Plugin-->>User: no state echo
  end
Loading
sequenceDiagram
  participant MatterNode
  participant BooleanStateConfigHandler
  participant IndigoDevice

  MatterNode->>BooleanStateConfigHandler: CurrentSensitivityLevel attribute update
  BooleanStateConfigHandler->>BooleanStateConfigHandler: _parse_sensitivity(value)
  BooleanStateConfigHandler->>IndigoDevice: check declared states for sensitivityLevel
  alt state declared
    BooleanStateConfigHandler->>IndigoDevice: update sensitivityLevel state
  else not declared
    BooleanStateConfigHandler-->>MatterNode: no-op
  end
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: Boolean State Configuration support and a new Set Sensitivity action.
Linked Issues check ✅ Passed The PR implements issue #85 by exposing sensitivity as state and action for 0x0080 on the FP300-related sensor types.
Out of Scope Changes check ✅ Passed The changes stay focused on 0x0080 support, with only matching tests, docs, and a version bump added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-85-sensitivity-0x0080

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
indigo-matter.indigoPlugin/Contents/Server Plugin/device_sync.py (1)

165-170: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Consider clearing _sensitivity_supported entries on node decommission.

delete_node removes entries from _index but never touches _sensitivity_supported, unlike _power_source_eps which is popped per node-id when empty. This means cached sensitivity-level counts for a decommissioned node's endpoints persist indefinitely, and could resurface incorrect data if the node id is ever reused by a different device (Matter allows arbitrary node-id assignment by the commissioner).

♻️ Suggested cleanup in delete_node
             self.logger.warning("could not delete Indigo device %s: %s", dev_id, exc)
         deleted_set = set(deleted)
         # Drop successfully-deleted devices from the nested index
         new_index: dict[tuple[int, int], dict[str, int]] = {}
         for key, type_map in self._index.items():
             if key[0] == target:
                 remaining = {tid: did for tid, did in type_map.items() if did not in deleted_set}
                 if remaining:
                     new_index[key] = remaining
             else:
                 new_index[key] = type_map
         self._index = new_index
+        self._sensitivity_supported = {
+            k: v for k, v in self._sensitivity_supported.items() if k[0] != target
+        }
         return deleted

Also applies to: 1023-1050

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@indigo-matter.indigoPlugin/Contents/Server` Plugin/device_sync.py around
lines 165 - 170, Clear stale sensitivity cache entries when a node is
decommissioned. Update delete_node in device_sync.py to remove any
_sensitivity_supported entries associated with the deleted node-id, similar to
how _power_source_eps is cleaned up when empty. Use the existing node/endpoint
bookkeeping in _index and the _sensitivity_supported dict so cached
SupportedSensitivityLevels values cannot persist after a node is removed and
later be reused incorrectly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@indigo-matter.indigoPlugin/Contents/Server` Plugin/Actions.xml:
- Around line 17-18: The setSensitivityLevel action is using an invalid
multi-device deviceFilter value, since deviceFilter only accepts one filter
string and cannot scope to both motion and contact sensors at once. Update the
Action entry in Actions.xml by either splitting it into two separate Action
definitions for setSensitivityLevel, one for matterMotionSensor and one for
matterContactSensor, or by replacing it with a single broader filter if a shared
one exists. Use the setSensitivityLevel Action and its deviceFilter attribute to
locate and adjust the mapping.

---

Nitpick comments:
In `@indigo-matter.indigoPlugin/Contents/Server` Plugin/device_sync.py:
- Around line 165-170: Clear stale sensitivity cache entries when a node is
decommissioned. Update delete_node in device_sync.py to remove any
_sensitivity_supported entries associated with the deleted node-id, similar to
how _power_source_eps is cleaned up when empty. Use the existing node/endpoint
bookkeeping in _index and the _sensitivity_supported dict so cached
SupportedSensitivityLevels values cannot persist after a node is removed and
later be reused incorrectly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 76030a29-bafd-4c92-b504-7f855b75346a

📥 Commits

Reviewing files that changed from the base of the PR and between b62a642 and 4ec9065.

📒 Files selected for processing (11)
  • indigo-matter.indigoPlugin/Contents/Info.plist
  • indigo-matter.indigoPlugin/Contents/Server Plugin/Actions.xml
  • indigo-matter.indigoPlugin/Contents/Server Plugin/Devices.xml
  • indigo-matter.indigoPlugin/Contents/Server Plugin/device_sync.py
  • indigo-matter.indigoPlugin/Contents/Server Plugin/matter_handlers/boolean_state_config.py
  • indigo-matter.indigoPlugin/Contents/Server Plugin/matter_handlers/registry.py
  • indigo-matter.indigoPlugin/Contents/Server Plugin/plugin.py
  • tests/test_boolean_state_config.py
  • tests/test_device_sync.py
  • tests/test_device_zoo.py
  • tests/test_plugin_module.py

Comment thread indigo-matter.indigoPlugin/Contents/Server Plugin/Actions.xml Outdated
simons-plugins and others added 2 commits July 6, 2026 22:51
…ate guard

Live-verified on jarvis: Indigo's deviceFilter takes exactly one filter;
both "a, b" and "a,b" comma forms yield an empty device picker. Fall
back to deviceFilter="self" and reject devices without the
sensitivityLevel state in the action callback (new test). 869 tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
…ve-verified)

deviceFilter="self.matterMotionSensor" works; comma lists don't. Ship
two scoped <Action> entries sharing one callback — motion (FP300
pairing) + contact (spec BooleanState pairing) — so the picker never
lists plugs/relays. State guard kept as defense-in-depth. 869 tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Arj5R66d73tc3PMPvHS65Z
@simons-plugins simons-plugins merged commit af4c456 into main Jul 6, 2026
3 checks passed
@simons-plugins simons-plugins deleted the feat/issue-85-sensitivity-0x0080 branch July 6, 2026 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Boolean State Configuration (0x0080) — surfaced by the new leftover-cluster log on Aqara FP300

1 participant