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

1336 lines
36 KiB
Markdown

# 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:**
- [x] `mkdir -p core clients parsers api config utils`
- [x] `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:**
- [x] `session_detector.py``core/session_detector.py`
- [x] `event_queue.py``core/event_queue.py`
- [ ] `device_manager.py``core/device_manager.py`
- [ ] Imports in allen Dateien anpassen:
- `from session_detector import``from core.session_detector import`
- `from event_queue import``from core.event_queue import`
- `from device_manager import``from 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:**
- [x] `mqtt_client.py``clients/mqtt_client.py`
- [x] `odoo_client.py``clients/odoo_client.py`
- [ ] Imports anpassen:
- `from mqtt_client import``from clients.mqtt_client import`
- `from odoo_client import``from 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:**
- [x] `parsers/base.py` erstellen mit Parser-Protocol/Base-Class
- [x] `shelly_parser.py``parsers/shelly_parser.py`
- [x] `shelly_parser.py` von `base.py` ableiten
- [ ] `parsers/tasmota_parser.py` als Placeholder erstellen (skip - nicht benötigt)
- [ ] Imports anpassen:
- `from shelly_parser import``from parsers.shelly_parser import`
**parsers/base.py:**
```python
"""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:**
- [x] `config_server.py``api/server.py` (FastAPI-App)
- [x] Pydantic-Models in `api/models.py` extrahieren
- [ ] Imports anpassen:
- `from config_server import``from api.server import`
- `from config_server import BridgeConfig``from api.models import BridgeConfig`
**api/models.py (NEU):**
```python
"""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:**
- [x] `config.py` aufteilen:
- Dataclasses → `config/schema.py`
- Loader-Functions → `config/loader.py`
- [ ] Imports anpassen:
- `from config import load_config``from config.loader import load_config`
- `from config import BridgeConfig``from config.schema import BridgeConfig`
**config/__init__.py:**
```python
"""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:**
- [x] `logger_setup.py``utils/logging.py`
- [x] `device_status_monitor.py``utils/status_monitor.py`
- [ ] Imports anpassen:
- `from logger_setup import``from utils.logging import`
- `from device_status_monitor import``from 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:**
- [x] Alle `__init__.py` befüllen mit Public API
- [x] Relative Imports innerhalb Packages nutzen
- [x] Absolute Imports von außen
**Beispiel core/__init__.py:**
```python
"""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:**
```python
# 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:**
- [x] Alle Test-Imports anpassen
- [x] Test-Fixtures auf neue Struktur anpassen
- [x] `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:**
- [x] README.md "Project Structure" Sektion aktualisieren
- [x] Import-Beispiele im Code aktualisieren
- [x] `git mv` Commits mit aussagekräftigen Messages
**Erfolgskriterien:**
- ✅ README.md zeigt neue Struktur
- ✅ Git-History ist nachvollziehbar
---
### Migrations-Strategie
**Git-Workflow:**
```bash
# 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:**
```bash
# 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:**
- [x] `pyproject.toml` erstellen mit Tool-Konfigurationen
- Black (Code-Formatter)
- isort (Import-Sortierer)
- mypy (Type-Checker)
- pytest (Test-Runner mit Coverage)
- flake8 (Linter)
- [x] `.pre-commit-config.yaml` für Git-Hooks erstellen
- [x] Pre-commit hooks lokal testen: `pre-commit run --all-files`
- [x] 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:**
- [x] Zentrale `conftest.py` mit Shared Fixtures erstellen
- [x] Mock-Factory für häufige Test-Objekte (MQTTClient, EventQueue, etc.)
- [x] Fixture für temporäre Config-Dateien
- [x] Fixture für MQTT-Broker-Simulation (in-memory)
- [x] 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:**
- [x] GitHub Actions Workflow für Tests erstellen
- [x] Matrix-Testing: Python 3.10, 3.11, 3.12
- [x] Coverage-Report zu GitHub Actions hinzufügen
- [x] 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:**
- [x] `exceptions.py` mit Exception-Hierarchie erstellen
- `BridgeError` (Base)
- `ConfigurationError`
- `MQTTConnectionError`
- `OdooAPIError`
- `DeviceNotFoundError`
- `ParserError`
- [x] Bestehende `except Exception` durch spezifische Exceptions ersetzen
- [x] Error-Messages standardisieren
- [x] 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:**
```python
# 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:**
- [x] `bootstrap.py` erstellen
- Config-Loading-Logik von main.py verschieben
- Logger-Setup-Logik verschieben
- Fallback-Strategie dokumentieren
- [x] `service_manager.py` erstellen
- Service-Lifecycle-Management (start/stop)
- Signal-Handler-Logik
- Graceful-Shutdown-Koordination
- [x] `main.py` auf ~50-80 Zeilen reduzieren (nur Orchestrierung)
- [x] Tests für Bootstrap-Logik schreiben
- [x] 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:**
- [x] Pydantic BaseSettings für ENV-Var-Support nutzen
- [x] Config-Validation mit Pydantic-Validatoren
- [x] Config-Hierarchie dokumentieren (ENV > YAML > Defaults)
- [x] `dataclass` zu Pydantic `BaseModel` migrieren
- [x] 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:**
```python
# 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:**
- [x] `dependencies.py` mit DI-Container erstellen
- [x] Factory-Methoden für Service-Initialisierung
- [x] Constructor-Injection statt globale Variablen
- [x] 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:**
- [x] Type Hints zu allen Funktions-Signaturen hinzufügen
- [x] `from __future__ import annotations` für Forward-References
- [x] `Protocol` für Callback-Interfaces (`bridge_types.py`)
- [x] Type-Aliases für komplexe Typen
- [x] 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:**
```python
# 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:**
- [x] Nur `structlog` verwenden (stdlib `logging` entfernen)
- [x] Log-Events konsistent benennen (snake_case)
- [x] Strukturierte Log-Felder statt f-strings
- [x] Context-Variablen für Request-Correlation
- [x] 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:**
```python
# 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:**
- [x] Retry-Logic mit Exponential Backoff dokumentieren
- [x] Circuit-Breaker-Pattern für Odoo-API (optional)
- [x] Timeout-Handling vereinheitlichen
- [x] 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:**
- [x] `tests/unit/test_config.py` - Config-Loading & Validation
- [x] `tests/unit/test_device_manager.py` - Device-Lifecycle
- [x] `tests/unit/test_bootstrap.py` - Config-Fallback-Strategie
- [x] `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:**
```python
# 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:**
- [x] `test_mqtt_reconnect.py` - MQTT-Broker-Switch-Szenarien
- [x] `test_config_push_integration.py` - Vollständiger Config-Push-Flow
- [x] `test_event_delivery.py` - Event-Queue mit Retry
- [x] 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:**
- [x] `ARCHITECTURE.md` erstellen
- Komponenten-Diagramm
- Data-Flow dokumentieren
- Entscheidungs-Rationale (ADRs)
- [x] `DEVELOPMENT.md` erstellen
- Local-Setup-Guide
- Testing-Guide
- Debugging-Tipps
- [x] 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:**
- [x] Google-Style Docstrings für alle public functions
- [x] Module-Level Docstrings
- [ ] Class-Level Docstrings mit Beispielen
- [x] `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:**
```python
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:**
```yaml
# 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
```python
# 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:**
```json
{
"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
```bash
# 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
```bash
# 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
```bash
# 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
```markdown
## [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](https://peps.python.org/pep-0484/)
- [Structlog Documentation](https://www.structlog.org/)
- [Pydantic BaseSettings](https://docs.pydantic.dev/latest/usage/settings/)
- [pytest Best Practices](https://docs.pytest.org/en/stable/goodpractices.html)
- [Clean Code Principles](https://github.com/zedr/clean-code-python)
---
## 🤝 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