Erweiterung des Backends #9

Open
opened 2026-08-29 23:54:08 +02:00 by erdbruegger · 3 comments
Owner

Ich habe heute wieder ein paar Tests am Auto gemacht. Dump habe ich dir angehangen (vllt kannst du auch in deinem Context des Aiways Projects schauen? Für mehr Infos, in wesentlichen:
Der Lese-Pfad per MQTT funktioniert jetzt, aber noch viel besser das dbcvpage command über Port 50000 auf der TBox liefert alles.

Das wird jetzt unser primärer Lese-Pfad werden. Kannst du einmal das Backend um die neuen Informationen erweitern? Ich würde das in zwei Tabellen trennen, einmal unsere Telemetrie-Daten die wir ja heute schon haben und dann eine "Details" Tabelle und gegebenfalls eine Diagnose-daten Tabelle. Anschließend die entsprechenden Endpoints erstellen/hinzufügen/erweitern. Admin-dashboard aktualisieren und auch die test-daten einmal einspielen

Ich habe heute wieder ein paar Tests am Auto gemacht. Dump habe ich dir angehangen (vllt kannst du auch in deinem Context des Aiways Projects schauen? Für mehr Infos, in wesentlichen: Der Lese-Pfad per MQTT funktioniert jetzt, aber noch viel besser das dbcvpage command über Port 50000 auf der TBox liefert alles. Das wird jetzt unser primärer Lese-Pfad werden. Kannst du einmal das Backend um die neuen Informationen erweitern? Ich würde das in zwei Tabellen trennen, einmal unsere Telemetrie-Daten die wir ja heute schon haben und dann eine "Details" Tabelle und gegebenfalls eine Diagnose-daten Tabelle. Anschließend die entsprechenden Endpoints erstellen/hinzufügen/erweitern. Admin-dashboard aktualisieren und auch die test-daten einmal einspielen
Collaborator

Umgesetzt und deployt (Commit c6a37b2, CI + Deploy gruen)

Der dbcvpage-Pfad ueber Port 50000 ist jetzt der primaere Lesepfad. Dein Dump ist eingespielt und live durchgemessen.

Datenmodell — drei Toepfe, wie von dir vorgeschlagen

Tabelle Inhalt Warum getrennt
telemetry (bestehend) die Kerngroessen: SoC, Packspannung/-strom, Odometer, Reichweite, Speed, 96 Zellspannungen, 24 Zelltemperaturen Charts, /latest, Reichweiten-Schaetzung und die App laufen damit unveraendert weiter — der neue Pfad ist fuer sie nur eine weitere source
vehicle_details (neu) alle uebrigen Messwerte, ein Signal je Zeile, mit Rohwert und physikalischem Wert + Einheit Skalierung ist nicht bei jedem Signal bestaetigt — der Rohwert bleibt so nachrechenbar
vehicle_diagnostics (neu) die Fault-/Warnflags (Tier H aus deinem Katalog), active = raw != 0 wird ganz anders abgefragt ("was ist gerade aktiv?") und waechst anders

Dazu ein Kopfsatz vehicle_snapshots je Sweep (Zeitpunkt, Quelle, Zahl der Messwerte/Flags/aktiven Flags/verworfenen Signale).

Schmal (ein Signal je Zeile) statt ~1000 Spalten, weil die Signalliste nicht stabil ist: ein spaeterer Sweep bringt Seiten dazu und kostet dann kein Schema-Update. Housekeeping (Rolling-Counter, Checksummen, Gueltigkeitsbits) wird verworfen statt als tote Spalten mitgeschleppt.

Signal-Katalog

src/ingest/dbcvpageCatalog.ts ist generiert aus deiner aichi_dbcvpage_katalog_1.xlsx — 991 Signale mit Seite, Domaene, Tier, Kategorie, Einheit und Skala/Offset. Deine 930 Signale aus dem Sweep sind damit vollstaendig katalogisiert (unknown: []). Skalierungen kommen aus deiner Spalte Formatiert, z.B. BMSCellVoltMax 3651 -> 3.651 V, BCMIBSBatTemp 62 -> 22 °C, VCUDrivingrange 1010 -> 101 km, BMSStateOfEnergy 182 -> 18.2 kWh.

Signale, die ein spaeterer Sweep dazubringt, ordnet eine Heuristik ueber den Namen grob ein (Fault / Housekeeping / sonstiges) — eine Einheit behauptet sie nicht. Die Ingest-Antwort listet sie unter unknown, dann gehoert der Katalog nachgezogen.

Neue Endpoints

Methode Pfad Zweck
POST /ingest/dbcvpage Sweep-Log als text/plain oder JSON {vin,ts,signals:{...}} fuer eine Live-Bridge. ?dry=1 parst nur. Idempotent.
GET /vehicles/:id/snapshots Liste der Sweeps
GET /vehicles/:id/details Messwerte eines Sweeps. ?ts=&domain=BMS,VCU&tier=A,B&category=&signal=CellVolt&sort=&dir=&limit=&offset=, ?history=1&from=&to= fuer den Verlauf
GET /vehicles/:id/diagnostics Fault-Flags — per Default nur die aktiven, ?all=1 auch die stillen

/vehicles/:id/latest nennt zusaetzlich snapshot (Kopfsatz des juengsten Sweeps). :id ist wie ueberall Fahrzeug-ID oder VIN. Halter-Sichtbarkeit (#5) gilt auch fuer die neuen Tabellen.

Dashboard

Zwei neue Tabs: Details und Diagnose — Fahrzeug- und Snapshot-Auswahl, Filter nach Domaene/Tier/Kategorie/Signalname, serverseitig sortier- und blaetterbar. Im Status-Popup unter Fahrzeuge steht jetzt zusaetzlich der letzte Sweep (Zahl der Messwerte, aktive Flags, Alter).

Deine Testdaten sind drin

Eingespielt als Fahrzeug 7 / VIN TEST-DBCVPAGE auf der Live-Instanz:

ts 2026-08-29T21:17:58Z (= 23:17:58 lokal, passt zu IVIHourSet/MinuteSet)
930 Signale -> 490 Messwerte, 236 Fault-Flags (davon 16 aktiv), 204 Housekeeping verworfen
Kern: SoC 30 %, Pack 349.5 V / -7.5 A, Odometer 43038 km, Reichweite 101 km,
      96 Zellspannungen, 24 Zelltemperaturen

Gegengelesen live: TPMS z.B. BCMTpmsFrntLeWhlTemp 60 -> 20 °C, die 16 aktiven Flags sind VCUFltSN5/7/9/17/20/21/22/23/29/30/38/39/43/47/50/51.

Bewusste Entscheidungen — bitte einmal drueberschauen

  1. gear, charge_state, status bleiben bei dbcvpage leer. In telemetry stehen dort GB32960-Codes aus cache_data; VCUShftstt / BMSACChgConnectStt zaehlen anders. Beide Kodierungen in einer Spalte waeren stiller Datenmuell — die Signale stehen vollstaendig in vehicle_details. Wenn du die Zuordnung kennst, baue ich sie gern ein.
  2. speed = IPVehicleSpeedDisplay (Fallback ESPVehicleSpeed), Skala 1. Beide standen im Sweep auf 0 (Auto geparkt), die Skalierung ist also unbestaetigt. Ich habe den Tachowert genommen, weil er im Auto sichtbar ist und sich bei der naechsten Fahrt in einer Minute gegenpruefen laesst.
  3. Kein GPS aus dbcvpage — der Katalog fuehrt keine Position. lat/lon kommen weiter aus dem .inx.
  4. VIN nicht dekodiert. GWVINValue1..5 liessen sich nicht sauber zu 17 Zeichen zusammensetzen (Nullbytes an unpassenden Stellen, GWVINFrameNumber deutet auf Multi-Frame-Zusammenbau). Statt zu raten habe ich die Testdaten unter TEST-DBCVPAGE abgelegt. Wenn du die echte VIN durchgibst, ziehe ich sie um.
  5. TPMS-Druck-Einheit steht als (kPa?) in der Antwort — genau so unsicher, wie dein Katalog sie fuehrt. Lieber ehrlich als falsch beschriftet.

Tests

39 neue Selbsttests in dbcvpageSelftest.ts (Parser, Katalog, Skalierung, Aufteilung, Filter/Sortierung inkl. Injection) + 7 fuers Dashboard. Vor dem Push ausserdem lokal gegen ein echtes Postgres end-to-end durchgespielt: Ingest (Text + JSON), Idempotenz, alle Query-Endpoints, Halter-Isolation, Fehlerfaelle.

README hat einen eigenen Abschnitt zum dbcvpage-Pfad bekommen, die Sandbox kennt die neuen Endpoints.

## Umgesetzt und deployt (Commit `c6a37b2`, CI + Deploy gruen) Der dbcvpage-Pfad ueber Port 50000 ist jetzt der primaere Lesepfad. Dein Dump ist eingespielt und live durchgemessen. ### Datenmodell — drei Toepfe, wie von dir vorgeschlagen | Tabelle | Inhalt | Warum getrennt | |---|---|---| | `telemetry` (bestehend) | die Kerngroessen: SoC, Packspannung/-strom, Odometer, Reichweite, Speed, 96 Zellspannungen, 24 Zelltemperaturen | Charts, `/latest`, Reichweiten-Schaetzung und die App laufen damit **unveraendert** weiter — der neue Pfad ist fuer sie nur eine weitere `source` | | `vehicle_details` (neu) | alle uebrigen **Messwerte**, ein Signal je Zeile, mit Rohwert **und** physikalischem Wert + Einheit | Skalierung ist nicht bei jedem Signal bestaetigt — der Rohwert bleibt so nachrechenbar | | `vehicle_diagnostics` (neu) | die **Fault-/Warnflags** (Tier H aus deinem Katalog), `active = raw != 0` | wird ganz anders abgefragt ("was ist gerade aktiv?") und waechst anders | Dazu ein Kopfsatz `vehicle_snapshots` je Sweep (Zeitpunkt, Quelle, Zahl der Messwerte/Flags/aktiven Flags/verworfenen Signale). **Schmal (ein Signal je Zeile) statt ~1000 Spalten**, weil die Signalliste nicht stabil ist: ein spaeterer Sweep bringt Seiten dazu und kostet dann kein Schema-Update. Housekeeping (Rolling-Counter, Checksummen, Gueltigkeitsbits) wird verworfen statt als tote Spalten mitgeschleppt. ### Signal-Katalog `src/ingest/dbcvpageCatalog.ts` ist **generiert** aus deiner `aichi_dbcvpage_katalog_1.xlsx` — 991 Signale mit Seite, Domaene, Tier, Kategorie, Einheit und Skala/Offset. Deine 930 Signale aus dem Sweep sind damit **vollstaendig** katalogisiert (`unknown: []`). Skalierungen kommen aus deiner Spalte *Formatiert*, z.B. `BMSCellVoltMax` 3651 -> 3.651 V, `BCMIBSBatTemp` 62 -> 22 °C, `VCUDrivingrange` 1010 -> 101 km, `BMSStateOfEnergy` 182 -> 18.2 kWh. Signale, die ein spaeterer Sweep dazubringt, ordnet eine Heuristik ueber den Namen grob ein (Fault / Housekeeping / sonstiges) — eine Einheit behauptet sie **nicht**. Die Ingest-Antwort listet sie unter `unknown`, dann gehoert der Katalog nachgezogen. ### Neue Endpoints | Methode | Pfad | Zweck | |---|---|---| | POST | `/ingest/dbcvpage` | Sweep-Log als `text/plain` **oder** JSON `{vin,ts,signals:{...}}` fuer eine Live-Bridge. `?dry=1` parst nur. Idempotent. | | GET | `/vehicles/:id/snapshots` | Liste der Sweeps | | GET | `/vehicles/:id/details` | Messwerte eines Sweeps. `?ts=&domain=BMS,VCU&tier=A,B&category=&signal=CellVolt&sort=&dir=&limit=&offset=`, `?history=1&from=&to=` fuer den Verlauf | | GET | `/vehicles/:id/diagnostics` | Fault-Flags — per Default nur die **aktiven**, `?all=1` auch die stillen | `/vehicles/:id/latest` nennt zusaetzlich `snapshot` (Kopfsatz des juengsten Sweeps). `:id` ist wie ueberall Fahrzeug-ID **oder** VIN. Halter-Sichtbarkeit (#5) gilt auch fuer die neuen Tabellen. ### Dashboard Zwei neue Tabs: **Details** und **Diagnose** — Fahrzeug- und Snapshot-Auswahl, Filter nach Domaene/Tier/Kategorie/Signalname, serverseitig sortier- und blaetterbar. Im Status-Popup unter *Fahrzeuge* steht jetzt zusaetzlich der letzte Sweep (Zahl der Messwerte, aktive Flags, Alter). ### Deine Testdaten sind drin Eingespielt als Fahrzeug **7 / VIN `TEST-DBCVPAGE`** auf der Live-Instanz: ``` ts 2026-08-29T21:17:58Z (= 23:17:58 lokal, passt zu IVIHourSet/MinuteSet) 930 Signale -> 490 Messwerte, 236 Fault-Flags (davon 16 aktiv), 204 Housekeeping verworfen Kern: SoC 30 %, Pack 349.5 V / -7.5 A, Odometer 43038 km, Reichweite 101 km, 96 Zellspannungen, 24 Zelltemperaturen ``` Gegengelesen live: TPMS z.B. `BCMTpmsFrntLeWhlTemp` 60 -> 20 °C, die 16 aktiven Flags sind `VCUFltSN5/7/9/17/20/21/22/23/29/30/38/39/43/47/50/51`. ### Bewusste Entscheidungen — bitte einmal drueberschauen 1. **`gear`, `charge_state`, `status` bleiben bei dbcvpage leer.** In `telemetry` stehen dort GB32960-Codes aus `cache_data`; `VCUShftstt` / `BMSACChgConnectStt` zaehlen anders. Beide Kodierungen in einer Spalte waeren stiller Datenmuell — die Signale stehen vollstaendig in `vehicle_details`. Wenn du die Zuordnung kennst, baue ich sie gern ein. 2. **`speed` = `IPVehicleSpeedDisplay`** (Fallback `ESPVehicleSpeed`), Skala 1. Beide standen im Sweep auf 0 (Auto geparkt), die Skalierung ist also **unbestaetigt**. Ich habe den Tachowert genommen, weil er im Auto sichtbar ist und sich bei der naechsten Fahrt in einer Minute gegenpruefen laesst. 3. **Kein GPS aus dbcvpage** — der Katalog fuehrt keine Position. `lat`/`lon` kommen weiter aus dem `.inx`. 4. **VIN nicht dekodiert.** `GWVINValue1..5` liessen sich nicht sauber zu 17 Zeichen zusammensetzen (Nullbytes an unpassenden Stellen, `GWVINFrameNumber` deutet auf Multi-Frame-Zusammenbau). Statt zu raten habe ich die Testdaten unter `TEST-DBCVPAGE` abgelegt. Wenn du die echte VIN durchgibst, ziehe ich sie um. 5. **TPMS-Druck-Einheit** steht als `(kPa?)` in der Antwort — genau so unsicher, wie dein Katalog sie fuehrt. Lieber ehrlich als falsch beschriftet. ### Tests 39 neue Selbsttests in `dbcvpageSelftest.ts` (Parser, Katalog, Skalierung, Aufteilung, Filter/Sortierung inkl. Injection) + 7 fuers Dashboard. Vor dem Push ausserdem lokal gegen ein echtes Postgres end-to-end durchgespielt: Ingest (Text + JSON), Idempotenz, alle Query-Endpoints, Halter-Isolation, Fehlerfaelle. README hat einen eigenen Abschnitt zum dbcvpage-Pfad bekommen, die Sandbox kennt die neuen Endpoints.
Author
Owner

Die echte VIN lautet LVXMAXBA4LR901219,
Lat/Long standen im MQTT-Datensatz drin, den hatte ich nicht mit ins Dump gepackt, können wir aber von dort ziehen. Vielleicht hast du ihn noch im Backlog?

Im Auto wird für den Reifendruck so 2,5/2,6 bar angezeigt, reicht dir das als Verifizierung?

Die echte VIN lautet LVXMAXBA4LR901219, Lat/Long standen im MQTT-Datensatz drin, den hatte ich nicht mit ins Dump gepackt, können wir aber von dort ziehen. Vielleicht hast du ihn noch im Backlog? Im Auto wird für den Reifendruck so 2,5/2,6 bar angezeigt, reicht dir das als Verifizierung?
Collaborator

Deine drei Punkte sind umgesetzt und live (Commits fc5b052 + 2a90495, CI + Deploy gruen)

1. VIN

Fahrzeug 7 heisst jetzt LVXMAXBA4LR901219 (Name "U5"). Nichts neu eingespielt --
Telemetrie, der Sweep und die Halter-Historie hingen ohnehin an der Fahrzeug-ID.

Dafuer gibt es jetzt PATCH /vehicles/:id (Admin, Body {vin?, name?}) und im Dashboard
unter Fahrzeuge den Knopf Umbenennen -- fuer den naechsten Fall, dass die richtige VIN
erst nach dem ersten Ingest feststeht. Doppelte VIN gibt 409.

2. Lat/Long -- ja, ich hatte den Datensatz noch

Nicht im Dump, aber im USB-Abzug vom 19.08.: sysi.log.0. Da drin beantwortet die TBox
ihr getNetInfoInd mit getNetInfoRsp, und dessen Body traegt neben Funkzelle und Pegel
die Position -- NMEA ddmm.mmmm, genau wie im .inx.

Neuer Ingest POST /ingest/mqtt: entweder ein TBox-Log am Stueck (text/plain,
?year= gibt das Jahr, das die Logzeitstempel nicht mitbringen) oder die MQTT-Nachricht
einer Live-Bridge als JSON. Eingespielt sind die 7 Fixes vom 18./19.08. unter deiner VIN;
/latest liefert die Position, das Status-Popup zeigt die Karte.

Zwei Sachen, die dabei aufgefallen sind:

  • Jeder Fix steht im Log zweimal -- einmal als C-Logzeile mit voller Genauigkeit und
    gleich darauf im JSON der abgehenden Nachricht, dort aber auf zwei Nachkommastellen
    gerundet (rund 20 m grober). Gelesen wird nur die genauere; sonst zaehlte jeder Fix
    doppelt, mit der schlechteren Variante obendrauf.
  • Gegengeprueft an einer unabhaengigen Quelle: der Fix vom 19.08. 06:15:00 aus dem
    Log deckt sich auf rund 4 m mit deinem .inx-Track derselben Sekunde
    (5302.306/839.357 gegen 5302.306/839.359). Beide Quellen benutzen also dieselbe Uhr --
    die Log-Zeitstempel gehen ohne Umrechnung in dieselbe Zeitachse wie der Rest.

Der eingespielte Ausschnitt ist duenn: die TBox fragt netInfo nur gelegentlich (OTA-nah) ab,
in ~19 h Log stehen 7 Fixes, sechs davon auf dem Stellplatz. Fuer eine echte Spur brauchen
wir die Live-Bridge am Broker -- die JSON-Form steht dafuer bereit.

3. Reifendruck -- ja, das reicht als Verifizierung

Deine Ablesung sagt das Entscheidende: der Rohwert ist weder kPa noch bar. Der Sweep las
96/96/97/98, angezeigt waren rund 2,5-2,6 bar -- macht rund 2,7 kPa je Schritt.

Ich habe 2.75 kPa genommen (= 0,4 psi). Das ist genau das Doppelte der 1,373 kPa,
mit denen die Kopfeinheit selbst ihren TPMS-Druck rechnet (TpmsParseManager, byteweise) --
dbcvpage fuehrt das Feld also eine Stufe grober. Damit steht jetzt:

Rad roh Druck Temperatur
vorne links 96 264 kPa = 2,64 bar 20 °C
vorne rechts 96 264 kPa = 2,64 bar 20 °C
hinten links 97 266,75 kPa = 2,67 bar 19 °C
hinten rechts 98 269,5 kPa = 2,70 bar 20 °C

Eine Anzeigestelle ueber deiner Ablesung. Ehrlich gesagt: fuer die letzten 0,1 bar
reicht "so 2,5/2,6" nicht -- eine Skala von ~2,63 wuerde exakt deine Zahlen treffen, ist
aber sonst durch nichts gedeckt, waehrend 2,75 aus dem Code des Autos kommt. Wenn du bei
Gelegenheit radgenau ablesen magst (vorne beide gleich, hinten rechts am hoechsten --
das muss jede richtige Skalierung zeigen), ziehe ich die Zahl nach; es ist eine Zeile im
Katalog.

/vehicles/:id/latest liefert die vier Raeder jetzt fertig als tires (kPa und bar plus
Temperatur), das Status-Popup zeigt sie als 2x2-Raster ueber der Karte -- Dashboard und App
brauchen dafuer kein Wissen ueber Signalnamen.

Drei Sachen, die beim Lauf gegen die echten Rohdaten aufgefallen sind

  1. text/plain wurde pauschal mit 400 abgewiesen. Fastify vergleicht bei Text-Bodies
    die Zeichenzahl mit Content-Length (Bytes) -- ein echtes TBox-Log ist kein sauberes
    UTF-8, also passte die Rechnung nie. Wird jetzt als Buffer geparst.
  2. Die Zeitreihe blendete die GPS-Spur aus. Sie warf Records ohne SoC/Packspannung als
    "leer" weg -- ein Record aus dem MQTT-Pfad hat aber nur eine Position. ?flat=1 bleibt
    bewusst beim Kern-Record.
  3. Der Reifendruck stand live weiter falsch da, obwohl der Katalog stimmte. value und
    unit entstehen beim Ingest, und der Upload liess vorhandene Zeilen einfach stehen. Jetzt
    schreibt derselbe Sweep sie neu -- eine spaeter gegengepruefte Skalierung zieht sich durch
    erneutes Hochladen nach (refreshed in der Antwort sagt, wie viele). Deinen Sweep habe
    ich damit einmal durchlaufen lassen: 726 Zeilen aufgefrischt.

Tests

24 neue Selbsttests (Log-Parser, NMEA, Jahreslogik, Doppelte, Live-Bridge-Form,
Reifen-Aufbereitung und -Darstellung, TPMS-Skala). Dazu ein End-to-End-Lauf gegen ein echtes
Postgres: Log-Ingest samt Idempotenz, JSON-Form, /latest, Umbenennen, das Auffrischen der
abgeleiteten Werte und die Halter-Sichtbarkeit der neuen Felder (ein Halter ab dem 30.08.
sieht den Sweep vom 29.08. samt Reifen nicht).

Live gegengelesen unter deiner VIN: Position, Reifen, Sweep-Kopfsatz und GPS-Spur in der
Zeitreihe stehen. README und Sandbox sind nachgezogen.

## Deine drei Punkte sind umgesetzt und live (Commits `fc5b052` + `2a90495`, CI + Deploy gruen) ### 1. VIN Fahrzeug **7** heisst jetzt **LVXMAXBA4LR901219** (Name "U5"). Nichts neu eingespielt -- Telemetrie, der Sweep und die Halter-Historie hingen ohnehin an der Fahrzeug-ID. Dafuer gibt es jetzt `PATCH /vehicles/:id` (Admin, Body `{vin?, name?}`) und im Dashboard unter *Fahrzeuge* den Knopf **Umbenennen** -- fuer den naechsten Fall, dass die richtige VIN erst nach dem ersten Ingest feststeht. Doppelte VIN gibt 409. ### 2. Lat/Long -- ja, ich hatte den Datensatz noch Nicht im Dump, aber im USB-Abzug vom 19.08.: **`sysi.log.0`**. Da drin beantwortet die TBox ihr `getNetInfoInd` mit `getNetInfoRsp`, und dessen Body traegt neben Funkzelle und Pegel die Position -- NMEA `ddmm.mmmm`, genau wie im `.inx`. Neuer Ingest **`POST /ingest/mqtt`**: entweder ein TBox-Log am Stueck (`text/plain`, `?year=` gibt das Jahr, das die Logzeitstempel nicht mitbringen) oder die MQTT-Nachricht einer Live-Bridge als JSON. Eingespielt sind die **7 Fixes** vom 18./19.08. unter deiner VIN; `/latest` liefert die Position, das Status-Popup zeigt die Karte. Zwei Sachen, die dabei aufgefallen sind: * **Jeder Fix steht im Log zweimal** -- einmal als C-Logzeile mit voller Genauigkeit und gleich darauf im JSON der abgehenden Nachricht, dort aber auf zwei Nachkommastellen gerundet (rund 20 m grober). Gelesen wird nur die genauere; sonst zaehlte jeder Fix doppelt, mit der schlechteren Variante obendrauf. * **Gegengeprueft an einer unabhaengigen Quelle:** der Fix vom 19.08. **06:15:00** aus dem Log deckt sich auf rund **4 m** mit deinem `.inx`-Track derselben Sekunde (5302.306/839.357 gegen 5302.306/839.359). Beide Quellen benutzen also dieselbe Uhr -- die Log-Zeitstempel gehen ohne Umrechnung in dieselbe Zeitachse wie der Rest. Der eingespielte Ausschnitt ist duenn: die TBox fragt netInfo nur gelegentlich (OTA-nah) ab, in ~19 h Log stehen 7 Fixes, sechs davon auf dem Stellplatz. Fuer eine echte Spur brauchen wir die Live-Bridge am Broker -- die JSON-Form steht dafuer bereit. ### 3. Reifendruck -- ja, das reicht als Verifizierung Deine Ablesung sagt das Entscheidende: der Rohwert ist **weder kPa noch bar**. Der Sweep las 96/96/97/98, angezeigt waren rund 2,5-2,6 bar -- macht rund **2,7 kPa je Schritt**. Ich habe **2.75 kPa** genommen (= 0,4 psi). Das ist genau das Doppelte der **1,373 kPa**, mit denen die Kopfeinheit selbst ihren TPMS-Druck rechnet (`TpmsParseManager`, byteweise) -- `dbcvpage` fuehrt das Feld also eine Stufe grober. Damit steht jetzt: | Rad | roh | Druck | Temperatur | |---|---|---|---| | vorne links | 96 | 264 kPa = **2,64 bar** | 20 °C | | vorne rechts | 96 | 264 kPa = **2,64 bar** | 20 °C | | hinten links | 97 | 266,75 kPa = **2,67 bar** | 19 °C | | hinten rechts | 98 | 269,5 kPa = **2,70 bar** | 20 °C | **Eine Anzeigestelle ueber deiner Ablesung.** Ehrlich gesagt: fuer die letzten 0,1 bar reicht "so 2,5/2,6" nicht -- eine Skala von ~2,63 wuerde exakt deine Zahlen treffen, ist aber sonst durch nichts gedeckt, waehrend 2,75 aus dem Code des Autos kommt. Wenn du bei Gelegenheit **radgenau** ablesen magst (vorne beide gleich, hinten rechts am hoechsten -- das muss jede richtige Skalierung zeigen), ziehe ich die Zahl nach; es ist eine Zeile im Katalog. `/vehicles/:id/latest` liefert die vier Raeder jetzt fertig als `tires` (kPa **und** bar plus Temperatur), das Status-Popup zeigt sie als 2x2-Raster ueber der Karte -- Dashboard und App brauchen dafuer kein Wissen ueber Signalnamen. ### Drei Sachen, die beim Lauf gegen die echten Rohdaten aufgefallen sind 1. **`text/plain` wurde pauschal mit 400 abgewiesen.** Fastify vergleicht bei Text-Bodies die Zeichenzahl mit `Content-Length` (Bytes) -- ein echtes TBox-Log ist kein sauberes UTF-8, also passte die Rechnung nie. Wird jetzt als Buffer geparst. 2. **Die Zeitreihe blendete die GPS-Spur aus.** Sie warf Records ohne SoC/Packspannung als "leer" weg -- ein Record aus dem MQTT-Pfad hat aber nur eine Position. `?flat=1` bleibt bewusst beim Kern-Record. 3. **Der Reifendruck stand live weiter falsch da, obwohl der Katalog stimmte.** `value` und `unit` entstehen beim Ingest, und der Upload liess vorhandene Zeilen einfach stehen. Jetzt schreibt derselbe Sweep sie neu -- eine spaeter gegengepruefte Skalierung zieht sich durch erneutes Hochladen nach (`refreshed` in der Antwort sagt, wie viele). Deinen Sweep habe ich damit einmal durchlaufen lassen: 726 Zeilen aufgefrischt. ### Tests 24 neue Selbsttests (Log-Parser, NMEA, Jahreslogik, Doppelte, Live-Bridge-Form, Reifen-Aufbereitung und -Darstellung, TPMS-Skala). Dazu ein End-to-End-Lauf gegen ein echtes Postgres: Log-Ingest samt Idempotenz, JSON-Form, `/latest`, Umbenennen, das Auffrischen der abgeleiteten Werte und die Halter-Sichtbarkeit der neuen Felder (ein Halter ab dem 30.08. sieht den Sweep vom 29.08. samt Reifen **nicht**). Live gegengelesen unter deiner VIN: Position, Reifen, Sweep-Kopfsatz und GPS-Spur in der Zeitreihe stehen. README und Sandbox sind nachgezogen.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
aiways/Backend#9
No description provided.