open_workshop/open_workshop_mqtt/TODO.md
matthias.lotz 5a27dc6a65 refactor: Remove old service-based MQTT integration
Removed deprecated in-process MQTT service in favor of standalone IoT Bridge container:

Deleted:
- services/ directory (iot_bridge_service, mqtt_client, session_detector, parsers)
- Old tests (test_mqtt_connection, test_mqtt_mocked, test_session_detector, test_topic_matching, test_no_duplicate_messages)

Modified:
- mqtt_connection.py: action_start/stop now show deprecation message
- mqtt_connection.py: Auto-start on Odoo restart disabled
- mqtt_device.py: Auto-subscribe on device changes disabled
- tests/__init__.py: Removed old test imports
- tests/common.py: Replaced with stub (legacy support only)

Reason:
- Old integration ran MQTT client in Odoo process (tight coupling)
- New architecture: Standalone IoT Bridge container + REST API
- Better separation of concerns, scalability, and maintainability
- All functionality moved to iot_bridge/ (Phase 1) + REST API (Phase 2)

All old code is preserved in git history if needed.
Models (mqtt.device, mqtt.session, mqtt.connection, ows.iot.event) remain unchanged.
2026-02-05 16:49:18 +01:00

12 KiB

TODO - Open Workshop MQTT (Stand: 30. Januar 2026)

Status-Übersicht

Phase 1: Python Prototyp (ABGESCHLOSSEN)

  • M0: Projekt Setup & MQTT Verbindung
  • M1: Shelly PM Mini G3 Integration
  • M2: Event-Normalisierung & Unified Schema
  • M3: Session Detection Engine
  • M4: Multi-Device Support & Config
  • M5: Monitoring & Robustheit
  • Unit Tests (pytest)
  • Integration Tests (mit echtem MQTT Broker)

Ergebnis: python_prototype/ ist vollständig implementiert und getestet


🔄 Phase 2: ARCHITEKTUR-REDESIGN (IN ARBEIT)

ALTE Architektur (VERALTET):

Shelly PM → MQTT Broker → Odoo (MQTT Client) → Session Detection → Sessions

Problem: MQTT Client in Odoo = zu eng gekoppelt, Container-Restart-Issues

NEUE Architektur (Sidecar-Pattern):

Shelly PM → MQTT Broker ← Bridge Container → REST API → Odoo (Business Logic)

Vorteile:

  • Klare Prozess-Trennung (Odoo = HTTP+Business, Bridge = MQTT+Retry)
  • Bridge restart unabhängig von Odoo
  • Docker Best Practice (ein Prozess pro Container)
  • Einfache Orchestrierung via docker compose up -d

M6: Odoo Modul Grundgerüst (FERTIG - 100%)

  • Modul open_workshop_mqtt erstellt
  • Models implementiert:
    • mqtt.connection - MQTT Broker Verbindungen
    • mqtt.device - IoT Device Management
    • mqtt.session - Runtime Sessions
    • mqtt.message - Message Log (Debug)
  • Views erstellt (List, Form, Kanban, Pivot, Graph)
  • Security Rules (ir.model.access.csv)
  • Services:
    • mqtt_client.py - MQTT Client (mit TLS, Auto-Reconnect)
    • iot_bridge_service.py - Singleton Service für Connection Management
    • MQTT Client in Odoo - Subscribed DIREKT auf MQTT Topics
  • Parsers:
    • shelly_parser.py - Shelly PM Mini G3
    • Generic Parser Support

Code-Location: /models/, /services/, /views/

Flow: Shelly → MQTT → Odoo (kein REST API nötig!)


M7: REST Endpoint & Authentication (GESTRICHEN!)

Begründung: Odoo hat bereits MQTT Client → REST API überflüssig!

NICHT NÖTIG weil:

  • Odoo subscribed DIREKT auf MQTT Topics (via mqtt_client.py)
  • Keine externe Bridge erforderlich
  • python_prototype/ bleibt als Standalone-Tool für Tests/Entwicklung

M8: Python-Bridge Integration (GESTRICHEN!)

Begründung: Python Prototype bleibt Standalone für Tests. Odoo macht Production!


M7: Session-Engine in Odoo (GESTRICHEN - wird zu Bridge!)

Alte Architektur (in Odoo implementiert):

  • SessionDetector State Machine in services/session_detector.py
  • 5-State Machine: IDLE → STARTING → STANDBY/WORKING → STOPPING → IDLE
  • Dual-Threshold Detection + Debounce
  • Alle 7 Unit Tests grün

NEUE Architektur:

  • 🔄 SessionDetector wird in Bridge Container portiert
  • 🔄 Odoo bekommt nur noch fertige Events (run_start/run_stop)
  • 🔄 Sessions werden in Odoo via REST API erstellt

Code wird wiederverwendet:

  • services/session_detector.pyiot_bridge/session_detector.py (leicht angepasst)
  • State Machine Logic bleibt identisch
  • Nur Odoo-Abhängigkeiten (env, cursor) werden entfernt

🔧 M7: IoT Bridge Docker Container (IN ARBEIT - 0%)

Ziel: Separater Container für MQTT Bridge

Location: iot_bridge/ Unterverzeichnis

Tasks:

  • Projekt-Struktur erstellen:
    iot_bridge/
      main.py           # Bridge Hauptprogramm
      mqtt_client.py    # MQTT Client (aus services/ portiert)
      session_detector.py # State Machine (aus services/ portiert)
      odoo_client.py    # REST API Client für Odoo
      config.py         # Config Management
      parsers/
        shelly_parser.py
        tasmota_parser.py
      requirements.txt
      Dockerfile
      README.md
    
  • Docker Image: iot_mqtt_bridge_for_odoo
  • ENV-Variablen:
    • ODOO_URL (z.B. http://odoo:8069)
    • ODOO_TOKEN (API Token)
    • MQTT_URL (z.B. mqtt://mosquitto:1883)
  • Code-Portierung aus Odoo:
    • SessionDetector State Machine
    • MQTT Client (ohne Odoo-Abhängigkeiten)
    • Shelly Parser
  • Retry-Queue bei Odoo-Ausfall (lokal, in-memory oder SQLite)
  • Config-Refresh alle 5 Min via GET /ows/iot/config

Test:

  • docker build -t iot_mqtt_bridge_for_odoo iot_bridge/
  • docker run -e ODOO_URL=... -e ODOO_TOKEN=... iot_mqtt_bridge_for_odoo

🔧 M8: Odoo REST API Endpoints (IN ARBEIT - 0%)

Ziel: Odoo bietet REST API für Bridge-Kommunikation

Tasks:

  • Controller: controllers/iot_api.py
    • GET /ows/iot/config - Device-Config für Bridge
    • POST /ows/iot/event - Event-Empfang von Bridge
  • Authentifizierung:
    • Token in ir.config_parameter: ows_iot.bridge_token
    • Bearer Token Validation in Controller
  • Event-Validation:
    • Schema v1 prüfen
    • Unique-Constraint auf event_uid
    • 409 Conflict bei Duplikaten
  • Session-Mapping:
    • Events → Session-Updates
    • run_start/run_stop Events

Test:

# Config abrufen
curl -H "Authorization: Bearer <token>" http://localhost:8069/ows/iot/config

# Event senden
curl -X POST -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"schema_version":"v1","event_uid":"...","device_id":"..."}' \
  http://localhost:8069/ows/iot/event

🔧 M9: Docker Compose Integration (TODO - 0%)

Tasks:

  • docker-compose.yaml Update:
    services:
      iot_bridge:
        image: iot_mqtt_bridge_for_odoo
        build:
          context: ./extra-addons/open_workshop/open_workshop_mqtt/iot_bridge
        environment:
          ODOO_URL: http://odoo:8069
          ODOO_TOKEN: ${IOT_BRIDGE_TOKEN}
          MQTT_URL: mqtt://mosquitto:1883
        depends_on:
          - odoo
          - mosquitto
        restart: unless-stopped
    
  • .env Template mit IOT_BRIDGE_TOKEN
  • DEPLOYMENT.md - Setup-Anleitung

Test:

  • docker compose up -d startet Odoo + Bridge
  • Bridge logs zeigen MQTT connection
  • Events erscheinen in Odoo UI
    • Standby/Working Thresholds
    • Debounce (Start: 3s, Stop: 15s)
    • 5-State Machine (IDLE → STARTING → STANDBY/WORKING → STOPPING → IDLE)
    • Timeout Detection (20s)
    • Duration Tracking (standby_duration_s, working_duration_s)
    • State Recovery nach Restart
  1. Views & UI - Forms, Lists, Pivot Tables, Graphs
  2. ENV-Passing Architecture - Keine Cursor-Fehler mehr!

TESTS BROKEN (Code IST NICHT FERTIG!)

  1. 8 Unit Tests schlagen fehl - Tests verwenden alte Signaturen

    • Änderung nötig: SessionDetector(device)SessionDetector(device.id, device.name)
    • Änderung nötig: detector.process_power_event(power, ts)detector.process_power_event(env, power, ts)
    • Alle Assertions müssen mit env arbeiten
    • Aufwand: ~1-2 Stunden (nicht 30 Min - Tests müssen auch laufen!)
  2. **Keine grünen Tests = NICHT FERTIG!ctor(device)SessionDetector(device.id, device.name)`

    • Änderung: detector.process_power_event(power, ts)detector.process_power_event(env, power, ts)
    • Aufwand: ~30 Minuten

NICHT MEHR NÖTIG

  • REST API Endpoint - Odoo macht MQTT direkt
  • Event Storage Model - mqtt.message reicht für Debug
  • Python Bridge - Odoo ist die Bridge

Phase 3: Optional Features (Noch nicht gestartet)

🟡 MEDIUM PRIORITY (Optional M9)

  1. POS Integration (später)

    • Realtime Display
    • WebSocket Feed
    • Live Power Consumption
  2. Maintenance Integration

    • Link zu maintenance.equipment
    • Usage Tracking
    • Separate Module open_workshop_mqtt_maintenance

🟢 LOW PRIORITY (Nice-to-have)

  1. Performance & Scale

    • Last-Tests (20 Devices, 1h)
    • Queue Optimization
    • Database Indexes
  2. Security Hardening

    • IP Allowlist
    • Rate Limiting (Reverse Proxy)
    • Token Rotation

Bekannte Probleme

🐛 BUGS

  1. Tests hängen mit echtem MQTT Broker

    • Location: tests/test_mqtt_connection.py, etc.
    • Reason: TransactionCase + Background Threads inkompatibel
    • Solution: Mock-basierte Tests (erstellt, aber nicht aktiv)
    • Status: WORKAROUND erstellt, muss aktiviert werden
  2. Manual Session Start/Stop TODO

    • Location: models/mqtt_device.py:327, 349
    • Methods: action_start_session(), action_stop_session()
    • Status: Placeholder, nicht implementiert
  3. Topic Matching ohne Wildcards

    • Location: services/iot_bridge_service.py:498
    • TODO Comment: Implement proper topic matching (+, #)
    • Status: Funktioniert nur mit exakten Topics

⚠️ TECHNICAL DEBT

  1. Session Detection zu simpel
    • Problem: power > 0 = start ist zu vereinfacht
    • Impact: Flackernde Sessions bei Power-Spikes
    • Solution: Session-Engine aus Python portieren (M7) ← DAS IST ALLES
  • M7: REST Endpoint /ows/iot/event funktioniert
    • Auth Tests: Alle Tests grün
    • Manual Test: curl -H "Authorization: Bearer xxx" -X POST ... → 200 OK
  • M7: Events werden in mqtt.event persistiert
    • Test: Event in DB sichtbar nach POST
  • M8: Python Bridge sendet Events an Odoo
    • Integration Test: Event kommt in Odoo an
    • Manual Test: Bridge läuft, Events in Odoo UI sichtbar
  • M9: Session-Detection läuft in Odoo (Dual-Threshold!)
    • Unit Tests: State Machine korrekt
    • Integration Test: Shelly → Session mit Debounce
    • Manual Test: Maschine an/aus → Session startet/stoppt korrekt
  • End-to-End: Shelly → MQTT → Bridge → Odoo → Session sichtbar
    • Test: Kompletter Flow funktioniert
  • Dokumentation: API, Setup, Troubleshooting komplett

Test-Driven Development:

  • Jeder Milestone hat Tests BEVOR Code geschrieben wird
  • Keine manuelle UI-Klickerei zum Testen
  • run-tests.sh läuft jederzeit durch

Geschätzter Aufwand: 4-6 Tage (bei fokussierter TDD-rt

  • Python Bridge sendet Events an Odoo (statt nur File)
  • Events werden in mqtt.event persistiert
  • Session-Detection läuft in Odoo (nicht nur Python)
  • Sessions werden automatisch bei Events aktualisiert
  • Tests laufen durch (Mock-basiert)
  • End-to-End Test: Shelly → MQTT → Bridge → Odoo → Session sichtbar
  • Dokumentation komplett (API, Setup, Troubleshooting)

Geschätzter Aufwand: 4-6 Tage (bei fokussierter Arbeit)


Changelog

2026-01-30 16:40 Uhr (Phase 2 FERTIG!):

  • Phase 1: Komplett (Python Prototype)
  • Phase 2: 100% FERTIG! - Code + Tests komplett!
  • SessionDetector vollständig portiert + env-passing refactoring
  • Live-Tests erfolgreich: State Machine funktioniert mit echten MQTT Messages!
  • Alle 26 Unit Tests grün! (0 failed, 0 errors)
  • Test-Fixes:
    • test_session_detector.py: Alle 7 Tests an env-passing angepasst
    • test_mqtt_mocked.py: Alle 4 Service-Tests repariert
    • run-tests.sh: Verbesserte Ausgabe mit klarer Zusammenfassung
  • SessionDetector ist produktionsreif!

2026-01-29 (Env-Passing Refactoring): Odoo Cursor Management gelöst

  • Komplettes Refactoring: SessionDetector speichert nur IDs
  • 20+ Method Signatures geändert (env-passing)
  • Keine "Cursor already closed" Fehler mehr
  • Live getestet mit echten MQTT Messages

2026-01-28 (Update 2): Architektur vereinfacht - Odoo macht ALLES direkt

  • Phase 1: Komplett (Python Prototype)
  • Phase 2: 🚧 70% (Odoo Integration)
  • M7+M8 (REST/Bridge) GESTRICHEN → 2 Tage gespart!
  • Nur noch: M7 (Session-Engine portieren) + M8 (Tests reparieren)
  • Geschätzt: 2-3 Tage statt 4-6!