Modularisierung eines Python‑Projekts in PyCharm – am Beispiel einer WetterApp

Eine saubere Modularisierung ist entscheidend, wenn ein Projekt sowohl eigenständig laufen als auch in anderen Anwendungen wiederverwendet werden soll. Das folgende Vorgehen zeigt, wie man in PyCharm ein Projekt so strukturiert, dass es als Python‑Paket installierbar wird – passend zu einer setup.py wie:

from setuptools import setup, find_packages

setup(
    name="weatherapp",
    version="0.1.0",
    packages=find_packages(),
    include_package_data=True,
)


1. Projekt als Paket strukturieren

Damit find_packages() funktioniert, benötigt jede Modul‑Ebene eine klare Struktur:

weatherapp/
    __init__.py
    screens/
        __init__.py
        forecast_screen.py
    services/
        __init__.py
        weather_reader.py
        weather_icons.py
    config/
        __init__.py
        settings.py
    ui/
        visualizer.kv
    assets/
        icons/
        forecast_plot.png
setup.py

PyCharm erleichtert das Anlegen dieser Struktur:

  • Rechtsklick → New → Python Package
  • PyCharm erzeugt automatisch __init__.py
  • Dateien können sauber in Module verschoben werden

2. Module klar trennen

Die Modularisierung folgt dem Prinzip „eine Verantwortung pro Modul“:

  • screens/ enthält ausschließlich Kivy‑Screens
  • services/ enthält API‑ und Datenlogik
  • config/ enthält Einstellungen
  • ui/ enthält KV‑Dateien und Assets

Diese Trennung sorgt dafür, dass das Paket später problemlos in anderen Projekten importiert werden kann.


3. setup.py korrekt konfigurieren

Die gezeigte setup.py nutzt:

  • find_packages() → erkennt automatisch alle Python‑Pakete
  • include_package_data=True → bindet KV‑Dateien, Icons und Assets ein

Damit PyCharm diese Dateien beim Packaging berücksichtigt, muss zusätzlich eine MANIFEST.in erstellt werden:

recursive-include weatherapp/ui *.kv
recursive-include weatherapp/assets *

PyCharm erkennt diese Datei automatisch beim Build.


4. Paket lokal installierbar machen

In PyCharm:

  1. Terminal öffnen
  2. Im Projektordner ausführen:
pip install -e .

Das installiert weatherapp im Editable Mode – Änderungen im Code wirken sofort.

Damit kann das Paket:

  • in anderen Projekten importiert werden
  • als Plugin genutzt werden
  • ohne Kopieren von Dateien wiederverwendet werden

5. Modular testen und integrieren

Durch die Paketstruktur kann PyCharm:

  • einzelne Module separat ausführen
  • Screens unabhängig testen
  • Services ohne UI testen
  • das Paket in anderen Projekten importieren:
from weatherapp.screens.forecast_screen import ForecastScreen

Damit wird die Wiederverwendbarkeit maximiert.


Fazit

Die Kombination aus:

  • klarer Paketstruktur
  • sauber getrennten Modulen
  • einer einfachen setup.py
  • include_package_data=True
  • MANIFEST‑Regeln für KV‑ und Asset‑Dateien

macht dein Projekt modular, installierbar und wiederverwendbar – sowohl als eigenständige App als auch als integriertes Modul in größeren Anwendungen wie dem BuildingDataVisualizer.

Die Wetter‑App als Paket integrieren: Herausforderungen, Stolpersteine und die finale Lösung

Die Integration der Wettervorhersage‑App in die Gebäudedaten‑App war einer der anspruchsvollsten Schritte des gesamten Projekts. Obwohl beide Apps modular aufgebaut sind, war es keineswegs trivial, die Wetter‑App als vollständiges, eigenständiges Paket in die Visualisierung einzubinden. Dieser Artikel dokumentiert den gesamten Prozess — inklusive der Probleme, die unterwegs aufgetreten sind, und der Lösungen, die letztlich zu einer stabilen, sauberen Integration geführt haben.

Damit dient dieser Artikel als technischer Erfahrungsbericht, als Dokumentation und als Referenz für alle, die ähnliche Projekte planen.

Ziel der Integration

Die Wetter‑App sollte:

  • unverändert in die Gebäudedaten‑App übernommen werden
  • als eigenes Modul funktionieren
  • keine Konflikte mit bestehenden Screens, KV‑Layouts oder Services verursachen
  • über den Startscreen erreichbar sein
  • denselben ScreenManager nutzen
  • keine Änderungen am bestehenden Gebäudedaten‑Code erzwingen

Kurz:
Die Wetter‑App sollte sich wie ein Plug‑in verhalten.

Ausgangssituation

Die Wetter‑App war ein eigenständiges Projekt mit:

  • eigenem ForecastScreen
  • eigenem weatherapp/‑Paket
  • eigenen Services (WeatherReader, WeatherApiClient, WeatherParser)
  • eigener KV‑Datei (visualizer.kv)
  • eigenem Icon‑Downloader
  • eigener Konfiguration (settings.py)

Die Gebäudedaten‑App hatte:

  • eine klare Screen‑Struktur
  • einen zentralen AppState
  • eigene KV‑Layouts
  • eigene Services
  • eine SQLite‑Datenbank
  • eine lineare Navigation

Beide Projekte mussten zusammengeführt werden, ohne dass eines das andere beschädigt.

Die größten Herausforderungen

1. Paketstruktur und Import‑Pfadprobleme

Die Wetter‑App war ursprünglich ein Standalone‑Projekt.
Beim Einbinden in die Gebäudedaten‑App traten typische Python‑Importprobleme auf:

  • relative Importe funktionierten nicht mehr
  • KV‑Dateien wurden nicht gefunden
  • Services konnten ihre Module nicht mehr auflösen
  • der Icon‑Downloader suchte Pfade relativ zum falschen Arbeitsverzeichnis

Lösung:
Die Wetter‑App wurde als vollständiges Paket weatherapp/ in das Projekt kopiert.
Alle Importe wurden auf absolute Paketpfade umgestellt:

from weatherapp.services.weather_reader import WeatherReader

Damit war das Paket stabil eingebunden.

2. KV‑Dateien und Kivy‑Suchpfade

Kivy lädt .kv‑Dateien standardmäßig relativ zum Arbeitsverzeichnis.
Das führte zu:

  • „File not found“
  • „ParserException“
  • fehlenden Widgets

Lösung:
Alle KV‑Dateien wurden über absolute Pfade geladen:

KV_PATH = Path(__file__).resolve().parent.parent / "ui" / "visualizer.kv"
Builder.load_file(str(KV_PATH))

Damit war die Wetter‑UI unabhängig vom Startverzeichnis.

3. Konflikte im ScreenManager

Beide Apps hatten:

  • eigene Screens
  • eigene Navigationslogik
  • eigene Back‑Navigation

Die Wetter‑App durfte:

  • nicht den AppState der Gebäudedaten‑App verändern
  • nicht die Navigation der Gebäudedaten‑App überschreiben
  • nicht eigene ScreenManager erzeugen

Lösung:
Der ForecastScreen wurde als zusätzlicher Screen in den bestehenden ScreenManager eingefügt:

weather_settings = Settings()
sm.add_widget(ForecastScreen(settings=weather_settings, name="weather"))

Damit war die Wetter‑App vollständig integriert, ohne eigene Navigation.

4. Ressourcen‑Pfadprobleme (Icons, Diagramme)

Die Wetter‑App lädt Icons dynamisch herunter.
Dabei traten Probleme auf:

  • falsche Speicherpfade
  • fehlende Schreibrechte
  • Icons wurden im falschen Ordner abgelegt
  • Diagramme wurden nicht gefunden

Lösung:
Ein zentraler assets/‑Ordner wurde definiert, und alle Pfade wurden vereinheitlicht.

5. Kivy‑Namenskonflikte

Beide Apps hatten Widgets mit ähnlichen IDs:

  • header
  • content
  • scroll

Das führte zu:

  • „Duplicate id“
  • „Widget not found“
  • UI‑Fehlern

Lösung:
Die Wetter‑App erhielt eindeutige ID‑Präfixe, z. B.:

  • weather_header
  • weather_scroll
  • weather_icon_box

Damit waren alle Konflikte beseitigt.

Die finale Integration

Nach allen Anpassungen bestand die Integration aus nur einer einzigen Zeile in app.py:

sm.add_widget(ForecastScreen(settings=weather_settings, name="weather"))

Aber der Weg dahin war deutlich länger — und genau deshalb ist dieser Artikel wichtig.

Was dieser Artikel dokumentiert

Dieser Artikel fasst zusammen:

  • warum die Integration nicht trivial war
  • welche Probleme auftraten
  • wie sie gelöst wurden
  • wie die Wetter‑App heute als Paket funktioniert
  • wie du ähnliche Module in Zukunft integrieren kannst

Nächste Schritte

Wenn du lernen willst, wie man schlussendlich ein Modul aus der App macht, schau dir diesen Artikel an

Artikel 7 – Abschluss, Architektur und Ausblick: Wie die Gebäudedaten‑App als modulares Gesamtsystem funktioniert

Mit diesem Artikel schließt du die siebenteilige Serie zur Gebäudedaten‑App ab. In den vorherigen Artikeln hast du die Navigation, die Datenbank, die Sensorlogik, die Diagrammerstellung, die Zonenstruktur und die Integration der Wettervorhersage im Detail kennengelernt. Dieser letzte Artikel fasst alles zusammen, ordnet die Architektur ein und zeigt dir, wie du das Projekt in Zukunft erweitern kannst — ohne die bestehende Struktur zu gefährden.

Dieser Artikel ist bewusst reflektierend aufgebaut. Er zeigt dir, warum die App so stabil funktioniert, welche Designentscheidungen sie so flexibel machen und wie du das Projekt in Zukunft weiterführen kannst. Gleichzeitig bekommst du eine klare Übersicht über alle Module, ihre Aufgaben und ihre Abhängigkeiten.

1. Die Gebäudedaten‑App als modulares Gesamtsystem

Die Gebäudedaten‑App ist ein Paradebeispiel für eine modular aufgebaute Kivy‑Anwendung. Sie besteht aus mehreren klar getrennten Bereichen:

  • Screens für die Benutzeroberfläche
  • Services für Datenbank, Sensorlogik und Diagrammerstellung
  • KV‑Layouts für die visuelle Darstellung
  • WeatherApp‑Modul für die Wettervorhersage
  • AppState als zentraler Navigationszustand
  • app.py als Einstiegspunkt

Diese Struktur sorgt dafür, dass die App leicht verständlich, gut wartbar und problemlos erweiterbar ist. Jeder Bereich hat eine klar definierte Aufgabe, und die Module sind so entkoppelt, dass Änderungen an einem Teil der App keine unerwarteten Auswirkungen auf andere Teile haben.

2. Die Rolle des AppState – das verbindende Element

Der AppState ist eines der wichtigsten Elemente der App. Er speichert alle Informationen, die für die Navigation relevant sind:

  • aktuelle Zone
  • aktueller Raum
  • aktueller Sensor
  • vorheriger Screen

Dadurch müssen die Screens nicht direkt miteinander kommunizieren. Stattdessen greifen sie alle auf denselben Zustand zu. Das macht die App flexibel und verhindert enge Kopplungen zwischen den Screens.

Beispiel:

  • Der SensorScreen setzt current_sensor_id.
  • Der DiagrammScreen liest current_sensor_id.
  • Der OutdoorScreen setzt current_zone_id.
  • Der RoomScreen liest current_zone_id.

Diese Struktur ist robust und leicht erweiterbar.

3. Die Datenbank als stabile Grundlage

Die Datenbank ist das Herzstück der App. Sie enthält alle Informationen über:

  • Zonen
  • Räume
  • Sensoren
  • Messwerte

Die Tabellenstruktur ist bewusst einfach gehalten, aber sie bildet die Grundlage für die gesamte App. Die Abfragen sind klar strukturiert und leicht verständlich.

Beispiel:

SELECT id, name FROM rooms WHERE zone_id=? ORDER BY name ASC

Diese Abfrage lädt alle Räume einer Zone.

Die Datenbank ist flexibel genug, um später erweitert zu werden — z. B. um weitere Zonen, Räume oder Sensortypen.

4. Die Sensorlogik – wie die App Daten erzeugt

Der SensorService erzeugt Zufallswerte, um die Live‑Aktualisierung zu simulieren. Das ist wichtig, weil die App ohne echte Sensoren keine Daten hätte. Der SensorService sorgt dafür, dass die App immer aktuelle Werte hat.

Beispiel:

value = random.uniform(19.0, 24.0)
timestamp = datetime.now().isoformat(timespec="seconds")

Diese Werte werden in die Datenbank geschrieben und später im Diagramm angezeigt.

5. Die Diagrammerstellung – Matplotlib als Visualisierungstool

Der DiagrammService ist für die Erstellung der Diagramme verantwortlich. Er verwendet Matplotlib, um ein einfaches Liniendiagramm zu erzeugen. Die Diagramme werden transparent gespeichert, damit sie sich gut in das UI einfügen.

Beispiel:

fig, ax = plt.subplots(figsize=(6, 3), dpi=100)
ax.plot(timestamps, values, color=color, linewidth=1.8)
fig.savefig(path, transparent=True)

Die Diagramme sind leicht, modern und gut lesbar.

6. Die Zonenlogik – Innen und Außen sauber getrennt

Die App unterstützt zwei Zonen:

  • Zone 1: Innenräume
  • Zone 2: Außenbereich

Diese Struktur ist nicht nur logisch, sondern auch technisch sinnvoll. Innenräume haben typischerweise mehrere Räume, während der Außenbereich meist nur einen Raum hat.

Der OutdoorScreen lädt die Sensoren der Zone 2:

zone_id = 2
rooms = get_rooms_by_zone(zone_id)
room_id, room_name = rooms[0]
sensors = get_sensors_by_room(room_id)

Diese Struktur ist flexibel genug, um später erweitert zu werden — z. B. um mehrere Außenbereiche.

7. Die Wettervorhersage – ein vollständig integriertes Modul

Die Wettervorhersage‑App ist ein eigenständiges Modul, das du vollständig in die Gebäudedaten‑App integriert hast. Sie besteht aus:

  • ForecastScreen
  • WeatherReader
  • WeatherApiClient
  • WeatherParser
  • download_icon
  • visualizer.kv

Die Integration erfolgt in app.py:

weather_settings = Settings()
sm.add_widget(ForecastScreen(settings=weather_settings, name="weather"))

Mehr ist nicht nötig.

8. Die Navigation – klar, intuitiv und konsistent

Die Navigation erfolgt über den Startscreen. Der Benutzer kann:

  • Räume anzeigen
  • Sensoren anzeigen
  • Diagramme anzeigen
  • Außensensoren anzeigen
  • Wettervorhersage anzeigen

Alles über drei Buttons.

Beispiel:

def open_forecast(self):
    self.manager.current = "weather"

Die Navigation ist bewusst einfach gehalten, damit die App leicht zu bedienen ist.

9. Warum die App so stabil ist

Die App ist stabil, weil sie:

  • modular aufgebaut ist
  • klare Verantwortlichkeiten hat
  • eine saubere Trennung von Logik und Layout besitzt
  • eine robuste Datenbankstruktur hat
  • eine einfache Fehlerbehandlung nutzt
  • den AppState als zentrales Bindeglied verwendet
  • Matplotlib für die Visualisierung nutzt
  • die Wettervorhersage als eigenständiges Modul integriert

Diese Struktur ist professionell und leicht erweiterbar.

10. Ausblick: Wie du die App in Zukunft erweitern kannst

Die App ist so aufgebaut, dass du sie jederzeit erweitern kannst. Mögliche Erweiterungen:

Weitere Sensoren

Du kannst neue Sensortypen hinzufügen, z. B.:

  • CO₂
  • VOC
  • Luftdruck
  • Helligkeit

Weitere Räume oder Zonen

Du kannst neue Räume oder Zonen hinzufügen, z. B.:

  • Keller
  • Garage
  • Dachboden

Weitere Diagramme

Du kannst zusätzliche Diagramme im bestehenden Stil hinzufügen.

UI‑Verbesserungen

Du kannst das UI modernisieren, z. B.:

  • dunkles Theme
  • neue Icons
  • animierte Übergänge

Erweiterung der Wetteranzeige

Du kannst zusätzliche Wetterdaten anzeigen, z. B.:

  • UV‑Index
  • Sonnenauf‑ und ‑untergang
  • Luftdruck

Fazit: Die Gebäudedaten‑App ist ein solides, erweiterbares Gesamtsystem

Nach diesem Artikel verstehst du:

  • wie die Architektur aufgebaut ist
  • wie die Module zusammenarbeiten
  • warum die App so stabil ist
  • wie du sie in Zukunft erweitern kannst

Damit ist die Serie abgeschlossen. Du hast eine App, die sowohl Gebäudedaten als auch Wetterdaten visualisiert und deren Struktur so modular ist, dass du sie jederzeit erweitern kannst.Wenn du möchtest, kann ich dir jetzt:

Artikel 6 – Datenbank, Sensorwerte und Diagramme im Detail: Wie die Gebäudedaten‑App ihre Daten verarbeitet und visualisiert

In den bisherigen Artikeln hast du die Navigation, die Zonenlogik und die Integration der Wettervorhersage kennengelernt. In diesem Artikel tauchst du tief in die technischen Grundlagen der Gebäudedaten‑App ein: die Datenbank, die Sensorwerte und die Diagrammerstellung. Diese drei Bereiche bilden das Fundament der gesamten App. Ohne eine funktionierende Datenbank gäbe es keine Räume, keine Sensoren und keine Messwerte. Ohne Sensorwerte gäbe es keine Daten zum Anzeigen. Und ohne Diagramme gäbe es keine visuelle Darstellung der Messwerte.

Dieser Artikel erklärt dir Schritt für Schritt, wie die App ihre Daten speichert, verarbeitet und visualisiert. Du lernst, wie die Datenbank aufgebaut ist, wie die Sensorwerte erzeugt werden, wie die Diagramme erstellt werden und wie all diese Komponenten zusammenarbeiten, um eine stabile und zuverlässige App zu bilden.

1. Die Datenbank als zentrales Element der App

Die Gebäudedaten‑App verwendet eine SQLite‑Datenbank, die über init_db.py erzeugt wird. SQLite ist ideal für lokale Anwendungen, weil es keine Installation benötigt und die Daten in einer einzigen Datei speichert. Die Datenbank ist das Herzstück der App. Sie enthält alle Informationen über:

  • Zonen
  • Räume
  • Sensoren
  • Messwerte

Diese Struktur ist bewusst einfach gehalten, aber sie bildet die Grundlage für die gesamte App.

Die Verbindung zur Datenbank

Die Verbindung wird über eine einfache Funktion hergestellt:

def get_connection() -> sqlite3.Connection:<br>    DB_PATH.parent.mkdir(parents=True, exist_ok=True)<br>    return sqlite3.connect(DB_PATH)<br>

Diese Funktion stellt sicher, dass der Ordner existiert und öffnet dann die Datenbankdatei. Wenn die Datei nicht existiert, wird sie automatisch erstellt.

2. Die Tabellenstruktur – wie die Daten organisiert sind

Die Datenbank enthält vier Tabellen:

zones

Diese Tabelle enthält die verschiedenen Zonen des Gebäudes, z. B.:

  • Innenbereich
  • Außenbereich

Jede Zone hat eine eindeutige ID und einen Namen.

rooms

Diese Tabelle enthält die Räume innerhalb einer Zone, z. B.:

  • Wohnzimmer
  • Küche
  • Büro
  • Außenbereich

Jeder Raum gehört zu einer Zone.

sensors

Diese Tabelle enthält die Sensoren innerhalb eines Raums, z. B.:

  • Temperatur
  • Feuchtigkeit
  • Luftqualität

Jeder Sensor gehört zu einem Raum und hat einen Typ.

readings

Diese Tabelle enthält die Messwerte eines Sensors:

  • Zeitstempel
  • Wert

Diese Struktur ist flexibel genug, um später erweitert zu werden — z. B. um weitere Sensortypen oder zusätzliche Zonen.

3. Die Datenbankabfragen – wie die App ihre Daten lädt

Die Abfragen sind in services/database/queries.py definiert. Sie sind klar strukturiert und leicht verständlich.

Räume einer Zone laden

SELECT id, name FROM rooms WHERE zone_id=? ORDER BY name ASC

Diese Abfrage lädt alle Räume einer Zone und sortiert sie alphabetisch.

Sensoren eines Raums laden

SELECT id, name, type FROM sensors WHERE room_id=? ORDER BY name ASC

Diese Abfrage lädt alle Sensoren eines Raums.

Messwerte eines Sensors laden

SELECT timestamp, value FROM readings WHERE sensor_id=? ORDER BY timestamp ASC LIMIT ?

Diese Abfrage lädt die Messwerte eines Sensors und sortiert sie nach Zeitstempel.

4. Der SensorService – wie die App Sensorwerte erzeugt

Der SensorService erzeugt Zufallswerte, um die Live‑Aktualisierung zu simulieren. Das ist wichtig, weil die App ohne echte Sensoren keine Daten hätte. Der SensorService sorgt dafür, dass die App immer aktuelle Werte hat.

Der Code sieht so aus:

value = random.uniform(19.0, 24.0)
timestamp = datetime.now().isoformat(timespec="seconds")

Diese Werte werden in die Datenbank geschrieben und später im Diagramm angezeigt.

Warum Zufallswerte?

  • Die App bleibt funktionsfähig, auch ohne echte Sensoren.
  • Die Diagramme sehen realistisch aus.
  • Die App kann jederzeit getestet werden.

5. Der DiagrammService – wie die App Diagramme erzeugt

Der DiagrammService ist für die Erstellung der Diagramme verantwortlich. Er verwendet Matplotlib, um ein einfaches Liniendiagramm zu erzeugen. Die Diagramme werden transparent gespeichert, damit sie sich gut in das UI einfügen.

Der Code sieht so aus:

fig, ax = plt.subplots(figsize=(6, 3), dpi=100)
ax.plot(timestamps, values, color=color, linewidth=1.8)
fig.savefig(path, transparent=True)

Warum transparente Diagramme?

  • Sie passen sich dem Hintergrund an.
  • Sie wirken moderner und leichter.
  • Sie lassen sich besser in dunkle Themes integrieren.

Farbwahl basierend auf dem Sensortyp

Der DiagrammService wählt die Farbe basierend auf dem Sensornamen:

color = "blue" if "feuchte" in sensor_name.lower() else "red"

Das ist eine einfache, aber effektive Methode, um die Diagramme visuell zu unterscheiden.

6. Wie der DiagrammScreen die Diagramme lädt

Der DiagrammScreen liest die Sensorinformationen aus dem AppState:

sensor_id = state.current_sensor_id
sensor_name = state.current_sensor_name or "Diagramm"

Wenn kein Sensor ausgewählt wurde, wird kein Diagramm angezeigt.

Der DiagrammScreen ruft den DiagrammService auf:

path = create_sensor_diagram(sensor_id, sensor_name)

Wenn ein Fehler auftritt, wird das Diagramm zurückgesetzt:

except Exception as e:
    self.ids.diagram_image.source = ""
    return

Anschließend wird das Bild neu geladen:

self.ids.diagram_image.source = path
self.ids.diagram_image.reload()

7. Fehlerbehandlung – warum sie so wichtig ist

Die Fehlerbehandlung im DiagrammScreen ist bewusst einfach gehalten. Wenn ein Fehler auftritt, wird das Diagramm zurückgesetzt. Das ist wichtig, weil die Diagrammerstellung fehlschlagen kann, wenn:

  • keine Messwerte vorhanden sind
  • der Sensor keine Daten hat
  • die Datenbank leer ist

Durch die einfache Fehlerbehandlung bleibt die App stabil und reagiert vorhersehbar.

8. Wie alle Komponenten zusammenarbeiten

Die Datenbank, der SensorService und der DiagrammService arbeiten eng zusammen:

  1. Der SensorService erzeugt neue Werte.
  2. Die Werte werden in die Datenbank geschrieben.
  3. Der DiagrammService liest die Werte aus der Datenbank.
  4. Der DiagrammScreen zeigt das Diagramm an.

Diese Struktur ist robust und leicht erweiterbar.

9. Warum diese Struktur so stabil ist

Die Kombination aus:

  • klaren Datenbankabfragen
  • sauberer Trennung von Logik und Layout
  • einfacher Fehlerbehandlung
  • dynamischer UI‑Erzeugung
  • transparenten Diagrammen

macht die App extrem stabil. Du kannst sie problemlos erweitern, ohne die bestehende Struktur zu gefährden.

Fazit: Die technische Basis der App ist vollständig

Nach diesem Artikel verstehst du:

  • wie die Datenbank aufgebaut ist
  • wie die Sensorwerte erzeugt werden
  • wie die Diagramme erstellt werden
  • wie der DiagrammScreen funktioniert
  • wie die App ihre Daten verarbeitet
  • warum die App so stabil läuft

Damit bist du perfekt vorbereitet für Artikel 7, in dem du die Architektur als Ganzes betrachtest und einen Ausblick auf mögliche Erweiterungen bekommst.

Artikel 5 – Wettervorhersage integrieren. Wie die Forecast‑App nahtlos Teil der Gebäudedaten‑App wird

Die Wettervorhersage‑App, die du in einem separaten Projekt entwickelt hast, ist ein vollwertiges Modul mit eigener Logik, eigener Datenverarbeitung und eigenem UI. In diesem Artikel lernst du, wie du diese App vollständig in die Gebäudedaten‑App integrierst, ohne ihren Code zu verändern oder anzupassen. Die Integration erfolgt modular, sauber und so, dass beide Systeme weiterhin unabhängig voneinander funktionieren könnten — aber in der gemeinsamen App perfekt zusammenspielen.

Dieser Artikel ist ein wichtiger Meilenstein der Serie, denn ab hier wird aus der Gebäudedaten‑App ein echtes Dashboard, das sowohl interne Sensordaten als auch externe Wetterdaten darstellen kann. Du wirst sehen, wie einfach die Integration dank der klaren Struktur beider Projekte ist, und wie du die Navigation so erweiterst, dass der Benutzer intuitiv zwischen Gebäudedaten und Wettervorhersage wechseln kann.

1. Warum die Wettervorhersage ein natürlicher Bestandteil der Gebäudedaten‑App ist

Bevor wir in die technische Integration einsteigen, lohnt es sich, kurz darüber nachzudenken, warum die Wettervorhersage überhaupt in die Gebäudedaten‑App gehört. Die Antwort ist einfach: Außensensoren und Wetterdaten gehören zusammen. Wenn du die Temperatur im Wohnzimmer misst, ist es sinnvoll zu wissen, wie warm es draußen ist. Wenn du die Luftfeuchtigkeit im Keller misst, ist es hilfreich zu wissen, ob draußen Regen angekündigt ist.

Die Wettervorhersage ergänzt die Gebäudedaten‑App also nicht nur — sie erweitert sie logisch. Die App wird dadurch zu einem echten Monitoring‑Tool, das sowohl interne als auch externe Faktoren berücksichtigt.

2. Die Struktur der Wettervorhersage‑App

Die Wettervorhersage‑App ist modular aufgebaut und besteht aus mehreren klar getrennten Komponenten:

  • ForecastScreen – der Hauptscreen der App
  • WeatherReader – lädt die Wetterdaten
  • WeatherApiClient – kommuniziert mit der API
  • WeatherParser – bereitet die API‑Antwort auf
  • download_icon – lädt die Wettericons herunter
  • visualizer.kv – definiert das Layout

Diese Struktur ist ideal für die Integration, weil du keine einzige Datei verändern musst. Du kannst die Wetter‑App einfach in die Gebäudedaten‑App einfügen und als weiteren Screen registrieren.


3. Die Integration in app.py – ein einziger Eintrag genügt

Die Integration erfolgt in der Datei app.py. Dort wird der ScreenManager erstellt und alle Screens registriert. Die Wettervorhersage wird einfach als weiterer Screen hinzugefügt:

weather_settings = Settings()<br>sm.add_widget(ForecastScreen(settings=weather_settings, name="weather"))<br>

Das ist alles. Mehr ist nicht nötig.

Warum funktioniert das so einfach?

Weil die Wetter‑App:

  • ihren eigenen Screen mitbringt
  • ihre eigenen Services mitbringt
  • ihre eigenen KV‑Layouts mitbringt
  • keine Abhängigkeiten zu anderen Teilen der Gebäudedaten‑App hat

Sie ist ein vollständig gekapseltes Modul.

4. Der ForecastScreen – das Herz der Wettervorhersage

Der ForecastScreen ist der zentrale Screen der Wetter‑App. Er lädt:

  • die aktuelle Wetterlage
  • die 5‑Tage‑Vorhersage
  • die Icons für jede Tageskachel
  • Diagramme für Temperatur, Wind, Regen und Bewölkung

Der ForecastScreen verwendet mehrere Services, um diese Daten zu laden und darzustellen.

WeatherApiClient

Der WeatherApiClient ist für die Kommunikation mit der API zuständig. Er sendet HTTP‑Anfragen und gibt die Antworten zurück.

WeatherReader

Der WeatherReader ruft den ApiClient auf und bereitet die Daten für den Parser vor.

WeatherParser

Der Parser extrahiert die relevanten Informationen aus der API‑Antwort:

  • Temperatur
  • Feuchtigkeit
  • Wind
  • Regen
  • Bewölkung
  • Zeitstempel

def download_icon(icon_code: str) -> Path:

Diese Funktion lädt die Icons für die Wetterlage herunter und speichert sie lokal.

5. Die KV‑Datei visualizer.kv – das Layout der Wettervorhersage

Die Datei visualizer.kv definiert das Layout des ForecastScreens. Sie enthält:

  • eine Kopfzeile
  • eine ScrollView für die Tageskacheln
  • Diagrammflächen
  • Labels für Temperatur, Wind, Regen und Bewölkung

Das Layout ist modern, übersichtlich und passt gut zur Gebäudedaten‑App.

6. Die Navigation zum ForecastScreen – ein eigener Button im Startscreen

Der Startscreen der Gebäudedaten‑App enthält drei Buttons:

  • Räume
  • Außensensoren
  • Wettervorhersage

Der Button für die Wettervorhersage öffnet den ForecastScreen:

def open_forecast(self):
    self.manager.current = "weather"

Das ist bewusst einfach gehalten. Der ForecastScreen kümmert sich selbst darum, die Wetterdaten zu laden.

7. Wie die Wettervorhersage geladen wird

Der ForecastScreen lädt die Wetterdaten, sobald er betreten wird. Das geschieht in der Methode on_pre_enter. Dort wird der WeatherReader aufgerufen, der die Daten lädt und an den Parser weitergibt.

Die Icons werden ebenfalls automatisch heruntergeladen, wenn sie noch nicht vorhanden sind.

Warum on_pre_enter?

Weil die Wetterdaten dynamisch sind. Wenn du die App startest und später erneut die Wettervorhersage öffnest, sollen die Daten aktualisiert werden.

8. Die Diagramme der Wettervorhersage

Die Wettervorhersage enthält mehrere Diagramme:

  • Temperaturverlauf
  • Windgeschwindigkeit
  • Regenmenge
  • Bewölkungsgrad

Diese Diagramme werden mit Matplotlib erzeugt — genau wie die Diagramme der Gebäudedaten‑App. Dadurch entsteht ein einheitliches Erscheinungsbild.

Die Diagramme werden transparent gespeichert, damit sie sich gut in das UI einfügen.

9. Warum die Integration so sauber funktioniert

Die Integration funktioniert so gut, weil beide Apps:

  • modular aufgebaut sind
  • klare Verantwortlichkeiten haben
  • ihre eigenen Layouts mitbringen
  • ihre eigenen Services mitbringen
  • keine gegenseitigen Abhängigkeiten haben

Der ForecastScreen ist ein vollständig gekapselter Screen. Er benötigt nur:

  • eine API‑Key‑Einstellung
  • einen Namen im ScreenManager

Mehr nicht.

10. Die Wettervorhersage als Teil der Navigation

Durch die Integration wird die Wettervorhersage ein natürlicher Teil der App. Der Benutzer kann:

  • Räume anzeigen
  • Sensoren anzeigen
  • Diagramme anzeigen
  • Außensensoren anzeigen
  • Wettervorhersage anzeigen

Alles über den Startscreen.

11. Die Rolle des AppState in der Wettervorhersage

Der ForecastScreen verwendet den AppState nicht. Das ist wichtig, denn:

  • die Wettervorhersage ist unabhängig von den Gebäudedaten
  • sie benötigt keine Informationen über Räume oder Sensoren
  • sie hat ihre eigene Logik

Das macht die Integration besonders einfach.

12. Fazit: Die Wettervorhersage ist vollständig integriert

Nach diesem Artikel verstehst du:

  • wie die Wettervorhersage‑App aufgebaut ist
  • wie sie in die Gebäudedaten‑App integriert wird
  • wie der ForecastScreen funktioniert
  • wie die Navigation erweitert wird
  • wie die Diagramme erzeugt werden
  • warum die Integration so sauber funktioniert

Damit ist die App bereit für die nächsten Schritte. In Artikel 6 wirst du die Datenbank, die Sensorwerte und die Diagrammerstellung im Detail analysieren.

Artikel 4 – Außensensoren und Zonenlogik: Wie die Gebäudedaten‑App Innen‑ und Außenbereiche sauber trennt und darstellt

Die Gebäudedaten‑App ist so aufgebaut, dass sie verschiedene Bereiche eines Gebäudes strukturiert darstellen kann. Dazu gehören nicht nur Innenräume wie Wohnzimmer, Küche oder Büro, sondern auch Außenbereiche wie Terrasse, Garten oder Balkon. In diesem Artikel tauchst du tief in die Zonenlogik der App ein und lernst, wie die App Innen‑ und Außenbereiche unterscheidet, wie der OutdoorScreen funktioniert und wie die Navigation zwischen den Zonen umgesetzt ist.

Dieser Artikel ist ein wichtiger Schritt, bevor du in den nächsten Artikeln die Wettervorhersage integrierst. Denn die Außensensoren bilden die Brücke zwischen internen Gebäudedaten und externen Wetterdaten. Wenn du verstehst, wie die App mit Zone 2 (Außenbereich) umgeht, wirst du später die Wettervorhersage viel natürlicher in die App einfügen können.

1. Was sind Zonen – und warum braucht die App sie?

Die Gebäudedaten‑App arbeitet mit zwei Zonen:

  • Zone 1: Innenräume
  • Zone 2: Außenbereich

Diese Einteilung ist nicht nur logisch, sondern auch technisch sinnvoll. Innenräume haben typischerweise mehrere Räume, in denen verschiedene Sensoren installiert sind. Der Außenbereich hingegen wird in der App als eine eigene Zone behandelt, die ebenfalls Räume und Sensoren enthalten kann — auch wenn es in der Praxis meist nur einen „Raum“ gibt, z. B. „Außenbereich“.

Die Zonen sind in der Datenbank hinterlegt und werden über die Tabelle zones verwaltet. Jeder Raum gehört zu einer Zone, und jeder Sensor gehört zu einem Raum. Dadurch entsteht eine klare Hierarchie:

Zone → Raum → Sensor → Messwerte

Diese Struktur ist flexibel genug, um später erweitert zu werden — z. B. um weitere Zonen wie „Keller“, „Garage“ oder „Dachboden“.

2. Wie die App Zonen lädt – ein Blick in die Datenbankabfragen

Die Datenbankabfragen für Zonen und Räume sind in services/database/queries.py definiert. Die Abfrage für Räume einer Zone sieht so aus:

SELECT id, name FROM rooms WHERE zone_id=? ORDER BY name ASC

Das bedeutet:

  • Die App lädt alle Räume, deren zone_id der gewünschten Zone entspricht.
  • Die Räume werden alphabetisch sortiert.

Für Zone 1 (Innenbereich) kann es mehrere Räume geben, z. B.:

  • Wohnzimmer
  • Küche
  • Büro
  • Schlafzimmer

Für Zone 2 (Außenbereich) gibt es typischerweise nur einen Raum, z. B.:

  • Außenbereich

Aber die App ist flexibel genug, um mehrere Außenräume zu unterstützen — falls du das später möchtest.

3. Der OutdoorScreen – der Spezialfall für Zone 2

Der OutdoorScreen ist ein eigener Screen, der speziell für die Außensensoren entwickelt wurde. Er funktioniert ähnlich wie der RoomScreen und der SensorScreen, aber mit einem wichtigen Unterschied: Er lädt nicht mehrere Räume, sondern nur den ersten Raum der Zone 2.

Der Code sieht so aus:

zone_id = 2
rooms = get_rooms_by_zone(zone_id)
room_id, room_name = rooms[0]
sensors = get_sensors_by_room(room_id)

Das bedeutet:

  1. Die App lädt alle Räume der Zone 2.
  2. Sie nimmt den ersten Raum aus der Liste.
  3. Sie lädt alle Sensoren dieses Raums.

Warum nur der erste Raum?

Weil die App davon ausgeht, dass der Außenbereich nur einen Raum hat. Das ist in den meisten Fällen sinnvoll — du hast draußen vielleicht einen Temperatursensor, einen Feuchtesensor oder einen Windsensor, aber du wirst selten mehrere „Außenräume“ definieren.

Wenn du später mehrere Außenbereiche unterstützen möchtest, kannst du den OutdoorScreen leicht erweitern. Aber für das aktuelle Projekt ist die Annahme völlig ausreichend.

4. Die Navigation zum OutdoorScreen – ein eigener Button im Startscreen

Der Startscreen bietet drei Buttons:

  • Räume
  • Außensensoren
  • Wettervorhersage

Der Button für die Außensensoren öffnet den OutdoorScreen:

def open_outdoor(self):
    self.manager.current = "outdoor"

Das ist bewusst einfach gehalten. Der OutdoorScreen kümmert sich selbst darum, die richtigen Sensoren zu laden.

5. Wie der OutdoorScreen Sensoren darstellt

Der OutdoorScreen erzeugt für jeden Sensor einen Button — genau wie der SensorScreen. Wenn der Benutzer auf einen Sensor klickt, passiert Folgendes:

  1. Der AppState wird aktualisiert: sm.state.current_sensor_id = sid sm.state.current_sensor_name = sname
  2. Der vorherige Screen wird gespeichert: sm.state.previous_screen = sm.current
  3. Die App wechselt zum Diagramm‑Screen: sm.current = "diagrams"

Der Code ist nahezu identisch mit dem SensorScreen — und das ist gut so. Die App bleibt dadurch konsistent und leicht verständlich.

6. Warum Außensensoren wichtig sind – die Brücke zur Wettervorhersage

Die Außensensoren sind nicht nur ein nettes Extra — sie sind ein wichtiger Bestandteil der App. Sie bilden die Brücke zwischen internen Gebäudedaten und externen Wetterdaten.

Beispiele:

  • Außentemperatur vs. Innentemperatur
  • Außenfeuchte vs. Innenfeuchte
  • Außensensorwerte vs. Wettervorhersage

Wenn du später die Wettervorhersage integrierst, wirst du feststellen, dass die Außensensoren eine natürliche Ergänzung sind. Sie ermöglichen Vergleiche, Analysen und Visualisierungen, die ohne sie nicht möglich wären.

7. Die Rolle des AppState im OutdoorScreen

Der AppState spielt auch im OutdoorScreen eine zentrale Rolle. Er speichert:

  • die aktuelle Zone
  • den aktuellen Raum
  • den ausgewählten Sensor
  • den vorherigen Screen

Dadurch bleibt die Navigation konsistent. Wenn du vom Diagramm‑Screen zurückgehst, landest du wieder im OutdoorScreen — nicht im RoomScreen oder Startscreen.

Das ist wichtig, weil der OutdoorScreen ein eigener Bereich ist, der nicht Teil der normalen Raumstruktur ist.

8. Fehlerbehandlung im OutdoorScreen

Der OutdoorScreen geht davon aus, dass Zone 2 mindestens einen Raum hat. Wenn das nicht der Fall ist, würde die App abstürzen. In der Praxis ist das aber kein Problem, weil die Datenbank beim Initialisieren immer einen Außenraum anlegt.

Wenn du möchtest, kannst du später eine Fehlerbehandlung einbauen — aber für das aktuelle Projekt ist das nicht notwendig.

9. Warum die Zonenlogik so wichtig ist

Die Zonenlogik ist ein zentraler Bestandteil der App. Sie sorgt dafür, dass:

  • Innen‑ und Außenbereiche sauber getrennt sind
  • die Navigation klar und intuitiv bleibt
  • die Datenbankstruktur flexibel bleibt
  • die Wettervorhersage später nahtlos integriert werden kann

Ohne die Zonenlogik wäre die App unübersichtlich und schwer zu erweitern.

10. Fazit: Die Außensensoren sind bereit für die Integration der Wettervorhersage

Nach diesem Artikel verstehst du:

  • wie die Zonenlogik funktioniert
  • wie der OutdoorScreen aufgebaut ist
  • wie die Navigation zwischen Innen‑ und Außenbereichen funktioniert
  • wie der AppState alle Screens verbindet
  • warum Außensensoren wichtig sind
  • wie die App später die Wettervorhersage integrieren kann

Damit bist du perfekt vorbereitet für Artikel 5, in dem du die Wettervorhersage vollständig in die App einbindest.

Artikel 3 – Navigation und Visualisierung stabilisieren: Wie die Gebäudedaten‑App zuverlässig zwischen Screens wechselt und Diagramme erzeugt

Die Gebäudedaten‑App lebt von ihrer klaren Navigation und der Fähigkeit, Sensordaten zuverlässig zu visualisieren. In diesem Artikel tauchst du tief in die Mechanik der Navigation ein und lernst, wie die App zwischen den verschiedenen Screens wechselt, wie der AppState dabei eine zentrale Rolle spielt und wie der Diagramm‑Screen die Messwerte eines Sensors in ein Matplotlib‑Diagramm verwandelt.

Dieser Artikel ist bewusst praxisnah aufgebaut: Du erfährst nicht nur, wie die Navigation funktioniert, sondern auch, warum sie so implementiert wurde und wie sie sich im Zusammenspiel mit der Visualisierung verhält. Am Ende wirst du verstehen, warum die App so stabil läuft und wie du sie später erweitern kannst, ohne die bestehende Struktur zu gefährden.

1. Die Navigation als Rückgrat der App

Die Navigation ist das zentrale Element, das alle Screens miteinander verbindet. Ohne eine saubere Navigation wäre die App schwer zu bedienen und fehleranfällig. Die Gebäudedaten‑App nutzt den ScreenManager von Kivy, um zwischen den verschiedenen Screens zu wechseln. Jeder Screen hat einen eindeutigen Namen, und die App wechselt zwischen ihnen, indem sie self.manager.current setzt.

Beispiel:

self.manager.current = "sensors"

Das klingt einfach — und das ist es auch. Aber die wahre Stärke liegt in der Kombination mit dem AppState. Der AppState speichert alle Informationen, die für die Navigation wichtig sind: die aktuelle Zone, den aktuellen Raum, den ausgewählten Sensor und den vorherigen Screen. Dadurch müssen die Screens nicht direkt miteinander kommunizieren, sondern greifen alle auf denselben Zustand zu.

Warum ist das wichtig?

Stell dir vor, der Diagramm‑Screen müsste wissen, welcher Sensor gerade ausgewählt wurde. Ohne AppState müsstest du diese Information beim Wechsel des Screens übergeben. Das wäre fehleranfällig und würde die Screens enger miteinander verknüpfen.

Mit dem AppState ist das viel einfacher:

  • Der SensorScreen setzt current_sensor_id und current_sensor_name.
  • Der DiagrammScreen liest diese Werte aus.
  • Der RoomScreen setzt current_room_id und current_room_name.
  • Der SensorScreen liest diese Werte aus.

So entsteht eine lose Kopplung, die die App flexibel macht.

2. Der SensorScreen – das Bindeglied zwischen Raum und Diagramm

Der SensorScreen ist einer der wichtigsten Screens der App. Er zeigt alle Sensoren eines Raums an und ermöglicht es dem Benutzer, einen Sensor auszuwählen, um dessen Messwerte zu visualisieren. Die Logik ist klar strukturiert und leicht verständlich.

Der SensorScreen lädt die Sensoren eines Raums über die Datenbankabfrage:

sensors = get_sensors_by_room(room_id)

Für jeden Sensor wird ein Button erzeugt. Wenn der Benutzer auf einen Button klickt, passiert Folgendes:

  1. Der AppState wird aktualisiert: sm.state.current_sensor_id = sid sm.state.current_sensor_name = sname
  2. Der vorherige Screen wird gespeichert: sm.state.previous_screen = sm.current
  3. Die App wechselt zum Diagramm‑Screen: sm.current = "diagrams"

Der Code sieht so aus:

def refresh_sensors(self):
    sensors = get_sensors_by_room(room_id)
    for sensor_id, name, sensor_type in sensors:
        btn = Button(...)
        def on_release(...):
            sm.state.current_sensor_id = sid
            sm.state.current_sensor_name = sname
            sm.state.previous_screen = sm.current
            sm.current = "diagrams"

Warum ist diese Struktur so effektiv?

  • Die Buttons werden dynamisch erzeugt.
  • Die Navigation ist klar und nachvollziehbar.
  • Der AppState hält alle relevanten Informationen bereit.
  • Der Diagramm‑Screen muss keine Parameter entgegennehmen.

Diese Struktur ist robust und leicht erweiterbar.


3. Der Diagramm‑Screen – Visualisierung der Messwerte

Der Diagramm‑Screen ist das Herzstück der Visualisierung. Er lädt die Messwerte eines Sensors aus der Datenbank und erzeugt ein Diagramm mit Matplotlib. Die Logik ist bewusst einfach gehalten, damit du sie leicht verstehen und später erweitern kannst.

Der Diagramm‑Screen liest die Sensorinformationen aus dem AppState:

sensor_id = state.current_sensor_id
sensor_name = state.current_sensor_name or "Diagramm"

Wenn kein Sensor ausgewählt wurde, wird kein Diagramm angezeigt.

Das Laden des Diagramms

Der Diagramm‑Screen ruft den diagram_service auf:

path = create_sensor_diagram(sensor_id, sensor_name)

Wenn ein Fehler auftritt, wird das Diagramm zurückgesetzt:

except Exception as e:
    self.ids.diagram_image.source = ""
    return

Anschließend wird das Bild neu geladen:

self.ids.diagram_image.source = path
self.ids.diagram_image.reload()

4. Der DiagrammService – Matplotlib in Kivy integrieren

Der DiagrammService ist für die Erstellung der Diagramme verantwortlich. Er verwendet Matplotlib, um ein einfaches Liniendiagramm zu erzeugen. Die Diagramme werden transparent gespeichert, damit sie sich gut in das UI einfügen.

Der Code sieht so aus:

fig, ax = plt.subplots(figsize=(6, 3), dpi=100)
ax.plot(timestamps, values, color=color, linewidth=1.8)
fig.savefig(path, transparent=True)

Warum transparente Diagramme?

  • Sie passen sich dem Hintergrund an.
  • Sie wirken moderner und leichter.
  • Sie lassen sich besser in dunkle Themes integrieren.

Farbwahl basierend auf dem Sensortyp

Der DiagrammService wählt die Farbe basierend auf dem Sensornamen:

color = "blue" if "feuchte" in sensor_name.lower() else "red"

Das ist eine einfache, aber effektive Methode, um die Diagramme visuell zu unterscheiden.

5. Die Rolle des AppState im Diagramm‑Screen

Der AppState spielt im Diagramm‑Screen eine zentrale Rolle. Er sorgt dafür, dass der Diagramm‑Screen immer weiß, welcher Sensor gerade ausgewählt wurde. Ohne den AppState müsstest du die Sensorinformationen beim Wechsel des Screens übergeben — das wäre fehleranfällig und würde die Screens enger miteinander verknüpfen.

Mit dem AppState ist das viel einfacher:

  • Der SensorScreen setzt die Sensorinformationen.
  • Der DiagrammScreen liest sie aus.
  • Der OutdoorScreen setzt die Zone.
  • Der RoomScreen liest sie aus.

Diese Struktur ist robust und leicht erweiterbar.

6. Fehlerbehandlung im Diagramm‑Screen

Die Fehlerbehandlung im Diagramm‑Screen ist bewusst einfach gehalten. Wenn ein Fehler auftritt, wird das Diagramm zurückgesetzt:

except Exception as e:
    self.ids.diagram_image.source = ""
    return

Das ist wichtig, weil die Diagrammerstellung fehlschlagen kann, wenn:

  • keine Messwerte vorhanden sind
  • der Sensor keine Daten hat
  • die Datenbank leer ist

Durch die einfache Fehlerbehandlung bleibt die App stabil und reagiert vorhersehbar.

7. Die Navigation zurück – previous_screen

Der previous_screen im AppState sorgt dafür, dass du jederzeit zurückspringen kannst. Der Diagramm‑Screen verwendet ihn, um den vorherigen Screen wiederherzustellen:

prev = self.manager.state.previous_screen
if prev:
    self.manager.current = prev

Das ist eine einfache, aber effektive Methode, um eine konsistente Navigation zu gewährleisten.

8. Warum diese Struktur so stabil ist

Die Kombination aus:

  • ScreenManager
  • AppState
  • klaren Datenbankabfragen
  • sauberer Trennung von Logik und Layout
  • einfacher Fehlerbehandlung
  • dynamischer UI‑Erzeugung

macht die App extrem stabil. Du kannst sie problemlos erweitern, ohne die bestehende Struktur zu gefährden.

Fazit: Die Navigation und Visualisierung sind bereit für die nächsten Schritte

Nach diesem Artikel verstehst du:

  • wie die Navigation funktioniert
  • wie der SensorScreen aufgebaut ist
  • wie der DiagrammScreen Diagramme erzeugt
  • wie der DiagrammService arbeitet
  • wie der AppState alle Screens verbindet
  • warum die App so stabil läuft

Damit bist du perfekt vorbereitet für Artikel 4, in dem du die Außensensoren und die Zonenlogik im Detail betrachtest.

Artikel 2 – Grundlagen der Gebäudedaten‑App: Architektur, Datenbank, Navigation und KV‑Layouts

Die Gebäudedaten‑App, die du in dieser Serie weiterentwickelst, ist ein hervorragendes Beispiel für eine klar strukturierte Kivy‑Anwendung. Bevor du neue Funktionen einbaust oder die App mit der Wettervorhersage kombinierst, lohnt es sich, die bestehenden Grundlagen noch einmal bewusst zu betrachten. Dieser Artikel führt dich durch die wichtigsten Bausteine der App: die Architektur, die Datenbank, die Navigation über den AppState, die KV‑Layouts und die grundlegenden Services.

Das Ziel dieses Artikels ist, dass du die Struktur der App vollständig verstehst, bevor du in den nächsten Artikeln tiefer in die Navigation, die Visualisierung und die Integration der Wettervorhersage einsteigst.

1. Die Architektur der App – ein bewusst modularer Aufbau

Die Gebäudedaten‑App ist in mehrere klar getrennte Bereiche gegliedert. Diese Trennung ist kein Zufall, sondern folgt einem Prinzip, das du in professionellen Softwareprojekten immer wieder findest: Separation of Concerns. Jede Komponente hat eine klar definierte Aufgabe, und die App bleibt dadurch übersichtlich und erweiterbar.

Die wichtigsten Bereiche sind:

  • screens/ – enthält die UI‑Logik
  • services/ – enthält Datenbankzugriffe, Sensorlogik, Diagrammerstellung
  • ui/ – enthält die KV‑Layouts
  • weatherapp/ – enthält die Wettervorhersage‑App
  • app.py – Einstiegspunkt
  • services/state.py – zentraler Navigationszustand

Diese Struktur sorgt dafür, dass du jederzeit weißt, wo du etwas findest. Wenn du etwas am UI ändern möchtest, gehst du in den ui/‑Ordner. Wenn du die Datenbankabfragen anpassen möchtest, findest du sie in services/database/queries.py. Wenn du die Navigation erweitern möchtest, schaust du in den AppState.

2. Der AppState – das zentrale Bindeglied zwischen allen Screens

Der AppState ist eines der wichtigsten Elemente der App. Er speichert alle Informationen, die für die Navigation relevant sind. Dadurch müssen die Screens nicht direkt miteinander kommunizieren, sondern greifen alle auf denselben Zustand zu. Das macht die App flexibel und verhindert enge Kopplungen zwischen den Screens.

Der Code sieht so aus:

class AppState:
    def __init__(self):
        self.current_zone_id = None
        self.current_room_id = None
        self.current_room_name = ""
        self.current_sensor_id = None
        self.current_sensor_name = ""
        self.previous_screen = None

Dieser Zustand wird in app.py einmal erzeugt und dem ScreenManager zugewiesen:

sm.state = AppState()

Ab diesem Moment kann jeder Screen über self.manager.state auf den Zustand zugreifen.

Warum ist das wichtig?

Stell dir vor, der Diagramm‑Screen müsste wissen, welcher Sensor gerade ausgewählt wurde. Ohne AppState müsstest du diese Information beim Wechsel des Screens übergeben. Das wäre fehleranfällig und würde die Screens enger miteinander verknüpfen.

Mit dem AppState ist das viel einfacher:

  • Der SensorScreen setzt current_sensor_id und current_sensor_name.
  • Der DiagrammScreen liest diese Werte aus.
  • Der OutdoorScreen setzt current_zone_id.
  • Der RoomScreen liest diese Werte aus.

So entsteht eine lose Kopplung, die die App flexibel macht.

3. Die Datenbank – das Herz der Gebäudedaten

Die Gebäudedaten‑App verwendet eine SQLite‑Datenbank, die über init_db.py erzeugt wird. SQLite ist ideal für lokale Anwendungen, weil es keine Installation benötigt und die Daten in einer einzigen Datei speichert.

Die Verbindung wird über eine einfache Funktion hergestellt:

def get_connection() -> sqlite3.Connection:
    DB_PATH.parent.mkdir(parents=True, exist_ok=True)
    return sqlite3.connect(DB_PATH)

Diese Funktion stellt sicher, dass der Ordner existiert und öffnet dann die Datenbankdatei.

Die Tabellenstruktur

Die Datenbank enthält vier Tabellen:

  • zones – z. B. Innenbereich, Außenbereich
  • rooms – Räume innerhalb einer Zone
  • sensors – Sensoren innerhalb eines Raums
  • readings – Messwerte eines Sensors

Diese Struktur ist bewusst einfach gehalten, aber sie bildet die Grundlage für die gesamte App.

Die Abfragen

Die Abfragen sind in services/database/queries.py definiert. Sie sind klar strukturiert und leicht verständlich.

Beispiel: Räume einer Zone laden:

SELECT id, name FROM rooms WHERE zone_id=? ORDER BY name ASC

Sensoren eines Raums:

SELECT id, name, type FROM sensors WHERE room_id=? ORDER BY name ASC

Messwerte eines Sensors:

SELECT timestamp, value FROM readings WHERE sensor_id=? ORDER BY timestamp ASC LIMIT ?

Diese Abfragen bilden die Grundlage für die Visualisierung.

4. Die KV‑Layouts – das visuelle Fundament der App

Kivy trennt Logik und Layout, und das ist einer der größten Vorteile des Frameworks. Die Layouts liegen in eigenen .kv‑Dateien im Ordner ui/.

Jeder Screen lädt seine KV‑Datei über einen absoluten Pfad:

KV_PATH = Path(__file__).resolve().parent.parent / "ui" / "rooms.kv"
Builder.load_file(str(KV_PATH))

Das ist wichtig, weil Kivy sonst versucht, die KV‑Datei relativ zum aktuellen Arbeitsverzeichnis zu laden — und das kann je nach Startmethode variieren.

Warum absolute Pfade?

  • Die App funktioniert unabhängig vom Startverzeichnis.
  • Die KV‑Dateien können überall im Projekt liegen.
  • Die Struktur bleibt stabil, auch wenn du später etwas verschiebst.
# ui/rooms.kv
#:set BG_COLOR (0.388, 0.569, 0.659, 1)
#:set BG_COLOR_DARK (0.30, 0.45, 0.52, 1)

<RoomScreen>:
    name: "rooms"

    canvas.before:
        Color:
            rgba: BG_COLOR
        Rectangle:
            pos: self.pos
            size: self.size

    BoxLayout:
        orientation: "vertical"
        padding: 20
        spacing: 20

        Label:
            text: "Räume"
            font_size: "26sp"
            color: 1, 1, 1, 1
            size_hint_y: None
            height: 50

        ScrollView:
            GridLayout:
                id: room_list
                cols: 1
                spacing: 10
                size_hint_y: None
                height: self.minimum_height

        Button:
            text: "Zurück"
            size_hint_y: None
            height: 50
            background_color: BG_COLOR_DARK
            on_release: root.manager.current = "start"

Beispiel: rooms.kv

Die Datei definiert das Layout des RoomScreens. Sie enthält:

  • eine Überschrift
  • eine Liste von Buttons für die Räume
  • einen Zurück‑Button

Die Logik liegt im Python‑Code, das Layout in der KV‑Datei — eine klare Trennung.

5. Die Services – Logik und Daten getrennt vom UI

Die Services sind ein weiterer wichtiger Bestandteil der App. Sie sorgen dafür, dass die UI‑Screens schlank bleiben und sich auf die Darstellung konzentrieren können.

Der SensorService

Der SensorService erzeugt Zufallswerte, um die Live‑Aktualisierung zu simulieren:

value = random.uniform(19.0, 24.0)
timestamp = datetime.now().isoformat(timespec="seconds")

Diese Werte werden in die Datenbank geschrieben und später im Diagramm angezeigt.

Der DiagrammService

Der DiagrammService erzeugt ein einfaches Liniendiagramm mit Matplotlib:

fig, ax = plt.subplots(figsize=(6, 3), dpi=100)
ax.plot(timestamps, values, color=color, linewidth=1.8)
fig.savefig(path, transparent=True)

Die Diagramme werden transparent gespeichert, damit sie sich gut in das UI einfügen.

6. Die Navigation – wie die Screens zusammenarbeiten

Die Navigation erfolgt über den ScreenManager. Jeder Screen hat einen Namen, und die App wechselt zwischen den Screens, indem sie sm.current setzt.

Beispiel:

self.manager.current = "sensors"

Der previous_screen im AppState sorgt dafür, dass du jederzeit zurückspringen kannst.

Warum ist das wichtig?

  • Die Navigation bleibt konsistent.
  • Jeder Screen weiß, woher er kommt.
  • Der Zurück‑Button funktioniert zuverlässig.

7. Die Wettervorhersage‑App – bereit für die Integration

Die Wettervorhersage‑App ist ein eigenständiges Projekt, das du später integrieren wirst. Sie ist modular aufgebaut und bringt eigene Screens, Services und Layouts mit.

Der ForecastScreen wird in app.py einfach hinzugefügt:

weather_settings = Settings()
sm.add_widget(ForecastScreen(settings=weather_settings, name="weather"))

Damit ist die Wettervorhersage technisch bereits Teil der App — sie muss nur noch logisch eingebunden werden.

Fazit: Die Grundlage steht

Nach diesem Artikel hast du ein tiefes Verständnis der bestehenden Gebäudedaten‑App:

  • du kennst die Architektur
  • du verstehst die Rolle des AppState
  • du weißt, wie die Datenbank aufgebaut ist
  • du kennst die KV‑Layouts
  • du verstehst die Services
  • du weißt, wie die Navigation funktioniert
  • du weißt, wie die Wetter‑App integriert wird

Damit bist du perfekt vorbereitet für Artikel 3, in dem du die Navigation und Visualisierung stabilisierst und die App robuster machst.

Artikel 1 – Projektstart: Überblick über die Gebäudedaten‑App und Ziel der Erweiterung

Die Gebäudedaten‑App, die du in den bisherigen Tutorials entwickelt hast, ist ein hervorragendes Beispiel für eine klar strukturierte, modular aufgebaute Kivy‑Anwendung. Sie zeigt, wie du Räume, Sensoren und Messwerte aus einer SQLite‑Datenbank laden und visuell darstellen kannst. Gleichzeitig ist sie ein ideales Fundament für Erweiterungen, weil sie bereits eine saubere Trennung zwischen UI, Logik und Datenhaltung besitzt. In dieser neuen Artikelserie wirst du die App nicht nur weiterentwickeln, sondern sie auch mit einer vollständigen Wettervorhersage‑App kombinieren, die du ebenfalls schon erstellt hast. Dadurch entsteht eine Anwendung, die sowohl interne Gebäudedaten als auch externe Wetterdaten in einer gemeinsamen Oberfläche präsentiert.

Dieser erste Artikel dient als Einstieg und Überblick. Du lernst die bestehende Struktur noch einmal bewusst kennen, verstehst die Rolle der einzelnen Module und bekommst ein Gefühl dafür, wie die beiden Projekte später zusammengeführt werden. Gleichzeitig legst du die Grundlage für die kommenden Artikel, in denen du tiefer in die Navigation, die Datenbank, die Diagrammerstellung und die Integration der Wettervorhersage eintauchst.

Warum diese Serie wichtig ist

Bevor wir in die technischen Details einsteigen, lohnt sich ein Blick auf das „Warum“. Die Gebäudedaten‑App ist bereits funktional, aber sie ist noch nicht das, was man als „Dashboard“ bezeichnen würde. Sie zeigt Messwerte an, aber sie vergleicht sie nicht mit externen Daten. Sie visualisiert Sensorwerte, aber sie bietet keine Möglichkeit, diese in einen größeren Kontext zu setzen. Genau hier setzt die Erweiterung an.

Durch die Integration der Wettervorhersage‑App entsteht eine Anwendung, die:

  • interne Sensordaten (z. B. Temperatur, Feuchte)
  • externe Wetterdaten (z. B. Außentemperatur, Wind, Regen)
  • und eine klare, einheitliche Navigation

in einem einzigen System vereint.

Das ist nicht nur praktisch, sondern auch ein realistisches Szenario für Smart‑Home‑Anwendungen, Energiemonitoring oder Gebäudeautomation. Die App wird dadurch zu einem echten Werkzeug, das du später beliebig erweitern kannst.

Die bestehende Gebäudedaten‑App im Überblick

Die Gebäudedaten‑App basiert auf einer einfachen, aber sehr effektiven Navigationsstruktur:

  1. Startscreen
    Von hier aus gelangst du zu allen Bereichen der App.
  2. RoomScreen
    Zeigt alle Räume einer Zone an.
  3. SensorScreen
    Zeigt alle Sensoren eines Raums an.
  4. DiagramScreen
    Visualisiert die Messwerte eines Sensors.
  5. OutdoorScreen
    Zeigt die Sensoren der Außen‑Zone (Zone 2).

Diese Struktur ist bewusst linear gehalten, damit sie leicht verständlich ist. Gleichzeitig ist sie flexibel genug, um später erweitert zu werden — zum Beispiel durch zusätzliche Screens oder neue Datenquellen.

[Screenshot einfügen: Navigationsfluss der Gebäudedaten‑App]

Die Wettervorhersage‑App im Überblick

Die Wettervorhersage‑App ist ein eigenständiges Projekt, das du bereits vollständig entwickelt hast. Sie besteht aus:

  • einem ForecastScreen
  • einem WeatherReader
  • einem WeatherApiClient
  • einem WeatherParser
  • einem Icon‑Downloader
  • einer eigenen KV‑Datei für das Layout

Diese App ist modular aufgebaut und lässt sich ohne Änderungen in andere Projekte integrieren. Genau das wirst du in dieser Serie tun.

Die gemeinsame Projektstruktur

Wenn du beide Projekte zusammenführst, entsteht eine Struktur wie diese:

project/
│
├── screens/
│   ├── start_screen.py
│   ├── room_screen.py
│   ├── sensor_screen.py
│   ├── diagram_screen.py
│   └── outdoor_screen.py
│
├── services/
│   ├── database/
│   │   ├── core.py
│   │   ├── init_db.py
│   │   └── queries.py
│   ├── sensor_service.py
│   ├── diagram_service.py
│   └── state.py
│
├── ui/
│   ├── start.kv
│   ├── rooms.kv
│   ├── sensors.kv
│   ├── diagram.kv
│   └── outdoor.kv
│
├── weatherapp/
│   ├── screens/
│   │   └── forecast_screen.py
│   ├── services/
│   │   ├── weather_reader.py
│   │   ├── weather_api_client.py
│   │   └── weather_parser.py
│   ├── ui/
│   │   └── visualizer.kv
│   └── config/
│       └── settings.py
│
└── app.py

Diese Struktur ist klar, modular und leicht verständlich. Jeder Bereich hat seine eigene Aufgabe, und die Dateien sind logisch gruppiert. Das macht es einfach, die App zu erweitern, zu warten oder zu debuggen.

Der Einstiegspunkt: app.py

Die Datei app.py ist der zentrale Einstiegspunkt der Anwendung. Hier wird der ScreenManager erstellt, der AppState initialisiert und alle Screens registriert. Der Code ist übersichtlich und zeigt, wie modular die App bereits aufgebaut ist:

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, NoTransition

from screens.start_screen import StartScreen
from screens.room_screen import RoomScreen
from screens.sensor_screen import SensorScreen
from screens.diagram_screen import DiagramScreen
from screens.outdoor_screen import OutdoorScreen

from weatherapp.config.settings import Settings
from weatherapp.screens.forecast_screen import ForecastScreen

from services.state import AppState

class BuildingApp(App):
    def build(self):
        sm = ScreenManager(transition=NoTransition())
        sm.state = AppState()

        sm.add_widget(StartScreen(name="start"))
        sm.add_widget(RoomScreen(name="rooms"))
        sm.add_widget(SensorScreen(name="sensors"))
        sm.add_widget(DiagramScreen(name="diagrams"))
        sm.add_widget(OutdoorScreen(name="outdoor"))

        weather_settings = Settings()
        sm.add_widget(ForecastScreen(settings=weather_settings, name="weather"))

        return sm

if __name__ == "__main__":
    BuildingApp().run()

Weiterführender Code auf GitHub

Wenn du den vollständigen Quellcode der Gebäudedaten‑App einsehen möchtest, findest du das komplette Projekt auf meinem GitHub‑Repository. Dort kannst du alle Module, Screens, Services und KV‑Layouts im Detail nachvollziehen, eigene Anpassungen vornehmen oder das Projekt direkt klonen.

➡️ GitHub‑Repository ansehen: https://github.com/HaikoKrais/BuildingDataVisualizer

Das Repository enthält die gesamte App‑Struktur, inklusive der Wettervorhersage‑Integration, der Datenbankmodule, der Diagrammerstellung und aller UI‑Layouts. Es eignet sich ideal, um die Inhalte dieser Artikelserie praktisch nachzuvollziehen oder als Grundlage für eigene Erweiterungen zu nutzen.

Dieser Code ist der Ausgangspunkt für die gesamte Serie. Du wirst ihn nicht verändern müssen, sondern lediglich die dahinterliegenden Module und Screens erweitern und erklären. Am Ende dieser Serie hast du eine App, die sowohl Gebäudedaten als auch Wetterdaten übersichtlich darstellt und deren Struktur so modular ist, dass du sie jederzeit erweitern kannst.

Was dich in den nächsten Artikeln erwartet

In den kommenden Artikeln wirst du:

  • die Navigation verbessern
  • die Sensor‑ und Diagramm‑Screens stabilisieren
  • die Außensensoren logisch integrieren
  • die Wettervorhersage vollständig einbinden
  • die Datenbankabfragen im Detail verstehen
  • die Diagrammerstellung analysieren
  • die Architektur als Ganzes betrachten

Jeder Artikel baut auf dem vorherigen auf und führt dich Schritt für Schritt durch die Erweiterung der App.