Schmales Leerzeichen vor Einheiten in Uebersicht, Anlage, Speicher, Ladefenster
Vor W, kW, kWh, V, mV, A, % und °C steht jetzt ueberall U+2009 wie in der Uebersicht von Hand begonnen (65 Stellen, nur in Anzeigetexten; CSS-Werte und freistehende Achseneinheiten bleiben). Dazu "Wirkungsgrad 96 %" mit Leerzeichen und die Heizstab-Temperaturen mit " / " wie Sonne und Netz. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+4
-4
@@ -65,7 +65,7 @@ $box = wallboxen()[$wallbox];
|
|||||||
<output data-lade="zielAusgabe"></output>
|
<output data-lade="zielAusgabe"></output>
|
||||||
</div>
|
</div>
|
||||||
<input type="range" id="lade-ziel-<?= $wallbox ?>" data-lade="ziel" min="0" max="100" step="5" value="80">
|
<input type="range" id="lade-ziel-<?= $wallbox ?>" data-lade="ziel" min="0" max="100" step="5" value="80">
|
||||||
<div class="lade-marken"><span data-lade="markeLinks">0 %</span><span data-lade="markeMitte"></span><span>100 %</span></div>
|
<div class="lade-marken"><span data-lade="markeLinks">0 %</span><span data-lade="markeMitte"></span><span>100 %</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="lade-plan-zeile"><label>Abfahrt</label><output data-lade="abfahrtAusgabe"></output></div>
|
<div class="lade-plan-zeile"><label>Abfahrt</label><output data-lade="abfahrtAusgabe"></output></div>
|
||||||
@@ -88,9 +88,9 @@ $box = wallboxen()[$wallbox];
|
|||||||
<div class="lade-abschnitt">
|
<div class="lade-abschnitt">
|
||||||
<h3 id="lade-strom-<?= $wallbox ?>">Höchstens</h3>
|
<h3 id="lade-strom-<?= $wallbox ?>">Höchstens</h3>
|
||||||
<div class="lade-strom" role="radiogroup" aria-labelledby="lade-strom-<?= $wallbox ?>">
|
<div class="lade-strom" role="radiogroup" aria-labelledby="lade-strom-<?= $wallbox ?>">
|
||||||
<button type="button" role="radio" aria-checked="false" data-ampere="6"><b>6 A</b><span>≈ 4,1 kW</span></button>
|
<button type="button" role="radio" aria-checked="false" data-ampere="6"><b>6 A</b><span>≈ 4,1 kW</span></button>
|
||||||
<button type="button" role="radio" aria-checked="false" data-ampere="10"><b>10 A</b><span>≈ 6,9 kW</span></button>
|
<button type="button" role="radio" aria-checked="false" data-ampere="10"><b>10 A</b><span>≈ 6,9 kW</span></button>
|
||||||
<button type="button" role="radio" aria-checked="false" data-ampere="16"><b>16 A</b><span>≈ 11 kW</span></button>
|
<button type="button" role="radio" aria-checked="false" data-ampere="16"><b>16 A</b><span>≈ 11 kW</span></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -32,8 +32,8 @@
|
|||||||
|
|
||||||
let laufendeNummer = 0;
|
let laufendeNummer = 0;
|
||||||
|
|
||||||
const kw = w => (Math.abs(w) / 1000).toFixed(Math.abs(w) < 10000 ? 2 : 1).replace(".", ",") + " kW";
|
const kw = w => (Math.abs(w) / 1000).toFixed(Math.abs(w) < 10000 ? 2 : 1).replace(".", ",") + " kW";
|
||||||
const watt = w => Math.abs(w) < 1000 ? Math.round(w) + " W" : kw(w);
|
const watt = w => Math.abs(w) < 1000 ? Math.round(w) + " W" : kw(w);
|
||||||
const schutz = s => String(s).replace(/[&<>"]/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """ }[c]));
|
const schutz = s => String(s).replace(/[&<>"]/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """ }[c]));
|
||||||
|
|
||||||
function el(name, attr, eltern) {
|
function el(name, attr, eltern) {
|
||||||
@@ -393,7 +393,7 @@
|
|||||||
<div class="anl-flaeche" style="--farbe:${s.f.farbe}">
|
<div class="anl-flaeche" style="--farbe:${s.f.farbe}">
|
||||||
<div class="anl-flaeche-kopf"><i></i><span>${schutz(s.f.name)}</span><b>${kw(s.w)}</b></div>
|
<div class="anl-flaeche-kopf"><i></i><span>${schutz(s.f.name)}</span><b>${kw(s.w)}</b></div>
|
||||||
<div class="anl-flaeche-balken"><span style="width:${(s.w / summe * 100).toFixed(1)}%"></span></div>
|
<div class="anl-flaeche-balken"><span style="width:${(s.w / summe * 100).toFixed(1)}%"></span></div>
|
||||||
<small>${s.n} Platten · ${Math.round(s.w / summe * 100)} % der Erzeugung</small>
|
<small>${s.n} Platten · ${Math.round(s.w / summe * 100)} % der Erzeugung</small>
|
||||||
</div>`).join("");
|
</div>`).join("");
|
||||||
if (this.dom.flaechen._html !== flaechenHtml) {
|
if (this.dom.flaechen._html !== flaechenHtml) {
|
||||||
// Beim ersten Mal ganz schreiben, danach nur Werte - sonst springen die Balken.
|
// Beim ersten Mal ganz schreiben, danach nur Werte - sonst springen die Balken.
|
||||||
@@ -404,7 +404,7 @@
|
|||||||
const s = summen[i];
|
const s = summen[i];
|
||||||
c.querySelector("b").textContent = kw(s.w);
|
c.querySelector("b").textContent = kw(s.w);
|
||||||
c.querySelector(".anl-flaeche-balken span").style.width = (s.w / summe * 100).toFixed(1) + "%";
|
c.querySelector(".anl-flaeche-balken span").style.width = (s.w / summe * 100).toFixed(1) + "%";
|
||||||
c.querySelector("small").textContent = s.n + " Platten · " + Math.round(s.w / summe * 100) + " % der Erzeugung";
|
c.querySelector("small").textContent = s.n + " Platten · " + Math.round(s.w / summe * 100) + " % der Erzeugung";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.dom.flaechen._html = flaechenHtml;
|
this.dom.flaechen._html = flaechenHtml;
|
||||||
@@ -419,7 +419,7 @@
|
|||||||
const ausl = w.limit > 0 ? Math.min(100, w.ac / w.limit * 100) : 0;
|
const ausl = w.limit > 0 ? Math.min(100, w.ac / w.limit * 100) : 0;
|
||||||
const aktiv = wahlWr === d.nr ? ' aria-pressed="true"' : ' aria-pressed="false"';
|
const aktiv = wahlWr === d.nr ? ' aria-pressed="true"' : ' aria-pressed="false"';
|
||||||
return `<li><button type="button" data-wahl="wr:${d.nr}"${aktiv}>
|
return `<li><button type="button" data-wahl="wr:${d.nr}"${aktiv}>
|
||||||
<span class="anl-wr-name">${schutz(d.name)}<small>${schutz(d.modell)}${w.temp > 0 && !w.gestoert ? " · " + Math.round(w.temp) + " °C" : ""}</small></span>
|
<span class="anl-wr-name">${schutz(d.name)}<small>${schutz(d.modell)}${w.temp > 0 && !w.gestoert ? " · " + Math.round(w.temp) + " °C" : ""}</small></span>
|
||||||
<span class="anl-wr-wert">${w.gestoert ? "–" : watt(w.ac)}${w.limit > 0 ? `<span class="anl-wr-last"><span style="width:${ausl.toFixed(0)}%"></span></span>` : ""}</span>
|
<span class="anl-wr-wert">${w.gestoert ? "–" : watt(w.ac)}${w.limit > 0 ? `<span class="anl-wr-last"><span style="width:${ausl.toFixed(0)}%"></span></span>` : ""}</span>
|
||||||
${pille}
|
${pille}
|
||||||
</button></li>`;
|
</button></li>`;
|
||||||
@@ -452,7 +452,7 @@
|
|||||||
: '<span class="anl-pille anl-ok">normal</span>';
|
: '<span class="anl-pille anl-ok">normal</span>';
|
||||||
const vergleich = p.offline ? "Wechselrichter meldet nichts"
|
const vergleich = p.offline ? "Wechselrichter meldet nichts"
|
||||||
: mittel[p.def.flaeche] < SCHWACHLICHT ? "zu wenig Licht zum Vergleichen"
|
: mittel[p.def.flaeche] < SCHWACHLICHT ? "zu wenig Licht zum Vergleichen"
|
||||||
: Math.round(p.anteil * 100) + " % des Mittels " + f.name;
|
: Math.round(p.anteil * 100) + " % des Mittels " + f.name;
|
||||||
return `
|
return `
|
||||||
<div class="anl-kopf"><h3 class="anl-ueberschrift">${schutz(this.plattenName(p))}</h3>${pille}</div>
|
<div class="anl-kopf"><h3 class="anl-ueberschrift">${schutz(this.plattenName(p))}</h3>${pille}</div>
|
||||||
<div class="anl-gross"><b>${p.offline ? "–" : watt(p.w)}</b><span>${vergleich}</span></div>
|
<div class="anl-gross"><b>${p.offline ? "–" : watt(p.w)}</b><span>${vergleich}</span></div>
|
||||||
@@ -461,7 +461,7 @@
|
|||||||
<dt>Wechselrichter</dt><dd><button type="button" class="anl-link" data-wahl="wr:${p.wr.def.nr}">${schutz(p.wr.def.name)}</button></dd>
|
<dt>Wechselrichter</dt><dd><button type="button" class="anl-link" data-wahl="wr:${p.wr.def.nr}">${schutz(p.wr.def.name)}</button></dd>
|
||||||
<dt>Eingang</dt><dd>${p.index + 1} von ${p.wr.def.eingaenge.length}</dd>
|
<dt>Eingang</dt><dd>${p.index + 1} von ${p.wr.def.eingaenge.length}</dd>
|
||||||
<dt>Mittel ${schutz(f.name)}</dt><dd>${watt(mittel[p.def.flaeche])}</dd>
|
<dt>Mittel ${schutz(f.name)}</dt><dd>${watt(mittel[p.def.flaeche])}</dd>
|
||||||
<dt>Temperatur Wechselrichter</dt><dd>${p.wr.temp > 0 && !p.offline ? Math.round(p.wr.temp) + " °C" : "–"}</dd>
|
<dt>Temperatur Wechselrichter</dt><dd>${p.wr.temp > 0 && !p.offline ? Math.round(p.wr.temp) + " °C" : "–"}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
${p.klasse === "schwach" ? '<p class="anl-hinweis">Liefert deutlich weniger als die anderen Platten dieser Fläche. Mögliche Gründe: Verschattung, Schmutz, ein loser Stecker – oder die Platte liegt anders ausgerichtet.</p>' : ""}`;
|
${p.klasse === "schwach" ? '<p class="anl-hinweis">Liefert deutlich weniger als die anderen Platten dieser Fläche. Mögliche Gründe: Verschattung, Schmutz, ein loser Stecker – oder die Platte liegt anders ausgerichtet.</p>' : ""}`;
|
||||||
}
|
}
|
||||||
@@ -505,8 +505,8 @@
|
|||||||
<div class="anl-gross"><b>${w.gestoert ? "–" : watt(w.ac)}</b><span>${schutz(w.def.modell)}</span></div>
|
<div class="anl-gross"><b>${w.gestoert ? "–" : watt(w.ac)}</b><span>${schutz(w.def.modell)}</span></div>
|
||||||
<ul class="anl-eingaenge">${eingaenge}</ul>
|
<ul class="anl-eingaenge">${eingaenge}</ul>
|
||||||
<dl class="anl-paare">
|
<dl class="anl-paare">
|
||||||
${w.limit > 0 ? `<dt>Leistungsgrenze</dt><dd>${watt(w.limit)} · ${Math.round(w.ac / w.limit * 100)} % genutzt</dd>` : ""}
|
${w.limit > 0 ? `<dt>Leistungsgrenze</dt><dd>${watt(w.limit)} · ${Math.round(w.ac / w.limit * 100)} % genutzt</dd>` : ""}
|
||||||
<dt>Temperatur</dt><dd>${w.temp > 0 && !w.gestoert ? Math.round(w.temp) + " °C" : "–"}</dd>
|
<dt>Temperatur</dt><dd>${w.temp > 0 && !w.gestoert ? Math.round(w.temp) + " °C" : "–"}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
${w.gestoert ? '<p class="anl-hinweis">Der Wechselrichter antwortet der DTU gerade nicht. Seine Platten stehen deshalb auf „ohne Daten“ – über ihren Zustand sagt das nichts.</p>' : ""}
|
${w.gestoert ? '<p class="anl-hinweis">Der Wechselrichter antwortet der DTU gerade nicht. Seine Platten stehen deshalb auf „ohne Daten“ – über ihren Zustand sagt das nichts.</p>' : ""}
|
||||||
${w.geschaetzt ? '<p class="anl-hinweis">Aktuelle Werte fehlen; die Leistung ist aus den anderen Wechselrichtern hochgerechnet.</p>' : ""}`;
|
${w.geschaetzt ? '<p class="anl-hinweis">Aktuelle Werte fehlen; die Leistung ist aus den anderen Wechselrichtern hochgerechnet.</p>' : ""}`;
|
||||||
@@ -521,7 +521,7 @@
|
|||||||
const punkte = [
|
const punkte = [
|
||||||
...ohne.map(w => `<li><button type="button" data-wahl="wr:${w.def.nr}"><span class="anl-pille anl-krit">keine Daten</span>${schutz(w.def.name)}</button></li>`),
|
...ohne.map(w => `<li><button type="button" data-wahl="wr:${w.def.nr}"><span class="anl-pille anl-krit">keine Daten</span>${schutz(w.def.name)}</button></li>`),
|
||||||
...geschaetzt.map(w => `<li><button type="button" data-wahl="wr:${w.def.nr}"><span class="anl-pille anl-warn">hochgerechnet</span>${schutz(w.def.name)}</button></li>`),
|
...geschaetzt.map(w => `<li><button type="button" data-wahl="wr:${w.def.nr}"><span class="anl-pille anl-warn">hochgerechnet</span>${schutz(w.def.name)}</button></li>`),
|
||||||
...auffaellig.map(p => `<li><button type="button" data-wahl="platte:${p.def.eingang}"><span class="anl-pille anl-krit">${Math.round(p.anteil * 100)} %</span>${schutz(this.plattenName(p))}</button></li>`),
|
...auffaellig.map(p => `<li><button type="button" data-wahl="platte:${p.def.eingang}"><span class="anl-pille anl-krit">${Math.round(p.anteil * 100)} %</span>${schutz(this.plattenName(p))}</button></li>`),
|
||||||
];
|
];
|
||||||
return `
|
return `
|
||||||
<div class="anl-kopf"><h3 class="anl-ueberschrift">Anlage</h3><span class="anl-pille ${punkte.length ? "anl-warn" : "anl-ok"}">${punkte.length ? punkte.length + " Hinweis" + (punkte.length > 1 ? "e" : "") : "alles in Ordnung"}</span></div>
|
<div class="anl-kopf"><h3 class="anl-ueberschrift">Anlage</h3><span class="anl-pille ${punkte.length ? "anl-warn" : "anl-ok"}">${punkte.length ? punkte.length + " Hinweis" + (punkte.length > 1 ? "e" : "") : "alles in Ordnung"}</span></div>
|
||||||
|
|||||||
@@ -164,8 +164,8 @@
|
|||||||
|
|
||||||
function leistungText(w) {
|
function leistungText(w) {
|
||||||
const a = Math.abs(w);
|
const a = Math.abs(w);
|
||||||
if (a < 1000) return Math.round(a) + " W";
|
if (a < 1000) return Math.round(a) + " W";
|
||||||
return (a / 1000).toFixed(a < 10000 ? 2 : 1).replace(".", ",") + " kW";
|
return (a / 1000).toFixed(a < 10000 ? 2 : 1).replace(".", ",") + " kW";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Liest mqttData: Werte kommen als Buffer, Zahl und Text wie gehabt. */
|
/** Liest mqttData: Werte kommen als Buffer, Zahl und Text wie gehabt. */
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ const ENERGIEFLUSS_KATALOG = (function () {
|
|||||||
const a = n => (Math.round(Math.abs(m.zahl("solarManager/i_" + n + "evu")) * 10) / 10).toString().replace(".", ",");
|
const a = n => (Math.round(Math.abs(m.zahl("solarManager/i_" + n + "evu")) * 10) / 10).toString().replace(".", ",");
|
||||||
return {
|
return {
|
||||||
leistung: Math.abs(netz),
|
leistung: Math.abs(netz),
|
||||||
neben: a("l1") + " / " + a("l2") + " / " + a("l3") + " A",
|
neben: a("l1") + " / " + a("l2") + " / " + a("l3") + " A",
|
||||||
fluss: -netz,
|
fluss: -netz,
|
||||||
ruhe: Math.abs(netz) < 30,
|
ruhe: Math.abs(netz) < 30,
|
||||||
};
|
};
|
||||||
@@ -130,7 +130,7 @@ const ENERGIEFLUSS_KATALOG = (function () {
|
|||||||
const laden = p < -20;
|
const laden = p < -20;
|
||||||
const zeichen = [];
|
const zeichen = [];
|
||||||
if (laden && grenze < 100) {
|
if (laden && grenze < 100) {
|
||||||
zeichen.push({ art: "uhr", text: Math.round(grenze) + " %", titel: "Ladeleistung begrenzt" });
|
zeichen.push({ art: "uhr", text: Math.round(grenze) + " %", titel: "Ladeleistung begrenzt" });
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
leistung: Math.abs(p),
|
leistung: Math.abs(p),
|
||||||
@@ -151,8 +151,8 @@ const ENERGIEFLUSS_KATALOG = (function () {
|
|||||||
const aut = m.zahl("solarManager/autarky");
|
const aut = m.zahl("solarManager/autarky");
|
||||||
return {
|
return {
|
||||||
leistung: aut,
|
leistung: aut,
|
||||||
wert: Math.round(aut) + " %",
|
wert: Math.round(aut) + " %",
|
||||||
neben: "Wirkungsgrad " + Math.round(m.zahl("solarManager/eff")) + "%",
|
neben: "Wirkungsgrad " + Math.round(m.zahl("solarManager/eff")) + " %",
|
||||||
segmente: [{ w: aut, farbe: "#6cbe58" }],
|
segmente: [{ w: aut, farbe: "#6cbe58" }],
|
||||||
zustand: { an: m.zahl("solarManager/P_PV") >= 20 },
|
zustand: { an: m.zahl("solarManager/P_PV") >= 20 },
|
||||||
};
|
};
|
||||||
@@ -174,7 +174,7 @@ const ENERGIEFLUSS_KATALOG = (function () {
|
|||||||
const allgemein = Math.max(0, gemein - heiz);
|
const allgemein = Math.max(0, gemein - heiz);
|
||||||
return {
|
return {
|
||||||
leistung: last,
|
leistung: last,
|
||||||
neben: "Gemein " + kw(gemein) + " kW",
|
neben: "Gemein " + kw(gemein) + " kW",
|
||||||
segmente: [
|
segmente: [
|
||||||
{ w: og, farbe: "#70ccbb", knoten: "og" },
|
{ w: og, farbe: "#70ccbb", knoten: "og" },
|
||||||
{ w: eg, farbe: "#70cc9c", knoten: "eg" },
|
{ w: eg, farbe: "#70cc9c", knoten: "eg" },
|
||||||
@@ -238,7 +238,7 @@ const ENERGIEFLUSS_KATALOG = (function () {
|
|||||||
const grad = t => (Math.round(t * 10) / 10).toString().replace(".", ",");
|
const grad = t => (Math.round(t * 10) / 10).toString().replace(".", ",");
|
||||||
return {
|
return {
|
||||||
leistung: w, fluss: w, ruhe: w < 20,
|
leistung: w, fluss: w, ruhe: w < 20,
|
||||||
neben: grad(oben) + " · " + grad(mitte) + " °C",
|
neben: grad(oben) + " / " + grad(mitte) + " °C",
|
||||||
zeichen: [eco ? { art: "eco", titel: "Automatik (Überschuss)" } : { art: "manuell", titel: "Feste Leistung" }],
|
zeichen: [eco ? { art: "eco", titel: "Automatik (Überschuss)" } : { art: "manuell", titel: "Feste Leistung" }],
|
||||||
zustand: { an: w >= 20, temps: [oben, mitte, unten] },
|
zustand: { an: w >= 20, temps: [oben, mitte, unten] },
|
||||||
};
|
};
|
||||||
@@ -271,7 +271,7 @@ const ENERGIEFLUSS_KATALOG = (function () {
|
|||||||
// Text der Wallbox ("no car", "charging", ...).
|
// Text der Wallbox ("no car", "charging", ...).
|
||||||
const roh = m.text("solarManager/evPlug");
|
const roh = m.text("solarManager/evPlug");
|
||||||
const stecker = isNaN(Number(roh)) ? (roh !== undefined && roh !== "no car") : Number(roh) > 0;
|
const stecker = isNaN(Number(roh)) ? (roh !== undefined && roh !== "no car") : Number(roh) > 0;
|
||||||
let neben = Math.round(soc) + " %";
|
let neben = Math.round(soc) + " %";
|
||||||
// Restladezeit in Minuten laut Fahrzeug (gatherSkodaData.py). Das
|
// Restladezeit in Minuten laut Fahrzeug (gatherSkodaData.py). Das
|
||||||
// frühere carRemChrg schickt der Manager nicht mehr.
|
// frühere carRemChrg schickt der Manager nicht mehr.
|
||||||
const rest = m.zahl("solarManager/evRemChrgTime");
|
const rest = m.zahl("solarManager/evRemChrgTime");
|
||||||
@@ -280,7 +280,7 @@ const ENERGIEFLUSS_KATALOG = (function () {
|
|||||||
neben = "fertig " + String(fertig.getHours()).padStart(2, "0") + ":" + String(fertig.getMinutes()).padStart(2, "0");
|
neben = "fertig " + String(fertig.getHours()).padStart(2, "0") + ":" + String(fertig.getMinutes()).padStart(2, "0");
|
||||||
}
|
}
|
||||||
const zeichen = wallboxZeichen(m.text("solarManager/evMode"), stecker, m.zahl("solarManager/evLock") > 0);
|
const zeichen = wallboxZeichen(m.text("solarManager/evMode"), stecker, m.zahl("solarManager/evLock") > 0);
|
||||||
if (tank > 0) zeichen.push({ art: "tank", text: Math.round(tank) + " %", titel: "Tank" });
|
if (tank > 0) zeichen.push({ art: "tank", text: Math.round(tank) + " %", titel: "Tank" });
|
||||||
return {
|
return {
|
||||||
leistung: w, fluss: w, ruhe: w < 50 && !stecker,
|
leistung: w, fluss: w, ruhe: w < 50 && !stecker,
|
||||||
neben, zeichen,
|
neben, zeichen,
|
||||||
|
|||||||
@@ -135,18 +135,18 @@
|
|||||||
const zb = wurzel.querySelector(".lade-ziel");
|
const zb = wurzel.querySelector(".lade-ziel");
|
||||||
zb.style.strokeDasharray = zielBogen + " 100";
|
zb.style.strokeDasharray = zielBogen + " 100";
|
||||||
zb.style.strokeDashoffset = -ist;
|
zb.style.strokeDashoffset = -ist;
|
||||||
setze("soc", mitSoc ? Math.round(s.soc) + " %" : (Number(wurzel.dataset.akkuKwh) ? komma(Number(wurzel.dataset.akkuKwh)) + " kWh" : "–"));
|
setze("soc", mitSoc ? Math.round(s.soc) + " %" : (Number(wurzel.dataset.akkuKwh) ? komma(Number(wurzel.dataset.akkuKwh)) + " kWh" : "–"));
|
||||||
setze("ringUnten", s.modus === "plan" ? (mitSoc ? "Ziel " + s.ziel + " %" : "+ " + s.ziel + " %") : mitSoc ? "Ladestand" : "Akku");
|
setze("ringUnten", s.modus === "plan" ? (mitSoc ? "Ziel " + s.ziel + " %" : "+ " + s.ziel + " %") : mitSoc ? "Ladestand" : "Akku");
|
||||||
|
|
||||||
// Zustand
|
// Zustand
|
||||||
const zustand = laedt ? "lädt" : s.frc === 1 ? "gestoppt" : s.auto === "fertig" ? "beendet" : s.auto === "kein" ? "kein Auto" : "wartet";
|
const zustand = laedt ? "lädt" : s.frc === 1 ? "gestoppt" : s.auto === "fertig" ? "beendet" : s.auto === "kein" ? "kein Auto" : "wartet";
|
||||||
$("leistung").innerHTML = komma(s.kw) + " kW<small>" + zustand + "</small>";
|
$("leistung").innerHTML = komma(s.kw) + " kW<small>" + zustand + "</small>";
|
||||||
const pille = $("stecker");
|
const pille = $("stecker");
|
||||||
const pilleText = s.auto === "kein" ? "kein Auto" : s.auto === "laedt" ? "lädt" : s.auto === "fertig" ? "beendet" : s.auto ? "angesteckt" : "";
|
const pilleText = s.auto === "kein" ? "kein Auto" : s.auto === "laedt" ? "lädt" : s.auto === "fertig" ? "beendet" : s.auto ? "angesteckt" : "";
|
||||||
setze("stecker", pilleText);
|
setze("stecker", pilleText);
|
||||||
pille.className = "lade-pille" + (s.auto && s.auto !== "kein" ? " an" : "");
|
pille.className = "lade-pille" + (s.auto && s.auto !== "kein" ? " an" : "");
|
||||||
const anteil = laedt && s.kw > 0 ? Math.max(0, Math.min(1, 1 - Math.max(0, s.netz) / (s.kw * 1000))) : null;
|
const anteil = laedt && s.kw > 0 ? Math.max(0, Math.min(1, 1 - Math.max(0, s.netz) / (s.kw * 1000))) : null;
|
||||||
setze("quelle", anteil !== null ? Math.round(anteil * 100) + " % aus Sonnenstrom" : "");
|
setze("quelle", anteil !== null ? Math.round(anteil * 100) + " % aus Sonnenstrom" : "");
|
||||||
let fertig = "";
|
let fertig = "";
|
||||||
if (laedt && s.restMin > 0) fertig = "fertig " + inStunden(s.restMin / 60);
|
if (laedt && s.restMin > 0) fertig = "fertig " + inStunden(s.restMin / 60);
|
||||||
else if (s.modus === "plan") fertig = "Ziel bis " + naechstes(s.zeit);
|
else if (s.modus === "plan") fertig = "Ziel bis " + naechstes(s.zeit);
|
||||||
@@ -168,9 +168,9 @@
|
|||||||
// Erklärung
|
// Erklärung
|
||||||
const kwMax = KW_JE_A[s.ampere] || (s.ampere ? s.ampere * 0.69 : 11);
|
const kwMax = KW_JE_A[s.ampere] || (s.ampere ? s.ampere * 0.69 : 11);
|
||||||
let erkl = {
|
let erkl = {
|
||||||
sofort: "Lädt mit bis zu " + komma(kwMax) + " kW – reicht die Sonne nicht, kommt der Rest aus dem Netz.",
|
sofort: "Lädt mit bis zu " + komma(kwMax) + " kW – reicht die Sonne nicht, kommt der Rest aus dem Netz.",
|
||||||
sonne: "Lädt nur mit Überschuss. Scheint zu wenig Sonne, pausiert die Ladung.",
|
sonne: "Lädt nur mit Überschuss. Scheint zu wenig Sonne, pausiert die Ladung.",
|
||||||
plan: "Lädt bis " + naechstes(s.zeit) + (mitSoc ? " auf " + s.ziel + " %" : " " + s.ziel + " % nach") + " – bevorzugt mit Sonnenstrom, nötigenfalls aus dem Netz.",
|
plan: "Lädt bis " + naechstes(s.zeit) + (mitSoc ? " auf " + s.ziel + " %" : " " + s.ziel + " % nach") + " – bevorzugt mit Sonnenstrom, nötigenfalls aus dem Netz.",
|
||||||
}[s.modus] || "";
|
}[s.modus] || "";
|
||||||
if (s.frc === 1) erkl = "Gestoppt: die Wallbox lädt erst wieder nach „Ladung freigeben“ – dann entscheidet der Modus.";
|
if (s.frc === 1) erkl = "Gestoppt: die Wallbox lädt erst wieder nach „Ladung freigeben“ – dann entscheidet der Modus.";
|
||||||
if (s.frc === 2) erkl = "Lädt sofort, unabhängig vom Modus. „Zurück zur Automatik“ überlässt es wieder dem Modus.";
|
if (s.frc === 2) erkl = "Lädt sofort, unabhängig vom Modus. „Zurück zur Automatik“ überlässt es wieder dem Modus.";
|
||||||
@@ -190,9 +190,9 @@
|
|||||||
regler.style.setProperty("--ist", (mitSoc ? s.soc : 0) + "%");
|
regler.style.setProperty("--ist", (mitSoc ? s.soc : 0) + "%");
|
||||||
regler.style.setProperty("--wert", wert + "%");
|
regler.style.setProperty("--wert", wert + "%");
|
||||||
setze("zielTitel", mitSoc ? "Ladestand bei Abfahrt" : "Zusätzlich laden");
|
setze("zielTitel", mitSoc ? "Ladestand bei Abfahrt" : "Zusätzlich laden");
|
||||||
setze("markeMitte", mitSoc ? "jetzt " + Math.round(s.soc) + " %" : "");
|
setze("markeMitte", mitSoc ? "jetzt " + Math.round(s.soc) + " %" : "");
|
||||||
const plusWh = mitSoc ? Math.max(0, wert - s.soc) * whProProzent : wert * whProProzent;
|
const plusWh = mitSoc ? Math.max(0, wert - s.soc) * whProProzent : wert * whProProzent;
|
||||||
$("zielAusgabe").innerHTML = wert + " %<small>" + (plusWh > 0 ? "+ " + komma(plusWh / 1000) + " kWh" : "schon erreicht") + "</small>";
|
$("zielAusgabe").innerHTML = wert + " %<small>" + (plusWh > 0 ? "+ " + komma(plusWh / 1000) + " kWh" : "schon erreicht") + "</small>";
|
||||||
setze("abfahrtAusgabe", naechstes(s.zeit));
|
setze("abfahrtAusgabe", naechstes(s.zeit));
|
||||||
let bekannt = false;
|
let bekannt = false;
|
||||||
wurzel.querySelectorAll("[data-zeit]").forEach(c => {
|
wurzel.querySelectorAll("[data-zeit]").forEach(c => {
|
||||||
|
|||||||
+23
-23
@@ -233,25 +233,25 @@
|
|||||||
const h = kwh * soc / 100 / (-p / 1000);
|
const h = kwh * soc / 100 / (-p / 1000);
|
||||||
prognose = "leer " + wann(h);
|
prognose = "leer " + wann(h);
|
||||||
}
|
}
|
||||||
if (p > 50 && s.grenze > 0 && s.grenze < 100) prognose += " · begrenzt auf " + Math.round(s.grenze) + " %";
|
if (p > 50 && s.grenze > 0 && s.grenze < 100) prognose += " · begrenzt auf " + Math.round(s.grenze) + " %";
|
||||||
|
|
||||||
const kacheln = [
|
const kacheln = [
|
||||||
{ titel: "Ladestand", zeichen: "\uF187", wert: Math.round(soc) + " %", neben: kwh ? "≈ " + komma(kwh * soc / 100) + " von " + komma(kwh) + " kWh" : "", balken: soc },
|
{ titel: "Ladestand", zeichen: "\uF187", wert: Math.round(soc) + " %", neben: kwh ? "≈ " + komma(kwh * soc / 100) + " von " + komma(kwh) + " kWh" : "", balken: soc },
|
||||||
{ titel: "Leistung", zeichen: p > 50 ? "\uF185" : "\uF46E", wert: (p > 50 ? "+" : p < -50 ? "−" : "") + komma(Math.abs(p) < 50 ? 0 : Math.abs(p) / 1000, 2) + " kW",
|
{ titel: "Leistung", zeichen: p > 50 ? "\uF185" : "\uF46E", wert: (p > 50 ? "+" : p < -50 ? "−" : "") + komma(Math.abs(p) < 50 ? 0 : Math.abs(p) / 1000, 2) + " kW",
|
||||||
neben: (p > 50 ? "lädt · " : p < -50 ? "entlädt · " : "") + prognose, klasse: p > 50 ? "spk-gut" : p < -50 ? "spk-warm" : "" },
|
neben: (p > 50 ? "lädt · " : p < -50 ? "entlädt · " : "") + prognose, klasse: p > 50 ? "spk-gut" : p < -50 ? "spk-warm" : "" },
|
||||||
];
|
];
|
||||||
if (s.bmu) {
|
if (s.bmu) {
|
||||||
const zyklen = kwh ? s.entladen / kwh : 0;
|
const zyklen = kwh ? s.entladen / kwh : 0;
|
||||||
kacheln.push(
|
kacheln.push(
|
||||||
{ titel: "Gesundheit", zeichen: "\uF76E", wert: komma(s.soh, 0) + " %", neben: "SOH laut BMU" },
|
{ titel: "Gesundheit", zeichen: "\uF76E", wert: komma(s.soh, 0) + " %", neben: "SOH laut BMU" },
|
||||||
{ titel: "Zellspreizung", zeichen: "\uF304", wert: tausend(s.spreizung) + " mV",
|
{ titel: "Zellspreizung", zeichen: "\uF304", wert: tausend(s.spreizung) + " mV",
|
||||||
neben: komma(s.zelleMin / 1000, 3) + "–" + komma(s.zelleMax / 1000, 3) + " V",
|
neben: komma(s.zelleMin / 1000, 3) + "–" + komma(s.zelleMax / 1000, 3) + " V",
|
||||||
klasse: s.spreizung > 30 ? "spk-warm" : "" },
|
klasse: s.spreizung > 30 ? "spk-warm" : "" },
|
||||||
{ titel: "Temperatur", zeichen: "\uF5CD", wert: Math.round(s.tMin) + "–" + Math.round(s.tMax) + " °C", neben: (s.temps || []).length + " Fühler" },
|
{ titel: "Temperatur", zeichen: "\uF5CD", wert: Math.round(s.tMin) + "–" + Math.round(s.tMax) + " °C", neben: (s.temps || []).length + " Fühler" },
|
||||||
{ titel: "Spannung", zeichen: "\uF66B", wert: komma(s.spannung) + " V", neben: komma(s.strom) + " A" },
|
{ titel: "Spannung", zeichen: "\uF66B", wert: komma(s.spannung) + " V", neben: komma(s.strom) + " A" },
|
||||||
{ titel: "Durchsatz", zeichen: "\uF130", wert: tausend(s.entladen) + " kWh",
|
{ titel: "Durchsatz", zeichen: "\uF130", wert: tausend(s.entladen) + " kWh",
|
||||||
neben: "≈ " + tausend(zyklen) + " Zyklen · " + (s.geladen ? Math.round(s.entladen / s.geladen * 100) : 0) + " % zurück",
|
neben: "≈ " + tausend(zyklen) + " Zyklen · " + (s.geladen ? Math.round(s.entladen / s.geladen * 100) : 0) + " % zurück",
|
||||||
titelLang: "entladen seit Inbetriebnahme; Zyklen gerechnet mit " + komma(kwh) + " kWh; zurück = entladen je geladen" },
|
titelLang: "entladen seit Inbetriebnahme; Zyklen gerechnet mit " + komma(kwh) + " kWh; zurück = entladen je geladen" },
|
||||||
{ titel: "Zustand", zeichen: s.fehler ? "\uF33A" : "\uF26A", wert: s.fehler ? "Fehler" : "in Ordnung",
|
{ titel: "Zustand", zeichen: s.fehler ? "\uF33A" : "\uF26A", wert: s.fehler ? "Fehler" : "in Ordnung",
|
||||||
neben: (s.firmware || "") + (s.ausgleich ? " · gleicht " + s.ausgleich + " Zellen aus" : ""), klasse: s.fehler ? "spk-krit" : "spk-gut" },
|
neben: (s.firmware || "") + (s.ausgleich ? " · gleicht " + s.ausgleich + " Zellen aus" : ""), klasse: s.fehler ? "spk-krit" : "spk-gut" },
|
||||||
);
|
);
|
||||||
@@ -324,9 +324,9 @@
|
|||||||
<span class="spk-nr">M${i + 1}</span>
|
<span class="spk-nr">M${i + 1}</span>
|
||||||
<span class="spk-zellen">${d.zellen.map((v, j) => {
|
<span class="spk-zellen">${d.zellen.map((v, j) => {
|
||||||
const a = (v - mittel) / skala;
|
const a = (v - mittel) / skala;
|
||||||
return `<i style="--h:${(52 + a * 40).toFixed(0)}%;--f:${zellFarbe(a)};--j:${j}" title="Zelle ${i * ZELLEN_JE_MODUL + j + 1}: ${tausend(v)} mV"></i>`;
|
return `<i style="--h:${(52 + a * 40).toFixed(0)}%;--f:${zellFarbe(a)};--j:${j}" title="Zelle ${i * ZELLEN_JE_MODUL + j + 1}: ${tausend(v)} mV"></i>`;
|
||||||
}).join("")}</span>
|
}).join("")}</span>
|
||||||
<span class="spk-werte"><b>${komma(d.min / 1000, 3)}–${komma(d.max / 1000, 3)} V</b><small>${d.tMin !== null ? d.tMin + "–" + d.tMax + " °C" : ""}</small></span>
|
<span class="spk-werte"><b>${komma(d.min / 1000, 3)}–${komma(d.max / 1000, 3)} V</b><small>${d.tMin !== null ? d.tMin + "–" + d.tMax + " °C" : ""}</small></span>
|
||||||
</button>`).join("");
|
</button>`).join("");
|
||||||
this.dom.turm.innerHTML = kopf + reihen + '<div class="spk-sockel"></div>';
|
this.dom.turm.innerHTML = kopf + reihen + '<div class="spk-sockel"></div>';
|
||||||
this.detailZeigen(s, gewaehlt);
|
this.detailZeigen(s, gewaehlt);
|
||||||
@@ -350,14 +350,14 @@
|
|||||||
const nrGesamt = nr * ZELLEN_JE_MODUL + j + 1;
|
const nrGesamt = nr * ZELLEN_JE_MODUL + j + 1;
|
||||||
const markiert = nrGesamt === s.zelleMinNr || nrGesamt === s.zelleMaxNr;
|
const markiert = nrGesamt === s.zelleMinNr || nrGesamt === s.zelleMaxNr;
|
||||||
return `<rect class="spk-zelle${markiert ? " markiert" : ""}" x="${X(j).toFixed(1)}" y="${Y(v).toFixed(1)}" width="${bw.toFixed(1)}"
|
return `<rect class="spk-zelle${markiert ? " markiert" : ""}" x="${X(j).toFixed(1)}" y="${Y(v).toFixed(1)}" width="${bw.toFixed(1)}"
|
||||||
height="${(H - U - Y(v)).toFixed(1)}" rx="2" style="fill:${zellFarbe(a)};--j:${j}"><title>Zelle ${nrGesamt}: ${tausend(v)} mV</title></rect>`;
|
height="${(H - U - Y(v)).toFixed(1)}" rx="2" style="fill:${zellFarbe(a)};--j:${j}"><title>Zelle ${nrGesamt}: ${tausend(v)} mV</title></rect>`;
|
||||||
}).join("");
|
}).join("");
|
||||||
|
|
||||||
const temps = d.temps.map((t, j) => `<span style="--f:${tempFarbe(t)}" title="Fühler ${nr * FUEHLER_JE_MODUL + j + 1}">${t}°</span>`).join("");
|
const temps = d.temps.map((t, j) => `<span style="--f:${tempFarbe(t)}" title="Fühler ${nr * FUEHLER_JE_MODUL + j + 1}">${t}°</span>`).join("");
|
||||||
const html = `
|
const html = `
|
||||||
<div class="spk-kopf"><h3 class="spk-ueberschrift">Modul ${nr + 1}</h3>
|
<div class="spk-kopf"><h3 class="spk-ueberschrift">Modul ${nr + 1}</h3>
|
||||||
<span class="spk-pille ${spr > 20 ? "warn" : "ok"}">${spr > 20 ? "ungleich" : "ausgeglichen"}</span></div>
|
<span class="spk-pille ${spr > 20 ? "warn" : "ok"}">${spr > 20 ? "ungleich" : "ausgeglichen"}</span></div>
|
||||||
<div class="spk-gross"><b>${spr} mV</b><span>Spreizung der ${d.zellen.length} Zellen</span></div>
|
<div class="spk-gross"><b>${spr} mV</b><span>Spreizung der ${d.zellen.length} Zellen</span></div>
|
||||||
<svg class="spk-zellchart" viewBox="0 0 ${B} ${H}" role="img" aria-label="Zellspannungen Modul ${nr + 1}">
|
<svg class="spk-zellchart" viewBox="0 0 ${B} ${H}" role="img" aria-label="Zellspannungen Modul ${nr + 1}">
|
||||||
${stufen.map(v => `<line x1="${L}" x2="${B}" y1="${Y(v).toFixed(1)}" y2="${Y(v).toFixed(1)}" class="spk-gitter"/><text x="${L - 5}" y="${(Y(v) + 3).toFixed(1)}" class="spk-achse" text-anchor="end">${v}</text>`).join("")}
|
${stufen.map(v => `<line x1="${L}" x2="${B}" y1="${Y(v).toFixed(1)}" y2="${Y(v).toFixed(1)}" class="spk-gitter"/><text x="${L - 5}" y="${(Y(v) + 3).toFixed(1)}" class="spk-achse" text-anchor="end">${v}</text>`).join("")}
|
||||||
<line x1="${L}" x2="${B}" y1="${Y(mittel).toFixed(1)}" y2="${Y(mittel).toFixed(1)}" class="spk-mittel"/>
|
<line x1="${L}" x2="${B}" y1="${Y(mittel).toFixed(1)}" y2="${Y(mittel).toFixed(1)}" class="spk-mittel"/>
|
||||||
@@ -368,9 +368,9 @@
|
|||||||
<div class="spk-notiz">Zellspannung in mV · gestrichelt: Mittel aller Zellen · weiß umrandet: tiefste und höchste Zelle der Batterie</div>
|
<div class="spk-notiz">Zellspannung in mV · gestrichelt: Mittel aller Zellen · weiß umrandet: tiefste und höchste Zelle der Batterie</div>
|
||||||
<div class="spk-fuehler" aria-label="Temperaturfühler">${temps}</div>
|
<div class="spk-fuehler" aria-label="Temperaturfühler">${temps}</div>
|
||||||
<dl class="spk-paare">
|
<dl class="spk-paare">
|
||||||
<dt>Modulspannung</dt><dd>${komma(d.zellen.reduce((a, v) => a + v, 0) / 1000)} V</dd>
|
<dt>Modulspannung</dt><dd>${komma(d.zellen.reduce((a, v) => a + v, 0) / 1000)} V</dd>
|
||||||
<dt>Zellen</dt><dd>${komma(d.min / 1000, 3)} – ${komma(d.max / 1000, 3)} V</dd>
|
<dt>Zellen</dt><dd>${komma(d.min / 1000, 3)} – ${komma(d.max / 1000, 3)} V</dd>
|
||||||
<dt>Temperatur</dt><dd>${d.tMin !== null ? d.tMin + " – " + d.tMax + " °C" : "–"}</dd>
|
<dt>Temperatur</dt><dd>${d.tMin !== null ? d.tMin + " – " + d.tMax + " °C" : "–"}</dd>
|
||||||
<dt>Ganze Batterie</dt><dd>Zelle ${s.zelleMinNr} am tiefsten, ${s.zelleMaxNr} am höchsten</dd>
|
<dt>Ganze Batterie</dt><dd>Zelle ${s.zelleMinNr} am tiefsten, ${s.zelleMaxNr} am höchsten</dd>
|
||||||
</dl>`;
|
</dl>`;
|
||||||
this.dom.detail.innerHTML = html;
|
this.dom.detail.innerHTML = html;
|
||||||
@@ -399,8 +399,8 @@
|
|||||||
links: { min: 0, max: 100, einheit: "%" },
|
links: { min: 0, max: 100, einheit: "%" },
|
||||||
rechts: { einheit: "kW", symmetrisch: true },
|
rechts: { einheit: "kW", symmetrisch: true },
|
||||||
reihen: [
|
reihen: [
|
||||||
{ name: "Leistung", achse: "rechts", werte: v.soc.map(r => [r[0], r[2] / 1000]), flaeche: true, farbe: "#6cbe58", farbeNegativ: "#e8a33a", format: w => (w > 0 ? "+" : "") + komma(w, 2) + " kW" },
|
{ name: "Leistung", achse: "rechts", werte: v.soc.map(r => [r[0], r[2] / 1000]), flaeche: true, farbe: "#6cbe58", farbeNegativ: "#e8a33a", format: w => (w > 0 ? "+" : "") + komma(w, 2) + " kW" },
|
||||||
{ name: "Ladestand", achse: "links", werte: v.soc.map(r => [r[0], r[1]]), farbe: "#e3e8ec", format: w => komma(w, 0) + " %" },
|
{ name: "Ladestand", achse: "links", werte: v.soc.map(r => [r[0], r[1]]), farbe: "#e3e8ec", format: w => komma(w, 0) + " %" },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
if (!v.bmu.length) {
|
if (!v.bmu.length) {
|
||||||
@@ -416,9 +416,9 @@
|
|||||||
links: { min: 0, einheit: "mV" },
|
links: { min: 0, einheit: "mV" },
|
||||||
rechts: { einheit: "°C" },
|
rechts: { einheit: "°C" },
|
||||||
reihen: [
|
reihen: [
|
||||||
{ name: "Spreizung", achse: "links", werte: v.bmu.map(r => [r[0], r[1]]), flaeche: true, farbe: "#8fb8de", format: w => komma(w, 0) + " mV" },
|
{ name: "Spreizung", achse: "links", werte: v.bmu.map(r => [r[0], r[1]]), flaeche: true, farbe: "#8fb8de", format: w => komma(w, 0) + " mV" },
|
||||||
{ name: "wärmster Fühler", achse: "rechts", werte: v.bmu.map(r => [r[0], r[3]]), farbe: "#e8a33a", format: w => komma(w, 0) + " °C" },
|
{ name: "wärmster Fühler", achse: "rechts", werte: v.bmu.map(r => [r[0], r[3]]), farbe: "#e8a33a", format: w => komma(w, 0) + " °C" },
|
||||||
{ name: "kältester Fühler", achse: "rechts", werte: v.bmu.map(r => [r[0], r[2]]), farbe: "#4f8fb8", format: w => komma(w, 0) + " °C" },
|
{ name: "kältester Fühler", achse: "rechts", werte: v.bmu.map(r => [r[0], r[2]]), farbe: "#4f8fb8", format: w => komma(w, 0) + " °C" },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user