8a8e74561d
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).
61 lines
3.5 KiB
Markdown
61 lines
3.5 KiB
Markdown
---
|
||
type: entity
|
||
tags: [parking, hardware, readers, offline-first]
|
||
sources: [parking-system-architecture]
|
||
updated: 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 `curl` test 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()` → valid `image/jpeg`, ~322 KB,
|
||
correct JPEG magic. Digest handshake works through `HttpCamera`.
|
||
- 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).
|