Commit Graph

33 Commits

Author SHA1 Message Date
080a7275d9 Phase 3.3: Harden error handling and recovery patterns
- Add optional Odoo circuit-breaker for transient failures
- Unify timeout handling in Odoo and MQTT clients
- Improve transient error classification (timeout/connection/5xx/429)
- Add focused unit tests for recovery and circuit-breaker behavior
- Mark Phase 3.3 tasks as completed in optimization plan
2026-02-19 19:07:13 +01:00
f7b5a28f9a Fix: sync device status timeout with Odoo message timeout
- Include device_status_timeout_s in Odoo bridge payload
- Resolve status monitor timeout robustly with backward-compatible fallbacks
- Update running status monitor timeout on POST /config without restart
- Keep compatibility for legacy/local configs without device_status_timeout_s

Result: shaperorigin uses configured 90s timeout for online/offline monitor, preventing 30s flapping.
2026-02-19 18:40:30 +01:00
e723315e35 Fix: Unify device_status timeout with message_timeout_s
Problem: Device Status Monitor was using a hardcoded 30-second global timeout
for marking devices offline, independent of the configurable message_timeout_s.
This caused alternating offline/online events for devices with power=0 that
don't send frequent MQTT messages.

Solution: Use the same timeout value (message_timeout_s) for both:
1. Session Detection (message_timeout_s)
2. Device Status Monitoring (device_status_timeout_s)

Implementation:
- Add device_status_timeout_s field to api/models.py DeviceConfig (default: 120s)
- Update Odoo iot_api.py to include device_status_timeout_s in config response
  (synchronized with message_timeout_s from device strategy config)
- Update Bridge service_manager.py to use device_status_timeout_s when
  initializing DeviceStatusMonitor (fallback to global config if not provided)

Result:
- Single configurable timeout per device in Odoo
- Both checks (session + device status) use same value
- Backward compatible (defaults to 120s if not provided)
- Solves alternating offline/online events for low-power/idle devices

Validation:
- mypy: 0 errors across 47 files
- API model test: device_status_timeout_s field functional
2026-02-19 00:09:22 +01:00
ff4ef2f563 Phase 3: Complete type safety & logging unification (3.1-3.2)
Phase 3.1: Type Safety
- Add bridge_types.py for shared type aliases (EventDict, PowerWatts, Timestamp, DeviceID)
- Define protocols for callbacks and message parsers
- Strict type annotations on all core modules (session_detector, event_queue, device_manager)
- Fix Optional handling and type guards throughout codebase
- Achieve full mypy compliance: 0 errors across 47 source files

Phase 3.2: Logging Unification
- Migrate from stdlib logging to pure structlog across all runtime modules
- Convert all logs to structured event+fields format (snake_case event names)
- Remove f-string and printf-style logger calls
- Add contextvars support for per-request correlation
- Implement FastAPI middleware to bind request_id, http_method, http_path
- Propagate X-Request-ID header in responses
- Remove stdlib logging imports except setup layer (utils/logging.py)
- Ensure log-level consistency across all modules

Files Modified:
- iot_bridge/bridge_types.py (new) - Central type definitions
- iot_bridge/core/* - Type safety and logging unification
- iot_bridge/clients/* - Structured logging with request context
- iot_bridge/parsers/* - Type-safe parsing with structured logs
- iot_bridge/utils/logging.py - Pure structlog setup with contextvars
- iot_bridge/api/server.py - Added request correlation middleware
- iot_bridge/tests/* - Test fixtures updated for type safety
- iot_bridge/OPTIMIZATION_PLAN.md - Phase 3 status updated

Validation:
- mypy . → 0 errors (47 files)
- All unit tests pass
- Runtime behavior unchanged
- API response headers include X-Request-ID
2026-02-18 23:54:27 +01:00
4214a61b19 Complete phase 2 rest points: env overrides and unit tests 2026-02-18 23:30:33 +01:00
ca31e3f4a6 Update README.md 2026-02-18 23:29:36 +01:00
a4ea77e6b3 feat(phase2.4): add dependency injection container and factory wiring
Implemented Phase 2.4 (Dependency Injection Pattern):

- Added new dependencies module with DI container and runtime context
  - RuntimeContainer for injectable factories
  - RuntimeContext for resolved runtime objects
  - create_service_manager() factory
  - build_runtime_context() composition root
- Refactored main.py to use dependency container wiring
  - Main orchestration now resolves runtime via DI factories
  - Reduced direct constructor coupling in entrypoint
- Added unit tests for DI behavior with mocked dependencies
  - Verifies factory injection for service manager creation
  - Verifies runtime composition uses injected callables
- Updated optimization plan checkboxes for Phase 2.4

Validation:
- py_compile passed for new/changed files
- tests/unit/test_dependencies.py passed
- regression test test_event_queue::test_enqueue passed

Notes:
- Keeps existing runtime behavior unchanged
- Establishes clear composition root for future testability improvements
2026-02-18 23:17:22 +01:00
0c19bd35d0 docs(plan): Update optimization plan progress for phases 0-2
- Set overall status to in-progress
- Mark Phase 2 as partially completed
- Add implemented Phase 2 commit references
- Check off completed tasks for 2.1, 2.2 and 2.3
- Update timeline table (Phase 0/1 done, Phase 2 partial)

Note: Remaining open checkboxes now reflect work still pending (tests, DI, env hierarchy docs).
2026-02-18 23:13:39 +01:00
bad1d5d528 fix(runtime): restore MQTT reconnect reliability and persist API config state
- Recreate MQTT client on reconnect to apply broker/auth/TLS changes reliably
- Restart loop on new MQTT client instance after reconnect
- Track loop lifecycle to avoid stale client state
- Include MQTT section in initial ConfigServer current_config state
- Keep /config response consistent with persisted /data/config-active.yaml after restart

Result:
- Broker switches via Odoo push now connect reliably (including TLS/non-TLS changes)
- Bridge startup + persisted config reload now exposes mqtt data correctly via GET /config
- Event flow MQTT -> Bridge -> Odoo remains stable after container restarts
2026-02-18 23:10:12 +01:00
527b5645ed refactor(phase2.3): Migrate to Pydantic V2 and modernize config management
Complete Pydantic V2 migration and config modernization:

api/models.py:
- Migrated @validator → @field_validator (Pydantic V2)
- Added @classmethod decorators (required in V2)
- Updated validator signatures: (cls, v, values) → (cls, v, info)
- Consolidated unique validators into one method
- Fixed: 3 PydanticDeprecatedSince20 warnings 

config/schema.py:
- Migrated from @dataclass → Pydantic BaseModel
- Added Field() with validation constraints:
  * Port: ge=1, le=65535
  * Floats: gt=0, ge=0
  * Strings: min_length constraints
- Added descriptive field descriptions
- Better type safety and runtime validation

core/bootstrap.py:
- Replaced SimpleNamespace → MQTTConfig (Pydantic)
- Now returns properly typed Pydantic models
- Better IDE autocomplete and type checking

Benefits:
 No more Pydantic V1 deprecation warnings
 Runtime validation for all config fields
 Better error messages on invalid config
 Type-safe config throughout the application
 Automatic validation (port ranges, positive numbers, etc.)
 Prepared for Pydantic V3 migration

Migration verified:
- Config loading works: load_config('config.example.yaml') ✓
- Bootstrap works with Pydantic models ✓
- Field validation works (tested port ranges, thresholds) ✓
- All existing functionality preserved ✓

Test: python3 -c 'from core.bootstrap import bootstrap; bootstrap()'
 Works perfectly with new Pydantic V2 models

See OPTIMIZATION_PLAN.md Phase 2.3 for details.
2026-02-18 22:53:36 +01:00
eb3c49c8c4 refactor(phase2.2): Refactor main.py - Extract bootstrap and service_manager
Massive refactoring of main.py to improve code organization:

Files Created:
1. core/bootstrap.py (234 lines)
   - BootstrapConfig: Configuration container
   - parse_arguments(): CLI arg parsing
   - load_bridge_config(): Config loading with persisted fallback
   - setup_logger(): Structured logging setup
   - get_mqtt_config(): MQTT config with env var fallback
   - bootstrap(): Complete initialization orchestration

2. core/service_manager.py (369 lines)
   - ServiceManager: Central service lifecycle coordinator
   - Signal handlers for graceful shutdown
   - Service initialization (Odoo, MQTT, Event Queue, etc.)
   - Callbacks for config updates and MQTT reconnection
   - Graceful shutdown sequencing

Files Modified:
   - Now ultra-clean entry point
   - Only orchestration logic remains
   - 7-phase startup sequence clearly documented

2. core/__init__.py
   - Export new modules for clean imports

Benefits:
-  Single Responsibility: Each module has one clear purpose
-  Testability: Services can be tested independently
-  Readability: main.py is now self-documenting
-  Maintainability: Easy to find and modify specific logic
-  No global variables: All state in ServiceManager
-  Type hints throughout

Architecture:
  main.py (orchestration)
    ├── bootstrap() → config + logger
    └── ServiceManager() → all services
         ├── Odoo Client
         ├── Event Queue
         ├── Status Monitor
         ├── MQTT Client
         ├── Device Manager
         └── HTTP Config Server

Test: python3 main.py --config config.example.yaml
 Bridge starts successfully with all services

See OPTIMIZATION_PLAN.md Phase 2.2 for details.
2026-02-18 22:43:00 +01:00
548f94a652 refactor(exceptions): Erweitere Exception-Klassen mit vollständigen Implementierungen
Alle Exception-Klassen haben jetzt sinnvolle __init__-Methoden:

- ConfigurationError: path Parameter für Config-Dateipfad
- ConfigValidationError: field + value für fehlerhafte Felder
- ConnectionError: service Parameter (mqtt/odoo)
- MQTTConnectionError: broker + port Parameter
- DeviceError: device_id Parameter
- ValidationError: field + value für Validierungsfehler

Vorher: Klassen hatten nur 'pass' (technisch korrekt, aber wenig nützlich)
Nachher: Strukturierte Fehlerkontext-Erfassung mit dedizierten Attributen

Beispiel:
  # Alt:  raise ConfigurationError('File not found', details={'path': ...})
  # Neu:  raise ConfigurationError('File not found', path='/etc/config.yaml')

Angepasst:
- config/loader.py: Nutzt neuen path-Parameter statt details-Dict
- Alle bestehenden Aufrufe bleiben kompatibel (backward-compatible)

Test: python3 -c 'from exceptions import *; e = MQTTConnectionError(...)'
2026-02-18 22:33:37 +01:00
e744a1e4cb feat(phase2): Add custom exception hierarchy (Phase 2.1)
Implemented structured exception handling:

Exception Hierarchy:
- BridgeError (base)
  ├── ConfigurationError
  │   └── ConfigValidationError
  ├── ConnectionError
  │   ├── MQTTConnectionError
  │   └── OdooAPIError (with status_code, response fields)
  ├── DeviceError
  │   ├── DeviceNotFoundError
  │   └── ParserError (with topic, payload context)
  └── ValidationError

Changes:
- Created exceptions.py with comprehensive exception classes
- Updated clients/odoo_client.py to use OdooAPIError
  * Replaced generic Exception with OdooAPIError
  * Added status_code and response context
  * Better error messages for API failures
- Updated clients/mqtt_client.py to import MQTTConnectionError
- Updated config/loader.py to use ConfigurationError
  * Replaced FileNotFoundError with ConfigurationError
  * Added file path context to errors
- Updated parsers/shelly_parser.py to import ParserError (for future use)

Benefits:
- Specific exception types enable targeted error handling
- Better debugging with structured error context
- Easier to catch and handle specific error categories
- Backward compatible - errors still propagate correctly
- Foundation for better error reporting in Phase 4

Remaining Phase 2 tasks (deferred):
- 2.2: main.py refactoring (will be separate PR)
- 2.3: Config management modernization (Pydantic migration)

See OPTIMIZATION_PLAN.md Phase 2.1 for details.
2026-02-18 22:27:28 +01:00
e675256e0e chore: Apply code quality tools (black, isort, ruff)
Automated code quality improvements:

Black (Code Formatter):
- Reformatted 30 files to match PEP 8 style
- Consistent line length (100 chars)
- Consistent quote style and spacing

isort (Import Sorter):
- Fixed import order in 30+ files
- Grouped imports: stdlib → third-party → first-party → local
- Consistent multi-line import formatting

Ruff (Linter):
- Auto-fixed 161 issues:
  * Modernized type hints (List → list, Optional[X] → X | None)
  * Removed unused imports (json, os, typing utilities)
  * Updated deprecated typing imports (typing.List → list)
  * Simplified type annotations with | operator (Python 3.10+)
- Remaining 20 issues (acceptable):
  * 9x unused-method-argument (callback signatures, cannot be changed)
  * 2x bare-except (intentional for resilience)
  * 2x unused-variable (will be addressed in Phase 2)
  * Minor simplification opportunities (not critical)

Code Quality Stats:
- 32 files modified
- +1749/-1589 lines (net cleanup)
- Code is now consistent and formatted
- Ready for gradual type safety improvements (Phase 3)

All changes are non-functional - pure formatting and import organization.
2026-02-18 22:20:25 +01:00
33f238a5b4 docs: Mark Phase 1 as completed with commit hash 2026-02-18 22:11:46 +01:00
fdddba7469 Phase 1: Foundation & Quality Tools
Implemented comprehensive development infrastructure:

1.1 Code Quality Tools:
- Created pyproject.toml with configurations for:
  * Black (code formatter, line-length=100)
  * isort (import sorter, black profile)
  * mypy (type checker, lenient settings for gradual adoption)
  * pytest (test runner with coverage)
  * ruff (modern linter replacing flake8/pylint)
  * bandit (security scanner)
- Added .pre-commit-config.yaml with:
  * File hygiene hooks (trailing whitespace, EOF, YAML/JSON checks)
  * Code formatting (black, isort, ruff)
  * Security checks (bandit)
- Created requirements-dev.txt for development dependencies
- Added .gitignore for Python projects

1.2 Test Infrastructure:
- Created tests/conftest.py with shared fixtures:
  * Config fixtures (mqtt_config, odoo_config, bridge_config, etc.)
  * MQTT client mocks (mock_mqtt_client, mock_paho_mqtt_client)
  * Odoo client mocks (mock_odoo_client, mock_requests)
  * Device/parser fixtures (shelly_pm_message, mock_parser)
  * Session detector & event queue fixtures
- Created tests/helpers.py with test utilities:
  * assert_event_valid, assert_mqtt_topic_valid
  * create_mock_mqtt_message
  * wait_for_condition helper
- Created tests/fixtures/ with specialized fixtures:
  * mqtt_fixtures.py: MQTT message factory, simulated broker
  * config_fixtures.py: Config file factory, minimal/full configs
  * device_fixtures.py: Device events, session events, Shelly payloads

1.3 CI/CD Pipeline:
- Created .github/workflows/iot-bridge-test.yml:
  * Lint job: ruff, black, isort, bandit
  * Type check job: mypy
  * Test job: pytest on Python 3.10, 3.11, 3.12 with coverage
  * Integration test job: with Mosquitto MQTT broker service
  * Docker build test job
  * Quality gate job: ensures all checks pass

Documentation:
- Updated README.md with Development section:
  * Local setup instructions
  * Code quality tools usage
  * Testing commands
  * Updated project structure diagram

Benefits:
- Automated code quality checks via pre-commit hooks
- Comprehensive test fixtures reduce test boilerplate
- CI/CD pipeline catches issues early
- Matrix testing ensures Python 3.10-3.12 compatibility
- Foundation for gradual type safety improvements (Phase 3)

See OPTIMIZATION_PLAN.md Phase 1 for details.
2026-02-18 22:11:25 +01:00
21279c80bf fix: Update remaining import from config_server to api.models
- Fix ModuleNotFoundError in core/device_manager.py
- Change 'from config_server import BridgeConfig' to 'from api.models import BridgeConfig'
- This was missed during Phase 0 refactoring
2026-02-18 21:54:27 +01:00
2f9201ad8b docs: Mark Phase 0 as completed in OPTIMIZATION_PLAN.md 2026-02-18 21:49:38 +01:00
a5929ed290 Phase 0: Reorganize directory structure for better code organization
- Create modular package structure (core/, clients/, parsers/, api/, config/, utils/)
- Move core business logic to core/ (session_detector, event_queue, device_manager)
- Move external clients to clients/ (mqtt_client, odoo_client)
- Split config.py into config/schema.py (dataclasses) and config/loader.py (I/O)
- Split config_server.py into api/server.py (FastAPI) and api/models.py (Pydantic)
- Create parsers/base.py with MessageParser protocol for extensible parser architecture
- Move utilities to utils/ (logging, status_monitor)
- Update all imports across project (main.py, tests)
- Add __init__.py to all packages with proper exports
- Update README.md with new project structure
- All git mv commands preserve file history

This reorganization improves:
- Code discoverability (clear package responsibilities)
- Maintainability (separation of concerns)
- Extensibility (protocols for parsers, clean API separation)
- Testing (isolated packages easier to mock/test)

See OPTIMIZATION_PLAN.md for full roadmap (Phase 0-5)
2026-02-18 21:48:14 +01:00
e82c73441b Update Implementation Plan 2026-02-18 21:20:22 +01:00
3eaf2e933d feat: IoT Bridge Health Monitoring & Dynamic MQTT Reconnection
Features:
- Added ows.mqtt.bridge model with health status monitoring
- Bridge list/form views with status indicators (Online/Offline/Unknown)
- Scheduled action for periodic health checks (every 2 minutes)
- Health metrics: devices count, subscriptions, last seen timestamp
- Manual health check button in UI
- Smart button linking brokers to bridge instance

Infrastructure:
- Added ows.mqtt.broker model for MQTT broker configurations
- Bridge-Broker relation via Many2one field
- Dynamic MQTT reconnection without container restart
- Robust startup: Bridge starts even when MQTT fails
- TLS reconfiguration limitation documented (paho-mqtt)

Technical Changes:
- Updated models to use @api.model_create_multi for Odoo 18
- Fixed view definitions: tree → list for Odoo 18 compatibility
- Removed mail.thread dependency (unnecessary chatter)
- Added ir.cron for automated health monitoring
- Security/ACL rules for bridge and broker models
- Menu integration under IoT/MQTT section

Documentation:
- Updated IMPLEMENTATION_PLAN.md with new features
- Updated Odoo module README with bridge/broker models
- iot_bridge/README.md already documents dynamic reconnection

Testing:
- All changes tested via Odoo module upgrade
- Health check endpoint verified: GET /health
- Bridge reconnection tested with broker config changes
2026-02-18 20:36:11 +01:00
d3a28fddb6 feat: benutzerfreundliche GUI für Device-Konfiguration mit Auto-Config-Push
Hauptänderungen:
─────────────
 Benutzerfreundliche GUI statt JSON-Eingabe
  • Abrechnungs-Intervall (Minuten) - klar verständlich statt heartbeat_interval_s
  • Einschalt-/Arbeits-Schwellen (Watt) - statt technischer Begriffe
  • Anlauf-/Abschalt-Verzögerung (Sekunden) - erklärt was es tut
  • Icons, Hilfe-Texte, Beispiele direkt am Feld

🔄 Auto-Config-Push an Bridge
  • write() Hook: Automatischer Push bei Feldänderungen
  • create() Hook: Push bei neuem Device
  • unlink() Hook: Push bei Device-Löschung
  • Retry-Logic: 3 Versuche mit exponential backoff
  • Manueller Button: 🔄 Push Config to Bridge

📊 Transparente Abrechnung
  • Duration-Breakdown: Total = Working + Standby + Idle
  • Alle Zeiten in Minuten (billing-friendly)
  • Idle-Zeit zeigt Overhead (Debounce/Timeout) transparent

🧹 Code-Cleanup
  • Deprecated write() Hook entfernt
  • Überflüssige _onchange_session_strategy() entfernt
  • Computed Field: strategy_config automatisch generiert
  • Validation mit verständlichen deutschen Fehlermeldungen

Technische Details:
──────────────────
Models (mqtt_device.py):
  • billing_interval_min, power_on_threshold_w, active_work_threshold_w,
    startup_delay_s, shutdown_delay_s, message_timeout_s
  • Computed: strategy_config = f(alle benutzerfreundlichen Felder)
  • relevant_fields erweitert für Auto-Push Trigger

Views (mqtt_device_views.xml):
  •  Leistungs-Schwellenwerte
  • ⏱️ Zeitsteuerung
  • 💰 Abrechnung mit Info-Box
  • Generierte Config (readonly) für Debugging

Sessions (mqtt_session.py):
  • idle_duration_s = max(0, total - working - standby)
  • *_duration_min Felder für alle Zeiten
  • Displays konvertiert: hours → minutes

Bridge (session_detector.py):
  • Payload standardisiert: power_w, state (konsistent in allen Events)
  • Heartbeat-Intervall aus Odoo billing_interval_min

Feature Request:
  • Implementierungsstatus aktualisiert (Phase 1+2 komplett)
  • Lessons Learned dokumentiert
  • Nächste Schritte definiert

 Tests bestätigt:
  • Events kommen im konfigurierten Abrechnungs-Intervall (1 Min)
  • Config-Push funktioniert automatisch
  • Duration-Breakdown ist transparent
  • GUI ist verständlich und hilfreich
2026-02-17 00:09:51 +01:00
0b6e41d207 refactor: standardize model naming to ows.* prefix for consistency
BREAKING CHANGE: Renamed models for consistent naming convention
- mqtt.device → ows.mqtt.device (table: ows_mqtt_device)
- mqtt.session → ows.mqtt.session (table: ows_mqtt_session)
- ows.iot.event unchanged (table: ows_iot_event)

Changes:
- Updated all Many2one/One2many relations to use new model names
- Updated all env references in controllers and tests
- Updated security CSV file with new model IDs
- Updated all view records (list/form/kanban/pivot/graph/search)
- Fixed controller reference that was still using old mqtt.session

Documentation:
- Added README.md for user-facing module documentation
- Regenerated API.md from updated docstrings
- Regenerated index.html from README.md

Cleanup:
- Removed debug/test files (check_routes.py, test-*.sh/txt)
- Removed obsolete python_proto_type directory

Note: This requires database migration or fresh setup.
Database was reset and module reinstalled successfully.
E2E test with Shelly Simulator passed.
2026-02-15 13:56:52 +01:00
78b9befc26 Changed Odoo Test Database from OWS_MQTT to odoo 2026-02-15 11:07:21 +01:00
ba588842ad feat: Add automatic API documentation generation and device status monitoring
- Implement build script (build_docs.py) with AST parser to auto-generate HTML docs from docstrings
- Add comprehensive Google-style docstrings to all controllers and models
- Create static/description/index.html for Odoo Apps UI with module overview
- Generate api_reference.html (20.5 KB) from source code, linked from Odoo UI
- Add DOCUMENTATION_STRATEGY.md with comparison of 5 documentation approaches
- Create API.md with complete REST API documentation

Device Status Monitoring:
- Implement device_status_monitor.py with health checks and offline detection
- Add /status endpoint for device health overview
- Automatic offline detection after message_timeout_s

Config Push Architecture:
- Add POST /config endpoint to IoT Bridge for dynamic device management
- Auto-push device config from Odoo on create/write/unlink
- Implement device_manager.py for runtime device updates

E2E Tests:
- All 6 E2E tests passing (Create, Update, Push, Delete, Restart, Status Monitor)
- Test coverage for device lifecycle and config synchronization

Documentation is auto-generated via: ./build_docs.sh
View in Odoo: Settings → Apps → Open Workshop MQTT → API Reference
2026-02-15 11:03:22 +01:00
f1af17fd39 docs: complete phase 4 documentation 2026-02-12 21:12:02 +01:00
deaa95c650 refactor: Remove legacy PULL config methods (Phase 3.3)
Completes PUSH-only architecture - removes all PULL-based config fetching

REMOVED:
- MockOdooClient.get_config() method (~15 lines)
  - Legacy PULL logic: returned hardcoded device config
  - No longer used after PUSH architecture (Phase 3.1/3.2)

- OdooClient.get_config() method (~27 lines)
  - Legacy PULL logic: GET /ows/iot/config from Odoo
  - No longer used after PUSH architecture (Phase 3.1/3.2)

VERIFIED:
-  No periodic config refresh logic in main.py
-  Bridge loads config-active.yaml at startup only
-  Bridge receives config via POST /config (pushed by Odoo)
-  No GET requests to Odoo for config anymore

KEPT (unchanged):
- odoo_client.send_event() - still used for event pushing
- config_server.py GET /config - returns bridge's current config (debugging)

ARCHITECTURE CLEANUP:
Before: Bridge could PULL config from Odoo (get_config)
After:  Bridge ONLY receives PUSH from Odoo (POST /config)
        - Cleaner separation of concerns
        - No periodic polling overhead
        - Bridge fully autonomous with config-active.yaml

MODIFIED FILES:
- iot_bridge/odoo_client.py                          - ~40 lines removed
- IMPLEMENTATION_PLAN.md                            - Phase 3.3 marked complete

TESTING:
 Bridge still runs without config-active.yaml (waits for push)
 Bridge loads config-active.yaml at startup
 No errors in bridge logs (no missing get_config calls)
 Odoo push still works (Phase 3.2 model hooks)

NEXT STEP:
Phase 3.5 - End-to-End Tests (full PUSH architecture validation)
2026-02-12 20:28:54 +01:00
7337e57b40 feat: Implement Odoo Config-Push System (Phase 3.2)
Completes PUSH architecture - Odoo automatically pushes config to Bridge

NEW FEATURES:
- Model Hooks in mqtt.device (create/write/unlink)
  - Automatically push config after device create/update/delete
  - Smart detection: only relevant fields trigger push
  - Non-blocking: UI works even if bridge is offline

- Config Builder (_build_bridge_config)
  - Collects all active mqtt.device records
  - Converts to Bridge-compatible JSON format
  - Topic pattern transformation (/#→/status/pm1:0)
  - Session config extraction from strategy_config JSON
  - Returns BridgeConfig schema with timestamp + version

- HTTP Client with Retry Logic (_push_bridge_config)
  - POST to bridge_url/config with JSON payload
  - 3 retries with exponential backoff (1s, 2s, 4s)
  - Timeout: 10 seconds per request
  - Error handling: 4xx no retry, 5xx retry
  - Returns success/message dict for UI notifications

- System Parameter for Bridge URL
  - Configurable via ir.config_parameter
  - Key: open_workshop_mqtt.bridge_url
  - Default: http://iot-bridge:8080
  - Stored in data/system_parameters.xml

- Manual Push Button in UI
  - '🔄 Push Config to Bridge' button in device list header
  - Calls action_push_config_to_bridge()
  - Shows success/error notification toast
  - Allows manual sync when needed

NEW FILES:
- data/system_parameters.xml                          - Bridge URL param
- tests/test_config_push_integration.py              - Python integration test

MODIFIED FILES:
- models/mqtt_device.py                              - +250 lines (hooks, builder, client)
- views/mqtt_device_views.xml                        - Manual push button
- __manifest__.py                                    - requests dependency, data file

ARCHITECTURE CHANGE:
Before: Bridge pulls config from Odoo via GET /api/config
After:  Odoo pushes config to Bridge via POST /config
        - Triggered automatically on device changes (create/write/unlink)
        - Manual trigger via UI button
        - Bridge receives validated config via FastAPI endpoint

TESTING:
 Model hooks fire on create/write/unlink
 Config builder generates valid JSON
 HTTP client successfully pushes to bridge
 Retry logic works (tested with bridge down→up)
 Manual button displays notifications
 Bridge receives and applies config
 Device add/update/remove reflected in bridge

NEXT STEP:
Phase 3.3 - Remove legacy get_config() from bridge (no longer needed)
2026-02-12 20:18:13 +01:00
19be0903d2 feat: Implement HTTP Config API for Bridge (Phase 3.1)
Implements PUSH architecture - Bridge receives config from Odoo via HTTP

NEW FEATURES:
- HTTP Config Server (FastAPI on port 8080)
  - POST /config: Receive device configuration from Odoo
  - GET /config: Query currently active configuration
  - GET /health: Health check endpoint with device statistics
  - Optional Bearer token authentication (BRIDGE_API_TOKEN)

- Config Validation (Pydantic models)
  - BridgeConfig, DeviceConfig, SessionConfig schemas
  - Validation: unique device_id, unique mqtt_topic
  - Threshold validation: working_threshold_w > standby_threshold_w

- Dynamic Device Management (DeviceManager)
  - Device diff detection (add/update/remove)
  - Automatic MQTT subscribe/unsubscribe for topic changes
  - SessionDetector lifecycle management
  - Active session closing on device removal

- Config Persistence
  - Saves received config to /data/config-active.yaml
  - Bridge startup: loads config-active.yaml as fallback
  - Docker volume iot-bridge-data:/data for persistence

NEW FILES:
- iot_bridge/config_server.py          - FastAPI HTTP server
- iot_bridge/device_manager.py         - Device lifecycle management
- iot_bridge/tests/test-config-push.sh - Integration test script
- iot_bridge/tests/test-config-push.json - Test configuration

MODIFIED FILES:
- iot_bridge/main.py                   - Integrated HTTP server in thread
- iot_bridge/mqtt_client.py            - Added subscribe()/unsubscribe()
- iot_bridge/requirements.txt          - Added fastapi, uvicorn, pydantic
- iot_bridge/Dockerfile                - EXPOSE 8080, HTTP healthcheck
- odoo/docker-compose.dev.yaml         - Port 8080, volume /data

TESTING:
Verified via iot_bridge/tests/test-config-push.sh:
 Config push via HTTP works (200 OK)
 Old devices removed, new devices added
 MQTT topics dynamically updated (subscribe/unsubscribe)
 Config persisted to /data/config-active.yaml
 Health endpoint shows last_config_update timestamp
 Bridge restarts load config-active.yaml automatically

NEXT STEP:
Phase 3.2 - Implement Odoo-side config push (Model hooks)
2026-02-12 20:05:49 +01:00
18cac263a2 fix: Make IoT Bridge autonomous and fix session closing
Major architectural improvements to make Bridge resilient:

1. Bridge Autonomy (CRITICAL FIX):
   - Remove sys.exit(1) when Odoo config fails (iot_bridge/main.py)
   - Bridge now runs autonomously with local config.yaml
   - No longer crashes in endless restart loop when Odoo is down
   - Odoo connection check becomes optional warning, not blocker

2. Event Type Compatibility:
   - Add 'session_ended' to controller event processing (iot_api.py)
   - Bridge sends 'session_ended', controller expected 'session_stopped'
   - Now accepts both event types for closing sessions

3. Event Type Support:
   - Add 'session_ended' to iot_event model selection (iot_event.py)
   - Fixes 500 errors when Bridge sends session_ended events

4. Architecture Documentation:
   - Update FEATURE_REQUEST with new PUSH architecture (Odoo -> Bridge)
   - Update IMPLEMENTATION_PLAN with Phase 3 refactoring plan
   - Document autonomous mode and config-push design
   - Remove obsolete documentation files

Tested Scenarios:
-  Bridge starts and runs without Odoo
-  Session detection works autonomously
-  Events queue when Odoo is down
-  Queue automatically processes when Odoo returns
-  Sessions close correctly with session_ended events

This enables the next phase: Odoo pushing config to Bridge via HTTP API.
2026-02-12 19:28:25 +01:00
8c27373697 initial MQTT Development 2026-02-11 21:07:32 +01:00
a7897ecc9b added python_proto_type 2026-02-10 20:13:58 +01:00
807436df58 initial version 2026-02-10 20:00:27 +01:00