* fix(cache): web UI can read what the display service caches again ledmatrix-web.service carried CacheDirectory=ledmatrix. With User= set to the installing user, systemd re-owns /var/cache/ledmatrix and everything in it to that user and its primary group whenever the directory's owner differs -- for a directory root created, on the first start. That erased the root:ledmatrix setgid layout the installers set up, so every file the display service (root) wrote afterwards was root:root 0660 and unreadable by the web interface: WARNING - Permission denied loading cache for display_current_state ... Since #547 install_service.sh renders the web unit from the template, so every fresh install hit this. Measured on one rig: 392 unreadable files, and the web UI's display status, on-demand state and plugin health empty. Existing installs only receive `git pull`, never a reinstalled unit, so the fix for them is in the code the root display service runs: - DiskCache.set gives each file the directory's group (when the directory is group-writable) and 0660 on the open descriptor before the rename, independent of setgid. This also closes a window where a fresh file was visible as mkstemp's 0600. - DiskCache.share_existing_files repairs files an older version left behind, once per process from the cleanup thread. It works through O_NOFOLLOW descriptors and skips hard links and other users' files: the directory is writable by the web user, and root must not be steered into changing a file outside it. For new installs, the web unit drops CacheDirectory=/CacheDirectoryMode=, and install_web_service.sh stops replacing an existing directory's ledmatrix group with the user's group. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(web): on-demand and current-display status read the display's latest state Found testing the cache-permission fix on a rig: once the web interface could read display_on_demand_state at all, /display/on-demand/status kept answering "active" for over 100 seconds while the file on disk said "idle". Both status routes read the display service's keys through the web process's memory tier, which serves the first copy it read for the full max_age (120s). Read them with memory_ttl=0, as every other cross-process reader (plugin health/metrics, the on-demand mailbox) already does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(install): re-group the cache dir whenever the web user is outside its group install_web_service.sh replaced an existing cache directory's group only when it was root's. A directory in any other group the web user is not a member of -- root:ledmatrix, for a user who is not in ledmatrix -- was left alone, and every file root wrote there stayed unreadable to the web interface. Replace the group whenever the installing user is not in it. A directory whose group the user is already in (ledmatrix, or the user's own group where CacheDirectory= left it) is still left as it is: re-grouping a working directory strands the files already in it on the old group. When the group does change and root-owned JSON files carrying the old group are present, try-restart ledmatrix.service so DiskCache.share_existing_files re-groups them through its symlink- and hard-link-safe path, rather than a recursive chgrp. Verified under WSL's systemd for seven directory states (user group, ledmatrix member, ledmatrix non-member with and without root files, root:root, missing, unnamed gid); the previous version left the non-member case unchanged. Addresses CodeRabbit review on #593. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Systemd Service Files
This directory contains systemd service unit files for LEDMatrix services.
Service Files
-
ledmatrix.service- Main LED Matrix display service- Runs the display controller (
run.py) - Starts automatically on boot
- Runs as root for hardware access
- Runs the display controller (
-
ledmatrix-web.service- Web interface service- Runs the web interface conditionally based on config
- Starts automatically on boot if
web_display_autostartis enabled - Uses
scripts/utils/start_web_conditionally.py
-
ledmatrix-update-verify.service/.path- Automatic update health check and rollback- The path unit starts the service when the web interface creates
data/auto_update_verify.requestafter a weekly automatic update - Installed by the installers, or by the display service when automatic
updates are turned on in the web UI (
src/auto_update_setup.py) - Restarts the services, checks they stay up, and otherwise resets to the previous commit and its dependencies
- Runs
data/auto_update_verifier.py, a copy ofscripts/utils/auto_update_verify.pytaken before the update
- The path unit starts the service when the web interface creates
-
ledmatrix-wifi-monitor.service- WiFi monitor daemon service- Monitors WiFi/Ethernet connectivity
- Automatically enables/disables access point mode
- Uses
scripts/utils/wifi_monitor_daemon.py
-
ledmatrix-dns-fix.service- DNS single-request fix (optional)- Re-applies
options single-requestto the resolver on every boot, because whatever managesresolv.confregenerates it and drops the option again - Works around glibc's parallel A/AAAA lookup stalling ~5s per name on routers that answer only the A query, which makes any plugin calling an external API slow or (for Starlark apps, which have a render timeout) fail outright
- Uses
scripts/utils/apply_dns_single_request.sh - Install only if external API calls are timing out; it is not part of a normal install
- Re-applies
-
ledmatrix-mqtt-bridge.service- Home Assistant MQTT bridge (optional)- Exposes the display to Home Assistant over MQTT Discovery: force a mode, stop on-demand, toggle power, set brightness
- Uses
integrations/mqtt_bridge/ledmatrix_mqtt_bridge.py, which drives the web API rather than the display directly - Needs
integrations/mqtt_bridge/bridge_config.json; see that directory's README
Installation
These service files are installed by the installation scripts in scripts/install/:
install_service.shinstallsledmatrix.serviceinstall_web_service.shinstallsledmatrix-web.serviceand theledmatrix-update-verifyservice and path unitsinstall_wifi_monitor.shinstallsledmatrix-wifi-monitor.serviceinstall_dns_fix.shinstallsledmatrix-dns-fix.service(opt-in, not run by the normal installer)install_mqtt_bridge.shinstallsledmatrix-mqtt-bridge.service(opt-in)
Manual Installation
Important: the unit files in this directory contain
__PROJECT_ROOT_DIR__placeholders that the install scripts replace with the actual project directory at install time. Do not copy them directly to/etc/systemd/system/— the service will fail to start withWorkingDirectory=__PROJECT_ROOT_DIR__errors.Always install via the helper script:
sudo ./scripts/install/install_service.shIf you really need to do it by hand, substitute the placeholder first:
PROJECT_ROOT="$(pwd)" sed "s|__PROJECT_ROOT_DIR__|$PROJECT_ROOT|g" systemd/ledmatrix.service \ | sudo tee /etc/systemd/system/ledmatrix.service > /dev/null sudo systemctl daemon-reload sudo systemctl enable ledmatrix.service sudo systemctl start ledmatrix.service
Service Management
# Check status
sudo systemctl status ledmatrix.service
# Start/stop/restart
sudo systemctl start ledmatrix.service
sudo systemctl stop ledmatrix.service
sudo systemctl restart ledmatrix.service
# Enable/disable autostart
sudo systemctl enable ledmatrix.service
sudo systemctl disable ledmatrix.service
# View logs
journalctl -u ledmatrix.service -f