This commit is contained in:
chk
2026-06-19 06:43:56 +02:00
parent 83cef32a37
commit 8deb7bb8a6
3 changed files with 326 additions and 0 deletions

View File

@@ -0,0 +1,237 @@
\documentclass[a4paper,11pt]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[ngerman]{babel}
\usepackage{geometry}
\usepackage{amsmath}
\usepackage{booktabs}
\usepackage{listings}
\usepackage{xcolor}
\usepackage[unicode=true]{hyperref}
\usepackage{enumitem}
\lstset{
basicstyle=\ttfamily\small,
keywordstyle=\color{blue},
commentstyle=\color{gray},
stringstyle=\color{orange},
backgroundcolor=\color{gray!10},
frame=single,
breaklines=true,
columns=fullflexible
}
\title{\textbf{Emergency Stop Button -- ESP32}\\
\large Technische Dokumentation}
\author{}
\date{Juni 2026}
\begin{document}
\maketitle
\tableofcontents
\newpage
% -----------------------------------------------
\section{Ziel und Anforderungen}
Ein physischer Notaus-Taster soll beim Drücken so schnell wie möglich einen
API-Call absetzen. Der ESP32 befindet sich im Ruhezustand und wird durch den
Tastendruck geweckt.
\begin{itemize}
\item Latenz Knopfdruck $\rightarrow$ API-Call: \textbf{< 250\,ms}
\item Stromversorgung: LiPo 1000\,mAh (kabellos, batteriebetrieben)
\item Möglichst lange Akkulaufzeit (Taster wird selten gedrückt, $\leq$1\,×/h)
\item Einfache, wartungsarme Architektur
\end{itemize}
% -----------------------------------------------
\section{Architekturentscheidung}
\subsection{Bewertete Optionen}
\begin{center}
\begin{tabular}{lllll}
\toprule
Option & Latenz & Ø Strom & Gateway nötig & Komplexität \\
\midrule
Deep Sleep + WiFi (RTC-Memory) & 600--1300\,ms & $\approx$0{,}02\,mA & nein & niedrig \\
\textbf{WiFi Light Sleep (DTIM=10)} & \textbf{150--250\,ms} & \textbf{0{,}5--1\,mA} & \textbf{nein} & \textbf{niedrig} \\
BLE Light Sleep + Gateway & 100--300\,ms & 0{,}5--2\,mA & ja & hoch \\
\bottomrule
\end{tabular}
\end{center}
\subsection{Entscheidung: WiFi Light Sleep}
WiFi Light Sleep erfüllt alle Anforderungen ohne zusätzliche Infrastruktur:
\begin{itemize}
\item Der ESP32 hält die WiFi-Verbindung aufrecht und schläft nur die CPU
\item Ein GPIO-Interrupt weckt den ESP32 sofort beim Tastendruck
\item Der API-Call geht direkt vom ESP32 -- kein Container, kein Gateway
\end{itemize}
\textbf{Warum nicht BLE?} Bluetooth LE wäre minimal sparsamer
($\approx$0{,}5\,mA vs. $\approx$1\,mA), erfordert aber ein dauerhaft laufendes
Gateway-Gerät (Raspberry Pi, PC), das seinerseits Strom verbraucht und eine
Fehlerquelle darstellt.
\textbf{Warum nicht Deep Sleep?} Deep Sleep braucht beim Aufwachen
600--1300\,ms (WiFi-Reconnect), was die Latenzanforderung von 250\,ms
verfehlt.
% -----------------------------------------------
\section{WiFi Light Sleep -- Funktionsprinzip}
Im WiFi Light Sleep (Modem Sleep) schläft die CPU, während der WiFi-Stack
aktiv bleibt. Der Router sendet alle 100\,ms einen Beacon; mit DTIM=10 wacht
der ESP32 automatisch alle $\approx$1000\,ms für 1--2\,ms auf, um gepufferte
Pakete abzuholen. Die Verbindungsassoziation bleibt dabei erhalten.
\subsection{DTIM-Einstellung und Stromverbrauch}
\begin{center}
\begin{tabular}{lll}
\toprule
DTIM & Wakeup-Intervall & Ø Strom \\
\midrule
1 & 100\,ms & 5--10\,mA \\
3 & 300\,ms & 2--4\,mA \\
10 & 1000\,ms & 0{,}5--1\,mA \\
\bottomrule
\end{tabular}
\end{center}
Empfohlen: \texttt{DTIM=10} -- sparsamste Option, Verbindung bleibt stabil.
\subsection{Akkulaufzeit (1000 mAh LiPo)}
Bei $\approx$1\,mA Durchschnittsstrom (DTIM=10, selten gedrückt):
\[
t = \frac{1000~\mathrm{mAh}}{1~\mathrm{mA}} \approx 40~\mathrm{Tage}
\]
% -----------------------------------------------
\section{Latenzbudget}
\begin{center}
\begin{tabular}{ll}
\toprule
Schritt & Zeit \\
\midrule
ESP32 Wakeup aus Light Sleep & 1--5\,ms \\
WiFi-Verbindung prüfen (bereits aktiv) & 0\,ms \\
HTTP-Request aufbauen & 20--50\,ms \\
TLS-Handshake (HTTPS) & 50--150\,ms \\
Server-Antwort & 20--50\,ms \\
\midrule
\textbf{Gesamt} & \textbf{$\approx$100--250\,ms} \\
\bottomrule
\end{tabular}
\end{center}
% -----------------------------------------------
\section{Hardware}
\subsection{Empfohlene Boards}
\begin{center}
\begin{tabular}{llll}
\toprule
Board & Lader & Preis & Bemerkung \\
\midrule
\textbf{FireBeetle ESP32-E} (DFRobot) & integriert & 8--12\,& Low-Power optimiert \\
LOLIN D32 (Wemos) & TP4054 & 5--8\,& günstig, bewährt \\
Adafruit HUZZAH32 Feather & MCP73831 & $\approx$20\,& gute Dokumentation \\
\bottomrule
\end{tabular}
\end{center}
\subsection{Schaltung}
\begin{lstlisting}
ESP32 Taster
GPIO 9 ---- [Taster] ---- GND
(interner Pull-Up aktiv: HIGH = offen, LOW = gedrueckt)
LiPo 1000mAh ---- BAT+ / BAT- des Boards
\end{lstlisting}
Kein weiteres Bauteil nötig -- der interne Pull-Up des ESP32 reicht.
% -----------------------------------------------
\section{Software}
\subsection{Abhängigkeiten (Arduino IDE)}
\begin{itemize}
\item Board-Package: \texttt{esp32} by Espressif (Boards Manager)
\item Bibliotheken: \texttt{WiFi.h}, \texttt{HTTPClient.h} (im esp32-Package enthalten)
\end{itemize}
\subsection{Konfiguration in \texttt{EmergencyStopButton.ino}}
\begin{lstlisting}[language=C]
#define BUTTON_PIN 9
#define WIFI_SSID "DEIN_SSID"
#define WIFI_PASSWORD "DEIN_PASSWORT"
#define API_URL "https://deine-api.example.com/emergency-stop"
#define API_TOKEN "DEIN_API_TOKEN"
\end{lstlisting}
\subsection{Ablauf}
\begin{enumerate}
\item \texttt{setup()}: WiFi verbinden, \texttt{WIFI\_PS\_MAX\_MODEM} aktivieren
\item \texttt{loop()}: \texttt{esp\_light\_sleep\_start()} -- CPU schläft, WiFi aktiv
\item Tastendruck löst GPIO-Interrupt aus -- ESP32 wacht auf
\item \texttt{sendEmergencyStop()} sendet HTTP-POST an API
\item Warten bis Taster losgelassen, zurück zu Schritt 2
\end{enumerate}
\subsection{Kritische API-Funktion}
\begin{lstlisting}[language=C]
void sendEmergencyStop() {
HTTPClient http;
http.begin(API_URL);
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", "Bearer " API_TOKEN);
http.setTimeout(3000);
String body = "{\"event\":\"emergency_stop\",\"device\":\"esp32-estop\"}";
int httpCode = http.POST(body);
http.end();
}
\end{lstlisting}
% -----------------------------------------------
\section{Deployment-Hinweise}
\begin{itemize}
\item \textbf{HTTPS}: TLS-Handshake kostet 50--150\,ms. Falls die Latenz
kritisch ist und das Netz vertrauenswürdig, kann HTTP verwendet werden
(dann $\approx$50--100\,ms Gesamt).
\item \textbf{DTIM am Router}: Manche Router ignorieren den DTIM-Wunsch des
Clients. Im Zweifelsfall DTIM=3 am Router einstellen.
\item \textbf{API-Token}: Nicht im Quellcode einchecken -- z.\,B. in eine
separate \texttt{secrets.h} auslagern, die im \texttt{.gitignore} steht.
\item \textbf{Watchdog}: Bei produktivem Einsatz einen Hardware-Watchdog
aktivieren, damit der ESP32 sich bei WiFi-Verlust selbst neu startet.
\end{itemize}
% -----------------------------------------------
\section{Dateien}
\begin{center}
\begin{tabular}{ll}
\toprule
Datei & Beschreibung \\
\midrule
\texttt{EmergencyStopButton.ino} & Arduino-Sketch (Hauptprogramm) \\
\texttt{eStopESP32.tex} & Diese Dokumentation \\
\bottomrule
\end{tabular}
\end{center}
\end{document}