482 lines
32 KiB
HTML
482 lines
32 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Fensterpiepser ESP32 – Architekturübersicht</title>
|
||
<style>
|
||
:root {
|
||
--bg: #0f1117;
|
||
--panel: #1a1d27;
|
||
--border: #2e3248;
|
||
--accent: #4f8ef7;
|
||
--green: #3ecf8e;
|
||
--orange: #f7964f;
|
||
--red: #f75f5f;
|
||
--purple: #b57bee;
|
||
--yellow: #f7d44f;
|
||
--text: #d4d8f0;
|
||
--muted: #6b7194;
|
||
--mono: 'Consolas', 'Courier New', monospace;
|
||
}
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body { background: var(--bg); color: var(--text); font-family: var(--mono); font-size: 13px; padding: 24px; }
|
||
h1 { font-size: 20px; color: var(--accent); margin-bottom: 4px; }
|
||
h2 { font-size: 14px; color: var(--orange); margin: 28px 0 10px; text-transform: uppercase; letter-spacing: 1px; }
|
||
.subtitle { color: var(--muted); font-size: 11px; margin-bottom: 24px; }
|
||
svg text { font-family: var(--mono); }
|
||
table { border-collapse: collapse; width: 100%; margin-bottom: 8px; }
|
||
th { background: #22263a; color: var(--orange); font-weight: normal; text-align: left; padding: 5px 10px; border: 1px solid var(--border); font-size: 11px; text-transform: uppercase; letter-spacing: .5px; }
|
||
td { padding: 5px 10px; border: 1px solid var(--border); vertical-align: top; }
|
||
tr:nth-child(even) td { background: #161924; }
|
||
.tag { display: inline-block; padding: 1px 6px; border-radius: 3px; font-size: 10px; margin: 1px; }
|
||
.t-isr { background:#3a1a1a; color:var(--red); border:1px solid var(--red); }
|
||
.t-task { background:#1a2a3a; color:var(--accent); border:1px solid var(--accent); }
|
||
.t-loop { background:#1a3a2a; color:var(--green); border:1px solid var(--green); }
|
||
.t-hw { background:#2a2a1a; color:var(--yellow); border:1px solid var(--yellow); }
|
||
.t-net { background:#2a1a3a; color:var(--purple); border:1px solid var(--purple); }
|
||
.col-core0 { color: var(--accent); }
|
||
.col-core1 { color: var(--green); }
|
||
.col-isr { color: var(--red); }
|
||
.col-hw { color: var(--yellow); }
|
||
.col-net { color: var(--purple); }
|
||
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
|
||
.grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 20px; }
|
||
section { margin-bottom: 32px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<h1>Fensterpiepser ESP32 — Architekturübersicht</h1>
|
||
<div class="subtitle">NodeMCU-32S · Arduino/ESP-IDF · v2.0.8 · Varianten: EG / DG</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
1. DUAL-CORE / TASK ÜBERSICHT
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>1 · Tasks & Interrupts – Gesamtübersicht</h2>
|
||
<svg viewBox="0 0 960 460" width="100%" style="max-width:960px;display:block;">
|
||
<defs>
|
||
<marker id="arr" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
|
||
<polygon points="0 0,8 3,0 6" fill="#4f8ef7"/>
|
||
</marker>
|
||
<marker id="arr-g" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
|
||
<polygon points="0 0,8 3,0 6" fill="#3ecf8e"/>
|
||
</marker>
|
||
<marker id="arr-o" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
|
||
<polygon points="0 0,8 3,0 6" fill="#f7964f"/>
|
||
</marker>
|
||
<marker id="arr-r" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
|
||
<polygon points="0 0,8 3,0 6" fill="#f75f5f"/>
|
||
</marker>
|
||
<marker id="arr-p" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
|
||
<polygon points="0 0,8 3,0 6" fill="#b57bee"/>
|
||
</marker>
|
||
</defs>
|
||
|
||
<!-- ESP32 chip outline -->
|
||
<rect x="10" y="10" width="940" height="440" rx="10" fill="#12151f" stroke="#2e3248" stroke-width="1.5"/>
|
||
<text x="480" y="32" text-anchor="middle" fill="#2e3248" font-size="13" font-weight="bold">ESP32 NodeMCU-32S · 240 MHz · Xtensa LX6 Dual-Core</text>
|
||
|
||
<!-- ── Core 0 ── -->
|
||
<rect x="30" y="44" width="420" height="390" rx="8" fill="#14192a" stroke="#4f8ef7" stroke-width="1.2"/>
|
||
<text x="240" y="64" text-anchor="middle" fill="#4f8ef7" font-size="12" font-weight="bold">Core 0</text>
|
||
|
||
<!-- beepTask -->
|
||
<rect x="50" y="76" width="380" height="90" rx="6" fill="#1a2240" stroke="#4f8ef7" stroke-width="1"/>
|
||
<text x="70" y="96" fill="#4f8ef7" font-size="12" font-weight="bold">beepTask</text>
|
||
<text x="380" y="96" text-anchor="end" fill="#6b7194" font-size="10">Prio 5 · Core 0 · Stack 2 KB</text>
|
||
<text x="70" y="114" fill="#d4d8f0" font-size="10">· Wartet auf Task Notification (gegeben alle 10 ms von timerIsr)</text>
|
||
<text x="70" y="129" fill="#d4d8f0" font-size="10">· Short-Beep-Timing (30 ms Puls)</text>
|
||
<text x="70" y="144" fill="#d4d8f0" font-size="10">· PiepPattern::TaskCyclic() → PiepMode → toneRequest → GPIO18</text>
|
||
|
||
<!-- rfDecodeTask -->
|
||
<rect x="50" y="178" width="380" height="80" rx="6" fill="#1a2240" stroke="#4f8ef7" stroke-width="1"/>
|
||
<text x="70" y="198" fill="#4f8ef7" font-size="12" font-weight="bold">rfDecodeTask</text>
|
||
<text x="380" y="198" text-anchor="end" fill="#6b7194" font-size="10">Prio 4 · Core 0 · Stack 3 KB</text>
|
||
<text x="70" y="216" fill="#d4d8f0" font-size="10">· Wartet auf rfEventQueue (RfEvent_t: dtMicros, pinValue)</text>
|
||
<text x="70" y="231" fill="#d4d8f0" font-size="10">· receiverSw / Aiggend / Oval / Kerui / Thermo .Isr()</text>
|
||
<text x="70" y="246" fill="#d4d8f0" font-size="10">· Setzt lastReceivedKeyNum / bNewData für loop</text>
|
||
|
||
<!-- WiFi stack -->
|
||
<rect x="50" y="270" width="380" height="60" rx="6" fill="#1a1a30" stroke="#2e3248" stroke-width="1" stroke-dasharray="4,3"/>
|
||
<text x="70" y="292" fill="#6b7194" font-size="12" font-weight="bold">WiFi / TCP-IP Stack</text>
|
||
<text x="380" y="292" text-anchor="end" fill="#6b7194" font-size="10">ESP-IDF intern</text>
|
||
<text x="70" y="310" fill="#6b7194" font-size="10">· Autonome Tasks (pro_cpu_0) · PubSubClient nutzt WiFiClient</text>
|
||
<text x="70" y="323" fill="#6b7194" font-size="10">· SSID: Elektrosmog · Broker: flokke.de:1883</text>
|
||
|
||
<!-- NTP / Hostname -->
|
||
<rect x="50" y="342" width="380" height="74" rx="6" fill="#1a1a2a" stroke="#2e3248" stroke-width="1" stroke-dasharray="4,3"/>
|
||
<text x="70" y="362" fill="#6b7194" font-size="11">NTP: ptbtime3.ptb.de (GMT+1 / DST+1)</text>
|
||
<text x="70" y="378" fill="#6b7194" font-size="11">Hostname: FENSTER_PIEPSER_NODEMCU_32_S_EG</text>
|
||
<text x="70" y="394" fill="#6b7194" font-size="11">OTA: WebServer Port 80 (/update)</text>
|
||
<text x="70" y="409" fill="#6b7194" font-size="11">Reset nach 24 h (wenn alle Fenster zu)</text>
|
||
|
||
<!-- ── Core 1 ── -->
|
||
<rect x="510" y="44" width="420" height="390" rx="8" fill="#14211a" stroke="#3ecf8e" stroke-width="1.2"/>
|
||
<text x="720" y="64" text-anchor="middle" fill="#3ecf8e" font-size="12" font-weight="bold">Core 1</text>
|
||
|
||
<!-- timerIsr -->
|
||
<rect x="530" y="76" width="380" height="75" rx="6" fill="#2a1a1a" stroke="#f75f5f" stroke-width="1"/>
|
||
<text x="550" y="96" fill="#f75f5f" font-size="12" font-weight="bold">timerIsr</text>
|
||
<text x="900" y="96" text-anchor="end" fill="#6b7194" font-size="10">hw_timer 0 · 1 MHz · Alarm 10 000 µs</text>
|
||
<text x="550" y="114" fill="#d4d8f0" font-size="10">· ++count; if count==10 → tDecis++ (volatile)</text>
|
||
<text x="550" y="129" fill="#d4d8f0" font-size="10">· vTaskNotifyGiveFromISR(beepTaskHandle) + portYIELD_FROM_ISR</text>
|
||
<text x="550" y="144" fill="#6b7194" font-size="10"> ← gesamte Beep-Logik jetzt in beepTask</text>
|
||
|
||
<!-- pinLevelChangeIsr -->
|
||
<rect x="530" y="163" width="380" height="75" rx="6" fill="#2a1a1a" stroke="#f75f5f" stroke-width="1"/>
|
||
<text x="550" y="183" fill="#f75f5f" font-size="12" font-weight="bold">pinLevelChangeIsr</text>
|
||
<text x="900" y="183" text-anchor="end" fill="#6b7194" font-size="10">GPIO 26 · CHANGE · INPUT_PULLUP</text>
|
||
<text x="550" y="201" fill="#d4d8f0" font-size="10">· dtMicros = micros() − lastMics · pinVal = digitalRead(26)</text>
|
||
<text x="550" y="216" fill="#d4d8f0" font-size="10">· Filter: loopCountSincePause < 2 || dtMicros < 100 µs → skip</text>
|
||
<text x="550" y="231" fill="#d4d8f0" font-size="10">· xQueueSendFromISR(rfEventQueue, &ev) + portYIELD_FROM_ISR</text>
|
||
|
||
<!-- loopTask -->
|
||
<rect x="530" y="250" width="380" height="174" rx="6" fill="#1a2a1a" stroke="#3ecf8e" stroke-width="1"/>
|
||
<text x="550" y="270" fill="#3ecf8e" font-size="12" font-weight="bold">loopTask (Arduino loop)</text>
|
||
<text x="900" y="270" text-anchor="end" fill="#6b7194" font-size="10">Prio 1 · Core 1 · vTaskDelay 5 ms</text>
|
||
<text x="550" y="289" fill="#d4d8f0" font-size="10">1 handleKeyReceived() – Empfangene Keys → Fenster-State → MQTT</text>
|
||
<text x="550" y="304" fill="#d4d8f0" font-size="10">2 handleDispUpdate() – SPI-Display (1 s / 10 s Interval)</text>
|
||
<text x="550" y="319" fill="#d4d8f0" font-size="10">3 handleWifiConnection() – Reconnect nach 30 s, Restart on Timeout</text>
|
||
<text x="550" y="334" fill="#d4d8f0" font-size="10">4 myMqttClient.onLoop() – MQTT keepalive, RSSI alle 600 s</text>
|
||
<text x="550" y="349" fill="#d4d8f0" font-size="10">5 UpdateHandler() – HTTP OTA (WebServer Port 80)</text>
|
||
<text x="550" y="364" fill="#d4d8f0" font-size="10">6 updatePiepPattern() – Pause-Modus nach 6 min Dauerbeeep</text>
|
||
<text x="550" y="379" fill="#d4d8f0" font-size="10">7 xcpLoop() – XCP-Events 10 / 100 / 500 / 1000 ms</text>
|
||
<text x="550" y="394" fill="#d4d8f0" font-size="10">8 loopCountSincePause++ – RF-Debounce Zähler</text>
|
||
<text x="550" y="409" fill="#d4d8f0" font-size="10">9 vTaskDelay(5 ms) – gibt Core 1 für ISRs frei</text>
|
||
|
||
<!-- ── FreeRTOS Primitives ── -->
|
||
<!-- Task Notification arrow: timerIsr → beepTask -->
|
||
<line x1="530" y1="108" x2="432" y2="108" stroke="#4f8ef7" stroke-width="1.5" marker-end="url(#arr)" stroke-dasharray="5,3"/>
|
||
<rect x="436" y="98" width="90" height="18" rx="3" fill="#0f1117"/>
|
||
<text x="481" y="111" text-anchor="middle" fill="#4f8ef7" font-size="10">Task Notification</text>
|
||
|
||
<!-- rfEventQueue arrow: pinLevelChangeIsr → rfDecodeTask -->
|
||
<line x1="530" y1="210" x2="432" y2="218" stroke="#4f8ef7" stroke-width="1.5" marker-end="url(#arr)" stroke-dasharray="5,3"/>
|
||
<rect x="438" y="207" width="82" height="18" rx="3" fill="#0f1117"/>
|
||
<text x="479" y="220" text-anchor="middle" fill="#4f8ef7" font-size="10">rfEventQueue[8]</text>
|
||
|
||
<!-- receiver state arrow: rfDecodeTask → loop (dashed green) -->
|
||
<line x1="430" y1="242" x2="530" y2="310" stroke="#3ecf8e" stroke-width="1" marker-end="url(#arr-g)" stroke-dasharray="4,3"/>
|
||
<text x="471" y="284" text-anchor="middle" fill="#3ecf8e" font-size="10" transform="rotate(-27,471,284)">keyNum / dir</text>
|
||
</svg>
|
||
</section>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
2. FreeRTOS PRIMITIVE
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>2 · FreeRTOS Synchronisationsobjekte</h2>
|
||
<table>
|
||
<tr><th>Objekt</th><th>Typ</th><th>Größe</th><th>Produzent (ISR)</th><th>Konsument (Task)</th><th>Zweck</th></tr>
|
||
<tr>
|
||
<td><span class="tag t-task">beepSemaphore</span></td>
|
||
<td>Binary Semaphore</td><td>–</td>
|
||
<td><span class="tag t-isr">timerIsr</span> alle 10 ms</td>
|
||
<td><span class="tag t-task">beepTask</span> Core 0, Prio 5</td>
|
||
<td>Takt für Beep-State-Machine; ersetzt direkten ISR-Aufruf von PiepPattern::TaskCyclic()</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="tag t-task">rfEventQueue</span></td>
|
||
<td>Queue – RfEvent_t</td><td>32 Einträge × 5 B</td>
|
||
<td><span class="tag t-isr">pinLevelChangeIsr</span> bei jeder Flanke</td>
|
||
<td><span class="tag t-task">rfDecodeTask</span> Core 0, Prio 4</td>
|
||
<td>Überträgt {dtMicros, pinValue}; alle 5 Receiver-State-Machines laufen jetzt im Task-Kontext</td>
|
||
</tr>
|
||
</table>
|
||
</section>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
3. SIGNAL-FLÜSSE
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>3 · Signalflüsse</h2>
|
||
<svg viewBox="0 0 960 300" width="100%" style="max-width:960px;display:block;">
|
||
<defs>
|
||
<marker id="a1" markerWidth="7" markerHeight="5" refX="7" refY="2.5" orient="auto"><polygon points="0 0,7 2.5,0 5" fill="#f7964f"/></marker>
|
||
<marker id="a2" markerWidth="7" markerHeight="5" refX="7" refY="2.5" orient="auto"><polygon points="0 0,7 2.5,0 5" fill="#3ecf8e"/></marker>
|
||
<marker id="a3" markerWidth="7" markerHeight="5" refX="7" refY="2.5" orient="auto"><polygon points="0 0,7 2.5,0 5" fill="#b57bee"/></marker>
|
||
</defs>
|
||
|
||
<!-- ── RF-Empfangspfad ── -->
|
||
<text x="20" y="28" fill="#f7964f" font-size="11" font-weight="bold">RF-Empfangspfad (433 MHz OOK)</text>
|
||
|
||
<!-- boxes -->
|
||
<rect x="20" y="38" width="100" height="40" rx="5" fill="#2a1a0a" stroke="#f7964f" stroke-width="1"/>
|
||
<text x="70" y="54" text-anchor="middle" fill="#f7964f" font-size="10">433 MHz</text>
|
||
<text x="70" y="68" text-anchor="middle" fill="#f7964f" font-size="10">Empfänger</text>
|
||
|
||
<rect x="150" y="38" width="110" height="40" rx="5" fill="#2a1a1a" stroke="#f75f5f" stroke-width="1"/>
|
||
<text x="205" y="54" text-anchor="middle" fill="#f75f5f" font-size="10">pinLevelChange</text>
|
||
<text x="205" y="68" text-anchor="middle" fill="#f75f5f" font-size="10">Isr (Core 1)</text>
|
||
|
||
<rect x="290" y="38" width="100" height="40" rx="5" fill="#1a2240" stroke="#4f8ef7" stroke-width="1"/>
|
||
<text x="340" y="54" text-anchor="middle" fill="#4f8ef7" font-size="10">rfEventQueue</text>
|
||
<text x="340" y="68" text-anchor="middle" fill="#6b7194" font-size="10">32 × RfEvent_t</text>
|
||
|
||
<rect x="420" y="38" width="100" height="40" rx="5" fill="#1a2240" stroke="#4f8ef7" stroke-width="1"/>
|
||
<text x="470" y="54" text-anchor="middle" fill="#4f8ef7" font-size="10">rfDecodeTask</text>
|
||
<text x="470" y="68" text-anchor="middle" fill="#6b7194" font-size="10">Core 0 Prio 4</text>
|
||
|
||
<rect x="550" y="20" width="115" height="18" rx="3" fill="#1a2a1a" stroke="#3ecf8e" stroke-width="1"/>
|
||
<text x="607" y="33" text-anchor="middle" fill="#3ecf8e" font-size="10">ReceiverSmartWares</text>
|
||
<rect x="550" y="42" width="115" height="18" rx="3" fill="#1a2a1a" stroke="#3ecf8e" stroke-width="1"/>
|
||
<text x="607" y="55" text-anchor="middle" fill="#3ecf8e" font-size="10">ReceiverAiggend</text>
|
||
<rect x="550" y="64" width="115" height="18" rx="3" fill="#1a2a1a" stroke="#3ecf8e" stroke-width="1"/>
|
||
<text x="607" y="77" text-anchor="middle" fill="#3ecf8e" font-size="10">ReceiverOval</text>
|
||
<rect x="550" y="86" width="115" height="18" rx="3" fill="#1a2a1a" stroke="#3ecf8e" stroke-width="1"/>
|
||
<text x="607" y="99" text-anchor="middle" fill="#3ecf8e" font-size="10">ReceiverKerui</text>
|
||
<rect x="550" y="108" width="115" height="18" rx="3" fill="#1a2a1a" stroke="#3ecf8e" stroke-width="1"/>
|
||
<text x="607" y="121" text-anchor="middle" fill="#3ecf8e" font-size="10">ReceiverFunkThermo</text>
|
||
|
||
<rect x="695" y="38" width="100" height="40" rx="5" fill="#1a2a1a" stroke="#3ecf8e" stroke-width="1"/>
|
||
<text x="745" y="54" text-anchor="middle" fill="#3ecf8e" font-size="10">loopTask</text>
|
||
<text x="745" y="68" text-anchor="middle" fill="#6b7194" font-size="10">handleKey</text>
|
||
|
||
<rect x="825" y="38" width="110" height="40" rx="5" fill="#2a1a3a" stroke="#b57bee" stroke-width="1"/>
|
||
<text x="880" y="54" text-anchor="middle" fill="#b57bee" font-size="10">MQTT publish</text>
|
||
<text x="880" y="68" text-anchor="middle" fill="#6b7194" font-size="10">flokke.de:1883</text>
|
||
|
||
<!-- arrows RF path -->
|
||
<line x1="120" y1="58" x2="148" y2="58" stroke="#f7964f" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<line x1="260" y1="58" x2="288" y2="58" stroke="#f7964f" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<line x1="390" y1="58" x2="418" y2="58" stroke="#f7964f" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<line x1="520" y1="50" x2="548" y2="30" stroke="#f7964f" stroke-width="1" marker-end="url(#a1)"/>
|
||
<line x1="520" y1="55" x2="548" y2="51" stroke="#f7964f" stroke-width="1" marker-end="url(#a1)"/>
|
||
<line x1="520" y1="58" x2="548" y2="73" stroke="#f7964f" stroke-width="1" marker-end="url(#a1)"/>
|
||
<line x1="520" y1="62" x2="548" y2="95" stroke="#f7964f" stroke-width="1" marker-end="url(#a1)"/>
|
||
<line x1="520" y1="66" x2="548" y2="117" stroke="#f7964f" stroke-width="1" marker-end="url(#a1)"/>
|
||
<line x1="665" y1="58" x2="693" y2="58" stroke="#3ecf8e" stroke-width="1.5" marker-end="url(#a2)"/>
|
||
<line x1="795" y1="58" x2="823" y2="58" stroke="#b57bee" stroke-width="1.5" marker-end="url(#a3)"/>
|
||
|
||
<!-- ── Beep-Pfad ── -->
|
||
<text x="20" y="165" fill="#f7964f" font-size="11" font-weight="bold">Beep-Pfad (Buzzer-Ansteuerung)</text>
|
||
|
||
<rect x="20" y="175" width="100" height="40" rx="5" fill="#2a1a1a" stroke="#f75f5f" stroke-width="1"/>
|
||
<text x="70" y="191" text-anchor="middle" fill="#f75f5f" font-size="10">timerIsr</text>
|
||
<text x="70" y="205" text-anchor="middle" fill="#6b7194" font-size="10">10 ms · Core 1</text>
|
||
|
||
<rect x="150" y="175" width="100" height="40" rx="5" fill="#1a2240" stroke="#4f8ef7" stroke-width="1"/>
|
||
<text x="200" y="191" text-anchor="middle" fill="#4f8ef7" font-size="10">beepSemaphore</text>
|
||
<text x="200" y="205" text-anchor="middle" fill="#6b7194" font-size="10">binary</text>
|
||
|
||
<rect x="280" y="175" width="100" height="40" rx="5" fill="#1a2240" stroke="#4f8ef7" stroke-width="1"/>
|
||
<text x="330" y="191" text-anchor="middle" fill="#4f8ef7" font-size="10">beepTask</text>
|
||
<text x="330" y="205" text-anchor="middle" fill="#6b7194" font-size="10">Core 0 Prio 5</text>
|
||
|
||
<rect x="410" y="175" width="100" height="40" rx="5" fill="#1a2240" stroke="#4f8ef7" stroke-width="1"/>
|
||
<text x="460" y="191" text-anchor="middle" fill="#4f8ef7" font-size="10">PiepPattern</text>
|
||
<text x="460" y="205" text-anchor="middle" fill="#6b7194" font-size="10">TaskCyclic()</text>
|
||
|
||
<rect x="540" y="157" width="90" height="18" rx="3" fill="#1a2040" stroke="#4f8ef7" stroke-width="1"/>
|
||
<text x="585" y="170" text-anchor="middle" fill="#4f8ef7" font-size="10">piepFast ×2</text>
|
||
<rect x="540" y="179" width="90" height="18" rx="3" fill="#1a2040" stroke="#4f8ef7" stroke-width="1"/>
|
||
<text x="585" y="192" text-anchor="middle" fill="#4f8ef7" font-size="10">piepSlow ×1</text>
|
||
<rect x="540" y="201" width="90" height="18" rx="3" fill="#1a2040" stroke="#4f8ef7" stroke-width="1"/>
|
||
<text x="585" y="214" text-anchor="middle" fill="#4f8ef7" font-size="10">piepPause ×120</text>
|
||
|
||
<rect x="660" y="175" width="100" height="40" rx="5" fill="#2a2a1a" stroke="#f7d44f" stroke-width="1"/>
|
||
<text x="710" y="191" text-anchor="middle" fill="#f7d44f" font-size="10">toneRequest</text>
|
||
<text x="710" y="205" text-anchor="middle" fill="#6b7194" font-size="10">bitmask</text>
|
||
|
||
<rect x="790" y="175" width="100" height="40" rx="5" fill="#2a2a1a" stroke="#f7d44f" stroke-width="1"/>
|
||
<text x="840" y="191" text-anchor="middle" fill="#f7d44f" font-size="10">GPIO 18</text>
|
||
<text x="840" y="205" text-anchor="middle" fill="#6b7194" font-size="10">PIEP_VCC</text>
|
||
|
||
<rect x="910" y="175" width="35" height="40" rx="5" fill="#1a1a00" stroke="#f7d44f" stroke-width="1"/>
|
||
<text x="928" y="199" text-anchor="middle" fill="#f7d44f" font-size="20">🔔</text>
|
||
|
||
<!-- arrows beep path -->
|
||
<line x1="120" y1="195" x2="148" y2="195" stroke="#f7964f" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<line x1="250" y1="195" x2="278" y2="195" stroke="#f7964f" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<line x1="380" y1="195" x2="408" y2="195" stroke="#f7964f" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<line x1="510" y1="188" x2="538" y2="167" stroke="#f7964f" stroke-width="1" marker-end="url(#a1)"/>
|
||
<line x1="510" y1="193" x2="538" y2="188" stroke="#f7964f" stroke-width="1" marker-end="url(#a1)"/>
|
||
<line x1="510" y1="198" x2="538" y2="210" stroke="#f7964f" stroke-width="1" marker-end="url(#a1)"/>
|
||
<line x1="630" y1="195" x2="658" y2="195" stroke="#f7964f" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<line x1="760" y1="195" x2="788" y2="195" stroke="#f7964f" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
<line x1="890" y1="195" x2="908" y2="195" stroke="#f7964f" stroke-width="1.5" marker-end="url(#a1)"/>
|
||
|
||
<!-- PWM note -->
|
||
<text x="840" y="240" text-anchor="middle" fill="#6b7194" font-size="9">GPIO33 PIEP_PWM</text>
|
||
<text x="840" y="252" text-anchor="middle" fill="#6b7194" font-size="9">2 kHz · LEDC Ch12</text>
|
||
<text x="840" y="264" text-anchor="middle" fill="#6b7194" font-size="9">duty 127/255 (fix)</text>
|
||
|
||
<!-- bRequestShortBeep note -->
|
||
<text x="310" y="240" text-anchor="middle" fill="#6b7194" font-size="9">bRequestShortBeep (volatile)</text>
|
||
<text x="310" y="252" text-anchor="middle" fill="#6b7194" font-size="9">gesetzt von loopTask</text>
|
||
<text x="310" y="264" text-anchor="middle" fill="#6b7194" font-size="9">→ 30 ms Bestätigungs-Piep</text>
|
||
</svg>
|
||
</section>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
4. RECEIVER-ÜBERSICHT
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>4 · 433-MHz-Receiver</h2>
|
||
<table>
|
||
<tr><th>Objekt</th><th>Protokoll</th><th>Key-Bytes</th><th>Anzahl Keys</th><th>Key-Index-Offset</th><th>Basisklasse</th></tr>
|
||
<tr><td>receiverSw</td><td>SmartWares Manchester OOK</td><td>8 B</td><td>22</td><td>0</td><td>Receiver433</td></tr>
|
||
<tr><td>receiverAiggend</td><td>3-Byte-Key PWM</td><td>3 B + 1 Richtungs-B</td><td>konfigurierbar</td><td>+30</td><td>Receiver3ByteKey</td></tr>
|
||
<tr><td>receiverOval</td><td>3-Byte-Key PWM</td><td>3 B + 1 Richtungs-B</td><td>konfigurierbar</td><td>+40</td><td>Receiver3ByteKey</td></tr>
|
||
<tr><td>receiverKerui</td><td>3-Byte-Key PWM</td><td>3 B + 1 Richtungs-B</td><td>konfigurierbar</td><td>+50</td><td>Receiver3ByteKey</td></tr>
|
||
<tr><td>receiverThermo</td><td>Funk-Thermometer PWM</td><td>4 B (36 bit, 4 bit ignoriert)</td><td>–</td><td>–</td><td>Receiver433</td></tr>
|
||
</table>
|
||
<div style="color:var(--muted);font-size:11px;margin-top:6px;">
|
||
Alle .Isr()-Aufrufe erfolgen in <span class="tag t-task">rfDecodeTask</span> (Core 0) via rfEventQueue.
|
||
Debounce: loopCountSincePause < 2 → ISR verwirft Flanke nach Key-Empfang.
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
5. FENSTER-OBJEKTE
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>5 · Fenster-Objekte</h2>
|
||
<div class="grid2">
|
||
<div>
|
||
<div style="color:var(--accent);font-size:11px;margin-bottom:6px;">Variante EG (VERSION_DG_ONLY=0, alleFenster[4])</div>
|
||
<table>
|
||
<tr><th>Name</th><th>Sensor-Typ</th><th>Key-Nr (mit Offset)</th><th>Wait-Zeit-Quelle</th></tr>
|
||
<tr><td>fensterWz</td><td>Kerui</td><td>2 + 50 = 52</td><td>waitTimeDs (Temperatur)</td></tr>
|
||
<tr><td>fensterBadUnten</td><td>Aiggend</td><td>3 + 30 = 33</td><td>waitTimeDs</td></tr>
|
||
<tr><td>fensterKueche</td><td>Oval</td><td>2 + 40 = 42</td><td>waitTimeDs</td></tr>
|
||
<tr><td>fensterToniNeu</td><td>Oval</td><td>1 + 40 = 41</td><td>waitTimeDs</td></tr>
|
||
</table>
|
||
</div>
|
||
<div>
|
||
<div style="color:var(--accent);font-size:11px;margin-bottom:6px;">Variante DG (VERSION_DG_ONLY=1, alleFenster[4])</div>
|
||
<table>
|
||
<tr><th>Name</th><th>Sensor-Typ</th><th>Key-Nr (mit Offset)</th><th>Wait-Zeit-Quelle</th></tr>
|
||
<tr><td>fensterBadOben</td><td>Aiggend</td><td>1 + 30 = 31</td><td>waitTimeDs</td></tr>
|
||
<tr><td>fensterFlo</td><td>Aiggend</td><td>2 + 30 = 32</td><td>waitTimeDs</td></tr>
|
||
<tr><td>fensterHanna</td><td>Oval</td><td>5 + 40 = 45</td><td>waitTimeDs</td></tr>
|
||
<tr><td>fensterFloBuero</td><td>Oval</td><td>4 + 40 = 44</td><td>waitTimeDs</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top:10px;">
|
||
<table>
|
||
<tr><th colspan="4">Sonder-Objekte (immer instanziiert)</th></tr>
|
||
<tr><th>Name</th><th>Sensor-Typ</th><th>Key-Nr</th><th>Besonderheit</th></tr>
|
||
<tr><td>fensterGefrier</td><td>SmartWares</td><td>10</td><td>Feste Wait-Zeit: 30 s (hardcodiert in ShallPiep())</td></tr>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
6. BEEP-MUSTER
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>6 · Beep-Muster (PiepPattern)</h2>
|
||
<table>
|
||
<tr><th>Modus</th><th>onTime</th><th>offTime</th><th>requestCount</th><th>Reihenfolge</th></tr>
|
||
<tr><td>piepFast</td><td>20 ms</td><td>80 ms</td><td>2 Mal</td><td>1.</td></tr>
|
||
<tr><td>piepSlow</td><td>500 ms</td><td>100 ms</td><td>1 Mal</td><td>2.</td></tr>
|
||
<tr><td>piepPauseLong</td><td>0 ms</td><td>1000 ms</td><td>120 × = 60 s</td><td>3. (Standardpause)</td></tr>
|
||
<tr><td>piepPauseShort</td><td>0 ms</td><td>1000 ms</td><td>20 × = 10 s</td><td>3. (nach 6 min Dauerbeeep)</td></tr>
|
||
</table>
|
||
<div style="color:var(--muted);font-size:11px;margin-top:6px;">
|
||
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.
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
7. WAITTIME (Temperaturabhängige Alarmverzögerung)
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>7 · Wartezeit-Berechnung (waitTimeDs)</h2>
|
||
<table>
|
||
<tr><th>Außentemperatur</th><th>Wartezeit</th><th>Erklärung</th></tr>
|
||
<tr><td>< −5 °C</td><td>5 min</td><td>Kurz – kalte Luft, schnelles Lüften</td></tr>
|
||
<tr><td>−5 … 19,5 °C</td><td>5 … 30 min (linear)</td><td>Lineare Interpolation: 5 + (T+5)×25/24,5</td></tr>
|
||
<tr><td>19,5 … 25 °C</td><td>~2 Wochen</td><td>Kein Alarm – Sommer, Lüften sinnvoll</td></tr>
|
||
<tr><td>> 25 °C</td><td>30 min</td><td>Heiß – kurze Alarmverzögerung</td></tr>
|
||
<tr><td>kein Sensor-Wert</td><td>10 min</td><td>Default bis erste Thermo-Meldung</td></tr>
|
||
</table>
|
||
<div style="color:var(--muted);font-size:11px;margin-top:6px;">
|
||
Quelle: receiverThermo (Funk-Thermometer, Aussensensor) · Update bei jedem neuen Thermo-Paket (~50 s Intervall).
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
8. GPIO-BELEGUNG
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>8 · GPIO-Belegung</h2>
|
||
<div class="grid2">
|
||
<table>
|
||
<tr><th>GPIO</th><th>Richtung</th><th>Funktion</th></tr>
|
||
<tr><td>26</td><td>INPUT_PULLUP</td><td>DIN_FUNK – 433-MHz-Datensignal → pinLevelChangeIsr</td></tr>
|
||
<tr><td>12</td><td>OUTPUT HIGH</td><td>DOUT_FUNK_VCC – Versorgung Empfängermodul</td></tr>
|
||
<tr><td>32</td><td>OUTPUT LOW</td><td>DOUT_FUNK_GND – GND Empfängermodul</td></tr>
|
||
<tr><td>18</td><td>OUTPUT</td><td>DOUT_PIEP_VCC – Buzzer-Versorgung (geschaltet via toneRequest)</td></tr>
|
||
<tr><td>33</td><td>LEDC PWM</td><td>DOUT_PIEP_PWM – Buzzer-PWM 2 kHz, Ch 12, duty 127</td></tr>
|
||
<tr><td>16</td><td>OUTPUT HIGH</td><td>DOUT_TEST_TIMER – Debug-Pin</td></tr>
|
||
</table>
|
||
<table>
|
||
<tr><th>GPIO</th><th>Funktion</th><th>Interface</th></tr>
|
||
<tr><td>14</td><td>TFT_PIN_CLK (SCK)</td><td rowspan="5" style="vertical-align:middle">SPI – Adafruit ST7735<br>(VERSION_BIG_DISPLAY)</td></tr>
|
||
<tr><td>13</td><td>TFT_PIN_MOSI (SDA)</td></tr>
|
||
<tr><td>22</td><td>TFT_PIN_RST (RES)</td></tr>
|
||
<tr><td>21</td><td>TFT_PIN_DC (RS)</td></tr>
|
||
<tr><td>15</td><td>TFT_PIN_CS</td></tr>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
9. MQTT-TOPICS
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>9 · MQTT-Topics (Broker: flokke.de:1883)</h2>
|
||
<table>
|
||
<tr><th>Topic</th><th>Retain</th><th>Wann</th><th>Payload (Beispiel)</th></tr>
|
||
<tr><td>fenster/system/EG</td><td>nein</td><td>Connect, Reset</td><td>{"e":"hello","client":"FensterpiepserEG_v2.0.8"}</td></tr>
|
||
<tr><td>fenster/status/EG</td><td>ja</td><td>Fenster bewegt / Beep gestartet</td><td>{"t":1700000000,"e":"move","n":4,"f":["Wohnz",…],"o":[0,1,…],"b":[0,0,…]}</td></tr>
|
||
<tr><td>fenster/temprh/EG</td><td>ja</td><td>Neues Thermo-Paket (~50 s)</td><td>{"T":7,"rh":65,"t":1700000000,"raw":3422534}</td></tr>
|
||
<tr><td>fenster/rssi/EG</td><td>nein</td><td>Alle 600 s</td><td>{"rssi":-62}</td></tr>
|
||
</table>
|
||
<div style="color:var(--muted);font-size:11px;margin-top:6px;">
|
||
LWT (Will) auf fenster/temprh/EG: {"T":0,"rh":0,"t":0} · User: lightcontrol · Keepalive: 600 s
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
10. VOLATILE / SHARED STATE
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>10 · Geteilte Variablen & volatile-Annotierungen</h2>
|
||
<table>
|
||
<tr><th>Variable</th><th>Typ</th><th>volatile</th><th>Schreiber</th><th>Leser</th><th>Anmerkung</th></tr>
|
||
<tr><td>tDecis</td><td>uint32_t</td><td>✓</td><td>timerIsr (Core 1)</td><td>loopTask, beepTask, Fenster::ShallPiep</td><td>Monoton steigend, 32-bit-Reads atomar auf LX6</td></tr>
|
||
<tr><td>bRequestShortBeep</td><td>bool</td><td>✓</td><td>loopTask (Core 1)</td><td>beepTask (Core 0)</td><td>Cross-Core; single-byte write atomar</td></tr>
|
||
<tr><td>loopCountSincePause</td><td>uint32_t</td><td>✓</td><td>loopTask (Core 1)</td><td>pinLevelChangeIsr (Core 1)</td><td>RF-Debounce nach Key-Empfang</td></tr>
|
||
<tr><td>PiepPattern::startRequest<br>PiepPattern::stopRequest</td><td>uint8_t</td><td>✓</td><td>loopTask via Start()/Stop()</td><td>beepTask via TaskCyclic()</td><td>Cross-Core; Flags, nicht Zähler</td></tr>
|
||
<tr><td>toneRequest</td><td>uint8_t</td><td>–</td><td>beepTask (exklusiv)</td><td>beepTask</td><td>Kein Cross-Core-Zugriff mehr nach Refactoring</td></tr>
|
||
</table>
|
||
</section>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════
|
||
11. XCP
|
||
═══════════════════════════════════════════════════════════ -->
|
||
<section>
|
||
<h2>11 · XCP-Protokoll</h2>
|
||
<table>
|
||
<tr><th>Event</th><th>Intervall</th><th>Aufruf</th></tr>
|
||
<tr><td>XcpEvent(0)</td><td>10 ms</td><td>xcpLoop() in loopTask (millis-basiert)</td></tr>
|
||
<tr><td>XcpEvent(1)</td><td>100 ms</td><td>xcpLoop()</td></tr>
|
||
<tr><td>XcpEvent(2)</td><td>500 ms</td><td>xcpLoop()</td></tr>
|
||
<tr><td>XcpEvent(3)</td><td>1000 ms</td><td>xcpLoop()</td></tr>
|
||
</table>
|
||
<div style="color:var(--muted);font-size:11px;margin-top:6px;">
|
||
XcpPoll() + XcpSendLoop() werden ebenfalls in xcpLoop() aufgerufen.
|
||
Timing ist millis()-basiert → toleriert den 5-ms-vTaskDelay des loopTask.
|
||
</div>
|
||
</section>
|
||
|
||
</body>
|
||
</html>
|