change web ui v2 server side loading

This commit is contained in:
Chuck
2025-08-10 12:02:33 -05:00
parent 8b7ae3beed
commit a49feb2971
2 changed files with 45 additions and 28 deletions

View File

@@ -1779,7 +1779,7 @@
// Socket.IO connection // Socket.IO connection
function initializeSocket() { function initializeSocket() {
socket = io(); socket = io({ transports: ['websocket', 'polling'] });
socket.on('connect', function() { socket.on('connect', function() {
updateConnectionStatus(true); updateConnectionStatus(true);
@@ -1789,6 +1789,17 @@
socket.on('disconnect', function() { socket.on('disconnect', function() {
updateConnectionStatus(false); updateConnectionStatus(false);
showNotification('Disconnected from LED Matrix', 'error'); showNotification('Disconnected from LED Matrix', 'error');
// Try to reconnect with exponential backoff
let attempt = 0;
const retry = () => {
attempt++;
const delay = Math.min(30000, 1000 * Math.pow(2, attempt));
setTimeout(() => {
if (socket.connected) return;
socket.connect();
}, delay);
};
retry();
}); });
socket.on('display_update', function(data) { socket.on('display_update', function(data) {

View File

@@ -19,7 +19,15 @@ import logging
app = Flask(__name__) app = Flask(__name__)
app.secret_key = os.urandom(24) app.secret_key = os.urandom(24)
socketio = SocketIO(app, cors_allowed_origins="*") # Prefer eventlet if available for stable websockets on Pi; fall back gracefully
async_mode = None
try:
import eventlet # noqa: F401
async_mode = 'eventlet'
except Exception:
async_mode = 'threading'
socketio = SocketIO(app, cors_allowed_origins="*", async_mode=async_mode)
# Global variables # Global variables
config_manager = ConfigManager() config_manager = ConfigManager()
@@ -40,28 +48,21 @@ class DisplayMonitor:
def start(self): def start(self):
if not self.running: if not self.running:
self.running = True self.running = True
self.thread = threading.Thread(target=self._monitor_loop) # Use SocketIO background task for better async compatibility
self.thread.daemon = True self.thread = socketio.start_background_task(self._monitor_loop)
self.thread.start()
def stop(self): def stop(self):
self.running = False self.running = False
if self.thread: # Background task will exit on next loop; no join needed
self.thread.join()
def _monitor_loop(self): def _monitor_loop(self):
global display_manager, current_display_data global display_manager, current_display_data
while self.running: while self.running:
try: try:
if display_manager and hasattr(display_manager, 'image'): if display_manager and hasattr(display_manager, 'image'):
# Convert PIL image to base64 for web display # Convert raw image to base64 (no server-side scaling; client scales visually)
img_buffer = io.BytesIO() img_buffer = io.BytesIO()
# Scale up the image for better visibility (8x instead of 4x for better clarity) display_manager.image.save(img_buffer, format='PNG')
scaled_img = display_manager.image.resize((
display_manager.image.width * 8,
display_manager.image.height * 8
), Image.NEAREST)
scaled_img.save(img_buffer, format='PNG')
img_str = base64.b64encode(img_buffer.getvalue()).decode() img_str = base64.b64encode(img_buffer.getvalue()).decode()
current_display_data = { current_display_data = {
@@ -77,7 +78,11 @@ class DisplayMonitor:
except Exception as e: except Exception as e:
logger.error(f"Display monitor error: {e}", exc_info=True) logger.error(f"Display monitor error: {e}", exc_info=True)
time.sleep(0.05) # Update 20 times per second for smoother display # Yield to the async loop; target ~10 FPS to reduce load
try:
socketio.sleep(0.1)
except Exception:
time.sleep(0.1)
display_monitor = DisplayMonitor() display_monitor = DisplayMonitor()
@@ -126,7 +131,7 @@ def get_system_status():
"""Get current system status including display state, performance metrics, and CPU utilization.""" """Get current system status including display state, performance metrics, and CPU utilization."""
try: try:
# Check if display service is running # Check if display service is running
result = subprocess.run(['sudo', 'systemctl', 'is-active', 'ledmatrix'], result = subprocess.run(['systemctl', 'is-active', 'ledmatrix'],
capture_output=True, text=True) capture_output=True, text=True)
service_active = result.stdout.strip() == 'active' service_active = result.stdout.strip() == 'active'
@@ -134,8 +139,8 @@ def get_system_status():
memory = psutil.virtual_memory() memory = psutil.virtual_memory()
mem_used_percent = round(memory.percent, 1) mem_used_percent = round(memory.percent, 1)
# Get CPU utilization # Get CPU utilization (non-blocking to avoid stalling the event loop)
cpu_percent = round(psutil.cpu_percent(interval=0.1), 1) cpu_percent = round(psutil.cpu_percent(interval=None), 1)
# Get CPU temperature # Get CPU temperature
try: try:
@@ -191,8 +196,8 @@ def start_display():
logger.info("DisplayManager initialized successfully") logger.info("DisplayManager initialized successfully")
except Exception as dm_error: except Exception as dm_error:
logger.error(f"Failed to initialize DisplayManager: {dm_error}") logger.error(f"Failed to initialize DisplayManager: {dm_error}")
# Create a fallback display manager for web simulation # Re-attempt with minimal config to enable fallback simulation
display_manager = DisplayManager(config) display_manager = DisplayManager({'display': {'hardware': {}}})
logger.info("Using fallback DisplayManager for web simulation") logger.info("Using fallback DisplayManager for web simulation")
display_monitor.start() display_monitor.start()
@@ -871,4 +876,5 @@ if __name__ == '__main__':
display_monitor.start() display_monitor.start()
# Run the app # Run the app
socketio.run(app, host='0.0.0.0', port=5001, debug=False, allow_unsafe_werkzeug=True) # eventlet/gevent provide a proper WSGI server; Werkzeug is fine for dev
socketio.run(app, host='0.0.0.0', port=5001, debug=False)