Files
parking_solution/wiki/entities/uhppote-controller.md
T
julian 77606da2c9 UHPPOTE hardware bring-up + entry-flow blocker
Brought up the real UHPPOTE controller (serial 225088491, fw 09120) end to end
and recorded a procurement-level blocker.

Verified on hardware:
- discovery (LAN scan), host-commanded openDoor on doors 1 & 2 (physically
  actuated; reason="remote open door"), and live button capture
  (reason="push button ok").

Driver/networking fixes (packages/devices/src/drivers/access-uhppote.ts):
- broadcast to subnet-directed address (lib doesn't enable SO_BROADCAST for the
  global 255.255.255.255 -> EACCES);
- Config broadcast must match the target's subnet for unicast reply routing
  (fixes the health-check timeout: 5s -> 24ms ready);
- discover across all local subnets, dedupe by serial;
- serialize all controller I/O (concurrent calls collided on UDP :60001).

Server/UX:
- load .env via node --env-file-if-exists (vars weren't being read before);
- SETUP_AUTH_BYPASS hardened: env-gated, dev + loopback only, fails closed
  otherwise; surfaced as catalog.authBypass so the wizard drops the token field;
- .env.example documents all vars; inline favicon stops a 404.
- apps/server/scripts/: uhppote-listen (live events, restores prior listener)
  and uhppote-relay (guarded door-open test).

BLOCKER (wiki/decisions/access-controller-button-flow.md): the controller's
push-button input auto-opens the relay in firmware with no report-without-open
mode, so ticket-first entry (button -> print -> open, fail-closed) is impossible
as wired. UHPPOTE can't do it on that input; ZKTeco *might* via a programmable
aux input + PULL SDK but that's unverified and needs a new driver. Entry-lane
hardware decision paused to focus on the business side.

wiki: access-controller-button-flow (blocker), zkteco-controller (stub +
assessment), uhppote-controller callout, index + log.
2026-06-14 10:29:43 +02:00

3.2 KiB

type, tags, sources, updated
type tags sources updated
entity
parking
hardware
access-control
current-choice
parking-system-architecture
2026-06-15

UHPPOTE Controller (current choice)

The starting access-control hardware: a UHPPOTE Wiegand 26/34 network controller (4-door) — a cheap reader-plus-relay frontend, acceptable provided you understand its limits. The plan is UHPPOTE now → ZKTeco later (see bom). (See parking-system-architecture §6.)

⚠️ Entry-flow blocker (verified on hardware): the push-button input auto-opens the relay in firmware — there's no command to make it report-without-opening — so it cannot do ticket-first entry (button → print → open). Fine as a host-commanded relay and for wiegand/permit lanes, but not the button-driven entry lane as wired. Full detail and options: access-controller-button-flow.

Verified working on the real unit (serial 225088491, fw 09120): host-commanded openDoor on doors 1 & 2 (physically actuated, reason="remote open door"); button presses captured live (reason="push button ok"); device-discovery scan. Test scripts: apps/server/scripts/.

Implementation: integrated via the official uhppoted npm package (MIT, by the uhppoted org — github.com/uhppoted/uhppoted-lib-nodejs), added to @parking/devices as the uhppote access driver (device-registry). It exposes exactly the protocol commands this 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. 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

  • Combines reader input (wiegand) and door relays, with an onboard card list enabling autonomous offline decisions for Wiegand lanes.
  • Stores an indexed event log (see event-log-ingestion): get-events returns the stored range + current index; each record has event ID, timestamp, card number, door, access-granted flag, reason code. At the record level it's effectively append-only — no command edits/deletes an individual event.

The catch

It speaks the uhppote-udp-protocol: UDP port 60000, no auth, no encryption. Anyone on the LAN can open any door — and several unauthenticated commands can blind/reset/skew the log. So the device is tamper-evident, not tamper-proof, and only trustworthy behind network-isolation (mandatory). Firmware cannot be customized — the open-source uhppoted ecosystem is protocol reverse-engineering only; the controller accepts only the manufacturer's official firmware images.

Make the log trustworthy via event-log-ingestion (host-side index tracking) landing into the append-only-event-chain. For prevention-grade authentication, see the esp32-custom-controller. The choice between them is the trust-boundary decision.