Two comments asserted an entity id that has never existed

mqtt.py said the P1 age entity "must be exactly sensor.p1_sample_age_s,
because SAFETY-01's firmware watchdog subscribes to that literal id", and
main.py:340 repeated it. Both are wrong, and wrong in the direction that
disarms a safety layer.

On HA 2026.8 object_id in a discovery payload does not determine entity_id.
HA composes it from the device name plus the entity name, so this one is
sensor.goodwe_p1_sample_age. That is what the firmware subscribes to, that is
what exists on the live system (verified 2026-08-26), and the firmware's own
comment records that sensor.p1_sample_age_s never existed on any HA.

The hazard is not the stale name itself, it is that two shipped artefacts
disagreed about a safety-critical id while sounding certain. A reader who
trusted these comments would have "corrected" the firmware to a name that
resolves to nothing - and the failure is silent, because has_state() simply
stays false forever and the ingest guard never arms. The firmware calls that
out as the shape that FAILS SILENTLY AND LOOKS CORRECT.

The comment now says what actually determines the id, and states plainly that
renaming the device or the entity's friendly name changes the composed id and
disarms the guard. It also cross-references TEL-06, since the guard reads this
sensor's value rather than its arrival and so cannot fire for a dead publisher.

Found in a backlog audit, as the substance behind PKG-02's premise: the real
coupling between firmware and add-on is names, not versions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Du77usMj8XNKNFZGmUiWDa
This commit is contained in:
glenn schrooyen
2026-08-27 23:48:40 +02:00
co-authored by Claude Opus 5
parent c70239cac2
commit 80ebb96e7d
2 changed files with 28 additions and 8 deletions
+2 -1
View File
@@ -337,7 +337,8 @@ class Controller:
"status": "running" if self.auto else "stopped", "status": "running" if self.auto else "stopped",
} }
# ⚠️ ONLY when P1 ingestion is actually running. The ESP32's stale-input # ⚠️ 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 # 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 # ingester feeding it, so published_age_s would be time-since-startup
# climbing without bound - i.e. every existing install would cross the # climbing without bound - i.e. every existing install would cross the
+26 -7
View File
@@ -45,13 +45,32 @@ SENSORS = [
("soc", "goodwe_battery_soc", "Battery SoC", "%", "battery", "measurement", None), ("soc", "goodwe_battery_soc", "Battery SoC", "%", "battery", "measurement", None),
("phase", "goodwe_maintenance_phase", "Maintenance phase", None, None, None, "mdi:battery-sync"), ("phase", "goodwe_maintenance_phase", "Maintenance phase", None, None, None, "mdi:battery-sync"),
("status", "goodwe_controller_status", "Controller status", None, None, None, "mdi:heart-pulse"), ("status", "goodwe_controller_status", "Controller status", None, None, None, "mdi:heart-pulse"),
# ⚠️ This one deliberately breaks the goodwe_ prefix above: the entity id # ⚠️ THE LIVE ENTITY IS `sensor.goodwe_p1_sample_age`, NOT what this
# must be exactly `sensor.p1_sample_age_s`, because SAFETY-01's firmware # object_id spells. An earlier version of this comment said the id "must be
# watchdog subscribes to that literal id and the ENV-01 simulation rig # exactly sensor.p1_sample_age_s" - that name has never existed on any HA,
# asserts on it. Renaming it silently disarms a safety layer. It is seconds # and believing it is how a safety layer gets disarmed by someone tidying up.
# 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 # On HA 2026.8 `object_id` in a discovery payload does NOT determine the
# false-trip that this entity exists to remove. # 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), ("p1_age", "p1_sample_age_s", "P1 sample age", "s", "duration", "measurement", None),
] ]