docs(wiki): camera 503/stream, alarm URL helper, reader ICMP liveness

- lpr-camera.md: "503 Device Busy" can be PERSISTENT (main-stream saturation on
  the G3H) — the real fix is sub-stream selection, not just retry.
- device-status-monitoring.md: QR reader health was false-healthy (hardcoded
  "ready") until the ICMP-ping fix; document the push-device monitoring model.
- log entries for both 2026-06-26 sessions.

Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
2026-06-26 16:47:19 +02:00
parent dd0f6e483a
commit 898cf1953a
3 changed files with 83 additions and 2 deletions
+36
View File
@@ -1636,3 +1636,39 @@ booth `ModuleNotFoundError` is a STALE image (fix: `booth.sh update`). **Fix:**
`dev`/`start`/`recognize` now `uv sync --extra alpr &&` first (self-healing), `.env` set to `fast_alpr`,
+ a `dev:stub` escape hatch. Restored real ANPR locally (`/health` → `fast_alpr` ready, model loaded from
cache, no download). Documented in [[vision-service-packaging]] ("Two runtimes, one fragile").
## [2026-06-26] fix | Hikvision snapshot 503 "Device Busy" — stream selection + retry + Alarm URL helper
Three camera fixes. (1) **503 Device Busy — the REAL fix is stream selection.** First framed as
"transient, just retry" — WRONG for this camera. Hardware probe of **DS-2CD1047G3H-LIU** (10.0.10.13):
`channels/101/picture` (MAIN) → 503 `deviceBusy` on 5 consecutive probes 800ms apart, while
`channels/102/picture` (SUB) → 200 clean JPEG every time. The main encoder is PERSISTENTLY saturated;
a retry loop can't fix it. Added a **`stream` config field** to the Hikvision driver (1=main default
for back-compat, 2=sub; ISAPI id `<channel><stream>`). Verified live: setting the camera to Sub flips
its status degraded→ready (14.7KB JPEG in ~87ms). (2) **Transient retry** (still useful for a genuine
momentary blip + the de-dup case): `HttpCamera.captureSnapshot` retries 503/500 with linear backoff
(250/500/750ms ×4), fails naming it `(device busy)`, does NOT retry 401/404. Plus the already-landed
`captureSnapshotShared` removing concurrent self-collision. `healthCheck` reports a live 503 as
`degraded` (surfaces a saturated main stream rather than hiding it). Covered by `camera.test.ts`
(10 tests: retry + main/sub path). (3) **Alarm Server URL helper:** the camera setup form now generates the camera's Alarm
Settings (Destination IP / URL / Protocol / Port) ready to paste, so the operator never hunts the
deviceId or memorises the endpoint. CRUCIAL: host/port come from the **backend address on the camera's
subnet** (`backendIpForDevice` + server port, the same probe the push-IP picker uses) — NOT
`window.location.origin` (the SPA's dev/proxy origin, which would wrongly say `localhost:5173`).
Verified live: matches the on-camera config field-for-field (10.0.10.203 / …/event / HTTP / 3000).
Shows a "save first" (needs a deviceId) then "test first" (needs the resolved backend IP) hint.
Documented in [[lpr-camera]] ("503 Device Busy"). Devices 6 new tests; server 168 green.
## [2026-06-26] fix | QR reader status was a LIE (hardcoded "ready") → real ICMP liveness
Two genuinely-OFFLINE QR readers showed GREEN in the status bar. Cause: the QR-reader adapter
(`StubReader`) had `healthCheck → { ready, "stub" }` hardcoded — it never probed anything. These are
PUSH devices (scan → GET our backend, resolve by serial) that expose **no TCP port**, so a connect
probe (cameras/printers) has nothing to hit; the stub "solved" that by lying. False-healthy is the
worst failure for a status bar. Fix: an **optional reader IP** (monitor-ONLY — scans still resolve by
serial, operation unchanged) + an **unprivileged ICMP ping** (`drivers/icmp.ts`: shells `/bin/ping`
`-c1`, exit-0 = reply; no native dep, no CAP_NET_RAW). `healthCheck`: IP replies → `ready`, no reply →
`offline`, **no IP → `degraded` ("set IP to monitor")** (never a false green). Booth compose
(`docker-compose.prod.yml`) sets `net.ipv4.ping_group_range=0 2147483647` so `/bin/ping` works
unprivileged for the non-root container user. Verified on hardware: the readers (10.0.10.7/.8) answer
ICMP on the device VLAN (eth1) — distinct MACs — and the UI Test connection shows "● ready — ping
10.0.10.7". (NB: an earlier "offline" reading was a WSL wrong-route artifact, not the readers.) Covered
by `reader.test.ts` (4 tests). Documented in [[device-status-monitoring]]. Devices +4 tests, all green.