Fahrten, Statistik, Trip-Timer (2026.8.31.3)
Der 15-Minuten-Timer war doppelt: der FMM003 wartet laut Konfiguration (Trip \ Odometer, Ignition OFF Timeout) selbst 900 s, die App noch einmal 15 Minuten. Zusammen eine halbe Stunde. Die Pausenregel ist damit entfallen - in der Live-Erkennung, im Historienimport und in beiden Oberflaechen. Der Schwellwert "ab wann ist es ein Parkplatz" hing an derselben Einstellung, hat damit aber nichts zu tun und steht jetzt als eigene Zahl. Hoechst- und Durchschnittsgeschwindigkeit je Fahrt. Der Durchschnitt folgt aus Strecke und Dauer, vmax aus der neuen Rolle GESCHWINDIGKEIT_SENSOR - laut Konfiguration liest das Geraet die Geschwindigkeit vom OBD/CAN. Es ist der groesste gemeldete Wert, nicht die tatsaechliche Spitze: alle zehn Sekunden ein Datensatz. So ist es auch beschriftet. Der Langzeitverbrauch war um einen ganzen Tankinhalt zu hoch. Gemessen wird die Strecke ZWISCHEN erstem und letztem Tankstop; verbraucht wurde darauf, was ab dem ZWEITEN hineinkam - der erste fuellte die Strecke davor. Bei 13 Tankvorgaengen rund 8 Prozent, im Testfall 16,7 statt 8,3 l/100 km. Der Test hatte die falsche Rechnung festgeschrieben und ist mitkorrigiert. Eine negative Strecke (falscher Kilometerstand an einem Tankvorgang) gilt jetzt als unplausibel statt als Null ohne Erklaerung. Verbrauch je Fahrt bekommt Grenzen: am Sensor nachgemessen loest can_fuel_volume 0,1 l auf, ein Schritt entspricht also 10/Strecke l/100 km Fehler. Unter 3 km sagt die Differenz nichts mehr, ueber 60 l/100 km ist es kein Verbrauch. Statistik: zusaetzlich "Absolut", und die Einheit steht jetzt in eckigen Klammern an der Rubrik statt vier Mal am Zeitraum. Fuenf Spalten passen auf einem Telefon nicht nebeneinander, das Raster bricht um. Radfoto in Reifen war ein reines <Bild> - Ersetzen und Loeschen von dort aus gar nicht erreichbar. Jetzt BildMitMenue wie im Panel. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -146,7 +146,6 @@ function profilZuConfig(p) {
|
||||
tankvolumen: p.fahrzeug.tankvolumen_liter,
|
||||
nachtVon: p.einstellungen.nacht_von,
|
||||
nachtBis: p.einstellungen.nacht_bis,
|
||||
pauseMin: p.einstellungen.fahrten_pausenzeit_min,
|
||||
markenname: p.einstellungen.kraftstoffanbieter,
|
||||
backupIntervall: p.einstellungen.backup_intervall || "aus",
|
||||
letztesBackup: p.einstellungen.letztes_backup || null,
|
||||
@@ -233,7 +232,6 @@ function configCarZuProfil(vorherigesProfil) {
|
||||
p.fahrzeug.erstzulassung = CAR.erstzulassung;
|
||||
p.fahrzeug.ausfuehrung = CONFIG.ausfuehrung;
|
||||
p.einstellungen.uebersichtsbild = CONFIG.startbild;
|
||||
p.einstellungen.fahrten_pausenzeit_min = CONFIG.pauseMin;
|
||||
p.einstellungen.backup_intervall = CONFIG.backupIntervall;
|
||||
p.einstellungen.smartdeal = { aktiv: CAR.smartdeal.aktiv, laeuft_ab: CAR.smartdeal.laeuftAb };
|
||||
p.einstellungen.oelwechsel_intervall = {
|
||||
@@ -792,9 +790,14 @@ function standortZustand() {
|
||||
faehrt: false,
|
||||
unbekannt: CAR.zuendung == null,
|
||||
seitTs,
|
||||
parkplatz: minuten != null && minuten >= (CONFIG.pauseMin ?? 15),
|
||||
parkplatz: minuten != null && minuten >= PARKPLATZ_AB_MIN,
|
||||
};
|
||||
}
|
||||
/* Ab wann aus "steht gerade" ein "Parkplatz" wird. Hing bis 2026-08-31 an
|
||||
der Einstellung fahrten_pausenzeit_min - die ist mit der Pausenregel
|
||||
entfallen (der FMM003 bringt sie selbst mit), der Schwellwert hier hat
|
||||
damit aber nichts zu tun und bleibt als eigene Zahl stehen. */
|
||||
const PARKPLATZ_AB_MIN = 15;
|
||||
function dauerSeitText(ts) {
|
||||
if (ts == null) return "unbekannt";
|
||||
const sekunden = Math.max(0, Math.floor((Date.now() - ts) / 1000));
|
||||
@@ -2901,13 +2904,6 @@ function vEinst() {
|
||||
</div>
|
||||
</div>` : ""}
|
||||
</div>
|
||||
<div class="tile"><span class="label">Fahrten zusammenfassen</span>
|
||||
<div class="feld" style="border-bottom:0"><label for="pause">Pause bis</label>
|
||||
<span class="mitEinheit"><input id="pause" type="number" step="5" min="0"
|
||||
value="${CONFIG.pauseMin}" data-pause><span>Minuten</span></span></div>
|
||||
<span class="label" style="margin-top:14px">Steigst du kürzer als diese Zeit aus — etwa zum Tanken —,
|
||||
bleibt es eine zusammenhängende Fahrt statt zweier</span>
|
||||
</div>
|
||||
<div class="tile"><span class="label">Fahrzeugprofil</span>
|
||||
<span class="label" style="margin-top:10px;color:var(--fg2);letter-spacing:0;
|
||||
text-transform:none;font-size:12.5px;line-height:1.6">
|
||||
@@ -3530,6 +3526,8 @@ function vTrip(id) {
|
||||
<div class="row"><dt>Startkilometer</dt><dd>${t.odo_start != null ? de(t.odo_start) + " km" : "noch offen"}</dd></div>
|
||||
<div class="row"><dt>Endkilometer</dt><dd>${t.odo_end != null ? de(t.odo_end) + " km" : "noch offen"}</dd></div>
|
||||
<div class="row"><dt>Dauer</dt><dd>${dauerText(t.duration_s)}</dd></div>
|
||||
<div class="row"><dt>Ø Geschwindigkeit</dt><dd>${t.avg_speed_kmh != null ? de(t.avg_speed_kmh, 1) + " km/h" : "liegt nicht vor"}<small>Strecke ÷ Dauer, Standzeiten eingerechnet</small></dd></div>
|
||||
<div class="row"><dt>Höchstgeschwindigkeit</dt><dd>${t.vmax_kmh != null ? de(t.vmax_kmh, 1) + " km/h" : "liegt nicht vor"}<small>größter gemeldeter Wert, alle 10 s ein Datensatz</small></dd></div>
|
||||
<div class="row"><dt>Verbrauch</dt><dd>${fahrtVerbrauch(t) != null ? de(fahrtVerbrauch(t), 1) + " l/100 km" : "liegt nicht vor"}<small>Näherung aus Tankfüllstand</small></dd></div>
|
||||
</dl>
|
||||
<button class="aktion" data-fahrtbearbeiten>Werte bearbeiten</button>
|
||||
@@ -3559,6 +3557,8 @@ function statTile(id, label, fig, unit, extra, body) {
|
||||
tragen - erst über einen Zeitraum gemittelt ergibt das einen sinnvollen
|
||||
l/100km-Wert. */
|
||||
function periodStart(art) {
|
||||
// Alles, was je erfasst wurde - kein Zeitraum, sondern die Summe.
|
||||
if (art === "absolut") return new Date(0);
|
||||
const jetzt = new Date();
|
||||
if (art === "jahr") return new Date(jetzt.getFullYear(), 0, 1);
|
||||
if (art === "monat") return new Date(jetzt.getFullYear(), jetzt.getMonth(), 1);
|
||||
@@ -3606,27 +3606,46 @@ function langzeitverbrauch() {
|
||||
if (!tanks.length) return { wert: "–", km: 0, liter: 0, bis: null, basis: "–" };
|
||||
const letzter = tanks[tanks.length - 1];
|
||||
const bis = new Date(letzter.ts);
|
||||
const liter = sum(tanks, (f) => f.liters);
|
||||
/* Kilometerbasis: bevorzugt der Kilometerstand an den Tankvorgängen selbst -
|
||||
er zählt auch Strecke mit, für die keine Fahrt aufgezeichnet wurde. Fehlt
|
||||
er, bleibt die Summe der erfassten Fahrten bis zum letzten Tankstop. */
|
||||
const mitOdo = tanks.filter((f) => f.odometer_km != null);
|
||||
let km = 0, basis = "erfasste Fahrten";
|
||||
let km = 0, basis = "erfasste Fahrten", liter;
|
||||
if (mitOdo.length >= 2) {
|
||||
km = mitOdo[mitOdo.length - 1].odometer_km - mitOdo[0].odometer_km;
|
||||
basis = "Kilometerstand an den Tankvorgängen";
|
||||
/* Von-Tank-zu-Tank: gemessen wird die Strecke ZWISCHEN erstem und
|
||||
letztem Tankstop, verbraucht wurde auf ihr alles, was ab dem zweiten
|
||||
Tankstop hineingefüllt wurde. Der erste Tankvorgang füllte die
|
||||
Strecke DAVOR - ihn mitzuzählen hat den Verbrauch um einen ganzen
|
||||
Tankinhalt zu hoch ausgewiesen (bei 13 Tankvorgängen rund 8 %).
|
||||
Korrigiert am 2026-08-31. */
|
||||
liter = sum(mitOdo.slice(1), (f) => f.liters);
|
||||
} else {
|
||||
km = sum(TRIPS.filter((t) => t.distance_km != null && new Date(t.ts_start) <= bis), (t) => t.distance_km);
|
||||
/* Ohne Kilometerstände ist die Bezugsstrecke alles Erfasste bis zum
|
||||
letzten Tankstop - dann zählt auch der erste Tankvorgang dazu. */
|
||||
liter = sum(tanks, (f) => f.liters);
|
||||
}
|
||||
/* Eine negative Strecke ist kein Messwert, sondern ein falscher
|
||||
Kilometerstand an einem Tankvorgang (schon einmal aufgetreten, siehe
|
||||
AGENTS.md Abschnitt AF). Sie darf nicht als Zahl durchgehen. */
|
||||
if (km < 0) km = 0;
|
||||
const roh = km > 0 ? (liter / km) * 100 : null;
|
||||
/* Plausibilitätsfenster: alles außerhalb gilt als unbekannt, statt einen
|
||||
physikalisch unmöglichen Wert als Tatsache anzuzeigen. */
|
||||
const gueltig = roh != null && roh >= 3 && roh <= 30;
|
||||
return { wert: gueltig ? de(roh, 1) : "–", km, liter, bis, basis, unplausibel: roh != null && !gueltig };
|
||||
/* Auch eine Strecke von null zaehlt als unplausibel, wenn sie aus
|
||||
Kilometerstaenden kommt: dann laufen die Werte an den Tankvorgaengen
|
||||
rueckwaerts. Ohne diesen Zweig staende dort nur "0 km" und "-", ohne
|
||||
jeden Hinweis, woran es liegt. */
|
||||
const streckeFehlt = basis === "Kilometerstand an den Tankvorgängen" && km <= 0;
|
||||
return { wert: gueltig ? de(roh, 1) : "–", km, liter, bis, basis, unplausibel: (roh != null && !gueltig) || streckeFehlt };
|
||||
}
|
||||
function vStat() {
|
||||
const jahr = new Date().getFullYear();
|
||||
const fJahr = fahrtenSeit("jahr"), fMonat = fahrtenSeit("monat"), fWoche = fahrtenSeit("woche"), fTag = fahrtenSeit("tag");
|
||||
const fAbs = fahrtenSeit("absolut"), tAbs = tankSeit("absolut");
|
||||
const kmJahr = sum(fJahr, (t) => t.distance_km), hJahr = sum(fJahr, (t) => t.duration_s) / 3600;
|
||||
const tJahr = tankSeit("jahr");
|
||||
const lJahr = sum(tJahr, (f) => f.liters), eJahr = sum(tJahr, (f) => f.fuel_total_eur || 0);
|
||||
@@ -3637,11 +3656,11 @@ function vStat() {
|
||||
const lv = langzeitverbrauch();
|
||||
return `
|
||||
${statTile("s1", `Distanz und Fahrzeit ${jahr}`, de(kmJahr), "km", de(hJahr) + " h",
|
||||
quad("Gefahrene Distanz", [[de(kmJahr), "Jahr"], [de(sum(fMonat, (t) => t.distance_km)), "Monat"], [de(sum(fWoche, (t) => t.distance_km)), "Woche"], [de(sum(fTag, (t) => t.distance_km)), "Tag"]]) +
|
||||
quad("Fahrzeit", [[de(hJahr), "Jahr h"], [de(sum(fMonat, (t) => t.duration_s) / 3600), "Monat h"], [de(sum(fWoche, (t) => t.duration_s) / 3600, 1), "Woche h"], [de(sum(fTag, (t) => t.duration_s) / 3600, 1), "Tag h"]]))}
|
||||
quad("Gefahrene Distanz [km]", [[de(kmJahr), "Jahr"], [de(sum(fMonat, (t) => t.distance_km)), "Monat"], [de(sum(fWoche, (t) => t.distance_km)), "Woche"], [de(sum(fTag, (t) => t.distance_km)), "Tag"], [de(sum(fAbs, (t) => t.distance_km)), "Absolut"]]) +
|
||||
quad("Fahrzeit [h]", [[de(hJahr), "Jahr"], [de(sum(fMonat, (t) => t.duration_s) / 3600), "Monat"], [de(sum(fWoche, (t) => t.duration_s) / 3600, 1), "Woche"], [de(sum(fTag, (t) => t.duration_s) / 3600, 1), "Tag"], [de(sum(fAbs, (t) => t.duration_s) / 3600), "Absolut"]]))}
|
||||
${statTile("s2", `Getankte Menge und Kosten ${jahr}`, de(lJahr), "l", de(eJahr) + " €",
|
||||
quad("Getankte Liter", [[de(lJahr), "Jahr"], [de(sum(tankSeit("monat"), (f) => f.liters)), "Monat"], [de(sum(tankSeit("woche"), (f) => f.liters)), "Woche"], [de(sum(tankSeit("tag"), (f) => f.liters)), "Tag"]]) +
|
||||
quad("Kraftstoffkosten", [[de(eJahr), "Jahr €"], [de(sum(tankSeit("monat"), (f) => f.fuel_total_eur || 0)), "Monat €"], [de(sum(tankSeit("woche"), (f) => f.fuel_total_eur || 0)), "Woche €"], [de(sum(tankSeit("tag"), (f) => f.fuel_total_eur || 0)), "Tag €"]]))}
|
||||
quad("Getankte Liter [l]", [[de(lJahr), "Jahr"], [de(sum(tankSeit("monat"), (f) => f.liters)), "Monat"], [de(sum(tankSeit("woche"), (f) => f.liters)), "Woche"], [de(sum(tankSeit("tag"), (f) => f.liters)), "Tag"], [de(sum(tAbs, (f) => f.liters)), "Absolut"]]) +
|
||||
quad("Kraftstoffkosten [€]", [[de(eJahr), "Jahr"], [de(sum(tankSeit("monat"), (f) => f.fuel_total_eur || 0)), "Monat"], [de(sum(tankSeit("woche"), (f) => f.fuel_total_eur || 0)), "Woche"], [de(sum(tankSeit("tag"), (f) => f.fuel_total_eur || 0)), "Tag"], [de(sum(tAbs, (f) => f.fuel_total_eur || 0)), "Absolut"]]))}
|
||||
${statTile("s3", "Langzeitverbrauch", lv.wert, "l/100 km", lv.bis ? "bis " + dedat(lv.bis) : "–",
|
||||
`<dl class="rows">
|
||||
<div class="row"><dt>Getankt insgesamt</dt><dd>${de(lv.liter, 1)} l</dd></div>
|
||||
@@ -3649,7 +3668,7 @@ function vStat() {
|
||||
<div class="row" style="border-bottom:0"><dt>Letzter Tankstop</dt><dd>${lv.bis ? dedat(lv.bis) : "–"}</dd></div>
|
||||
</dl>
|
||||
${lv.unplausibel ? `<span class="label" style="margin-top:16px;color:var(--warn)">Aus Litern und Strecke ergibt sich derzeit kein plausibler Wert. Sobald Tankvorgänge und Kilometerstände vollständig vorliegen, erscheint er hier.</span>` : ""}
|
||||
${quad("Näherung je Fahrt, je Zeitraum", [[schnittFahrtVerbrauch(fJahr), "Jahr"], [schnittFahrtVerbrauch(fMonat), "Monat"], [schnittFahrtVerbrauch(fWoche), "Woche"], [schnittFahrtVerbrauch(fTag), "Tag"]])}
|
||||
${quad("Näherung je Fahrt, je Zeitraum [l/100 km]", [[schnittFahrtVerbrauch(fJahr), "Jahr"], [schnittFahrtVerbrauch(fMonat), "Monat"], [schnittFahrtVerbrauch(fWoche), "Woche"], [schnittFahrtVerbrauch(fTag), "Tag"], [schnittFahrtVerbrauch(fAbs), "Absolut"]])}
|
||||
<span class="label" style="margin-top:16px">Der Langzeitwert rechnet alle je getankten Liter gegen die Strecke bis zum letzten Tankstop. Die Werte je Zeitraum sind eine Näherung aus der Tankfüllstand-Differenz der einzelnen Fahrten, keine Meldung des Fahrzeugs.</span>`)}
|
||||
${statTile("s4", "Tag und Nacht", kmJahr > 0 ? de(Math.round((tagKm / kmJahr) * 100)) : "–", "% bei Tag", de(tagKm) + " km",
|
||||
`<div class="bar"><i style="flex:${tagKm};background:var(--fg)"></i><i style="flex:${nachtKm};background:var(--fg3)"></i></div>
|
||||
@@ -5747,7 +5766,6 @@ function ereignisseVerdrahten() {
|
||||
CAR.versicherung.selbst[+i][+feld] = e.target.value;
|
||||
profilSpeichern(); render(); return;
|
||||
}
|
||||
if (e.target.dataset.pause !== undefined) { CONFIG.pauseMin = parseInt(e.target.value, 10) || 0; profilSpeichern(); return; }
|
||||
if (e.target.dataset.sd !== undefined) {
|
||||
if (e.target.checked) { smartdealPopupOffen = true; render(); }
|
||||
else { CAR.smartdeal.aktiv = false; profilSpeichern(); render(); }
|
||||
|
||||
Reference in New Issue
Block a user