odoo_mqtt/docs/OPTIMIZATION_PLAN.md
2026-03-17 21:22:22 +01:00

36 KiB

IoT Bridge - Optimization Plan

Projekt: IoT MQTT Bridge Code-Qualität & Wartbarkeit
Version: 1.0
Datum: 18. Februar 2026
Status: 🚧 In Umsetzung (Phase 0-1 abgeschlossen, Phase 2 weitgehend umgesetzt)


🎯 Projektziele

  1. Code-Qualität verbessern ohne Funktionalitätsverlust
  2. Wartbarkeit erhöhen durch bessere Struktur
  3. Testabdeckung erweitern für kritische Komponenten
  4. Kompatibilität mit Odoo-Modul vollständig erhalten
  5. Performance durch gezielte Optimierungen steigern

📋 Grundprinzipien

  • Backward-Kompatibilität: Keine Breaking Changes für Odoo-Integration
  • Inkrementell: Kleine, testbare Änderungen
  • Test-First: Jede Änderung wird durch Tests abgesichert
  • Dokumentation: Code-Änderungen werden dokumentiert
  • Review-Ready: Commits sind atomar und nachvollziehbar

🗓️ Projektphasen

Phase 0: Verzeichnisstruktur ⏱️ ~2-3 Stunden

Ziel: Klare, logische Verzeichnisstruktur für besseren Überblick

Phase 1: Foundation & Quality Tools ⏱️ ~4-6 Stunden

Ziel: Test-Infrastruktur und Code-Quality-Tools etablieren

Phase 2: Code Organization ⏱️ ~6-8 Stunden

Ziel: Code-Struktur verbessern, Verantwortlichkeiten klären

Phase 3: Type Safety & Error Handling ⏱️ ~4-5 Stunden

Ziel: Type Hints vervollständigen, robuste Fehlerbehandlung

Phase 4: Testing & Documentation ⏱️ ~6-8 Stunden

Ziel: Test-Coverage erhöhen, Dokumentation verbessern

Phase 5: Performance & Observability ⏱️ ~4-6 Stunden

Ziel: Performance optimieren, Monitoring verbessern


📦 Phase 0: Verzeichnisstruktur

Status: ABGESCHLOSSEN
Aufwand: ~2 Stunden (erwartet: 2-3h)
Priorität: 🔴 Hoch (Fundament für alle anderen Phasen)
Abhängigkeiten: Keine
Git-Commit: a5929ed

Motivation

Eine klare Verzeichnisstruktur:

  • Verbessert die Übersichtlichkeit
  • Erleichtert Navigation im Code
  • Trennt Verantwortlichkeiten (Separation of Concerns)
  • Macht Abhängigkeiten explizit
  • Vorbereitung für zukünftige Erweiterungen (z.B. weitere Parser)

Ziel-Struktur

iot_bridge/
├── main.py                      # Entry Point (bleibt im Root)
├── requirements.txt
├── Dockerfile
├── config.yaml
├── config.example.yaml
│
├── core/                        # ✨ NEU - Kern-Logik
│   ├── __init__.py
│   ├── session_detector.py      # State Machine
│   ├── event_queue.py           # Event Queue mit Retry
│   └── device_manager.py        # Device Lifecycle Management
│
├── clients/                     # ✨ NEU - External Integrations
│   ├── __init__.py
│   ├── mqtt_client.py           # MQTT Broker Client
│   └── odoo_client.py           # Odoo REST API Client
│
├── parsers/                     # ✨ NEU - Message Parser
│   ├── __init__.py
│   ├── base.py                  # ✨ NEU - Parser Protocol/Base Class
│   ├── shelly_parser.py         # Shelly PM Parser
│   └── tasmota_parser.py        # ✨ Placeholder für zukünftige Parser
│
├── api/                         # ✨ NEU - HTTP API
│   ├── __init__.py
│   ├── server.py                # FastAPI App (von config_server.py)
│   └── models.py                # ✨ NEU - Pydantic Models separiert
│
├── config/                      # ✨ NEU - Configuration
│   ├── __init__.py
│   ├── schema.py                # Config Schema (von config.py)
│   └── loader.py                # Config Loader (von config.py)
│
├── utils/                       # ✨ NEU - Utilities
│   ├── __init__.py
│   ├── logging.py               # Logger Setup (von logger_setup.py)
│   └── status_monitor.py        # Device Status Monitor
│
├── tests/                       # Tests (bestehend, erweitert)
│   ├── conftest.py
│   ├── fixtures/
│   ├── unit/
│   ├── integration/
│   └── tools/
│
└── logs/                        # Log files

Aufgaben

0.1 Verzeichnisse erstellen

Aufwand: 5 Minuten

Aufgaben:

  • mkdir -p core clients parsers api config utils
  • touch core/__init__.py clients/__init__.py parsers/__init__.py api/__init__.py config/__init__.py utils/__init__.py

Erfolgskriterien:

  • Alle Verzeichnisse existieren
  • __init__.py in jedem Verzeichnis

0.2 Core-Module verschieben

Aufwand: 30 Minuten

Aufgaben:

  • session_detector.pycore/session_detector.py
  • event_queue.pycore/event_queue.py
  • device_manager.pycore/device_manager.py
  • Imports in allen Dateien anpassen:
    • from session_detector importfrom core.session_detector import
    • from event_queue importfrom core.event_queue import
    • from device_manager importfrom core.device_manager import

Betroffene Dateien:

  • main.py
  • tests/unit/test_*.py
  • tests/integration/test_*.py

Erfolgskriterien:

  • python main.py --config config.yaml startet ohne ImportError
  • pytest tests/ läuft durch

0.3 Client-Module verschieben

Aufwand: 20 Minuten

Aufgaben:

  • mqtt_client.pyclients/mqtt_client.py
  • odoo_client.pyclients/odoo_client.py
  • Imports anpassen:
    • from mqtt_client importfrom clients.mqtt_client import
    • from odoo_client importfrom clients.odoo_client import

Betroffene Dateien:

  • main.py
  • core/device_manager.py
  • Tests

Erfolgskriterien:

  • Bridge startet ohne Fehler
  • MQTT-Connection funktioniert
  • Tests laufen durch

0.4 Parser-Module verschieben & erweitern

Aufwand: 40 Minuten

Aufgaben:

  • parsers/base.py erstellen mit Parser-Protocol/Base-Class
  • shelly_parser.pyparsers/shelly_parser.py
  • shelly_parser.py von base.py ableiten
  • parsers/tasmota_parser.py als Placeholder erstellen (skip - nicht benötigt)
  • Imports anpassen:
    • from shelly_parser importfrom parsers.shelly_parser import

parsers/base.py:

"""Base parser interface for MQTT message parsers."""
from typing import Protocol, Dict, Optional
from abc import ABC, abstractmethod

class MessageParser(Protocol):
    """Protocol for message parsers."""
    
    def parse_message(self, topic: str, payload: dict) -> Optional[Dict]:
        """Parse MQTT message to standardized format."""
        ...

class BaseParser(ABC):
    """Base class for message parsers with common utilities."""
    
    @abstractmethod
    def parse_message(self, topic: str, payload: dict) -> Optional[Dict]:
        """Parse MQTT message. Must be implemented by subclasses."""
        pass
    
    def _extract_device_id(self, topic: str) -> str:
        """Extract device ID from topic (override if needed)."""
        parts = topic.split('/')
        return parts[0] if parts else "unknown"

Betroffene Dateien:

  • core/device_manager.py
  • Tests

Erfolgskriterien:

  • Shelly-Parser funktioniert wie vorher
  • Base-Class ist für neue Parser wiederverwendbar

0.5 API-Module verschieben & aufteilen

Aufwand: 30 Minuten

Aufgaben:

  • config_server.pyapi/server.py (FastAPI-App)
  • Pydantic-Models in api/models.py extrahieren
  • Imports anpassen:
    • from config_server importfrom api.server import
    • from config_server import BridgeConfigfrom api.models import BridgeConfig

api/models.py (NEU):

"""Pydantic models for API validation."""
from pydantic import BaseModel, Field, validator
from typing import List, Optional

class MqttConfig(BaseModel):
    """MQTT Broker configuration."""
    broker: str = Field("localhost")
    port: int = Field(1883)
    # ... rest der Models von config_server.py

Betroffene Dateien:

  • main.py
  • Tests

Erfolgskriterien:

  • HTTP-API funktioniert (/health, /config)
  • Config-Push von Odoo funktioniert
  • Pydantic-Validation unverändert

0.6 Config-Module verschieben & aufteilen

Aufwand: 30 Minuten

Aufgaben:

  • config.py aufteilen:
    • Dataclasses → config/schema.py
    • Loader-Functions → config/loader.py
  • Imports anpassen:
    • from config import load_configfrom config.loader import load_config
    • from config import BridgeConfigfrom config.schema import BridgeConfig

config/init.py:

"""Configuration package."""
from config.schema import (
    MQTTConfig,
    OdooConfig,
    LoggingConfig,
    SessionConfig,
    DeviceConfig,
    BridgeConfig,
)
from config.loader import load_config, load_devices_from_config

__all__ = [
    "MQTTConfig",
    "OdooConfig",
    "LoggingConfig",
    "SessionConfig",
    "DeviceConfig",
    "BridgeConfig",
    "load_config",
    "load_devices_from_config",
]

Betroffene Dateien:

  • main.py
  • api/server.py
  • Tests

Erfolgskriterien:

  • Config-Loading funktioniert
  • YAML-Parsing unverändert
  • Backward-Kompatibilität zu bestehenden config.yaml

0.7 Utils-Module verschieben

Aufwand: 15 Minuten

Aufgaben:

  • logger_setup.pyutils/logging.py
  • device_status_monitor.pyutils/status_monitor.py
  • Imports anpassen:
    • from logger_setup importfrom utils.logging import
    • from device_status_monitor importfrom utils.status_monitor import

Betroffene Dateien:

  • main.py
  • core/device_manager.py

Erfolgskriterien:

  • Logging funktioniert
  • Status-Monitor funktioniert

0.8 Import-Cleanup & init.py befüllen

Aufwand: 20 Minuten

Aufgaben:

  • Alle __init__.py befüllen mit Public API
  • Relative Imports innerhalb Packages nutzen
  • Absolute Imports von außen

Beispiel core/init.py:

"""Core business logic for IoT Bridge."""
from core.session_detector import SessionDetector
from core.event_queue import EventQueue, QueuedEvent
from core.device_manager import DeviceManager

__all__ = [
    "SessionDetector",
    "EventQueue",
    "QueuedEvent",
    "DeviceManager",
]

main.py imports werden:

# Vorher:
from config import load_config
from logger_setup import setup_logging
from odoo_client import MockOdooClient, OdooClient
from mqtt_client import MQTTClient
from session_detector import SessionDetector
from event_queue import EventQueue
from config_server import ConfigServer, BridgeConfig
from device_manager import DeviceManager
from device_status_monitor import DeviceStatusMonitor

# Nachher:
from config import load_config
from config.schema import BridgeConfig
from utils.logging import setup_logging
from clients.odoo_client import MockOdooClient, OdooClient
from clients.mqtt_client import MQTTClient
from core import SessionDetector, EventQueue, DeviceManager
from api.server import ConfigServer
from api.models import BridgeConfig as ApiBridgeConfig
from utils.status_monitor import DeviceStatusMonitor

Erfolgskriterien:

  • Imports sind konsistent
  • Keine zirkulären Imports
  • IDE/Editor zeigt korrekte Auto-Completion

0.9 Tests aktualisieren

Aufwand: 20 Minuten

Aufgaben:

  • Alle Test-Imports anpassen
  • Test-Fixtures auf neue Struktur anpassen
  • pytest tests/ durchlaufen lassen (Syntax validiert, pytest nicht installiert)

Erfolgskriterien:

  • Alle Tests laufen durch
  • Keine ImportErrors
  • Test-Coverage unverändert

0.10 Dokumentation aktualisieren

Aufwand: 10 Minuten

Aufgaben:

  • README.md "Project Structure" Sektion aktualisieren
  • Import-Beispiele im Code aktualisieren
  • git mv Commits mit aussagekräftigen Messages

Erfolgskriterien:

  • README.md zeigt neue Struktur
  • Git-History ist nachvollziehbar

Migrations-Strategie

Git-Workflow:

# 1. Feature-Branch
git checkout -b refactor/phase0-directory-structure

# 2. Verzeichnisse erstellen
mkdir -p core clients parsers api config utils
# __init__.py files...

# 3. Git mv (erhält History!)
git mv session_detector.py core/
git mv event_queue.py core/
git mv device_manager.py core/
git commit -m "refactor: Move core modules to core/ directory"

git mv mqtt_client.py clients/
git mv odoo_client.py clients/
git commit -m "refactor: Move client modules to clients/ directory"

# ... usw. für jeden Schritt

# 4. Imports anpassen
# ... Code-Änderungen ...
git commit -m "refactor: Update imports for new directory structure"

# 5. Tests anpassen
# ... Test-Änderungen ...
git commit -m "test: Update test imports for new structure"

# 6. Final verification
pytest tests/
python main.py --help

Rollback-Plan:

# Falls etwas schiefgeht:
git reset --hard origin/main

Erfolgskriterien Gesamt

  • Alle Module in logischen Verzeichnissen
  • pytest tests/ - Alle Tests grün
  • python main.py --config config.yaml - Bridge startet
  • MQTT-Connection funktioniert
  • Config-Push von Odoo funktioniert
  • Health-Endpoint erreichbar (curl localhost:8080/health)
  • Docker-Build erfolgreich: docker build -t iot_bridge:test .
  • Git-History sauber (git mv verwendet)

Kompatibilität

Keine Breaking Changes:

  • API-Endpoints unverändert (/health, /config)
  • Config-File-Format (config.yaml) kompatibel
  • ENV-Variablen funktionieren weiter
  • Docker-Image-Build unverändert
  • Odoo-Integration unberührt

⚠️ Nur intern geändert:

  • Python-Import-Paths (nur relevant für Entwickler)
  • Test-Imports (werden angepasst)

Vorteile der neuen Struktur

  1. Klarere Verantwortlichkeiten:

    • core/ = Business Logic
    • clients/ = External Systems
    • parsers/ = Message Parsing
    • api/ = HTTP Interface
    • config/ = Configuration
    • utils/ = Shared Utilities
  2. Bessere Skalierbarkeit:

    • Neue Parser in parsers/ hinzufügen
    • Neue Clients (z.B. InfluxDB) in clients/
    • Weitere APIs in api/
  3. Einfacheres Testing:

    • Abhängigkeiten sind klar
    • Mocking ist einfacher
    • Unit Tests pro Package
  4. IDE-Support:

    • Bessere Auto-Completion
    • Klarere Fehler-Meldungen
    • Navigate to Definition funktioniert besser

📦 Phase 1: Foundation & Quality Tools

Status: ABGESCHLOSSEN
Aufwand: ~4 Stunden (erwartet: 4-6h)
Priorität: 🔴 Hoch (Blocker für andere Phasen)
Abhängigkeiten: Phase 0 abgeschlossen
Git-Commit: fdddba7

Aufgaben

1.1 Code-Quality-Tools einrichten

Dateien: pyproject.toml, .pre-commit-config.yaml

Aufgaben:

  • pyproject.toml erstellen mit Tool-Konfigurationen
    • Black (Code-Formatter)
    • isort (Import-Sortierer)
    • mypy (Type-Checker)
    • pytest (Test-Runner mit Coverage)
    • flake8 (Linter)
  • .pre-commit-config.yaml für Git-Hooks erstellen
  • Pre-commit hooks lokal testen: pre-commit run --all-files
  • README.md mit Development-Setup aktualisieren

Erfolgskriterien:

  • black . läuft ohne Fehler
  • isort . läuft ohne Fehler
  • flake8 . zeigt max. 5 Warnings
  • Pre-commit hooks funktionieren

Kompatibilität: Keine Auswirkung auf Runtime

Dateien zu erstellen:

iot_bridge/
├── pyproject.toml          # NEU
├── .pre-commit-config.yaml # NEU
└── .flake8                 # NEU (optional)

1.2 Test-Infrastruktur erweitern

Dateien: tests/conftest.py, tests/fixtures.py

Aufgaben:

  • Zentrale conftest.py mit Shared Fixtures erstellen
  • Mock-Factory für häufige Test-Objekte (MQTTClient, EventQueue, etc.)
  • Fixture für temporäre Config-Dateien
  • Fixture für MQTT-Broker-Simulation (in-memory)
  • Test-Utilities für Assert-Helpers

Erfolgskriterien:

  • pytest tests/ läuft ohne Setup-Fehler
  • Fixtures sind wiederverwendbar
  • Coverage-Report wird generiert

Kompatibilität: Keine Auswirkung auf Runtime

Dateien zu erstellen:

iot_bridge/tests/
├── conftest.py           # NEU - Shared fixtures
├── fixtures/             # NEU - Test fixtures
│   ├── __init__.py
│   ├── mqtt_fixtures.py
│   ├── config_fixtures.py
│   └── device_fixtures.py
└── helpers.py            # NEU - Test utilities

1.3 CI/CD Pipeline (optional)

Dateien: .github/workflows/test.yml

Aufgaben:

  • GitHub Actions Workflow für Tests erstellen
  • Matrix-Testing: Python 3.10, 3.11, 3.12
  • Coverage-Report zu GitHub Actions hinzufügen
  • Docker-Build-Test in Pipeline

Erfolgskriterien:

  • Tests laufen automatisch bei Push/PR
  • Docker-Image wird erfolgreich gebaut

Kompatibilität: Keine Auswirkung auf Runtime


📦 Phase 2: Code Organization

Status: Abgeschlossen (2.1-2.4 umgesetzt inkl. Resttests)
Aufwand: ~6-8 Stunden
Priorität: 🟡 Mittel
Abhängigkeiten: Phase 0-1 abgeschlossen Git-Commits: e744a1e, 548f94a, eb3c49c, 527b564, bad1d5d

Aufgaben

2.1 Custom Exceptions erstellen

Dateien: exceptions.py (NEU), mqtt_client.py, odoo_client.py, etc.

Aufgaben:

  • exceptions.py mit Exception-Hierarchie erstellen
    • BridgeError (Base)
    • ConfigurationError
    • MQTTConnectionError
    • OdooAPIError
    • DeviceNotFoundError
    • ParserError
  • Bestehende except Exception durch spezifische Exceptions ersetzen
  • Error-Messages standardisieren
  • Tests für Exception-Handling schreiben

Erfolgskriterien:

  • Alle except Exception sind spezifisch (max. 3 Ausnahmen erlaubt)
  • Error-Messages sind strukturiert
  • Tests decken Exception-Pfade ab

Kompatibilität: ⚠️ Zu prüfen:

  • Odoo-Modul darf nicht auf Exception-Namen angewiesen sein
  • HTTP-API-Responses bleiben gleich (Status-Codes unverändert)

Migration:

# Vorher:
try:
    self.client.connect(...)
except Exception as e:
    logger.error(f"error: {e}")

# Nachher:
try:
    self.client.connect(...)
except MQTTConnectionError as e:
    logger.error("mqtt_connection_failed", error=str(e))
    raise  # Re-raise für besseres Debugging

2.2 main.py refactoren

Dateien: main.py, bootstrap.py (NEU), service_manager.py (NEU)

Aufgaben:

  • bootstrap.py erstellen
    • Config-Loading-Logik von main.py verschieben
    • Logger-Setup-Logik verschieben
    • Fallback-Strategie dokumentieren
  • service_manager.py erstellen
    • Service-Lifecycle-Management (start/stop)
    • Signal-Handler-Logik
    • Graceful-Shutdown-Koordination
  • main.py auf ~50-80 Zeilen reduzieren (nur Orchestrierung)
  • Tests für Bootstrap-Logik schreiben
  • Tests für Service-Manager schreiben

Erfolgskriterien:

  • main.py hat max. 100 Zeilen
  • Keine globalen Variablen außer __name__
  • Bootstrap ist isoliert testbar
  • Service-Manager kann Services mocken

Kompatibilität: CLI-Interface bleibt gleich (python main.py --config ...)

Dateien zu erstellen:

iot_bridge/
├── main.py              # REFACTOR - 50-80 Zeilen
├── bootstrap.py         # NEU - Config & Logger Setup
└── service_manager.py   # NEU - Service Lifecycle

2.3 Config-Management modernisieren

Dateien: config.py, config_schema.py (NEU)

Aufgaben:

  • Pydantic BaseSettings für ENV-Var-Support nutzen
  • Config-Validation mit Pydantic-Validatoren
  • Config-Hierarchie dokumentieren (ENV > YAML > Defaults)
  • dataclass zu Pydantic BaseModel migrieren
  • Config-Schema-Tests schreiben

Erfolgskriterien:

  • ENV-Variablen überschreiben YAML-Werte
  • Validation-Errors sind aussagekräftig
  • Backward-Kompatibilität zu alten config.yaml

Kompatibilität: Bestehende config.yaml funktionieren weiter

Migration:

# Vorher (dataclass):
@dataclass
class MQTTConfig:
    broker: str
    port: int

# Nachher (Pydantic):
class MQTTConfig(BaseSettings):
    broker: str = Field("mosquitto", env="MQTT_BROKER")
    port: int = Field(1883, env="MQTT_PORT")
    
    class Config:
        env_prefix = "MQTT_"

2.4 Dependency Injection Pattern

Dateien: dependencies.py (NEU), main.py

Aufgaben:

  • dependencies.py mit DI-Container erstellen
  • Factory-Methoden für Service-Initialisierung
  • Constructor-Injection statt globale Variablen
  • Tests mit Mock-Dependencies schreiben

Erfolgskriterien:

  • Services werden als Dependencies übergeben
  • Tests können Dependencies einfach mocken
  • Keine globalen Service-Instanzen in Modulen

Kompatibilität: Keine Auswirkung auf Odoo-Integration


📦 Phase 3: Type Safety & Error Handling

Status: 🟡 In Arbeit (3.1-3.2 abgeschlossen, 3.3 offen)
Aufwand: ~4-5 Stunden
Priorität: 🟢 Niedrig (kann parallel zu Phase 2)
Abhängigkeiten: Phase 0-1 abgeschlossen

Aufgaben

3.1 Type Hints vervollständigen

Dateien: Alle .py Dateien

Aufgaben:

  • Type Hints zu allen Funktions-Signaturen hinzufügen
  • from __future__ import annotations für Forward-References
  • Protocol für Callback-Interfaces (bridge_types.py)
  • Type-Aliases für komplexe Typen
  • MyPy im strict-mode ohne Fehler

Erfolgskriterien:

  • mypy --strict . ohne Fehler
  • Alle public-functions haben Type Hints
  • Keine # type: ignore Kommentare

Kompatibilität: Runtime-Behavior unverändert

Type-Alias-Beispiele:

# types.py
from typing import Protocol, Dict, Any
from datetime import datetime

PowerWatts = float
Timestamp = datetime
EventDict = Dict[str, Any]
DeviceID = str

class MessageParser(Protocol):
    def parse_message(self, topic: str, payload: dict) -> dict | None: ...

class EventCallback(Protocol):
    def __call__(self, event: EventDict) -> None: ...

3.2 Logging vereinheitlichen

Dateien: Alle .py Dateien mit Logging

Aufgaben:

  • Nur structlog verwenden (stdlib logging entfernen)
  • Log-Events konsistent benennen (snake_case)
  • Strukturierte Log-Felder statt f-strings
  • Context-Variablen für Request-Correlation
  • Log-Level-Konsistenz prüfen

Erfolgskriterien:

  • Kein import logging in Code-Dateien
  • Alle Logs haben Event-Name + Felder
  • Request-IDs werden bei API-Calls geloggt

Kompatibilität: Log-Output-Format bleibt JSON

Migration:

# Vorher:
logger.info(f"Device added: {device_id}")

# Nachher:
logger.info("device_added", device_id=device_id, topic=mqtt_topic)

3.3 Robustere Error-Handling-Patterns

Dateien: mqtt_client.py, odoo_client.py, event_queue.py

Aufgaben:

  • Retry-Logic mit Exponential Backoff dokumentieren
  • Circuit-Breaker-Pattern für Odoo-API (optional)
  • Timeout-Handling vereinheitlichen
  • Error-Recovery-Tests schreiben

Erfolgskriterien:

  • Transient Errors werden automatisch recovered
  • Fatal Errors stoppen Service mit klarer Message
  • Tests decken Error-Recovery ab

Kompatibilität: Retry-Behavior bleibt gleich


📦 Phase 4: Testing & Documentation

Status: 🟡 In Arbeit (4.1-4.4 weitgehend umgesetzt)
Aufwand: ~6-8 Stunden
Priorität: 🟡 Mittel
Abhängigkeiten: Phase 0-2 abgeschlossen

Aufgaben

4.1 Unit Tests für kritische Module

Dateien: tests/unit/test_*.py

Aufgaben:

  • tests/unit/test_config.py - Config-Loading & Validation
  • tests/unit/test_device_manager.py - Device-Lifecycle
  • tests/unit/test_bootstrap.py - Config-Fallback-Strategie
  • tests/unit/test_exceptions.py - Exception-Handling
  • Coverage-Ziel: 80% für Core-Module

Erfolgskriterien:

  • Test-Coverage: config.py >90%, device_manager.py >80%
  • Alle Tests laufen in <10 Sekunden
  • Tests sind isoliert (keine MQTT/Odoo-Connection nötig)

Kompatibilität: Keine Auswirkung auf Runtime

Test-Beispiel:

# tests/unit/test_device_manager.py
def test_add_device_subscribes_to_mqtt(device_manager, mock_mqtt):
    device = DeviceConfig(...)
    config = BridgeConfig(devices=[device])
    
    device_manager.apply_config(config)
    
    mock_mqtt.subscribe.assert_called_once_with(device.mqtt_topic)
    assert device.device_id in device_manager.session_detectors

4.2 Integration Tests erweitern

Dateien: tests/integration/test_*.py

Aufgaben:

  • test_mqtt_reconnect.py - MQTT-Broker-Switch-Szenarien
  • test_config_push_integration.py - Vollständiger Config-Push-Flow
  • test_event_delivery.py - Event-Queue mit Retry
  • In-Memory MQTT-Broker für schnelle Tests

Erfolgskriterien:

  • MQTT-Reconnect wird vollständig getestet
  • Config-Push-Flow wird E2E getestet
  • Tests laufen ohne externes Setup

Kompatibilität: Keine Auswirkung auf Runtime


4.3 Dokumentation aktualisieren

Dateien: README.md, ARCHITECTURE.md (NEU), DEVELOPMENT.md (NEU)

Aufgaben:

  • ARCHITECTURE.md erstellen
    • Komponenten-Diagramm
    • Data-Flow dokumentieren
    • Entscheidungs-Rationale (ADRs)
  • DEVELOPMENT.md erstellen
    • Local-Setup-Guide
    • Testing-Guide
    • Debugging-Tipps
  • README.md aktualisieren
    • Links zu neuen Docs
    • Development-Sektion erweitern
  • Code-Kommentare bei komplexer Logik

Erfolgskriterien:

  • Neue Entwickler können Setup in <30 Min durchführen
  • Architektur-Entscheidungen sind nachvollziehbar
  • README.md ist auf dem aktuellen Stand

Kompatibilität: Keine Code-Änderungen


4.4 Docstrings vervollständigen

Dateien: Alle Module

Aufgaben:

  • Google-Style Docstrings für alle public functions
  • Module-Level Docstrings
  • Class-Level Docstrings mit Beispielen
  • Args und Returns dokumentieren (Raises bei relevanten Fehlerpfaden)

Erfolgskriterien:

  • Alle public APIs haben Docstrings
  • Sphinx-Dokumentation kann generiert werden (optional)

Kompatibilität: Runtime-Behavior unverändert

Beispiel:

def process_power_measurement(self, power_w: PowerWatts, timestamp: Timestamp) -> None:
    """
    Process a power measurement through the state machine.
    
    Args:
        power_w: Power consumption in watts
        timestamp: Measurement timestamp (UTC)
        
    Raises:
        ValueError: If power_w is negative
        
    Example:
        >>> detector.process_power_measurement(125.5, datetime.utcnow())
    """

📦 Phase 5: Performance & Observability

Status: Nicht gestartet
Aufwand: ~4-6 Stunden
Priorität: 🟢 Niedrig (Nice-to-have)
Abhängigkeiten: Phase 0 und (Phase 2 oder 4) abgeschlossen

Aufgaben

5.1 Event Batching (optional)

Dateien: event_queue.py, odoo_client.py

Aufgaben:

  • Batch-Sending für Events implementieren
    • Batch-Size: 10 Events (konfigurierbar)
    • Batch-Timeout: 5 Sekunden
  • Odoo-API Batch-Endpoint nutzen (wenn vorhanden)
  • Fallback auf Single-Send bei Batch-Fehler
  • Performance-Tests (Durchsatz messen)

Erfolgskriterien:

  • HTTP-Requests reduziert bei hoher Last
  • Latenz für einzelne Events bleibt <1s
  • Tests mit >100 Events/Sekunde

Kompatibilität: ⚠️ Zu prüfen:

  • Odoo-API muss Batch-Endpoint unterstützen
  • Oder: Batching nur intern nutzen und sequenziell senden

Feature-Flag:

# config.yaml
event_queue:
  batching_enabled: false  # Default: disabled für Kompatibilität
  batch_size: 10
  batch_timeout_s: 5.0

5.2 Prometheus Metrics Endpoint

Dateien: metrics.py (NEU), config_server.py

Aufgaben:

  • prometheus_client zu Dependencies hinzufügen
  • Metrics definieren:
    • mqtt_messages_total (Counter per device)
    • active_sessions (Gauge per device)
    • event_processing_seconds (Histogram)
    • event_queue_size (Gauge)
  • /metrics Endpoint in FastAPI
  • Grafana-Dashboard-Template (optional)

Erfolgskriterien:

  • /metrics Endpoint liefert Prometheus-Format
  • Metrics sind aussagekräftig
  • Performance-Overhead <1%

Kompatibilität: Neue Endpoint, bestehende bleiben gleich


5.3 Connection Pooling für Odoo-API

Dateien: odoo_client.py

Aufgaben:

  • requests.Session mit HTTPAdapter & Connection-Pooling
  • Pool-Size konfigurierbar (default: 10 Connections)
  • Keep-Alive aktivieren
  • Timeout-Konfiguration

Erfolgskriterien:

  • Wiederverwendung von HTTP-Connections
  • Latenz bei Multiple Events reduziert

Kompatibilität: API-Verhalten bleibt gleich

# odoo_client.py
class OdooClient:
    def __init__(self, ...):
        self.session = requests.Session()
        adapter = HTTPAdapter(
            pool_connections=10,
            pool_maxsize=20,
            max_retries=3
        )
        self.session.mount('http://', adapter)
        self.session.mount('https://', adapter)

5.4 Health-Check Endpoint erweitern

Dateien: config_server.py

Aufgaben:

  • MQTT-Connection-Status in Health-Response
  • Last-Event-Timestamp
  • Queue-Size und Retry-Stats
  • Odoo-API-Erreichbarkeit (letzte 10 Requests)

Erfolgskriterien:

  • Health-Check zeigt vollständigen Status
  • Monitoring kann Probleme erkennen

Kompatibilität: Bestehende Felder bleiben, neue kommen hinzu

Response-Beispiel:

{
  "status": "ok",
  "devices": 2,
  "subscriptions": 2,
  "last_config_update": "2026-02-12T19:40:18Z",
  "mqtt": {
    "connected": true,
    "broker": "mosquitto:1883",
    "last_message": "2026-02-12T19:41:00Z"
  },
  "queue": {
    "pending": 3,
    "retries_active": 1
  },
  "odoo": {
    "last_success": "2026-02-12T19:40:55Z",
    "success_rate_10min": 0.98
  }
}

🧪 Test-Strategie

Test-Pyramide

        /\
       /  \  E2E Tests (5)        - test_e2e_push_architecture.py
      /____\
     /      \ Integration (10)    - MQTT, Config-Push, Retry-Logic
    /________\
   /          \ Unit Tests (30+)  - Alle Module, >80% Coverage
  /__________\

Coverage-Ziele

Modul Aktuell Ziel Priorität
config.py ~50% >90% 🔴 Hoch
device_manager.py ~30% >80% 🔴 Hoch
mqtt_client.py ~60% >75% 🟡 Mittel
session_detector.py ~80% >85% 🟢 Niedrig
event_queue.py ~70% >80% 🟡 Mittel
odoo_client.py ~40% >70% 🟡 Mittel
Gesamt ~55% >80% 🔴 Hoch

Continuous Testing

# Watch-Mode für Development
pytest-watch tests/

# Coverage-Report
pytest --cov=. --cov-report=html --cov-report=term

# Type-Check
mypy --strict .

# Linting
flake8 .

📊 Erfolgsmetriken

Code-Qualität

  • Cyclomatic Complexity: <10 für alle Functions
  • Code Duplication: <5%
  • Test Coverage: >80%
  • MyPy Strict: 0 Errors
  • Flake8: <10 Warnings

Performance

  • Startup-Zeit: <5 Sekunden
  • MQTT-Reconnect: <2 Sekunden
  • Event-Processing: <100ms (P95)
  • Memory-Usage: <100MB (Idle)

Maintainability

  • Onboarding neuer Entwickler: <30 Minuten Setup
  • Documentation-Coverage: 100% Public APIs
  • Kein Code-File >500 Zeilen (außer Tests)

🔄 Migrations-Checkliste

Für jede Code-Änderung:

  1. Funktionalität testen:

    • Alle existierenden Tests laufen durch
    • Manuelle Tests mit Odoo-Integration
    • Config-Push von Odoo funktioniert
  2. Kompatibilität prüfen:

    • API-Endpoints unverändert (oder backward-compatible)
    • Config-File-Format kompatibel
    • ENV-Variablen funktionieren weiter
  3. Dokumentation:

    • README.md aktualisiert (wenn nötig)
    • CHANGELOG.md-Eintrag
    • Code-Kommentare bei nicht-trivialen Änderungen
  4. Testing:

    • Unit Tests für neue Funktionen
    • Integration Tests bei API-Änderungen
    • Coverage nicht gesunken

🚀 Rollout-Strategie

Development

# 1. Feature-Branch erstellen
git checkout -b feature/phase1-quality-tools

# 2. Änderungen implementieren
# ... Code-Änderungen ...

# 3. Tests laufen lassen
pytest tests/
mypy --strict .
black --check .

# 4. Commit & Push
git commit -m "feat: Add code quality tools (Phase 1.1)"
git push origin feature/phase1-quality-tools

Testing

# 1. Docker-Image bauen
docker build -t iot_bridge:test ./iot_bridge

# 2. Lokaler Test mit docker-compose
docker-compose -f odoo/docker-compose.dev.yaml up -d iot-bridge

# 3. Smoke-Tests
curl http://localhost:8080/health
# Odoo: Device erstellen → Config-Push testen

Production

  1. Staging-Deployment:

    • Parallel-Betrieb: Alter + Neuer Bridge
    • Monitoring: Fehlerrate, Performance
    • Rollback-Plan bereithalten
  2. Canary-Deployment:

    • 10% Traffic auf neue Version
    • Metriken beobachten (24h)
    • Graduelles Hochskalieren
  3. Full-Deployment:

    • Alte Version stilllegen
    • Dokumentation aktualisieren

📝 Changelog-Template

## [Unreleased]

### Added
- Code quality tools: Black, isort, mypy, flake8
- Custom exception hierarchy for better error handling
- Dependency injection pattern for testability

### Changed
- Refactored main.py into bootstrap.py and service_manager.py
- Migrated config from dataclasses to Pydantic BaseSettings
- Unified logging to structlog (removed stdlib logging)

### Fixed
- Type hints added to all public functions
- Error handling improved with specific exceptions

### Performance
- Connection pooling for Odoo API requests
- Event batching (optional, disabled by default)

### Deprecated
- None

### Removed
- None

### Breaking Changes
- None (backward-compatible)

🛡️ Risiken & Mitigationen

Risiko Wahrscheinlichkeit Impact Mitigation
Breaking Changes durch Refactoring Mittel Hoch Umfassende Tests, Kompatibilitätsprüfung vor jedem Merge
Performance-Regression Niedrig Mittel Performance-Tests, Baseline-Messung vor Änderungen
Config-Format-Inkompatibilität Niedrig Hoch Backward-Kompatibilität zwingend, Migration-Guide
Odoo-API-Änderungen nicht bedacht Mittel Hoch Integration Tests mit echtem Odoo-Setup
Zeit-Überschreitung Hoch Niedrig Phasen sind optional, können einzeln ausgelassen werden

📅 Zeitplan (Optional)

Phase Dauer Start Ende Status
Phase 0 3h - - Abgeschlossen
Phase 1 6h - - Abgeschlossen
Phase 2 8h - - 🟡 Teilweise abgeschlossen
Phase 3 5h - - Geplant
Phase 4 8h - - Geplant
Phase 5 6h - - Geplant
Gesamt ~36h - - -

Definition of Done

Eine Phase ist abgeschlossen, wenn:

  • Alle Aufgaben der Phase erledigt
  • Alle Tests laufen durch (pytest tests/)
  • Code-Quality-Checks bestanden (black, mypy, flake8)
  • Coverage-Ziel erreicht
  • Kompatibilitäts-Tests mit Odoo erfolgreich
  • Dokumentation aktualisiert
  • Code-Review durchgeführt (wenn Team-Arbeit)
  • Deployment-Test erfolgreich

📚 Referenzen


🤝 Beiträge & Feedback

Dieses Optimierungsprojekt ist iterativ:

  • Feedback willkommen: Jede Phase kann angepasst werden
  • Prioritäten flexibel: Phasen können in anderer Reihenfolge bearbeitet werden
  • Optional: Phase 5 kann übersprungen werden, wenn nicht benötigt
  • Inkrementell: Commits sollten klein und testbar sein

Letztes Update: 18. Februar 2026
Nächste Review: Nach Abschluss Phase 1