Skoda: Schluessel in den Einstellungen, Ladungen am Stueck, Wallbox in kW

- neuer Reiter "Fahrzeug": API-Schluessel eintragen und pruefen, ohne dass
  ein Wert je an den Browser zurueckgeht (restricted/skodaKeys.php)
- ajax/skoda.php trennt Ladungen am Zustand statt an 30 Minuten Pause und
  rahmt sie mit der Zeile davor und danach ein
- solarLog_skoda_ladepunkte.sql: Wallbox-Verlauf waehrend einer Ladung
- Kachelformat "leistung_kw" fuer Quellen, die schon Kilowatt melden
- Steckersymbol versteht evPlug als 1/0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 09:30:18 +02:00
co-authored by Claude Opus 5
parent b01e938905
commit deb81045d5
13 changed files with 1272 additions and 126 deletions
+36 -1
View File
@@ -649,7 +649,10 @@ function baueKurve() {
options: {
maintainAspectRatio: false,
animation: false,
interaction: { mode: "index", intersect: false },
// "nearest" statt "index": Wallbox-Verlauf und Fahrzeugmeldungen haben
// verschiedene Zeitpunkte, der n-te Wert der einen Reihe gehört nicht zum
// n-ten der anderen.
interaction: { mode: "nearest", axis: "x", intersect: false },
scales: {
// 'timestack' ist die Zeitachse, die diese Seite mitbringt
// (js/chartjs-scale-timestack.min.js). Chart.js' eingebautes 'time'
@@ -1151,6 +1154,38 @@ async function ladeKurve() {
// Date-Objekten - die nimmt sie stillschweigend nicht an und zeigt
// stattdessen den heutigen Tag.
const zeit = (p) => new Date(String(p.datetime).replace(" ", "T")).getTime();
// Mit Wallbox-Verlauf (skoda_ladepunkte): die Leistung im Minutentakt,
// der Ladestand dazwischen nach der geflossenen Energie aufgefüllt, und
// die echten Meldungen des Fahrzeugs als Punkte darauf - damit sichtbar
// bleibt, was gemessen und was abgeleitet ist. Das Fahrzeug meldet beim
// Laden mitunter nur einmal in der Stunde; eine Linie durch diese Punkte
// allein erfände den Verlauf dazwischen.
if (d.verlauf && d.verlauf.length) {
const imBild = (m) => zeit(m) >= zeit(d.verlauf[0]) - 600000
&& zeit(m) <= zeit(d.verlauf[d.verlauf.length - 1]) + 600000;
const meldungen = (d.meldungen || []).filter(imBild);
kurveChart.data.datasets = [
{ label: "Wallbox", yAxisID: "y", borderColor: "#4caf7d", backgroundColor: "rgba(76,175,125,.18)",
borderWidth: 2, pointRadius: 0, fill: "origin", tension: 0,
data: d.verlauf.map(p => ({ x: zeit(p), y: +p.kw })) },
{ label: "Ladestand, aufgefüllt", yAxisID: "y1", borderColor: "#f0b429", borderWidth: 2,
borderDash: [5, 4], pointRadius: 0, tension: 0, spanGaps: false,
data: d.verlauf.map(p => ({ x: zeit(p), y: p.soc === null ? null : +p.soc })) },
{ label: "Ladestand laut Fahrzeug", yAxisID: "y1", showLine: false,
borderColor: "#f0b429", backgroundColor: "#f0b429", pointRadius: 4, pointHoverRadius: 6,
data: meldungen.map(m => ({ x: zeit(m), y: +m.soc })) },
{ label: "Leistung laut Fahrzeug", yAxisID: "y", showLine: false,
borderColor: "#7aa7c7", backgroundColor: "#7aa7c7", pointRadius: 3, pointStyle: "rectRot",
data: meldungen.filter(m => m.chg_kw !== null && m.chg_state === "CHARGING")
.map(m => ({ x: zeit(m), y: +m.chg_kw })) }
];
kurveChart.update();
return;
}
// Ohne Wallbox-Verlauf - Ladungen von vor der Aufzeichnung - wie bisher
// aus den Zeilen der Fahrzeugtabelle.
kurveChart.data.datasets = [
{ label: "Wallbox", yAxisID: "y", borderColor: "#4caf7d", backgroundColor: "rgba(76,175,125,.18)",
borderWidth: 2, pointRadius: 0, fill: "origin", tension: .25,