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
- Code-Qualität verbessern ohne Funktionalitätsverlust
- Wartbarkeit erhöhen durch bessere Struktur
- Testabdeckung erweitern für kritische Komponenten
- Kompatibilität mit Odoo-Modul vollständig erhalten
- 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 utilstouch core/__init__.py clients/__init__.py parsers/__init__.py api/__init__.py config/__init__.py utils/__init__.py
Erfolgskriterien:
- ✅ Alle Verzeichnisse existieren
- ✅
__init__.pyin jedem Verzeichnis
0.2 Core-Module verschieben
Aufwand: 30 Minuten
Aufgaben:
session_detector.py→core/session_detector.pyevent_queue.py→core/event_queue.pydevice_manager.py→core/device_manager.py- Imports in allen Dateien anpassen:
from session_detector import→from core.session_detector importfrom event_queue import→from core.event_queue importfrom device_manager import→from core.device_manager import
Betroffene Dateien:
main.pytests/unit/test_*.pytests/integration/test_*.py
Erfolgskriterien:
- ✅
python main.py --config config.yamlstartet ohne ImportError - ✅
pytest tests/läuft durch
0.3 Client-Module verschieben
Aufwand: 20 Minuten
Aufgaben:
mqtt_client.py→clients/mqtt_client.pyodoo_client.py→clients/odoo_client.py- Imports anpassen:
from mqtt_client import→from clients.mqtt_client importfrom odoo_client import→from clients.odoo_client import
Betroffene Dateien:
main.pycore/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.pyerstellen mit Parser-Protocol/Base-Classshelly_parser.py→parsers/shelly_parser.pyshelly_parser.pyvonbase.pyableitenparsers/tasmota_parser.pyals Placeholder erstellen (skip - nicht benötigt)- Imports anpassen:
from shelly_parser import→from 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.py→api/server.py(FastAPI-App)- Pydantic-Models in
api/models.pyextrahieren - Imports anpassen:
from config_server import→from api.server importfrom config_server import BridgeConfig→from 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.pyaufteilen:- Dataclasses →
config/schema.py - Loader-Functions →
config/loader.py
- Dataclasses →
- Imports anpassen:
from config import load_config→from config.loader import load_configfrom config import BridgeConfig→from 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.pyapi/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.py→utils/logging.pydevice_status_monitor.py→utils/status_monitor.py- Imports anpassen:
from logger_setup import→from utils.logging importfrom device_status_monitor import→from utils.status_monitor import
Betroffene Dateien:
main.pycore/device_manager.py
Erfolgskriterien:
- ✅ Logging funktioniert
- ✅ Status-Monitor funktioniert
0.8 Import-Cleanup & init.py befüllen
Aufwand: 20 Minuten
Aufgaben:
- Alle
__init__.pybefü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 mvCommits 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ünpython 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
-
Klarere Verantwortlichkeiten:
core/= Business Logicclients/= External Systemsparsers/= Message Parsingapi/= HTTP Interfaceconfig/= Configurationutils/= Shared Utilities
-
Bessere Skalierbarkeit:
- Neue Parser in
parsers/hinzufügen - Neue Clients (z.B. InfluxDB) in
clients/ - Weitere APIs in
api/
- Neue Parser in
-
Einfacheres Testing:
- Abhängigkeiten sind klar
- Mocking ist einfacher
- Unit Tests pro Package
-
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.tomlerstellen mit Tool-Konfigurationen- Black (Code-Formatter)
- isort (Import-Sortierer)
- mypy (Type-Checker)
- pytest (Test-Runner mit Coverage)
- flake8 (Linter)
.pre-commit-config.yamlfü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.pymit 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.pymit Exception-Hierarchie erstellenBridgeError(Base)ConfigurationErrorMQTTConnectionErrorOdooAPIErrorDeviceNotFoundErrorParserError
- Bestehende
except Exceptiondurch spezifische Exceptions ersetzen - Error-Messages standardisieren
- Tests für Exception-Handling schreiben
Erfolgskriterien:
- ✅ Alle
except Exceptionsind 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.pyerstellen- Config-Loading-Logik von main.py verschieben
- Logger-Setup-Logik verschieben
- Fallback-Strategie dokumentieren
service_manager.pyerstellen- Service-Lifecycle-Management (start/stop)
- Signal-Handler-Logik
- Graceful-Shutdown-Koordination
main.pyauf ~50-80 Zeilen reduzieren (nur Orchestrierung)- Tests für Bootstrap-Logik schreiben
- Tests für Service-Manager schreiben
Erfolgskriterien:
- ✅
main.pyhat 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)
dataclasszu PydanticBaseModelmigrieren- 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.pymit 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 annotationsfür Forward-ReferencesProtocolfü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: ignoreKommentare
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
structlogverwenden (stdlibloggingentfernen) - 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 loggingin 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 & Validationtests/unit/test_device_manager.py- Device-Lifecycletests/unit/test_bootstrap.py- Config-Fallback-Strategietests/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-Szenarientest_config_push_integration.py- Vollständiger Config-Push-Flowtest_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.mderstellen- Komponenten-Diagramm
- Data-Flow dokumentieren
- Entscheidungs-Rationale (ADRs)
DEVELOPMENT.mderstellen- 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
ArgsundReturnsdokumentieren (Raisesbei 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_clientzu Dependencies hinzufügen- Metrics definieren:
mqtt_messages_total(Counter per device)active_sessions(Gauge per device)event_processing_seconds(Histogram)event_queue_size(Gauge)
/metricsEndpoint in FastAPI- Grafana-Dashboard-Template (optional)
Erfolgskriterien:
- ✅
/metricsEndpoint 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.Sessionmit 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:
-
Funktionalität testen:
- Alle existierenden Tests laufen durch
- Manuelle Tests mit Odoo-Integration
- Config-Push von Odoo funktioniert
-
Kompatibilität prüfen:
- API-Endpoints unverändert (oder backward-compatible)
- Config-File-Format kompatibel
- ENV-Variablen funktionieren weiter
-
Dokumentation:
- README.md aktualisiert (wenn nötig)
- CHANGELOG.md-Eintrag
- Code-Kommentare bei nicht-trivialen Änderungen
-
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
-
Staging-Deployment:
- Parallel-Betrieb: Alter + Neuer Bridge
- Monitoring: Fehlerrate, Performance
- Rollback-Plan bereithalten
-
Canary-Deployment:
- 10% Traffic auf neue Version
- Metriken beobachten (24h)
- Graduelles Hochskalieren
-
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
- Python Type Hints PEP 484
- Structlog Documentation
- Pydantic BaseSettings
- pytest Best Practices
- Clean Code Principles
🤝 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