Files
ledgrab/contexts/server-operations.md
alexei.dolgolyov 2b5dac2c42
Build Android APK / build-android (push) Failing after 1m44s
Lint & Test / test (push) Successful in 4m22s
feat(devices): BLE LED controller support (SP110E/Triones/Zengge/Govee)
End-to-end BLE streaming: provider + client + per-protocol wire encoders
with whole-strip averaging, desktop (bleak) and Android (Kotlin BleBridge
via Chaquopy) transports, discovery with protocol-family detection that
auto-fills the UI, throttled not-connected warning + 10 s reconnect
cooldown so a dropped link no longer stalls the pipeline at ~30 s/frame,
and an explicit asyncio.wait_for wrapper around bleak connect() since
the WinRT backend doesn't always honor the timeout kwarg.

Also rewrites server/restart.ps1 to be parameterized (-Port / -Module /
-PythonVersion / timeouts / -Quiet), pick the right interpreter via the
py launcher, pre-flight the target module, poll port readiness on both
shutdown and startup, redirect child stdout/stderr so Start-Process
doesn't hang on inherited Git-Bash handles, and return proper exit codes.

Rolls in concurrent work: Android BLE permissions + launcher icons + ru/zh
resources, Chaquopy-safe value_stream psutil fallback, setup-required
modal, asset-store test coverage, and misc system/config touch-ups.
2026-04-21 14:58:35 +03:00

4.0 KiB

Server Operations

Read this file when restarting, starting, or managing the server process.

Server Modes

Two independent server modes with separate configs, ports, and data directories:

Mode Command Config Port API Key Data
Real python -m ledgrab config/default_config.yaml 8080 development-key-change-in-production data/
Demo python -m ledgrab.demo config/demo_config.yaml 8081 demo data/demo/

Demo mode can also be triggered via the LEDGRAB_DEMO environment variable (true, 1, or yes). This works with any launch method — Python, Docker (-e LEDGRAB_DEMO=true), or the installed app (set LEDGRAB_DEMO=true before LedGrab.bat).

Both modes can run simultaneously on different ports.

Restart Procedure

Use the PowerShell restart script — it gracefully shuts the running server down (so stores persist to disk), kills stragglers, launches a detached replacement, and polls the port until it's actually accepting connections. Exit code is 0 on success, 1 if the new server failed to bind the port, 2 on environment errors.

Real server

powershell -ExecutionPolicy Bypass -File "c:\Users\Alexei\Documents\led-grab-mixed\led-grab\server\restart.ps1"

Demo server

powershell -ExecutionPolicy Bypass -File "c:\Users\Alexei\Documents\led-grab-mixed\led-grab\server\restart.ps1" `
    -Port 8081 -Module ledgrab.demo -ConfigPath "config\demo_config.yaml"

Useful parameters

  • -Port <int> / -Module <name> — override the target (default: 8080 / ledgrab).
  • -StartupTimeoutSec <int> — how long to wait for the new server to bind the port (default: 30).
  • -ShutdownTimeoutSec <int> — how long to wait for graceful shutdown before force-killing (default: 15).
  • -Quiet — suppress progress output.
  • -SkipBrowser:$false — allow the app to open a browser tab on startup (default: skipped).

Do NOT use Stop-Process -Name python — it kills unrelated Python processes (VS Code extensions, etc.).

Do NOT use bash background & jobs — they get killed when the shell session ends.

When to Restart

Restart required for changes to:

  • API routes (api/routes/, api/schemas/)
  • Core logic (core/*.py)
  • Configuration (config.py)
  • Utilities (utils/*.py)
  • Data models (storage/)

No restart needed for:

  • Static files (static/js/, static/css/) — but must rebuild bundle: cd server && npm run build
  • Locale files (static/locales/*.json) — loaded by frontend
  • Documentation files (*.md)

Auto-Reload Note

Auto-reload is disabled (reload=False in main.py) due to watchfiles causing an infinite reload loop. Manual restart is required after server code changes.

Demo Mode Awareness

When adding new entity types, engines, device providers, or stores — keep demo mode in sync:

  1. New entity stores: Add the store's file path to StorageConfig in config.pymodel_post_init() auto-rewrites data/ to data/demo/ paths when demo is active.
  2. New capture engines: Verify demo mode filtering works — demo engines use is_demo_mode() gate in is_available().
  3. New audio engines: Same as capture engines — is_available() must respect is_demo_mode().
  4. New device providers: Gate discovery with is_demo_mode() like DemoDeviceProvider.discover().
  5. New seed data: Update server/src/ledgrab/core/demo_seed.py to include sample entities.
  6. Frontend indicators: Demo state exposed via GET /api/v1/version -> demo_mode: bool. Frontend stores it as demoMode in app state and sets document.body.dataset.demo = 'true'.
  7. Backup/Restore: New stores added to STORE_MAP in system.py automatically work in demo mode since the data directory is already isolated.

Key files

  • Config flag: server/src/ledgrab/config.py -> Config.demo, is_demo_mode()
  • Demo engines: core/capture_engines/demo_engine.py, core/audio/demo_engine.py
  • Demo devices: core/devices/demo_provider.py
  • Seed data: core/demo_seed.py