# Cluster-F > Projektdokumentation – ESP32-Umweltsensor mit BME280 über MQTT This document contains the full content of all documentation pages for AI consumption. --- ## Funktionsweise **URL:** https://docs.example.com/docs/ablauf **Description:** Programmablauf zur Laufzeit und der Entwicklungs-Workflow ## Ablauf des Programms Nach dem Start durchläuft der ESP32 die folgenden Schritte: ## Entwicklungs-Workflow Der typische Ablauf beim Bearbeiten des Codes: ```text Code in Thonny bearbeiten ↓ Datei auf ESP32 speichern (main.py) ↓ ESP32 startet das Skript automatisch ↓ Ausgabe / Fehler in der Thonny-Konsole prüfen ``` | Aspekt | Wert | |--------------|--------------------------------------------------------| | IDE | [Thonny](https://thonny.org/) | | Sprache | MicroPython | | Übertragung | Dateien werden per Thonny direkt auf den ESP32 geschrieben | --- ## Fehlerbehebung **URL:** https://docs.example.com/docs/fehlerbehebung **Description:** Häufige Fehlermeldungen, ihre Ursachen und Lösungen Treten Probleme auf, hilft meist ein Blick in die **Thonny-Konsole** weiter. Dort werden die Fehlermeldungen ausgegeben. Die folgenden Fehler kommen am häufigsten vor. --- ## Node-RED-Flows **URL:** https://docs.example.com/docs/finn-nodered-flows **Description:** Flows, die die Messwerte vom MQTT-Broker in die Datenbank schreiben Die Flows in Node-RED holen die Messwerte vom MQTT-Broker und schreiben sie in die PostgreSQL-Datenbank. Der Server selbst (die VM) ist in [Tims Bereich](/docs/tim-nodered-server) beschrieben. ## Aufbau des Flows ```text MQTT-In (sensor/#) ──▶ Function (in 3 Werte aufteilen) ──▶ SQL-Insert ──▶ PostgreSQL ``` ## Die Knoten im Einzelnen ### 1. MQTT-In Abonniert **alle Sensor-Topics** über den Wildcard `sensor/#`. Damit kommt alles rein, was der ESP32 veröffentlicht (`sensor/temperatur`, `sensor/luftfeuchte`, `sensor/luftdruck`). ### 2. Function Ein Function-Node teilt die eingehenden Daten in die **drei Werte** auf: **Temperatur**, **Luftdruck** und **Luftfeuchte**. Sie werden so aufbereitet, dass sie als Parameter an den SQL-Insert weitergegeben werden können. ### 3. SQL-Insert Die drei Werte werden per `INSERT` in die Tabelle `messungen` geschrieben. Den Zeitstempel setzt die Datenbank automatisch (`DEFAULT now()`). ```sql INSERT INTO messungen (temperatur, air_pressure, humidity) VALUES ($1, $2, $3); ``` Die Datenbank-Details (DB `sensordaten`, Tabelle `messungen`, Benutzer `psql_F`) stehen auf der [Datenbank-Seite](/docs/tim-datenbank). --- ## Python-Auswertung **URL:** https://docs.example.com/docs/finn-python-auswertung **Description:** Python-Skript, das die letzten Messungen aus der Datenbank liest und Statistiken ausgibt Das Auswertungsskript liest die letzten Messungen aus der PostgreSQL-Datenbank und gibt für **Temperatur, Luftdruck und Luftfeuchte** jeweils Durchschnitt, Minimum und Maximum aus. ## Was das Skript macht - Verbindet sich über `psycopg2` mit der Datenbank - Liest die letzten `ANZAHL_MESSUNGEN` Messungen (Standard: 100) aus der Tabelle `messungen` mit `pandas` - Berechnet Ø / Min / Max für die drei Messwerte - Gibt das Ergebnis in der Konsole aus ## Voraussetzungen ```bash pip install psycopg2-binary pandas ``` ## Datenbank-Verbindung | Punkt | Wert | |-----------|----------------| | Host | `192.168.1.10` | | Port | `5432` | | Datenbank | `sensordaten` | | Benutzer | `psql_f` | | Tabelle | `messungen` | ## Das Skript ```python """Sensordaten-Statistik (BME280 -> PostgreSQL).""" DB = dict(host="192.168.1.10", port=5432, dbname="sensordaten", user="psql_f", password="IchbinPSQL") ANZAHL_MESSUNGEN = 100 conn = psycopg2.connect(**DB) df = pd.read_sql( f"""SELECT timestamp, temperatur, air_pressure, humidity FROM messungen ORDER BY timestamp DESC LIMIT {ANZAHL_MESSUNGEN};""", conn, ) conn.close() if df.empty: print("Keine Messungen gefunden.") else: print(f"--- Statistik (letzte {len(df)} Messungen) ---") for spalte, label, einheit in [("temperatur", "Temperatur", "°C"), ("air_pressure", "Luftdruck", "hPa"), ("humidity", "Luftfeuchte", "%")]: print(f"{label:11} Ø {df[spalte].mean():.2f} {einheit} " f"Min {df[spalte].min():.2f} Max {df[spalte].max():.2f}") ``` ## Beispiel-Ausgabe ```text --- Statistik (letzte 100 Messungen) --- Temperatur Ø 22.34 °C Min 21.10 Max 23.80 Luftdruck Ø 1013.20 hPa Min 1011.00 Max 1015.40 Luftfeuchte Ø 45.10 % Min 40.20 Max 50.90 ``` --- ## Übersicht **URL:** https://docs.example.com/docs **Description:** Messdatenerfassung mit ESP32, virtualisiert auf einem Proxmox-Cluster – Projektübersicht und Aufgabenverteilung Dieses Projekt erfasst Messdaten mit einem **ESP32**, speichert sie dauerhaft in einer **Datenbank** und wertet sie mit einem **Python-Skript** aus. Der komplette Stack läuft **virtualisiert** auf einem **Proxmox-Cluster** aus drei Hosts. ## Datenfluss ```text ESP32 ──MQTT──▶ MQTT-Broker ──▶ Node-RED ──▶ Datenbank ──▶ Python-Auswertung (Sensor) (Mosquitto) (Middleware) (PostgreSQL) (Visualisierung) ``` Alles läuft als VMs im Proxmox-Cluster und wird über eine OPNsense-Firewall abgesichert. ## Wer hat was gemacht | Person | Bereich | Inhalt | |-------------|------------------------|--------------------------------------------------------------| | **Tim** | Server & Infrastruktur | Datenbank-, MQTT- und Node-RED-Server (Debian-VMs) aufgesetzt | | **Finn** | Software & Code | ESP32 programmiert, MQTT angebunden, Node-RED-Flows | | **Marcel** | Netzwerk & Sicherheit | OPNsense-Firewall, Vernetzung & Absicherung der VMs | > Der **Proxmox-Cluster** wurde gemeinsam aufgesetzt: jeder hat seinen eigenen PVE-Host installiert und ins Cluster integriert (mit Live-Migration zwischen den Hosts). ## Anforderungen aus der Aufgabe | Anforderung | Status | Wer | |--------------------------------------------|----------|----------| | Proxmox-Cluster (3 Hosts, Live-Migration) | läuft | Team | | Debian-VM: Datenbankserver | ok | Tim | | Debian-VM: MQTT-Broker | ok | Tim | | Debian-VM (GUI): Node-RED als Middleware | ok | Tim/Finn | | Messdatenerfassung mit ESP32 → MQTT | ok | Finn | | Python-Auswertungsskript | ok | Finn | | Netzwerkplanung & Sicherheit | ok | Marcel | | KI-Nutzung dokumentiert | siehe [KI-Nutzung](/docs/ki-nutzung) | Team | ## Bereiche --- ## Installation **URL:** https://docs.example.com/docs/installation **Description:** MicroPython-Libraries installieren und die Dateien auf den ESP32 bringen Damit der Sensor funktioniert, müssen auf dem ESP32 zwei MicroPython-Libraries installiert sein und das Programm `main.py` aufgespielt werden. ## Voraussetzungen - **Thonny** ist installiert ([thonny.org](https://thonny.org/)) - Der **ESP32** ist mit der **MicroPython-Firmware** geflasht - Der ESP32 ist per USB-Kabel mit dem Computer verbunden ## Verwendete Libraries | Library | Zweck | |----------------------------|----------------------------------| | `micropython-bme280` | Auslesen der BME280-Sensorwerte | | `micropython-umqtt.simple` | MQTT-Client für die Veröffentlichung | ## Installation über Thonny ## Dateistruktur auf dem ESP32 Nach erfolgreicher Installation liegen folgende Dateien auf dem ESP32: ```text / ├── main.py # Hauptprogramm (Sensor lesen + MQTT senden) └── lib/ ├── bme280.py # BME280-Library └── umqtt/ └── simple.py # MQTT-Client-Library ``` --- ## KI-Nutzung **URL:** https://docs.example.com/docs/ki-nutzung **Description:** Dokumentation des KI-Einsatzes im Projekt (laut Aufgabe verpflichtend) Laut Aufgabenstellung muss dokumentiert werden, wo und wie KI im Projekt genutzt wurde. Das ist hier festgehalten. ## Dokumentation aufbereiten Die Inhalte dieser Dokumentation stammen von uns. KI haben wir genutzt, um die Doku zu **organisieren und übersichtlich darzustellen**: Struktur, Aufteilung nach Personen und anschauliche Aufbereitung. Geschrieben haben wir die Inhalte selbst, die KI hat beim Strukturieren und Darstellen geholfen. ## Fehlersuche KI wurde durchgehend zur **Fehlersuche** eingesetzt: bei **Code-Fehlern**, **Installationsfehlern** und ähnlichen Problemen. Fehlermeldungen haben wir mit KI analysiert, um schneller eine Lösung zu finden. ## Übersicht | Bereich | KI-Einsatz | |---------------|--------------------------------------------------------| | Dokumentation | Struktur, Aufteilung und übersichtliche Darstellung | | Fehlersuche | Code-Fehler, Installationsfehler und ähnliche Probleme | --- ## Konfiguration **URL:** https://docs.example.com/docs/konfiguration **Description:** MQTT-Broker-Adresse einstellen und die verwendeten Topics im Überblick Die wichtigsten Einstellungen befinden sich in der Datei `main.py`. ## MQTT-Broker-IP anpassen Der MQTT-Broker hat eine **feste IP** (per DHCP-Reservierung über die OPNsense). In `main.py` ist sie als Konstante `BROKER` eingetragen: ```python # main.py BROKER = "192.168.1.5" # <-- IP des MQTT-Brokers ``` ## MQTT-Topics Der ESP32 veröffentlicht die Messwerte unter folgenden Topics: | Topic | Inhalt | Einheit | |----------------------|------------------|---------| | `sensor/temperatur` | Temperatur | °C | | `sensor/luftfeuchte` | Relative Feuchte | % | | `sensor/luftdruck` | Luftdruck | hPa | --- ## Netzwerk & Sicherheit **URL:** https://docs.example.com/docs/marcell-netzwerk **Description:** IP-Bereiche, VLAN und Firewall-Regeln der Cluster-F Group Hier sind die Netzwerk-Eckdaten der Cluster-F Group dokumentiert – Adressbereich, VLAN und die Firewall-Logik. ## IP-Bereich & VLAN Alle Maschinen der Cluster-F Group liegen im selben Subnetz und werden über ein eigenes VLAN getrennt. | Parameter | Wert | |--------------|------------------| | IP-Bereich | `192.168.1.0/24` | | VLAN | `VLAN10` | ## Firewall-Regeln Die Firewall (OPNsense, siehe [Maschinen](/docs/maschinen)) verhält sich wie ein **ganz normaler Router**: nach außen ist alles offen, von außen herein ist nur das Nötigste freigegeben. | Richtung | Dienst | Port | Regel | |------------|---------------|--------|-----------| | Ausgehend | alles | – | erlaubt | | Eingehend | Node-RED | `1880` | erlaubt | | Eingehend | MQTT | `1883` | erlaubt | | Eingehend | alles Übrige | – | blockiert | --- ## Maschinen **URL:** https://docs.example.com/docs/maschinen **Description:** Übersicht aller Maschinen der Cluster-F Group und der darauf laufenden Dienste Die Cluster-F Group besteht aus mehreren Maschinen. Jede Maschine ist für **einen Dienst** zuständig – und ist nach genau diesem Dienst benannt. ## Namenskonvention | Dienst | Maschinenname | IP | Zweck | |------------|---------------|----------------|-------------------------------| | unmint | `unmint` | — | Generiert diese Dokumentation | | Node-RED | `nodered` | `192.168.1.3` | Automatisierung & Flows | | PostgreSQL | `posql` | `192.168.1.10` | Datenbank | | OPNsense | `opnsense` | `172.16.3.38` | Firewall / Router | | MQTT | `mqtt` | `192.168.1.5` | MQTT-Broker (Mosquitto) | ## Zugangsdaten Die Passwörter folgen einer festen Regel (`Ichbin` + Name in Großbuchstaben) und sind zentral hinterlegt. --- ## Passwörter **URL:** https://docs.example.com/docs/passwoerter **Description:** Zentrale Ablage aller Zugangsdaten der Cluster-F-Maschinen – inklusive Namens- und Passwort-Regel Hier liegen die Zugangsdaten **aller Maschinen** der Cluster-F Group an einem Ort. Damit man sich nichts merken muss, folgt alles einer festen Regel – sie steht ganz oben. ## Die Regel Damit ergibt sich das Passwort jeder Maschine automatisch: ```text Passwort = "Ichbin" + MASCHINENNAME (in CAPSLOCK) unmint → IchbinUNMINT nodered → IchbinNODERED ``` ## Maschinen & Passwörter | Maschine | Läuft darauf / Dienst | Passwort | |------------|------------------------------------|------------------| | `unmint` | unmint – diese Dokumentation | `IchbinUNMINT` | | `nodered` | Node-RED – Automatisierung & Flows | `IchbinNODERED` | | `posql` | PostgreSQL – Datenbank | `IchbinPOSQL` | | `opnsense` | OPNsense – Firewall / Router | `IchbinOPNSENSE` | | `mqtt` | MQTT-Broker (Mosquitto) | `IchbinMQTT` | ## Dienst-Zugänge Eigene Benutzer **innerhalb der Dienste** (nicht zu verwechseln mit dem Login der Maschinen): | Dienst | Benutzer | Wofür | Passwort | |------------|----------|--------------------------------------------------|--------------------| | PostgreSQL | `psql_F` | Zugriff auf die Datenbank `sensordaten` (Node-RED) | `IchbinPSQL` | | MQTT | `mqtt_f` | Anmeldung am Mosquitto-Broker (ESP32 + Node-RED) | `IchbinMQTT` | ## Neue Maschine aufnehmen --- ## Datenbank-Server **URL:** https://docs.example.com/docs/tim-datenbank **Description:** Debian-VM mit PostgreSQL 18, in der die Messdaten gespeichert werden Die Datenbank läuft auf einer eigenen Debian-VM (ohne GUI). Hier werden die Messwerte gespeichert, die Node-RED aus dem MQTT-Broker holt. Als Datenbank wird **PostgreSQL 18** genutzt. ## Eckdaten | Punkt | Wert | |---------------|---------------------------------------| | VM | Debian (ohne GUI) | | Maschinenname | `posql` | | Interne IP | `192.168.1.10` | | Datenbank | PostgreSQL 18 | | DB-Name | `sensordaten` | | Tabelle | `messungen` | | DB-Benutzer | `psql_F` | | Zugang | siehe [Passwörter](/docs/passwoerter) | ## Installation PostgreSQL 18 ist als normale Standard-Installation auf der Debian-VM eingerichtet. Die VM hängt im internen Netz unter der festen IP `192.168.1.10`. ## Zugriff / Benutzer Statt mit dem Standard-Superuser `postgres` zu arbeiten, wurde ein **eigener Benutzer `psql_F`** angelegt, der **nur auf die Datenbank `sensordaten`** zugreifen darf. So kommt Node-RED nur an genau diese eine Datenbank und nicht an den Rest des Systems. ```sql -- eigener Benutzer nur für die Messdaten-DB (Passwort siehe Passwörter-Seite) CREATE USER psql_F WITH PASSWORD '...'; GRANT CONNECT ON DATABASE sensordaten TO psql_F; GRANT SELECT, INSERT ON messungen TO psql_F; ``` Das Passwort von `psql_F` steht bei den [Passwörtern](/docs/passwoerter). ## Datenbank & Tabelle Es gibt die Datenbank **`sensordaten`** und darin die Tabelle **`messungen`**: ```sql CREATE TABLE messungen ( id BIGSERIAL PRIMARY KEY, timestamp TIMESTAMPTZ NOT NULL DEFAULT now(), temperatur REAL, air_pressure REAL, humidity REAL ); ``` ### Spalten | Spalte | Typ | Bedeutung | |----------------|------------------|--------------------------------------------| | `id` | `BIGSERIAL` (PK) | Fortlaufende ID, wird automatisch vergeben | | `timestamp` | `TIMESTAMPTZ` | Zeitpunkt der Messung, Standard `now()` | | `temperatur` | `REAL` | Temperatur in °C | | `air_pressure` | `REAL` | Luftdruck in hPa | | `humidity` | `REAL` | Luftfeuchte in % | Jede Messung bekommt automatisch eine `id` und einen `timestamp`. Die drei Messwerte (`temperatur`, `air_pressure`, `humidity`) kommen vom BME280 über den ESP32 und werden von Node-RED in die Tabelle geschrieben. --- ## MQTT-Broker-Server **URL:** https://docs.example.com/docs/tim-mqtt-server **Description:** Debian-VM mit Mosquitto als MQTT-Broker, mit eigener Benutzer-Authentifizierung Der MQTT-Broker läuft auf einer eigenen Debian-VM (ohne GUI). Er nimmt die Messwerte vom ESP32 entgegen und stellt sie für Node-RED bereit. Als Broker wird **Mosquitto** genutzt. ## Eckdaten | Punkt | Wert | |---------------|---------------------------------------| | VM | Debian (ohne GUI) | | Maschinenname | `mqtt` | | Interne IP | `192.168.1.5` | | Broker | Mosquitto | | Port | `1883` | | Auth | Benutzer + Passwort (Passwort-Datei) | | MQTT-Benutzer | `mqtt_f` | | Zugang | siehe [Passwörter](/docs/passwoerter) | ## Installation Mosquitto ist als normale Standard-Installation auf der Debian-VM eingerichtet. ## Authentifizierung (Besonderheit) Standardmäßig würde Mosquitto jeden ohne Login annehmen. Damit nur unsere Geräte zugreifen, ist in der Config eine **Passwort-Datei** eingetragen und der anonyme Zugriff abgeschaltet. Darüber wurde ein eigener Benutzer **`mqtt_f`** für unsere Gruppe angelegt. Mit dem meldet sich der ESP32 (publish) und Node-RED (subscribe) am Broker an. In der Mosquitto-Config: ```text # /etc/mosquitto/mosquitto.conf (bzw. eine Datei in conf.d) allow_anonymous false password_file /etc/mosquitto/passwd ``` Benutzer anlegen (das `-c` legt die Passwort-Datei neu an): ```bash sudo mosquitto_passwd -c /etc/mosquitto/passwd mqtt_f ``` Das Passwort von `mqtt_f` steht bei den [Passwörtern](/docs/passwoerter). ## Topics Die genutzten Topics (vom ESP32 befüllt) stehen in Finns [Konfiguration](/docs/konfiguration): `sensor/temperatur`, `sensor/luftfeuchte`, `sensor/luftdruck`. --- ## Node-RED-Server **URL:** https://docs.example.com/docs/tim-nodered-server **Description:** Debian-VM mit GUI, auf der Node-RED über das offizielle Install-Skript läuft Debian-VM (**mit GUI**), auf der **Node-RED** läuft. Node-RED ist die Middleware, die die Daten vom MQTT-Broker in die Datenbank schreibt. Die Flows selbst sind in [Finns Bereich](/docs/finn-nodered-flows) beschrieben. ## Eckdaten | Punkt | Wert | |----------------|---------------------------------------| | VM | Debian (mit GUI) | | Maschinenname | `nodered` | | Interne IP | `192.168.1.3` | | Dienst | Node-RED | | Web-Oberfläche | Port `1880` | | Netzwerk | hinter der OPNsense, per NAT auf Port `1880` | | Zugang | siehe [Passwörter](/docs/passwoerter) | ## Installation Node-RED ist mit dem **offiziellen Install-Skript** eingerichtet, ohne Sonderkonfiguration. Das Skript installiert Node.js und Node-RED und richtet Node-RED als Dienst ein: ```bash bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered) ``` Danach als Dienst aktivieren (Autostart): ```bash sudo systemctl enable --now nodered.service ``` Die Weboberfläche läuft auf dem Standard-Port `1880`. Der Server steht **hinter der OPNsense** und ist von außen per **NAT (Port-Weiterleitung)** auf dem Standard-Port erreichbar. Die Firewall- und Weiterleitungs-Details stehen in [Marcels Netzwerk-Teil](/docs/marcell-netzwerk). ## Was läuft darauf Auf dem Server läuft nur Node-RED. Die eigentlichen Flows (MQTT abonnieren, Werte in die Datenbank schreiben) sind in [Finns Node-RED-Flows](/docs/finn-nodered-flows) dokumentiert. --- ## Links - [GitHub](https://github.com/gsmgh/cluter-f-unmint) - [Discord](https://discord.gg/your-invite)