From ed9a59e5dc3fe3130fc7e09ab486631593807525 Mon Sep 17 00:00:00 2001 From: Marc Date: Sat, 8 Aug 2026 11:42:39 -0700 Subject: [PATCH] fix: report a pump as running from its telemetry, not its STATUS The PUMP binary sensor treats STATUS == "10" as running. On both of my PUMP/VSF pumps STATUS sits at "10" whether or not the pump is turning, so both sensors read on permanently. At one moment the idle spa jets pump reports STATUS 10 with RPM 0, PWR 0 and GPM 0 while the filter pump reports STATUS 10 with RPM 3068, PWR 1300 and GPM 53. The controller never pushes STATUS for a pump either, only RPM, PWR and GPM, so a STATUS-keyed sensor is not re-evaluated when a pump starts or stops. PumpBinarySensor derives is_on from whichever of RPM, PWR and GPM the pump publishes and keys isUpdated on the same attributes. A pump that publishes none of them keeps the STATUS comparison. The unique_id is unchanged, so existing entities carry over. --- .../intellicenter/binary_sensor.py | 67 +++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/custom_components/intellicenter/binary_sensor.py b/custom_components/intellicenter/binary_sensor.py index 9d9227b..a997ca9 100644 --- a/custom_components/intellicenter/binary_sensor.py +++ b/custom_components/intellicenter/binary_sensor.py @@ -9,13 +9,24 @@ ) from custom_components.intellicenter.water_heater import HEATER_ATTR, HTMODE_ATTR -from homeassistant.components.binary_sensor import BinarySensorEntity +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, +) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from . import PoolEntity from .const import DOMAIN -from .pyintellicenter import STATUS_ATTR, ModelController, PoolObject +from .pyintellicenter import ( + GPM_ATTR, + PUMP_TYPE, + PWR_ATTR, + RPM_ATTR, + STATUS_ATTR, + ModelController, + PoolObject, +) _LOGGER = logging.getLogger(__name__) @@ -60,8 +71,8 @@ async def async_setup_entry( extraStateAttributes={"VACFLO"}, ) ) - elif obj.objtype == "PUMP": - sensors.append(PoolBinarySensor(entry, controller, obj, valueForON="10")) + elif obj.objtype == PUMP_TYPE: + sensors.append(PumpBinarySensor(entry, controller, obj)) async_add_entities(sensors) @@ -89,6 +100,54 @@ def is_on(self): return self._poolObject[self._attribute_key] == self._valueForON +# ------------------------------------------------------------------------------------- + +# Real time telemetry a variable speed pump publishes while it turns, most to least +# reliable. A pump that publishes none of these has only STATUS to go on. +PUMP_ACTIVITY_ATTRS = (RPM_ATTR, PWR_ATTR, GPM_ATTR) + + +class PumpBinarySensor(PoolEntity, BinarySensorEntity): + """Representation of a Pentair pump, on while it is actually running.""" + + _attr_device_class = BinarySensorDeviceClass.RUNNING + + def __init__( + self, + entry: ConfigEntry, + controller: ModelController, + poolObject: PoolObject, + **kwargs, + ): + """Initialize.""" + super().__init__(entry, controller, poolObject, **kwargs) + self._activityAttrs = [ + attr for attr in PUMP_ACTIVITY_ATTRS if poolObject[attr] is not None + ] + + @property + def is_on(self): + """Return true if the pump is running.""" + if not self._activityAttrs: + # Single speed pumps report no telemetry, so STATUS is all we have. + return self._poolObject[STATUS_ATTR] == self._poolObject.onStatus + for attr in self._activityAttrs: + try: + if float(self._poolObject[attr]) > 0: + return True + except (TypeError, ValueError): + continue + return False + + def isUpdated(self, updates: dict[str, dict[str, str]]) -> bool: + """Return true if the entity is updated by the updates from Intellicenter.""" + + keys = updates.get(self._poolObject.objnam, {}).keys() + if not self._activityAttrs: + return STATUS_ATTR in keys + return bool(set(self._activityAttrs) & keys) + + # -------------------------------------------------------------------------------------