diff --git a/templates/index_v2.html b/templates/index_v2.html index a1dd648b..a188c838 100644 --- a/templates/index_v2.html +++ b/templates/index_v2.html @@ -1779,11 +1779,19 @@ // Socket.IO connection function initializeSocket() { - socket = io({ transports: ['websocket', 'polling'] }); + socket = io({ + path: '/socket.io', + transports: ['websocket', 'polling'], + reconnection: true, + reconnectionAttempts: Infinity, + reconnectionDelay: 1000, + reconnectionDelayMax: 10000 + }); socket.on('connect', function() { updateConnectionStatus(true); showNotification('Connected to LED Matrix', 'success'); + stopPreviewPolling(); }); socket.on('disconnect', function() { @@ -1800,6 +1808,12 @@ }, delay); }; retry(); + startPreviewPolling(); + }); + + socket.on('connect_error', function(_err){ + updateConnectionStatus(false); + startPreviewPolling(); }); socket.on('display_update', function(data) { @@ -1807,6 +1821,24 @@ }); } + // Fallback polling when websocket is disconnected + let __previewPollTimer = null; + function startPreviewPolling(){ + if (__previewPollTimer) return; + __previewPollTimer = setInterval(fetchCurrentDisplayOnce, 1000); + } + function stopPreviewPolling(){ + if (__previewPollTimer) clearInterval(__previewPollTimer); + __previewPollTimer = null; + } + async function fetchCurrentDisplayOnce(){ + try { + const res = await fetch('/api/display/current'); + const data = await res.json(); + if (data && data.image) updateDisplayPreview(data); + } catch (_) {} + } + // Draw pixel grid lines on top of scaled image function drawGrid(canvas, logicalWidth, logicalHeight, scale) { const show = document.getElementById('toggleGrid')?.checked; diff --git a/web_interface_v2.py b/web_interface_v2.py index 66862703..2e42de05 100644 --- a/web_interface_v2.py +++ b/web_interface_v2.py @@ -851,9 +851,23 @@ def get_current_display(): def handle_connect(): """Handle client connection.""" emit('connected', {'status': 'Connected to LED Matrix Interface'}) - # Send current display state - if current_display_data: - emit('display_update', current_display_data) + # Send current display state immediately after connect + try: + if display_manager and hasattr(display_manager, 'image'): + img_buffer = io.BytesIO() + display_manager.image.save(img_buffer, format='PNG') + img_str = base64.b64encode(img_buffer.getvalue()).decode() + payload = { + 'image': img_str, + 'width': display_manager.width, + 'height': display_manager.height, + 'timestamp': time.time() + } + emit('display_update', payload) + elif current_display_data: + emit('display_update', current_display_data) + except Exception as e: + logger.error(f"Error sending initial display_update on connect: {e}") @socketio.on('disconnect') def handle_disconnect(): @@ -872,7 +886,7 @@ if __name__ == '__main__': signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) - # Start the display monitor + # Start the display monitor (runs even if display is not started yet for web preview) display_monitor.start() # Run the app