diff --git a/architecture.html b/architecture.html new file mode 100644 index 0000000..49c8d40 --- /dev/null +++ b/architecture.html @@ -0,0 +1,481 @@ + + + + +Fensterpiepser ESP32 – Architekturübersicht + + + + +

Fensterpiepser ESP32 — Architekturübersicht

+
NodeMCU-32S  ·  Arduino/ESP-IDF  ·  v2.0.8  ·  Varianten: EG / DG
+ + +
+

1 · Tasks & Interrupts – Gesamtübersicht

+ + + + + + + + + + + + + + + + + + + + + + ESP32 NodeMCU-32S · 240 MHz · Xtensa LX6 Dual-Core + + + + Core 0 + + + + beepTask + Prio 5 · Core 0 · Stack 2 KB + · Wartet auf beepSemaphore (gegeben alle 10 ms von timerIsr) + · Short-Beep-Timing (30 ms Puls) + · PiepPattern::TaskCyclic() → PiepMode → toneRequest → GPIO18 + + + + rfDecodeTask + Prio 4 · Core 0 · Stack 3 KB + · Wartet auf rfEventQueue (RfEvent_t: dtMicros, pinValue) + · receiverSw / Aiggend / Oval / Kerui / Thermo .Isr() + · Setzt lastReceivedKeyNum / bNewData für loop + + + + WiFi / TCP-IP Stack + ESP-IDF intern + · Autonome Tasks (pro_cpu_0) · PubSubClient nutzt WiFiClient + · SSID: Elektrosmog · Broker: flokke.de:1883 + + + + NTP: ptbtime3.ptb.de (GMT+1 / DST+1) + Hostname: FENSTER_PIEPSER_NODEMCU_32_S_EG + OTA: WebServer Port 80 (/update) + Reset nach 24 h (wenn alle Fenster zu) + + + + Core 1 + + + + timerIsr + hw_timer 0 · 1 MHz · Alarm 10 000 µs + · ++count; if count==10 → tDecis++ (volatile) + · xSemaphoreGiveFromISR(beepSemaphore) + portYIELD_FROM_ISR + ← gesamte Beep-Logik jetzt in beepTask + + + + pinLevelChangeIsr + GPIO 26 · CHANGE · INPUT_PULLUP + · dtMicros = micros() − lastMics · pinVal = digitalRead(26) + · Filter: loopCountSincePause < 2 || dtMicros < 100 µs → skip + · xQueueSendFromISR(rfEventQueue, &ev) + portYIELD_FROM_ISR + + + + loopTask (Arduino loop) + Prio 1 · Core 1 · vTaskDelay 5 ms + 1 handleKeyReceived() – Empfangene Keys → Fenster-State → MQTT + 2 handleDispUpdate() – SPI-Display (1 s / 10 s Interval) + 3 handleWifiConnection() – Reconnect nach 30 s, Restart on Timeout + 4 myMqttClient.onLoop() – MQTT keepalive, RSSI alle 600 s + 5 UpdateHandler() – HTTP OTA (WebServer Port 80) + 6 updatePiepPattern() – Pause-Modus nach 6 min Dauerbeeep + 7 xcpLoop() – XCP-Events 10 / 100 / 500 / 1000 ms + 8 loopCountSincePause++ – RF-Debounce Zähler + 9 vTaskDelay(5 ms) – gibt Core 1 für ISRs frei + + + + + + beepSemaphore + + + + + rfEventQueue[32] + + + + keyNum / dir + +
+ + +
+

2 · FreeRTOS Synchronisationsobjekte

+ + + + + + + + + + + + + + + + +
ObjektTypGrößeProduzent (ISR)Konsument (Task)Zweck
beepSemaphoreBinary SemaphoretimerIsr alle 10 msbeepTask Core 0, Prio 5Takt für Beep-State-Machine; ersetzt direkten ISR-Aufruf von PiepPattern::TaskCyclic()
rfEventQueueQueue – RfEvent_t32 Einträge × 5 BpinLevelChangeIsr bei jeder FlankerfDecodeTask Core 0, Prio 4Überträgt {dtMicros, pinValue}; alle 5 Receiver-State-Machines laufen jetzt im Task-Kontext
+
+ + +
+

3 · Signalflüsse

+ + + + + + + + + RF-Empfangspfad (433 MHz OOK) + + + + 433 MHz + Empfänger + + + pinLevelChange + Isr (Core 1) + + + rfEventQueue + 32 × RfEvent_t + + + rfDecodeTask + Core 0 Prio 4 + + + ReceiverSmartWares + + ReceiverAiggend + + ReceiverOval + + ReceiverKerui + + ReceiverFunkThermo + + + loopTask + handleKey + + + MQTT publish + flokke.de:1883 + + + + + + + + + + + + + + + Beep-Pfad (Buzzer-Ansteuerung) + + + timerIsr + 10 ms · Core 1 + + + beepSemaphore + binary + + + beepTask + Core 0 Prio 5 + + + PiepPattern + TaskCyclic() + + + piepFast ×2 + + piepSlow ×1 + + piepPause ×120 + + + toneRequest + bitmask + + + GPIO 18 + PIEP_VCC + + + 🔔 + + + + + + + + + + + + + + GPIO33 PIEP_PWM + 2 kHz · LEDC Ch12 + duty 127/255 (fix) + + + bRequestShortBeep (volatile) + gesetzt von loopTask + → 30 ms Bestätigungs-Piep + +
+ + +
+

4 · 433-MHz-Receiver

+ + + + + + + +
ObjektProtokollKey-BytesAnzahl KeysKey-Index-OffsetBasisklasse
receiverSwSmartWares Manchester OOK8 B220Receiver433
receiverAiggend3-Byte-Key PWM3 B + 1 Richtungs-Bkonfigurierbar+30Receiver3ByteKey
receiverOval3-Byte-Key PWM3 B + 1 Richtungs-Bkonfigurierbar+40Receiver3ByteKey
receiverKerui3-Byte-Key PWM3 B + 1 Richtungs-Bkonfigurierbar+50Receiver3ByteKey
receiverThermoFunk-Thermometer PWM4 B (36 bit, 4 bit ignoriert)Receiver433
+
+ Alle .Isr()-Aufrufe erfolgen in rfDecodeTask (Core 0) via rfEventQueue. + Debounce: loopCountSincePause < 2 → ISR verwirft Flanke nach Key-Empfang. +
+
+ + +
+

5 · Fenster-Objekte

+
+
+
Variante EG (VERSION_DG_ONLY=0, alleFenster[4])
+ + + + + + +
NameSensor-TypKey-Nr (mit Offset)Wait-Zeit-Quelle
fensterWzKerui2 + 50 = 52waitTimeDs (Temperatur)
fensterBadUntenAiggend3 + 30 = 33waitTimeDs
fensterKuecheOval2 + 40 = 42waitTimeDs
fensterToniNeuOval1 + 40 = 41waitTimeDs
+
+
+
Variante DG (VERSION_DG_ONLY=1, alleFenster[4])
+ + + + + + +
NameSensor-TypKey-Nr (mit Offset)Wait-Zeit-Quelle
fensterBadObenAiggend1 + 30 = 31waitTimeDs
fensterFloAiggend2 + 30 = 32waitTimeDs
fensterHannaOval5 + 40 = 45waitTimeDs
fensterFloBueroOval4 + 40 = 44waitTimeDs
+
+
+
+ + + + +
Sonder-Objekte (immer instanziiert)
NameSensor-TypKey-NrBesonderheit
fensterGefrierSmartWares10Feste Wait-Zeit: 30 s (hardcodiert in ShallPiep())
+
+
+ + +
+

6 · Beep-Muster (PiepPattern)

+ + + + + + +
ModusonTimeoffTimerequestCountReihenfolge
piepFast20 ms80 ms2 Mal1.
piepSlow500 ms100 ms1 Mal2.
piepPauseLong0 ms1000 ms120 × = 60 s3. (Standardpause)
piepPauseShort0 ms1000 ms20 × = 10 s3. (nach 6 min Dauerbeeep)
+
+ Pattern läuft zyklisch: fast → slow → pause(Long/Short) → fast → …   + Start/Stop über piepPattern→startRequest / stopRequest (volatile).   + Stopp bei Nacht (bIsNightTime) oder alle Fenster zu. +
+
+ + +
+

7 · Wartezeit-Berechnung (waitTimeDs)

+ + + + + + + +
AußentemperaturWartezeitErklärung
< −5 °C5 minKurz – kalte Luft, schnelles Lüften
−5 … 19,5 °C5 … 30 min (linear)Lineare Interpolation: 5 + (T+5)×25/24,5
19,5 … 25 °C~2 WochenKein Alarm – Sommer, Lüften sinnvoll
> 25 °C30 minHeiß – kurze Alarmverzögerung
kein Sensor-Wert10 minDefault bis erste Thermo-Meldung
+
+ Quelle: receiverThermo (Funk-Thermometer, Aussensensor) · Update bei jedem neuen Thermo-Paket (~50 s Intervall). +
+
+ + +
+

8 · GPIO-Belegung

+
+ + + + + + + + +
GPIORichtungFunktion
26INPUT_PULLUPDIN_FUNK – 433-MHz-Datensignal → pinLevelChangeIsr
12OUTPUT HIGHDOUT_FUNK_VCC – Versorgung Empfängermodul
32OUTPUT LOWDOUT_FUNK_GND – GND Empfängermodul
18OUTPUTDOUT_PIEP_VCC – Buzzer-Versorgung (geschaltet via toneRequest)
33LEDC PWMDOUT_PIEP_PWM – Buzzer-PWM 2 kHz, Ch 12, duty 127
16OUTPUT HIGHDOUT_TEST_TIMER – Debug-Pin
+ + + + + + + +
GPIOFunktionInterface
14TFT_PIN_CLK (SCK)SPI – Adafruit ST7735
(VERSION_BIG_DISPLAY)
13TFT_PIN_MOSI (SDA)
22TFT_PIN_RST (RES)
21TFT_PIN_DC (RS)
15TFT_PIN_CS
+
+
+ + +
+

9 · MQTT-Topics (Broker: flokke.de:1883)

+ + + + + + +
TopicRetainWannPayload (Beispiel)
fenster/system/EGneinConnect, Reset{"e":"hello","client":"FensterpiepserEG_v2.0.8"}
fenster/status/EGjaFenster bewegt / Beep gestartet{"t":1700000000,"e":"move","n":4,"f":["Wohnz",…],"o":[0,1,…],"b":[0,0,…]}
fenster/temprh/EGjaNeues Thermo-Paket (~50 s){"T":7,"rh":65,"t":1700000000,"raw":3422534}
fenster/rssi/EGneinAlle 600 s{"rssi":-62}
+
+ LWT (Will) auf fenster/temprh/EG: {"T":0,"rh":0,"t":0} · User: lightcontrol · Keepalive: 600 s +
+
+ + +
+

10 · Geteilte Variablen & volatile-Annotierungen

+ + + + + + + +
VariableTypvolatileSchreiberLeserAnmerkung
tDecisuint32_ttimerIsr (Core 1)loopTask, beepTask, Fenster::ShallPiepMonoton steigend, 32-bit-Reads atomar auf LX6
bRequestShortBeepboolloopTask (Core 1)beepTask (Core 0)Cross-Core; single-byte write atomar
loopCountSincePauseuint32_tloopTask (Core 1)pinLevelChangeIsr (Core 1)RF-Debounce nach Key-Empfang
PiepPattern::startRequest
PiepPattern::stopRequest
uint8_tloopTask via Start()/Stop()beepTask via TaskCyclic()Cross-Core; Flags, nicht Zähler
toneRequestuint8_tbeepTask (exklusiv)beepTaskKein Cross-Core-Zugriff mehr nach Refactoring
+
+ + +
+

11 · XCP-Protokoll

+ + + + + + +
EventIntervallAufruf
XcpEvent(0)10 msxcpLoop() in loopTask (millis-basiert)
XcpEvent(1)100 msxcpLoop()
XcpEvent(2)500 msxcpLoop()
XcpEvent(3)1000 msxcpLoop()
+
+ XcpPoll() + XcpSendLoop() werden ebenfalls in xcpLoop() aufgerufen. + Timing ist millis()-basiert → toleriert den 5-ms-vTaskDelay des loopTask. +
+
+ + +