Skip to content

Base valve platform - #909

Merged
puddly merged 5 commits into
zigpy:devfrom
puddly:puddly/valve-platform4
Sep 28, 2026
Merged

puddly merged 5 commits into
zigpy:devfrom
puddly:puddly/valve-platform4

Conversation

@puddly

@puddly puddly commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Supersedes #673, which has gotten stale and needed a rewrite to account for the current ZHA APIs.

As with the other new platforms, this is only an abstract base. Device support will need to be implemented in https://github.com/zigpy/zha-device-handlers/. The ZCL spec doesn't have a concept of valves (only OnOff and LevelControl clusters without a distinguishing device type) so this platform cannot participate in ZCL discovery.


Architecturally, the ZCL OnOff cluster has a safety feature that I think HA Core would really benefit from: on_with_timed_off. Feel free to express your support in my architecture proposal, the more the better 😄: home-assistant/architecture#1491

Copilot AI lite review requested due to automatic review settings September 28, 2026 17:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

A critical primary-entity election issue remains unresolved.

Review effort: Lite
Findings: 1 High severity

Open (1)
What changed in this PR

Adds an abstract ZHA valve platform API for future device-handler implementations.

Changes:

  • Defines valve classes and feature flags.
  • Adds base valve state and control interfaces.
  • Adds tests for valve behavior and capabilities.
File Summary
zha/​application/​platforms/​valve/​const.py Valve constants and feature flags
zha/​application/​platforms/​valve/​__init__.py Abstract valve entity implementation
tests/​test_platform_valve.py Valve state and capability tests

Blocking issue: BaseValve needs a positive primary weight so valve-only devices can elect a primary entity.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread zha/application/platforms/valve/__init__.py
@codecov

codecov Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.21%. Comparing base (939b2b3) to head (9e9ea95).
⚠️ Report is 1 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #909      +/-   ##
==========================================
+ Coverage   97.19%   97.21%   +0.01%     
==========================================
  Files          57       59       +2     
  Lines       10561    10617      +56     
==========================================
+ Hits        10265    10321      +56     
  Misses        296      296              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@zigpy-review-bot zigpy-review-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good — a clean abstract base whose state and constants line up with HA's ValveEntity, following the same shape as the event base from #864. Nothing blocking; a few optional suggestions for the subclass API below.

Optional

  • Position-reporting valves have to re-implement things HA derives from the position. is_closed, async_open_valve and async_close_valve are all abstract, but HA computes the closed state from current_valve_position == 0 whenever reports_position is set, and routes open/close to async_set_valve_position(100/0) whenever SET_POSITION is supported. HA's async_toggle still reads is_closed, though, so a positional subclass that leaves it None (as FakePositionValve does — current_position=40 alongside is_closed=None) gets a toggle that ignores the actual position. Consider concrete defaults in BaseValve for those cases (is_closed → None if the position is unknown, else position == 0, when reports_position is set; open/close → async_set_valve_position(100/0) when SET_POSITION is supported), still overridable. An is_closed assertion in test_position_valve_state would cover it.
  • Nothing ties the advertised capabilities to the implementation: a subclass can set SET_POSITION / STOP without overriding the matching method (surfaces as NotImplementedError on the first service call), or reports_position = True without overriding current_valve_position (the valve stays unknown in HA). This matches HA's own base class, so it's a judgment call, but a constructor check — like the doorbell ring guard BaseEvent.__init__ got in #864 — would catch quirk mistakes at entity creation instead of at runtime.
  • Question: _attr_primary_weight = 10 ties with the default Switch on the OnOff cluster (also 10), and a tie elects no primary entity (Device._compute_primary_entity). Is the expectation that valve quirks always suppress the default switch (or set _attr_primary / a different weight)? If so, that's worth a line in the base class docstring for quirk authors.
  • Nit: #864 also added event to the platform imports and Platform.EVENT to PLATFORMS in zha/application/discovery.py. PLATFORMS has no consumer in zha or HA core and the base registers no entities, so this is consistency only.

Note: HA's zha integration has no valve platform yet, so valve entities created by quirks won't show up in HA until a paired core change adds a valve platform (an adapter like the existing cover.py) to the ZHA integration. This is expected for a base-only PR, as with event (home-assistant/core#183109).

Verified (5 checks)
  • ValveDeviceClass / ValveEntityFeature values match HA's homeassistant/components/valve/const.py exactly (water/gas; 1/2/4/8); ValveEntityState fields map onto ValveEntity's properties.
  • Platform.VALVE already exists in zha/application/__init__.py; the base registers no entities, so there's no discovery or diagnostics-snapshot impact.
  • tests/test_platform_valve.py passes locally; mypy (worktree venv with real deps) and ruff are clean; CI is green, and Codecov reports all modified lines as covered.
  • Copilot's primary-weight thread is addressed by 9e9ea95 (_attr_primary_weight = 10, same as cover, fan, light, switch and climate).
  • No overlapping open zha PRs; #673 (superseded) is closed.

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.

4 participants