Skip to content

Filter root device application CCs from UI presentation when mirrored on endpoints #188

@dfederm

Description

@dfederm

Spec Requirement

Per CL:0060.01.52.01.1 (§6.4.2.4.1 "Root Device and End Point Command Classes"):

When End Point functionality is advertised in the Root Device NIF, service discovery mechanisms like mDNS and installer-style GUIs risk presenting a Root Device functionality which is actually a mirror representation of an End Point functionality.

Therefore, application command classes of the Root Device capabilities that are also advertised by at least one End Point SHOULD be filtered out by controlling nodes before presenting the functionalities via service discovery mechanisms like mDNS or to users in a GUI.

This is a SHOULD (not MUST), but following it produces a much cleaner UI experience - without it, a 5-output power strip would show 6 Binary Switch controls (root + 5 endpoints) instead of 5.

What this means

The Root Device of a Multi Channel node always advertises application functionality (Binary Switch, Multilevel Sensor, etc.) even when that functionality is actually provided by forwarding commands to endpoints. Per spec §4.1.3.2, "The Root Device of a Multi Channel always presents functionality which can also be reached via End Point 1." This is for backwards compatibility with legacy controllers that don't understand Multi Channel.

A modern controlling node (like us) should hide these mirrored root application CCs from UI/service discovery, while still keeping them functional internally. The root CCs are still interviewed and still work — this is purely a presentation-layer filter.

Filter logic

For a node with endpoints:

  1. Collect all application CC IDs (per CommandClassCategory.Application) supported by any endpoint
  2. For the root device's command classes, filter out any application CC that also appears in the set from step 1
  3. Management and Transport CCs on the root are never filtered — they are node-level concerns

Design considerations

  • Where: A method on Node, e.g. GetPresentableCommandClasses(), or a property like PresentableCommandClasses. This is a Node-level concern (not Endpoint or CommandClassCollection) since it requires cross-referencing root CCs against endpoint CCs.
  • Category lookup: The CommandClassCategory enum and CommandClass.Category property already exist (added in the interview phasing work). However, the filter needs to classify CCs at the CommandClassId level, including CCs we haven't implemented yet. Options:
    • Only filter implemented CCs (simplest, covers all practical cases since unimplemented CCs won't have UI values anyway)
    • Add a static CommandClassId → CommandClassCategory mapping (more complete, but requires maintaining a lookup table)
  • The root CCs are not removed — they remain in Node.CommandClasses, are still interviewed, and still accept commands. The filter only affects what's presented to users.

Prior art

zwave-js implements this via:

  • shouldHideRootApplicationCCValues() — determines whether to apply filtering (checks if endpoints exist and aren't explicitly preserved via device config)
  • filterRootApplicationCCValueIDs() — removes root endpoint value IDs for application CCs when an identical value ID exists on a non-root endpoint
  • applicationCCs — a static set of CC IDs classified as application CCs
  • Device config override: preserveRootApplicationCCValueIDs flag for misbehaving devices that need root values visible

Their filter operates at the value-ID level (per-property granularity), not the CC level. We could start with CC-level filtering (simpler) and refine to value-level later if needed.

Depends on

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions