The readings get their own card

The register data was appended to the control card, which turned a card for
acting on the charger into a long scroll with the buttons at the top of it.
It is a separate concern and now a separate card: control above, readings
below, alongside the charger information card that was already there.

Its title says readings rather than information, since the card below it holds
what the record knows about the charger while this one holds what the charger
itself just said.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tajniak81
2026-09-01 20:10:13 +02:00
co-authored by Claude Opus 5
parent 05f8bd07ed
commit 5547daa689
4 changed files with 84 additions and 78 deletions
+1
View File
@@ -107,6 +107,7 @@
"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": {
"title": "Laderaflæsninger",
"phases": "Pr. fase",
"live": "Live data",
"settings": "Indstillinger",
+1
View File
@@ -93,6 +93,7 @@
"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": {
"title": "Charger readings",
"phases": "Per phase",
"live": "Live data",
"settings": "Settings",
+1
View File
@@ -109,6 +109,7 @@
"modbusHint": "Podaj adres ładowarki w tej sieci i zapisz go. Ładowarka musi być włączona i w tej samej sieci co DriverVault."
},
"modbus": {
"title": "Odczyty ładowarki",
"phases": "Na fazę",
"live": "Dane na żywo",
"settings": "Ustawienia",
+81 -78
View File
@@ -855,84 +855,6 @@ onMounted(async () => {
{{ t("charging.control.boost") }}
</button>
<!-- Everything else the register map carries. One poll brings back
metering, the control settings and the charger's identity, so
they are grouped rather than listed: doing, set to, is. -->
<div v-if="ctlIsModbus" class="mt-4 flex flex-col gap-2">
<section v-if="modbusPhases.length" class="rounded-control bg-sunken p-3">
<h4 class="eyebrow">{{ t("charging.modbus.phases") }}</h4>
<div class="mt-2 overflow-x-auto">
<table class="w-full text-xs">
<thead>
<tr class="text-muted">
<th class="py-1 text-left font-medium">{{ t("charging.modbus.phase") }}</th>
<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>
</tr>
</thead>
<tbody class="data">
<tr v-for="p in modbusPhases" :key="p.phase" class="border-t border-subtle">
<td class="py-1 text-left text-muted">{{ p.phase }}</td>
<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>
</tr>
</tbody>
</table>
</div>
<p v-if="modbusLineVoltages.length" class="data mt-2 text-[11px] text-muted">
{{ t("charging.modbus.lineToLine") }}: {{ modbusLineVoltages.join(" · ") }}
</p>
</section>
<section v-if="modbusLive.length" class="rounded-control bg-sunken p-3">
<h4 class="eyebrow">{{ t("charging.modbus.live") }}</h4>
<dl class="mt-2 grid grid-cols-2 gap-x-3 gap-y-1">
<template v-for="r in modbusLive" :key="r.label">
<dt class="text-xs text-muted">{{ r.label }}</dt>
<dd class="data text-right text-xs text-strong">{{ r.value }}</dd>
</template>
</dl>
</section>
<section v-if="modbusSettings.length" class="rounded-control bg-sunken p-3">
<h4 class="eyebrow">{{ t("charging.modbus.settings") }}</h4>
<dl class="mt-2 grid grid-cols-2 gap-x-3 gap-y-1">
<template v-for="r in modbusSettings" :key="r.label">
<dt class="text-xs text-muted">{{ r.label }}</dt>
<dd class="data text-right text-xs text-strong">{{ r.value }}</dd>
</template>
</dl>
</section>
<section v-if="modbusDevice.length" class="rounded-control bg-sunken p-3">
<h4 class="eyebrow">{{ t("charging.modbus.device") }}</h4>
<dl class="mt-2 grid grid-cols-2 gap-x-3 gap-y-1">
<template v-for="r in modbusDevice" :key="r.label">
<dt class="text-xs text-muted">{{ r.label }}</dt>
<dd class="data text-right text-xs text-strong">{{ r.value }}</dd>
</template>
</dl>
</section>
<!-- Alarms, when any word is non-zero. Which register is set is
reportable even though the bit list is not published. -->
<section v-if="modbusAlarms.length" class="rounded-control border border-warning/40 bg-warning-soft p-3">
<h4 class="eyebrow" style="color: var(--warning-600)">{{ t("charging.modbus.alarms") }}</h4>
<p class="data mt-2 text-xs text-strong">
<span v-for="a in modbusAlarms" :key="a.n" class="mr-3 inline-block">
{{ t("charging.modbus.alarmWord", { n: a.n }) }} {{ a.hex }}
</span>
</p>
<p class="mt-1 text-[11px] text-muted">{{ t("charging.modbus.alarmsHint") }}</p>
</section>
</div>
<!-- Reset reboots the charger over OCPP; the register map has no
equivalent, so the button is not offered on the local path. -->
<button
@@ -970,6 +892,87 @@ onMounted(async () => {
<p v-if="ctlError" class="mt-2 text-sm text-danger">{{ ctlError }}</p>
</div>
<!-- What the charger reports over Modbus. Its own card rather than a
tail on the control one: control is for acting on the charger, and
this is a long read that pushed the buttons off the screen. -->
<div v-if="ctlIsModbus && ctlConnected" class="dh-card p-4">
<p class="text-sm font-semibold text-strong">{{ t("charging.modbus.title") }}</p>
<div class="mt-3 flex flex-col gap-2">
<section v-if="modbusPhases.length" class="rounded-control bg-sunken p-3">
<h4 class="eyebrow">{{ t("charging.modbus.phases") }}</h4>
<div class="mt-2 overflow-x-auto">
<table class="w-full text-xs">
<thead>
<tr class="text-muted">
<th class="py-1 text-left font-medium">{{ t("charging.modbus.phase") }}</th>
<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>
</tr>
</thead>
<tbody class="data">
<tr v-for="p in modbusPhases" :key="p.phase" class="border-t border-subtle">
<td class="py-1 text-left text-muted">{{ p.phase }}</td>
<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>
</tr>
</tbody>
</table>
</div>
<p v-if="modbusLineVoltages.length" class="data mt-2 text-[11px] text-muted">
{{ t("charging.modbus.lineToLine") }}: {{ modbusLineVoltages.join(" · ") }}
</p>
</section>
<section v-if="modbusLive.length" class="rounded-control bg-sunken p-3">
<h4 class="eyebrow">{{ t("charging.modbus.live") }}</h4>
<dl class="mt-2 grid grid-cols-2 gap-x-3 gap-y-1">
<template v-for="r in modbusLive" :key="r.label">
<dt class="text-xs text-muted">{{ r.label }}</dt>
<dd class="data text-right text-xs text-strong">{{ r.value }}</dd>
</template>
</dl>
</section>
<section v-if="modbusSettings.length" class="rounded-control bg-sunken p-3">
<h4 class="eyebrow">{{ t("charging.modbus.settings") }}</h4>
<dl class="mt-2 grid grid-cols-2 gap-x-3 gap-y-1">
<template v-for="r in modbusSettings" :key="r.label">
<dt class="text-xs text-muted">{{ r.label }}</dt>
<dd class="data text-right text-xs text-strong">{{ r.value }}</dd>
</template>
</dl>
</section>
<section v-if="modbusDevice.length" class="rounded-control bg-sunken p-3">
<h4 class="eyebrow">{{ t("charging.modbus.device") }}</h4>
<dl class="mt-2 grid grid-cols-2 gap-x-3 gap-y-1">
<template v-for="r in modbusDevice" :key="r.label">
<dt class="text-xs text-muted">{{ r.label }}</dt>
<dd class="data text-right text-xs text-strong">{{ r.value }}</dd>
</template>
</dl>
</section>
<!-- Alarms, when any word is non-zero. Which register is set is
reportable even though the bit list is not published. -->
<section v-if="modbusAlarms.length" class="rounded-control border border-warning/40 bg-warning-soft p-3">
<h4 class="eyebrow" style="color: var(--warning-600)">{{ t("charging.modbus.alarms") }}</h4>
<p class="data mt-2 text-xs text-strong">
<span v-for="a in modbusAlarms" :key="a.n" class="mr-3 inline-block">
{{ t("charging.modbus.alarmWord", { n: a.n }) }} {{ a.hex }}
</span>
</p>
<p class="mt-1 text-[11px] text-muted">{{ t("charging.modbus.alarmsHint") }}</p>
</section>
</div>
</div>
<!-- Charger information: everything the record holds about each imported
charger. It stands on its own — control needs Own/Proxy CSMS, but
what the charger *is* is known either way, so with control off this