Files
parking_solution/wiki/entities/gee-qr-er80.md
T
julian 392d44d842 server: GEE/Dingtian QR reader endpoint + synchronous ReadOutcome
The reader HTTP-GETs on each scan and beeps/acts on our JSON reply (host-in-the-
loop, synchronous). New route GET/POST /qa/mcardsea.php parses the SDK query,
runs the scan through the read dispatcher (permit match -> permit flow; else
transient exit), and replies the SDK verdict: status 1=valid (beep 2x) /
0=invalid (beep 1x), output, time-sync.

Refactored the read flows to return a ReadOutcome {accepted, direction, reason}
so the reply reflects the real accept/reject decision (ReadDispatcher.dispatch,
ExitFlow.handleAt, PermitFlow.run). Fire-and-forget readers ignore it.

Reader's lane is keyed off its serial (cjihao) as lane_devices.id for now;
endpoint is public (reader has no auth, on the device subnet).

Verified via inject: valid permit QR -> status:1 + open; re-scan -> permit exit;
unknown QR -> status:0; barrier-less lane -> status:0.
2026-06-16 12:12:09 +02:00

4.6 KiB
Raw Blame History

type, tags, sources, updated, status
type tags sources updated status
entity
parking
hardware
readers
qr
gee-qr-er80
2026-06-16 open

GEE-QR-ER80 (QR access reader)

The project's QR-code reader (GEE NFC LIMITED). A static optical scanner for QR / DataMatrix / 1D barcode, optional ID/IC card. This is the ticket-encoding scanner the design called for — read at the pay station and exit lane — and a path for QR permit credentials. On hand: variant -Q-W (QR scanner; Wiegand/RS-232/RS-485). (See gee-qr-er80 / raw/.)

What it is (and isn't)

  • Optical, not RFID-prox. Earlier we assumed "ER80-EM" = a 125 kHz EM4100 card reader — the datasheet corrects that: it's a QR/barcode scanner. The -EM in the original label was a mis-id; the real model is GEE-QR-ER80. Optional D/C variants add ID/IC card, but the unit on hand is QR-only (-Q).
  • Multi-interface (Wiegand 26/34, RS-232, RS-485, USB, TCP/IP); the -W variant exposes Wiegand + RS-232/RS-485.

How it integrates — HTTP-GET push, server replies the verdict (confirmed via SDK)

The protocol is settled by the qrcode-sdk (not serial as first guessed). The reader is configured (Windows tool QRCode_v1_6_5.exe) with a server IP/port and a "server language" (only picks the URL path, e.g. /qa/mcardsea.php). On each scan it HTTP-GETs the host:

GET /qa/mcardsea.php?cardid=<QR>&mjihao=<devId>&cjihao=<devSN>&status=<2 chars>&time=<utc>

cardid = scanned data; status low digit = direction (1=in / 0=out). The host replies JSON {data:[{cardid,cjihao,mjihao,status,time,output}],code:0} where reply status 1=valid (beep 2×) / 0=invalid (beep 1×), output 0=Access/1=WG26/2=WG34, time syncs the clock.

This is host-in-the-loop and SYNCHRONOUS: the GET is the access query and our reply is the decision — it drives the reader's beep + output. So unlike a fire-and-forget reader, the endpoint must decide (valid/invalid, direction from status) and reply, then also emit a DeviceReadEvent on the read bus for the entry/exit/permit flows (parking-session, permit) to open the barrier. (device-input-flow is the analogous push pattern; this one also returns a verdict.)

This explains the "no beep": feedback comes from the server's JSON reply, not locally. A non-JSON / missing reply ⇒ no beep even though the scan worked. So "no beep" ≠ "didn't scan."

  • Pushes over plain HTTP to our 10.0.10.x host (on the device subnet); no serial wiring, no Wiegand-decode hardware. Suits the host-in-the-loop model; autonomy is moot anyway (dingtian-relay has no onboard ACL).
  • Linux-supported, 4–15 VDC, default IP 192.168.1.99 — fits the disk-os-hardening.

Resolved (2026-06-16)

  • Protocol = HTTP GET poll + JSON verdict (above). The earlier "serial/Wiegand, find the baud" open questions are moot — it's HTTP. Wiegand is the reader's output line on a valid read (the reply output field), not the host transport.

As-built (2026-06-16)

  • Endpoint GET/POST /qa/mcardsea.php (apps/server/src/routes/qr-reader.ts, public — the reader has no auth, sits on the device subnet). Parses cardid/mjihao/cjihao/status/time, runs the scan through the read dispatcher (permit match → permit flow; else transient exit), and replies the SDK verdict: status 1=valid(beep 2×)/0=invalid(beep 1×), output 0, time.
  • The read flows were refactored to return a ReadOutcome { accepted, direction, reason } so the endpoint's reply reflects the real accept/reject (the dispatcher decides AND opens the barrier via the flows). A fire-and-forget reader ignores the outcome.
  • Lane mapping: the endpoint keys the reader's lane_devices id off the device serial (cjihao) for now — so assign the reader with lane_devices.id = <serial>. Refine when the setup wizard models the reader's server-side identity properly.
  • Verified via inject: valid permit QR → status:1 + open; re-scan → permit exit (still valid); unknown QR → status:0; reader on a barrier-less lane → status:0.

Open / to confirm on hardware

  • A live scan still hadn't reached the server during bring-up (no beep). With the real endpoint now replying the verdict, re-test: scan → expect a beep + a GET in the server log. If still nothing, it's the reader's scan/trigger/mode (not the server).
  • Reader→lane identity: confirm what the device actually sends as cjihao/mjihao and align the lane_devices assignment (the wizard doesn't yet capture the reader's serial as its id).