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_idundcurrent_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.