Files
parking_solution/wiki/entities/dingtian-relay.md
T
julian 1b55e2034d Dingtian relay driver — resolves the ticket-first entry blocker
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.
2026-06-14 14:15:00 +02:00

4.1 KiB

type, tags, sources, updated
type tags sources updated
entity
parking
hardware
access-control
relay
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.

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.

Driver & config API

The dingtian driver (device-registry) implements three capabilities: AccessControlDevice (relay pulse/latch over UDP), InputDevice (read inputs + poll-based press/release events ~50 ms), and PreconditionDevice (below). Config fields include a separate httpPort — the device's web/config API is on a configurable HTTP port (this unit: 8080, not the default 80), distinct from the UDP control port 60001.

The driver reads the device's JSON config (GET /api/v2/config.cgi) and checks input_link_relay; if enabled it reports a fixable issue, and fixPreconditions() writes the correction (POST /api/v2/config_set.cgi) — setting the flag to 0 and clearing on_action_on, preserving everything else (network, etc.). This is the generic device-registry capability: the app doesn't own full device config (that's the vendor web UI), only the few settings our flow depends on.

Write gotcha (cost real debugging): the GET config payload omits a "command" field, but the set endpoint requires "command":"setconfig" injected right after "status". Without it the POST returns/looks like success but silently does nothing (and the device may reset). With it, POST returns {"status":0} and the change sticks. JSON node order must be preserved.

Status — VERIFIED on hardware (DT-R004, sw V3.1.5461A, 10.0.10.172)

  • ✅ status read (0000:1111:4), relay pulse, input press/release events (active-LOW, idle HIGH).
  • ✅ input_link_relay disabled via the driver → confirmed: pressing an input now reports the event and fires NO relay (0000 after presses). The access-controller-button-flow blocker is solved — host-in-the-loop entry (button → host → ticket → host opens relay) works.
  • ⬜ Next: input HTTP-push endpoint (device input_link_url → backend), and wiring the entry flow (input event → print ticket → pulseOpen). Polling works today; push is the lower-latency path.