The service's own field names, said in the card's words
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0657decbd1
commit
905eb24cc1
@@ -273,6 +273,16 @@
|
||||
"relatedBy": "Kan nås via",
|
||||
"timeZone": "Tidszone",
|
||||
"linked": "Tilknyttet",
|
||||
"nickname": "Kaldenavn",
|
||||
"productCode": "Produktkode",
|
||||
"deviceType": "Enhedstype",
|
||||
"charging": "Oplader",
|
||||
"statusCode": "Statuskode",
|
||||
"ocppLink": "OCPP-forbindelse",
|
||||
"wifiOnline": "Wi-Fi forbundet",
|
||||
"bleId": "Bluetooth-id",
|
||||
"blePassword": "Bluetooth-parringskode",
|
||||
"ownerId": "Ejer-id",
|
||||
"groups": {
|
||||
"device": "Enhed",
|
||||
"status": "Status",
|
||||
|
||||
@@ -259,6 +259,16 @@
|
||||
"relatedBy": "Reachable by",
|
||||
"timeZone": "Time zone",
|
||||
"linked": "Linked",
|
||||
"nickname": "Nickname",
|
||||
"productCode": "Product code",
|
||||
"deviceType": "Device type",
|
||||
"charging": "Charging",
|
||||
"statusCode": "Status code",
|
||||
"ocppLink": "OCPP connection",
|
||||
"wifiOnline": "Wi-Fi connected",
|
||||
"bleId": "Bluetooth id",
|
||||
"blePassword": "Bluetooth pairing code",
|
||||
"ownerId": "Owner id",
|
||||
"groups": {
|
||||
"device": "Device",
|
||||
"status": "Status",
|
||||
|
||||
@@ -275,6 +275,16 @@
|
||||
"relatedBy": "Dostępna przez",
|
||||
"timeZone": "Strefa czasowa",
|
||||
"linked": "Powiązano",
|
||||
"nickname": "Nazwa własna",
|
||||
"productCode": "Kod produktu",
|
||||
"deviceType": "Typ urządzenia",
|
||||
"charging": "Ładowanie",
|
||||
"statusCode": "Kod statusu",
|
||||
"ocppLink": "Połączenie OCPP",
|
||||
"wifiOnline": "Wi-Fi połączone",
|
||||
"bleId": "Identyfikator Bluetooth",
|
||||
"blePassword": "Kod parowania Bluetooth",
|
||||
"ownerId": "Identyfikator właściciela",
|
||||
"groups": {
|
||||
"device": "Urządzenie",
|
||||
"status": "Status",
|
||||
|
||||
@@ -880,6 +880,82 @@ function homeChargerSubtitle(c) {
|
||||
return [c.serial, c.model, c.siteName].filter(Boolean).join(" · ");
|
||||
}
|
||||
|
||||
// The service's own field names, given the names the rest of this card uses.
|
||||
// Anker documents none of these, so only the fields whose meaning is plain from
|
||||
// the value are named here — each says which group it belongs in and what to
|
||||
// call it. A field whose meaning would be a guess stays out and keeps its own
|
||||
// key in the box below, where the key is the only honest label it has.
|
||||
const NAMED_ATTRS = {
|
||||
alias_name: { group: "device", label: "nickname" },
|
||||
product_code: { group: "device", label: "productCode" },
|
||||
ms_device_type: { group: "device", label: "deviceType" },
|
||||
charge: { group: "status", label: "charging", bool: true },
|
||||
chargerStatus: { group: "status", label: "statusCode" },
|
||||
ocpp_connect_status: { group: "status", label: "ocppLink" },
|
||||
// The box on the wall is on two networks, and the service says more about
|
||||
// both than the typed fields carry.
|
||||
wifi_online: { group: "network", label: "wifiOnline", bool: true },
|
||||
bt_ble_id: { group: "network", label: "bleId", sameAs: "bleMac" },
|
||||
blue_password: { group: "network", label: "blePassword" },
|
||||
owner_user_id: { group: "account", label: "ownerId" },
|
||||
};
|
||||
|
||||
// Fields that repeat, in the service's own words, a row the card already draws:
|
||||
// the same serial, the same firmware, the same Wi-Fi, the same picture. Shown
|
||||
// twice they make the card longer without making it say more, so they are
|
||||
// dropped instead.
|
||||
const ECHOED_ATTRS = new Set([
|
||||
"deviceName",
|
||||
"device_name",
|
||||
"deviceSn",
|
||||
"device_sn",
|
||||
"device_sw_version",
|
||||
"img_url",
|
||||
"link_time",
|
||||
"rssi",
|
||||
"time_zone",
|
||||
"wifi_mac",
|
||||
"wifi_name",
|
||||
"bt_ble_mac",
|
||||
]);
|
||||
|
||||
// relate_type arrives indexed — relate_type[0], relate_type[1] — and is the
|
||||
// list the "Reachable by" row is built from.
|
||||
function isEchoedAttr(key) {
|
||||
return ECHOED_ATTRS.has(key) || key.startsWith("relate_type[");
|
||||
}
|
||||
|
||||
// Two values that are the same fact written two ways: 7C:E9:13:73:C2:38 is the
|
||||
// address 7CE91373C238 with colons in it.
|
||||
function sameAttrValue(a, b) {
|
||||
const norm = (v) => String(v ?? "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
||||
return norm(a) !== "" && norm(a) === norm(b);
|
||||
}
|
||||
|
||||
// A flag the service sends as true/false or 1/0, read out in words. Anything
|
||||
// else is relayed as it arrived rather than forced into a yes.
|
||||
function attrBoolLabel(v) {
|
||||
const s = String(v).toLowerCase();
|
||||
if (s === "true" || s === "1") return t("common.yes");
|
||||
if (s === "false" || s === "0") return t("common.no");
|
||||
return v;
|
||||
}
|
||||
|
||||
// The named fields that belong in one group, for a charger whose service sent
|
||||
// them. Unlike the rows above, a field missing here draws nothing: these are one
|
||||
// service's fields, and a row of dashes on a charger from another service would
|
||||
// say a field is absent when it was never a field at all.
|
||||
function namedAttrRows(groupId, attrs, live) {
|
||||
return Object.entries(NAMED_ATTRS)
|
||||
.filter(([key, spec]) => spec.group === groupId && isSet(attrs[key]) && attrs[key] !== "")
|
||||
.filter(([key, spec]) => !(spec.sameAs && sameAttrValue(attrs[key], live[spec.sameAs])))
|
||||
.map(([key, spec]) => ({
|
||||
key,
|
||||
label: t(`charging.info.${spec.label}`),
|
||||
value: spec.bool ? attrBoolLabel(attrs[key]) : attrs[key],
|
||||
}));
|
||||
}
|
||||
|
||||
// Everything the card can say about one charger, in groups: what the box is,
|
||||
// what it is doing, how it is connected, and how it sits on the account. Four
|
||||
// short lists under headings, one box each the way the readings card draws its
|
||||
@@ -925,14 +1001,20 @@ function chargerInfoGroups(c) {
|
||||
["added", c.created ? formatDateTime(c.created) : ""],
|
||||
]],
|
||||
];
|
||||
const attrs = live.attrs || {};
|
||||
return groups.map(([id, rows]) => ({
|
||||
id,
|
||||
label: t(`charging.info.groups.${id}`),
|
||||
rows: rows.map(([key, value]) => ({
|
||||
key,
|
||||
label: t(`charging.info.${key}`),
|
||||
value: value === "" || value == null ? "—" : value,
|
||||
})),
|
||||
rows: [
|
||||
...rows.map(([key, value]) => ({
|
||||
key,
|
||||
label: t(`charging.info.${key}`),
|
||||
value: value === "" || value == null ? "—" : value,
|
||||
})),
|
||||
// The fields the service sent under its own names that this group has a
|
||||
// name for, after the ones DriverVault stores itself.
|
||||
...namedAttrRows(id, attrs, live),
|
||||
],
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -995,6 +1077,7 @@ const chargerDetailViews = computed(() => {
|
||||
function chargerAttrRows(c) {
|
||||
const attrs = liveFor(c)?.attrs || {};
|
||||
return Object.keys(attrs)
|
||||
.filter((key) => !isEchoedAttr(key) && !NAMED_ATTRS[key])
|
||||
.sort()
|
||||
.map((key) => ({ key, value: attrs[key] }));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user