1b55e2034d
The Dingtian board's inputs are independent of its relays (configurable), so a button on an input can report to the host WITHOUT auto-firing a relay — solving the access-controller-button-flow blocker the UHPPOTE/ZKTeco couldn't. packages/devices: - access-dingtian.ts: `dingtian` access driver implementing AccessControlDevice (relay pulse/latch via UDP string protocol :60001), InputDevice (read inputs + poll-based press/release events, active-LOW), and the new PreconditionDevice. - PreconditionDevice capability on the interface: a device can report config it requires for parking and optionally fix it. Dingtian checks input_link_relay via the HTTP config API and can disable it. - httpPort config field — the web/config API port is separate from UDP control (this unit uses 8080, not the default 80). - Register dingtian; export driver objects from the package. Verified on real hardware (DT-R004 @ 10.0.10.172): status read, relay pulse, input events; disabled input_link_relay via the driver, then confirmed pressing inputs fires NO relay (0000) — host-in-the-loop entry works. Config-write gotcha recorded: config_set.cgi requires "command":"setconfig" injected after "status" (GET omits it) or the POST silently no-ops. apps/server/scripts/dingtian-test.mjs: status / watch / pulse hardware test. wiki: dingtian-relay verified; button-flow marked RESOLVED; index + log.
92 lines
5.1 KiB
Markdown
92 lines
5.1 KiB
Markdown
---
|
|
type: decision
|
|
tags: [parking, hardware, access-control, resolved]
|
|
sources: [parking-system-architecture]
|
|
updated: 2026-06-15
|
|
status: settled
|
|
---
|
|
|
|
# Push-Button → Auto-Open: the Ticket-First Entry Blocker (RESOLVED)
|
|
|
|
> **✅ RESOLVED (2026-06-15) by the [[dingtian-relay]] controller.** Its inputs are decoupled from
|
|
> its relays (`input_link_relay` configurable off — done & verified on hardware), so a button on an
|
|
> input reports to the host **without** firing a relay. Host-in-the-loop entry
|
|
> (`button → host → ticket → host opens relay`) now works. The original blocker (below) stands as
|
|
> the record of why the UHPPOTE/ZKTeco units couldn't do it.
|
|
>
|
|
> **Original procurement-blocking finding (2026-06-15), from on-hardware testing:** the UHPPOTE and
|
|
> ZKTeco controllers on hand could not, as wired/configured, deliver the required entry flow.
|
|
> See [[entry-exit-readers]], [[trust-boundary]].
|
|
|
|
## The required flow
|
|
|
|
```
|
|
car arrives → driver presses button → TICKET PRINTS → then barrier opens
|
|
```
|
|
|
|
The ticket must print **before** the barrier opens, and entry must **fail closed**: if the
|
|
ticket can't print (printer offline / out of paper), the barrier must **stay shut** — no
|
|
untracked car enters (the anti-fraud core, see [[threat-model]], [[append-only-event-chain]]).
|
|
|
|
## The problem (verified on real hardware)
|
|
|
|
The push-button is wired into the controller's **push-button / request-to-exit (REX) input**.
|
|
On that input the controller **firmware auto-fires the relay immediately** — the door opens on
|
|
press. The host only **observes** the event *after* the relay has already actuated, so there is
|
|
no point at which it can insert the ticket-print step. The host is structurally too late.
|
|
|
|
This is the [[entry-exit-readers]] principle in the negative: a button on the controller's own
|
|
input is decided **by the controller**, not the host. For host-in-the-loop entry, the button
|
|
must be a **host-side input** and the controller demoted to a **commanded relay**.
|
|
|
|
### Verified facts (UHPPOTE 225088491, firmware 09120)
|
|
|
|
Tested live via the `uhppoted` lib (see `apps/server/scripts/`):
|
|
|
|
- **Relays work**, host-commanded: `openDoor` doors 1 & 2 → `{opened:true}`, physically
|
|
actuated, logged as events with `reason="remote open door"`.
|
|
- **Buttons fire events** — but only **after** auto-opening: press logs an event with
|
|
`reason="push button ok"` (door 1 button → door 1, door 2 button → door 2).
|
|
- Both doors are in `control: "controlled"` mode with a 3 s delay.
|
|
- **No UDP command exists** to stop the push-button input from auto-opening the relay. The
|
|
`uhppoted` protocol (and the UHPPOTE firmware, which is **not changeable** —
|
|
[[uhppote-udp-protocol]]) has no "report-but-don't-open" mode for that input.
|
|
|
|
## Per-device assessment
|
|
|
|
- **UHPPOTE** — push-button input is **firmware-hardwired to auto-open**; not configurable.
|
|
Cannot do ticket-first entry while the button is on that input. Fine as a **commanded relay**
|
|
(host `openDoor`) and for permit/[[wiegand]] lanes; **not suitable for the button-driven entry
|
|
lane** without rewiring the button to a host-side input. See [[uhppote-controller]].
|
|
- **ZKTeco (C3 / inBio)** — *better positioned but unverified by us.* Its **auxiliary inputs**
|
|
have **programmable linkage** (via ZKBioSecurity / the PULL SDK) and need **not** be tied to
|
|
"open door", and its SDK streams real-time events + an explicit open command — so
|
|
`button → aux input → host event → print → host opens` is achievable **in principle**. BUT:
|
|
(a) wiring the button to the door's *exit-switch* input still auto-opens, same as UHPPOTE — it
|
|
only works on a properly-configured **aux** input; (b) ZKTeco speaks its **own PULL SDK
|
|
protocol**, not the UHPPOTE one — no verified MIT-licensed Node lib exists (mature open
|
|
implementations are Python: `zkaccess-c3-py`, `pyzkaccess`), so it needs a **new driver**.
|
|
See [[zkteco-controller]].
|
|
|
|
**Bottom line:** *neither controller currently on hand* delivers ticket-first entry as wired.
|
|
UHPPOTE can't at all on that input; ZKTeco might with an aux-input reconfig + a new driver, but
|
|
that is unverified.
|
|
|
|
## Options (unresolved — to settle later)
|
|
|
|
1. **Rewire the button off the controller's REX/exit input** to a host-readable input (spare
|
|
GPIO, a USB/IP digital-input module, or a non-auto-open input) so the host sees the press,
|
|
prints, then commands `openDoor`. Keeps UHPPOTE as a commanded relay.
|
|
2. **ZKTeco aux-input path** — wire the button to a programmable aux input, host decides via SDK.
|
|
Requires building a `[[zkteco-controller|zkteco]]` driver (PULL SDK) and validating the
|
|
no-auto-open linkage on real hardware.
|
|
3. **Custom [[esp32-custom-controller|ESP32]] controller** for the entry lane — full control of
|
|
button logic; the documented (currently deferred) prevention-grade path.
|
|
|
|
## Status
|
|
|
|
**Open / paused.** Recorded so the constraint isn't rediscovered. The relay + event-log command
|
|
path is otherwise **proven on hardware** (discovery, open, event capture all work) — the gap is
|
|
specifically the **button-before-ticket ordering** on the entry lane. Revisit when the entry-lane
|
|
hardware decision is taken. Related: [[open-questions]] (lane topology, failure modes).
|