From dc840b63d8cfa1005bb1c79e85a83b12dc34857f Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:01:16 -0500 Subject: [PATCH] trying to improve on demand display --- src/display_manager.py | 29 ++++++++++++++++++++++------- web_interface_v2.py | 16 +++++++++------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/display_manager.py b/src/display_manager.py index 3ad61318..3bbbb167 100644 --- a/src/display_manager.py +++ b/src/display_manager.py @@ -21,10 +21,11 @@ class DisplayManager: cls._instance = super(DisplayManager, cls).__new__(cls) return cls._instance - def __init__(self, config: Dict[str, Any] = None, force_fallback: bool = False): + def __init__(self, config: Dict[str, Any] = None, force_fallback: bool = False, suppress_test_pattern: bool = False): start_time = time.time() self.config = config or {} self._force_fallback = force_fallback + self._suppress_test_pattern = suppress_test_pattern # Snapshot settings for web preview integration (service writes, web reads) self._snapshot_path = "/tmp/led_matrix_preview.png" self._snapshot_min_interval_sec = 0.2 # max ~5 fps @@ -105,8 +106,9 @@ class DisplayManager: logger.error(f"Failed to load initial font: {e}") self.font = ImageFont.load_default() - # Draw a test pattern - self._draw_test_pattern() + # Draw a test pattern unless caller suppressed it (e.g., web on-demand) + if not getattr(self, '_suppress_test_pattern', False): + self._draw_test_pattern() except Exception as e: logger.error(f"Failed to initialize RGB Matrix: {e}", exc_info=True) @@ -222,11 +224,24 @@ class DisplayManager: self.image = Image.new('RGB', (self.matrix.width, self.matrix.height)) self.draw = ImageDraw.Draw(self.image) - # Clear both canvases - self.offscreen_canvas.Clear() - self.current_canvas.Clear() + # Clear both canvases and the underlying matrix to ensure no artifacts + try: + self.offscreen_canvas.Clear() + except Exception: + pass + try: + self.current_canvas.Clear() + except Exception: + pass + try: + # Extra safety: clear the matrix front buffer as well + self.matrix.Clear() + except Exception: + pass - # Update the display to show the clear + # Update the display to show the clear. Swap twice to flush any latent frame. + self.update_display() + time.sleep(0.01) self.update_display() except Exception as e: logger.error(f"Error clearing display: {e}") diff --git a/web_interface_v2.py b/web_interface_v2.py index 4829c6df..0b49af36 100644 --- a/web_interface_v2.py +++ b/web_interface_v2.py @@ -38,15 +38,16 @@ import logging app = Flask(__name__) app.secret_key = os.urandom(24) -# Prefer eventlet if available for stable websockets on Pi; fall back gracefully -async_mode = None +# Use standard threads for background tasks to avoid blocking the web UI when +# running blocking I/O (e.g., requests) inside on-demand update loops. +# We still import eventlet if present so environments with it installed don't break, +# but we intentionally choose 'threading' for async_mode. try: import eventlet # noqa: F401 - async_mode = 'eventlet' except Exception: - async_mode = 'threading' + pass -socketio = SocketIO(app, cors_allowed_origins="*", async_mode=async_mode) +socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading') # Global variables config_manager = ConfigManager() @@ -151,9 +152,10 @@ class OnDemandRunner: if not display_manager: # Initialize with hardware if possible try: - display_manager = DisplayManager(self.config) + # Suppress the startup test pattern to avoid random lines flash during on-demand + display_manager = DisplayManager(self.config, suppress_test_pattern=True) except Exception: - display_manager = DisplayManager({'display': {'hardware': {}}}, force_fallback=True) + display_manager = DisplayManager({'display': {'hardware': {}}}, force_fallback=True, suppress_test_pattern=True) display_monitor.start() def _is_service_active(self) -> bool: