mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-05-14 01:23:32 +00:00
fix: service control buttons and AP-mode SSH lockout post-install
Two user-reported issues after fresh install:
1. All service buttons (Start/Stop/Restart Display, Restart Web Service)
failed silently — only Reboot worked.
Root cause: sudoers rules use `ledmatrix.service` (with suffix) but
api_v3.py called `sudo systemctl start ledmatrix` (no suffix). sudo
does exact string matching, so every service action was rejected with
returncode=1. Also missing from sudoers: ledmatrix-web, journalctl,
and is-active entries.
Fix:
- Add `.service` suffix to all 8 sudo systemctl call sites in
api_v3.py (_ensure_display_service_running, _stop_display_service,
and all execute_system_action branches).
- Add timeout=15 to all subprocess.run calls in execute_system_action
(previously could hang indefinitely).
- Add missing sudoers rules to first_time_install.sh and
configure_web_sudo.sh: ledmatrix-web.service start/stop/restart,
is-active for both name forms, and journalctl -u/-t ledmatrix rules.
2. SSH and web UI became inaccessible after ~1 hour even though the
display kept running.
Root cause: wifi_monitor_daemon restarts NetworkManager after 5
consecutive internet failures (~2.5 min). Each NM restart drops WiFi
briefly. During that window check_and_manage_ap_mode() increments
_disconnected_checks but the daemon never reset it after the restart.
After 3 such NM-restart cycles, _disconnected_checks reached 3 and
AP mode activated — changing the Pi from WiFi client to hotspot
(192.168.4.1) and killing SSH on the old IP.
Fix:
- Reset wifi_manager._disconnected_checks = 0 in the daemon
immediately after a successful NM restart so the brief drop it
causes doesn't count toward AP-mode activation.
- Increase _disconnected_checks_required from 3 to 6 (90s → 3min)
as an additional buffer against transient network flaps.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -218,7 +218,7 @@ def _ensure_display_service_running():
|
||||
if status.get('active'):
|
||||
status['started'] = False
|
||||
return status
|
||||
result = _run_systemctl_command(['sudo', 'systemctl', 'start', 'ledmatrix'])
|
||||
result = _run_systemctl_command(['sudo', 'systemctl', 'start', 'ledmatrix.service'])
|
||||
service_status = _get_display_service_status()
|
||||
result['started'] = result.get('returncode') == 0
|
||||
result['active'] = service_status.get('active')
|
||||
@@ -227,7 +227,7 @@ def _ensure_display_service_running():
|
||||
|
||||
def _stop_display_service():
|
||||
"""Stop the ledmatrix display service."""
|
||||
result = _run_systemctl_command(['sudo', 'systemctl', 'stop', 'ledmatrix'])
|
||||
result = _run_systemctl_command(['sudo', 'systemctl', 'stop', 'ledmatrix.service'])
|
||||
status = _get_display_service_status()
|
||||
result['active'] = status.get('active')
|
||||
result['status'] = status
|
||||
@@ -1716,8 +1716,8 @@ def execute_system_action():
|
||||
if mode:
|
||||
# For on-demand modes, we would need to integrate with the display controller
|
||||
# For now, just start the display service
|
||||
result = subprocess.run(['sudo', 'systemctl', 'start', 'ledmatrix'],
|
||||
capture_output=True, text=True)
|
||||
result = subprocess.run(['sudo', 'systemctl', 'start', 'ledmatrix.service'],
|
||||
capture_output=True, text=True, timeout=15)
|
||||
return jsonify({
|
||||
'status': 'success' if result.returncode == 0 else 'error',
|
||||
'message': f'Started display in {mode} mode',
|
||||
@@ -1726,23 +1726,23 @@ def execute_system_action():
|
||||
'stderr': result.stderr
|
||||
})
|
||||
else:
|
||||
result = subprocess.run(['sudo', 'systemctl', 'start', 'ledmatrix'],
|
||||
capture_output=True, text=True)
|
||||
result = subprocess.run(['sudo', 'systemctl', 'start', 'ledmatrix.service'],
|
||||
capture_output=True, text=True, timeout=15)
|
||||
elif action == 'stop_display':
|
||||
result = subprocess.run(['sudo', 'systemctl', 'stop', 'ledmatrix'],
|
||||
capture_output=True, text=True)
|
||||
result = subprocess.run(['sudo', 'systemctl', 'stop', 'ledmatrix.service'],
|
||||
capture_output=True, text=True, timeout=15)
|
||||
elif action == 'enable_autostart':
|
||||
result = subprocess.run(['sudo', 'systemctl', 'enable', 'ledmatrix'],
|
||||
capture_output=True, text=True)
|
||||
result = subprocess.run(['sudo', 'systemctl', 'enable', 'ledmatrix.service'],
|
||||
capture_output=True, text=True, timeout=15)
|
||||
elif action == 'disable_autostart':
|
||||
result = subprocess.run(['sudo', 'systemctl', 'disable', 'ledmatrix'],
|
||||
capture_output=True, text=True)
|
||||
result = subprocess.run(['sudo', 'systemctl', 'disable', 'ledmatrix.service'],
|
||||
capture_output=True, text=True, timeout=15)
|
||||
elif action == 'reboot_system':
|
||||
result = subprocess.run(['sudo', 'reboot'],
|
||||
capture_output=True, text=True)
|
||||
capture_output=True, text=True, timeout=10)
|
||||
elif action == 'shutdown_system':
|
||||
result = subprocess.run(['sudo', 'poweroff'],
|
||||
capture_output=True, text=True)
|
||||
capture_output=True, text=True, timeout=10)
|
||||
elif action == 'git_pull':
|
||||
# Use PROJECT_ROOT instead of hardcoded path
|
||||
project_dir = str(PROJECT_ROOT)
|
||||
@@ -1823,12 +1823,11 @@ def execute_system_action():
|
||||
'stderr': result.stderr
|
||||
})
|
||||
elif action == 'restart_display_service':
|
||||
result = subprocess.run(['sudo', 'systemctl', 'restart', 'ledmatrix'],
|
||||
capture_output=True, text=True)
|
||||
result = subprocess.run(['sudo', 'systemctl', 'restart', 'ledmatrix.service'],
|
||||
capture_output=True, text=True, timeout=15)
|
||||
elif action == 'restart_web_service':
|
||||
# Try to restart the web service (assuming it's ledmatrix-web.service)
|
||||
result = subprocess.run(['sudo', 'systemctl', 'restart', 'ledmatrix-web'],
|
||||
capture_output=True, text=True)
|
||||
result = subprocess.run(['sudo', 'systemctl', 'restart', 'ledmatrix-web.service'],
|
||||
capture_output=True, text=True, timeout=15)
|
||||
else:
|
||||
return jsonify({'status': 'error', 'message': f'Unknown action: {action}'}), 400
|
||||
|
||||
|
||||
Reference in New Issue
Block a user