fix(reader): correct the QR reader's identity — Dingtian DT-008, not "GEE"
An early wrong assumption named the QR/RFID access reader "GEE" / "GEE/Fondvision" / "GEE-QR-ER80" (and summarized a raw GEE PDF as its datasheet). There is no GEE device — it's the Dingtian DT-008 (dingtian-tech.com/en_us/qr_code_reader.html), the same vendor as the relay board, which is why it integrates the identical HTTP-GET-push way. Code: - Driver symbol geeQrReaderDriver → dingtianQrReaderDriver; label → "Dingtian DT-008 QR/RFID reader (HTTP push)"; comments/description rewritten to the real DT-008 facts (Wiegand 26/34, TCP/IP, USB, RS485 — not RS-232; QR/barcode + ID/IC/NFC — not DataMatrix/1D). - Persisted driverId "gee-qr-reader" → "dingtian-qr-reader" (the registry lookup key + the row created on assign in qr-reader.ts). - Migration 0015 rewrites existing devices.driver_id rows so configured readers keep resolving (applied to the dev DB — 2 rows; the booth applies it on boot). Behaviour is unchanged: naming + the persisted id only. Wiki + memory: - Renamed entities/gee-qr-er80.md → dingtian-dt008-reader.md and sources/gee-qr-er80.md → dingtian-dt008.md; rewrote both to the real DT-008 product-page specs while KEEPING all the verified-on-hardware protocol facts (cjihao serial, .jsp path, Connection: close). Fixed every cross-reference + "GEE" mention in 6 other pages. Memory gee-reader-serial-binding → dingtian-reader-serial-binding. The only surviving "GEE" mentions are deliberate naming-correction notes, the raw PDF filename, and the append-only log history. Full workspace build/lint/test green; dev DB readers verified resolving to the registered dingtian-qr-reader driver. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -30,7 +30,7 @@ export interface DeviceReadEvent {
|
|||||||
/**
|
/**
|
||||||
* The decision a read produced. Returned by the read flows so a SYNCHRONOUS reader
|
* The decision a read produced. Returned by the read flows so a SYNCHRONOUS reader
|
||||||
* (e.g. the QR reader, whose HTTP reply drives its beep + output) can answer the
|
* (e.g. the QR reader, whose HTTP reply drives its beep + output) can answer the
|
||||||
* device. A fire-and-forget reader simply ignores it. See wiki/entities/gee-qr-er80.md.
|
* device. A fire-and-forget reader simply ignores it. See wiki/entities/dingtian-dt008-reader.md.
|
||||||
*/
|
*/
|
||||||
export interface ReadOutcome {
|
export interface ReadOutcome {
|
||||||
/** Was the vehicle admitted/exited (barrier opened)? Drives the reader's beep. */
|
/** Was the vehicle admitted/exited (barrier opened)? Drives the reader's beep. */
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import type { DeviceReadEvent } from "../device-events.js";
|
|||||||
import type { ReadDispatcher } from "../read-dispatch.js";
|
import type { ReadDispatcher } from "../read-dispatch.js";
|
||||||
import type { CredentialCapture } from "../credential-capture.js";
|
import type { CredentialCapture } from "../credential-capture.js";
|
||||||
|
|
||||||
// GEE/Dingtian QR reader endpoint. The reader is configured (vendor tool) with our
|
// Dingtian DT-008 QR/RFID reader endpoint. The reader is configured (vendor tool) with
|
||||||
// host as its "server"; on each scan it sends an HTTP GET and BEEPS/acts based on
|
// our host as its "server"; on each scan it sends an HTTP GET and BEEPS/acts based on
|
||||||
// our JSON reply — host-in-the-loop and synchronous. Protocol from the QRCode SDK
|
// our JSON reply — host-in-the-loop and synchronous. Protocol from the QRCode SDK
|
||||||
// v1.6.5; see wiki/sources/qrcode-sdk.md and wiki/entities/gee-qr-er80.md.
|
// v1.6.5; see wiki/sources/qrcode-sdk.md and wiki/entities/dingtian-dt008-reader.md.
|
||||||
//
|
//
|
||||||
// reader → GET /qa/mcardsea.php?cardid=<QR>&mjihao=<devId>&cjihao=<devSN>&status=<2ch>&time=<utc>
|
// reader → GET /qa/mcardsea.php?cardid=<QR>&mjihao=<devId>&cjihao=<devSN>&status=<2ch>&time=<utc>
|
||||||
// server → {"data":[{cardid,cjihao,mjihao,status,time,output}],"code":0,"message":""}
|
// server → {"data":[{cardid,cjihao,mjihao,status,time,output}],"code":0,"message":""}
|
||||||
@@ -35,7 +35,7 @@ export async function qrReaderRoutes(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Resolve the lane_devices row whose config.serial matches the reader's reported
|
// Resolve the lane_devices row whose config.serial matches the reader's reported
|
||||||
// serial (cjihao). The row id is a normal UUID; the serial is config the admin
|
// serial (cjihao). The row id is a normal UUID; the serial is config the admin
|
||||||
// enters when assigning the gee-qr-reader. Returns the row id, or null if no
|
// enters when assigning the dingtian-qr-reader. Returns the row id, or null if no
|
||||||
// reader is assigned for that serial. (Small device set → scan in JS.)
|
// reader is assigned for that serial. (Small device set → scan in JS.)
|
||||||
const readerRowIdForSerial = (serial: string): string | null => {
|
const readerRowIdForSerial = (serial: string): string | null => {
|
||||||
if (!serial) return null;
|
if (!serial) return null;
|
||||||
@@ -52,7 +52,7 @@ export async function qrReaderRoutes(
|
|||||||
// drive output) once the socket CLOSES — every vendor demo replies
|
// drive output) once the socket CLOSES — every vendor demo replies
|
||||||
// `Connection: close` and shuts the socket. Without it the reader waits out a
|
// `Connection: close` and shuts the socket. Without it the reader waits out a
|
||||||
// ~10 s keep-alive timeout before beeping. So force-close the connection.
|
// ~10 s keep-alive timeout before beeping. So force-close the connection.
|
||||||
// See wiki/sources/qrcode-sdk.md, entities/gee-qr-er80.md.
|
// See wiki/sources/qrcode-sdk.md, entities/dingtian-dt008-reader.md.
|
||||||
reply.header("connection", "close");
|
reply.header("connection", "close");
|
||||||
const cardid = (q.cardid ?? "").trim();
|
const cardid = (q.cardid ?? "").trim();
|
||||||
const mjihao = q.mjihao != null ? Number(q.mjihao) : 0;
|
const mjihao = q.mjihao != null ? Number(q.mjihao) : 0;
|
||||||
@@ -75,7 +75,7 @@ export async function qrReaderRoutes(
|
|||||||
accepted = true; // beep "ok" so the operator knows the card was read
|
accepted = true; // beep "ok" so the operator knows the card was read
|
||||||
} else {
|
} else {
|
||||||
const read: DeviceReadEvent = {
|
const read: DeviceReadEvent = {
|
||||||
driverId: "gee-qr-reader",
|
driverId: "dingtian-qr-reader",
|
||||||
deviceId,
|
deviceId,
|
||||||
value: cardid,
|
value: cardid,
|
||||||
kind: "qr",
|
kind: "qr",
|
||||||
|
|||||||
@@ -234,10 +234,10 @@ export async function buildServer(opts: BuildOptions = {}): Promise<FastifyInsta
|
|||||||
// reader's live flow. Single-shot + TTL. See credential-capture.ts.
|
// reader's live flow. Single-shot + TTL. See credential-capture.ts.
|
||||||
const credentialCapture = new CredentialCapture();
|
const credentialCapture = new CredentialCapture();
|
||||||
|
|
||||||
// GEE/Dingtian QR reader: it HTTP-GETs on each scan and beeps/acts on our JSON
|
// Dingtian DT-008 QR/RFID reader: it HTTP-GETs on each scan and beeps/acts on our JSON
|
||||||
// verdict (host-in-the-loop, synchronous). The capture service can intercept a read
|
// verdict (host-in-the-loop, synchronous). The capture service can intercept a read
|
||||||
// on an armed reader for enrollment; otherwise the read routes through the
|
// on an armed reader for enrollment; otherwise the read routes through the
|
||||||
// dispatcher. See wiki/entities/gee-qr-er80.md, qrcode-sdk.md.
|
// dispatcher. See wiki/entities/dingtian-dt008-reader.md, qrcode-sdk.md.
|
||||||
await qrReaderRoutes(app, db, readDispatcher, credentialCapture);
|
await qrReaderRoutes(app, db, readDispatcher, credentialCapture);
|
||||||
|
|
||||||
// Shifts (manned mode): explicit open/close → signed shift_open / shift_z_report
|
// Shifts (manned mode): explicit open/close → signed shift_open / shift_z_report
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
-- The QR/RFID access reader was misnamed "GEE" on a wrong early assumption; it's actually a
|
||||||
|
-- Dingtian DT-008 (same vendor as the relay board). The driver was renamed
|
||||||
|
-- `gee-qr-reader` → `dingtian-qr-reader`. `devices.driver_id` is the persisted registry
|
||||||
|
-- lookup key, so rewrite existing reader rows or they'd fail to resolve a driver. Idempotent.
|
||||||
|
UPDATE `devices` SET `driver_id` = 'dingtian-qr-reader' WHERE `driver_id` = 'gee-qr-reader';
|
||||||
@@ -106,6 +106,13 @@
|
|||||||
"when": 1781885700000,
|
"when": 1781885700000,
|
||||||
"tag": "0014_user_font_scale",
|
"tag": "0014_user_font_scale",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 15,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1781885800000,
|
||||||
|
"tag": "0015_dingtian_qr_reader_driverid",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { execFile } from "node:child_process";
|
import { execFile } from "node:child_process";
|
||||||
|
|
||||||
// Unprivileged ICMP liveness check for PUSH-only devices that expose no TCP port —
|
// Unprivileged ICMP liveness check for PUSH-only devices that expose no TCP port —
|
||||||
// e.g. the Dingtian/GEE QR readers, which GET our backend on each scan but listen on
|
// e.g. the Dingtian DT-008 QR readers, which GET our backend on each scan but listen on
|
||||||
// nothing. For those a TCP connect probe (what cameras/printers use) has nothing to
|
// nothing. For those a TCP connect probe (what cameras/printers use) has nothing to
|
||||||
// connect to; ICMP echo is the only honest "powered + on-network" signal.
|
// connect to; ICMP echo is the only honest "powered + on-network" signal.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { stubAccessDriver } from "./access-stub.js";
|
|||||||
import { dahuaDriver, hikvisionDriver } from "./camera.js";
|
import { dahuaDriver, hikvisionDriver } from "./camera.js";
|
||||||
import { cashinoDriver } from "./printer-cashino.js";
|
import { cashinoDriver } from "./printer-cashino.js";
|
||||||
import { rongtaDriver } from "./printer-rongta.js";
|
import { rongtaDriver } from "./printer-rongta.js";
|
||||||
import { geeQrReaderDriver, tcpipReaderDriver, wiegandReaderDriver } from "./reader.js";
|
import { dingtianQrReaderDriver, tcpipReaderDriver, wiegandReaderDriver } from "./reader.js";
|
||||||
|
|
||||||
let registered = false;
|
let registered = false;
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ export function registerBuiltinDrivers(): void {
|
|||||||
registry.register(stubAccessDriver);
|
registry.register(stubAccessDriver);
|
||||||
registry.register(wiegandReaderDriver);
|
registry.register(wiegandReaderDriver);
|
||||||
registry.register(tcpipReaderDriver);
|
registry.register(tcpipReaderDriver);
|
||||||
registry.register(geeQrReaderDriver);
|
registry.register(dingtianQrReaderDriver);
|
||||||
registry.register(hikvisionDriver);
|
registry.register(hikvisionDriver);
|
||||||
registry.register(dahuaDriver);
|
registry.register(dahuaDriver);
|
||||||
registry.register(rongtaDriver);
|
registry.register(rongtaDriver);
|
||||||
@@ -31,7 +31,7 @@ export {
|
|||||||
stubAccessDriver,
|
stubAccessDriver,
|
||||||
wiegandReaderDriver,
|
wiegandReaderDriver,
|
||||||
tcpipReaderDriver,
|
tcpipReaderDriver,
|
||||||
geeQrReaderDriver,
|
dingtianQrReaderDriver,
|
||||||
hikvisionDriver,
|
hikvisionDriver,
|
||||||
dahuaDriver,
|
dahuaDriver,
|
||||||
rongtaDriver,
|
rongtaDriver,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
|||||||
const icmpPing = vi.fn<(host: string, timeoutMs?: number) => Promise<boolean>>();
|
const icmpPing = vi.fn<(host: string, timeoutMs?: number) => Promise<boolean>>();
|
||||||
vi.mock("./icmp.js", () => ({ icmpPing: (...a: [string, number?]) => icmpPing(...a) }));
|
vi.mock("./icmp.js", () => ({ icmpPing: (...a: [string, number?]) => icmpPing(...a) }));
|
||||||
|
|
||||||
const { geeQrReaderDriver } = await import("./reader.js");
|
const { dingtianQrReaderDriver } = await import("./reader.js");
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
icmpPing.mockReset();
|
icmpPing.mockReset();
|
||||||
@@ -17,26 +17,26 @@ afterEach(() => {
|
|||||||
describe("QR reader healthCheck (ICMP liveness)", () => {
|
describe("QR reader healthCheck (ICMP liveness)", () => {
|
||||||
it("with an IP that replies → ready", async () => {
|
it("with an IP that replies → ready", async () => {
|
||||||
icmpPing.mockResolvedValue(true);
|
icmpPing.mockResolvedValue(true);
|
||||||
const r = geeQrReaderDriver.create({ serial: "H05M2AFA", host: "10.0.10.7" });
|
const r = dingtianQrReaderDriver.create({ serial: "H05M2AFA", host: "10.0.10.7" });
|
||||||
expect(await r.healthCheck()).toEqual({ status: "ready", detail: "ping 10.0.10.7" });
|
expect(await r.healthCheck()).toEqual({ status: "ready", detail: "ping 10.0.10.7" });
|
||||||
expect(icmpPing).toHaveBeenCalledWith("10.0.10.7");
|
expect(icmpPing).toHaveBeenCalledWith("10.0.10.7");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("with an IP that does NOT reply → offline (this is the bug fix)", async () => {
|
it("with an IP that does NOT reply → offline (this is the bug fix)", async () => {
|
||||||
icmpPing.mockResolvedValue(false);
|
icmpPing.mockResolvedValue(false);
|
||||||
const r = geeQrReaderDriver.create({ serial: "H05M2AFA", host: "10.0.10.7" });
|
const r = dingtianQrReaderDriver.create({ serial: "H05M2AFA", host: "10.0.10.7" });
|
||||||
expect(await r.healthCheck()).toEqual({ status: "offline", detail: "no ping reply from 10.0.10.7" });
|
expect(await r.healthCheck()).toEqual({ status: "offline", detail: "no ping reply from 10.0.10.7" });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("with NO IP → degraded (never a false 'ready')", async () => {
|
it("with NO IP → degraded (never a false 'ready')", async () => {
|
||||||
const r = geeQrReaderDriver.create({ serial: "H05M2AFA" });
|
const r = dingtianQrReaderDriver.create({ serial: "H05M2AFA" });
|
||||||
const h = await r.healthCheck();
|
const h = await r.healthCheck();
|
||||||
expect(h.status).toBe("degraded");
|
expect(h.status).toBe("degraded");
|
||||||
expect(icmpPing).not.toHaveBeenCalled(); // nothing to ping
|
expect(icmpPing).not.toHaveBeenCalled(); // nothing to ping
|
||||||
});
|
});
|
||||||
|
|
||||||
it("exposes an optional host field for monitoring", () => {
|
it("exposes an optional host field for monitoring", () => {
|
||||||
const hostField = geeQrReaderDriver.configFields.find((f) => f.key === "host");
|
const hostField = dingtianQrReaderDriver.configFields.find((f) => f.key === "host");
|
||||||
expect(hostField).toBeDefined();
|
expect(hostField).toBeDefined();
|
||||||
expect(hostField!.required).toBe(false); // operation is push-by-serial; IP is monitor-only
|
expect(hostField!.required).toBe(false); // operation is push-by-serial; IP is monitor-only
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -75,18 +75,19 @@ export const tcpipReaderDriver: ReaderDriver = {
|
|||||||
create: (c) => new StubReader("tcpip-reader", c),
|
create: (c) => new StubReader("tcpip-reader", c),
|
||||||
};
|
};
|
||||||
|
|
||||||
// GEE/Fondvision QR access reader (e.g. GEE-QR-ER80). A PUSH device: on each scan
|
// Dingtian DT-008 QR/RFID access reader (same vendor as the relay board). Scans QR/barcode
|
||||||
// it HTTP-GETs our backend (/qa/mcardsea.<ext>) carrying its serial (cjihao); the
|
// + ID/IC/NFC cards. A PUSH device: on each scan it HTTP-GETs our backend (/qa/mcardsea.<ext>)
|
||||||
// backend resolves the lane by matching that serial to this device's `serial`
|
// carrying its serial (cjihao); the backend resolves the lane by matching that serial to this
|
||||||
// config, decides, and replies the verdict (drives the beep). No host-side
|
// device's `serial` config, decides, and replies the verdict (drives the beep). No host-side
|
||||||
// connection — the adapter is a stub; the real integration is the HTTP endpoint
|
// connection — the adapter is a stub; the real integration is the HTTP endpoint (apps/server
|
||||||
// (apps/server routes/qr-reader.ts). See wiki/entities/gee-qr-er80.md.
|
// routes/qr-reader.ts). Interfaces: Wiegand 26/34, TCP/IP, USB, RS485. See
|
||||||
export const geeQrReaderDriver: ReaderDriver = {
|
// wiki/entities/dingtian-dt008-reader.md.
|
||||||
id: "gee-qr-reader",
|
export const dingtianQrReaderDriver: ReaderDriver = {
|
||||||
|
id: "dingtian-qr-reader",
|
||||||
category: "reader",
|
category: "reader",
|
||||||
label: "GEE/Fondvision QR reader (HTTP push)",
|
label: "Dingtian DT-008 QR/RFID reader (HTTP push)",
|
||||||
description:
|
description:
|
||||||
"QR/barcode access reader that HTTP-pushes each scan to the backend. Set its server IP/port to this host in the vendor tool; enter its serial here so scans resolve to this lane.",
|
"Dingtian DT-008 QR/barcode/RFID access reader that HTTP-pushes each scan to the backend. Set its server IP/port to this host in the vendor tool; enter its serial here so scans resolve to this lane.",
|
||||||
transports: ["tcp-ip"],
|
transports: ["tcp-ip"],
|
||||||
configFields: [
|
configFields: [
|
||||||
{
|
{
|
||||||
@@ -105,5 +106,5 @@ export const geeQrReaderDriver: ReaderDriver = {
|
|||||||
help: "Optional: the reader's IP, used ONLY to monitor it (ping). Scans still resolve by serial. Leave blank to skip liveness monitoring.",
|
help: "Optional: the reader's IP, used ONLY to monitor it (ping). Scans still resolve by serial. Leave blank to skip liveness monitoring.",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
create: (c) => new StubReader("gee-qr-reader", c),
|
create: (c) => new StubReader("dingtian-qr-reader", c),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export {
|
|||||||
stubAccessDriver,
|
stubAccessDriver,
|
||||||
wiegandReaderDriver,
|
wiegandReaderDriver,
|
||||||
tcpipReaderDriver,
|
tcpipReaderDriver,
|
||||||
geeQrReaderDriver,
|
dingtianQrReaderDriver,
|
||||||
hikvisionDriver,
|
hikvisionDriver,
|
||||||
dahuaDriver,
|
dahuaDriver,
|
||||||
rongtaDriver,
|
rongtaDriver,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ talks only to the adapter interfaces ([[device-adapter-pattern]]), never a drive
|
|||||||
> an **unprivileged ICMP ping** (`drivers/icmp.ts`, shells `/bin/ping` in SOCK_DGRAM mode — no
|
> an **unprivileged ICMP ping** (`drivers/icmp.ts`, shells `/bin/ping` in SOCK_DGRAM mode — no
|
||||||
> CAP_NET_RAW, no native dep; the booth compose sets `net.ipv4.ping_group_range`). Reply → `ready`,
|
> CAP_NET_RAW, no native dep; the booth compose sets `net.ipv4.ping_group_range`). Reply → `ready`,
|
||||||
> no reply → `offline`; **no IP set → `degraded` ("set IP to monitor")**, never a false green.
|
> no reply → `offline`; **no IP set → `degraded` ("set IP to monitor")**, never a false green.
|
||||||
> Verified on hardware: pinged the real readers on the device VLAN. See [[gee-qr-er80]].
|
> Verified on hardware: pinged the real readers on the device VLAN. See [[dingtian-dt008-reader]].
|
||||||
|
|
||||||
Both collapse to one **traffic-light**: `ready | degraded | offline`, plus a `detail` string. Fail
|
Both collapse to one **traffic-light**: `ready | degraded | offline`, plus a `detail` string. Fail
|
||||||
**toward "there's a problem"**, never false-healthy: a probe that throws or times out reads
|
**toward "there's a problem"**, never false-healthy: a probe that throws or times out reads
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ There are **two populations** of users, and they map to **two integration paths*
|
|||||||
| [[wiegand]] reader → UHPPOTE port | The controller | Controller (onboard card list) | **Yes** — works if host down |
|
| [[wiegand]] reader → UHPPOTE port | The controller | Controller (onboard card list) | **Yes** — works if host down |
|
||||||
| Pure TCP/IP reader | Host only | Host, then UDP `open` to relay | No — host on critical path |
|
| Pure TCP/IP reader | Host only | Host, then UDP `open` to relay | No — host on critical path |
|
||||||
| [[lpr-camera|LPR]] / QR scanner | Host only | Host | No |
|
| [[lpr-camera|LPR]] / QR scanner | Host only | Host | No |
|
||||||
| **[[gee-qr-er80]] QR reader (serial)** | Host only | Host (reads serial → `read` bus) | No |
|
| **[[dingtian-dt008-reader|Dingtian DT-008]] QR reader** | Host only | Host (reads serial → `read` bus) | No |
|
||||||
|
|
||||||
> Concrete host-side reader on hand: the **[[gee-qr-er80]]** (QR over RS-232/RS-485). Note autonomy
|
> Concrete host-side reader on hand: the **[[dingtian-dt008-reader|Dingtian DT-008]]** (QR/RFID over HTTP push). Note autonomy
|
||||||
> is moot here anyway — the current relay ([[dingtian-relay]]) has **no onboard card list**, so even
|
> is moot here anyway — the current relay ([[dingtian-relay]]) has **no onboard card list**, so even
|
||||||
> a Wiegand reader would be host-decided. So we take the serial/QR path straight to the host's
|
> a Wiegand reader would be host-decided. So we take the serial/QR path straight to the host's
|
||||||
> `read` bus.
|
> `read` bus.
|
||||||
|
|||||||
@@ -80,9 +80,9 @@ must have:
|
|||||||
- The **scanner is a device behind an adapter** ([[device-adapter-pattern]]): a new `ReaderDevice`
|
- The **scanner is a device behind an adapter** ([[device-adapter-pattern]]): a new `ReaderDevice`
|
||||||
kind (QR/barcode imager) — likely the same `IdentitySource = "ticket"` / `"qr"` path. Keeps the
|
kind (QR/barcode imager) — likely the same `IdentitySource = "ticket"` / `"qr"` path. Keeps the
|
||||||
app device-agnostic; hardware model is procurement ([[bom]], [[open-questions]]).
|
app device-agnostic; hardware model is procurement ([[bom]], [[open-questions]]).
|
||||||
- **On hand:** the **[[gee-qr-er80]]** QR access reader (`-Q-W`: QR scanner, Wiegand/RS-232/RS-485,
|
- **On hand:** the **[[dingtian-dt008-reader|Dingtian DT-008]]** QR/RFID reader (Wiegand/TCP-IP/USB/RS485,
|
||||||
Linux-supported) — the concrete scanner for this path. A serial `ReaderDevice` adapter feeds the
|
Linux-supported) — the concrete scanner for this path. A serial `ReaderDevice` adapter feeds the
|
||||||
`read` bus; pending the reader's RS-232 frame/baud (see [[gee-qr-er80]] open questions).
|
`read` bus; via HTTP-GET push (see [[dingtian-dt008-reader]]).
|
||||||
|
|
||||||
## Ticketless alternative (plate as the ticket)
|
## Ticketless alternative (plate as the ticket)
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,34 @@
|
|||||||
---
|
---
|
||||||
type: entity
|
type: entity
|
||||||
tags: [parking, hardware, readers, qr]
|
tags: [parking, hardware, readers, qr, dingtian]
|
||||||
sources: [gee-qr-er80]
|
sources: [dingtian-dt008]
|
||||||
updated: 2026-06-16
|
updated: 2026-06-28
|
||||||
status: open
|
status: open
|
||||||
---
|
---
|
||||||
|
|
||||||
# GEE-QR-ER80 (QR access reader)
|
# Dingtian DT-008 (QR/RFID access reader)
|
||||||
|
|
||||||
The project's **QR-code reader** (GEE NFC LIMITED). A static optical scanner for **QR /
|
The project's **QR / barcode / RFID reader** — Dingtian **DT-008**, the **same vendor as the
|
||||||
DataMatrix / 1D barcode**, optional ID/IC card. This is the **[[ticket-encoding|QR ticket]]
|
[[dingtian-relay|relay board]]** (which is why it integrates the same HTTP-push way). A static
|
||||||
scanner** the design called for — read at the pay station and exit lane — and a path for **QR
|
optical + card scanner for **QR / barcode (simple)** and **ID/IC/NFC cards**. This is the
|
||||||
[[subscription]]** credentials. On hand: variant **`-Q-W`** (QR scanner; Wiegand/RS-232/RS-485).
|
**[[ticket-encoding|QR ticket]]** scanner (read at the pay station / exit lane) and a path for **QR
|
||||||
(See [[gee-qr-er80|datasheet summary]] / `raw/`.)
|
or RFID [[subscription]]** credentials. Product page: dingtian-tech.com/en_us/qr_code_reader.html.
|
||||||
|
(See [[dingtian-dt008|spec summary]] / `raw/`.)
|
||||||
|
|
||||||
## What it is (and isn't)
|
> **Naming correction (2026-06-28).** Through most of this project this reader was wrongly called
|
||||||
|
> **"GEE" / "GEE/Fondvision" / "GEE-QR-ER80"** — a bad early assumption. There is no GEE device; it
|
||||||
|
> is the **Dingtian DT-008**. The driver id was renamed `gee-qr-reader` → `dingtian-qr-reader`
|
||||||
|
> (migration 0015 rewrites existing rows). All *protocol/behaviour* facts below were observed on the
|
||||||
|
> real hardware and remain correct — only the device identity was wrong.
|
||||||
|
|
||||||
- **Optical, not RFID-prox.** Earlier we *assumed* "ER80-EM" = a 125 kHz EM4100 card reader — the
|
## What it is
|
||||||
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
|
- **QR/barcode + card.** Reads **QR / simple barcode** AND **ID/IC/NFC cards** (~0.2 s, 0–10 cm).
|
||||||
on hand is **QR-only** (`-Q`).
|
(An earlier note guessed "ER80-EM = 125 kHz EM4100 prox" — that was part of the same mis-id.)
|
||||||
- **Multi-interface** (Wiegand 26/34, RS-232, RS-485, USB, TCP/IP); the `-W` variant exposes
|
- **Interfaces: Wiegand 26/34, TCP/IP, USB, RS485.** (NOT RS-232 — that was a fictional-datasheet
|
||||||
**Wiegand + RS-232/RS-485**.
|
claim.) For our integration it talks **HTTP over TCP/IP**; Wiegand is the reader's *output line*
|
||||||
|
on a valid read, not the host transport.
|
||||||
|
- **Power** 9–16 V DC, 800 mA; **86×86×42 mm**; −30…70 °C. Fits the [[disk-os-hardening|appliance]].
|
||||||
|
|
||||||
## How it integrates — HTTP-GET push, server replies the verdict (confirmed via SDK)
|
## How it integrates — HTTP-GET push, server replies the verdict (confirmed via SDK)
|
||||||
|
|
||||||
@@ -48,7 +55,7 @@ barrier. ([[device-input-flow]] is the analogous push pattern; this one also ret
|
|||||||
- Pushes over plain **HTTP** to our `10.0.10.x` host (on the device subnet); no serial wiring, no
|
- 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
|
Wiegand-decode hardware. Suits the host-in-the-loop model; autonomy is moot anyway
|
||||||
([[dingtian-relay]] has no onboard ACL).
|
([[dingtian-relay]] has no onboard ACL).
|
||||||
- **Linux-supported**, 4–15 VDC, default IP `192.168.1.99` — fits the [[disk-os-hardening|appliance]].
|
- Default IP `192.168.1.99` (set its server IP/port to this host in the vendor tool).
|
||||||
|
|
||||||
## Resolved (2026-06-16)
|
## Resolved (2026-06-16)
|
||||||
|
|
||||||
@@ -93,18 +100,18 @@ from 10.0.10.7 (referer: http://www.fondvision.com — the OEM is Fondvision)
|
|||||||
|
|
||||||
## Assignment (as-built 2026-06-16)
|
## Assignment (as-built 2026-06-16)
|
||||||
|
|
||||||
A dedicated **`gee-qr-reader`** driver ([[device-registry]], reader category) models the push reader:
|
A dedicated **`dingtian-qr-reader`** driver ([[device-registry]], reader category) models the push reader:
|
||||||
its one config field is **`serial`** (the `cjihao` the device reports). The admin assigns it in the
|
its one config field is **`serial`** (the `cjihao` the device reports). The admin assigns it in the
|
||||||
[[first-run-setup|setup wizard]] like any device (normal UUID row id), enters the serial, and binds
|
[[first-run-setup|setup wizard]] like any device (normal UUID row id), enters the serial, and binds
|
||||||
it to a controller relay. The QR endpoint resolves the reader by **matching `config.serial` to the
|
it to a controller relay. The QR endpoint resolves the reader by **matching `config.serial` to the
|
||||||
scan's `cjihao`** — not by row id — so no DB hand-editing. Set the reader's server IP/port to this
|
scan's `cjihao`** — not by row id — so no DB hand-editing. Set the reader's server IP/port to this
|
||||||
host in the **vendor tool**; assign + enter its serial + bind it here.
|
host in the **vendor tool**; assign + enter its serial + bind it here.
|
||||||
|
|
||||||
- Verified via inject: assign `gee-qr-reader` {serial:"H05M2AFA"} bound to an access relay →
|
- Verified via inject: assign `dingtian-qr-reader` {serial:"H05M2AFA"} bound to an access relay →
|
||||||
a `.jsp` scan with that serial + a matching permit QR → `status:1` (2-beep accept) + open; re-scan
|
a `.jsp` scan with that serial + a matching permit QR → `status:1` (2-beep accept) + open; re-scan
|
||||||
→ permit exit; unknown card → `status:0`; unassigned serial → `status:0` (no relay, graceful).
|
→ permit exit; unknown card → `status:0`; unassigned serial → `status:0` (no relay, graceful).
|
||||||
- Note `tcpip-reader` is the WRONG model for this device (host-connects-out, a stub) — use
|
- Note `tcpip-reader` is the WRONG model for this device (host-connects-out, a stub) — use
|
||||||
`gee-qr-reader`.
|
`dingtian-qr-reader`.
|
||||||
|
|
||||||
## Open / next
|
## Open / next
|
||||||
|
|
||||||
@@ -237,7 +237,7 @@ LPR/ANPR plate identity** (the plate binding below):
|
|||||||
(a chosen value could be guessable or collide). The UI sends a blank QR credential; the server
|
(a chosen value could be guessable or collide). The UI sends a blank QR credential; the server
|
||||||
mints the value and returns it (so the UI can print it). **An RF credential, by contrast, carries
|
mints the value and returns it (so the UI can print it). **An RF credential, by contrast, carries
|
||||||
the physical card id, so it is operator-entered.**
|
the physical card id, so it is operator-entered.**
|
||||||
- **Reader output = TCP/IP full string** (decided 2026-06-18, the [[gee-qr-er80|host-in-the-loop
|
- **Reader output = TCP/IP full string** (decided 2026-06-18, the [[dingtian-dt008-reader|host-in-the-loop
|
||||||
QR reader]] path): the reader delivers the whole decoded string, so the code length is free
|
QR reader]] path): the reader delivers the whole decoded string, so the code length is free
|
||||||
(unguessable token). *If a site ever wires the reader as **Wiegand 26/34** instead, a scanned
|
(unguessable token). *If a site ever wires the reader as **Wiegand 26/34** instead, a scanned
|
||||||
QR truncates to a 24-/32-bit number — the generated code would then have to be a numeric id in
|
QR truncates to a 24-/32-bit number — the generated code would then have to be a numeric id in
|
||||||
@@ -255,7 +255,7 @@ LPR/ANPR plate identity** (the plate binding below):
|
|||||||
- **RF tag / chip / card — selectable later, NOT live yet.** An RFID/proximity credential, read
|
- **RF tag / chip / card — selectable later, NOT live yet.** An RFID/proximity credential, read
|
||||||
**host-side** (reader → host → `pulseOpen`). **LIVE since 2026-06-18** — the operator selects RFID
|
**host-side** (reader → host → `pulseOpen`). **LIVE since 2026-06-18** — the operator selects RFID
|
||||||
and **reads the card off a physical reader** (see "Enrolling a card" below) rather than typing the
|
and **reads the card off a physical reader** (see "Enrolling a card" below) rather than typing the
|
||||||
number. The GEE readers are combo QR + RFID (ID/IC/NFC), so the same device captures both. A
|
number. The Dingtian DT-008 readers are combo QR + RFID (ID/IC/NFC), so the same device captures both. A
|
||||||
Wiegand-out reader keeps a future autonomous path open ([[entry-exit-readers]]); the
|
Wiegand-out reader keeps a future autonomous path open ([[entry-exit-readers]]); the
|
||||||
[[dingtian-relay]] has no onboard card list.
|
[[dingtian-relay]] has no onboard card list.
|
||||||
- **Plate (LPR/ANPR) — matching is BUILT, the live SOURCE is the one missing wire.** When plate-bound
|
- **Plate (LPR/ANPR) — matching is BUILT, the live SOURCE is the one missing wire.** When plate-bound
|
||||||
@@ -296,7 +296,7 @@ traffic, so capture must **borrow one reader briefly without blocking the other*
|
|||||||
A subscription is a one-to-many aggregate: it may hold **several credentials at once** — e.g. a QR
|
A subscription is a one-to-many aggregate: it may hold **several credentials at once** — e.g. a QR
|
||||||
**and** an RFID card (and later NFC). Each is its own `subscription_credentials` row; any of them
|
**and** an RFID card (and later NFC). Each is its own `subscription_credentials` row; any of them
|
||||||
resolves the same subscription at the barrier. (NFC works today as an `rf` credential on the combo
|
resolves the same subscription at the barrier. (NFC works today as an `rf` credential on the combo
|
||||||
GEE reader; a distinct `nfc` `kind` is a small future labelling-only addition.)
|
Dingtian DT-008 reader; a distinct `nfc` `kind` is a small future labelling-only addition.)
|
||||||
|
|
||||||
Crucially, **entry and exit are NOT bound to the same credential.** Originally the session was keyed
|
Crucially, **entry and exit are NOT bound to the same credential.** Originally the session was keyed
|
||||||
by the exact credential value read, so you had to leave with whatever you arrived with — an
|
by the exact credential value read, so you had to leave with whatever you arrived with — an
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@ Counts: 4 sources · 19 entities · 45 concepts · 7 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).
|
- [[dingtian-dt008]] — Dingtian DT-008 product page: QR/RFID access reader (QR/barcode + ID/IC/NFC; Wiegand/TCP-IP/USB/RS485; HTTP-GET push).
|
||||||
- [[qrcode-sdk]] — QRCode SDK v1.6.5: the reader's HTTP-GET-poll protocol + JSON verdict (beep/output).
|
- [[qrcode-sdk]] — QRCode SDK v1.6.5: the reader's HTTP-GET-poll protocol + JSON verdict (beep/output).
|
||||||
- [[parksql2017-legacy-schema]] — predecessor SQL Server schema (Albanian market): legacy tariff/discount/membership/shift/fiscal model; confirms blocks, adds time-windows + categories, lacks postpaid sponsors.
|
- [[parksql2017-legacy-schema]] — predecessor SQL Server schema (Albanian market): legacy tariff/discount/membership/shift/fiscal model; confirms blocks, adds time-windows + categories, lacks postpaid sponsors.
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ Counts: 4 sources · 19 entities · 45 concepts · 7 decision records.
|
|||||||
- [[atecc608]] — secure element; non-extractable signing key (host events + controller auth).
|
- [[atecc608]] — secure element; non-extractable signing key (host events + controller auth).
|
||||||
- [[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.
|
||||||
- [[gee-qr-er80]] — QR access reader on hand; host-side serial → `read` bus (the QR-ticket scanner).
|
- [[dingtian-dt008-reader]] — Dingtian DT-008 QR/RFID reader on hand; host-side serial → `read` bus (the QR-ticket scanner).
|
||||||
- [[zkteco-controller]] — ❌ rejected/historical; aux-input path was a contender, not pursued.
|
- [[zkteco-controller]] — ❌ rejected/historical; aux-input path was a contender, not pursued.
|
||||||
- [[dingtian-relay]] — ✅ CHOSEN access controller; decoupled inputs solve the button blocker (driver verified on hardware); spare relays drive aux outputs (`setAux`).
|
- [[dingtian-relay]] — ✅ CHOSEN access controller; decoupled inputs solve the button blocker (driver verified on hardware); spare relays drive aux outputs (`setAux`).
|
||||||
- [[hikvision-radar]] — vehicle-presence radar on a Dingtian input; the entry presence gate (per-input active-level caveat).
|
- [[hikvision-radar]] — vehicle-presence radar on a Dingtian input; the entry presence gate (per-input active-level caveat).
|
||||||
|
|||||||
+17
@@ -1884,3 +1884,20 @@ snapshots from it before I caught it. The signed ledger was untouched (snapshots
|
|||||||
advisory; `PRAGMA integrity_check: ok`, ledger_events/sessions/subscriptions intact) and it was dev
|
advisory; `PRAGMA integrity_check: ok`, ledger_events/sessions/subscriptions intact) and it was dev
|
||||||
not prod — but it violated the never-touch-the-live-DB rule. Lesson: pass the scratch path
|
not prod — but it violated the never-touch-the-live-DB rule. Lesson: pass the scratch path
|
||||||
explicitly + guard-refuse any non-scratch path BEFORE any destructive op (the corrected harness does).
|
explicitly + guard-refuse any non-scratch path BEFORE any destructive op (the corrected harness does).
|
||||||
|
|
||||||
|
## [2026-06-28] fix | The QR reader is a Dingtian DT-008, NOT "GEE" (correct an early mis-id)
|
||||||
|
A wrong early assumption named the QR/RFID access reader "GEE" / "GEE/Fondvision" / "GEE-QR-ER80"
|
||||||
|
(and summarized a `raw/GEE-QR-ER80….pdf` as its datasheet). There is no GEE device — it's the
|
||||||
|
**Dingtian DT-008** (https://www.dingtian-tech.com/en_us/qr_code_reader.html), the SAME vendor as
|
||||||
|
the relay board, which is why it integrates the identical HTTP-GET-push way. Corrected across the
|
||||||
|
codebase + wiki: driver symbol `geeQrReaderDriver`→`dingtianQrReaderDriver`, **persisted driverId
|
||||||
|
`gee-qr-reader`→`dingtian-qr-reader`** (migration **0015** rewrites the existing `devices.driver_id`
|
||||||
|
rows so readers keep resolving — applied to the dev DB, 2 rows; the booth applies it on boot), label
|
||||||
|
"Dingtian DT-008 QR/RFID reader (HTTP push)", and all server/test/comment refs. Wiki: renamed
|
||||||
|
`entities/gee-qr-er80.md`→`entities/dingtian-dt008-reader.md` and `sources/gee-qr-er80.md`→
|
||||||
|
`sources/dingtian-dt008.md`, rewrote both to the REAL DT-008 specs (Wiegand26/34 + TCP/IP + USB +
|
||||||
|
RS485 — NOT RS-232; QR/barcode + ID/IC/NFC — NOT DataMatrix/1D; 9–16 V/800 mA) while keeping all the
|
||||||
|
verified-on-hardware protocol facts (cjihao serial, `.jsp` path, `Connection: close`). Memory
|
||||||
|
`gee-reader-serial-binding`→`dingtian-reader-serial-binding`. The only surviving "GEE" mentions are
|
||||||
|
deliberate naming-correction notes + the raw PDF filename. Behaviour unchanged — naming + the
|
||||||
|
persisted id only. build/lint/test green.
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
type: source
|
||||||
|
tags: [parking, hardware, readers, qr, dingtian, datasheet]
|
||||||
|
sources: [dingtian-dt008]
|
||||||
|
updated: 2026-06-28
|
||||||
|
---
|
||||||
|
|
||||||
|
# Source: Dingtian DT-008 QR Code Reader (product page)
|
||||||
|
|
||||||
|
Vendor product page for the **Dingtian DT-008** QR/barcode/RFID access reader —
|
||||||
|
https://www.dingtian-tech.com/en_us/qr_code_reader.html. This is the reader the project
|
||||||
|
actually has on hand for the [[ticket-encoding|QR ticket]] / RFID-[[subscription]] paths.
|
||||||
|
Entity: [[dingtian-dt008-reader]]. Same vendor as the [[dingtian-relay|Dingtian relay board]].
|
||||||
|
|
||||||
|
> **Supersedes a mis-identified source.** The project originally summarized
|
||||||
|
> `raw/GEE-QR-ER80 QR Code Access Control Reader.pdf` as if the reader were a "GEE-QR-ER80"
|
||||||
|
> (GEE NFC LIMITED). That was a wrong early assumption — the device is the Dingtian DT-008.
|
||||||
|
> Several facts in that PDF (RS-232, DataMatrix/1D, a Linux SDK) do **not** match the real
|
||||||
|
> hardware and were dropped. The HTTP-push protocol facts, however, were later **verified on the
|
||||||
|
> actual device** (see [[dingtian-dt008-reader]] "Verified on hardware").
|
||||||
|
|
||||||
|
## Key takeaways (DT-008 product page)
|
||||||
|
|
||||||
|
- **Scans:** QR / barcode (simple) **and** ID/IC/NFC cards. Read ~**0.2 s**, range **0–10 cm**.
|
||||||
|
- **Interfaces:** **Wiegand 26/34, TCP/IP, USB, RS485.** (For our integration: HTTP over TCP/IP.)
|
||||||
|
- **Power:** 9–16 V DC, 800 mA. **Size:** 86×86×42 mm. **Temp:** −30…70 °C.
|
||||||
|
- **Wiegand pinout:** Red(power), Black(GND), Green(D0), White(D1), Blue(LED), Yellow(BEEP).
|
||||||
|
- **Reporting:** "QR Code HTTP GET" — the reader HTTP-GETs a configured host on each scan; the host
|
||||||
|
replies the verdict (drives beep/output). Vendor ships a **QR Code config tool** + HTTP-GET demo
|
||||||
|
code (C++/C#/PHP) and an SDK (`QRCode_sdk.zip`). See [[qrcode-sdk]] for the protocol we implement.
|
||||||
|
|
||||||
|
## How we use it
|
||||||
|
|
||||||
|
Host-in-the-loop, synchronous HTTP: reader GETs `/qa/mcardsea.<ext>` with its serial (`cjihao`);
|
||||||
|
our endpoint (`apps/server/src/routes/qr-reader.ts`) decides and replies the SDK verdict, and emits
|
||||||
|
a `read` event for the access flows. Full integration + the on-hardware findings (the `.jsp` path
|
||||||
|
extension, `Connection: close` requirement, serial resolution) are in [[dingtian-dt008-reader]].
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
---
|
|
||||||
type: source
|
|
||||||
tags: [parking, hardware, readers, qr, datasheet]
|
|
||||||
sources: [gee-qr-er80]
|
|
||||||
updated: 2026-06-16
|
|
||||||
---
|
|
||||||
|
|
||||||
# Source: GEE-QR-ER80 QR Code Access Control Reader (datasheet)
|
|
||||||
|
|
||||||
Vendor datasheet (GEE NFC LIMITED, ©2007–2019) for the **GEE-QR-ER80** — a static
|
|
||||||
**QR-code access-control reader**, optional ID/IC card. The reader the project has
|
|
||||||
on hand for the [[ticket-encoding|QR ticket]] path. Raw:
|
|
||||||
`raw/GEE-QR-ER80 QR Code Access Control Reader.pdf` (3 pages). Entity: [[gee-qr-er80]].
|
|
||||||
|
|
||||||
## Key takeaways
|
|
||||||
|
|
||||||
- **Optical scanner**, not a prox-card reader: reads **QR, DataMatrix, 1D barcode** (static).
|
|
||||||
Optional add-ons for **IC card UID / ID card**.
|
|
||||||
- **Multi-interface:** **Wiegand 26/34, RS-232, RS-485, USB, TCP/IP** — selectable by variant.
|
|
||||||
- **Power:** 4–15 VDC, < 800 mA. **Read direction:** 360°. Built-in scanner LED.
|
|
||||||
- **OS:** Windows XP/7/8/10 **and Linux** (explicit) — fits the [[disk-os-hardening|Linux appliance]].
|
|
||||||
- **Wiring (Wiegand/RS-232/485 variant):** VCC(+12V), GND, **D0/D1** (Wiegand), **TX/R+ , RX/R-**
|
|
||||||
(RS-232 / RS-485), plus **LED** and **BEEP** control lines (host can drive feedback).
|
|
||||||
- **Order code** `GEE-QR-ER80-<scanner>-<interface>`: `Q`=QR scanner / `D`=ID reader / `C`=IC reader;
|
|
||||||
`W`=WG·RS232·RS485 / `U`=USB / `T`=RJ45 (TCP/IP). **On hand: `-Q-W`** (QR scanner; Wiegand/RS-232/RS-485).
|
|
||||||
|
|
||||||
## Section map
|
|
||||||
|
|
||||||
- p1 — overview, physical + feature table (interfaces, power, read direction).
|
|
||||||
- p2 — supported types (QR/DM/1D + optional IC/ID), OS, environment; **wire definition** (pin table).
|
|
||||||
- p3 — order-code breakdown, applications (access control / vacation rentals / time attendance).
|
|
||||||
|
|
||||||
## Not in this datasheet (open)
|
|
||||||
|
|
||||||
- The **RS-232/RS-485 data protocol**: baud rate, frame format, and whether a QR scan is emitted as
|
|
||||||
an **ASCII string** (expected) vs. some framed protocol. Decides the host-side adapter — see
|
|
||||||
[[gee-qr-er80]] open questions. Resolve by vendor docs or by observing the port on a scan.
|
|
||||||
@@ -5,13 +5,13 @@ sources: [qrcode-sdk]
|
|||||||
updated: 2026-06-16
|
updated: 2026-06-16
|
||||||
---
|
---
|
||||||
|
|
||||||
# Source: QRCode SDK v1.6.5 (GEE/Dingtian QR reader)
|
# Source: QRCode SDK v1.6.5 (Dingtian DT-008 QR reader)
|
||||||
|
|
||||||
Vendor SDK for the QR access reader ([[gee-qr-er80]]; also branded Dingtian). Defines the
|
Vendor SDK for the QR access reader (the Dingtian [[dingtian-dt008-reader]]). Defines the
|
||||||
reader↔server **HTTP protocol** — the missing piece the datasheet omitted. Files at
|
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
|
`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 +
|
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]].
|
binaries; this summary is the faithful capture. Entity: [[dingtian-dt008-reader]].
|
||||||
|
|
||||||
## The protocol — HTTP GET poll, server replies the verdict
|
## The protocol — HTTP GET poll, server replies the verdict
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ GET /qa/mcardsea.php?cardid=445D2C&mjihao=1&cjihao=HW256097&status=11&time=15404
|
|||||||
|
|
||||||
This is **host-in-the-loop, synchronous**: the GET *is* the access query; our JSON reply *is* the
|
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
|
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]] +
|
than a fire-and-forget read. Direction comes from the `status` low digit. See [[dingtian-dt008-reader]] +
|
||||||
[[device-input-flow]].
|
[[device-input-flow]].
|
||||||
|
|
||||||
## Defaults / misc
|
## Defaults / misc
|
||||||
|
|||||||
Reference in New Issue
Block a user