The fields the cloud sends, kept all the way to the card
Normalizing a provider's charger list threw most of the answer away: firmware, the site id, how the charger is registered, the charge power and the cloud's own OCPP reading all arrived from Anker and none of them got past providerCharger, which carried seven fields and dropped the rest. The information card could not show what it was never handed. It carries them now, and the card lays them out: firmware beside the model, site and site id where the charger lives, "Registered as" for standalone / in a system / bound, and — when the service knows — state, charge power and OCPP status. Charge power is relayed exactly as worded upstream, since the unit is theirs and putting one on it here would be inventing it. Settings' own list gains the firmware in its subtitle. A field no view supplied still leaves no row, so an account whose chargers stand outside a system reads shorter rather than emptier. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
86ea97b414
commit
ad785ee9f8
@@ -69,10 +69,24 @@ type providerCharger struct {
|
||||
Name string `json:"name"`
|
||||
Vendor string `json:"vendor,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
Firmware string `json:"firmware,omitempty"`
|
||||
SiteID string `json:"siteId,omitempty"`
|
||||
SiteName string `json:"siteName,omitempty"`
|
||||
Status string `json:"status,omitempty"` // the service's own word for its state
|
||||
Online *bool `json:"online,omitempty"`
|
||||
|
||||
// How the charger is registered on the account — standalone, inside a
|
||||
// system (site), or merely bound to it. A charger can be several at once,
|
||||
// and which ones it is decides how much the service says about it.
|
||||
Sources []string `json:"sources,omitempty"`
|
||||
|
||||
// What it is doing right now, when the service knows: the charge power as
|
||||
// the service words it (the unit is upstream's, so it is relayed verbatim)
|
||||
// and the charger's OCPP connector state as the service sees it.
|
||||
Power string `json:"power,omitempty"`
|
||||
OcppStatus *int `json:"ocppStatus,omitempty"`
|
||||
OcppStatusDesc string `json:"ocppStatusDesc,omitempty"`
|
||||
|
||||
// LinkedChargerID is set when this one is already in DriverVault, so the UI
|
||||
// never offers to import the same charger twice.
|
||||
LinkedChargerID string `json:"linkedChargerId,omitempty"`
|
||||
@@ -105,12 +119,18 @@ func (ankerChargerSource) gate(ctx context.Context, s *Server, who *callerIdenti
|
||||
func (ankerChargerSource) chargers(raw json.RawMessage) []providerCharger {
|
||||
var env struct {
|
||||
Chargers []struct {
|
||||
SN string `json:"sn"`
|
||||
Name string `json:"name"`
|
||||
Model string `json:"model"`
|
||||
SiteName string `json:"siteName"`
|
||||
StatusDesc string `json:"statusDesc"`
|
||||
Online *bool `json:"online"`
|
||||
SN string `json:"sn"`
|
||||
Name string `json:"name"`
|
||||
Model string `json:"model"`
|
||||
Firmware string `json:"firmware"`
|
||||
SiteID string `json:"siteId"`
|
||||
SiteName string `json:"siteName"`
|
||||
Sources []string `json:"sources"`
|
||||
StatusDesc string `json:"statusDesc"`
|
||||
Online *bool `json:"online"`
|
||||
Power string `json:"power"`
|
||||
OcppStatus *int `json:"ocppStatus"`
|
||||
OcppStatusDesc string `json:"ocppStatusDesc"`
|
||||
} `json:"chargers"`
|
||||
}
|
||||
if json.Unmarshal(raw, &env) != nil {
|
||||
@@ -123,7 +143,9 @@ func (ankerChargerSource) chargers(raw json.RawMessage) []providerCharger {
|
||||
}
|
||||
out = append(out, providerCharger{
|
||||
ID: c.SN, Name: c.Name, Vendor: "Anker Solix", Model: c.Model,
|
||||
SiteName: c.SiteName, Status: c.StatusDesc, Online: c.Online,
|
||||
Firmware: c.Firmware, SiteID: c.SiteID, SiteName: c.SiteName,
|
||||
Sources: c.Sources, Status: c.StatusDesc, Online: c.Online,
|
||||
Power: c.Power, OcppStatus: c.OcppStatus, OcppStatusDesc: c.OcppStatusDesc,
|
||||
})
|
||||
}
|
||||
return out
|
||||
|
||||
@@ -100,12 +100,22 @@
|
||||
"empty": "Intet importeret endnu — en lader, du importerer, viser alt, den melder, her.",
|
||||
"vendor": "Producent",
|
||||
"model": "Model",
|
||||
"firmware": "Firmware",
|
||||
"serial": "Serienummer",
|
||||
"site": "Placering",
|
||||
"siteId": "Placerings-id",
|
||||
"sources": "Registreret som",
|
||||
"sourceNames": {
|
||||
"standalone": "Selvstændig",
|
||||
"site": "I et system",
|
||||
"bound": "Knyttet til kontoen"
|
||||
},
|
||||
"power": "Effekt",
|
||||
"connector": "Stik",
|
||||
"providerId": "Id hos tjenesten",
|
||||
"state": "Tilstand",
|
||||
"chargePower": "Ladeeffekt",
|
||||
"ocpp": "OCPP-status",
|
||||
"added": "Tilføjet",
|
||||
"online": "Online",
|
||||
"offline": "Offline",
|
||||
|
||||
@@ -86,12 +86,22 @@
|
||||
"empty": "Nothing imported yet — a charger you import shows everything it reports here.",
|
||||
"vendor": "Vendor",
|
||||
"model": "Model",
|
||||
"firmware": "Firmware",
|
||||
"serial": "Serial",
|
||||
"site": "Site",
|
||||
"siteId": "Site id",
|
||||
"sources": "Registered as",
|
||||
"sourceNames": {
|
||||
"standalone": "Standalone",
|
||||
"site": "In a system",
|
||||
"bound": "Bound to the account"
|
||||
},
|
||||
"power": "Power",
|
||||
"connector": "Connector",
|
||||
"providerId": "Service id",
|
||||
"state": "State",
|
||||
"chargePower": "Charge power",
|
||||
"ocpp": "OCPP status",
|
||||
"added": "Added",
|
||||
"online": "Online",
|
||||
"offline": "Offline",
|
||||
|
||||
@@ -102,12 +102,22 @@
|
||||
"empty": "Nic jeszcze nie zaimportowano — zaimportowana ładowarka pokaże tutaj wszystko, co zgłasza.",
|
||||
"vendor": "Producent",
|
||||
"model": "Model",
|
||||
"firmware": "Oprogramowanie",
|
||||
"serial": "Numer seryjny",
|
||||
"site": "Lokalizacja",
|
||||
"siteId": "Identyfikator lokalizacji",
|
||||
"sources": "Zarejestrowana jako",
|
||||
"sourceNames": {
|
||||
"standalone": "Samodzielna",
|
||||
"site": "W systemie",
|
||||
"bound": "Powiązana z kontem"
|
||||
},
|
||||
"power": "Moc",
|
||||
"connector": "Złącze",
|
||||
"providerId": "Identyfikator w usłudze",
|
||||
"state": "Stan",
|
||||
"chargePower": "Moc ładowania",
|
||||
"ocpp": "Status OCPP",
|
||||
"added": "Dodano",
|
||||
"online": "Online",
|
||||
"offline": "Offline",
|
||||
|
||||
@@ -129,7 +129,7 @@ async function loadChargerProviders() {
|
||||
// held beside the records rather than in them. Asking costs a round trip to
|
||||
// each connected service, so it happens when the home tab is first opened —
|
||||
// the moment the question is being asked — and on demand after that.
|
||||
const chargerLive = ref({}); // provider charger id → { online, status }
|
||||
const chargerLive = ref({}); // provider charger id → the service's own record
|
||||
const chargerLiveLoading = ref(false);
|
||||
const chargerLiveLoaded = ref(false);
|
||||
|
||||
@@ -143,7 +143,7 @@ async function loadChargerLive(force = false) {
|
||||
connected.map(async (p) => {
|
||||
try {
|
||||
const res = await api.listProviderChargers(p.id);
|
||||
for (const c of res?.chargers || []) live[c.id] = { online: c.online, status: c.status };
|
||||
for (const c of res?.chargers || []) live[c.id] = c;
|
||||
} catch {
|
||||
// A service that will not answer leaves its chargers unknown rather
|
||||
// than offline — this page cannot tell those two apart.
|
||||
@@ -163,6 +163,23 @@ function liveFor(c) {
|
||||
return chargerLive.value[c.providerChargerId] || chargerLive.value[c.serial] || null;
|
||||
}
|
||||
|
||||
// How the charger is registered on the account, in the service's own terms.
|
||||
function sourcesLabel(sources) {
|
||||
if (!sources?.length) return "";
|
||||
return sources.map((src) => {
|
||||
const key = `charging.info.sourceNames.${src}`;
|
||||
const label = t(key);
|
||||
return label === key ? src : label;
|
||||
}).join(" · ");
|
||||
}
|
||||
|
||||
// The OCPP connector state as the *service* sees it — the cloud's own reading,
|
||||
// not our CSMS's. It words it when it can and numbers it when it cannot.
|
||||
function ocppStatusLabel(live) {
|
||||
if (live?.ocppStatusDesc) return live.ocppStatusDesc;
|
||||
return live?.ocppStatus == null ? "" : String(live.ocppStatus);
|
||||
}
|
||||
|
||||
// The cloud's own slug for what the charger is doing (charging, standby, …),
|
||||
// translated. The vocabulary is the integration's, so the wording lives with it
|
||||
// in Settings rather than being said twice.
|
||||
@@ -217,15 +234,23 @@ function homeChargerSubtitle(c) {
|
||||
// the card is what is known. The provider's own id for the charger is the serial
|
||||
// for both services we speak to, so it appears only when it is something else.
|
||||
function chargerInfoRows(c) {
|
||||
const live = liveFor(c) || {};
|
||||
const rows = [
|
||||
["vendor", c.vendor],
|
||||
["model", c.model],
|
||||
["firmware", live.firmware],
|
||||
["serial", c.serial],
|
||||
["site", c.siteName],
|
||||
["site", c.siteName || live.siteName],
|
||||
["siteId", live.siteId],
|
||||
["sources", sourcesLabel(live.sources)],
|
||||
["power", c.powerKw ? `${c.powerKw} kW` : ""],
|
||||
["connector", c.connector],
|
||||
["state", chargerStateLabel(live.status)],
|
||||
// Relayed as the service words it — the unit is upstream's, so putting one
|
||||
// on it here would be inventing it.
|
||||
["chargePower", live.power],
|
||||
["ocpp", ocppStatusLabel(live)],
|
||||
["providerId", c.providerChargerId === c.serial ? "" : c.providerChargerId],
|
||||
["state", chargerStateLabel(liveFor(c)?.status)],
|
||||
["added", c.created ? formatDateTime(c.created) : ""],
|
||||
];
|
||||
return rows
|
||||
|
||||
@@ -1551,7 +1551,7 @@ onBeforeUnmount(() => {
|
||||
{{ c.name || t("settings.integrations.chargerUnnamed") }}
|
||||
</p>
|
||||
<p class="data truncate text-xs text-muted">
|
||||
{{ c.sn }}<span v-if="c.model"> · {{ c.model }}</span><span v-if="c.siteName"> · {{ c.siteName }}</span>
|
||||
{{ c.sn }}<span v-if="c.model"> · {{ c.model }}</span><span v-if="c.firmware"> · {{ c.firmware }}</span><span v-if="c.siteName"> · {{ c.siteName }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex shrink-0 items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user