Add device discovery (UHPPOTE LAN scan) to setup
UHPPOTE controllers self-announce via UDP broadcast, but the frontend had no way to find them — the admin had to type the serial blind. Add a generic discovery capability and surface it in the setup wizard. packages/devices: - DiscoverableDriver capability + DiscoveredDevice type + isDiscoverable() guard on the registry (optional, so any driver can opt in). - uhppote driver implements discover() via uhppoted getDevices (UDP broadcast), mapping each controller's serial/IP/firmware into a DiscoveredDevice; extract shared buildCtx(). apps/server: - GET /api/setup/discover/:driverId (admin-only): runs discover() and health-checks each found device so reachability shows before assigning. - catalog now returns a `discoverable` driver-id list. apps/web: - SetupWizard "Scan for controllers" button for discoverable drivers; lists found devices with health badges; selecting one auto-fills serial + host. api client gains discoverDevices(). wiki: new device-discovery concept; cross-link from registry/setup/uhppote; note the broadcast-permission (EACCES) deployment caveat; index + log. Verified: catalog flags uhppote discoverable; discover runs and fails gracefully without hardware; non-discoverable driver -> 400; missing token -> 401.
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
---
|
||||
type: concept
|
||||
tags: [parking, architecture, devices, setup]
|
||||
sources: [parking-system-architecture]
|
||||
updated: 2026-06-15
|
||||
---
|
||||
|
||||
# Device Discovery
|
||||
|
||||
An optional driver capability: **find devices on the LAN** so the admin doesn't have to type
|
||||
connection details by hand during [[first-run-setup]]. Modeled generically so any driver can
|
||||
opt in.
|
||||
|
||||
> Implementation-derived (from `@parking/devices` + setup API/UI), not the source doc.
|
||||
|
||||
## The capability
|
||||
|
||||
A driver may implement `DiscoverableDriver` — `discover() => DiscoveredDevice[]`. Each found
|
||||
device carries an `id`, a `label`, a `config` blob to **auto-fill** the setup form, and `info`
|
||||
(firmware, MAC, …). The [[device-registry]]'s `isDiscoverable()` guard lets the system treat it
|
||||
as optional; the setup catalog returns a `discoverable` list of driver ids.
|
||||
|
||||
## UHPPOTE discovery
|
||||
|
||||
The [[uhppote-controller]] supports discovery natively: a **UDP broadcast** (`get-devices` on
|
||||
`255.255.255.255:60000`) that **every controller on the LAN answers** with its serial, IP,
|
||||
netmask, gateway, MAC, firmware version, and date. The official `uhppoted` lib exposes this as
|
||||
`getDevices(ctx)`; the `uhppote` driver maps each result into a `DiscoveredDevice` (serial → id,
|
||||
IP → host).
|
||||
|
||||
## Flow
|
||||
|
||||
1. The setup catalog flags `uhppote` as discoverable.
|
||||
2. Admin clicks **Scan** → `GET /api/setup/discover/:driverId` (admin-only).
|
||||
3. The server runs `discover()` and **health-checks each found device** so the admin sees
|
||||
reachability before assigning.
|
||||
4. Selecting a result **auto-fills serial + host**; the admin then assigns it to a lane.
|
||||
|
||||
## Deployment notes
|
||||
|
||||
- UHPPOTE discovery is a **broadcast** — the host socket needs broadcast permission (a raw
|
||||
`send EACCES …:60000` means the OS blocked it). Works on the isolated device VLAN
|
||||
([[network-isolation]]) where the controller and host share an L2 segment.
|
||||
- Discovery shares the same unauthenticated UDP exposure as everything else UHPPOTE — another
|
||||
reason the controllers live on an isolated VLAN ([[uhppote-udp-protocol]]).
|
||||
- Cameras (Hikvision/Dahua via ONVIF/WS-Discovery) could implement the same interface later.
|
||||
@@ -37,6 +37,8 @@ driver; **no business-logic change** — this is the [[device-adapter-pattern]]
|
||||
(mirrors the "mixable per lane" principle — see [[trust-boundary]], [[entry-exit-readers]]).
|
||||
- Config is **validated against the driver's declared fields** before persisting.
|
||||
- Selections persist in the `lane_devices` table and drive runtime adapter construction.
|
||||
- Drivers may optionally implement **[[device-discovery]]** (`discover()`), so the admin can scan
|
||||
the LAN instead of typing connection details — UHPPOTE does this today.
|
||||
|
||||
Cameras are modelled as **snapshot-on-event**: the host requests an image at entry/exit; it's
|
||||
stored and referenced from the signed event as an **independent record** — a fraud-control input
|
||||
|
||||
@@ -16,7 +16,8 @@ each device's connection config.
|
||||
## Flow
|
||||
|
||||
1. **Read the catalog** — `GET /api/setup/catalog` returns supported drivers per category (no
|
||||
secrets, just schema). The web `SetupWizard` renders a picker + the driver's config fields.
|
||||
secrets, just schema) plus a `discoverable` list. The web `SetupWizard` renders a picker + the
|
||||
driver's config fields, and a **Scan** button for discoverable drivers ([[device-discovery]]).
|
||||
2. **Assign per lane** — `POST /api/setup/assign` (admin-only, role-guarded; see
|
||||
[[local-jwt-auth]]). The server validates the chosen driver + config against the registry
|
||||
before persisting to the `lane_devices` table; unknown drivers / missing required fields are
|
||||
|
||||
@@ -17,8 +17,10 @@ is UHPPOTE now → ZKTeco later (see [[bom]]). (See [[parking-system-architectur
|
||||
> design needs: `openDoor`, `getStatus`, and the event-log set (`getEvent`, `getEventIndex`,
|
||||
> `setEventIndex`, `recordSpecialEvents`) plus `setListener`/`listen` for auto-push — see
|
||||
> [[event-log-ingestion]]. Transport defaults to **UDP** (broadcast `…:60000`), with optional
|
||||
> per-call TCP on newer firmware. Note: the lib pulls one trivial extra dep (the npm `os`
|
||||
> shim) and tends to use UDP broadcast, which needs socket broadcast permission on the host.
|
||||
> per-call TCP on newer firmware. The driver also implements **[[device-discovery]]**
|
||||
> (`getDevices` broadcast) so the setup wizard can scan for controllers. Note: the lib pulls one
|
||||
> trivial extra dep (the npm `os` shim) and uses UDP broadcast, which needs socket broadcast
|
||||
> permission on the host.
|
||||
|
||||
## What it is
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ Counts: 1 source · 14 entities · 10 concepts · 2 decision records.
|
||||
- [[device-adapter-pattern]] — business logic talks to interfaces; swap hardware → new adapter.
|
||||
- [[device-registry]] — catalog of selectable drivers per category (admin-configurable).
|
||||
- [[first-run-setup]] — admin assigns devices per lane from the catalog at install.
|
||||
- [[device-discovery]] — optional driver capability to scan the LAN (UHPPOTE UDP broadcast).
|
||||
- [[barrier-not-a-door]] — never timed-close a barrier; safety lives in barrier firmware.
|
||||
- [[trust-boundary]] — the core fork: network vs. device; auditable vs. unforgeable.
|
||||
- [[fail-state-safety]] — entry fails closed, exit fails open; manual override; watchdog.
|
||||
|
||||
+12
@@ -40,3 +40,15 @@ access driver (pulseOpen→openDoor, healthCheck→getStatus), registered in the
|
||||
catalog. CJS interop: default-import + destructure. Verified it builds, appears
|
||||
in the catalog, and degrades to "offline" gracefully without hardware. Real
|
||||
on-VLAN test still pending.
|
||||
|
||||
## [2026-06-15] feature | Device discovery (UHPPOTE scan in setup)
|
||||
The frontend had no way to find a UHPPOTE — but the controllers self-announce via
|
||||
UDP broadcast. Added a generic [[device-discovery]] capability: optional
|
||||
`DiscoverableDriver.discover()` on the registry, implemented by the `uhppote`
|
||||
driver via `getDevices`. New admin-only `GET /api/setup/discover/:driverId`
|
||||
(health-checks each found device); catalog now returns a `discoverable` list.
|
||||
SetupWizard gains a "Scan for controllers" button that lists found devices with
|
||||
health badges and auto-fills serial + host on selection. Verified: catalog flags
|
||||
uhppote; discover runs and fails gracefully without hardware (broadcast EACCES);
|
||||
non-discoverable driver → 400; no token → 401. Modeled generically so cameras
|
||||
(ONVIF) can add discovery later.
|
||||
|
||||
Reference in New Issue
Block a user