Skip to content

fix: format sensor readings + name multi-function devices by role#66

Merged
simons-plugins merged 1 commit into
mainfrom
fix/sensor-display-and-role-naming
Jun 13, 2026
Merged

fix: format sensor readings + name multi-function devices by role#66
simons-plugins merged 1 commit into
mainfrom
fix/sensor-display-and-role-naming

Conversation

@simons-plugins

@simons-plugins simons-plugins commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Surfaced commissioning a multi-sensor Matter node (HomePod mini: temperature + humidity).

1. Readings showed 6 decimal places

Sensor handlers rounded the value, but it reached Indigo as a bare {key, value} — and Indigo renders a Number state at full float precision without a uiValue/decimalPlaces (a round(x, 2) still displays as 21.340000000001). The plugin set neither anywhere.

  • New ClusterHandler.format_kv() hook converts a {state: value} dict into an Indigo updateStatesOnServer kvlist. The sensor base overrides it to attach uiValue + decimalPlaces.
  • device_sync now routes every handler-produced state write (live updates, node events, node-scoped battery fan-out, create-time priming) through handler.format_kv().
  • Precision/units: Temperature 21.5 °C, Humidity 47.5%, Illuminance 123 lux, Pressure 1013 hPa, Flow 2.5 m³/h, CO₂ ppm, PM2.5 µg/m³. Boolean sensors (motion/contact) pass through untouched.

2. Devices named "(endpoint 1)"

  • A node's devices now read {name} - {role} (e.g. HomePod - Temperature / HomePod - Humidity) via a device-type → role map. Endpoint-number naming is kept only as a fallback (unmapped type) or to disambiguate genuinely identical siblings (a 4-outlet strip → - Switch 1..4). Bridged children with their own identity are unaffected.
  • dev.model is stamped with the product name on every device, so a node's siblings share one Model column value.

3. Master device + children — investigated, kept standalone

Indigo's only master/children mechanism is the Device Factory (shared model + subType, tabbed editor), which is dialog-driven and fights the automated Domio-commission + WebSocket-reconcile creation path — and the children stay independent devices for triggers/control-pages/Domio regardless. Standalone devices + role naming + shared model column deliver the grouping without the factory machinery.

Notes

  • Existing devices: the display self-heals on the next reading; names only change on a commission (authoritative) pass, so re-commission or delete+reload to pick up the new names.
  • Tests: +sensor formatting, +role naming/model stamping, updated Patio multi-endpoint naming. 773 pass.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Multi-endpoint devices now display descriptive role-based names (e.g., "Patio - Temperature", "Patio - Switch 1") for improved clarity
    • Sensor readings now display with proper units and decimal precision: Temperature (°C), Humidity (%), Illuminance (lux), Pressure (hPa), Flow (m³/h), CO2 (ppm), and PM2.5 (µg/m³)

Two device-presentation fixes surfaced commissioning a multi-sensor node
(HomePod mini: temperature + humidity), plus the architecture call on
device grouping.

Display (the "6 decimal places" report):
- Add a ClusterHandler.format_kv() hook that turns a {state: value} dict
  into an Indigo updateStatesOnServer kvlist. The sensor base overrides it
  to attach uiValue + decimalPlaces, so a reading renders as "21.5 °C"
  instead of the raw float (a round(x,2) still shows 21.340000000001
  without it). device_sync routes every handler-produced state write —
  live updates, node events, battery fan-out, and create-time priming —
  through handler.format_kv(). Per-sensor precision/units set for
  temperature, humidity, illuminance, pressure, flow, CO2, PM2.5, TVOC;
  boolean sensors pass through untouched.

Naming (the "(endpoint 1)" report):
- Name a node's devices "{name} - {role}" (e.g. "HomePod - Temperature")
  via a device-type -> role map, instead of the opaque Matter endpoint
  number. The endpoint number remains only as a fallback (unmapped type)
  or to disambiguate genuinely identical siblings (a 4-outlet strip ->
  "- Switch 1..4"). Bridged children with their own identity unaffected.
- Stamp dev.model = product name on every device so a node's siblings
  share one Model-column value — the grouping Indigo offers short of a
  Device Factory (which is dialog-driven and a poor fit for the automated
  commission/reconcile path; standalone devices stay first-class for
  triggers, control pages, and Domio).

Tests: +sensor formatting, +role naming/model stamping; updated the Patio
multi-endpoint naming expectations. 773 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors device naming to use handler role labels and introduces handler-driven state formatting. Multi-function nodes now display as " - " (e.g., "HomePod - Temperature"), and state updates are formatted per-handler with numeric display hints like decimal places and unit suffixes instead of using a single generic conversion path.

Changes

Role-Based Naming and Handler Formatting

Layer / File(s) Summary
Handler formatting framework
matter_handlers/base.py, matter_handlers/sensors.py, matter_handlers/air_quality.py
ClusterHandler adds a format_kv() hook to convert state dicts into Indigo kvlist entries. SensorHandler implements format_kv() with decimal places and unit suffixes for TemperatureHandler (1 dp, °C), HumidityHandler (1 dp, %), IlluminanceHandler (0 dp, lux), PressureHandler (0 dp, hPa), and FlowHandler (1 dp, m³/h). CO2Handler, PM25Handler, and TVOCHandler declare formatting attributes for air quality measurements.
Device sync integration of handler formatting
device_sync.py (_prime_states, _on_node_event, _on_attribute)
Refactors state priming and event handling to call handler.format_kv(states) instead of the generic _kvlist() utility, ensuring per-handler formatting is applied when passing updates to apply_states.
Role-based device naming strategy
device_sync.py (create_devices, _ROLE_LABELS)
Adds _ROLE_LABELS mapping deviceTypeId to role suffixes, computes role histograms and model strings from node metadata in create_devices, and generates device names using " - " with endpoint number disambiguation for duplicate roles.
Model string stamping on devices
device_sync.py (_create_one signature and implementation)
Extends _create_one() to accept an optional model parameter, conditionally sets dev.model and calls replaceOnServer() when non-empty, and passes the computed model from create_devices into device creation.
Test coverage for naming and formatting
tests/test_sensors.py, tests/test_bridges.py, tests/test_device_sync.py
Validates numeric sensor format_kv() output (decimal places and uiValue formatting) and binary sensor passthrough behavior, confirms role-based naming for multi-endpoint and multi-function nodes, and updates assertions to match " - " format.
Version metadata update
indigo-matter.indigoPlugin/Contents/Info.plist
PluginVersion bumped from 2026.2.25 to 2026.2.26.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Device names now bloom with role,
No more endpoints taking their toll,
Handlers format with care and grace,
Each sensor shows its proper face,
The plugin springs to version .26! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: format sensor readings + name multi-function devices by role' directly and accurately summarizes the two main changes: sensor value formatting and role-based device naming for multi-function nodes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/sensor-display-and-role-naming

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 and usage tips.

@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

🤖 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/Info.plist`:
- Line 23: Replace the existing PluginVersion string "2026.2.26" with a new,
unused version (for example "2026.2.27") so the CI version-check won't fail;
locate the "2026.2.26" entry in Info.plist and update that string to the bumped
version.
🪄 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: b9a4490e-3b16-4610-97de-c2fc836d796e

📥 Commits

Reviewing files that changed from the base of the PR and between a0cb3a0 and 671d935.

📒 Files selected for processing (8)
  • indigo-matter.indigoPlugin/Contents/Info.plist
  • indigo-matter.indigoPlugin/Contents/Server Plugin/device_sync.py
  • indigo-matter.indigoPlugin/Contents/Server Plugin/matter_handlers/air_quality.py
  • indigo-matter.indigoPlugin/Contents/Server Plugin/matter_handlers/base.py
  • indigo-matter.indigoPlugin/Contents/Server Plugin/matter_handlers/sensors.py
  • tests/test_bridges.py
  • tests/test_device_sync.py
  • tests/test_sensors.py

<string>1.0.0</string>
<key>PluginVersion</key>
<string>2026.2.25</string>
<string>2026.2.26</string>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Version 2026.2.26 already exists as a git tag; the CI version-check workflow will fail.

The version-check pipeline confirms that v2026.2.26 is already tagged in the repository. Reusing a version number violates release hygiene and breaks the CI gate. Increment PluginVersion to an unused version (e.g., 2026.2.27).

🔖 Proposed fix to bump to the next available version
-	<string>2026.2.26</string>
+	<string>2026.2.27</string>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<string>2026.2.26</string>
<string>2026.2.27</string>
🤖 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/Info.plist` at line 23, Replace the
existing PluginVersion string "2026.2.26" with a new, unused version (for
example "2026.2.27") so the CI version-check won't fail; locate the "2026.2.26"
entry in Info.plist and update that string to the bumped version.

Source: Pipeline failures

@simons-plugins simons-plugins merged commit b4dbb4f into main Jun 13, 2026
3 checks passed
@simons-plugins simons-plugins deleted the fix/sensor-display-and-role-naming branch June 13, 2026 12:49
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.

1 participant