Skip to content

feat(entity): optional available on nodered/entity - #409

Open
Swamp-Ig wants to merge 4 commits into
zachowj:mainfrom
Swamp-Ig:feat/entity-available
Open

feat(entity): optional available on nodered/entity#409
Swamp-Ig wants to merge 4 commits into
zachowj:mainfrom
Swamp-Ig:feat/entity-available

Conversation

@Swamp-Ig

@Swamp-Ig Swamp-Ig commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Paired with contrib#2041. Full design, wire contract, and smoke matrix live there.

Summary

  • Accept optional available on nodered/entity and discovery.
  • When contrib has announced a package version (presence-available): omit
    available holds; discovery without state → unavailable.
  • Legacy (no announce): state-only updates still invent available: true;
    discovery without state stays unknown.

Stacking note

Depends on #408 (contrib version handshake). This branch is stacked on that
tip; GitHub shows the handshake commit too until #408 merges (base is
main because the handshake branch only exists on the fork). Fine to merge
#408 first, or skip it and merge this PR alone — it carries the handshake
commit.

Test plan

  • Unit / WS tests for schema, presence gating, discovery-without-state
  • CI green
  • Pair against contrib#2041

Swamp-Ig added 4 commits July 29, 2026 21:17
Accept optional contrib_version on the config entry and clear it on
disconnect. Expose contrib_announced_version as a fact helper for later
use. Load VERSION from manifest.json so release-please owns the bump.

Copilot AI 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.

Pull request overview

This PR extends the Node-RED Companion integration’s websocket protocol to support (1) an optional available field for discovery/entity messages (enabling availability-only updates and new “presence-available” semantics gated by contrib version announcement) and (2) storing the contrib package version via an enhanced nodered/version handshake.

Changes:

  • Update websocket schemas to accept optional available and allow omitting state for nodered/entity and nodered/discovery.
  • Add contrib-version handshake storage/clearing behavior on nodered/version, plus helpers to gate “presence-available” semantics.
  • Adjust entity availability/state handling (notably sensor/binary_sensor + base entity behavior) and expand unit/integration tests for the new contract.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/test_websocket.py Adds websocket-level tests for optional available, omitted state, and contrib version storage/clearing.
tests/test_utils.py Adds tests ensuring VERSION matches manifest and contrib capability helpers behave as expected.
tests/test_sensor.py Adds unit coverage for discovery-without-state semantics and availability-only restore behavior.
tests/test_entity.py Adds unit coverage for legacy vs presence-available update semantics in the base entity attribute/availability handling.
tests/test_binary_sensor_unit.py New unit tests for binary sensor availability + omitted-state semantics.
tests/test_availability_ws.py New websocket integration tests validating end-to-end HA state for Unknown/Unavailable and restore flows.
custom_components/nodered/websocket.py Expands websocket command schemas and adds contrib_version handshake persistence/cleanup.
custom_components/nodered/version.py Loads runtime version from manifest.json as the source of truth.
custom_components/nodered/utils.py Adds helpers to detect announced contrib version and gate presence-available semantics.
custom_components/nodered/sensor.py Sets default availability for discovery-without-state under presence-available gating; preserves values on availability-only updates.
custom_components/nodered/binary_sensor.py Adds omitted-state handling to preserve prior state; applies presence-available discovery behavior.
custom_components/nodered/manifest.json Bumps integration version to 4.2.4.
custom_components/nodered/entity.py Updates base attribute/availability update semantics for legacy vs presence-available behavior.
custom_components/nodered/const.py Introduces CONF_AVAILABLE / CONF_CONTRIB_VERSION constants.

Comment on lines 73 to +77
else:
self._attr_native_value = None
# No reading yet: unavailable once presence-available applies
if contrib_supports_presence_available(hass):
self._attr_available = False

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

See below.

Comment on lines +75 to +81
if CONF_STATE in config:
self._attr_is_on = self._evaluate_sensor_state(config[CONF_STATE])
else:
self._attr_is_on = None
# No reading yet: unavailable once presence-available applies
if contrib_supports_presence_available(hass):
self._attr_available = False

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The issue only arises as a bit of an edge-case when "Resend state, available, and attributes" is set on: create entity -> set available (HA state now unknown/available) -> HA restart -> resend happens without state -> HA state now unknown/unavailable.

I agree it's a bit inconsistent, but it's a very edge case. Discovery without state still defaults to unavailable on purpose (avoid available+unknown on first deploy / empty rediscovery). Availability-only updates after the entity exists already honor available and keep the last reading.

I don't think we should change this for this case, but if we were it would be to disallow setting available to false for resend sensors that have never had a value.

Comment on lines +220 to +222
vol.Optional(CONF_STATE): vol.Any(bool, str, int, float, None),
vol.Optional(CONF_ATTRIBUTES): dict,
vol.Optional(CONF_AVAILABLE): bool,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The non-sensor entities can't have this yet, they haven't been updated with the new code.

@Swamp-Ig

Copy link
Copy Markdown
Contributor Author

@zachowj could you kindly turn off forced copilot reviews? I have a pretty limited credits.
Settings -> Rules -> Rulesets -> Default -> uncheck “Automatically request Copilot code review”

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.

2 participants