Automatik-Editor als drei Baender, mit laufenden Werten
Das Akkordeon schloss beim Oeffnen die anderen Faecher - Ausloeser und
Aktion waren also nie gleichzeitig zu sehen, ausgerechnet bei einer
Regel, die genau daraus besteht. Und das mittlere Fach hiess
"Bedingungen", enthielt aber die Rahmenbedingungen; die echten standen
im ersten. Jetzt drei sichtbare Baender: Wenn, Wann, Dann, gebaut aus
.card mit farbigem Rand und .card-header.
Die Bedingungszeile magert von fuenf gleich schweren Kaesten auf zwei
ab. Das Geraet steht klein und matt ueber dem Messwert - es beantwortet
"woher", nicht "was" -, der Messwert ist Text mit gepunkteter Linie,
und nur Vergleich und Wert sehen noch wie Eingabefelder aus. Dort
steckt die Aussage der Bedingung, dort tippt man auch. Die Einheit
sitzt im Wertfeld statt in einem sechsten Kasten, der Papierkorb
erscheint erst beim Ueberfahren.
Neben jeder Bedingung laeuft ihr aktueller Wert mit. ?action=werte
liefert alle acht Sekunden {state_id: {value, unit}} aus actor_states -
bewusst von dort und nicht ueber MQTT, weil dort nur ein Teil der
Geraete auftaucht: die Jalousien haengen an der Tahoma-Box, die
gerechneten Werte an gar nichts. Das ersetzt den Satz, der frueher am
Ende stand und die Regel Wort fuer Wort nacherzaehlte: statt zu
wiederholen, was darueber steht, beantwortet die Zeile die Frage, die
man wirklich hat - warum laeuft die Automatik gerade nicht?
Bei time, date, datetime, deltatime und elapsed faellt der Browser
bewusst kein Urteil. Ob "Uhrzeit um 07:30" zutrifft, haengt am
Nachholfenster, am Tagesrand und bei elapsed am echten Abstand seit der
letzten Ausloesung - das steht im Runner. Es hier nachzubauen hiesse,
eine zweite Wahrheit zu pflegen, die auseinanderlaeuft. Diese Zeilen
bekommen einen gestrichelten Punkt statt einer Aussage.
Der Takt malt nur nach, statt neu zu bauen: renderConditions() ersetzt
den ganzen Block, damit waeren alle acht Sekunden eine offene
Geraeteliste weg und der Cursor aus einem Wertfeld, in das man gerade
tippt.
Der Rahmen steht zusammengefaltet da, solange nichts von der Vorgabe
abweicht - und das ist der Normalfall; vorher nahm er die meiste
Flaeche fuer den seltensten Inhalt. Aufgeklappt tauschen die drei
Vorlagen (taeglich, werktags, Wochenende) mit der Kurzfassung den
Platz. Sie stehen ausserhalb des Elements mit data-bs-toggle, und das
ist kein Zufall: Bootstrap haelt seinen Umschalter am Dokument in der
Capture-Phase, ein stopPropagation() im Knopf kaeme grundsaetzlich zu
spaet.
Getragen wird das von vier Variablen in solar.css, damit der Rest der
Seite mitzieht statt hinterherzuhinken: --ton-radius auf .875rem,
--ton-radius-klein neu auf .5rem (beide an Bootstraps
--bs-border-radius und -sm), --font-anzeige auf Poppins fuer alle
Ueberschriften. Poppins lag seit jeher unter assets/fonts und trug
bisher die vier Etagenknoepfe im Aussenplan - eine ganze Schrift fuer
vier Buchstaben. Fliesstext und Zahlenkolonnen bleiben beim Theme, weil
Poppins keine Tabellenziffern mitbringt.
Drei neue Klassen stehen absichtlich in solar.css und nicht im Editor.
.feld-als-text ist ein Auswahlfeld, das wie Text aussieht, bis man es
anfaehrt - dieselbe Not haben das Raum-Modal und die
Kachel-Einstellungen. .punkt ist an oder aus. .wert-jetzt ist die eine
echte Ausnahme und als einzelne Klasse auch als solche erkennbar. Der
Satz im Wann-Band braucht gar keine: .callout gibt es in AdminLTE, und
seine Toene kommen aus Bootstraps *-bg-subtle-Variablen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -336,7 +336,7 @@ klein: Diagramme füllen bzw. Logzeilen nachladen und einfärben.
|
||||
| Endpunkt | Aufruf | liefert / tut |
|
||||
|---|---|---|
|
||||
| `room.php` | `?room=EG_Bad`, `POST ?action=command\|temp` | Raum-Modal bauen; ein Kommando oder eine Solltemperatur senden |
|
||||
| `AutoAction.php` | `?action=editor\|list\|followers`, `POST save\|delete\|toggle` | Automatik-Editor und -Übersicht |
|
||||
| `AutoAction.php` | `?action=editor\|list\|followers\|werte`, `POST save\|delete\|toggle` | Automatik-Editor und -Übersicht |
|
||||
| `settings.php` | `?action=list\|kacheln\|geraete`, `POST save\|kacheln-save\|geraete-raeume\|geraet-loeschen` | Einstellungsseite |
|
||||
| `getStats.php` | `GET` | Jahresstatistik, alle Jahre, mit Metadaten je Kennzahl |
|
||||
| `energyHistory.php` | `?series=prod\|cons&range=month\|year\|decade` | Verbrauchs-/Erzeugungsverlauf (Rohdaten oder Stundenarchiv) |
|
||||
@@ -362,7 +362,7 @@ Kennzahlen, `energyHistory.php` wählt die Quelle nach Zeitraum,
|
||||
|---|---|---|
|
||||
| `rooms.php` | Räume, Etagen, Kachelwerte, Symbole | `allRooms()`, `roomsWithTile()`, `tileTopics()`, `kachelVorgabe()`, `kachelUeberschreibungen()`, `bootstrapIcons()`, `kachelIcon()` |
|
||||
| `costs.php` | Preistabellen, Verbindung zu `solarLog` | `solarDb()`, `preiseLaden()`, `preiseSpeichern()`, `grundpreisImZeitraum()` |
|
||||
| `automations.php` | Automatiken, Gerätekatalog, Verbindung zu `homeMesh` | `meshDb()`, `deviceCatalog()`, `loadAutomation()`, `saveAutomation()`, `deleteAutomation()`, `automationFollowers()`, `pruefeKreis()`, `geraeteListe()`, `geraetLoeschen()`, `saveRooms()` |
|
||||
| `automations.php` | Automatiken, Gerätekatalog, Verbindung zu `homeMesh` | `meshDb()`, `deviceCatalog()`, `loadAutomation()`, `saveAutomation()`, `deleteAutomation()`, `automationFollowers()`, `pruefeKreis()`, `kalendertagChoices()`, `tagVorlagen()`, `stateValues()`, `geraeteListe()`, `geraetLoeschen()`, `saveRooms()` |
|
||||
| `kacheln.php` | Anzeigewerte der Home-Kacheln (Maskenseite) | `kachelListe()`, `kachelKatalog()`, `kachelWertPruefen()`, `kachelWerteSpeichern()`, `kachelSymbole()` |
|
||||
| `roomControls.php` | Welches Gerät welches Bedienelement bekommt | `bedienform()`, `zeichneBeschattung()`, `zeichneLicht()`, `zeichneMesswerte()` |
|
||||
| `commands.php` | Ein Kommando abschicken (MQTT/WLED/HTTP/Tahoma) | `executeCommand()`, `sendeMqtt()`, `sendeWled()`, `sendeHttp()`, `sendeTahoma()` |
|
||||
@@ -526,6 +526,37 @@ das Regelwerk nach `homeMesh`; ausgeführt wird es von
|
||||
`autoActions/autoaction_runner.py` im anderen Repo. **Die Weboberfläche
|
||||
schaltet nichts von sich aus** — sie beschreibt nur, was gelten soll.
|
||||
|
||||
**Drei Bänder statt eines Akkordeons: Wenn · Wann · Dann.** Das Akkordeon
|
||||
schloss beim Öffnen die anderen Fächer — Auslöser und Aktion waren also nie
|
||||
gleichzeitig zu sehen, ausgerechnet bei einer Regel, die genau daraus
|
||||
besteht. Und das mittlere Fach hieß „Bedingungen", enthielt aber die
|
||||
*Rahmen*bedingungen. Gebaut aus `.card` mit farbigem Rand und `.card-header`,
|
||||
kein eigenes Bauteil.
|
||||
|
||||
**Der Rahmen steht zusammengefaltet da**, solange nichts von der Vorgabe
|
||||
abweicht — und das ist der Normalfall. `rahmenKurzText()` schreibt ihn in
|
||||
eine Zeile („täglich · rund um die Uhr"), `rahmenIstVorgabe()` entscheidet,
|
||||
ob sie matt oder hell ist. Vorher nahm er die meiste Fläche für den
|
||||
seltensten Inhalt.
|
||||
|
||||
**Neben jeder Bedingung läuft ihr aktueller Wert mit.** `?action=werte`
|
||||
liefert alle acht Sekunden `{state_id: {value, unit}}` aus `actor_states` —
|
||||
bewusst aus der Tabelle und nicht über MQTT, weil dort nur ein Teil der
|
||||
Geräte auftaucht (die Jalousien hängen an der Tahoma-Box, die gerechneten
|
||||
Werte an gar nichts); der Runner schreibt dagegen jeden Messwert zurück.
|
||||
Das ersetzt den Satz, der früher am Ende stand und die Regel Wort für Wort
|
||||
nacherzählte: statt zu wiederholen, was darüber steht, beantwortet die Zeile
|
||||
die Frage, die man wirklich hat — warum läuft die Automatik gerade nicht?
|
||||
|
||||
Ein voller Punkt heißt erfüllt, ein leerer noch nicht, ein **gestrichelter
|
||||
heißt „entscheidet der Runner"**. Bei `time`, `date`, `datetime`,
|
||||
`deltatime` und `elapsed` fällt der Browser bewusst kein Urteil: ob
|
||||
„Uhrzeit um 07:30" gerade zutrifft, hängt am Nachholfenster, am Tagesrand
|
||||
und beim Datentyp `elapsed` am echten Abstand seit der letzten Auslösung —
|
||||
das alles steht in `bedingung_erfuellt()` im Runner. Es hier nachzubauen
|
||||
hieße, eine zweite Wahrheit zu pflegen, die irgendwann auseinanderläuft.
|
||||
Lieber keine Aussage als eine, die manchmal falsch ist (`ZEITARTEN`).
|
||||
|
||||
Bedingungen mit derselben `group_no` sind mit UND verknüpft, verschiedene
|
||||
Gruppen mit ODER: ausgewertet wird `any(all(gruppe))`. Eine Bedingung zeigt
|
||||
auf einen `actor_states`-Eintrag, eine Aktion auf ein `actor_commands` samt
|
||||
@@ -556,8 +587,43 @@ Drei Stellen wissen trotzdem davon:
|
||||
eigenen Rahmenbedingungen und eigener Zeile im Protokoll. Sobald
|
||||
„gruppiert" auch „gehört dazu" hieße, wäre zu klären, wem die Pause gehört.
|
||||
|
||||
**Die Tagesauswahl in vier Stufen, von grob nach fein.** Ganz oben drei
|
||||
Vorlagen (`tagVorlagen()`): *täglich*, *werktags*, *Wochenende*. Sie setzen den
|
||||
**ganzen** Rahmen, nicht nur die Wochentagsmaske — „werktags" heißt auch
|
||||
„nicht an Feiertagen", „Wochenende" auch „dazu alle Feiertage". Wer das aus
|
||||
Maske und zwei Schaltern von Hand zusammensetzt, vergisst den zweiten Teil.
|
||||
Darunter sieben Wochentagsschalter, darunter Ferien und Feiertage mit je drei
|
||||
Stufen — **nie · egal · immer** (`kalendertagChoices()`) —, und ganz unten ein
|
||||
Satz, der zurückliest, was dabei herausgekommen ist: *„Läuft samstags und
|
||||
sonntags, dazu an allen Feiertagen."*
|
||||
|
||||
Der Satz ist der eigentliche Gewinn: man muss das Bedienelement nicht
|
||||
entziffern. `rahmenText()` in `autoActionFuncs.js` baut ihn, zieht drei und
|
||||
mehr aufeinanderfolgende Tage zu „montags bis freitags" zusammen und gibt bei
|
||||
gar keinem wählbaren Tag `""` zurück — dann steht dort die Warnung *„Kein Tag
|
||||
ausgewählt"*, genau wie beim fehlenden Auslöser.
|
||||
|
||||
„Immer" zählt wie ein angehakter Wochentag. Das ist die einzige Art, *an
|
||||
Wochenenden und Feiertagen* zu schreiben — für die Maske ist ein Feiertag am
|
||||
Dienstag eben ein Dienstag —, und mit **gar keinem** Wochentag angehakt ergibt
|
||||
es *nur an Feiertagen*.
|
||||
|
||||
Vorher standen dort zwei Auswahlfelder, deren Einträge ganze Sätze waren
|
||||
(„zusätzlich, auch am falschen Wochentag"). Ein Auswahlfeld zeigt immer nur
|
||||
den gewählten Eintrag — man sieht nie, was es sonst noch gibt, und die
|
||||
Erklärung steht an der Stelle, wo ein Etikett hingehört.
|
||||
|
||||
`kalendertagWert()` prüft beim Speichern mit `is_numeric`, weil `intval("")`
|
||||
sonst 0 wäre — und 0 heißt „nie": eine leere Angabe hätte eine Automatik
|
||||
stillschweigend an Feiertagen abgeschaltet.
|
||||
|
||||
**„Nur einmal am Tag"** (`once_per_day`) sperrt eine Automatik nach dem
|
||||
Auslösen bis Mitternacht. Für alles, was man hinterher von Hand wieder anders
|
||||
stellt: ein Rollladen, den man um acht zugezogen hat, soll nicht um neun von
|
||||
selbst wieder auffahren, nur weil eine Wolke weiterzieht.
|
||||
|
||||
Wie der Runner das auswertet — Datentyp `elapsed`, topologische Reihenfolge,
|
||||
was beim Pausieren geschieht — steht in
|
||||
der Rahmen, was beim Pausieren geschieht — steht in
|
||||
[`autoActions/README.md`](../../homes/wagner/SolarManager/autoActions/README.md)
|
||||
im SolarManager-Repo.
|
||||
|
||||
@@ -565,10 +631,10 @@ im SolarManager-Repo.
|
||||
|
||||
`restricted/deviceDiscovery/device_discovery.py` wird **von Hand** gestartet.
|
||||
Die Module suchen je eine Geräteart (Tahoma, WLED, Shelly, MQTT/Home-Assistant-
|
||||
Discovery, Gartenwasser, SolarManager-Werte, Logic); die Datenbanklogik liegt
|
||||
allein im Hauptskript.
|
||||
Discovery, Gartenwasser, SolarManager-Werte, Wetterstation, Logic); die
|
||||
Datenbanklogik liegt allein im Hauptskript.
|
||||
|
||||
Zwei Eigenschaften, die man kennen muss:
|
||||
Drei Eigenschaften, die man kennen muss:
|
||||
|
||||
* **Ein Suchlauf löscht nichts.** `clear_tables` steht in `config.ini` auf
|
||||
`false`, weil die Automatiken auf die Ids von `actor_states` zeigen.
|
||||
@@ -592,11 +658,49 @@ Zwei Eigenschaften, die man kennen muss:
|
||||
|
||||
Geschaltet werden auch die neuen Geräte über HTTP. Der Runner teilt seine
|
||||
Messwerte deshalb je Wert zu, nicht je Gerät.
|
||||
* **Vier Module suchen gar nichts.** Gartenwasser, SolarManager, Wetterstation
|
||||
und Logic schreiben feste Geräte hin, weil sich diese Quellen nicht von
|
||||
selbst melden. Wer einen Messwert vermisst, trägt im jeweiligen Modul eine
|
||||
Zeile ein — bei der Wetterstation in `MESSWERTE`, beim SolarManager in
|
||||
`GERAETE`. Bewusst knapp gehalten: `solarManager/#` allein trägt gut 130
|
||||
Topics, und eine vollständige Liste machte die Auswahl im Automatik-Editor
|
||||
unbrauchbar.
|
||||
|
||||
Die **Wetterstation** hängt am Websocket von `192.168.179.42`;
|
||||
`wsMQTTbridge.py` im SolarManager legt ihre Felder unter `weatherStation/#`
|
||||
ab. Von dort kommen Außentemperatur, Wind und Böe — die Außentemperatur ist
|
||||
für den Hitzeschutz die bessere Bedingung als die Raumtemperatur (ist es
|
||||
drinnen schon warm, ist es zum Verschatten zu spät), und ohne den Wind gibt
|
||||
es für Markise und Sonnensegel keinen Sturmschutz. Die trägen Werte
|
||||
(Temperatur, Feuchte, Druck, Taupunkt) gehen nur bei jeder einundzwanzigsten
|
||||
Nachricht raus; sie sind retained, für eine Bedingung macht das keinen
|
||||
Unterschied.
|
||||
|
||||
---
|
||||
|
||||
## Wiederkehrende Bauteile und Konventionen
|
||||
|
||||
**Zwei Radien, eine Anzeigeschrift.** `solar.css` tauscht die Palette über
|
||||
Variablen aus, statt Regel für Regel zu überschreiben — dasselbe gilt für
|
||||
Form und Schrift. `--ton-radius` (`.875rem`) gilt für Flächen, `--ton-radius-klein`
|
||||
(`.5rem`) für alles, was in einer Reihe steht; beide hängen an
|
||||
`--bs-border-radius` und `--bs-border-radius-sm`, also zieht jede Karte,
|
||||
jedes Modal und jeder kleine Knopf von allein mit. `--font-anzeige` ist
|
||||
Poppins — die Schrift lag seit jeher unter `assets/fonts` und trug nur die
|
||||
vier Etagenknöpfe im Außenplan; jetzt trägt sie alle Überschriften,
|
||||
`.card-title` und `.modal-title`. Fließtext und Zahlenkolonnen bleiben
|
||||
bewusst bei der Schrift des Themes: Poppins bringt keine Tabellenziffern
|
||||
mit, Messwerte würden sonst springen.
|
||||
|
||||
**Drei Klassen aus dem Automatik-Editor stehen absichtlich in `solar.css`
|
||||
und nicht dort.** `.feld-als-text` ist ein Auswahlfeld, das wie Text
|
||||
aussieht, bis man es anfährt — dieselbe Not haben das Raum-Modal und die
|
||||
Kachel-Einstellungen, wo ebenfalls jede Kleinigkeit in einem Kasten steht.
|
||||
`.punkt` ist an oder aus. `.wert-jetzt` ist die eine echte Ausnahme —
|
||||
Bedingungen gibt es sonst nirgends — und als einzelne Klasse auch als solche
|
||||
erkennbar.
|
||||
|
||||
|
||||
**Reiter.** Es gibt genau eine Bauart, `restricted/reiter.php`. Umgeschaltet
|
||||
wird von Bootstrap (`data-bs-toggle="tab"`), gemerkt wird der offene Reiter von
|
||||
`reiterMerken()` in `common.js`. Weniger als zwei Reiter ergeben keine Leiste.
|
||||
|
||||
Reference in New Issue
Block a user