Felix Pfarr

Projekte · Datenplattform

Selbst gehostete Datenplattform

Ein privates System, das erfasst, was ich esse, wie ich mich fühle, was ich tue, wie meine Vitalwerte aussehen und wie die Luft in dem Raum ist, in dem ich sitze. Alles läuft über eine eigene API in eine eigene Datenbank auf Servern, die ich selbst betreibe. Entstanden ist eine durchgehende Datenstrecke von der Erfassung über die Aufbereitung bis zum Modell, die seit einem Jahr ohne Unterbrechung läuft.

Rolle
Konzept, Entwicklung und Betrieb, allein
Zeitraum
laufend seit September 2025
Stack
Django, REST-API, Flutter, ESP32 mit BME680, NFC, Google Health API, MySQL, FullCalendar, Apache Airflow, TensorFlow, scikit-learn, Proxmox, Ubuntu Server
Code
Repository und README auf Anfrage, siehe Kontakt

Das System auf einen Blick

Sechs Quellen, eine Schnittstelle, drei virtuelle Maschinen. Zwei Flutter Apps, die Sensorik in den Räumen, die NFC-Tags an den Türen, meine Fitbit und ein Formular im Browser liefern alle an dieselbe Django Anwendung. Sie schreibt in einen MySQL-Server auf einer zweiten Maschine und liest von dort auch wieder, um die Auswertungen anzuzeigen. Auf einer dritten Maschine räumt Apache Airflow die Rohdaten auf und legt daraus einen Datensatz ab, mit dem sich unmittelbar trainieren lässt.

Proxmox-Hypervisor · eigene Hardware Geräte und Quellen Flutter · Mood-App Stimmung und Befinden mehrmals am Tag Flutter · Session-App Aktivität mit Start/Stopp Offline-Puffer und Sync ESP32 + BME680 Temperatur, Feuchte, Druck Luftqualität, je Raum NFC-Tag am Raum startet die Raum-Session Fitbit Inspire 3 über die Google Health API Puls, Schlaf, Schritte Food Tracker im Browser Lebensmittel und Getränke Menge in Gramm oder ml Django-Anwendung VM 1 · Ubuntu Server Nimmt entgegen POST · Stimmung POST · Aktivitäten POST · Raumklima POST · Vitaldaten Formular · Lebensmittel Zeigt an Tagebuch mit Tagessummen Nährwerte je Lebensmittel Stimmungsentwicklung Raumentwicklung Events im Kalender CSV-Download schreibt liest MySQL VM 2 · Datenbankserver Ernährung · Stimmung · Sessions Raumklima · Vitaldaten Apache Airflow VM 3 · Analyseumgebung Zeitstempel angleichen Lücken markieren Quellen zusammenführen ein Datensatz je Lauf Anaconda-Umgebung VM 3 TensorFlow · scikit-learn Modelle auf dem gemeinsamen Datensatz

Django als Drehscheibe

Die Django Anwendung hat zwei Aufgaben. Nach außen ist sie eine Weboberfläche, in der ich Mahlzeiten und Getränke erfasse und die Auswertungen ansehe. Nach innen ist sie die REST-Schnittstelle, an die alle anderen Quellen liefern.

Lebensmittel und Getränke liegen mit ihren Nährwerten in der Datenbank. Bei der Eingabe rechnet die Anwendung anhand der Menge in Gramm oder Millilitern um, ordnet das Ergebnis der Mahlzeit zu und summiert es über den Tag zu Kalorien, Protein, Kohlenhydraten mit Zuckeranteil, Fett mit gesättigtem Anteil, Ballaststoffen, Salz und bei Getränken zusätzlich Koffein.

Tagebuchansicht der Django-Anwendung mit Tages-Gesamtsummen für Essen, Getränke und Gesamt sowie den Mahlzeitenblöcken Frühstück und Mittagessen
Tagesansicht der Django-Anwendung

Zwei Apps für das, was kein Sensor misst

Stimmung und Aktivitäten kann kein Gerät automatisch erheben, also habe ich zwei Flutter Apps für Android gebaut. Eine erfasst Konzentration, Müdigkeit, Hunger, Stimmung, Stress und Beschwerden, die andere läuft als Stoppuhr für Aktivitäten mit Typ, Start und Ende. Beide halten die Eingabe bewusst kurz, weil eine Tracking-App, die eine Minute Aufmerksamkeit kostet, nach zwei Wochen nicht mehr benutzt wird.

Gesendet wird an die Schnittstelle, sobald das Handy im lokalen Netz ist. Bis dahin liegen die Einträge lokal in der App, der Zähler in der Kopfzeile zeigt die offenen an, und ein Tippen schickt sie nach. Ohne diesen Puffer wäre jeder Eintrag außer Haus verloren.

Eingabemaske der Flutter-App für die Stimmung mit Auswahlfeldern für Konzentration, Müdigkeit, Hunger, Stimmung, Stress und Beschwerden
Stimmung erfassen
Liste bereits erfasster Stimmungseinträge in der Flutter-App mit Uhrzeit und Kurzfassung der Werte
Erfasste Einträge
Auswahlliste der Session-Typen in der Flutter-App, unter anderem Arbeit, Uni, Projekt, Haushalt und Computerspiele
Auswahl der Aktivität
Session-App mit einer laufenden Session und den zuletzt beendeten Sessions samt Typ, Ort, Start, Ende und Dauer
Laufende Aufzeichnung

Was daraus im Browser wird

Beide Apps schreiben in dieselbe Datenbank, aus der die Django-Anwendung ihre Ansichten baut. Die Aktivitäten laufen als Termine in einen FullCalendar, die Stimmungseinträge in eine Übersicht, die sich nach Zeitraum, nach Wertebereich je Merkmal, nach Beschwerden und nach Sitzung filtern lässt.

Kalenderansicht der Django-Anwendung mit den aufgezeichneten Aktivitäten als Termine im Monat September 2026
Aktivitäten im Kalender
Auswertung der Stimmungsdaten mit Filtern für Zeitraum, Konzentration, Müdigkeit, Hunger, Stimmung, Beschwerden und Stress
Auswertung der Stimmungsdaten

Sensorik und NFC

In den Räumen hängen ESP32 Boards mit BME680-Sensoren. Vier Leitungen, Strom und I²C, mehr braucht der Aufbau nicht. Das Board liest Temperatur, Luftfeuchte, Luftdruck und Luftqualität aus und schickt sie über das eigene WLAN an dieselbe API wie alles andere.

Damit die Messwerte einen Bezug zu mir bekommen, klebt an jeder Tür ein NFC-Tag. Einmal mit dem Handy dranhalten, und ein Aufruf der Schnittstelle startet die Sitzung für diesen Raum. So weiß das System nicht nur, wie die Luft war, sondern auch, ob ich darin war.

Django-REST-API nimmt die Messwerte entgegen und legt sie in MySQL ab WLAN im eigenen Netz ESP32 WLAN-Mikrocontroller misst zyklisch 3V3 GND SDA SCL Strom und I²C, vier Leitungen BME680 Temperatur, Feuchte Druck, Luftqualität NFC-Tag klebt am selben Raum scannen Handy startet die Raum-Session
Aufbau einer Messstelle

In der Anwendung liegt für jeden Raum der letzte Messwert und darunter der Verlauf. Die Kurve zeigt, was der Aufbau leistet. Der Abfall am Abend, die flache Nacht und der steile Anstieg am Morgen sind keine Messfehler, sondern ein geöffnetes Fenster, ein auskühlender Raum und ein Arbeitstag, der beginnt.

Zwei Kacheln mit den letzten Messwerten für Wohnzimmer und Arbeitszimmer: Zeitstempel, Temperatur, Luftfeuchtigkeit und Gaswiderstand
Letzter Messwert je Raum
Temperaturverlauf im Arbeitszimmer über 24 Stunden mit Abfall am Abend, flachem Verlauf über Nacht und steilem Anstieg am Morgen
Temperaturverlauf im Arbeitszimmer

Vitaldaten über die Google Health API

Herzfrequenz, Schritte, Schlaf und Aktivitäten kommen von einer Fitbit Inspire 3. Der Import lief ursprünglich über die Fitbit Web API und ist auf die Google Health API umgezogen, nachdem die alte Schnittstelle abgekündigt wurde. Geholt wird planmäßig, damit die Zeitreihen lückenlos bleiben. Der folgende Lauf ist so ein Datensatz, ausgewertet auf dem eigenen Server.

DAUER 22:13 min DISTANZ 2,94 km PULS MITTEL 117 bpm PULS MAX 127 bpm TEMPO 7:33 /km KALORIEN 178 kcal ANSTIEG 37 m Herzfrequenz in Schlägen pro Minute 100 110 120 130 Tempo in Minuten pro Kilometer 4:00 6:00 8:00 10:00 12:00 14:00 0 5 10 15 20 Minuten
Ein Lauf vom 10. September 2026

Aufbereitung mit Apache Airflow

Sechs Quellen heißen sechs Formate, sechs Zeitauflösungen und sechs Arten, unvollständig zu sein. Der Sensor misst im Sekundentakt, die Fitbit liefert Tagesaggregate, eine Mahlzeit hat einen Zeitpunkt, eine Session einen Zeitraum. Airflow-DAGs bereinigen die Rohdaten, gleichen die Zeitstempel an, markieren Lücken und führen alles in ein gemeinsames Datenmodell zusammen. Am Ende jedes Laufs liegt ein Datensatz bereit, mit dem sich direkt trainieren lässt.

Der Punkt daran ist Wiederholbarkeit. Ein Notebook, das einmal funktioniert hat, ist keine Pipeline. Ein DAG, der jeden Tag durchläuft und bei einem Fehler an genau einer Stelle stehen bleibt, schon.

DAG plattform_aufbereitung Datenbank 1 Ernährung, Stimmung Sessions, Raumklima Datenbank 2 Vitaldaten aus dem Fitbit-Import zeitstempel_angleichen Zeitzonen und Auflösung vereinheitlichen auf_zeitraster_legen gemeinsames Fünf-Minuten-Raster quellen_verbinden eine Zeile je Zeitpunkt statt fünf Tabellen luecken_markieren fehlende Messungen kennzeichnen statt raten analyse.datensatz eine Tabelle, direkt trainierbar Lesen Aufbereiten Schreiben Zeitplan täglich um 03:00 Bei Fehlern stoppt genau ein Task, der Rest bleibt stehen Wiederholbar jeder Lauf erzeugt denselben Stand Aktualität der Datensatz ist nie älter als ein Tag

Betrieb auf eigenem Hypervisor

Die Plattform läuft auf einem Proxmox Hypervisor bei mir zu Hause, aufgeteilt auf drei getrennte Maschinen mit Ubuntu Server. Eine trägt die Django Anwendung, eine die MySQL Datenbanken, eine den Fitbit-Import und die Analyseumgebung. Virtualisierung, Netzwerk, Nutzerrechte, Backups und Updates liegen damit genauso bei mir wie der Code.

Die Trennung ist Absicht. Ein fehlgeschlagenes Update in der Analyseumgebung darf die API nicht mitreißen, und eine Datenbank, die auf einer eigenen VM liegt, lässt sich unabhängig sichern und zurückspielen. Als Speicher liegt darunter ein ZFS-Pool, Updates und Backups laufen als wiederkehrende Aufgaben. Jede weitere Anwendung bekommt dasselbe Muster aus eigener Maschine und eigener Datenbank.

Proxmox-Oberfläche mit den drei virtuellen Maschinen der Plattform, den Speichern und dem Aufgabenprotokoll
Die Maschinen der Plattform in Proxmox

Was dabei herauskommt

Am Ende der Kette steht die Auswertung. In einer Anaconda-Umgebung arbeite ich mit TensorFlow und scikit-learn auf dem zusammengeführten Datensatz und gehe Zusammenhängen nach, die ohne durchgehende Messung unsichtbar bleiben. Dazu gehört, ob sich Sport am Vortag in der Stimmung niederschlägt, ob die Konzentration mit der Luftqualität im Arbeitszimmer nachlässt und ob spätes Essen den Schlaf verändert. Veranschaulicht durch eine Korrelationsmatrix über alle Merkmale. Sie zeigt, wo sich überhaupt etwas abzeichnet, und entscheidet darüber, welche Größen in ein Modell wandern.

Zusammenhänge zwischen den Merkmalen Stim Konz Müd Schlaf Aktiv Luft Puls Stimmung 1,00 0,58 −0,52 0,41 0,34 0,22 −0,19 Konzentration 0,58 1,00 −0,63 0,37 0,18 0,44 −0,12 Müdigkeit −0,52 −0,63 1,00 −0,46 −0,09 −0,31 0,27 Schlafdauer 0,41 0,37 −0,46 1,00 0,25 0,08 −0,33 Aktivität 0,34 0,18 −0,09 0,25 1,00 0,03 −0,41 Luftqualität 0,22 0,44 −0,31 0,08 0,03 1,00 −0,06 Ruhepuls −0,19 −0,12 0,27 −0,33 −0,41 −0,06 1,00 gegenläufig gleichläufig

Was ich daraus mitgenommen habe

Der aufwendigste Teil war nicht das Modell, sondern alles davor. Zeitstempel über sechs Quellen hinweg vergleichbar zu machen, Ausfälle einer Sensoreinheit sauber zu behandeln und eine API so zu schneiden, dass eine neue Quelle keine Migration im Bestand auslöst, hat mehr Zeit gekostet als das Training.

Genauso wichtig war die Einsicht, dass Erfassung nur überlebt, wenn sie nichts kostet. Alles, was mehr als ein paar Sekunden Aufmerksamkeit verlangt hätte, ist entweder automatisiert worden oder aus dem System geflogen.

Quellcode und Dokumentation stelle ich auf Anfrage zur Verfügung, ebenso weitergehende Auskunft zum Aufbau. Die Kontaktangaben stehen auf der Startseite.

Zurück zu den Projekten