The display service PNG-encoded its frame to /tmp/led_matrix_preview.png at 5 fps, 24/7 — identical frames, no viewers, per-call imports and a chmod every write. On the devpi baseline the display service idles at ~92% CPU; this was one of its biggest fixed costs. - New pure policy (src/common/snapshot_policy.py, unit-tested off-Pi): WRITE changed frames at full rate only while a viewer is watching, at a 30s idle cadence otherwise; NEVER re-encode unchanged frames — bump mtime (os.utime) every 20s instead, keeping the health check's snapshot-age liveness proxy (60s threshold in api_v3) green. Cross- referencing comments guard the two constants. - Viewer detection: the web SSE display broadcaster (which only runs while browsers are subscribed) touches /tmp/led_matrix_preview_viewer each loop; the display service stats it at most 1/s. On viewer arrival the write clock resets so the first frame lands within ~1s. - Hoisted the per-call pathlib/permission_utils imports; directory permissions ensured once instead of every frame. Claude-Session: https://claude.ai/code/session_01FqzC1nzTWL4kaqgMaQZFam Co-authored-by: Chuck <chuck@example.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Common Utilities
This directory contains reusable utilities and helpers for LEDMatrix plugins and core modules.
Adaptive Layout & Images (src/adaptive_layout.py, src/adaptive_images.py)
The recommended way to lay out plugins that render legibly on any panel
size (64x32 through 256x128+) without hand-tuned coordinates. Re-exported
from src.common for convenience; canonical import paths are
src.adaptive_layout / src.adaptive_images.
# Every BasePlugin already has self.layout and the draw helpers:
regs = scoreboard_regions(self.layout.bounds, ctx=self.layout)
self.draw_image(away_logo, regs.away_slot, mode="fill_height",
crop_to_ink=True, cache_key=f"logo:{abbr}")
self.draw_fit(score_text, regs.score_area) # largest crisp font that fits
self.draw_fit(status, regs.status_band)
Key pieces: Region (rect algebra: bands/columns/splits/offset),
font ladders (LADDER_GRID, LADDER_ARCADE — discrete crisp sizes, never
fractional scaling), LayoutContext (fit_text, fit_image, by_tier,
px), and composite carvers scoreboard_regions() / media_row().
Full guide: docs/ADAPTIVE_LAYOUT.md.
Error Handling (error_handler.py)
Common error handling patterns and utilities:
handle_file_operation()- Handle file I/O with consistent error handlinghandle_json_operation()- Handle JSON operations with error handlingsafe_execute()- Safely execute operations with error handlingretry_on_failure()- Decorator for retrying failed operationslog_and_continue()- Log non-critical errors and continuelog_and_raise()- Log errors and raise exceptions
Example Usage
from src.common.error_handler import handle_json_operation, safe_execute
# Handle JSON loading
config = handle_json_operation(
lambda: json.load(open('config.json')),
"Failed to load config",
logger,
default={}
)
# Safe execution with error handling
result = safe_execute(
lambda: risky_operation(),
"Operation failed",
logger,
default=None
)
API Helpers (api_helper.py)
Utilities for making HTTP requests and handling API responses.
Configuration Helpers (config_helper.py)
Utilities for loading, saving, and validating configuration files.
Display Helpers (display_helper.py)
Utilities for rendering content to the LED matrix display.
Game Helpers (game_helper.py)
Utilities for processing game data and team information.
Logo Helpers (logo_helper.py)
Utilities for loading and managing team logos.
Text Helpers (text_helper.py)
Utilities for text processing and formatting.
Scroll Helpers (scroll_helper.py)
Utilities for scrolling text on the display.
General Utilities (utils.py)
General-purpose utility functions:
- Team abbreviation normalization
- Time formatting
- Boolean parsing
- Logger creation (deprecated - use
src.logging_config.get_logger())
Permission Utilities (permission_utils.py)
Helpers for ensuring directory permissions and ownership are correct
when running as a service (used by CacheManager to set up its
persistent cache directory).
CLI Helpers (cli.py)
Shared CLI argument parsing helpers used by scripts/dev/* and other
command-line entry points.
Best Practices
- Use centralized logging: Import from
src.logging_configinstead of creating loggers directly - Use error handlers: Use
error_handlerutilities for consistent error handling - Reuse utilities: Check existing utilities before creating new ones
- Document additions: Add documentation when adding new utilities