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:
co-authored by
Claude Opus 5
parent
90558d60b2
commit
1dc20461de
@@ -159,6 +159,9 @@
|
||||
"forgetAddress": "Glem",
|
||||
"forgetAddressConfirm": "Glem laderens lokale adresse? Styring over det lokale netværk stopper, indtil du indtaster den igen.",
|
||||
"boost": "Boost denne session",
|
||||
"skipDelay": "Spring startforsinkelsen over",
|
||||
"cloudNote": "Der er intet at sætte op her: Anker-kontoen er legitimationen, og den indtastes i Indstillinger. Kommandoer sendes over den forbindelse, laderen i forvejen holder åben til Anker.",
|
||||
"cloudLocalFound": "Denne lader oplyser sin egen lokale adresse som {address}. Skift kontroltilstand til Modbus TCP for at bruge den.",
|
||||
"modbusHint": "Indtast laderens adresse på dette netværk og gem den. Laderen skal være tændt og på samme netværk som DriverVault."
|
||||
},
|
||||
"modbus": {
|
||||
@@ -207,6 +210,7 @@
|
||||
"mqttLink": "MQTT",
|
||||
"alarmWord": "Ord {n}",
|
||||
"alarmsHint": "Laderen melder en alarm. Anker offentliggør ikke, hvad de enkelte bit betyder, så ordene vises, som de kommer.",
|
||||
"phaseMode0": "Automatisk",
|
||||
"phaseMode1": "Enfaset",
|
||||
"phaseMode3": "Trefaset",
|
||||
"phaseSet0": "Automatisk",
|
||||
|
||||
@@ -159,6 +159,9 @@
|
||||
"forgetAddress": "Forget",
|
||||
"forgetAddressConfirm": "Forget this charger's local address? Control over the local network stops until you enter it again.",
|
||||
"boost": "Boost this session",
|
||||
"skipDelay": "Skip the start delay",
|
||||
"cloudNote": "Nothing to set up here: the Anker account is the credential, and it is entered in Settings. Commands travel over the connection the charger already holds open to Anker.",
|
||||
"cloudLocalFound": "This charger reports its own local address as {address}. Switch the control mode to Modbus TCP to use it.",
|
||||
"modbusHint": "Enter the charger's address on this network and save it. The charger must be powered on and on the same network as DriverVault."
|
||||
},
|
||||
"modbus": {
|
||||
@@ -207,6 +210,7 @@
|
||||
"mqttLink": "MQTT",
|
||||
"alarmWord": "Word {n}",
|
||||
"alarmsHint": "The charger reports an alarm. Anker does not publish what the individual bits mean, so the words are shown as they arrive.",
|
||||
"phaseMode0": "Automatic",
|
||||
"phaseMode1": "Single-phase",
|
||||
"phaseMode3": "Three-phase",
|
||||
"phaseSet0": "Automatic",
|
||||
|
||||
@@ -161,6 +161,9 @@
|
||||
"forgetAddress": "Zapomnij",
|
||||
"forgetAddressConfirm": "Zapomnieć lokalny adres tej ładowarki? Sterowanie przez sieć lokalną przestanie działać, dopóki nie wpiszesz go ponownie.",
|
||||
"boost": "Boost w tej sesji",
|
||||
"skipDelay": "Pomiń opóźnienie startu",
|
||||
"cloudNote": "Nie ma tu nic do skonfigurowania: poświadczeniem jest konto Anker, które podajesz w Ustawieniach. Polecenia idą połączeniem, które ładowarka i tak utrzymuje z Anker.",
|
||||
"cloudLocalFound": "Ta ładowarka podaje swój lokalny adres: {address}. Przełącz tryb sterowania na Modbus TCP, aby go użyć.",
|
||||
"modbusHint": "Podaj adres ładowarki w tej sieci i zapisz go. Ładowarka musi być włączona i w tej samej sieci co DriverVault."
|
||||
},
|
||||
"modbus": {
|
||||
@@ -209,6 +212,7 @@
|
||||
"mqttLink": "MQTT",
|
||||
"alarmWord": "Słowo {n}",
|
||||
"alarmsHint": "Ładowarka zgłasza alarm. Anker nie publikuje znaczenia poszczególnych bitów, więc słowa pokazane są tak, jak przychodzą.",
|
||||
"phaseMode0": "Automatycznie",
|
||||
"phaseMode1": "Jednofazowo",
|
||||
"phaseMode3": "Trójfazowo",
|
||||
"phaseSet0": "Automatycznie",
|
||||
|
||||
@@ -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"),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -106,6 +106,9 @@
|
||||
"forgetAddress": "Glem",
|
||||
"forgetAddressConfirm": "Glem laderens lokale adresse? Styring over det lokale netværk stopper, indtil du indtaster den igen.",
|
||||
"boost": "Boost denne session",
|
||||
"skipDelay": "Spring startforsinkelsen over",
|
||||
"cloudNote": "Der er intet at sætte op her: Anker-kontoen er legitimationen, og den indtastes i Indstillinger. Kommandoer sendes over den forbindelse, laderen i forvejen holder åben til Anker.",
|
||||
"cloudLocalFound": "Denne lader oplyser sin egen lokale adresse som {address}. Skift kontroltilstand til Modbus TCP for at bruge den.",
|
||||
"modbusHint": "Indtast laderens adresse på dette netværk og gem den. Laderen skal være tændt og på samme netværk som DriverVault."
|
||||
},
|
||||
"cards": {
|
||||
@@ -168,6 +171,7 @@
|
||||
"mqttLink": "MQTT",
|
||||
"alarmWord": "Ord {n}",
|
||||
"alarmsHint": "Laderen melder en alarm. Anker offentliggør ikke, hvad de enkelte bit betyder, så ordene vises, som de kommer.",
|
||||
"phaseMode0": "Automatisk",
|
||||
"phaseMode1": "Enfaset",
|
||||
"phaseMode3": "Trefaset",
|
||||
"phaseSet0": "Automatisk",
|
||||
|
||||
@@ -92,6 +92,9 @@
|
||||
"forgetAddress": "Forget",
|
||||
"forgetAddressConfirm": "Forget this charger's local address? Control over the local network stops until you enter it again.",
|
||||
"boost": "Boost this session",
|
||||
"skipDelay": "Skip the start delay",
|
||||
"cloudNote": "Nothing to set up here: the Anker account is the credential, and it is entered in Settings. Commands travel over the connection the charger already holds open to Anker.",
|
||||
"cloudLocalFound": "This charger reports its own local address as {address}. Switch the control mode to Modbus TCP to use it.",
|
||||
"modbusHint": "Enter the charger's address on this network and save it. The charger must be powered on and on the same network as DriverVault."
|
||||
},
|
||||
"cards": {
|
||||
@@ -154,6 +157,7 @@
|
||||
"mqttLink": "MQTT",
|
||||
"alarmWord": "Word {n}",
|
||||
"alarmsHint": "The charger reports an alarm. Anker does not publish what the individual bits mean, so the words are shown as they arrive.",
|
||||
"phaseMode0": "Automatic",
|
||||
"phaseMode1": "Single-phase",
|
||||
"phaseMode3": "Three-phase",
|
||||
"phaseSet0": "Automatic",
|
||||
|
||||
@@ -108,6 +108,9 @@
|
||||
"forgetAddress": "Zapomnij",
|
||||
"forgetAddressConfirm": "Zapomnieć lokalny adres tej ładowarki? Sterowanie przez sieć lokalną przestanie działać, dopóki nie wpiszesz go ponownie.",
|
||||
"boost": "Boost w tej sesji",
|
||||
"skipDelay": "Pomiń opóźnienie startu",
|
||||
"cloudNote": "Nie ma tu nic do skonfigurowania: poświadczeniem jest konto Anker, które podajesz w Ustawieniach. Polecenia idą połączeniem, które ładowarka i tak utrzymuje z Anker.",
|
||||
"cloudLocalFound": "Ta ładowarka podaje swój lokalny adres: {address}. Przełącz tryb sterowania na Modbus TCP, aby go użyć.",
|
||||
"modbusHint": "Podaj adres ładowarki w tej sieci i zapisz go. Ładowarka musi być włączona i w tej samej sieci co DriverVault."
|
||||
},
|
||||
"cards": {
|
||||
@@ -170,6 +173,7 @@
|
||||
"mqttLink": "MQTT",
|
||||
"alarmWord": "Słowo {n}",
|
||||
"alarmsHint": "Ładowarka zgłasza alarm. Anker nie publikuje znaczenia poszczególnych bitów, więc słowa pokazane są tak, jak przychodzą.",
|
||||
"phaseMode0": "Automatycznie",
|
||||
"phaseMode1": "Jednofazowo",
|
||||
"phaseMode3": "Trójfazowo",
|
||||
"phaseSet0": "Automatycznie",
|
||||
|
||||
@@ -536,6 +536,15 @@ const devicePhases = computed(() => {
|
||||
}));
|
||||
});
|
||||
|
||||
// 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 whose firmware leaves them out.
|
||||
const devicePhasesHaveVA = computed(() => {
|
||||
const s = dev.value;
|
||||
return [1, 2, 3].some((n) => isSet(s[`reactiveL${n}`]) || isSet(s[`apparentL${n}`]));
|
||||
});
|
||||
|
||||
// Line-to-line voltages only mean anything on a three-phase supply, so they are
|
||||
// shown when the charger reports one rather than as three more zeroes.
|
||||
const deviceLineVoltages = computed(() => {
|
||||
@@ -1560,8 +1569,8 @@ onMounted(async () => {
|
||||
<th class="py-1 text-right font-medium">{{ t("charging.modbus.voltage") }}</th>
|
||||
<th class="py-1 text-right font-medium">{{ t("charging.modbus.current") }}</th>
|
||||
<th class="py-1 text-right font-medium">{{ t("charging.modbus.activePower") }}</th>
|
||||
<th class="py-1 text-right font-medium">{{ t("charging.modbus.reactivePower") }}</th>
|
||||
<th class="py-1 text-right font-medium">{{ t("charging.modbus.apparentPower") }}</th>
|
||||
<th v-if="devicePhasesHaveVA" class="py-1 text-right font-medium">{{ t("charging.modbus.reactivePower") }}</th>
|
||||
<th v-if="devicePhasesHaveVA" class="py-1 text-right font-medium">{{ t("charging.modbus.apparentPower") }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="data">
|
||||
@@ -1570,8 +1579,8 @@ onMounted(async () => {
|
||||
<td class="py-1 text-right text-strong">{{ p.volts }}</td>
|
||||
<td class="py-1 text-right text-strong">{{ p.amps }}</td>
|
||||
<td class="py-1 text-right text-strong">{{ p.watts }}</td>
|
||||
<td class="py-1 text-right text-strong">{{ p.reactive }}</td>
|
||||
<td class="py-1 text-right text-strong">{{ p.apparent }}</td>
|
||||
<td v-if="devicePhasesHaveVA" class="py-1 text-right text-strong">{{ p.reactive }}</td>
|
||||
<td v-if="devicePhasesHaveVA" class="py-1 text-right text-strong">{{ p.apparent }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user