diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 2d23337..b0bb234 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -337,7 +337,8 @@ class Controller: "status": "running" if self.auto else "stopped", } # ⚠️ ONLY when P1 ingestion is actually running. The ESP32's stale-input - # watchdog subscribes to sensor.p1_sample_age_s and forces the layer-1 + # watchdog subscribes to sensor.goodwe_p1_sample_age - see the entity-id + # note in mqtt.py; the composed name is not the object_id - and forces layer-1 # failsafe once it reaches max_age_s. With meter_source off there is no # ingester feeding it, so published_age_s would be time-since-startup # climbing without bound - i.e. every existing install would cross the diff --git a/goodwe_controller/app/mqtt.py b/goodwe_controller/app/mqtt.py index c91d94c..7d6c807 100644 --- a/goodwe_controller/app/mqtt.py +++ b/goodwe_controller/app/mqtt.py @@ -45,13 +45,32 @@ SENSORS = [ ("soc", "goodwe_battery_soc", "Battery SoC", "%", "battery", "measurement", None), ("phase", "goodwe_maintenance_phase", "Maintenance phase", None, None, None, "mdi:battery-sync"), ("status", "goodwe_controller_status", "Controller status", None, None, None, "mdi:heart-pulse"), - # ⚠️ This one deliberately breaks the goodwe_ prefix above: the entity id - # must be exactly `sensor.p1_sample_age_s`, because SAFETY-01's firmware - # watchdog subscribes to that literal id and the ENV-01 simulation rig - # asserts on it. Renaming it silently disarms a safety layer. It is seconds - # since the newest accepted P1 telegram, republished every second so that a - # meter frozen at a constant value still shows a climbing age - which is the - # false-trip that this entity exists to remove. + # ⚠️ THE LIVE ENTITY IS `sensor.goodwe_p1_sample_age`, NOT what this + # object_id spells. An earlier version of this comment said the id "must be + # exactly sensor.p1_sample_age_s" - that name has never existed on any HA, + # and believing it is how a safety layer gets disarmed by someone tidying up. + # + # On HA 2026.8 `object_id` in a discovery payload does NOT determine the + # entity_id. HA composes it from the device name plus the entity name: + # "GoodWe RS485 Controller" + "P1 sample age" -> sensor.goodwe_p1_sample_age. + # Verified against the live system 2026-08-26; the firmware subscribes to + # that composed name (goodwe-master-stage4-failsafe.yaml, homeassistant + # sensor p1_age_s), and its own comment records that sensor.p1_sample_age_s + # never existed. + # + # So: do NOT "fix" the firmware to match the object_id below, and do not + # rename the device or this entity's friendly name - either changes the + # composed id and silently disarms the ingest guard, because has_state() + # simply stays false forever and nothing reports it. The firmware calls this + # out as the failure that "FAILS SILENTLY AND LOOKS CORRECT". + # + # The value: seconds since the newest accepted P1 telegram, republished + # every second so a meter frozen at a constant value still shows a climbing + # age - the false-trip this entity exists to remove. + # + # ⚠️ Separately, and not fixed here: the firmware's ingest guard tests this + # sensor's VALUE rather than its arrival, so a dead publisher freezes the + # number and reads permanently fresh. Filed as TEL-06. ("p1_age", "p1_sample_age_s", "P1 sample age", "s", "duration", "measurement", None), ]