updates to evse

This commit is contained in:
2026-05-09 11:34:26 -04:00
parent 8c7b5fb711
commit df3fb3466a
3 changed files with 75 additions and 26 deletions

View File

@@ -292,19 +292,18 @@ def decode_modbus_response(frame: ModbusFrame) -> dict[str, Any]:
# live probing of a single pack. See ../NOTES.md "Register map" section.
# High-confidence fields promoted to named entities; unknowns (reg 32, 35,
# 38-40, 43-45) still emitted as register_NN for correlation.
_WARNING_BITS = [
"pack_ov", "cell_ov", "pack_uv", "cell_uv",
"charge_oc", "discharge_oc", "temp_anomaly", "mos_ot",
"charge_ot", "discharge_ot", "charge_ut", "discharge_ut",
"low_capacity", "other_error",
]
_PROTECTION_BITS = [
"pack_ov", "cell_ov", "pack_uv", "cell_uv",
"charge_oc", "discharge_oc", "temp_anomaly", "mos_ot",
"charge_ot", "discharge_ot", "charge_ut", "discharge_ut",
"float_stopped", "discharge_sc",
]
#
# regs 33 and 34 USED to decode as warning_* / protection_* bitfields here,
# per the lv_host.app UI display order. That mapping was wrong: live probe
# (2026-05-09, all 3 packs) showed reg33 == reg34 always, with both halves
# of each register equal to the byte value of reg20 (temperature_03):
# pack 1/2 temp_03 = 19 (0x13) → reg33 = reg34 = 0x1313
# pack 3 temp_03 = 18 (0x12) → reg33 = reg34 = 0x1212
# i.e. the "alarms that flipped between packs" were just a 1 °C ambient
# difference, decoded as if the temperature byte were a 14-bit alarm mask.
# The real alarm word is reg35 (error_code), already exposed and = 0 on
# healthy packs. Don't re-add reg33/34 as alarms without first confirming
# they break out of the temp-mirror pattern under a real fault condition.
def _signed16(v: int) -> int:
@@ -357,13 +356,10 @@ def decode_eg4_modbus_regs(regs: list[int], expose_raw: bool = False) -> dict[st
# --- max charge/discharge current limit (reg 31), A ---
out["max_current_limit"] = round(regs[31] / 100.0, 2)
# --- bitfields: warnings (reg 33), protections (reg 34), error code (reg 35) ---
warn = regs[33]
for i, name in enumerate(_WARNING_BITS):
out[f"warning_{name}"] = "on" if (warn >> i) & 1 else "off"
prot = regs[34]
for i, name in enumerate(_PROTECTION_BITS):
out[f"protection_{name}"] = "on" if (prot >> i) & 1 else "off"
# --- error / alarm word (reg 35) ---
# reg 33/34 used to decode as warning_/protection_ bitfields but were
# actually mirroring a temperature byte — see the file-header comment.
# reg 35 is the canonical alarm word; 0 on healthy packs.
out["error_code"] = regs[35]
# --- static-ish (regs 36, 37) ---
@@ -706,12 +702,6 @@ _FIELD_META.update({
"firmware_version": (None, None, None, "mdi:chip"),
"firmware_date": (None, None, None, "mdi:calendar"),
})
for _name in _WARNING_BITS:
_FIELD_META[f"warning_{_name}"] = (None, None, None, "mdi:alert")
for _name in _PROTECTION_BITS:
_FIELD_META[f"protection_{_name}"] = (None, None, None, "mdi:shield-alert")
def field_meta(key: str) -> tuple[str | None, str | None, str | None, str | None]:
if key.startswith("register_"):
return (None, None, "measurement", "mdi:numeric")