mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-12 13:42:59 +00:00
web preview fixes
This commit is contained in:
@@ -25,6 +25,10 @@ class DisplayManager:
|
|||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
self.config = config or {}
|
self.config = config or {}
|
||||||
self._force_fallback = force_fallback
|
self._force_fallback = force_fallback
|
||||||
|
# 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
|
||||||
|
self._last_snapshot_ts = 0.0
|
||||||
self._setup_matrix()
|
self._setup_matrix()
|
||||||
logger.info("Matrix setup completed in %.3f seconds", time.time() - start_time)
|
logger.info("Matrix setup completed in %.3f seconds", time.time() - start_time)
|
||||||
|
|
||||||
@@ -186,6 +190,8 @@ class DisplayManager:
|
|||||||
if self.matrix is None:
|
if self.matrix is None:
|
||||||
# Fallback mode - no actual hardware to update
|
# Fallback mode - no actual hardware to update
|
||||||
logger.debug("Update display called in fallback mode (no hardware)")
|
logger.debug("Update display called in fallback mode (no hardware)")
|
||||||
|
# Still write a snapshot so the web UI can preview
|
||||||
|
self._write_snapshot_if_due()
|
||||||
return
|
return
|
||||||
|
|
||||||
# Copy the current image to the offscreen canvas
|
# Copy the current image to the offscreen canvas
|
||||||
@@ -196,6 +202,9 @@ class DisplayManager:
|
|||||||
|
|
||||||
# Swap our canvas references
|
# Swap our canvas references
|
||||||
self.offscreen_canvas, self.current_canvas = self.current_canvas, self.offscreen_canvas
|
self.offscreen_canvas, self.current_canvas = self.current_canvas, self.offscreen_canvas
|
||||||
|
|
||||||
|
# Write a snapshot for the web preview (throttled)
|
||||||
|
self._write_snapshot_if_due()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error updating display: {e}")
|
logger.error(f"Error updating display: {e}")
|
||||||
|
|
||||||
@@ -615,4 +624,21 @@ class DisplayManager:
|
|||||||
else:
|
else:
|
||||||
suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(day % 10, 'th')
|
suffix = {1: 'st', 2: 'nd', 3: 'rd'}.get(day % 10, 'th')
|
||||||
|
|
||||||
return dt.strftime(f"%b %-d{suffix}")
|
return dt.strftime(f"%b %-d{suffix}")
|
||||||
|
|
||||||
|
def _write_snapshot_if_due(self) -> None:
|
||||||
|
"""Write the current image to a PNG snapshot file at a limited frequency."""
|
||||||
|
try:
|
||||||
|
now = time.time()
|
||||||
|
if (now - self._last_snapshot_ts) < self._snapshot_min_interval_sec:
|
||||||
|
return
|
||||||
|
# Ensure directory exists
|
||||||
|
snapshot_dir = os.path.dirname(self._snapshot_path)
|
||||||
|
if snapshot_dir and not os.path.exists(snapshot_dir):
|
||||||
|
os.makedirs(snapshot_dir, exist_ok=True)
|
||||||
|
# Write PNG snapshot
|
||||||
|
self.image.save(self._snapshot_path, format='PNG')
|
||||||
|
self._last_snapshot_ts = now
|
||||||
|
except Exception as e:
|
||||||
|
# Snapshot failures should never break display; log at debug to avoid noise
|
||||||
|
logger.debug(f"Snapshot write skipped: {e}")
|
||||||
@@ -57,32 +57,45 @@ class DisplayMonitor:
|
|||||||
|
|
||||||
def _monitor_loop(self):
|
def _monitor_loop(self):
|
||||||
global display_manager, current_display_data
|
global display_manager, current_display_data
|
||||||
|
snapshot_path = "/tmp/led_matrix_preview.png"
|
||||||
while self.running:
|
while self.running:
|
||||||
try:
|
try:
|
||||||
if display_manager and hasattr(display_manager, 'image'):
|
# Prefer service-provided snapshot if available (works when ledmatrix service is running)
|
||||||
# Convert raw image to base64 (no server-side scaling; client scales visually)
|
if os.path.exists(snapshot_path):
|
||||||
|
with open(snapshot_path, 'rb') as f:
|
||||||
|
img_bytes = f.read()
|
||||||
|
img_str = base64.b64encode(img_bytes).decode()
|
||||||
|
# If we can infer dimensions from display_manager, include them; else leave 0
|
||||||
|
width = display_manager.width if display_manager else 0
|
||||||
|
height = display_manager.height if display_manager else 0
|
||||||
|
current_display_data = {
|
||||||
|
'image': img_str,
|
||||||
|
'width': width,
|
||||||
|
'height': height,
|
||||||
|
'timestamp': time.time()
|
||||||
|
}
|
||||||
|
socketio.emit('display_update', current_display_data)
|
||||||
|
elif display_manager and hasattr(display_manager, 'image'):
|
||||||
|
# Fallback to in-process manager image
|
||||||
img_buffer = io.BytesIO()
|
img_buffer = io.BytesIO()
|
||||||
display_manager.image.save(img_buffer, format='PNG')
|
display_manager.image.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 = {
|
||||||
'image': img_str,
|
'image': img_str,
|
||||||
'width': display_manager.width,
|
'width': display_manager.width,
|
||||||
'height': display_manager.height,
|
'height': display_manager.height,
|
||||||
'timestamp': time.time()
|
'timestamp': time.time()
|
||||||
}
|
}
|
||||||
|
|
||||||
# Emit to all connected clients
|
|
||||||
socketio.emit('display_update', current_display_data)
|
socketio.emit('display_update', current_display_data)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
# Yield to the async loop; target ~10 FPS to reduce load
|
# Yield to the async loop; target ~5-10 FPS
|
||||||
try:
|
try:
|
||||||
socketio.sleep(0.1)
|
socketio.sleep(0.2)
|
||||||
except Exception:
|
except Exception:
|
||||||
time.sleep(0.1)
|
time.sleep(0.2)
|
||||||
|
|
||||||
display_monitor = DisplayMonitor()
|
display_monitor = DisplayMonitor()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user