A raw key, a bare number, and two columns of dashes

Switch the control mode to the Anker cloud and the charging cards still read as
though they were built for Modbus. Three separate causes, and none of them was
the shared layout — the cards already branch on the control mode in sixteen
places, which is why the address fields, the reset button and the skip-delay
button each appear only under the transport that has them.

The loudest was a missing string. The cloud transport arrived with three keys the
templates call and the language files never got: cloudNote, cloudLocalFound and
skipDelay. A key missing from English returns itself, deliberately, so that a gap
shows up in the UI instead of rendering as a blank — and it did, as
"charging.control.cloudNote" sitting in the connection card where a sentence
belongs. All three are added, in both surfaces and all three languages, so the
Phone App is not left showing the same raw key.

The second was an enum wearing one name over two transports. Modbus register
20087 reports the phase mode as 1 single-phase or 3 three-phase; the cloud's own
field reports 0 automatic or 1 single-phase. Only phaseMode1 and phaseMode3 had
labels, so a cloud charger sitting on automatic rendered "Running on 0" — the
enum fell back to printing the number, which is the right fallback and the wrong
answer. phaseMode0 is added. Worth naming the shape of this one: it is the same
collision that made the cloud's d9 field wrong when it was called chargingMode
after the register at 20088, and a third transport reporting a 3 that means
something else would break it again.

The third was honest but useless. Reactive and apparent power are registers of
their own and the cloud has no message carrying either, so over that transport
those two columns could only ever be three dashes each. They now appear when the
charger actually reports them, which also tidies up a Modbus charger whose
firmware leaves them out.

The layout stays shared. A value both transports report should keep one name and
one row, and what each transport can be told still branches where it has to.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tajniak81
2026-09-02 20:22:50 +02:00
co-authored by Claude Opus 5
parent 90558d60b2
commit 1dc20461de
8 changed files with 49 additions and 8 deletions
+12 -4
View File
@@ -1900,8 +1900,8 @@ class _HomeTabState extends State<_HomeTab> {
_th(context, t("charging.modbus.voltage")),
_th(context, t("charging.modbus.current")),
_th(context, t("charging.modbus.activePower")),
_th(context, t("charging.modbus.reactivePower")),
_th(context, t("charging.modbus.apparentPower")),
if (_phasesHaveVA(s)) _th(context, t("charging.modbus.reactivePower")),
if (_phasesHaveVA(s)) _th(context, t("charging.modbus.apparentPower")),
]),
for (final row in phases)
TableRow(children: [
@@ -2095,6 +2095,13 @@ class _HomeTabState extends State<_HomeTab> {
]);
}
/// Reactive and apparent power are registers of their own, and the cloud has
/// no message carrying either — so on that transport the two columns could
/// only ever be three dashes each. They appear when the charger actually
/// reports them, which also covers a Modbus charger that leaves them out.
bool _phasesHaveVA(ChargerStatus s) => [1, 2, 3]
.any((n) => s.raw["reactiveL$n"] != null || s.raw["apparentL$n"] != null);
/// The per-phase matrix, or nothing at all when the charger reported none of
/// it. A cell with no reading is a dash, so the columns still line up.
List<List<String>> _phaseRows(ChargerStatus s) {
@@ -2102,6 +2109,7 @@ class _HomeTabState extends State<_HomeTab> {
v == null ? "" : "${v.toStringAsFixed(digits)} $unit";
final any = ["voltageL1", "currentL1", "powerL1"].any((k) => s.raw[k] != null);
if (!any) return const [];
final va = _phasesHaveVA(s);
return [
for (final n in [1, 2, 3])
[
@@ -2109,8 +2117,8 @@ class _HomeTabState extends State<_HomeTab> {
cell(s.number("voltageL$n"), 1, "V"),
cell(s.number("currentL$n"), 2, "A"),
cell(s.number("powerL$n"), 0, "W"),
cell(s.number("reactiveL$n"), 0, "var"),
cell(s.number("apparentL$n"), 0, "VA"),
if (va) cell(s.number("reactiveL$n"), 0, "var"),
if (va) cell(s.number("apparentL$n"), 0, "VA"),
],
];
}