Sfoglia il codice sorgente

perf(01-01): optimize timer, WebSocket, and preview cache in backend.py

Timer optimization (REQ-TIMER-01, REQ-TIMER-02):
- Replace 1-second continuous polling with event-driven single-shot timer
- Timer now fires once after timeout duration, not every second
- _reset_activity_timer restarts timer with full timeout
- Renamed _check_screen_timeout to _screen_timeout_triggered

WebSocket optimization (REQ-WS-01, REQ-WS-02):
- Remove print statements from pattern change detection
- Remove print statements from pause state changes
- Remove print statements from serial connection changes
- Remove print statements from speed changes
- Only emit signals when values actually change (existing behavior)

Preview cache (REQ-CACHE-01, REQ-CACHE-02):
- Add _preview_cache dictionary in __init__
- Check cache before filesystem lookup in _find_pattern_preview
- Cache positive results after successful lookup
- Add _clear_preview_cache method for cache invalidation
tuanchris 1 settimana fa
parent
commit
bd48ed481b
1 ha cambiato i file con 35 aggiunte e 40 eliminazioni
  1. 35 40
      dune-weaver-touch/backend.py

+ 35 - 40
dune-weaver-touch/backend.py

@@ -104,6 +104,9 @@ class Backend(QObject):
         self._backend_connected = False
         self._reconnect_status = "Connecting to backend..."
 
+        # Preview path cache to avoid repeated filesystem lookups
+        self._preview_cache = {}  # filename -> preview_path
+
         # LED control state
         self._led_provider = "none"  # "none", "wled", or "dw_leds"
         self._led_connected = False
@@ -138,11 +141,13 @@ class Backend(QObject):
         self._last_screen_change = 0  # Track last state change time
         self._use_touch_script = False  # Disable external touch-monitor script (too sensitive)
         self._screen_timer = QTimer()
-        self._screen_timer.timeout.connect(self._check_screen_timeout)
-        self._screen_timer.start(1000)  # Check every second
+        self._screen_timer.setSingleShot(True)  # Event-driven, fires only once per timeout
+        self._screen_timer.timeout.connect(self._screen_timeout_triggered)
         # Load local settings first
         self._load_local_settings()
-        print(f"🖥️ Screen management initialized: timeout={self._screen_timeout}s, timer started")
+        # Start the initial timeout timer if enabled
+        if self._screen_timeout > 0:
+            self._screen_timer.start(self._screen_timeout * 1000)
         
         # HTTP session - initialize lazily
         self.session = None
@@ -316,10 +321,8 @@ class Backend(QObject):
 
                 # Detect pattern change and emit executionStarted signal
                 if new_file and new_file != self._current_file:
-                    print(f"🎯 Pattern changed from '{self._current_file}' to '{new_file}'")
                     # Find preview for the new pattern
                     preview_path = self._find_pattern_preview(new_file)
-                    print(f"🖼️ Preview path for new pattern: {preview_path}")
                     # Emit signal so UI can update
                     self.executionStarted.emit(new_file, preview_path)
 
@@ -329,14 +332,12 @@ class Backend(QObject):
                 # Handle pause state from WebSocket
                 new_paused = status.get("is_paused", False)
                 if new_paused != self._is_paused:
-                    print(f"⏸️ Pause state changed: {self._is_paused} -> {new_paused}")
                     self._is_paused = new_paused
                     self.pausedChanged.emit(new_paused)
 
                 # Handle serial connection status from WebSocket
                 ws_connection_status = status.get("connection_status", False)
                 if ws_connection_status != self._serial_connected:
-                    print(f"🔌 WebSocket serial connection status changed: {ws_connection_status}")
                     self._serial_connected = ws_connection_status
                     self.serialConnectionChanged.emit(ws_connection_status)
 
@@ -351,7 +352,6 @@ class Backend(QObject):
                 # Handle speed updates from WebSocket
                 ws_speed = status.get("speed", None)
                 if ws_speed and ws_speed != self._current_speed:
-                    print(f"⚡ WebSocket speed changed: {ws_speed}")
                     self._current_speed = ws_speed
                     self.speedChanged.emit(ws_speed)
 
@@ -426,11 +426,14 @@ class Backend(QObject):
             self.errorOccurred.emit(str(e))
     
     def _find_pattern_preview(self, fileName):
-        """Find the preview image for a pattern"""
+        """Find the preview image for a pattern (with caching)"""
+        # Check cache first
+        if fileName in self._preview_cache:
+            return self._preview_cache[fileName]
+
         try:
             # Extract just the filename from the path (remove any directory prefixes)
             clean_filename = fileName.split('/')[-1]  # Get last part of path
-            print(f"🔍 Original fileName: {fileName}, clean filename: {clean_filename}")
 
             # Check multiple possible locations for patterns directory
             # Use relative paths that work across different environments
@@ -443,8 +446,6 @@ class Backend(QObject):
             for patterns_dir in possible_dirs:
                 cache_dir = patterns_dir / "cached_images"
                 if cache_dir.exists():
-                    print(f"🔍 Searching for preview in cache directory: {cache_dir}")
-
                     # Extensions to try - PNG first for better kiosk compatibility
                     extensions = [".png", ".webp", ".jpg", ".jpeg"]
 
@@ -457,11 +458,11 @@ class Backend(QObject):
                         for ext in extensions:
                             preview_file = cache_dir / (filename + ext)
                             if preview_file.exists():
-                                print(f"✅ Found preview (direct): {preview_file}")
-                                return str(preview_file.absolute())
+                                preview_path = str(preview_file.absolute())
+                                self._preview_cache[fileName] = preview_path
+                                return preview_path
 
                     # If not found directly, search recursively through subdirectories
-                    print(f"🔍 Searching recursively in {cache_dir}...")
                     for filename in filenames_to_try:
                         for ext in extensions:
                             target_name = filename + ext
@@ -469,15 +470,17 @@ class Backend(QObject):
                             matches = list(cache_dir.rglob(target_name))
                             if matches:
                                 # Return the first match found
-                                preview_file = matches[0]
-                                print(f"✅ Found preview (recursive): {preview_file}")
-                                return str(preview_file.absolute())
+                                preview_path = str(matches[0].absolute())
+                                self._preview_cache[fileName] = preview_path
+                                return preview_path
 
-            print("❌ No preview image found")
             return ""
         except Exception as e:
-            print(f"💥 Exception finding preview: {e}")
             return ""
+
+    def _clear_preview_cache(self):
+        """Clear the preview path cache (call when patterns might change)"""
+        self._preview_cache = {}
     
     @Slot()
     def stopExecution(self):
@@ -1128,27 +1131,19 @@ class Backend(QObject):
             traceback.print_exc()
     
     def _reset_activity_timer(self):
-        """Reset the last activity timestamp"""
-        old_time = self._last_activity
+        """Reset the screen timeout timer (event-driven approach)"""
         self._last_activity = time.time()
-        time_since_last = self._last_activity - old_time
-        if time_since_last > 1:  # Only log if it's been more than 1 second
-            print(f"🖥️ Activity detected - timer reset (was idle for {time_since_last:.1f}s)")
-    
-    def _check_screen_timeout(self):
-        """Check if screen should be turned off due to inactivity"""
-        if self._screen_on and self._screen_timeout > 0:  # Only check if timeout is enabled
-            idle_time = time.time() - self._last_activity
-            # Log every 10 seconds when getting close to timeout
-            if idle_time > self._screen_timeout - 10 and idle_time % 10 < 1:
-                print(f"🖥️ Screen idle for {idle_time:.0f}s (timeout at {self._screen_timeout}s)")
-            
-            if idle_time > self._screen_timeout:
-                print(f"🖥️ Screen timeout reached! Idle for {idle_time:.0f}s (timeout: {self._screen_timeout}s)")
-                self._turn_screen_off()
-                # Add delay before starting touch monitoring to avoid catching residual events
-                QTimer.singleShot(1000, self._start_touch_monitoring)  # 1 second delay
-        # If timeout is 0 (Never), screen stays on indefinitely
+        # Stop existing timer and restart with full timeout duration
+        self._screen_timer.stop()
+        if self._screen_timeout > 0 and self._screen_on:
+            self._screen_timer.start(self._screen_timeout * 1000)
+
+    def _screen_timeout_triggered(self):
+        """Handle screen timeout - timer has already waited the full duration"""
+        if self._screen_on and self._screen_timeout > 0:
+            self._turn_screen_off()
+            # Add delay before starting touch monitoring to avoid catching residual events
+            QTimer.singleShot(1000, self._start_touch_monitoring)
     
     def _start_touch_monitoring(self):
         """Start monitoring touch input for wake-up"""