Pivot from the hardware/integrity layer to the parking operation. All wiki-only; no code yet. Core principle throughout: business entities are projections over the signed append-only event log, never mutable tables. New concepts: parking-session, tariff (composable/versioned, FX-ready), shift (manned-only Z-report), capacity-occupancy, validation-discounts, reporting-analytics, clock-integrity, ticket-encoding, anti-passback. New entities: permit, opencv-anpr-service, blocklist. Decisions: session-model, vision-service (host-side ANPR + vehicle verification; scoped AGPL exception for the isolated service). Updates: append-only-event-chain (new event types + vision witness), local-jwt-auth (drop 8h expiry -> until logout; code change pending), lpr-camera (host-side recognition supersedes edge-AI), standing-decisions (AGPL exception), open-questions (+FX, +pay-station money corners, backup). Deferred + flagged: intercom/help-call, receipts/refunds/change, FX engine, lane topology (#1).
3.5 KiB
type, tags, sources, updated
| type | tags | sources | updated | |||||
|---|---|---|---|---|---|---|---|---|
| entity |
|
|
2026-06-15 |
LPR Camera
License-plate-recognition camera. For casual/transient vehicles, the plate acts as ticket + an independent record. (See parking-system-architecture §8, §9.)
Superseded direction (2026-06-15): recognition now runs host-side on snapshots from ordinary Hikvision/Dahua cameras via the opencv-anpr-service, not on a dedicated edge-AI LPR camera — see vision-service. The edge-AI camera below is kept as the original assumption / a fallback option, but is no longer the planned path. The host-side service also does vehicle verification (anti-plate-spoofing), which an edge-LPR camera does not.
- Edge AI (original assumption): recognition runs on-device, so it keeps working with no internet — fits offline-first.
- It's a host-side identity source: only the host sees the read; the host decides and commands the relay open (the uhppote-controller is demoted to a commanded relay for that lane). See entry-exit-readers.
- Being host-in-the-loop is good for fraud detection — you get two independent records (the host's signed append-only-event-chain entry + the controller's remote-open event) that should reconcile one-to-one; any mismatch is an anomaly.
- Mounting: within ~15° of vehicle travel at a controlled chokepoint for best reads.
Snapshot driver (entry/exit fraud-control record)
Separate from edge-AI LPR: the camera driver (packages/devices/src/drivers/camera.ts) does
snapshot-on-event — the host pulls a still over HTTP when an entry/exit fires and stores it,
referenced from the signed append-only-event-chain entry as an independent record. The camera
pulls, it does not push — so it is NOT pushesToBackend and the setup wizard correctly hides
the "Backend push IP" field for it (gated on the driver's pushesToBackend flag; only
dingtian-relay sets it).
- Hikvision uses ISAPI:
GET /ISAPI/Streaming/channels/<id>/picture(101= ch1 main stream) with HTTP Digest auth. The "Enable Hikvision-CGI" toggle (Network → Advanced → Integration Protocol) is a different legacy CGI surface — not needed for ISAPI. - Dahua uses CGI:
GET /cgi-bin/snapshot.cgi?channel=<n>(0-based channel; the wizard's 1-based channel is decremented).
Driver / storage boundary: the driver FETCHES the image bytes (client-side HTTP Digest in
drivers/http-digest.ts) and returns them on Snapshot.bytes; storage is the caller's job
(the future entry/exit flow stores the bytes + mints a durable imageRef). This keeps the device
adapter free of any filesystem/blob-store dependency. healthCheck() is honest — it actually pulls
a frame (exercising reachability + auth + path/channel in one shot), not a fake ready/stub.
Verified on hardware (2026-06-15)
A Hikvision unit ("Camera 20", MAC 94:e1:ac:…, Hikvision OUI) at 10.0.10.121, creds
admin / admin123 (Digest), TCP 80:
- Initial
curltest confirmed the ISAPI path returns a 2688×1520 JPEG (~306 KB). - The real driver (no longer a stub) was then run end to end against it:
healthCheck()→ready(pulled a frame),captureSnapshot()→ validimage/jpeg, ~322 KB, correct JPEG magic. Digest handshake works throughHttpCamera. - Reaching it from the WSL dev box required forcing the source address (
config.localAddress, threaded into the driver) — see wsl-dev-networking (multi-subnet source-selection trap).