Skip to content

Add Z-Wave battery low event entity#170111

Draft
TheJulianJES wants to merge 6 commits into
home-assistant:devfrom
TheJulianJES:tjj/zwave_battery_low_entity_2
Draft

Add Z-Wave battery low event entity#170111
TheJulianJES wants to merge 6 commits into
home-assistant:devfrom
TheJulianJES:tjj/zwave_battery_low_entity_2

Conversation

@TheJulianJES
Copy link
Copy Markdown
Member

@TheJulianJES TheJulianJES commented May 8, 2026

DRAFT + untested; Read the paragraph below.

Proposed change

This adds a new "Battery low" event entity for every Z-Wave node with the Battery CC. It triggers when a "Battery low" notification is sent. Unfortunately, I don't think this can currently be implemented in a clean way using the existing discovery schemas, as these notifications are not value-based, so the approach is similar to the node-based firmware update entities.

I'd really appreciate any suggestions or feedback here, or whether this approach is generally ok.

AI summary

Adds an event entity to the Z-Wave integration that fires when a node sends a Battery CC "battery low" notification, and forwards the same notification to the existing zwave_js_notification bus event so it can be used in automation triggers.

Background:

  • zwave-js#7984 reworked Battery CC battery low handling. Instead of persisting a stale stateful isLow value, Z-Wave JS now emits a node-level notification event with eventType: "battery low" and an urgency field (Soon / Now).
  • zwave-js-server-python#1365 added the BatteryNotification model and a BatteryReplacementStatus enum so HA can consume this directly.

This PR builds on those upstream changes:

  • Adds ZWaveBatteryLowEventEntity, a diagnostic event entity created per non-controller node that supports the Battery CC. Wired up via the same dispatcher signal pattern used for other node-level entities (ZWaveFirmwareUpdateEntity, ZWaveNodePingButton, ZWaveNodeStatusSensor, …).
    • event_types are soon and now, matching the urgency levels actually emitted upstream.
    • Each Battery CC notification triggers the entity with event_type set to the urgency name and urgency (the integer value) exposed as a state attribute.
  • Forwards BatteryNotification through the existing async_on_notification handler so the zwave_js_notification bus event also fires for Battery CC, with command_class_name: "Battery", event_type ("battery low") and urgency. New ATTR_URGENCY constant.
  • Adds translations for the new entity and the urgency states.
  • Adds tests covering entity creation, both urgency levels, that non-Battery notifications are ignored, that the entity is removed on reinterview, and that the Battery CC notification is forwarded on the zwave_js_notification bus event.

Notes:

  • The existing (CommandClass.BATTERY, "isLow") binary sensor mapping is kept for now, as older Z-Wave JS versions expose isLow.
    • Note: The Z-Wave JS version shipped with the official addon removed this a long time ago, so we can probably just remove it in a follow-up PR.
  • One entity per node (not per endpoint). Battery CC is in practice on the root endpoint; the entity reacts to whichever endpoint emits the notification.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

Checklist

  • I understand the code I am submitting and can explain how it works.
  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.
  • Any generated code has been carefully reviewed for correctness and compliance with project standards.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies a diff between library versions and ideally a link to the changelog/release notes is added to the PR description.

To help with the load of incoming pull requests:

Adds handling for the new BatteryNotification type from
zwave-js-server-python, so that Battery CC battery low notifications
fire the existing zwave_js_notification bus event with the event_type
("battery low") and urgency level included.
Adds a diagnostic event entity per battery-powered node that fires
when the device sends a Battery CC battery low notification. The
event_type reflects the urgency reported by the device (soon vs. now,
mapped from BatteryReplacementStatus), and the raw urgency value is
exposed as a state attribute.
zwave-js only ever emits a Battery CC `notification` event with urgency
of `Soon` or `Now` (the upstream handler falls back to `Soon` if the
device omits `rechargeOrReplace`), so guarding against `NO` was dead
code. Drop the check and its test.
Annotate the `client` fixture parameter as `MagicMock` to match the
project convention for typing test parameters.
The entity is dispatched from async_on_node_ready, which also runs on
reinterviews. Without listening for the
remove_entity_on_interview_started signal, a reinterview either tries
to add a duplicate unique ID (when Battery CC is still present) or
leaves a stale entity behind (when Battery CC is no longer reported).
Mirror the firmware update entity by subscribing to the
interview-started removal signal so the entity is rebuilt cleanly each
interview.
Copilot AI review requested due to automatic review settings May 8, 2026 12:11
@home-assistant home-assistant Bot added cla-signed has-tests integration: zwave_js new-feature Top 100 Integration is ranked within the top 100 by usage Top 200 Integration is ranked within the top 200 by usage by-code-owner Quality Scale: No score labels May 8, 2026
@home-assistant
Copy link
Copy Markdown
Contributor

home-assistant Bot commented May 8, 2026

Hey there @home-assistant/z-wave, mind taking a look at this pull request as it has been labeled with an integration (zwave_js) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of zwave_js can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant mark-draft Mark the pull request as draft.
  • @home-assistant ready-for-review Remove the draft status from the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign zwave_js Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant update-branch Update the pull request branch with the base branch.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) on the pull request.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 Z-Wave JS integration with a new diagnostic event entity that fires when a node reports a Battery CC “battery low” notification, and it also forwards those Battery CC notifications onto the existing zwave_js_notification bus event for automations.

Changes:

  • Add ZWaveBatteryLowEventEntity (per non-controller node with Battery CC) and wire it up via dispatcher-based node entity creation/removal signals.
  • Forward BatteryNotification through async_on_notification and include a new ATTR_URGENCY field in the fired zwave_js_notification event payload.
  • Add base translations and new tests covering entity creation, triggering for both urgency levels, ignoring non-battery notifications, and entity removal on reinterview.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/components/zwave_js/test_event.py Adds coverage for the new per-node “Battery low” event entity behavior and lifecycle.
homeassistant/components/zwave_js/strings.json Adds translated name and event_type state text for the new event entity.
homeassistant/components/zwave_js/event.py Implements the new ZWaveBatteryLowEventEntity and dispatcher hook to add it per eligible node.
homeassistant/components/zwave_js/const.py Introduces ATTR_URGENCY constant for the new notification payload/attributes.
homeassistant/components/zwave_js/__init__.py Dispatches creation of the battery-low event entity on node-ready and forwards BatteryNotification via zwave_js_notification.

Comment thread homeassistant/components/zwave_js/__init__.py
Mirror test_power_level_notification with a Battery CC case to cover
the new BatteryNotification branch in async_on_notification, asserting
that command_class_name, event_type, and urgency are forwarded on the
zwave_js_notification bus event.
Comment on lines +833 to +840
if not node.is_controller_node and any(
cc.id == CommandClass.BATTERY.value for cc in node.command_classes
):
async_dispatcher_send(
self.hass,
f"{DOMAIN}_{self.config_entry.entry_id}_add_battery_low_event_entity",
node,
)
Copy link
Copy Markdown
Member

@MartinHjelmare MartinHjelmare May 8, 2026

Choose a reason for hiding this comment

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

I suggest we do a refactor first, in a separate PR, and introduce a node discovery feature with node discovery schemas, a node discovery handler that forwards the discovery info to the correct platform, and a node base entity class that has the common features that node based entities share.

Most of the current node based entities (ping button, controller status sensor, node status sensor, statistics sensor, firmware update) seem to have almost the same base features.

Comment on lines +1002 to +1009
if isinstance(notification, BatteryNotification):
event_data.update(
{
ATTR_COMMAND_CLASS_NAME: "Battery",
ATTR_EVENT_TYPE: notification.event_type,
ATTR_URGENCY: notification.urgency,
}
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be a separate PR, I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

by-code-owner cla-signed has-tests integration: zwave_js new-feature Quality Scale: No score Top 100 Integration is ranked within the top 100 by usage Top 200 Integration is ranked within the top 200 by usage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add proper support for Battery CC "battery low" notification

3 participants