Both shipped in #538 with no interface at all: the bridge could only be configured by editing integrations/mqtt_bridge/bridge_config.json over SSH, and the Pixlet editor was a script you had to know existed. Neither appeared anywhere in the web UI. They are now two sections in the Tools tab. **MQTT bridge.** Service state (installed / running / stopped), install, start, stop and restart, and a form for every setting: broker host and port, username, TLS, command topic, client id, API base, request timeout, on-demand duration and log level. The password is write-only. GET returns every other field plus a password_set flag, never the value -- this interface has no authentication, so anything it hands back is readable by anyone who can reach the port. Submitting a blank password keeps whatever is stored; there is an explicit Clear for removing one. The file is written through a temp file in the same directory and chmod 0600, so a crash mid-write cannot leave a config the bridge would refuse to load. Values are range-checked server-side (port, timeouts, log level, http(s) API base). **Pixlet editor.** Lists the apps on disk and starts a session per app, with a banner showing which app is open, a link to the editor, a countdown, and Stop. The banner survives a page reload because status is polled while a session runs, and Edit is disabled while one is open. Two changes to the script make that safe to drive from a browser: - It binds 0.0.0.0 by default (PIXLET_EDITOR_HOST overrides). Loopback-only meant the URL shown in a browser was unreachable and needed an SSH tunnel, which is the confusing path. The no-auth argument for loopback does not hold when web_interface already serves 0.0.0.0:5000 unauthenticated and can reconfigure everything. - The session ends by itself after PIXLET_EDITOR_TIMEOUT (default 30 min), enforced by `timeout` inside the script rather than by the caller. The display is stopped while editing, so a forgotten session would otherwise leave the panel dark and read as broken hardware -- the timeout is the whole reason a Start button is defensible. Two bugs found while testing that lifecycle, both of which would have bitten the Stop button: - GNU timeout runs its child in a NEW process group, so signalling the script's group killed only bash and orphaned pixlet with the port still bound. Now --foreground keeps one group, and the EXIT trap kills the recorded child too. - The liveness check treated a zombie as running: the script is a child of the web process and stays unreaped after exiting, and signal 0 succeeds against a zombie, so a finished session would have read as running forever. It now reaps non-blockingly and falls back to /proc state for a process that is not ours. Covered by test/js/dom/test_tools_sections.js (26 assertions, real DOM against the server-rendered partial): form prefill, the blank-means-unchanged password contract, the running-session banner and countdown, and that the editor link uses the host the page was loaded from. Also chmod +x on both scripts, which the docs tell you to run directly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014RRtqXDCnvnY6EQwhT5CV9
Utility Scripts
This directory contains utility scripts for maintenance and system operations.
Scripts
clear_cache.py- Clears LEDMatrix cache data (specific keys or all cache)start_web_conditionally.py- Conditionally starts the web interface based on config settingswifi_monitor_daemon.py- Background daemon that monitors WiFi/Ethernet connection and manages access point modecleanup_venv.sh- Cleans up Python virtual environment filesclear_python_cache.sh- Clears Python cache files (pycache, *.pyc, etc.)pixlet_config_editor.sh- Opens Pixlet's own config UI for one installed Starlark appapply_dns_single_request.sh- Addsoptions single-requestto the resolver (run byledmatrix-dns-fix.service)
Usage
Clear Cache
python3 scripts/utils/clear_cache.py --list # List cache keys
python3 scripts/utils/clear_cache.py --clear-all # Clear all cache
python3 scripts/utils/clear_cache.py --clear <key> # Clear specific key
Start Web Interface Conditionally
This script is typically called by the systemd service (ledmatrix-web.service) and checks the web_display_autostart setting in config/config.json before starting the web interface.
WiFi Monitor Daemon
This daemon is typically run as a systemd service (ledmatrix-wifi-monitor.service) and automatically manages WiFi access point mode based on network connectivity.
Pixlet Config Editor
Run it when you want Pixlet's own config form for a Starlark app -- live render preview, cascading dropdowns -- rather than the LEDMatrix one.
./scripts/utils/pixlet_config_editor.sh # list installed apps
./scripts/utils/pixlet_config_editor.sh penndot_signs # edit, on localhost:8080
Deliberately not a service. It stops the display for the length of the
session and pixlet serve listens with no authentication, so it should only
be running while you are actually editing. It backs the config up first and
restarts the display on exit, however it exits.
It binds loopback only, with no flag to change that: anything that can reach
pixlet serve can rewrite the app's config, and a printed warning is not
access control. To edit from another machine, forward the port -- SSH does the
authenticating and nothing is left listening on the LAN:
ssh -L 8080:localhost:8080 pi@ledpi.local
Apply DNS Single-Request Fix
Installed and run by ledmatrix-dns-fix.service; see systemd/README.md.
Safe to run by hand (sudo ./scripts/utils/apply_dns_single_request.sh) and
idempotent.