Skip to content

fix: let a water heater's state be its operation mode - #40

Open
hacctarr wants to merge 1 commit into
dwradcliffe:mainfrom
hacctarr:fix/water-heater-state-contract
Open

fix: let a water heater's state be its operation mode#40
hacctarr wants to merge 1 commit into
dwradcliffe:mainfrom
hacctarr:fix/water-heater-state-contract

Conversation

@hacctarr

Copy link
Copy Markdown

Problem

PoolWaterHeater overrides state to return on / idle / off. WaterHeaterEntity.state is defined to return current_operation:

https://github.com/home-assistant/core/blob/dev/homeassistant/components/water_heater/__init__.py

@property
def state(self) -> str | None:
    """Return the current state."""
    return self.current_operation

Because the override's return values are never members of operation_list, the frontend's water-heater-operation-modes tile feature cannot resolve a selection. It builds its options from operation_list but takes the selected value from the entity state:

_getValue(t){return t.state}
_getOptions(){ ... this._stateObj.attributes.operation_list ... }

So the active heater never highlights when one is assigned, while an unheated body matches the literal off option and highlights correctly. The control reads as inverted: the body that is heating shows nothing selected, and the body that is not shows a selection.

Two bodies on the same controller, before this change:

entity state operation_mode operation_list highlights
water_heater.spa on MasterTemp ['off', 'MasterTemp'] nothing
water_heater.pool off off ['off', 'MasterTemp'] off

Why removing the override loses nothing

HeaterBinarySensor already publishes exactly the predicate the override encoded, against the same three attributes:

if (
    body[STATUS_ATTR] == "ON"
    and body[HEATER_ATTR] == self._poolObject.objnam
    and body[HTMODE_ATTR] != "0"
):

STATUS and HTMODE also stay exposed as entity attributes via extraStateAttributes, so nothing has to be recomputed to recover the old value. The former idle case (heater assigned, not currently firing) is now the operation mode reading as the heater's name while that binary sensor reads off.

This also follows the approach suggested in #11 for the closely related manual-heat case: put "the heater is actually firing" in a binary sensor rather than in the water heater's state.

Verification

Live against an IntelliCenter with one MasterTemp shared between a pool and a spa body, spa heating at the time (Status: ON, HEATER: H0001, HTMODE: 6).

After:

entity state operation_mode heater binary sensor
water_heater.spa MasterTemp MasterTemp on
water_heater.pool off off on (shared heater, other body)

Both tiles now highlight their active mode, and the firing signal is unchanged. No new errors from the integration in the log after reload.

Breaking change

Automations that test a water_heater entity for the states on or idle need to move to the heater's binary sensor. Tests for off are unaffected, since an unassigned body already returned off from both the override and current_operation.

Note on #25

If the migration to climate entities in #25 lands, it supersedes this. This is a small fix for the entities that exist today and should be easy to drop later.

WaterHeaterEntity.state returns current_operation. PoolWaterHeater
overrode it to return on/idle/off, values that are never members of
operation_list, so the frontend's water-heater-operation-modes feature
could not resolve a selection: it reads the entity state and matches it
against operation_list. The active heater therefore never highlighted
whenever one was assigned, while an unheated body highlighted "off"
correctly, which reads as the control being backwards.

Nothing is lost by removing the override. HeaterBinarySensor already
publishes the same predicate the override encoded (body ON, heater
assigned to this body, HTMODE non-zero), and STATUS and HTMODE remain
exposed as attributes on the entity. The former "idle" case is now the
operation mode reading as the heater's name while that binary sensor
reads off.

BREAKING CHANGE: automations that test a water_heater entity for the
states "on" or "idle" need to move to the heater's binary sensor.
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