Four questions asked of an account that answers twenty-one
The connector called ten endpoints of the read surface the map lists, and the charger card showed four views. Everything else an EV charger can reach is now a capability too: the sessions and the history, the savings, the sharing, the binding, the group, the Wi-Fi, the firmware and its update log, the tamper records, the site's own detail, price, networks and energy — plus the vehicle catalogue, dynamic pricing, the currencies and the notification views. Thirty-eight endpoints, one action each. The two message views are GET, so the request path grew a GET half that shares the login retry with the POST one. The per-charger fan-out asks all of them, six at a time rather than one after another, and a charger that belongs to a site brings that site's four views with it once the by-serial lookup has found it. A view that answers with nothing now says so instead of vanishing: the station record is empty for a standalone charger because it has no station, which is an answer worth reading. And "source 0" in the OCPP box carries the address the account's endpoint list gives it. Anker's account-level writes stay out, as do the endpoints whose payloads were only ever read out of the app package. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fb42791f8d
commit
3f9d5b943f
@@ -328,9 +328,10 @@ export const api = {
|
||||
// with an empty list and a reason when a gate is off, so the caller can show
|
||||
// the reason rather than an error.
|
||||
listAnkerChargers: () => request("/integrations/anker-solix/chargers"),
|
||||
// Every per-charger view the account holds — the station record, the charging
|
||||
// totals, the OCPP backend and the RFID cards — asked for one charger at a
|
||||
// time, because none of those endpoints lists chargers.
|
||||
// Every view the account holds about one charger — the station record, the
|
||||
// totals, the history, the sessions, the OCPP backend, the cards, the sharing,
|
||||
// the firmware and the rest, plus its site's views when it has a site — asked
|
||||
// for one charger at a time, because none of those endpoints lists chargers.
|
||||
getAnkerChargerDetails: (sn) =>
|
||||
request(`/integrations/anker-solix/chargers/${encodeURIComponent(sn)}/details`),
|
||||
|
||||
|
||||
@@ -278,10 +278,28 @@
|
||||
},
|
||||
"views": {
|
||||
"station": "Stationspost",
|
||||
"stationFeature": "Stationsfunktioner",
|
||||
"totals": "Ladetotaler",
|
||||
"orders": "Ladehistorik",
|
||||
"sessions": "Ladesessioner",
|
||||
"income": "Besparelse og indtægt",
|
||||
"ocpp": "OCPP-backend",
|
||||
"rfid": "RFID-kort"
|
||||
"ocppEndpoints": "OCPP-endepunkter hos Anker",
|
||||
"rfid": "RFID-kort",
|
||||
"shared": "Delt med",
|
||||
"binding": "Kontotilknytning",
|
||||
"group": "Enhedsgruppe",
|
||||
"wifi": "Wi-Fi-detaljer",
|
||||
"ota": "Firmwarestatus",
|
||||
"upgrades": "Opdateringshistorik",
|
||||
"tamper": "Manipulationslog",
|
||||
"siteBySn": "Systemopslag",
|
||||
"site": "Systemdetaljer",
|
||||
"sitePrice": "Pris og CO2-faktor",
|
||||
"siteWifi": "Netværk systemet kan se",
|
||||
"energy": "Energianalyse"
|
||||
},
|
||||
"viewEmpty": "Denne visning svarede, men uden indhold.",
|
||||
"offline": "Offline",
|
||||
"refresh": "Opdater",
|
||||
"rawTitle": "Som tjenesten melder det",
|
||||
|
||||
@@ -264,10 +264,28 @@
|
||||
},
|
||||
"views": {
|
||||
"station": "Station record",
|
||||
"stationFeature": "Station features",
|
||||
"totals": "Charging totals",
|
||||
"orders": "Charging history",
|
||||
"sessions": "Charging sessions",
|
||||
"income": "Savings and income",
|
||||
"ocpp": "OCPP backend",
|
||||
"rfid": "RFID cards"
|
||||
"ocppEndpoints": "OCPP endpoints Anker uses",
|
||||
"rfid": "RFID cards",
|
||||
"shared": "Shared with",
|
||||
"binding": "Account binding",
|
||||
"group": "Device group",
|
||||
"wifi": "Wi-Fi details",
|
||||
"ota": "Firmware status",
|
||||
"upgrades": "Update history",
|
||||
"tamper": "Tamper records",
|
||||
"siteBySn": "Site lookup",
|
||||
"site": "Site detail",
|
||||
"sitePrice": "Price and CO2 factor",
|
||||
"siteWifi": "Networks the site sees",
|
||||
"energy": "Energy analysis"
|
||||
},
|
||||
"viewEmpty": "This view answered, with nothing in it.",
|
||||
"offline": "Offline",
|
||||
"refresh": "Refresh",
|
||||
"rawTitle": "As the service reports it",
|
||||
|
||||
@@ -280,10 +280,28 @@
|
||||
},
|
||||
"views": {
|
||||
"station": "Rekord stacji",
|
||||
"stationFeature": "Funkcje stacji",
|
||||
"totals": "Sumy ładowania",
|
||||
"orders": "Historia ładowania",
|
||||
"sessions": "Sesje ładowania",
|
||||
"income": "Oszczędności i przychód",
|
||||
"ocpp": "Backend OCPP",
|
||||
"rfid": "Karty RFID"
|
||||
"ocppEndpoints": "Punkty OCPP używane przez Ankera",
|
||||
"rfid": "Karty RFID",
|
||||
"shared": "Udostępniono",
|
||||
"binding": "Powiązanie z kontem",
|
||||
"group": "Grupa urządzeń",
|
||||
"wifi": "Szczegóły Wi-Fi",
|
||||
"ota": "Stan firmware'u",
|
||||
"upgrades": "Historia aktualizacji",
|
||||
"tamper": "Rejestr naruszeń",
|
||||
"siteBySn": "Wyszukanie systemu",
|
||||
"site": "Szczegóły systemu",
|
||||
"sitePrice": "Cena i współczynnik CO2",
|
||||
"siteWifi": "Sieci widziane przez system",
|
||||
"energy": "Analiza energii"
|
||||
},
|
||||
"viewEmpty": "Ten widok odpowiedział, ale nic nie zawierał.",
|
||||
"offline": "Offline",
|
||||
"refresh": "Odśwież",
|
||||
"rawTitle": "Tak, jak podaje to usługa",
|
||||
|
||||
@@ -954,7 +954,13 @@ async function loadChargerDetails(force = false) {
|
||||
|
||||
// One view's fields, sorted, or the reason it could not be read. The keys are
|
||||
// the cloud's own: Anker documents none of these payloads, so a name invented
|
||||
// here would be a meaning invented here.
|
||||
// here would be a meaning invented here. Note is the exception, and the server
|
||||
// says which: a number the account elsewhere gives a meaning to, resolved.
|
||||
//
|
||||
// Every view the server asked for is drawn, the ones that answered with nothing
|
||||
// included. A standalone charger has no station record and no site; that its
|
||||
// site views are empty is the answer to "which of these does this account hold",
|
||||
// and a box that quietly disappears cannot say it.
|
||||
const chargerDetailViews = computed(() => {
|
||||
const c = selectedHomeCharger.value;
|
||||
const sn = c?.providerChargerId || c?.serial || "";
|
||||
@@ -962,10 +968,11 @@ const chargerDetailViews = computed(() => {
|
||||
return (doc?.views || []).map((view) => ({
|
||||
id: view.id,
|
||||
error: view.error || "",
|
||||
note: view.note || "",
|
||||
rows: Object.keys(view.attrs || {})
|
||||
.sort()
|
||||
.map((key) => ({ key, value: view.attrs[key] })),
|
||||
})).filter((view) => view.rows.length || view.error);
|
||||
}));
|
||||
});
|
||||
|
||||
// Everything else the service said about this charger, under its own field
|
||||
@@ -1941,18 +1948,25 @@ onMounted(async () => {
|
||||
</section>
|
||||
|
||||
<!-- The views that answer per charger rather than per account. Each
|
||||
says what it knows, or why it could not be read — an account
|
||||
that is not the charger's owner cannot read the cards, which is
|
||||
a fact about the account rather than a failure. -->
|
||||
says what it knows, why it could not be read — an account that
|
||||
is not the charger's owner cannot read the cards, which is a
|
||||
fact about the account rather than a failure — or that it
|
||||
answered with nothing, which is equally an answer. -->
|
||||
<section v-for="view in chargerDetailViews" :key="view.id" class="rounded-control bg-sunken p-3">
|
||||
<h4 class="eyebrow">{{ t(`charging.info.views.${view.id}`) }}</h4>
|
||||
<p v-if="view.error" class="mt-2 text-[11px] text-muted">{{ view.error }}</p>
|
||||
<p v-else-if="!view.rows.length" class="mt-2 text-[11px] text-muted">
|
||||
{{ t("charging.info.viewEmpty") }}
|
||||
</p>
|
||||
<dl v-else class="mt-2 grid grid-cols-[auto_1fr] gap-x-4 gap-y-1">
|
||||
<template v-for="row in view.rows" :key="row.key">
|
||||
<dt class="data break-all text-[11px] text-muted">{{ row.key }}</dt>
|
||||
<dd class="data break-all text-[11px] text-body">{{ row.value }}</dd>
|
||||
</template>
|
||||
</dl>
|
||||
<!-- The one line in DriverVault's own words: a number this view
|
||||
reports that another view gives an address. -->
|
||||
<p v-if="view.note" class="data mt-2 text-[11px] text-muted">{{ view.note }}</p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user