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",
}
# ⚠️ 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
+26 -7
View File
@@ -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),
]