Commit Graph

6 Commits

Author SHA1 Message Date
alexei.dolgolyov 2f31680823 feat(devices): pairing-UX scaffold (Phase 2)
Lays the groundwork for device families that require a one-time
physical pairing action (Nanoleaf hold-power-button, Tuya local-key
extraction, Twinkly network-setup mode, Hue link-button). No driver
uses it yet -- Nanoleaf will be the first concrete consumer.

Phase 2 as originally written had three bullets; only this one was
genuinely missing work. The other two (generic NetworkDiscoveryService
fan-out, unified scan-network UI) were already solved at the route
level by the existing /api/v1/devices/discover handler running all
providers in parallel via asyncio.gather(return_exceptions=True).
Marked WONTDO in TODO.md with rationale.

Backend:
- LEDDeviceProvider gains an async pair_device(url) -> dict method.
  Default raises NotImplementedError so missing implementations on a
  requires_pairing provider fail loud at request time.
- New PairingNotReady exception, distinct from generic errors so the
  route handler can return 409 (user must perform the physical action,
  retry possible) instead of 500.
- POST /api/v1/devices/pair endpoint with PairDeviceRequest /
  PairDeviceResponse schemas. Status-code mapping:
    200 -> paired, fields returned for the subsequent create payload
    400 -> unknown device type, or type doesn't support pairing
    409 -> PairingNotReady (retryable from the UI)
    422 -> invalid URL / device configuration (ValueError)
    502 -> transport / network failure (other exceptions)
    500 -> provider returned a non-dict (defensive)
- 8 route tests register a stub provider and exercise every
  status-code path.

Frontend:
- New modals/pair-device.html with five state blocks (idle / pairing
  / not_ready / success / failed) toggled via data-pair-state, plus
  a 30-second SVG progress ring with monospace countdown.
- New features/pairing-flow.ts exposing
  runPairingFlow({deviceType, url, instructionsKey?}) ->
  Promise<{fields: Record<string, unknown>>. Wires the modal to the
  pair endpoint, maps response codes to UI states, AbortControllers
  in-flight fetches on cancel. Exports a PairingCancelled sentinel
  error class.
- Generic pairing.* i18n keys in en/ru/zh. Drivers will add their own
  device.<type>.pair.instructions key that overrides the default.

Design decisions (per frontend-design skill):
- Single SVG ring + centered countdown (HomeKit-style)
- Instructions stay visible during pairing, dimmed to 60% via :has()
- Success state held 450 ms before auto-dismiss
- Cancel-X in the footer; primary action lives in the state block
- prefers-reduced-motion disables pulse/fade/ring transitions

Note: the components.css diff includes a pre-existing MiniSelect block
from the user's parallel work; pairing-specific styles are the second
hunk (lines ~1628+).
2026-05-16 03:26:53 +03:00
alexei.dolgolyov 02cd9d519c refactor: rename project to LedGrab, split HA integration into separate repo
Lint & Test / test (push) Successful in 1m56s
- Rename Python package: wled_controller -> ledgrab
- Rename env var prefix: WLED_ -> LEDGRAB_ (with auto-migration for old vars)
- Rename localStorage key: wled_api_key -> ledgrab_api_key (with migration)
- Rename HA integration domain: wled_screen_controller -> ledgrab
- Update all imports, build scripts, Docker, installer, config, docs
- Remove HA integration (moved to ledgrab-haos-integration repo)
- Remove hacs.json (belongs in HA repo now)
- Add startup warning for users with old WLED_ env vars
- All tests pass (715/715), ruff clean, tsc clean, frontend builds
2026-04-12 22:45:28 +03:00
alexei.dolgolyov 492bdb95e3 feat: game integration system
Receive real-time events from games (CS2, Dota 2, LoL, etc.) and drive
LED effects through the existing color strip and value source pipelines.

Core:
- GameEventBus (thread-safe pub/sub) with standardized 23-type event vocabulary
- GameAdapter ABC + AdapterRegistry + MappingAdapter (YAML-driven)
- Built-in adapters: CS2 GSI, Dota 2 GSI, LoL Live Client, Generic Webhook
- Community YAML adapters: Minecraft, Valorant, Rocket League
- GameEventColorStripStream with 5 effects (flash/pulse/sweep/color_shift/breathing)
- GameEventValueSource with EMA smoothing and timeout
- 4 built-in effect presets (FPS Combat, MOBA Health, Racing, Generic Alert)
- Auto-setup for Valve GSI games (Steam path detection, cfg file writing)
- Demo capture engine exposed to non-demo mode

Frontend:
- Game tab in Streams tree navigation with integration cards
- Game integration editor modal with adapter picker, config fields, event mappings
- game_event source type in CSS and ValueSource editors
- Setup instructions overlay (markdown rendered)
- Live event monitor and connection test

API:
- Full CRUD for game integrations
- Event ingestion endpoint (adapter-level auth)
- Adapter metadata, presets, auto-setup, status/diagnostics endpoints
2026-03-31 13:17:52 +03:00
alexei.dolgolyov 2da5c047f9 fix: update test fixtures for SQLite storage migration
Lint & Test / test (push) Failing after 1m33s
All store tests were passing file paths instead of Database objects
after the JSON-to-SQLite migration. Updated fixtures to create temp
Database instances, rewrote backup e2e tests for binary .db format,
and fixed config tests for the simplified StorageConfig.
2026-03-25 11:38:07 +03:00
alexei.dolgolyov 7380b33b9b fix: resolve all 153 ruff lint errors for CI
Lint & Test / test (push) Failing after 9s
Auto-fixed 138 unused imports and f-string issues. Manually fixed:
ambiguous variable names (l→layer), availability-check imports using
importlib.util.find_spec, unused Color import, ImagePool forward ref
via TYPE_CHECKING, multi-statement semicolons, and E402 suppression.
2026-03-22 01:29:26 +03:00
alexei.dolgolyov f2871319cb refactor: comprehensive code quality, security, and release readiness improvements
Lint & Test / test (push) Failing after 48s
Security: tighten CORS defaults, add webhook rate limiting, fix XSS in
automations, guard WebSocket JSON.parse, validate ADB address input,
seal debug exception leak, URL-encode WS tokens, CSS.escape in selectors.

Code quality: add Pydantic models for brightness/power endpoints, fix
thread safety and name uniqueness in DeviceStore, immutable update
pattern, split 6 oversized files into 16 focused modules, enable
TypeScript strictNullChecks (741→102 errors), type state variables,
add dom-utils helper, migrate 3 modules from inline onclick to event
delegation, ProcessorDependencies dataclass.

Performance: async store saves, health endpoint log level, command
palette debounce, optimized entity-events comparison, fix service
worker precache list.

Testing: expand from 45 to 293 passing tests — add store tests (141),
route tests (25), core logic tests (42), E2E flow tests (33), organize
into tests/api/, tests/storage/, tests/core/, tests/e2e/.

DevOps: CI test pipeline, pre-commit config, Dockerfile multi-stage
build with non-root user and health check, docker-compose improvements,
version bump to 0.2.0.

Docs: rewrite CLAUDE.md (202→56 lines), server/CLAUDE.md (212→76),
create contexts/server-operations.md, fix .js→.ts references, fix env
var prefix in README, rewrite INSTALLATION.md, add CONTRIBUTING.md and
.env.example.
2026-03-22 00:38:28 +03:00