wiki: Dingtian relay decision, HTTP-over-MQTT, unmanned direction
- dingtian-relay: relay+input controller (4ch on hand). Inputs are decoupled from relays (configurable via input_link_relay) — solves the access-controller-button-flow blocker the UHPPOTE couldn't. Full protocol from the SDK (UDP string control :60001, `00` status parse, input_link_url push, multicast discovery). Driver + hardware test still to build. - dingtian-vs-mqtt: use direct HTTP/UDP now; MQTT skipped (broker = extra infra + failure mode + overkill at one-host/few-devices scale) but kept for later multi-lane scale. - autonomous-direction: record the roadmap to fully unmanned (no booth) and how it reshapes the threat model (operator-fraud -> unattended-machine threats), makes host-in-the-loop entry mandatory, and raises fail-state stakes. - threat-model: note the unmanned shift. index + log. gitignore the vendor SDK (dingtian/, 71MB of binaries/examples) — reference only, protocol captured in the wiki.
This commit is contained in:
+3
-1
@@ -17,4 +17,6 @@ dist/
|
|||||||
*:Zone.Identifier
|
*:Zone.Identifier
|
||||||
.playwright-mcp/
|
.playwright-mcp/
|
||||||
# stray hardware/UI test screenshots
|
# stray hardware/UI test screenshots
|
||||||
/*.png
|
/*.png
|
||||||
|
# Vendor device SDKs (reference only — protocol captured in wiki, not committed)
|
||||||
|
/dingtian/
|
||||||
|
|||||||
@@ -35,3 +35,9 @@ The controls that actually address insider/operator fraud are different in kind:
|
|||||||
The same reframing recurs at the device layer: the [[uhppote-controller]]'s real problem is
|
The same reframing recurs at the device layer: the [[uhppote-controller]]'s real problem is
|
||||||
unauthenticated commands ([[uhppote-udp-protocol]]), addressed by detection
|
unauthenticated commands ([[uhppote-udp-protocol]]), addressed by detection
|
||||||
([[event-log-ingestion]]) or prevention ([[esp32-custom-controller]]).
|
([[event-log-ingestion]]) or prevention ([[esp32-custom-controller]]).
|
||||||
|
|
||||||
|
> **Direction shift:** the system is heading toward **fully unmanned operation** — no operator, no
|
||||||
|
> booth ([[autonomous-direction]]). That removes the booth-operator as the *primary* adversary, but
|
||||||
|
> swaps in **unattended-machine threats** (tailgating, plate spoofing, physical tampering, forced
|
||||||
|
> entry). The append-only signed log + reconciliation controls carry over; the emphasis moves from
|
||||||
|
> "catch the cashier" to "trust the automated record and detect tampering."
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
type: decision
|
||||||
|
tags: [parking, direction, roadmap]
|
||||||
|
sources: []
|
||||||
|
updated: 2026-06-15
|
||||||
|
status: open
|
||||||
|
---
|
||||||
|
|
||||||
|
# Project Direction: Toward Fully Autonomous (Unmanned)
|
||||||
|
|
||||||
|
> Stated goal (2026-06-15): the system will evolve to **fully automatic operation — no human
|
||||||
|
> operator, no booth at all**. Recorded because "unmanned" is an architectural force that shapes
|
||||||
|
> several existing decisions, not just a feature.
|
||||||
|
|
||||||
|
## What "unmanned" changes
|
||||||
|
|
||||||
|
- **Threat model shift.** The original primary adversary was *"the legitimate operator at the
|
||||||
|
booth"* ([[threat-model]]). Remove the operator and that specific fraud vector (take cash → void
|
||||||
|
the record) largely disappears — but it's replaced by **unattended-machine threats**: tailgating,
|
||||||
|
plate spoofing/obscuring, physical tampering with a box nobody is watching, and forced entry.
|
||||||
|
The [[append-only-event-chain]] + [[reconciliation]] controls still apply; the emphasis moves
|
||||||
|
from "catch the cashier" to "trust the automated record + detect tampering."
|
||||||
|
- **Host-in-the-loop entry becomes mandatory, not optional.** With no person to hand over a ticket
|
||||||
|
or wave a car through, the machine must own the whole flow: detect arrival → issue ticket / read
|
||||||
|
plate → open. This is exactly why the [[access-controller-button-flow]] blocker matters and why
|
||||||
|
a controller whose input does **not** auto-fire the relay (see [[dingtian-relay]]) is required.
|
||||||
|
- **Reliability / fail-state get more critical** ([[fail-state-safety]]). No operator to recover a
|
||||||
|
stuck barrier or a trapped car ⇒ watchdogs, **exit-fails-open**, and hardware manual override
|
||||||
|
stop being nice-to-haves. Unattended uptime is a hard requirement.
|
||||||
|
- **Payment goes unmanned.** Pay-station / pay-on-foot or in-lane unmanned terminal rather than a
|
||||||
|
booth P2PE + cash drawer — sharpens [[open-questions]] #3 toward the unmanned option (PCI scope
|
||||||
|
still kept out of the app via a certified terminal).
|
||||||
|
- **Identity leans on automation.** Plate recognition ([[lpr-camera]]) and permit reads become the
|
||||||
|
primary identity sources, since there's no one to issue/inspect a paper ticket by hand.
|
||||||
|
|
||||||
|
## Near-term stance
|
||||||
|
|
||||||
|
Build for the unmanned target but don't over-engineer ahead of it. Current concrete step: the
|
||||||
|
**[[dingtian-relay]]** controller over **HTTP** (device pushes input events to the host; host
|
||||||
|
commands relays) — see [[dingtian-vs-mqtt]] for why HTTP over a message bus for now.
|
||||||
|
|
||||||
|
## Open
|
||||||
|
|
||||||
|
Lane topology, payment subsystem, and reconciliation channel ([[open-questions]]) should all be
|
||||||
|
(re)evaluated through the **unmanned** lens before procurement.
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
type: decision
|
||||||
|
tags: [parking, decision, devices, transport]
|
||||||
|
sources: []
|
||||||
|
updated: 2026-06-15
|
||||||
|
status: settled
|
||||||
|
---
|
||||||
|
|
||||||
|
# Transport for the Relay Controller: HTTP/UDP now, MQTT parked
|
||||||
|
|
||||||
|
**Decision (2026-06-15): use direct HTTP + UDP for the [[dingtian-relay]] controller now. MQTT is
|
||||||
|
deliberately skipped, but kept on the radar** for when the system scales.
|
||||||
|
|
||||||
|
## Options the device supports
|
||||||
|
|
||||||
|
The Dingtian relay board speaks several protocols: Dingtian string (UDP/TCP), Dingtian binary
|
||||||
|
(UDP, optional multicast/password), **HTTP CGI**, **HTTP input-link push** (`input_link_url`),
|
||||||
|
**Modbus** (RTU/TCP/ASCII), and **MQTT**.
|
||||||
|
|
||||||
|
## Why not MQTT (yet)
|
||||||
|
|
||||||
|
- **A broker is new infrastructure** on a deliberately **single-purpose hardened appliance**
|
||||||
|
([[disk-os-hardening]]) — another service to install, secure, supervise, and keep alive.
|
||||||
|
- **Extra failure mode on the critical path.** Today host→UDP→relay. MQTT inserts a broker on both
|
||||||
|
control and event paths; if it stalls, the lane stalls — and there are 3 processes to debug, not 2.
|
||||||
|
- **Doesn't fit [[offline-first]] for this scale.** MQTT earns its keep with *many* devices/consumers
|
||||||
|
and intermittent links. Here it's **one host + a few devices on one isolated LAN, metres apart** —
|
||||||
|
request/response control + a single input event, no fleet.
|
||||||
|
- **The device's MQTT input publish is periodic** ("default every 30 s"), so it's not even a clean
|
||||||
|
on-press event without relying on unverified on-change behaviour.
|
||||||
|
|
||||||
|
## Why HTTP/UDP fits
|
||||||
|
|
||||||
|
- **Relay control:** direct **UDP string protocol** (port 60001) — `11`=relay1 on, `21`=off,
|
||||||
|
`T1`=toggle, `11*`=jog/pulse. No deps, no broker.
|
||||||
|
- **Input/button events:** the device's **`input_link_url`** can **HTTP POST to the host backend
|
||||||
|
when an input fires** — real push, device calls our existing Fastify server directly, no broker.
|
||||||
|
(Polling `00` status over UDP every ~50 ms is the self-contained fallback.)
|
||||||
|
- Fewest moving parts; matches the local same-origin model already in use.
|
||||||
|
|
||||||
|
## When to revisit MQTT
|
||||||
|
|
||||||
|
If the system grows to **many lanes / many controllers**, or multiple subsystems (LPR, payment,
|
||||||
|
signage) all need to share events, a broker becomes a worthwhile central event bus. That aligns
|
||||||
|
with the [[autonomous-direction|unmanned]] roadmap at multi-lane scale — re-evaluate then. Until
|
||||||
|
then, direct HTTP/UDP wins on simplicity and reliability.
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
type: entity
|
||||||
|
tags: [parking, hardware, access-control, relay]
|
||||||
|
sources: []
|
||||||
|
updated: 2026-06-15
|
||||||
|
---
|
||||||
|
|
||||||
|
# Dingtian Relay Controller
|
||||||
|
|
||||||
|
A network **relay + input** board (the unit on hand is the **4-channel** variant: 4 relays + 4
|
||||||
|
inputs). Chosen to drive the entry/exit lane because — unlike the [[uhppote-controller]] — its
|
||||||
|
**inputs are independent of its relays**, which solves the [[access-controller-button-flow]]
|
||||||
|
blocker (a button on an input does not auto-open a relay; the host decides).
|
||||||
|
|
||||||
|
SDK: `dingtian/4ch/sdk_v2_0_0/` (programming manual, examples). MIT-compatible use; no vendor
|
||||||
|
runtime needed.
|
||||||
|
|
||||||
|
## ⚠️ The one gotcha: `input_link_relay`
|
||||||
|
|
||||||
|
By **default the device links each input to auto-fire its matching relay** (`input_link_relay: 1`,
|
||||||
|
`on_action_on: [[0],[1],…]` in the config) — i.e. the *same* auto-open problem as the UHPPOTE.
|
||||||
|
The difference: **it is configurable.** Set `input_link_relay: 0` (or clear the action mappings)
|
||||||
|
so an input only *reports* and the host commands the relay. **This config step is mandatory** for
|
||||||
|
the ticket-first entry flow. See [[autonomous-direction]].
|
||||||
|
|
||||||
|
## Protocol (Dingtian string — what we use)
|
||||||
|
|
||||||
|
Transport options: UDP/TCP string, UDP binary, HTTP CGI, Modbus, MQTT. We use **HTTP + UDP** —
|
||||||
|
see [[dingtian-vs-mqtt]].
|
||||||
|
|
||||||
|
- **Relay control — UDP ASCII, port 60001:** `1`+ch = ON, `2`+ch = OFF, `T`+ch = toggle.
|
||||||
|
Pulse/jog `11*` (default 500 ms), delay `11:30` (30 s then off), flash `11F5`. `X` = all relays.
|
||||||
|
Intent-only pulse for a barrier = `pulseOpen` ([[barrier-not-a-door]]).
|
||||||
|
- **Status / inputs — send `00`** → `「relays」:「inputs」:「count」`, e.g. **`0000:1111:4`** (4ch:
|
||||||
|
relays off, inputs high). `0` = OFF/Low, `1` = ON/High. Poll-based.
|
||||||
|
- **Input push — `input_link_url`:** device **HTTP POSTs to a host URL on input change** — the
|
||||||
|
push path for button events without a broker.
|
||||||
|
- **Discovery:** UDP multicast `224.0.2.11:60000`, send `\x05\xAA` (devices reply). Defaults:
|
||||||
|
IP `192.168.1.100`, UDP `60000` (binary) / `60001` (string).
|
||||||
|
- Binary protocol (port 60000) adds optional **password** + multicast; bitmask relay/input maps.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Protocol understood from the SDK; **driver + on-hardware test not built yet**. Next: a `dingtian`
|
||||||
|
relay driver in [[device-registry]] (UDP control + status parse) and the input-push endpoint,
|
||||||
|
with `input_link_relay` disabled on the device. Needs the device IP + LAN to test.
|
||||||
@@ -38,6 +38,7 @@ Counts: 1 source · 14 entities · 10 concepts · 2 decision records.
|
|||||||
- [[wiegand]] — reader standard feeding the controller directly (autonomous permit-holder path).
|
- [[wiegand]] — reader standard feeding the controller directly (autonomous permit-holder path).
|
||||||
- [[lpr-camera]] — edge-AI plate recognition; host-side casual-identity source.
|
- [[lpr-camera]] — edge-AI plate recognition; host-side casual-identity source.
|
||||||
- [[zkteco-controller]] — C3/inBio controller; aux-input path may enable host-in-the-loop (driver TBD).
|
- [[zkteco-controller]] — C3/inBio controller; aux-input path may enable host-in-the-loop (driver TBD).
|
||||||
|
- [[dingtian-relay]] — relay+input board; inputs decoupled from relays → solves the button blocker (driver TBD).
|
||||||
- [[bom]] — reference bill of materials (barrier, loops, controller, readers, payment, host, network).
|
- [[bom]] — reference bill of materials (barrier, loops, controller, readers, payment, host, network).
|
||||||
|
|
||||||
## Concepts — foundational forces
|
## Concepts — foundational forces
|
||||||
@@ -74,3 +75,5 @@ Counts: 1 source · 14 entities · 10 concepts · 2 decision records.
|
|||||||
- [[standing-decisions]] — settled decisions (stack, platform, integrity, access control, readers).
|
- [[standing-decisions]] — settled decisions (stack, platform, integrity, access control, readers).
|
||||||
- [[open-questions]] — 7 open items (6 procurement + JWT key choice); ESP32 device auth deferred.
|
- [[open-questions]] — 7 open items (6 procurement + JWT key choice); ESP32 device auth deferred.
|
||||||
- [[access-controller-button-flow]] — ⚠️ BLOCKER: UHPPOTE/ZKTeco on hand can't do ticket-first entry as wired.
|
- [[access-controller-button-flow]] — ⚠️ BLOCKER: UHPPOTE/ZKTeco on hand can't do ticket-first entry as wired.
|
||||||
|
- [[autonomous-direction]] — roadmap: toward fully unmanned (no booth); reshapes threat model + fail-state.
|
||||||
|
- [[dingtian-vs-mqtt]] — transport choice: direct HTTP/UDP now, MQTT parked until multi-lane scale.
|
||||||
|
|||||||
+11
@@ -94,3 +94,14 @@ earlier "broadcast permission (EACCES)" note in [[device-discovery]] — the rea
|
|||||||
cause was the lib not enabling SO_BROADCAST for the global 255.255.255.255;
|
cause was the lib not enabling SO_BROADCAST for the global 255.255.255.255;
|
||||||
documented the three verified broadcast gotchas + serialization. Added a `reference`
|
documented the three verified broadcast gotchas + serialization. Added a `reference`
|
||||||
page type to the schema; new "Dev environment" index section.
|
page type to the schema; new "Dev environment" index section.
|
||||||
|
|
||||||
|
## [2026-06-15] decision | Dingtian relay chosen; HTTP over MQTT; unmanned direction
|
||||||
|
New relay+input controller on hand (Dingtian 4ch). Its inputs are decoupled from
|
||||||
|
relays (configurable via input_link_relay) — solves the [[access-controller-button-flow]]
|
||||||
|
blocker the UHPPOTE couldn't. Transport decision [[dingtian-vs-mqtt]]: direct
|
||||||
|
HTTP/UDP now (UDP string for relay control on :60001; device input_link_url HTTP
|
||||||
|
push for button events), MQTT skipped (broker = infra + failure mode + overkill at
|
||||||
|
this scale) but kept for later multi-lane scale. Recorded the stated roadmap to
|
||||||
|
**fully unmanned, no-booth** operation in [[autonomous-direction]] and its threat-model
|
||||||
|
shift (operator-fraud → unattended-machine threats). New stub [[dingtian-relay]]
|
||||||
|
with the full protocol from the SDK. Driver + on-hardware test still to build.
|
||||||
|
|||||||
Reference in New Issue
Block a user