From b08a3f25649e9e8a6b9ebd6bd58faa128751d8f4 Mon Sep 17 00:00:00 2001 From: Wolfgang Hottgenroth Date: Thu, 27 Nov 2025 19:17:59 +0100 Subject: [PATCH] hottis modbus relay 7 --- apps/abstraction/transformation.py | 8 +-- apps/ui/static/api-client.js | 14 ++++- apps/ui/templates/device.html | 95 +++++++++++++++++++++++++++++- 3 files changed, 109 insertions(+), 8 deletions(-) diff --git a/apps/abstraction/transformation.py b/apps/abstraction/transformation.py index 835e8ed..9aa013d 100644 --- a/apps/abstraction/transformation.py +++ b/apps/abstraction/transformation.py @@ -448,13 +448,11 @@ def _transform_three_phase_powermeter_hottis_modbus_to_abstract(payload: str) -> """Transform hottis_modbus three_phase_powermeter payload to abstract format. Transformations: - - current_heating_setpoint -> target (as float) - - local_temperature -> current (as float) - - system_mode -> mode + - Direct mapping of all power meter fields Example: - - zigbee2mqtt: {'current_heating_setpoint': 15, 'local_temperature': 23, 'system_mode': 'heat'} - - Abstract: {'target': 15.0, 'current': 23.0, 'mode': 'heat'} + - hottis_modbus: {'energy': 123.45, 'total_power': 1500.0, 'phase1_power': 500.0, ...} + - Abstract: {'energy': 123.45, 'total_power': 1500.0, 'phase1_power': 500.0, ...} """ payload = json.loads(payload) abstract_payload = { diff --git a/apps/ui/static/api-client.js b/apps/ui/static/api-client.js index 6d8a880..875bacd 100644 --- a/apps/ui/static/api-client.js +++ b/apps/ui/static/api-client.js @@ -150,11 +150,15 @@ class HomeAutomationClient { this.eventSource.close(); } - this.eventSource = new EventSource(this.api('/realtime')); + const realtimeUrl = this.api('/realtime'); + console.log('Connecting to SSE endpoint:', realtimeUrl); + this.eventSource = new EventSource(realtimeUrl); this.eventSource.onmessage = (event) => { + console.log('Raw SSE event received:', event.data); try { const data = JSON.parse(event.data); + console.log('Parsed SSE data:', data); // Normalize event format: convert API format to unified format const normalizedEvent = { @@ -163,6 +167,7 @@ class HomeAutomationClient { state: data.payload || data.state // Support both formats }; + console.log('Normalized SSE event:', normalizedEvent); onEvent(normalizedEvent); // Notify all registered listeners @@ -172,12 +177,17 @@ class HomeAutomationClient { } }); } catch (error) { - console.error('Failed to parse SSE event:', error); + console.error('Failed to parse SSE event:', error, 'Raw data:', event.data); } }; + this.eventSource.onopen = (event) => { + console.log('SSE connection opened:', event); + }; + this.eventSource.onerror = (error) => { console.error('SSE connection error:', error); + console.log('EventSource readyState:', this.eventSource.readyState); if (onError) { onError(error); } diff --git a/apps/ui/templates/device.html b/apps/ui/templates/device.html index ab73082..91f52fa 100644 --- a/apps/ui/templates/device.html +++ b/apps/ui/templates/device.html @@ -217,6 +217,48 @@ color: #666; } + .phase-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; + } + + .phase-section h4 { + color: #333; + margin-bottom: 12px; + text-align: center; + } + + .phase-values { + display: flex; + flex-direction: column; + gap: 8px; + } + + .phase-value { + display: flex; + justify-content: space-between; + padding: 8px 12px; + background: rgba(102, 126, 234, 0.1); + border-radius: 8px; + } + + .phase-value .value { + font-weight: 600; + color: #667eea; + } + + .phase-value .unit { + color: #666; + font-size: 14px; + } + + @media (max-width: 768px) { + .phase-grid { + grid-template-columns: 1fr; + } + } + .state-badge { display: inline-block; padding: 8px 20px; @@ -298,7 +340,8 @@