Skip to content

Software Konzept

Fabienne Rosa Schedler edited this page Apr 29, 2026 · 100 revisions

Software Konzept:

  • Deadline V1 12.03.2026, 12:00
  • Deadline V2 19.03.2026, 12:00
  • Deadline finale Version 30.04.2026, 18:00

[[TOC]]

1. Systemüberblick

ClimateCanary überwacht das Raumklima in Bürogebäuden über ein dreischichtiges IoT-System: Sensorstationen (Arduino) messen kontinuierlich und übertragen die Daten per BLE an einen Raspberry Pi pro Raum, der die Grenzwertlogik lokal ausführt und Daten datenschutzkonform an ein zentrales Spring Boot Backend weiterleitet. Nutzer sehen die Daten rollenabhängig in einer React-Webanwendung.

Zielsetzung

  • ClimateCanary ist ein IoT-basiertes Monitoring-System, das Unternehmen eine kontinuierliche und automatisierte Überwachung des Raumklimas in Bürogebäuden ermöglicht.
  • Das System erfasst Temperatur, Luftfeuchtigkeit, Luftdruck und Luftqualität in Echtzeit und stellt diese Daten rollenabhängig in einer zentralen Webanwendung dar.
  • Kurzfristiges Ziel: Mitarbeiter:innen und Verwaltung sollen jederzeit informiert sein, wenn Raumklimawerte kritische Grenzwerte über- oder unterschreiten, und können entsprechend reagieren.
  • Mittelfristiges Ziel: Langfristige Auswertungen der gesammelten Daten sollen als Entscheidungsgrundlage für gezielte Maßnahmen zur Raumklimaverbesserung dienen (z. B. Anschaffung von Klimaanlagen, Luftreinigern).
  • Langfristiges Ziel (außerhalb des aktuellen Projektumfangs): Automatische Steuerung von Heizung, Jalousien und Fenstern auf Basis der gesammelten Klimadaten.

Zielgruppe

  • Primäre Zielgruppe sind mittelständische bis große Unternehmen mit mehreren Büroräumen und Allgemeinflächen.
  • Das System richtet sich an alle Mitarbeiter:innen eines Unternehmens, die das Raumklima an ihrem Arbeitsplatz überwachen möchten.
  • Zusätzlich adressiert es Abteilungsleitungen, das höhere Management sowie die Gebäude- und Systemadministration, die das System konfigurieren und übergreifend auswerten.

Benutzer und Rollen

  • Mitarbeiter:in: Überwacht das Raumklima am eigenen Arbeitsplatz und in Allgemeinflächen der eigenen Abteilung. Verwaltet eigene Abwesenheiten.
  • Abteilungsleitung: Erbt alle Rechte der Mitarbeiter:in. Erhält zusätzlich eine Übersicht aller Räume der eigenen Abteilung in reduzierter Datengranularität (Tagesdurchschnitte für Büroräume). Sieht Abwesenheiten der Mitarbeiter:innen.
  • Geschäftsführung: Sieht firmenweite, aggregierte und anonymisierte Übersichten und Trendindikatoren. Kein Zugriff auf raumgenaue Daten.
  • Hausverwalter: Sieht alle Raumklimadaten aller Räume, konfiguriert Grenzwerte und verwaltet Raumklima-Tipps. Kein Zugriff auf Userdaten oder Raumzuweisungen.
  • Systemadministrator: Verwaltet Benutzer, Gebäudestruktur und Geräte (Raspberry Pis, Sensorstationen). Kein Zugriff auf Messdaten.

Wichtig: Hausverwalter und Systemadministrator sind strikt voneinander getrennt – diese Trennung ist der zentrale Datenschutzmechanismus des Systems. Der Hausverwalter sieht nie, welche User welchem Raum zugeordnet sind.

Kernfunktionalitäten

  • Automatische Erfassung von Temperatur, Luftfeuchtigkeit, Luftdruck und Luftqualität durch Arduino-Sensorstationen (BME680/688 Sensor).
  • Übertragung der Messdaten via Bluetooth Low Energy (BLE) an einen raumgebundenen Raspberry Pi. Das BLE-Protokoll (GATT-Profil) wird selbst definiert; nach der ersten erfolgreichen Verbindung koppelt sich der Arduino ausschließlich mit dem zugewiesenen Raspberry Pi.
  • Lokal am Raspberry Pi: Grenzwertprüfung mit Noise-Filter (Hysterese/Zeitfenster), datenschutzkonforme Zwischenspeicherung in SQLite, Weiterleitung an den zentralen Webserver per REST.
  • Visuelle Rückmeldung direkt an der Sensorstation: ampelartige RGB-LED mit den Kernfarben Türkis, Orange/Koralle und Rot sowie weiteren Farben bzw. Blinkmustern für spezielle Zustände; LCD-Display mit aktuellen Werten, Warnungen und Tipps.
  • Zentrale Webanwendung (Spring Boot + React/TypeScript) mit rollenabhängigen Ansichten, Verlaufsdiagrammen, Grenzwertwarnungen und Konfigurationsoptionen.
  • Datenschutzkonforme Datenhaltung: Bürodaten werden nur bei Mindestbelegung von 5 Personen persistent gespeichert. Transiente Verarbeitung am Raspberry Pi (z. B. für Grenzwertberechnung) ist immer erlaubt.
  • Abwesenheitssystem zur Pflege von Urlaub, Krankheit etc., das automatisch die Datenschutzprüfung beeinflusst und den zuständigen Raspberry Pi benachrichtigt.

2. Use Cases

Use Case Diagramm

Use Case Diagramm

Das vollständige Use Case Diagramm befindet sich als separates PNG im Projekt Repo -Ordner (Datei: /uploads/images/Use Case Diagramm V2.png).

Akteure

Akteur Typ Beschreibung
Raumnutzer:in (vor Ort) Mensch Interagiert physisch mit der Sensorstation; kein Webapp-Zugang.
Mitarbeiter:in Mensch Basisrolle; Zugriff auf eigenes Büro (bei Mindestbelegung ≥ 5) und Allgemeinflächen der Abteilung.
Abteilungsleitung Mensch Erbt Rechte der Mitarbeiter:in; zusätzlich Abteilungsübersicht mit reduzierter Granularität.
Geschäftsführung Mensch Nur aggregierte, firmenweite Sicht; keine Raumdetails, keine Userdaten.
Hausverwalter Mensch Vollzugriff auf Raumklimadaten und Konfiguration; keine Nutzer-Raum-Zuordnungen oder Abwesenheiten sichtbar.
Systemadministrator Mensch Benutzer- und Geräteverwaltung; kein Zugriff auf Messdaten oder Grenzwertkonfiguration.
«system» Deployment System Legt beim ersten Start den ersten Systemadministrator an.
«system» Raspberry Pi System Empfängt Messdaten via BLE, prüft Grenzwerte, leitet Daten datenschutzkonform an die Webapp weiter.
«system» Sensorstation (Arduino) System Misst Raumklimaparameter und sendet diese via BLE an den zugewiesenen Raspberry Pi.

Übersicht der Use Cases

Akteur Use Cases
Raumnutzer:in Messwerte / Warnungen / Fehlerzustand am Display ablesen, Navigation (Buttons), Anzeigemodus wechseln, LED-Status ablesen
Mitarbeiter:in Anmelden/Abmelden, aktuelle & historische Messungen eigenes Büro (nur bei Mindestbelegung ≥ 5), aktuelle & historische Messungen Allgemeinflächen, Echtzeitalarme lesen, eigene Abwesenheiten verwalten
Abteilungsleitung Abteilungsübersicht (Raumvergleich, Verletzungshäufigkeit), historische Bürodaten (Tagesdurchschnitte), Grenzwertverletzungen der Abteilung einsehen, Abwesenheiten der Abteilung einsehen
Geschäftsführung Unternehmensweites Dashboard, Trendindikatoren, anonymisierte Verletzungsstatistiken pro Abteilung
Hausverwalter Alle Raumdaten einsehen (volle Granularität, ohne Nutzerzuordnung), Grenzwertverletzungen aller Räume, Grenzwerte konfigurieren, Verbesserungstipps verwalten, Geräteausfälle einsehen
Systemadministrator Gebäude/Abteilungen/Räume verwalten, Raspberry Pis & Sensorstationen registrieren & zuweisen, Geräte konfigurieren, Benutzer verwalten, Rollen zuweisen (inkl. Abteilungsleiter:in ernennen), Geräteausfälle einsehen
«system» Deployment Ersten Systemadmin anlegen
«system» Raspberry Pi Konfigurationsänderungen empfangen, Messdaten empfangen & zwischenspeichern (BLE → SQLite), Grenzwertverletzungen prüfen & Warnungen auslösen, Messdaten an Webapp weiterleiten
«system» Sensorstation Messdaten erfassen & an Raspberry Pi übertragen, Warnungen empfangen & anzeigen, Grenzwertüberschreitungen via LED signalisieren

Use Case Beschreibungen

UC-01: Aktuelle Raumklimadaten eigenes Büro einsehen

  • Akteur: Mitarbeiter:in
  • Vorbedingung: Nutzer:in ist eingeloggt und einem Büroraum zugeordnet.
  • Normalablauf:
    1. Nutzer:in öffnet die Raumansicht des eigenen Büros.
    2. Das System prüft die aktuelle Belegung des Raums anhand der eingetragenen Abwesenheiten: Es berechnet, wie viele dem Raum zugeordnete Personen aktuell nicht als abwesend erfasst sind. Diese Prüfung ist notwendig, da aus hochfrequenten Messdaten (Minutenwerte) Rückschlüsse auf das Verhalten einzelner Personen möglich wären – die Datenschutzanforderung legt daher fest, dass Bürodaten nur bei einer Mindestbelegung von 5 Personen angezeigt werden dürfen.
    3. Wenn die Belegung ≥ 5 Personen beträgt: Das System zeigt aktuelle Messwerte (Temperatur, Luftfeuchtigkeit, Luftqualität) an.
    4. Konfigurierte Grenzwerte sind als Referenzlinien sichtbar.
    5. Aktive Grenzwertwarnungen werden prominent angezeigt, inklusive Raumklima-Tipps.
  • Alternativablauf – Mindestbelegung nicht erfüllt:
    1. Das System erkennt, dass die aktuelle Belegung unter 5 Personen liegt (mindestens eine Person hat eine Abwesenheit eingetragen, sodass die Gesamtzahl anwesender Personen des Raums unter die Mindestgrenze fällt).
    2. Das System zeigt den Hinweis: „Keine Daten verfügbar – Datenschutzbedingungen nicht erfüllt."
    3. Es werden keine aktuellen Messdaten angezeigt.
  • Alternativablauf – Verbindungsausfall:
    1. Für einen bestimmten Zeitraum fehlen Messdaten (z. B. Raspberry Pi offline).
    2. Das System zeigt eine Meldung, dass die Sensorstation aktuell offline ist.

UC-02: Historische Messdaten eigenes Büro einsehen

  • Akteur: Mitarbeiter:in
  • Vorbedingung: Nutzer:in ist eingeloggt und einem Büroraum zugeordnet.
  • Normalablauf:
    1. Nutzer:in navigiert zur Verlaufsansicht des eigenen Büros und wählt einen Zeitraum (Tag / Woche / Monat).
    2. Das System zeigt Verlaufsdiagramme (Temperatur, Luftfeuchtigkeit, Luftqualität) für den gewählten Zeitraum an.
    3. Konfigurierte Grenzwerte sind als Referenzlinien in den Diagrammen sichtbar.
    4. Zeitabschnitte, in denen die Mindestbelegung unterschritten war oder die Sensorstation offline war, werden als grau hinterlegte Lücken markiert („Daten nicht verfügbar").
  • Hinweis: Es werden nur Messdaten angezeigt, die zum Zeitpunkt der Erfassung unter datenschutzkonformen Bedingungen (Mindestbelegung ≥ 5) persistent gespeichert wurden. Zeiträume ohne persistente Daten erscheinen als Lücken.

UC-03: Historische Grenzwertüberschreitungen eigenes Büro einsehen

  • Akteur: Mitarbeiter:in
  • Vorbedingung: Nutzer:in ist eingeloggt und einem Büroraum zugeordnet.
  • Normalablauf:
    1. Nutzer:in öffnet die Übersicht der Grenzwertverletzungen des eigenen Büros.
    2. Das System zeigt eine Liste aktiver und vergangener Grenzwertverletzungen des Raums an (Zeitpunkt, Metrik, Wert, Status: ACTIVE / RESOLVED / DISABLED).
    3. Nutzer:in kann eine Verletzung auswählen, um Details (betroffene Messgröße, Dauer, Verlauf) einzusehen.

UC-04: Raumklimadaten Allgemeinflächen einsehen

  • Akteur: Mitarbeiter:in, Abteilungsleitung
  • Vorbedingung: Nutzer:in ist eingeloggt und einer Abteilung zugeordnet.
  • Normalablauf:
    1. Nutzer:in wählt eine Allgemeinfläche (Konferenzraum, Aufenthaltsraum etc.) der eigenen Abteilung aus.
    2. Das System zeigt aktuelle Messwerte und Verlaufsdiagramme in voller Granularität an.
    3. Es gelten keine Datenschutzeinschränkungen – die Daten sind immer verfügbar.

UC-05: Abteilungsübersicht einsehen

  • Akteur: Abteilungsleitung
  • Vorbedingung: Nutzer:in ist als Abteilungsleitung eingeloggt.
  • Normalablauf:
    1. Die Abteilungsleitung öffnet die Abteilungsübersicht.
    2. Das System zeigt eine vergleichende Darstellung aller Räume der Abteilung (aktuelle Messwerte, Anzahl aktiver Warnungen).
    3. Für Büroräume, deren aktuelle Belegung ≥ 5 beträgt, werden Verlaufsansichten in reduzierter Granularität (Tagesdurchschnitte) angezeigt. Die reduzierte Granularität ist eine bewusste Datenschutzentscheidung: Tagesdurchschnitte verhindern, dass aus Minutenwerten Rückschlüsse auf das Verhalten einzelner Personen gezogen werden können.
    4. Für Allgemeinflächen werden Verlaufsansichten in voller Granularität angezeigt.
    5. Aktive und vergangene Grenzwertverletzungen auf Raumebene sind einsehbar.
    6. Die Abteilungsleitung sieht Abwesenheiten der Mitarbeiter:innen ihrer Abteilung (ohne Zuordnung von Personen zu Räumen – diese Information ist ausschließlich dem Systemadmin zugänglich).

UC-06: Grenzwertwarnung – Auslösung und Anzeige

  • Akteur: Raspberry Pi (technisch), Mitarbeiter:in / Abteilungsleitung (sichtbar)
  • Vorbedingung: Grenzwerte sind für den betroffenen Raum konfiguriert. Die Sensorstation ist aktiv und mit dem Raspberry Pi verbunden.
  • Normalablauf:
    1. Der Raspberry Pi empfängt Messdaten von der Sensorstation via BLE.
    2. Der Raspberry Pi prüft die Messwerte gegen konfigurierte Grenzwerte mit Noise-Filter: Eine Warnung wird erst ausgelöst, wenn der Grenzwert über fünf Minuten überschritten wird. Einzelne Ausreißer (kurzes Öffnen eines Fensters, Atemstoß auf den Sensor) lösen keine Warnung aus.
    3. Bei bestätigter Grenzwertüberschreitung setzt der Raspberry Pi den Warnstatus, übermittelt diesen an die Sensorstation (via BLE) und sendet einen POST /api/cpi/{piId}/violation an das Backend der Webapp (via REST – der Raspberry Pi agiert dabei als REST-Client).
    4. An der Sensorstation wechselt die LED auf Rot, das Display zeigt den Warnmodus mit Hinweis und Tipp.
    5. In der Webapp wird die Warnung prominent für alle Nutzer:innen des betroffenen Raums angezeigt (z. B. als farblich hervorgehobenes Banner), inklusive konfigurierter Raumklima-Tipps.
    6. Die Abteilungsleitung sieht die Warnung in der Abteilungsübersicht.
  • Alternativablauf – Warnung aufheben: Warnungen können entweder manuell aufgehoben werden oder automatisch, wenn die Messwerte wieder in den Normalbereich zurückkehren.

Manuelles Aufheben

  1. User hebt die Warnung im Frontend auf.
  2. Backend schickt schickt mit POST eine ViolationResolvedDTO an /api/spi/{piId}/violation/resolve auf den Raspberry.
  3. Basierend auf der DTO deaktiviert der Raspberry die betroffenen Violation, informiert den Arduino und updated seine eigene Datenbank (gleiche Logik wie bei automatischer Deaktivierung der Grenzwertwarnung)

Automatisches Aufheben

  1. Die Messwerte kehren dauerhaft in den Normalbereich zurück.
  2. Der Raspberry Pi hebt den Warnstatus auf und informiert Sensorstation und Webapp.
  3. Die LED wechselt auf Türkis, die Warnmeldung in der Webapp verschwindet. Die vergangene Verletzung bleibt historisch gespeichert (violationStatus = RESOLVED).
  • Designentscheidung: Die Länge des Zeitfensters für die Durchschnittsberechnung beträgt 5min.

UC-07: Grenzwerte konfigurieren

  • Akteur: Hausverwalter
  • Vorbedingung: Nutzer:in ist als Hausverwalter eingeloggt. Raum und Sensorstation sind im System angelegt.
  • Normalablauf:
    1. Der Hausverwalter öffnet die Konfigurationsansicht eines Raums.
    2. Die Admin-Person setzt oder ändert obere Grenzwerte für Temperatur, Luftfeuchtigkeit, Luftdruck und Luftqualität. Untere Grenzwerte sind optional.
    3. Das System speichert die neuen Grenzwerte in der PostgreSQL-Datenbank.
    4. Der zuständige Raspberry Pi wird vom Backend per POST /api/spi/{piId}/config/thresholds über Grenzwertänderungen informiert.
    5. Der Raspberry Pi speichert die neuen Grenzwerte lokal in der SQLite-Datenbank und wendet sie ab der nächsten Messung an.

UC-08: Abwesenheit eintragen

  • Akteur: Mitarbeiter:in
  • Vorbedingung: Nutzer:in ist eingeloggt und einem Büroraum zugeordnet.
  • Normalablauf:
    1. Mitarbeiter:in trägt eine Abwesenheit (Urlaub, Krankheit etc.) stunden- oder tageweise ein.
    2. Das System speichert die neue Abwesenheit in der Datenbank.
    3. Ein gescheduledter Ablauf wird alle 5 Minuten ausgeführt.
    4. Der Ablauf fragt die relevanten Datenbankeinträge ab.
    5. Das System prüft anhand der Datenbankeinträge, ob durch Abwesenheiten die Mindestbelegung (5 Personen) in einem Büroraum unterschritten wird.
    6. Der Ablauf informiert alle Raspberry Pis darüber, ob der PrivacyMode aktualisiert werden muss über Endpunkt /api/spi/{piId}/occupancy.
    7. Wenn die Mindestbelegung unterschritten wird, aktiviert der betroffene Raspberry Pi den PrivacyMode und persistiert ab diesem Zeitpunkt keine Messdaten mehr.
    8. Wenn die Mindestbelegung nicht unterschritten wird, bleibt das Datenspeicherverhalten unverändert.

UC-09: Raspberry Pi registrieren und Raum zuordnen

  • Akteur: Systemadministrator
  • Vorbedingung: Nutzer:in ist als Systemadministrator eingeloggt. Die Gebäudestruktur (Gebäude, Abteilungen, Räume) ist bereits im System angelegt. Der physische Raspberry Pi ist aufgestellt und hat eine SD-Karte.
  • Normalablauf:
    1. Der Systemadministrator öffnet die Geräteverwaltung in der Webapp und wählt „Neuen Raspberry Pi registrieren".
    2. Das Backend speichert die vom User definierten Infos in einem neuen RaspberryPiDTO und setzt den Status auf OFFLINE.
    3. Das Backend bereitet dem Systemadmin eine config.yaml-Datei vor, die alle relevanten Setup-Infos für den Raspberry Pi enthält, und ermöglicht deren Download.
    4. Der Systemadministrator kopiert die config.yaml auf die SD-Karte des RPI.
    5. Der RPI updated seine Infos mit Hilfe der Infos aus der config.yaml.
    6. Der RPI sendet eine POST /api/cpi/{piId}/booted-Request an das Backend, dessen URL er auch aus der config.yaml entnimmt.
    7. Das Backend lernt durch diese Request die IP des RPI kennen und updated das RPI-Objekt.
    8. Der Systemadministrator klickt den check for connection-Button neben dem RPI, der ihm auf der Benutzeroberfläche angezeigt wird, und das RPI erscheint als connected.
  • Alternativablauf – Raum bereits belegt:
    1. Versucht der Systemadministrator, einen Raum zuzuordnen, dem bereits ein aktiver Raspberry Pi zugewiesen ist, zeigt das System eine Fehlermeldung: „Diesem Raum ist bereits ein Raspberry Pi zugeordnet."
    2. Der Systemadministrator kann den bestehenden Raspberry Pi zuerst aus dem Raum entfernen oder einen anderen Raum auswählen.
  • Alternativablauf – Raspberry Pi bleibt offline:
    1. Falls der Raspberry Pi nach der Registrierung keinen Kontakt mit dem Backend aufnimmt (z. B. Netzwerkproblem, falsche IP, conf.yaml noch nicht aktualisiert), bleibt der Status auf OFFLINE.
    2. Der Systemadministrator sieht den Status in der Geräteverwaltung und kann die Konfiguration prüfen.

UC-10: Sensorstation registrieren und Raspberry Pi zuordnen

  • Akteur: Systemadministrator
  • Vorbedingung:
    Die Nutzerin bzw. der Nutzer ist als Systemadministrator eingeloggt. Der Ziel-Raspberry-Pi ist bereits registriert, einem Raum zugeordnet und hat den Status ONLINE oder OFFLINE. Der physische Arduino ist mit Strom versorgt und sendet BLE-Advertising-Pakete.

Normalablauf

  1. Der Systemadministrator öffnet die Geräteverwaltung und wählt „Neue Sensorstation registrieren“ aus.
  2. Das Frontend sendet eine POST-Request an /api/sensorstation/find an das Backend. Das Backend leitet die Anfrage über eine POST-Request an /api/spi/{piId}/scan an den Raspberry-Pi weiter.
  3. Der Raspberry-Pi scannt per BLE nach möglichen Verbindungspartnern, die den deviceSetupService advertisen.
  4. Alle Sensorstationen besitzen initial denselben Namen, denselben advertised Service und dieselben Herstellerinformationen. Sie unterscheiden sich zunächst nur durch ihre Bluetooth-Adressen, die beim erstmaligen Setup als Identifikator dienen.
  5. Die Sensorstationen zeigen ihre Bluetooth-Adressen auf dem Display an. Gleichzeitig sendet der Raspberry-Pi eine POST-Request an /api/cpi/{piId}/discovered an das Backend. Diese enthält die BLE-MAC-Adressen aller potenziellen Verbindungspartner.
  6. Das Backend erstellt temporäre Sensorstation-Objekte mit dem Status AVAILABLE und weist diese dem aktuellen Raspberry-Pi zu.
  7. Der Systemadministrator klickt auf den Button „Check for available sensor stations“. Dadurch wird eine GET-Request an /api/bpi/{id}/availablesensorstations ausgelöst. Die Antwort enthält alle verfügbaren Sensorstationen.
  8. Der Systemadministrator wählt aus, mit welcher Station er sich verbinden möchte, und füllt alle relevanten Daten aus.
  9. Der Systemadministrator klickt auf den Button „Verbinden“. Dadurch wird eine POST-Request an /api/sensorstation mit einem SensorStationCreateDTO ausgelöst.
  10. Das Backend empfängt diese Request, erstellt die Sensorstation dauerhaft und löst anschließend eine POST-Request an /api/spi/{piId}/stations aus.
  11. Der Raspberry-Pi baut nun eine BLE-Verbindung zu der durch das SensorStationDTO spezifizierten Sensorstation auf.
  12. Im Zuge der Erstverbindung beschreibt der Raspberry-Pi die Characteristic deviceSetupCharacteristic mit seiner Identität als TrustedRpiId und dem MeasurementInterval. Diese Informationen werden persistent auf der Sensorstation gespeichert und dienen weiterhin der Ausfallsicherheit und Authentifizierung.
  13. Die Sensorstation rebootet und beginnt anschließend, den environmentalSensingService zu advertisen.
  14. Der Raspberry-Pi verbindet sich erneut mit der Sensorstation und schreibt seine eigene ID sowie den Raumnamen in die warningAuthCharacteristic.
  15. Die Sensorstation überprüft, ob die ID mit der gespeicherten TrustedRpiId übereinstimmt, und authentifiziert die Verbindung für den Datenaustausch.
  16. Der Raspberry-Pi abonniert die sensorDataCharacteristic und sendet nach dem ersten empfangenen Datenpaket eine PATCH-Request an /api/cpi/{piId}/{sensorStationId}, um den Status der Sensorstation auf CONNECTED zu aktualisieren.
  17. Der Systemadministrator klickt auf „Check connection“. Dadurch wird eine GET-Request an /api/bpi/{id} ausgelöst, die alle Sensorstationen zurückgibt, die mit dem aktuellen Raspberry-Pi verbunden sind.
  18. Der Systemadministrator sieht bei der soeben registrierten Sensorstation den Status CONNECTED.

Alternativablauf – Sensorstation sendet kein Advertising

  1. Falls der Raspberry-Pi nach dem Start des Registrierungsvorgangs kein passendes BLE-Advertising-Paket empfängt, beispielsweise weil der Arduino nicht eingeschaltet ist oder sich außerhalb der Reichweite befindet, scannt der Raspberry-Pi für einen begrenzten Zeitraum weiter.
  2. Wird auch nach längerem Scannen keine Sensorstation gefunden, protokolliert der Raspberry-Pi einen WARN-Eintrag.
  3. Sobald das Problem behoben ist, kann der Scanvorgang erneut gestartet werden, damit die neue Sensorstation wie vorgesehen eingebunden werden kann.

Alternativablauf – Sensorstation bereits an einen anderen Raspberry-Pi gebunden

  1. Erkennt der Raspberry-Pi beim Scan eine Sensorstation, deren advertised Service UUID nicht der erwarteten UUID entspricht, ignoriert er diese Sensorstation.
  2. Soll die Sensorstation einem anderen Raspberry-Pi zugeordnet werden, muss entweder die Firmware neu geflasht oder ein Reset ausgelöst werden, indem alle drei Knöpfe gleichzeitig gedrückt werden. Dadurch werden TrustedRpiId und MeasurementInterval zurückgesetzt.

Alternativablauf – Verbindung zur Sensorstation schlägt fehl

  1. Falls der Raspberry-Pi keine BLE-Verbindung zur ausgewählten Sensorstation aufbauen kann, sendet er eine PATCH-Request an das Backend via /api/cpi/{piId}/{sensorStationId} .
  2. Dabei wird der Status der Sensorstation auf CONNECTION_FAILED gesetzt.
  3. Das Frontend kann diesen Status beim nächsten Abruf über /api/bpi/{id} anzeigen.

Alternativablauf – Schreiben der Setup-Daten schlägt fehl

  1. Falls die BLE-Verbindung erfolgreich aufgebaut wurde, das Schreiben der Setup-Daten in die deviceSetupCharacteristic jedoch fehlschlägt, trennt der Raspberry-Pi die Verbindung zur Sensorstation.
  2. Anschließend sendet der Raspberry-Pi eine PATCH-Request an /api/cpi/{piId}/{sensorStationId}.
  3. Dabei wird der Status der Sensorstation auf CONNECTION_FAILED gesetzt.
  4. Das Frontend kann diesen Status beim nächsten Abruf über /api/bpi/{id} anzeigen.

Designentscheidung

Da alle Sensorstationen mit demselben Firmware-Stand betrieben werden, entfällt das individuelle Flashen pro Gerät. Die Exklusivität der BLE-Verbindung wird stattdessen über die Characteristic deviceSetupCharacteristic sichergestellt. Diese wird beim ersten erfolgreichen Verbindungsaufbau durch den Raspberry-Pi mit TrustedRpiId und MeasurementInterval beschrieben und anschließend persistent auf dem Arduino gespeichert.

Dadurch wird verhindert, dass sich fremde Raspberry-Pis, beispielsweise aus anderen Teams oder Testumgebungen, versehentlich mit einer bereits zugeordneten Sensorstation verbinden. Gleichzeitig werden ungewollte Reconnects oder fehlerhafte Neu-Zuordnungen nach einem Neustart vermieden.


3. Klassendiagramm

Klassendiagramm – fachliches Modell der Webapp-Backend-Daten

Das vollständige Klassendiagramm befindet sich als PNG im Projekt Repo (Datei: docs/images/climate-canary-webapp-backend.png).

Klassenbeschreibungen

  • ViolationStatus – Enum: ACTIVE, RESOLVED, DISABLED
  • UserxRole – Enum: SYSTEM_ADMIN, BUILDING_ADMIN, DEPARTMENT_LEAD, MANAGEMENT, EMPLOYEE
  • AbsenceType – Enum: HOLIDAY, SICKNESS, PARENTAL_LEAVE, OTHER
  • AbsenceStatus – Enum: PLANNED, APPROVED, REJECTED, CANCELLED
  • RoomType – Enum: OFFICE, COMMON_AREAS
  • DeviceStatus – Enum: ONLINE, OFFLINE, MAINTENANCE, DEGRADED, DECOMMISSIONED, AVAILABLE, CONNECTED, CONNECTION_FAILED
  • Metric – Enum: TEMPERATURE, HUMIDITY, PRESSURE, IAQ
  • ThresholdType – Enum: LOWER, UPPER
  • Userx – Repräsentiert einen Systembenutzer.
    Attribute: id: Long, username: String, password: String, firstName: String, lastName: String, email: String, phone: String, roles: Set<UserxRole>, enabled: boolean, createDate: LocalDateTime, updateDate: LocalDateTime
    Assoziationen: hat mehrere Abwesenheiten, kann genau ein EmployeeProfile besitzen und kann als Department Lead einer oder mehreren Abteilungen zugeordnet sein. Zusätzlich kann ein User als createUser oder updateUser andere Userx-Objekte referenzieren.
  • EmployeeProfile – Repräsentiert das Mitarbeiterprofil eines Users.
    Attribute: id: Long
    Assoziationen: referenziert genau einen Userx, eine Department und einen Room.
  • Absence – Repräsentiert eine Abwesenheit eines Users.
    Attribute: id: Long, startDate: LocalDateTime, endDate: LocalDateTime, absenceType: AbsenceType, absenceStatus: AbsenceStatus
    Assoziationen: referenziert genau einen Userx.
  • Building – Repräsentiert ein Gebäude.
    Attribute: id: Long, name: String
    Assoziationen: hat genau eine Address und kann mehrere Rooms besitzen.
  • Address – Repräsentiert eine Adresse.
    Attribute: id: Long, country: String, zipCode: String, city: String, street: String, houseNumber: String, extra: String
  • Department – Repräsentiert eine Abteilung.
    Attribute: id: Long, name: String
    Assoziationen: kann von einem Userx geleitet werden und wird von mehreren EmployeeProfiles und Räumen referenziert.
  • Room – Repräsentiert einen Raum.
    Attribute: id: Long, name: String, roomType: RoomType, privacyMode: Boolean, active: boolean
    privacyMode definiert, ob Messwerte gespeichert werden dürfen.
    Assoziationen: gehört zu einer Department und einem Building, kann maximal einen Raspberry Pi haben und wird von EmployeeProfiles, SensorStations, Measurements, Thresholds und ThresholdViolations referenziert.
  • RaspberryPi – Repräsentiert einen Raspberry Pi.
    Attribute: id: Long, hostName: String, ipAddress: String, deviceStatus: DeviceStatus
    Assoziationen: ist genau einem Room zugeordnet und verwaltet mehrere SensorStations.
  • SensorStation – Repräsentiert eine Sensorstation.
    Attribute: id: Long, name: String, deviceStatus: DeviceStatus, measurementInterval: Integer, bleMac: String
    Assoziationen: gehört zu genau einem RaspberryPi, ist genau einem Room zugeordnet und wird von Measurements referenziert.
  • Measurement – Repräsentiert einen einzelnen Messdatenpunkt.
    Attribute: id: Long, timestamp: LocalDateTime, measurement: Float, metric: Metric
    Assoziationen: gehört zu genau einer SensorStation, ist genau einem Room zugeordnet und kann von einer oder mehreren ThresholdViolations referenziert werden.
    Wird nur bei erfüllter Datenschutzbedingung persistent gespeichert.
  • Threshold – Repräsentiert Grenzwerte für einen Raum pro Messgröße.
    Attribute: id: Long, metric: Metric, enabled: boolean, boundValue: Float, thresholdType: ThresholdType
    Assoziationen: gehört zu genau einem Room, kann von mehreren ThresholdViolations referenziert werden und kann mit einem oder mehreren ClimateHints verknüpft sein.
  • ThresholdViolation – Repräsentiert eine aktive oder historische Grenzwertverletzung.
    Attribute: id: Long, metric: Metric, value: Float, violationStatus: ViolationStatus, startTime: LocalDateTime, endTime: LocalDateTime
    endTime ist null, solange die Verletzung aktiv ist.
    Assoziationen: referenziert genau einen Room, genau einen Threshold und eine oder mehrere Measurements.
    Designentscheidung: Mehrere Measurements müssen herangezogen werden, um kurze Extremwerte zu filtern. Eine Verletzung wird erst bestätigt, wenn 5 Minuten lang die Messungen den Grenzwert überschreiten.
  • ClimateHint – Repräsentiert einen Raumklima-Tipp.
    Attribute: id: Long, metric: Metric, hintText: String
    Wird bei Grenzwertverletzungen auf dem LCD-Display der Sensorstation und in der Webapp angezeigt.
    Assoziationen: wird von einem oder mehreren Thresholds referenziert.

Wichtige Assoziationen

  • Userx 1 -- * Absence: Ein User kann mehrere Abwesenheiten haben.
  • Userx 1 -- 0..1 EmployeeProfile: Ein User kann genau ein EmployeeProfile besitzen.
  • Department 1 -- * EmployeeProfile: Eine Abteilung hat mehrere EmployeeProfiles.
  • Room 1 -- * EmployeeProfile: Ein Raum kann mehreren EmployeeProfiles zugeordnet sein.
  • Department 1 -- * Room: Eine Abteilung hat mehrere Räume.
  • Building 1 -- * Room: Ein Gebäude kann mehrere Räume besitzen.
  • Department * -- 0..1 Userx: Eine Abteilung kann genau einen Department Lead haben; ein User kann mehrere Departments leiten.
  • Room 1 -- 0..1 RaspberryPi: Ein Raum hat maximal einen Raspberry Pi.
  • RaspberryPi 1 -- * SensorStation: Ein Raspberry Pi kann mehrere SensorStations verwalten.
  • SensorStation 1 -- * Measurement: Eine SensorStation produziert viele Messdaten.
  • Room 1 -- * Measurement: Ein Raum hat viele Messdaten.
  • Room 1 -- * Threshold: Ein Raum hat Grenzwerte pro Messgröße.
  • Threshold 1 -- * ThresholdViolation: Ein Grenzwert kann mehrfach verletzt werden.
  • Room 1 -- * ThresholdViolation: Eine Grenzwertverletzung gehört zu genau einem Raum.
  • Measurement * -- * ThresholdViolation: Mehrere Measurements können eine Verletzung belegen.
  • Threshold * -- * ClimateHint: Grenzwerte können mit einem oder mehreren Hinweisen verknüpft sein.
  • Building 1 -- 1 Address: Ein Gebäude hat genau eine Adresse.

Löschen von Daten

  • Wird ein User gelöscht, werden seine Abwesenheiten ebenfalls gelöscht (CASCADE).
  • Wird eine Sensorstation gelöscht, bleiben ihre bereits persistent gespeicherten Messdaten erhalten – Messdaten gelten als raumhistorische Daten und sind von der Existenz der Sensorstation entkoppelt. Die roomId-Referenz in ThresholdViolation bleibt ebenfalls bestehen.
  • Wird ein Raum gelöscht, werden alle zugehörigen Messdaten, Grenzwerte und Grenzwertverletzungen gelöscht (CASCADE).
  • Wird ein Raspberry Pi aus einem Raum entfernt oder gelöscht, bleiben historische Messdaten und Grenzwertverletzungen erhalten (Referenz über roomId); der Raspberry-Pi-Eintrag bleibt im System, bis er explizit gelöscht wird.
  • Messdaten, die aufgrund der Datenschutzbedingung (Mindestbelegung unterschritten) nie persistent gespeichert wurden, existieren nicht persistent und müssen daher nicht gelöscht werden.

4. SW-Architektur

Teil Konzept V2, Deadline 19.03.2026, 12:00

In diesem Abschnitt wird die Laufzeitsicht des Systems dokumentiert, also die Abläufe und Beziehungen zwischen den einzelnen Komponenten zur Laufzeit. Neben den geforderten Mindestabläufen werden auch weitere relevante Abläufe modelliert, um zentrale Designentscheidungen und Kommunikationswege im System sichtbar zu machen.

Laufzeitsicht

Folgende Sequenzdiagramme werden in diesem Abschnitt dokumentiert:

  • Sequenzdiagramm – Allgemeiner Messzyklus (Overview)
  • Sequenzdiagramm – Grenzwertverletzung des gesamten Systems
  • Sequenzdiagramm – Belegungs-Mindestgrenze
  • Sequenzdiagramm – Verbindungsaufbau und -konfiguration zwischen Arduino, Raspberry Pi und Webapp

Sequenzdiagramm - Allgemeiner Messzyklus (Overview)

Das folgende Diagramm zeigt den typischen Ablauf eines Messzyklus im System – von der Messung auf der Sensorstation (Arduino) über die Verarbeitung am Raspberry Pi bis zur Speicherung im Backend und der Darstellung in der Webanwendung.

Der Ablauf umfasst:

  • periodische Messung von Temperatur, Luftfeuchtigkeit und Luftqualität
  • Übertragung der Messdaten via BLE an den Raspberry Pi
  • Grenzwertprüfung und lokale Verarbeitung
  • Übermittlung relevanter Daten an das Backend
  • Darstellung der Messwerte und Warnungen in der Webapp

Sequenzdiagramm – Allgemeiner Messzyklus

Sequenzdiagramm – Grenzwertverletzung des gesamten Systems

Das folgende Sequenzdiagramm zeigt, was passiert, wenn ein Klimawert in einem Büroraum einen festgelegten Grenzwert überschreitet – beispielsweise wenn die Temperatur zu hoch oder die Luftqualität zu schlecht wird. Es beschreibt den gesamten Ablauf: von der ersten Erkennung auf dem Raspberry Pi über die Meldung ans Backend bis hin zur Anzeige im Frontend und der Aufhebung der Warnung.

Der Ablauf gliedert sich in fünf Phasen:

  1. Konfiguration beim Start: Der Raspberry Pi lädt beim Hochfahren die konfigurierten Grenzwerte – also die erlaubten Ober- und Untergrenzen für jeden Messwert. Falls noch keine Werte in der lokalen Datenbank vorhanden sind, werden Standardwerte verwendet. Das Backend kann die Grenzwerte jederzeit aktualisieren.
  2. Laufender Messbetrieb: Die Sensorstation misst kontinuierlich Temperatur, Luftfeuchtigkeit, Luftdruck und Luftqualität (IAQ) und sendet die Daten per Funk (BLE) an den Raspberry Pi. Dieser speichert die Werte lokal und prüft regelmäßig, ob der Durchschnitt der letzten fünf Minuten einen Grenzwert verletzt. Gleichzeitig wird der aktuelle Zustand an die Sensorstation zurückgemeldet, sodass die LED-Anzeige stets den aktuellen Status widerspiegelt.
  3. Grenzwertverletzung erkannt: Wird eine Überschreitung festgestellt und liegt für diesen Messwert noch keine offene Warnung vor, wird ein Warnungseintrag erzeugt und ans Backend gemeldet. Zusätzlich sendet der Raspberry Pi einen Warnhinweis (ClimateHint) an die Sensorstation – diese zeigt den Text auf dem Display an und schaltet die LED auf Rot.
  4. Automatische Auflösung: Sobald der betroffene Messwert wieder dauerhaft im normalen Bereich liegt, wird die Warnung automatisch aufgehoben. Backend und Sensorstation werden informiert, die LED wechselt zurück auf Türkis.
  5. Manuelle Quittierung: Ein Benutzer kann eine aktive Warnung im Dashboard manuell quittieren. Das System informiert daraufhin den Raspberry Pi und die Sensorstation – die LED wechselt auf Dunkelrot/Violett als Bestätigung der Kenntnisnahme.

Sequenzdiagramm – Grenzwertverletzung des gesamten Systems

Sequenzdiagramm – Belegungs-Mindestgrenze

Das folgende Sequenzdiagramm beschreibt, was passiert, wenn in einem Büroraum zu wenige Personen anwesend sind, um Klimadaten datenschutzkonform zu erheben und zu speichern. Es zeigt den gesamten Ablauf – von der Erkennung der Unterschreitung über das eingeschränkte Systemverhalten bis zur Rückkehr in den normalen Betrieb.

Der Ablauf gliedert sich in vier Phasen:

  1. Start und Erstkonfiguration: Beim Hochfahren holt sich der Raspberry Pi die aktuelle Konfiguration vom Backend – darunter auch, ob der Datenschutzmodus aktiviert sein soll.
  2. Belegungsänderung: Wenn sich die Anwesenheit im Raum ändert – zum Beispiel durch das Eintragen einer Abwesenheit oder das Entfernen einer Person aus dem Raum – berechnet das Backend die aktuelle Belegung neu. Liegt diese unterhalb der festgelegten Mindestgrenze, wird der Raspberry Pi informiert und schaltet in den Datenschutzmodus.
  3. Betrieb im Datenschutzmodus: Solange zu wenige Personen anwesend sind, werden keine Messdaten gespeichert und nicht ans Backend weitergeleitet. Die Sensorstation misst und prüft dennoch weiterhin, ob Grenzwerte überschritten werden – bei einer Überschreitung wird lokal gewarnt (LED und Display), aber kein Ereignis ans Backend gemeldet. Das Dashboard zeigt für diesen Raum keine Daten an.
  4. Rückkehr in den Normalbetrieb: Sobald wieder genügend Personen im Raum sind, hebt das Backend den Datenschutzmodus auf und informiert den Raspberry Pi. Dieser speichert Messdaten wieder lokal und übermittelt sie ans Backend. Das Dashboard steht anschließend wieder zur Verfügung – die Zeit ohne Daten wird dabei als Lücke kenntlich gemacht.

Sequenzdiagramm – Belegungs-Mindestgrenze

Sequenzdiagramm - Raspberry Pi und Arduino Sensor Station Verbindungsaufbau und Konfiguration

Das folgende Sequenzdiagramm beschreibt den Ablauf, bei dem ein Systemadministrator einen Raspberry Pi und eine Sensorstation erstmals im System registriert und einen diese miteinander verbindet. Der genaue Ablauf wird außerdem in UC-10 beschrieben.

Sequenzdiagram - Setup PI & Arduino

5. API Dokumentation

  • Fehlerbehandlung - GlobalExceptionHandler: Zur zentralen Behandlung aller auftretenden Fehler wird im Projekt ein GlobalExceptionHandler eingesetzt. Dieser fängt sämtliche Exceptions ab und verarbeitet sie einheitlich. Die Fehler werden dabei in verschiedene Kategorien eingeteilt: NotFoundException (404), ConflictException (409) sowie Bad Request-Fehler (400), insbesondere IllegalArgumentException und IllegalStateException. Zusätzlich wird die AuthorizationDeniedException als Forbidden (403) behandelt. Darüber hinaus überwacht der GlobalExceptionHandler auch MethodArgumentNotValidException. Tritt eine Verletzung der Jakarta-Validation auf, wird eine strukturierte Map mit den entsprechenden Validierungsfehlern zurückgegeben. Für unvorhersehbare Fehler existiert außerdem eine generische Fallback-Exception, um auch nicht explizit behandelte Ausnahmen sauber abzufangen. Alle Exceptions basieren auf einem einheitlichen ApiErrorResponse-DTO, das Felder wie path, timestamp, error code und error message enthält. Diese Designentscheidung ermöglicht es, Fehler in größere Kategorien zu bündeln, wodurch das Exception-Handling übersichtlich und skalierbar bleibt, ohne eine Vielzahl einzelner Exception-Klassen pflegen zu müssen.
  • Role-Based Access Endpoints: Alle Basis-Endpunkte unter /api/** sind auf der ersten Ebene geschützt, d. h. ein Zugriff ist nur für authentifizierte Nutzer möglich. Darauf aufbauend erfolgt die Autorisierung rollenbasiert: Benutzer können ausschließlich auf die Endpunkte zugreifen, für die sie die entsprechenden Berechtigungen besitzen. Beispielsweise haben System-Administratoren vollständigen Zugriff auf alle Endpunkte sowie exklusiven Zugriff auf spezielle Admin-Endpunkte. User-Self-Endpunkte hingegen sind strikt auf den jeweils aktuell im AuthenticationContext authentifizierten Benutzer beschränkt, sodass Nutzer nur auf ihre eigenen Ressourcen zugreifen können. Die Zuordnung der erforderlichen Rollen zu einzelnen Endpunkten orientiert sich an den fachlichen Anforderungen und kann aus dem Use-Case-Diagramm abgeleitet werden.

Die vollständige Dokumentation aller REST-API-Schnittstellen, die im System verwendet werden, ist in der Wiki-Page REST-Spezifikation bzw. in der Datei REST-Spezifikation dokumentiert.

6. Lösungsansätze komplexe Abläufe

6.1 Datenschutz-Logik: Belegungsprüfung und Privacy Mode

Problem: Messdaten von Büroräumen dürfen nur persistent gespeichert und an das Backend weitergeleitet werden, wenn mindestens 5 Personen anwesend sind. Die Logik muss klar zwischen transienter Verarbeitung (immer erlaubt) und persistenter Speicherung (nur bei ausreichender Belegung) unterscheiden.

Belegungsberechnung (Backend)

Die aktuelle Belegung eines Raums wird vom Backend berechnet als:

aktuelle Belegung = Gesamtanzahl zugeordneter User
                  − Anzahl User mit aktiver Abwesenheit

Eine Abwesenheit gilt als aktiv, wenn absenceStatus = APPROVED und das aktuelle Datum im Intervall [startDate, endDate] liegt.

Fällt die berechnete Belegung unter den konfigurierten Schwellwert minOccupancy (Standard: 5 für RoomType.OFFICE), sendet das Backend eine Request an den RPI, um die Konfiguration zu aktualisieren (Daten werden dann nicht mehr persistent gespeichert).

Die Belegungsberechnung erfolgt ausschließlich im Backend als Single Source of Truth. Der Raspberry Pi führt keine eigene Belegungslogik durch – er reagiert ausschließlich auf die vom Backend kommunizierten Informationen. Das vermeidet Inkonsistenzen bei gleichzeitigen Abwesenheitsänderungen mehrerer User.

Kommunikation an den Raspberry Pi

Ändert sich die Belegungssituation eines Raums (d. h. privacyMode wechselt seinen Wert), wird der RPI per POST /api/spi/{piId}/occupancy vom Backend über die relevante Änderung informiert. Die globale Variable privacy_mode im RP wird entsprechend gesetzt.

Da ein Raspberry Pi einem konkreten Raum zugeordnet ist und mehrere Sensorstationen verwalten kann, werden Änderungen an der Persistierung der Messwerte auf alle eingehenden Sensordaten des jeweiligen Raums angewendet. Es werden also entweder alle oder keine Daten persistiert.

Privacy Mode

Wechselt ein Raum in den Zustand aktuelle Belegung < 5, wird der Privacy Mode im RPI durch einen POST aktiviert. Dann gilt Folgendes für alle Sensorstationen dieses Raums:

  • Messdaten werden weiterhin von den Sensorstationen empfangen und transient im Arbeitsspeicher gehalten.
  • Es werden keine Messdaten in SQLite geschrieben.
  • Es werden keine Messdaten an das Backend übermittelt.
  • Grenzwertprüfungen sowie lokale LED- und Display-Warnungen an der Sensorstation laufen unverändert weiter – der Datenschutz betrifft ausschließlich die Persistierung, nicht die Echtzeitanzeige vor Ort.

Kehrt die Belegung über den Schwellwert zurück, verlässt der Raspberry Pi den Privacy Mode und nimmt die normale Speicher- und Übertragungslogik wieder auf.

Sonderfall: Allgemeinflächen

Für Räume vom Typ RoomType.COMMON_AREA gilt der Privacy Mode nie. Allgemeinflächen (Konferenzräume, Aufenthaltsräume etc.) werden unabhängig von ihrer Belegung immer gespeichert und weitergeleitet.


6.2 Messdaten-Upload und Deduplizierung

Problem: Wenn der Raspberry Pi nach einem Backend-Ausfall gepufferte Messdaten nachträglich überträgt, könnten Duplikate entstehen (z. B. wenn eine Übertragung halb ankam und wiederholt wird).

Lösungsansatz:

  • Jeder Measurement-Datensatz erhält einen timestamp, den der Raspberry Pi bereits beim Schreiben in SQLite vergibt – nicht erst das Backend.
  • Beim Upload prüft das Backend die eingehende Kombination aus timestamp, Sensorstation und Metrik gegen die PostgreSQL-Datenbank. Bereits vorhandene Kombinationen werden mit HTTP 200 OK (idempotent) quittiert, aber nicht doppelt gespeichert.
  • Jeder Eintrag in der SQLite-Tabelle sensor_data besitzt ein sent-Flag (0 = noch nicht übertragen, 1 = erfolgreich übertragen). Der Raspberry Pi überträgt gepufferte Daten nach Wiederherstellung chronologisch (älteste zuerst) in Batches von maximal 50 Einträgen pro Zyklus. Übertragen werden die Einträge einzeln. Bei einer erfolgreichen Antwort (2xx) wird das Flag auf sent=1 gesetzt und der Eintrag anschließend gelöscht. Bleibt die Übertragung erfolglos, verbleibt der Eintrag mit sent=0 und wird im nächsten Zyklus erneut versucht – es gehen somit keine Daten verloren.

Designentscheidung: Der Timestamp wird bereits am Raspberry Pi beim Erfassen bzw. Puffern der Messung vergeben. Dadurch bleibt derselbe Messdatensatz auch bei wiederholten Upload-Versuchen eindeutig wiedererkennbar, ohne dass das Backend nachträglich eine eigene ID erzeugen muss.

6.3 LED- und Display-Logik an der Sensorstation (Arduino)

Problem: Das Arduino-Display und die RGB-LED müssen den aktuellen Systemzustand korrekt widerspiegeln, auch wenn keine BLE-Verbindung besteht oder eine Grenzwertwarnung vom User quittiert wurde.

Zustandsautomat

Der Arduino hält intern einen einfachen Zustandsautomaten. Die Zustandswechsel werden hauptsächlich vom Raspberry Pi per BLE GATT Write ausgelöst; lokal reagiert der Arduino zusätzlich auf BLE-Verbindungsereignisse und Button-Eingaben.

Logischer Zustand Arduino-State im Code LED Display
NORMAL CONNECTED_ALL_VALID_DATA Türkis, dauerhaft Raumname + aktuelle Messwerte; Alternativansicht: „NO ACTIVE WARNINGS!“
INTERMEDIATE CONNECTED_SOME_SHORT_INVALID_DATA Orange/Koralle, dauerhaft Raumname + aktuelle Messwerte; betroffene Werte werden hervorgehoben
WARNING CONNECTED_ACTIVE_WARNING Rot, schnell blinkend Warnmeldung(en) + ClimateHint-/Warntext; während Übertragung: „RECEIVING MESSAGES...“
WARNING_ACKNOWLEDGED ACTIVE_WARNING_ACKNOWLEDGED Dunkelrot/Violett, dauerhaft Quittierte Warnmeldung(en); User kann weiter durch die Texte blättern
BLE_DISCONNECTED WAITING_FOR_KNOWN_CONNECTION Amber/Gelb, blinkend „DISCONNECTED“ + Verbindungsstatus; Alternativansicht zeigt weiterhin Rohmesswerte

Zusätzlich gibt es technische Zwischenzustände:

Arduino-State Bedeutung LED
WAITING_FOR_AUTHENTICATION BLE verbunden, aber Raspberry Pi noch nicht authentifiziert Aqua/Grün, schnell blinkend
WAITING_FOR_NEW_CONNECTION Ersteinrichtung/Pairing-Modus Magenta blinkend

Im Zustand BLE_DISCONNECTED misst der Arduino weiter und speichert Messwerte in einem lokalen Ringbuffer für die spätere Übertragung. Eine Grenzwertprüfung findet dort nicht statt, da diese Logik ausschließlich am Raspberry Pi liegt. Beim Verbindungsabbruch setzt der aktuelle Code statusCode und warningStatus lokal zurück; bereits empfangene Warntexte bleiben zwar im RAM, werden aber nicht als aktiver Warnzustand weitergeführt.

Quittierung von Warnmeldungen

Ein User kann eine aktive Grenzwertwarnung sowohl im Frontend der Webapp als auch direkt an der Sensorstation quittieren:

  • Quittierung im Frontend: Das Backend aktualisiert den Warnstatus und informiert den zuständigen Raspberry Pi. Dieser schreibt die Quittierung per BLE auf die warningAcknowledgedCharacteristic. Der Arduino wechselt bei vollständig empfangener Warnung in ACTIVE_WARNING_ACKNOWLEDGED.
  • Quittierung an der Sensorstation: Der User blättert mit den Buttons durch die empfangenen Warntexte. Nach dem letzten Warntext setzt der Arduino warningStatus = 3, wechselt in ACTIVE_WARNING_ACKNOWLEDGED und schreibt die Quittierung ebenfalls auf die BLE-Characteristic zurück.

Ist die zugrundeliegende Grenzwertverletzung weiterhin aktiv, verbleibt der Arduino im quittierten Warnzustand, bis der Raspberry Pi neue Statusdaten übermittelt. Bei einer neuen Warnmeldung wird die bisherige Warnliste geleert und der Zustand wieder auf CONNECTED_ACTIVE_WARNING gesetzt.

ClimateHints

ClimateHint- bzw. Warntexte werden vom Raspberry Pi per BLE an den Arduino übertragen. Die Übertragung erfolgt paketweise über Länge und einzelne Zeichen-Chunks. Der Arduino puffert die empfangenen Texte in currentWarningMessages und zeigt sie im Warnzustand auf dem Display an.

Designentscheidung: Der Arduino ist ein reines Anzeige- und Eingabegerät für den Endnutzer. Die Grenzwertlogik liegt am Raspberry Pi; der Arduino verarbeitet nur BLE-Statuscodes, Warntexte, Button-Eingaben, LED-Farben und Display-Ausgabe. Dadurch bleibt der Arduino-Code vergleichsweise einfach und testbar.

6.4 Grenzwertverletzungen: Erkennung, Alerting und Deaktivierung

Problem: Grenzwertverletzungen müssen zuverlässig erkannt, ans Backend gemeldet und auch explizit aufgehoben werden können – sowohl automatisch (Wert normalisiert sich) als auch manuell (Grenzwert wird deaktiviert).

Erkennung und Noise-Filterung

Die Grenzwertprüfung erfolgt am Raspberry Pi. Der Arduino führt selbst keine Grenzwertprüfung durch, sondern erhält vom Raspberry Pi einen kompakten statusCode per BLE. Darin ist pro Metrik codiert, ob der Wert gültig ist oder kurzzeitig bzw. langfristig außerhalb des erlaubten Bereichs liegt.

Der Raspberry Pi berechnet für jede Metrik einen gleitenden Durchschnitt (Sliding Window) über die letzten 5 Minuten. Da das Messintervall der Sensorstationen zwischen mindestens 3 Sekunden (hardwareseitig limitiert) und maximal 60 Sekunden liegt, befinden sich im Fenster stets mindestens 5 Messwerte. Einzelne Ausreißer beeinflussen den Durchschnitt damit nur geringfügig.

Kurzzeitige Abweichungen - d.h. der gleitende Durchschnitt überschreitet kurz einen Grenzwert, kehrt aber rasch zurück - werden auf dem Arduino als CONNECTED_SOME_SHORT_INVALID_DATA dargestellt. Erst wenn der Durchschnitt über das gesamte 5-Minuten-Fenster hinweg außerhalb des erlaubten Bereichs verbleibt, gilt die Verletzung als bestätigt: Warntexte werden an den Arduino übertragen und der Zustand wechselt zu CONNECTED_ACTIVE_WARNING.

Alert-Propagierung ans Backend

Erkennt der Raspberry Pi eine bestätigte Grenzwertverletzung, sendet er einen Alert per REST ans Backend. Das Backend:

  • loggt den Alert mit Timestamp,
  • speichert die letzte aktive Verletzung pro Raum und Metrik explizit mit Timestamp,
  • markiert die Verletzung als aktiv (violationStatus = ACTIVE).

Um Alert-Flooding zu vermeiden, sendet der Raspberry Pi für eine bereits aktive Verletzung keinen erneuten Alert, solange der vorherige Alert weniger als 15 Minuten zurückliegt. Ist die Verletzung weiterhin aktiv und die 15-Minuten-Frist abgelaufen, kann ein neuer Alert bzw. Reminder gesendet werden.

Aufhebung einer Verletzung

Eine Grenzwertverletzung wird aufgehoben, wenn:

  • der Messwert in den Normalbereich zurückkehrt: Der Raspberry Pi erkennt dies und sendet eine Aufhebungs-Meldung per REST ans Backend. Zusätzlich übermittelt er dem Arduino wieder einen gültigen statusCode. Der Arduino setzt daraufhin die lokale Warnanzeige zurück und wechselt zu CONNECTED_ALL_VALID_DATA.
  • der Grenzwert manuell deaktiviert wird: Ein Hausverwalter kann einen Grenzwert im Frontend bearbeiten. Das Backend setzt den Grenzwert auf enabled = false und laufende ThresholdViolations dieses Grenzwerts auf violationStatus = DISABLED. Der Raspberry Pi erhält diese Änderung vom Backend und propagiert relevante Statusänderungen per BLE an die verbundenen Sensorstationen.

Der Arduino unterscheidet dabei nicht selbst zwischen RESOLVED und DISABLED. Er reagiert nur auf die vom Raspberry Pi gelieferten Statuscodes, Warntexte und Quittierungsinformationen.

6.5 Raum-Abteilungs-Zuordnung und strukturelle Änderungen

Problem: Räume können im laufenden Betrieb einer anderen Abteilung zugeordnet werden. Diese Änderung muss konsistent in allen betroffenen Ansichten und Zuordnungen reflektiert werden, ohne historische Daten zu verlieren.

Abteilungswechsel eines Raums

Wird ein Raum einer neuen Abteilung zugeordnet, aktualisiert das Backend die roomIds die im Department verwaltet werden. Die Referenz zum übergeordneten Gebäude (buildingId) bleibt dabei unverändert – ein Raumwechsel betrifft ausschließlich die Abteilungszugehörigkeit, nicht die physische Gebäudezuordnung.

Folgende Konsequenzen ergeben sich automatisch:

  • Die Raumlisten beider betroffener Abteilungen (alte und neue) werden aktualisiert.
  • User, die dem Raum fix zugeordnet sind, bleiben dem Raum zugeordnet; ihre Abteilungszugehörigkeit wird jedoch nicht automatisch geändert – das erfordert einen separaten administrativen Schritt.
  • Historische Messdaten des Raums bleiben erhalten und sind weiterhin über die Raumreferenz abrufbar, unabhängig von der aktuellen Abteilungszugehörigkeit.
  • Aktive Grenzwertkonfigurationen und laufende Alerts des Raums bleiben bestehen.

Designentscheidung: Räume sind das zentrale Datenobjekt im System – Messdaten, Grenzwerte und Alerts sind stets an einen Raum, nicht an eine Abteilung gebunden. Abteilungen dienen primär der organisatorischen Gruppierung und Zugriffskontrolle. Ein Abteilungswechsel eines Raums ist daher eine reine Metadaten-Änderung ohne Auswirkung auf die Messkontinuität.


6.6 Heartbeat und Gerätestatus-Monitoring

Problem: Das System muss zu jeder Zeit wissen, ob Raspberry Pis und die ihnen zugeordneten Sensorstationen erreichbar und funktionsfähig sind. Ausfälle sollen zeitnah erkannt und im Frontend sowie an den Sensorstationen sichtbar gemacht werden.

Heartbeat-Mechanismus

Das Backend spricht den Raspberry Pi regelmäßig über einen dedizierten Heartbeat-Endpunkt (/api/spi/{piId}/heartbeat GET) an. Der Raspberry Pi antwortet mit einem strukturierten Status-Objekt, das folgende Informationen enthält:

  • Eigener Gerätestatus (ONLINE / DEGRADED / OFFLINE / MAINTENANCE)
  • Für jede zugeordnete Sensorstation: BLE-Verbindungsstatus (AVAILABLE / CONNECTED / CONNECTION_FAILED), letzte empfangene Messung mit Timestamp, aktiver Warnzustand
  • Systeminformationen (z. B. freier Speicher, SQLite-Puffergröße) – Details werden in der Implementierungsphase festgelegt

Das Backend wertet die Heartbeat-Antwort aus, aktualisiert die deviceStatus-Felder der betroffenen Geräte in PostgreSQL und stellt die Statusinformationen im Frontend bereit.

Bleibt eine Heartbeat-Antwort aus (Timeout), setzt das Backend den deviceStatus des Raspberry Pi auf OFFLINE und alle ihm zugeordneten Sensorstationen ebenfalls auf OFFLINE.

Propagierung an die Sensorstationen

Statusänderungen (wie aktualisierte Warnzustände, Quittierungen oder neue Warntexte) werden vom Raspberry Pi per BLE GATT Write an verbundene Sensorstationen übertragen. Dies setzt eine aktive BLE-Verbindung voraus.

Ein Verlust der BLE-Verbindung wird jedoch nicht aktiv an den Arduino propagiert, da in diesem Fall keine BLE-Kommunikation mehr möglich ist. Stattdessen erkennt der Arduino den Verbindungsabbruch eigenständig über das lokale BLE-Disconnect-Event und wechselt selbstständig in den Zustand WAITING_FOR_KNOWN_CONNECTION bzw. BLE_DISCONNECTED. Dabei zeigt er den Verbindungsverlust auf Display und LED an und misst lokal weiter.

Der Raspberry Pi meldet seinerseits den veränderten BLE-Verbindungsstatus der betroffenen Sensorstation im nächsten Heartbeat ans Backend. Das Backend aktualisiert daraufhin den Geräte- und Sensorstationsstatus in PostgreSQL, der anschließend im Frontend sichtbar wird.

Anzeige im Frontend

Der Verbindungs- und Warnstatus aller Geräte ist im Frontend für berechtigte Rollen (Systemadministrator, Gebäudeadministrator) in der Geräteverwaltung einsehbar. Nutzer:innen sehen im Kontext ihres eigenen Raums, ob die Sensorstation aktuell verbunden ist.


6.7 ID-Vergabe und Erstkonfiguration

Problem: Raspberry Pis und Sensorstationen müssen sowohl im Backend als auch auf den physischen Geräten eindeutig identifizierbar sein. Die ID-Vergabe und die initiale Konfiguration müssen daher einen klaren und möglichst fehlerarmen Ablauf definieren. Außerdem muss sichergestellt werden, dass nur zuvor im System registrierte Geräte mit dem Backend kommunizieren bzw. dauerhaft einem Raspberry Pi zugeordnet werden können.

ID-Format

  • Raspberry Pi IDs werden vom Backend eindeutig generiert und einem konkreten Raum zugeordnet.
  • Sensorstation IDs werden bereits während des Scan-Prozesses temporär im Backend erzeugt. Vom Raspberry Pi gefundene Sensorstationen werden nach dem Scan vorläufig der jeweiligen Raspberry-Pi-Instanz zugeordnet und erhalten eigene IDs. Wird keine Verbindung gestartet, läuft ein definierter Timeout ab oder wird ein neuer Scan gestartet, werden diese temporären Sensorstation-Einträge wieder gelöscht.
  • Die dauerhafte Bindung zwischen Raspberry Pi und Sensorstation entsteht erst nach erfolgreicher Auswahl und Verbindungsherstellung im Registrierungsprozess. Die Assoziation zwischen BLE-Adresse und System-ID erfolgt dabei per POST /sensorstation bei der Erstaufsetzung. Der Arduino selbst speichert seine eigene System-ID nicht, sie dient ausschließlich der sauberen Speicherung im Backend und wird der BLE-Adresse sowie dem Anzeige-Namen des Geräts zugeordnet. Am Arduino-Display wird die BLE-Adresse angezeigt, sodass eine eindeutige physische Zuordnung im Feld möglich ist.
  • Der Arduino speichert ausschließlich die TrustedRpiId (4 Bytes, persistent) sowie das MeasurementInterval. Diese werden beim ersten erfolgreichen Verbindungsaufbau durch den Raspberry Pi beschrieben. Muss ein Arduino mit einem neuen Raspberry Pi verbunden werden, ist ein Hardware-Reset des Arduino erforderlich (alle 3 Tasten gleichzeitig), wodurch die gespeicherte TrustedRpiId zurückgesetzt wird.

Erstkonfiguration Raspberry Pi

Die Erstkonfiguration eines Raspberry Pi erfolgt, nachdem der Systemadministrator ihn in der Webapp registriert und einem Raum zugeordnet hat. Dabei legt das Backend bereits ein Raspberry-Pi-Objekt an, setzt den deviceStatus zunächst auf OFFLINE und stellt eine config.yaml mit den benötigten Konfigurationsdaten bereit.

Der Systemadministrator kopiert diese config.yaml auf die SD-Karte des Raspberry Pi. Die darin enthaltenen Parameter werden beim Start als globale Variablen eingelesen und im Arbeitsspeicher gehalten, eine persistente Speicherung auf dem Gerät selbst findet nicht statt. Nach dem Start liest der Raspberry Pi die Konfigurationsdatei ein und sendet anschließend eine POST /api/cpi/{piId}/booted-Request an das Backend. Erst durch diese Anfrage lernt das Backend die aktuelle IP-Adresse des Geräts kennen und kann den registrierten Raspberry Pi als erreichbar behandeln. Sobald die Verbindung erfolgreich geprüft wurde, kann der Raspberry Pi im System als ONLINE geführt werden.

Das Backend akzeptiert dabei nur Anfragen von Raspberry Pis, die zuvor im System registriert wurden und sich mit einem bekannten piId melden.

Folgende Informationen müssen vor dem ersten Start auf dem Raspberry Pi verfügbar sein:

ROOM_ID: "<Backend-ID des vom User ausgewählten Raums>"
ROOM_NAME: "<Name des vom User ausgewählten Raums>"
BACKEND_URL: "http://<IP-Adresse>:<Port>"
PI_ID: "<Eigene Backend-ID des Raspberry Pi>"
HOST_NAME: "<Vom User definierter Name des Raspberry Pi>"
PRIVACY_MODE: "<Vom Backend generierter Privacy-Mode-Status für den gewählten Raum>"

Erstkonfiguration Sensorstation (Arduino)

Sensorstationen werden mit identischem Firmware-Stand betrieben und benötigen vorab keine individuelle fachliche Konfiguration. Für das erstmalige Setup senden alle Sensorstationen denselben Namen, denselben advertised Service und dieselben Manufacturer Data. Sie unterscheiden sich in diesem Zustand nur über ihre Bluetooth-Adresse, die während des Registrierungsprozesses als temporärer Identifikator dient.

Die Erstkonfiguration erfolgt im Rahmen des Registrierungsablaufs durch den Systemadministrator:

  1. Der Raspberry Pi scannt auf Anforderung des Backends per BLE nach verfügbaren Sensorstationen.
  2. Die gefundenen Geräte werden anhand ihrer Bluetooth-Adressen an das Backend gemeldet, dort temporär dem Raspberry Pi zugeordnet und mit dem Status AVAILABLE angelegt.
  3. Der Systemadministrator wählt im Frontend die gewünschte Sensorstation aus.
  4. Der Raspberry Pi baut eine BLE-Verbindung zur ausgewählten Sensorstation auf.
  5. Im Zuge dieser Erstverbindung schreibt der Raspberry Pi seine eigene Identität in die Characteristic TrustedRpiId sowie das konfigurierte MeasurementInterval auf den Arduino.
  6. Die Sensorstation führt anschließend einen Reboot durch. Dabei wechselt sie vollständig ihren BLE-Auftritt: Name, Manufacturer Data und advertised Service UUID werden auf die Normalbetrieb-Werte umgestellt.
  7. Nach dem Reboot advertised die Sensorstation mit aktualisierten BLE-Daten, neuem Namen, neuer Vendor-Data sowie angepasstem Service und Characteristic. Der Raspberry Pi verbindet sich weiterhin anhand der bekannten Bluetooth-Adresse.
  8. Zur Authentifizierung schreibt der Raspberry Pi die TrustedRpiId erneut auf die Sensorstation. Erst danach gilt die Verbindung als autorisiert.
  9. Sobald der Raspberry Pi die ersten Sensordaten von der Sensorstation empfangen hat, aktualisiert er den Status der Sensorstation im Backend auf CONNECTED.

Designentscheidung: Gefundene Sensorstationen werden bereits während des Scan-Prozesses als temporäre Objekte im Backend angelegt und dem suchenden Raspberry Pi mit Status AVAILABLE zugeordnet. Dadurch kann der Registrierungsprozess im Frontend mit konkreten Backend-Objekten arbeiten. Nicht ausgewählte oder nicht erfolgreich verbundene Sensorstationen werden nach Timeout oder bei einem neuen Scan wieder gelöscht. Erst nach erfolgreicher Verbindung, Authentifizierung über TrustedRpiId und Empfang erster Sensordaten gilt eine Sensorstation als vollständig registriert und wird dauerhaft mit dem Raspberry Pi verknüpft.

7. Ausfallssicherheit

Dieser Abschnitt beschreibt typische Ausfallszenarien des Systems sowie die Maßnahmen zur Sicherstellung von Datenkonsistenz, Wiederherstellung und Benutzerinformation.

Szenario 1 – Ausfall der Sensorstation

Aspekt Beschreibung
Datenkonsistenz Der Raspberry Pi erkennt den Ausfall über einen BLE-Verbindungs-Timeout. Da keine neuen Messdaten eintreffen, werden keine fehlerhaften oder unvollständigen Einträge in die SQLite-Datenbank geschrieben. Bereits gepufferte Daten bleiben erhalten.
Logging Der Raspberry Pi schreibt einen ERROR-Eintrag in sein lokales Logfile (sensor_offline, Sensor-ID, Timestamp). Die Wiederverbindung wird auf INFO-Level protokolliert.
Wiederaufnahme Sobald die Sensorstation wieder BLE-Advertising mit ihrer bekannten ID sendet, baut der Raspberry Pi automatisch die Verbindung wieder auf; kein manuelles Eingreifen ist notwendig.
Informationsaustausch Das Backend fragt den Status der Raspberry Pis sowie der angebundenen Sensorstationen regelmäßig über den Heartbeat Endpunkt (GET /api/rpi/{piId}/heartbeat) ab. Diese Abfrage erfolgt periodisch über einen Scheduler (z. B. mittels @Scheduled). Dabei werden auch Verbindungsinformationen einzelner Sensorstationen übermittelt. Das Backend verarbeitet die empfangenen Statusdaten und stellt sie dem Frontend zur Verfügung
User-Information Mitarbeiter:innen / Abteilungsleitung: Hinweis im Dashboard, dass die Sensorstation offline ist; Zeitlücke im Verlaufsdiagramm als „Daten nicht verfügbar“ markiert.
Systemadmins: Gerätestatus in der Verwaltungsansicht zeigt Ausfall; Logs einsehbar.
Gebäudeadmins: Keine direkten Geräteinformationen, aber fehlende Messdaten im Raumverlauf sichtbar.

Szenario 1 – Ausfall der Sensorstation

Szenario 2 – Eingeschränkte BLE-Kommunikation

Aspekt Beschreibung
Datenkonsistenz Die Sensorstation puffert Messwerte lokal im Arduino-Speicher, solange die BLE-Verbindung instabil ist. Dies erfolgt über einen Ringpuffer nach dem FIFO-Prinzip (First In – First Out).
Logging Verbindungsprobleme werden auf WARN-Level im Raspberry-Pi-Logfile festgehalten, inklusive Anzahl verworfener Pakete und Dauer der Instabilität. Sobald die Verbindung wieder stabil ist, wird dies auf INFO-Level geloggt.
Wiederaufnahme Nach Stabilisierung der BLE-Verbindung überträgt die Sensorstation die gepufferten Messwerte kumuliert. Der Raspberry Pi ergänzt Zeitstempel und verarbeitet die Daten regulär weiter. Dabei approximiert der Raspberry Pi fehlende Zeitstempel basierend auf dem Zeitstempel der letzten erfolgreichen Kommunikation mit der Sensorstation vor dem Verbindungsabbruch. Zusätzlich werden relative Zeitstempel aus den gepufferten Arduino-Daten berechnet, indem diese mit parallel empfangenen aktuellen Daten abgeglichen werden. Gepufferte Daten verfügen über einen ACK-Workflow und können mit aktuellen Daten interleaved verarbeitet werden. Die Zeitstempel werden in Mikrosekunden angegeben und können überlaufen (Overflow).
Informationsaustausch Während der Instabilität werden keine unvollständigen Daten an die Webapp weitergeleitet. Nach Wiederherstellung erfolgt die Übertragung der aufgelaufenen Daten über ein API-Endpoint.
User-Information Mitarbeiter:innen / Abteilungsleitung: Lücke im Verlaufsdiagramm als „Daten fehlen (Verbindungsproblem)“ markiert.
Systemadmins: Verbindungsstatus in der Geräteverwaltung sichtbar; WARN-Einträge in den Logs.

Szenario 2 – Eingeschränkte BLE-Kommunikation

Szenario 3 – Unerwarteter Neustart des Raspberry Pi

Aspekt Beschreibung
Datenkonsistenz Alle Datenbankoperationen in SQLite werden als ACID-konforme Transaktionen ausgeführt. Beim Start des Systems wird die Datenbank automatisch erstellt. Anschließend wird überprüft, ob die Struktur und Konfiguration korrekt sind.
Logging Der Neustart wird beim Start des Dienstes als WARN-Eintrag protokolliert. Der Webserver loggt den Reconnect auf INFO-Level.
Wiederaufnahme Beim Start führt der Raspberry Pi folgende Schritte aus:
1. Der Pi liest die IP des Webservers aus der zuletzt lokal zwischengespeicherten conf.yaml.
2. Anschließend wird eine GET-Request an das Backend gesendet, um die aktuelle Konfiguration abzurufen.
3. Danach erfolgt der Aufbau der BLE-Verbindungen zu den Sensorstationen.
Informationsaustausch Nach dem Reconnect sendet der Raspberry Pi einen initialen Config-Request an das Backend. Das Backend übermittelt dabei die vollständige conf.yaml. Im Frontend sieht der Systemadministrator in der Geräteverwaltung den Status aller Raspberry Pis. Betroffene Nutzer erhalten im Dashboard einen Hinweis in Form eines Banners mit der Meldung „Raspberry Pi nicht erreichbar“. Im Verlaufsdiagramm wird der Ausfall durch eine graue Lücke dargestellt.
User-Information Systemadmins / Gebäudeadmins: kurzer Ausfall in Logs und Gerätestatus sichtbar.
Alle Rollen: Datenlücke im Dashboard markiert.

Szenario 3 – Neustart des Raspberry Pi

Szenario 4 – Temporärer Ausfall: Raspberry Pi – Backend

Aspekt Beschreibung
Datenkonsistenz Der Raspberry Pi puffert alle Messdaten mit Timestamps in SQLite. Doppelte Übertragungen werden durch eine sent-Flag in der Raspberry-Pi-Datenbank verhindert, die nach erfolgreicher Übertragung gesetzt wird. Dadurch wird sichergestellt, dass jede Messung nur einmal erfolgreich an das Backend übertragen wird.
Logging Fehlgeschlagene Übertragungen werden auf ERROR-Level geloggt. Wiederherstellung der Verbindung wird auf INFO-Level festgehalten.
Wiederaufnahme Falls die Übertragung an das Backend fehlschlägt, versucht der Raspberry Pi erneut, alle Messungen mit sent = 0 zu übertragen. Dabei werden wie im Normalbetrieb maximal 50 Messungen gleichzeitig aus der Datenbank geladen und anschließend einzeln an das Backend gesendet.
Informationsaustausch Während des Backend-Ausfalls speichert der Raspberry Pi alle Messdaten lokal in der SQLite-Datenbank. Es erfolgt keine Datenweiterleitung an das Backend. Nach Wiederherstellung der Verbindung werden die zuvor nicht übertragenen Messungen automatisch nachträglich gesendet. Im Frontend wird der Ausfall im Verlaufsdiagramm durch eine graue Lücke dargestellt.
User-Information Mitarbeiter:innen / Abteilungsleitung: Hinweis auf fehlende Daten im Dashboard.
Systemadmins: Verbindungsstatus und Retry-Versuche in Logs sichtbar.

Szenario 4 – Ausfall Raspberry Pi und Backend

Szenario 5 – Kurzfristiger Ausfall des zentralen Backends

Aspekt Beschreibung
Datenkonsistenz Messdaten werden lokal in SQLite auf den Raspberry Pis gepuffert. Nach Wiederherstellung des Backends werden die gespeicherten Daten aus der lokalen Datenbank in die PostgreSQL-Datenbank übertragen. Dabei werden nur noch nicht übertragene Datensätze berücksichtigt, um doppelte Einträge zu vermeiden (sent Flag). Die Übertragung erfolgt in Batches und wird fortgesetzt, bis alle gepufferten Daten synchronisiert sind.
Logging Der Webserver loggt beim Hochfahren einen INFO-Eintrag.
Wiederaufnahme Nach dem Neustart authentifizieren sich die Raspberry Pis automatisch erneut und senden ihre gepufferten Daten.
Informationsaustausch Während des Ausfalls arbeiten Sensorstation und Raspberry Pi autonom weiter. Grenzwertprüfungen und lokale Warnungen funktionieren weiterhin.
User-Information Webapp-Nutzer: generische Fehlermeldung (HTTP 503 Service Unavailable).
Sensorstation: Warnungen über LEDs und Display funktionieren weiterhin.
Systemadmins: Ausfallzeitraum und Health-Check-Status in Logs sichtbar.

Szenario 5 – Ausfall Backend

8. GUI Prototyp

Die GUI wurde zunächst als Papierprototyp entwickelt, um die wichtigsten Abläufe frühzeitig zu visualisieren.
Die vollständigen Prototypen befinden sich im Repository unter /docs/images/gui_prototype/.

Login

  • Einfache Login-Maske mit E-Mail und Passwort
  • Validierung falscher Eingaben
  • Nach erfolgreichem Login erfolgt eine Weiterleitung auf ein rollenabhängiges Dashboard

Papierprototyp Login

Dashboard (Mitarbeiter:in)

Das Dashboard für Mitarbeiter:innen zeigt die aktuellen Klimadaten des eigenen Büros.

Funktionen:

  • Anzeige von Temperatur, Luftfeuchtigkeit und Luftqualität
  • Visualisierung der Luftqualität über Farbindikatoren
  • Prominente Warnanzeige bei Grenzwertverletzungen
  • Anzeige von Raumklima-Tipps bei Problemen
  • Navigation zu Verlaufsansicht und Abwesenheitsverwaltung

Papierprototyp Mitarbeiter Dashboard

Verlaufsansicht (Raumdetails)

Die Verlaufsansicht zeigt historische Messdaten eines Raumes.

Eigenschaften:

  • Liniendiagramme für Temperatur, Luftfeuchtigkeit und Luftqualität
  • Zeitraum wählbar (Tag / Woche / Monat)
  • Grenzwerte werden als Referenzlinien angezeigt
  • Grenzwertverletzungen werden farblich markiert
  • Datenlücken (z. B. Datenschutz oder Geräteausfall) werden als graue Bereiche dargestellt

Verlaufsansicht

Die Granularität der Daten hängt von der Rolle ab:

  • Mitarbeiter:innen sehen Rohdaten ihres eigenen Büros
  • Abteilungsleitung sieht aggregierte Tagesdurchschnitte für Büroräume

Dashboard (Abteilungsleitung)

Die Abteilungsleitung erhält eine Übersicht über alle Räume ihrer Abteilung.

Funktionen:

  • Rasteransicht aller Räume
  • Anzeige aktueller Messwerte pro Raum
  • Warnstatus bei Grenzwertverletzungen
  • Navigation zur Raumdetailansicht

Papierprototyp Abteilungsleitung Dashboard

Dashboard (Geschäftsführung)

Die Geschäftsführung sieht ausschließlich aggregierte Daten auf Abteilungsebene.

Funktionen:

  • Balkendiagramm mit Anzahl der Grenzwertverletzungen pro Abteilung
  • Trendanalyse über Wochen oder Monate
  • Keine raumbezogenen Einzelwerte (Datenschutz)

Konfigurationsansicht (Hausverwalter)

Der Hausverwalter kann die Raumkonfiguration und Grenzwerte verwalten.

Funktionen:

  • Liste aller Räume
  • Anzeige aktueller Grenzwerte
  • Bearbeitung der Grenzwerte pro Raum
  • Verwaltung von Raumklima-Tipps

Papierprototyp Geschäftsführung & Verwaltung

Gerätemanagement (Systemadministrator)

Die Systemadministration verwaltet die physische Infrastruktur.

Funktionen:

  • Übersicht aller Raspberry Pis und Sensorstationen
  • Statusanzeige (Online / Offline / Maintenance)
  • Registrierung neuer Geräte
  • Zuordnung von Sensorstationen zu Raspberry Pis und Räumen
  • Benutzerverwaltung und Rollenzuweisung

Papierprototyp Raumklima-Tipps & Gerätemanagment

9. Projektplan

Verantwortlichkeiten

Person Zuständigkeit
Maria Kuhn Arduino-Entwicklung (C/C++, Display/LED/Buttons), Frontend (React/TypeScript)
Fabienne Schedler Frontend (React/TypeScript, PrimeReact, GUI-Prototyp)
Emma Danko Raspberry Pi (Python, REST-Schnittstellen, BLE Central, SQLite, Docker)
Prahbdip Singh Raspberry Pi (REST-Schnittstellen, BLE Central, SQLite, Docker), Backend
Adriano Paganini Arduino-Entwicklung (C/C++, Display/LED/Buttons), Backend
Alle Softwarekonzept, Testing, Dokumentation, Code Review

Meilensteine und Zeitplan

Datum Meilenstein Inhalt
12.03.2026 Softwarekonzept V1 Systemüberblick, Use Cases, Klassendiagramm V1, GUI-Prototyp, Projektplan
19.03.2026 Softwarekonzept V2 Sequenzdiagramme, API Dokumentation, Ausfallssicherheit, Klassendiagramm V2
19.03.2026 Arduino Anschlussplan Pinout und Verdrahtungsplan der Sensorstation
23.03.2026 Durchstich Demonstration (PS-Einheit) Kommunikation zwischen Backend/Frontend – Raspberry Pi – Arduino
27.03.2026 Softwarekonzept finale Version Überarbeitetes Gesamtkonzept nach Feedback
28.05.2026 Slides für Ergebnispräsentation Präsentationsfolien
28.05.2026 Projektergebnisse Abnahmetests Abnahmetests der Projektergebnisse
01.06.2026 Ergebnispräsentation (PS-Einheit) Projektpräsentation
05.06.2026 Dokumentation Abnahmetests Schriftliche Dokumentation der Abnahmetests
25.06.2026 Finale Abgabe Projektergebnisse Vollständige Abgabe aller Projektergebnisse

Implementierungsphase

Zeitraum Meilenstein Inhalt
13.03. – 23.03.2026 M1: Hardware Setup Arduino + Sensoren funktionsfähig; BLE-Übertragung zum Raspberry Pi; Raspberry Pi OS + Docker eingerichtet; Basis-REST-API (OpenAPI)
24.03. – 12.04.2026 M2: Backend Grundgerüst Spring Boot Skeleton aufgesetzt; PostgreSQL-Datenbankschema implementiert; Login und Rollenverwaltung; ID-Generierungsablauf definieren (RPI, Arduino)
24.03. – 03.05.2026 M3: Datenfluss End-to-End Kompletter Datenfluss Arduino → Raspberry Pi → Backend funktionsfähig; Grenzwertberechnung am Raspberry Pi; Datenschutzlogik
24.03. – 24.05.2026 M4: Frontend + Warnungen Rollenabhängige Dashboards; Verlaufsdiagramme; Grenzwertwarnungen in Webapp und auf Sensorstation
25.05. – 05.06.2026 M5: Ausfallssicherheit + Testing Ausfallszenarien abgesichert; SonarQube integriert; mindestens 65 % Testabdeckung; Abnahmetests (28.05.) und Dokumentation (05.06.)
06.06. – 25.06.2026 M6: Finalisierung Bugfixes; vollständige Dokumentation; Ergebnispräsentation (01.06.); finale Abgabe (25.06.2026)

Inkrementelle Entwicklung

Organisatorische Maßnahmen:

  • Wöchentliche Team-Synchronisationsmeetings zur Besprechung von Fortschritt und Blockern
  • Nutzung von GitLab Issues zur Aufgabenverwaltung
  • Merge Requests und Code Reviews für Änderungen
  • Dokumentation des Softwarekonzepts im GitLab Wiki
  • Integration von SonarQube ab Beginn der Backend-Entwicklung zur kontinuierlichen Qualitätskontrolle

Clone this wiki locally