wiki: ER80 protocol = HTTP GET poll + JSON verdict (from QRCode SDK)
The QRCode SDK v1.6.5 settles the reader protocol (supersedes the earlier
serial guess). On each scan the reader HTTP-GETs the host
(/qa/mcardsea.php?cardid&mjihao&cjihao&status&time); the host replies JSON
{data:[{...,status,output}],code:0}. Reply status 1=valid(beep 2x)/0=invalid
(beep 1x); output 0=Access/1=WG26/2=WG34; time syncs the clock. The GET's status
low digit is the direction (1=in/0=out).
Key: the beep/accept is decided by the SERVER REPLY, not locally -- the 'no
beep' during bring-up was a plain-text reply, not a scan failure. Host-in-the-
loop and synchronous. 'Server language' only selects the URL path; transport is
plain HTTP.
New source page qrcode-sdk; updated gee-qr-er80 (protocol resolved), index.
This commit is contained in:
@@ -23,37 +23,42 @@ scanner** the design called for — read at the pay station and exit lane — an
|
|||||||
- **Multi-interface** (Wiegand 26/34, RS-232, RS-485, USB, TCP/IP); the `-W` variant exposes
|
- **Multi-interface** (Wiegand 26/34, RS-232, RS-485, USB, TCP/IP); the `-W` variant exposes
|
||||||
**Wiegand + RS-232/RS-485**.
|
**Wiegand + RS-232/RS-485**.
|
||||||
|
|
||||||
## How it fits our architecture — host-side reader
|
## How it integrates — HTTP-GET push, server replies the verdict (confirmed via SDK)
|
||||||
|
|
||||||
It's a **host-side identity source** ([[entry-exit-readers]]): the host sees the scan, decides, and
|
The protocol is settled by the **[[qrcode-sdk|QRCode SDK v1.6.5]]** (not serial as first guessed).
|
||||||
commands the relay — exactly the model the read-driven flows already use. A scan becomes a
|
The reader is configured (Windows tool `QRCode_v1_6_5.exe`) with a **server IP/port** and a "server
|
||||||
`DeviceReadEvent` on the internal `read` bus (`kind: "qr"`/`"ticket"`, value = the scanned string),
|
language" (only picks the URL path, e.g. `/qa/mcardsea.php`). **On each scan it HTTP-GETs the host:**
|
||||||
consumed by the **exit flow** and the **QR-permit** path ([[parking-session]], [[permit]]) — both
|
|
||||||
**already built**. So integration is a new **`ReaderDevice` adapter**, no business-logic change
|
|
||||||
([[device-adapter-pattern]]).
|
|
||||||
|
|
||||||
- **Interface choice:** prefer **RS-232/RS-485 (serial)** for the QR variant — Wiegand can't carry a
|
```
|
||||||
variable-length QR string well (it's built for fixed-width card IDs). The host reads scans over a
|
GET /qa/mcardsea.php?cardid=<QR>&mjihao=<devId>&cjihao=<devSN>&status=<2 chars>&time=<utc>
|
||||||
serial port (USB-serial on TX/RX, or the USB variant); no Wiegand-decode hardware needed. This
|
```
|
||||||
suits [[offline-first]] (local serial, no network) and sidesteps the [[dingtian-relay|Dingtian]]'s
|
`cardid` = scanned data; `status` low digit = **direction (1=in / 0=out)**. The host replies JSON
|
||||||
lack of an onboard card list (we never wanted autonomy here anyway).
|
`{data:[{cardid,cjihao,mjihao,status,time,output}],code:0}` where reply **`status` 1=valid (beep
|
||||||
- **LED/BEEP control lines** mean the host can drive scan feedback (accepted/rejected) — nice for an
|
2×) / 0=invalid (beep 1×)**, **`output` 0=Access/1=WG26/2=WG34**, `time` syncs the clock.
|
||||||
unmanned lane.
|
|
||||||
- **Linux-supported**, 4–15 VDC — fits the [[disk-os-hardening|appliance]].
|
|
||||||
|
|
||||||
## Open questions (block the adapter)
|
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.)
|
||||||
|
|
||||||
1. **RS-232/RS-485 protocol:** baud rate + frame format, and confirm a QR scan emits as an **ASCII
|
> **This explains the "no beep":** feedback comes from the server's JSON reply, not locally. A
|
||||||
string** (expected) terminated by CR/LF vs. a framed/checksummed protocol. This is the one fact
|
> non-JSON / missing reply ⇒ no beep even though the scan worked. So "no beep" ≠ "didn't scan."
|
||||||
the adapter needs and the datasheet omits. Resolve via vendor docs or by observing the port on a
|
|
||||||
scan.
|
- Pushes over plain **HTTP** to our `10.0.10.x` host (on the device subnet); no serial wiring, no
|
||||||
2. **Serial vs. USB-CDC vs. TCP/IP** for *this* unit: `-W` is Wiegand/RS-232/485. Decide the host
|
Wiegand-decode hardware. Suits the host-in-the-loop model; autonomy is moot anyway
|
||||||
wiring (a USB-RS232/485 adapter on TX/RX, most likely).
|
([[dingtian-relay]] has no onboard ACL).
|
||||||
3. **Does Wiegand mode even carry QR?** Likely Wiegand is for the optional *card* modes only; confirm
|
- **Linux-supported**, 4–15 VDC, default IP `192.168.1.99` — fits the [[disk-os-hardening|appliance]].
|
||||||
so we don't design a Wiegand path for QR.
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
A `ReaderDevice` driver in `packages/devices` (serial transport) emitting `read` events. Add it to
|
A backend route (like `routes/devices.ts` for the Dingtian push) that parses the GET, **decides**
|
||||||
the [[device-registry]] under the `reader` category so the [[first-run-setup]] wizard can assign it
|
(reuse the permit/exit lookup), replies the JSON verdict, and emits on the `read` bus. The
|
||||||
per lane. Pending open-question #1 (the serial frame) before coding.
|
[[device-registry]] `reader` entry can model it for [[first-run-setup]] (server IP/port are set in
|
||||||
|
the vendor tool; the app side is the endpoint). Build-ready — protocol fully known.
|
||||||
|
|||||||
+2
-1
@@ -7,7 +7,7 @@ updated: 2026-06-14
|
|||||||
# Index
|
# Index
|
||||||
|
|
||||||
Content catalog for the wiki. Start at [[overview]]. Maintained on every ingest.
|
Content catalog for the wiki. Start at [[overview]]. Maintained on every ingest.
|
||||||
Counts: 2 sources · 19 entities · 24 concepts · 5 decision records.
|
Counts: 3 sources · 19 entities · 24 concepts · 5 decision records.
|
||||||
|
|
||||||
## Overview & navigation
|
## Overview & navigation
|
||||||
- [[overview]] — the top-level synthesis and entry point.
|
- [[overview]] — the top-level synthesis and entry point.
|
||||||
@@ -17,6 +17,7 @@ Counts: 2 sources · 19 entities · 24 concepts · 5 decision records.
|
|||||||
## Sources
|
## Sources
|
||||||
- [[parking-system-architecture]] — design notes: stack, threat model, devices, UHPPOTE, ESP32, readers, BOM, open decisions.
|
- [[parking-system-architecture]] — design notes: stack, threat model, devices, UHPPOTE, ESP32, readers, BOM, open decisions.
|
||||||
- [[gee-qr-er80]] — datasheet: GEE QR access reader (QR/DM/1D; Wiegand/RS-232/485/USB/TCP; Linux).
|
- [[gee-qr-er80]] — datasheet: GEE QR access reader (QR/DM/1D; Wiegand/RS-232/485/USB/TCP; Linux).
|
||||||
|
- [[qrcode-sdk]] — QRCode SDK v1.6.5: the reader's HTTP-GET-poll protocol + JSON verdict (beep/output).
|
||||||
|
|
||||||
## Entities — technology stack
|
## Entities — technology stack
|
||||||
- [[technology-stack]] — the full stack table; all MIT/Apache/BSD, chosen to avoid lock-in.
|
- [[technology-stack]] — the full stack table; all MIT/Apache/BSD, chosen to avoid lock-in.
|
||||||
|
|||||||
+17
@@ -623,3 +623,20 @@ guarantee. Recorded in [[dingtian-relay]] (new Hardening section).
|
|||||||
[[entry-exit-readers]], [[index]].
|
[[entry-exit-readers]], [[index]].
|
||||||
- OPEN (blocks the adapter): the RS-232/485 **frame + baud** — is a QR scan an ASCII CR/LF string
|
- OPEN (blocks the adapter): the RS-232/485 **frame + baud** — is a QR scan an ASCII CR/LF string
|
||||||
(expected) or framed? Datasheet omits it; resolve via vendor docs or by observing the port.
|
(expected) or framed? Datasheet omits it; resolve via vendor docs or by observing the port.
|
||||||
|
|
||||||
|
## [2026-06-16] ingest+test | ER80 protocol = HTTP GET poll + JSON verdict (SDK)
|
||||||
|
- Hardware bring-up: configured the reader via the vendor Windows tool (server IP/port + "server
|
||||||
|
language"). Moved it to 10.0.10.7. It pings (source-pin must be 10.0.10.203 — trap recurs). No
|
||||||
|
beep on scans — initially looked like "not scanning."
|
||||||
|
- Found the QRCode SDK v1.6.5 (`QRCode_sdk - QRCode_v1_6_5/sdk/`). Protocol SETTLED, supersedes the
|
||||||
|
serial guess in [[gee-qr-er80]]: reader does **HTTP GET** `/qa/mcardsea.php?cardid&mjihao&cjihao&
|
||||||
|
status&time` on each scan; server replies **JSON** `{data:[{...,status,output}],code:0}`. Reply
|
||||||
|
`status` 1=valid(beep 2×)/0=invalid(beep 1×); `output` 0=Access/1=WG26/2=WG34; `time` syncs clock.
|
||||||
|
`status` low digit in the GET = direction (1=in/0=out).
|
||||||
|
- KEY: feedback/beep is decided by the SERVER REPLY, not locally → the "no beep" was my catch-all
|
||||||
|
replying plain "OK" not the JSON verdict, NOT a scan failure. Host-in-the-loop + SYNCHRONOUS.
|
||||||
|
- "Server language" (JSP/PHP/C#/ASP/CGI) only selects the URL PATH; transport is plain HTTP.
|
||||||
|
- New source [[qrcode-sdk]]; updated [[gee-qr-er80]] (protocol resolved, serial open-Qs dropped),
|
||||||
|
[[index]]. SDK kept in place (bulky+binaries), not copied to raw/.
|
||||||
|
- NEXT: backend route — parse GET, DECIDE (reuse permit/exit lookup), reply JSON verdict, emit on
|
||||||
|
read bus. Refactor read flows to RETURN an outcome so the reply can reflect accept/reject.
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
type: source
|
||||||
|
tags: [parking, hardware, readers, qr, protocol, sdk]
|
||||||
|
sources: [qrcode-sdk]
|
||||||
|
updated: 2026-06-16
|
||||||
|
---
|
||||||
|
|
||||||
|
# Source: QRCode SDK v1.6.5 (GEE/Dingtian QR reader)
|
||||||
|
|
||||||
|
Vendor SDK for the QR access reader ([[gee-qr-er80]]; also branded Dingtian). Defines the
|
||||||
|
reader↔server **HTTP protocol** — the missing piece the datasheet omitted. Files at
|
||||||
|
`QRCode_sdk - QRCode_v1_6_5/sdk/` (config tool `QRCode_v1_6_5.exe`, demos in C#/PHP/VC++, protocol
|
||||||
|
docs `readme.txt`, `qrcode_HTTP_GET.txt`, `VC++/how to.txt`). **Not copied into `raw/`** — bulky +
|
||||||
|
binaries; this summary is the faithful capture. Entity: [[gee-qr-er80]].
|
||||||
|
|
||||||
|
## The protocol — HTTP GET poll, server replies the verdict
|
||||||
|
|
||||||
|
The reader is configured (via the Windows tool) with a **server IP/port + "server language"**
|
||||||
|
(JSP/PHP/C#/ASP/CGI — this only selects the URL path, e.g. `/qa/mcardsea.php`; transport is plain
|
||||||
|
HTTP either way). **On each scan** the reader sends:
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /qa/mcardsea.php?cardid=445D2C&mjihao=1&cjihao=HW256097&status=11&time=1540402036 HTTP/1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
| Param | Meaning |
|
||||||
|
| --- | --- |
|
||||||
|
| `cardid` | **the scanned QR/barcode data** (or card id) |
|
||||||
|
| `mjihao` | device id (machine number) |
|
||||||
|
| `cjihao` | device serial number |
|
||||||
|
| `status` | **2 chars**: high = valid `1`/invalid `0` (reader's own pre-check), low = direction **`1`=in / `0`=out**. A 1-char status = fail. |
|
||||||
|
| `time` | UTC time |
|
||||||
|
|
||||||
|
**Server → reader reply (JSON) — this is the access DECISION and drives the beep + output:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"data":[{"cardid":"<echo>","cjihao":0,"mjihao":1,"status":1,"time":"<utc>","output":2}],"code":0,"message":""}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Reply field | Meaning (from the C# demo comments) |
|
||||||
|
| --- | --- |
|
||||||
|
| `status` | **`1` = valid → buzzer 2×; `0` = invalid → buzzer 1×** |
|
||||||
|
| `output` | **`0` = Access, `1` = WG26, `2` = WG34** — output line/format driven on a valid read |
|
||||||
|
| `time` | UTC — **can sync the device clock** |
|
||||||
|
| `code` | `0` = success |
|
||||||
|
|
||||||
|
> **Implication (explains the "no beep"):** the reader's beep/accept is decided by the **server's
|
||||||
|
> reply**, not locally. A non-JSON / missing reply ⇒ no valid feedback ⇒ no beep, even though the
|
||||||
|
> scan succeeded. So "no beep" ≠ "didn't scan" — it means the server didn't answer with the verdict.
|
||||||
|
|
||||||
|
## Integration consequence
|
||||||
|
|
||||||
|
This is **host-in-the-loop, synchronous**: the GET *is* the access query; our JSON reply *is* the
|
||||||
|
decision. So the backend endpoint must **decide (valid/invalid + direction) and reply** — richer
|
||||||
|
than a fire-and-forget read. Direction comes from the `status` low digit. See [[gee-qr-er80]] +
|
||||||
|
[[device-input-flow]].
|
||||||
|
|
||||||
|
## Defaults / misc
|
||||||
|
|
||||||
|
- Default device IP `192.168.1.99` (`readme.txt`).
|
||||||
|
- Demos: PHP `qa/mcardsea.php` (minimal echo, status 0), C# raw-socket server on :80 (full parse),
|
||||||
|
VC++ raw HTTP example. All show the same GET-in / JSON-out contract.
|
||||||
Reference in New Issue
Block a user