Doku: Solar-Uebersicht beschrieben
Katalog und Renderer, die Elternbeziehung als Struktur, und wie aus Watt eine Zahl, ein gestauchter Ring, ein Fluss mit Punktgroesse und Tempo, ein Fuellstand und Plaketten werden. Dazu quer/hochkant, der Sekundentakt mit seinen drei Sparmassnahmen und der Bearbeitungsmodus. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,8 +21,8 @@ Für einige Teile reicht diese Landkarte nicht, weil ihr Verhalten aus dem
|
||||
Zusammenspiel mehrerer Prozesse entsteht. Sie haben eigene, ausführliche
|
||||
Dokumente unter [`doku/`](doku/README.md):
|
||||
**[Automatiken](doku/automatiken.md)**, **[Zeitleiste](doku/zeitleiste.md)**,
|
||||
**[Datenbanken](doku/datenbank.md)** und
|
||||
**[Einstellungsseite](doku/einstellungen.md)**.
|
||||
**[Solar-Übersicht](doku/uebersicht.md)**, **[Datenbanken](doku/datenbank.md)**
|
||||
und **[Einstellungsseite](doku/einstellungen.md)**.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ abzulesen sind.
|
||||
|---|---|
|
||||
| [automatiken.md](automatiken.md) | Die Automatiken (AutoActions): Datenmodell, Editor, Runner, wie eine Bedingung wirklich ausgewertet wird, Verkettung, Sperren, Fehlerbilder |
|
||||
| [zeitleiste.md](zeitleiste.md) | Die Zeitleiste der Automatiken: wie der Server den Tag ausrechnet und wie der Browser ihn zeichnet |
|
||||
| [uebersicht.md](uebersicht.md) | Die Solar-Übersicht: Katalog und Renderer, wie aus Watt ein Ring, ein Fluss und ein Füllstand wird |
|
||||
| [datenbank.md](datenbank.md) | Die drei Schemata: wer was schreibt, wie Messreihen verdichtet werden, welche Tabelle man für welche Auswertung nimmt |
|
||||
| [einstellungen.md](einstellungen.md) | Die Einstellungsseite: was jeder Reiter speichert, welche Regeln das Modell durchsetzt und was die Seite bewusst nicht kann |
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 439 KiB |
@@ -0,0 +1,285 @@
|
||||
# Die Solar-Übersicht (Energiefluss)
|
||||
|
||||
Die Karte „Realtime“ auf der Solar-Seite: Wo kommt der Strom her, wo geht er
|
||||
hin, wie viel ist es gerade. Sie ist kein gezeichnetes Bild, sondern ein
|
||||
**Katalog plus ein Renderer** — und genau diese Trennung macht sie
|
||||
erweiterbar.
|
||||
|
||||

|
||||
|
||||
| Datei | Aufgabe |
|
||||
|---|---|
|
||||
| `js/solar/energieflussKatalog.js` | **Was** es gibt: jeder Kreis genau einmal — Name, Symbol, Farbe, Elternkreis, Lage, Ringskala, Klickziel und `lesen()` |
|
||||
| `js/solar/energiefluss.js` | **Wie** gezeichnet wird: Kreise, Ringe, Flüsse, Symbole, Plaketten, Hochkant, Bearbeitungsmodus. Kennt keinen Kreis beim Namen |
|
||||
| `restricted/energiefluss.php` | speichert **Abweichungen** je Haus (`homeMesh.energiefluss`) |
|
||||
| `js/solar/solarMQTT.js` | hängt beides an den MQTT-Strom und an die Reiter |
|
||||
|
||||
---
|
||||
|
||||
## 1. Der Aufbau: Kreise und ihre Eltern
|
||||
|
||||
Jeder Kreis nennt seinen **Elternkreis**; daraus entsteht der Fluss zwischen
|
||||
beiden. Es gibt keine getrennte Liste von Verbindungen — die Struktur ist die
|
||||
Elternbeziehung.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
PV["Sonne<br/><small>pv</small>"] --> WR
|
||||
NETZ["Netz<br/><small>netz</small>"] --> WR
|
||||
AKKU["Batterie<br/><small>akku</small>"] --> WR(("Autarkie<br/><small>wr · Pflicht</small>"))
|
||||
WR --> VERB(("Verbrauch<br/><small>verbrauch · Pflicht</small>"))
|
||||
VERB --> OG["Obergeschoss"] --> WBOG["Wallbox OG"]
|
||||
VERB --> EG["Erdgeschoss"] --> WBEG["Wallbox EG"]
|
||||
VERB --> UG["Untergeschoss"]
|
||||
VERB --> HEIZ["Heizstab"]
|
||||
BEW["Bewässerung<br/><small>frei stehend</small>"]
|
||||
```
|
||||
|
||||
Ein Eintrag im Katalog sieht so aus:
|
||||
|
||||
```js
|
||||
{
|
||||
id: "heizstab", name: "Heizstab", symbol: "speicher", farbe: "#c2614e",
|
||||
eltern: "verbrauch", // woher der Fluss kommt
|
||||
x: 1120, y: 380, // Lage in der Queransicht
|
||||
hochX: 670, hochY: 600, // optional: eigene Lage hochkant
|
||||
skala: 6000, // W, bei denen der Ring voll ist
|
||||
klick: { modal: "heater" }, // Ziel beim Antippen
|
||||
lesen(m, opt) { // aus MQTT-Werten wird ein Zustand
|
||||
const w = m.zahl("solarManager/pHeat");
|
||||
return { leistung: w, fluss: w, ruhe: w < 20, neben: "…", zeichen: [...],
|
||||
zustand: { an: w >= 20, temps: [...] } };
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Was `lesen()` zurückgeben darf:
|
||||
|
||||
| Feld | Wirkung |
|
||||
|---|---|
|
||||
| `leistung` | die große Zahl und der Ring |
|
||||
| `wert` | Text **statt** der Leistung (z. B. „93 %“) |
|
||||
| `neben` | die kleine Zeile darunter |
|
||||
| `segmente` | `[{w, farbe, knoten?}]` statt eines einfarbigen Rings |
|
||||
| `fluss` | Watt vom Elternkreis hierher; negativ = Gegenrichtung |
|
||||
| `ruhe` | Kreis blass zeichnen — es ist nichts los |
|
||||
| `zeichen` | Plaketten am Rand: `[{art, text?, titel?}]` |
|
||||
| `zustand` | was das Symbol braucht: `{an, stand, laden, temps}` |
|
||||
|
||||
> **Ein neuer Kreis ist ein neuer Eintrag hier — sonst nichts.** Kein
|
||||
> Markup, keine CSS-Regel, keine Zeile im Renderer. Nur ein neues *Symbol*
|
||||
> braucht einen Eintrag in `SYMBOLE` (`energiefluss.js`).
|
||||
|
||||
### Abweichungen je Haus
|
||||
|
||||
Der Katalog ist der Normalfall, `homeMesh.energiefluss` hält nur, was davon
|
||||
abweicht: Kreis aus, anderer Name, andere Lage, andere Optionen. Eingestellt
|
||||
wird das unter **Einstellungen → Übersicht**
|
||||
(→ [einstellungen.md](einstellungen.md#3-übersicht-energiefluss)).
|
||||
|
||||
Ist ein Kreis **aus**, rückt sein Kind automatisch an den nächsten
|
||||
eingeschalteten Vorfahren: `elternWirksam` sucht die Kette hinauf. Und ein
|
||||
Ringsegment, das zu einem ausgeschalteten Kreis gehört, fällt in das letzte
|
||||
verbleibende Segment — die Summe bleibt also richtig, auch wenn jemand die
|
||||
Wallbox ausblendet.
|
||||
|
||||
---
|
||||
|
||||
## 2. Die Leistungsvisualisierung
|
||||
|
||||
Drei Dinge zeigen dieselbe Leistung auf drei Arten. Das ist Absicht: Die Zahl
|
||||
ist genau, der Ring vergleicht, der Fluss zeigt die Richtung.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
W["Leistung in Watt<br/><small>aus lesen()</small>"] --> Z["Zahl im Kreis<br/><small>W bis 999, danach kW</small>"]
|
||||
W --> R["Ring<br/><small>Anteil an skala, gestaucht</small>"]
|
||||
W --> F["Fluss zum Elternkreis<br/><small>Punktgröße + Tempo</small>"]
|
||||
W --> S["Symbolzustand<br/><small>an/aus, Füllstand, Temperaturen</small>"]
|
||||
```
|
||||
|
||||
### 2.1 Der Ring — gestauchte Skala
|
||||
|
||||
Linear wäre der Ring unbrauchbar: Bei `skala = 15000` wären 300 W ein Strich
|
||||
von zwei Grad, und genau in diesem Bereich steht die Anlage die meiste Zeit.
|
||||
|
||||
```
|
||||
Anteil = log10(1 + 9 · w/skala)
|
||||
|
||||
w/skala 0 % 10 % 25 % 50 % 100 %
|
||||
Ring 0 % 28 % 47 % 70 % 100 %
|
||||
```
|
||||
|
||||
Der volle Ausschlag bleibt exakt bei `skala`, aber das untere Zehntel bekommt
|
||||
knapp ein Drittel des Rings.
|
||||
|
||||
**Mehrere Segmente** (etwa Verbrauch = Etagen + Heizstab + Rest) werden über
|
||||
die **Summe** gerechnet und nicht je Segment — die gestauchte Skala ist nicht
|
||||
additiv, sonst reichten drei Viertel-Segmente weiter als ein volles:
|
||||
|
||||
```
|
||||
Segment i = ringAnteil(Σ bis i) − ringAnteil(Σ bis i−1)
|
||||
```
|
||||
|
||||
Zwischen zwei Segmenten bleibt eine Lücke von 0,6 %; Segmente unter 0,4 %
|
||||
verschwinden ganz, sonst stünde dort ein Punkt statt eines Bogens.
|
||||
|
||||
### 2.2 Der Fluss — Punkte statt Linie
|
||||
|
||||
Ein Fluss ist ein Bogen vom Eltern- zum Kindkreis (`flussPfad()`): senkrecht
|
||||
los, dann waagerecht hinein — hochkant umgekehrt. Gezeichnet wird er als
|
||||
gestrichelte Linie mit runden Enden, also als Punktreihe, die über
|
||||
`stroke-dashoffset` wandert.
|
||||
|
||||
| Größe | Formel | Wirkung |
|
||||
|---|---|---|
|
||||
| Punktgröße | `2,4 + 11 · (1 − e^(−W/5000))` | 2,4 px bei ein paar hundert Watt, ~13 px bei Volllast |
|
||||
| Tempo | `1 / (0,7 + 1,9 · e^(−W/3000))` | 2,6 s je Abschnitt bei wenig, 0,7 s bei viel |
|
||||
| Richtung | Vorzeichen von `fluss` | `enf-rueck` dreht die Animation um |
|
||||
| Stillstand | unter 15 W | Punkte ausgeblendet |
|
||||
|
||||
Zwei Feinheiten, die teuer erkauft waren:
|
||||
|
||||
* **Das Tempo wird über `Animation.updatePlaybackRate()` gesetzt**, nicht über
|
||||
eine neue `animation-duration`. Eine geänderte Dauer rechnet die Position
|
||||
neu — die Punkte sprängen bei jeder Wertänderung.
|
||||
* **Keine Bahn unter den Punkten.** Die dunkle Linie gibt es nur im
|
||||
Bearbeitungsmodus, wo sie zeigt, was mit was verbunden ist. In der Ansicht
|
||||
erzählen die Punkte den Weg; wo nichts fließt, steht nichts.
|
||||
|
||||
### 2.3 Füllstände
|
||||
|
||||
Batterie und Wallbox haben statt eines bloßen Rings eine **Welle im Kreis**,
|
||||
die mit dem Ladestand steigt (`zustand.stand`, 0…1). Die Fläche liegt bei
|
||||
22 % Deckung, beim Laden 32 %, und die Wasserlinie ist zusätzlich als Kante
|
||||
gezeichnet — sonst muss man den Stand suchen. Meldet ein Kreis keinen Stand,
|
||||
bleibt die Füllung ganz weg: Eine Wallbox ohne Auto zeigte sonst eine Linie
|
||||
am unteren Rand.
|
||||
|
||||
### 2.4 Plaketten und Symbolzustände
|
||||
|
||||
Kleine runde Zeichen am Kreisrand, aus `lesen().zeichen`:
|
||||
|
||||
| `art` | Zeichen | Bedeutung |
|
||||
|---|---|---|
|
||||
| `eco` | Blatt | Eco-Modus (Wallbox, Heizstab) |
|
||||
| `uhr` | Uhr | „Nächste Fahrt“ |
|
||||
| `manuell` | Regler | fester Modus |
|
||||
| `stecker`, `schloss` | Stecker, Schloss | Fahrzeug angesteckt / verriegelt |
|
||||
| `heizung` | Flamme | Heizung im Geschoss an |
|
||||
| `tank` | Zapfsäule | Tankfüllung, mit Text |
|
||||
| `warnung` | Dreieck | Störung |
|
||||
|
||||
Die Glyphen sind Bootstrap-Icons und stehen als `\uF…`-Escapes im Quelltext —
|
||||
die Zeichen selbst liegen im privaten Unicode-Bereich, sind im Editor
|
||||
unsichtbar und werden beim Kopieren leicht verfälscht.
|
||||
|
||||
`zustand` steuert dagegen das Symbol selbst: `an` schaltet die
|
||||
Zustandsklasse (leuchtender Kern), `laden` die Ladeanimation, `temps` färbt
|
||||
die Schichten des Pufferspeichers zwischen kalt und heiß.
|
||||
|
||||
### 2.5 Die Bewässerung
|
||||
|
||||
Der einzige Kreis ohne Leistung: Statt Zahl und Ring stehen darin drei
|
||||
Zeilen, je Zone ein Symbol, der Name und der Zustand. Gezeichnet werden sie
|
||||
aus `katalog.zonen`, gefüllt von `bewaesserungAnzeige.js`, das die Ids
|
||||
kennt, die der Renderer vergibt.
|
||||
|
||||
---
|
||||
|
||||
## 3. Zwei Ansichten aus einer Lage
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Q["quer (≥ 720 px)"]
|
||||
direction LR
|
||||
Q1["Quellen links"] --> Q2["Mitte"] --> Q3["Verbraucher rechts"]
|
||||
end
|
||||
subgraph H["hochkant (< 720 px)"]
|
||||
direction TB
|
||||
H1["Quellen oben"] --> H2["Mitte"] --> H3["Verbraucher unten"]
|
||||
end
|
||||
```
|
||||
|
||||
Hochkant werden schlicht **x und y vertauscht**. So braucht es keine zweite
|
||||
Lage je Kreis, und eine eigene Lage aus den Einstellungen gilt in beiden
|
||||
Ansichten. Wo das Vertauschen unglücklich steht, nennt der Katalog mit
|
||||
`hochX`/`hochY` eine eigene Lage — so stehen UG und Heizstab hochkant
|
||||
getauscht, damit die drei Geschosse untereinander liegen.
|
||||
|
||||
Umgeschaltet wird über einen `ResizeObserver` am Behälter, und nur dann, wenn
|
||||
die Ansicht wirklich wechselt. Das Kiosk-Display (`anzeige.js`) setzt
|
||||
`hochkantUnter: 0` und bleibt damit immer quer.
|
||||
|
||||
Der `viewBox` wird nach dem Zeichnen aus den äußersten Kreisen gerechnet
|
||||
(`rahmenSetzen()`), inklusive Platz für den Namen unter dem Kreis — ein
|
||||
ausgeschalteter Randkreis verkleinert das Bild also automatisch.
|
||||
|
||||
---
|
||||
|
||||
## 4. Wie die Werte hereinkommen
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant M as MQTT-Broker
|
||||
participant S as solarMQTT.js
|
||||
participant E as Energiefluss
|
||||
participant K as Katalog
|
||||
|
||||
M->>S: solarManager/# (viele Nachrichten je Sekunde)
|
||||
Note over S: Werte in mqttData ablegen,<br/>höchstens 1× pro Sekunde weiterreichen
|
||||
S->>E: aktualisieren(mqttData)
|
||||
loop je sichtbarem Kreis
|
||||
E->>K: lesen(m, optionen)
|
||||
K-->>E: {leistung, fluss, zeichen, zustand, …}
|
||||
Note over E: nur schreiben, was sich geändert hat
|
||||
end
|
||||
```
|
||||
|
||||
Drei Sparmaßnahmen, die zusammen die Karte flüssig halten:
|
||||
|
||||
1. **Ein Takt je Sekunde.** Der Broker schickt deutlich öfter.
|
||||
2. **Nur geänderte Werte schreiben.** Jeder Schreibzugriff macht Style und
|
||||
Paint ungültig; gemessen waren rund 71 % der Zugriffe reine
|
||||
Wiederholungen.
|
||||
3. **Animationen stehen still, wenn niemand hinsieht** — `IntersectionObserver`
|
||||
für „Karte im Bild“ und `visibilitychange` für „Tab im Vordergrund“.
|
||||
|
||||
Ein Fehler in einem `lesen()` fängt der Renderer je Kreis ab: Er meldet ihn
|
||||
auf der Konsole und zeichnet die übrigen weiter. Eine kaputte Zeile im
|
||||
Katalog nimmt also nicht die ganze Übersicht mit.
|
||||
|
||||
---
|
||||
|
||||
## 5. Antippen und Bearbeiten
|
||||
|
||||
`klick` im Katalog sagt, was ein Tipp auf einen Kreis tut:
|
||||
|
||||
| Eintrag | Wirkung |
|
||||
|---|---|
|
||||
| `{ ansicht: "anlage" }` | schaltet auf die Anlagen-Ansicht (`anlage.js`) |
|
||||
| `{ ansicht: "speicher" }` | schaltet auf die Speicher-Ansicht (`speicher.js`) |
|
||||
| `{ modal: "heater" }` … | öffnet das passende Bedienfenster (`bedienfenster.js`, `ladefenster.js`) |
|
||||
|
||||
Klickbare Kreise bekommen ein Pfeil-Abzeichen, `tabindex`, `role="button"`
|
||||
und reagieren auf Enter und Leertaste.
|
||||
|
||||
Im **Bearbeitungsmodus** (`bearbeiten: true`, nur in den Einstellungen) sind
|
||||
die Kreise ziehbar, die Verbindungslinien sichtbar und die Lage wird beim
|
||||
Loslassen auf zehn Einheiten gerundet an `onVerschoben(id, x, y)` gemeldet.
|
||||
Die Vorschau dort läuft mit festen Beispielwerten, damit man auch nachts
|
||||
sieht, was man einstellt.
|
||||
|
||||
---
|
||||
|
||||
## 6. Wo fange ich an, wenn ich …
|
||||
|
||||
| Vorhaben | Ort |
|
||||
|---|---|
|
||||
| … einen Kreis hinzufügen | ein Eintrag in `ENERGIEFLUSS_KATALOG.knoten` — mehr nicht |
|
||||
| … ein neues Symbol | `SYMBOLE` in `energiefluss.js` (24er Raster, Mitte 0/0, `currentColor`) |
|
||||
| … eine neue Plakette | `ZEICHEN` in `energiefluss.js`, Glyph als `\uF…`-Escape |
|
||||
| … die Ringspreizung ändern | `ringAnteil()` — der Faktor 9 bestimmt die Stauchung |
|
||||
| … Punktgröße oder Tempo | `flussSetzen()` in `energiefluss.js` |
|
||||
| … die Lage hochkant korrigieren | `hochX`/`hochY` im Katalog (gilt nur dort) |
|
||||
| … einen Kreis ausblenden oder verschieben | Einstellungen → Übersicht, keine Codeänderung |
|
||||
Reference in New Issue
Block a user