odoo_mqtt/README.md

9.9 KiB

IoT MQTT Bridge for Odoo ../odoo

Separater Docker Container für MQTT-IoT-Device-Integration

Architektur-Übersicht

┌─────────────┐      MQTT       ┌──────────────┐     REST API    ┌────────────┐
│  Shelly PM  │ ────────────────► │ IoT Bridge   │ ──────────────► │   Odoo 18  │
│  (Hardware) │                  │ (THIS!)      │                 │ (Business) │
└─────────────┘                  └──────────────┘                 └────────────┘
                                        │                                │
                                        ▼                                │
                                 ┌──────────────┐                        │
                                 │ Mosquitto    │ ◄──────────────────────┘
                                 │ MQTT Broker  │    (Config via API)
                                 └──────────────┘

Zweck

Die IoT Bridge ist ein eigenständiger Python-Service der:

  1. MQTT-Verbindung verwaltet

    • Subscribed auf Device-Topics (z.B. Shelly PM Mini G3)
    • Auto-Reconnect bei Verbindungsabbruch
    • Exponential Backoff
  2. Event-Normalisierung durchführt

    • Parser für verschiedene Device-Typen (Shelly, Tasmota, Generic)
    • Konvertiert zu Unified Event Schema v1
    • Generiert eindeutige Event-UIDs
  3. Session Detection (State Machine)

    • Dual-Threshold Detection (Standby/Working)
    • Debounce Timer (Start/Stop)
    • Timeout Detection
    • 5-State Machine: IDLE → STARTING → STANDBY/WORKING → STOPPING
  4. Odoo-Kommunikation (REST API)

    • Holt Device-Config: GET /ows/iot/config
    • Sendet Events: POST /ows/iot/event
    • Bearer Token Authentication
    • Retry-Queue bei Odoo-Ausfall

Projekt-Struktur

iot_bridge/
├── main.py                 # Haupt-Entry-Point
├── mqtt_client.py          # MQTT Client (paho-mqtt)
├── session_detector.py     # State Machine für Session Detection
├── odoo_client.py          # REST API Client für Odoo
├── config.py               # Config Management (ENV + Odoo)
├── parsers/
│   ├── __init__.py
│   ├── base_parser.py      # Abstract Parser Interface
│   ├── shelly_parser.py    # Shelly PM Mini G3
│   ├── tasmota_parser.py   # Tasmota (optional)
│   └── generic_parser.py   # Generic JSON
├── requirements.txt        # Python Dependencies
├── Dockerfile              # Multi-stage Build
└── README.md               # Dieses Dokument

Konfiguration

ENV-Variablen

Die Bridge wird ausschließlich über Umgebungsvariablen konfiguriert:

Variable Pflicht Default Beschreibung
ODOO_URL - Odoo Base-URL (z.B. http://odoo:8069)
ODOO_TOKEN - API Token für Authentifizierung
MQTT_URL - MQTT Broker URL (z.B. mqtt://mosquitto:1883)
MQTT_USERNAME None MQTT Username (optional)
MQTT_PASSWORD None MQTT Password (optional)
LOG_LEVEL INFO Logging Level (DEBUG, INFO, WARNING, ERROR)
CONFIG_REFRESH_INTERVAL 300 Config-Refresh in Sekunden (5 Min)

Odoo-Konfiguration

Die Bridge holt Device-spezifische Konfiguration von Odoo via:

Request: GET /ows/iot/config

Response:

{
  "devices": [
    {
      "device_id": "shellypmminig3-48f6eeb73a1c",
      "mqtt_topic": "shaperorigin/status/pm1:0",
      "parser_type": "shelly_pm_mini_g3",
      "machine_name": "Shaper Origin",
      "session_config": {
        "strategy": "power_threshold",
        "standby_threshold_w": 20,
        "working_threshold_w": 100,
        "start_debounce_s": 3,
        "stop_debounce_s": 15,
        "message_timeout_s": 20
      }
    }
  ]
}

Event-Flow

1. MQTT Message empfangen

# Topic: shaperorigin/status/pm1:0
# Payload (Shelly Format):
{
  "id": 0,
  "voltage": 234.7,
  "current": 0.289,
  "apower": 120.5,  # ← Power-Wert!
  "aenergy": { "total": 256.325 }
}

2. Parser normalisiert zu Event Schema v1

{
  "schema_version": "v1",
  "event_uid": "b6d0a2c5-9b1f-4a0b-8b19-7f2e1b8f3d11",
  "ts": "2026-01-31T10:30:15.123Z",
  "device_id": "shellypmminig3-48f6eeb73a1c",
  "event_type": "power_measurement",
  "payload": {
    "apower": 120.5,
    "voltage": 234.7,
    "current": 0.289,
    "total_energy_kwh": 0.256325
  }
}

3. Session Detector analysiert

State Machine:
IDLE (Power < 20W)
  ↓ Power > 100W
STARTING (Debounce 3s)
  ↓ 3s vergangen, Power > 100W
WORKING (Session läuft)
  ↓ Power < 100W
STOPPING (Debounce 15s)
  ↓ 15s vergangen, Power < 20W
IDLE (Session beendet)

4. Events an Odoo senden

run_start Event:

POST /ows/iot/event
Authorization: Bearer <token>

{
  "schema_version": "v1",
  "event_uid": "...",
  "event_type": "run_start",
  "device_id": "shellypmminig3-48f6eeb73a1c",
  "ts": "2026-01-31T10:30:18.500Z",
  "payload": {
    "power_w": 120.5,
    "reason": "power_threshold"
  }
}

run_stop Event:

POST /ows/iot/event
{
  "event_type": "run_stop",
  "payload": {
    "power_w": 8.2,
    "reason": "normal",
    "duration_s": 187.3
  }
}

Docker Integration

Dockerfile

FROM python:3.11-slim

WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application
COPY . .

# Run as non-root
RUN useradd -m -u 1000 bridge && chown -R bridge:bridge /app
USER bridge

CMD ["python", "-u", "main.py"]

docker-compose.yaml

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
      LOG_LEVEL: INFO
    depends_on:
      - odoo
      - mosquitto
    networks:
      - odoo_network
    restart: unless-stopped

Development

Lokales Testen

# 1. Python Dependencies installieren
cd iot_bridge/
python -m venv venv
source venv/bin/activate  # Linux/Mac
pip install -r requirements.txt

# 2. ENV-Variablen setzen
export ODOO_URL=http://localhost:8069
export ODOO_TOKEN=your-token-here
export MQTT_URL=mqtt://localhost:1883
export LOG_LEVEL=DEBUG

# 3. Bridge starten
python main.py

Docker Build & Run

# Build
docker build -t iot_mqtt_bridge_for_odoo .

# Run
docker run --rm \
  -e ODOO_URL=http://odoo:8069 \
  -e ODOO_TOKEN=your-token \
  -e MQTT_URL=mqtt://mosquitto:1883 \
  iot_mqtt_bridge_for_odoo

Monitoring

Logs

# Docker Container Logs
docker compose logs -f iot_bridge

# Wichtige Log-Events:
# - [INFO] Bridge started, connecting to MQTT...
# - [INFO] MQTT connected, subscribing to topics...
# - [INFO] Config loaded: 3 devices
# - [DEBUG] Message received: topic=..., power=120.5W
# - [INFO] Session started: device=..., session_id=...
# - [WARNING] Odoo API error, retrying in 5s...

Health Check

Die Bridge sollte einen Health-Check-Endpoint anbieten:

# GET http://bridge:8080/health
{
  "status": "ok",
  "mqtt_connected": true,
  "odoo_reachable": true,
  "devices_configured": 3,
  "active_sessions": 1,
  "uptime_seconds": 3600
}

Fehlerbehandlung

MQTT Disconnect

  • Auto-Reconnect mit Exponential Backoff
  • Topics werden nach Reconnect neu subscribed
  • Laufende Sessions werden nicht beendet

Odoo Unreachable

  • Events werden in lokaler Queue gespeichert (in-memory oder SQLite)
  • Retry alle 5 Sekunden
  • Max. 1000 Events in Queue (älteste werden verworfen)

Config-Reload

  • Alle 5 Minuten: GET /ows/iot/config
  • Neue Devices → subscribe Topics
  • Gelöschte Devices → unsubscribe Topics
  • Geänderte Schwellenwerte → SessionDetector aktualisieren

Testing

Manuelle Tests

# Shelly Simulator für Tests
python tests/tools/shelly_simulator.py --scenario session_end
python tests/tools/shelly_simulator.py --scenario full_session
python tests/tools/shelly_simulator.py --scenario timeout

python3 tests/tools/shelly_simulator.py --broker localhost --port 1883 --no-tls --username "" --password "" --scenario full_session

### Unit Tests

```bash
pytest tests/test_session_detector.py -v
pytest tests/test_parsers.py -v
pytest tests/test_odoo_client.py -v

Integration Tests

# Requires: Running MQTT Broker + Odoo instance
pytest tests/integration/ -v

Production Deployment

Best Practices

  1. Token Security

    • Token in .env (nicht in Git)
    • Regelmäßige Token-Rotation
    • Separate Tokens pro Umgebung (dev/staging/prod)
  2. Logging

    • LOG_LEVEL=INFO in Production
    • LOG_LEVEL=DEBUG nur für Troubleshooting
    • Log-Aggregation (z.B. via Docker Logging Driver)
  3. Monitoring

    • Health-Check in Docker Compose
    • Alerts bei Container-Restart
    • Metrics: Events/s, Queue-Größe, Odoo-Latenz
  4. Scaling

    • Eine Bridge-Instanz pro MQTT-Broker
    • Mehrere Broker → mehrere Bridge-Container
    • Shared Subscriptions (MQTT 5.0) für Load-Balancing

Roadmap

Phase 1 (MVP)

  • Architektur-Design
  • MQTT Client Implementation
  • Shelly Parser
  • Session Detector (aus Odoo portiert)
  • Odoo REST Client
  • Dockerfile

Phase 2 (Features)

  • Retry-Queue (SQLite)
  • Health-Check-Endpoint
  • Tasmota Parser
  • Generic JSON Parser
  • Config-Hot-Reload

Phase 3 (Production)

  • Integration Tests
  • Docker Compose Example
  • Deployment Guide
  • Monitoring Dashboard
  • Performance Tuning

License

LGPL-3 (same as Odoo)