68d61f2d99
The QR reader is a push device and the setup wizard assigns random-UUID ids, so
'id = serial' can't be set via the UI. Add a dedicated gee-qr-reader driver
(reader category) with a single 'serial' config field; the admin assigns it
normally and enters the device's serial (its cjihao).
The QR endpoint now resolves the lane by matching lane_devices.config.serial to
the scan's cjihao (instead of row id == cjihao), so no DB hand-editing. An
unassigned serial resolves to no lane -> status:0, gracefully.
Verified via inject through the real /api/setup/assign: assign {serial:
H05M2AFA} -> .jsp scan with a matching permit QR -> status:1 (accept) + open;
re-scan -> permit exit; unknown card -> status:0; unassigned serial -> status:0.
86 lines
3.3 KiB
TypeScript
86 lines
3.3 KiB
TypeScript
import type { DeviceHealth, ReaderDevice, ReaderEvent } from "../interfaces.js";
|
|
import type { DeviceConfig, ReaderDriver } from "../registry.js";
|
|
import { hostField, portField, stubLog } from "./common.js";
|
|
|
|
// Reader drivers (RF / optical). Two integration paths: Wiegand reads reach the
|
|
// access controller directly (autonomous); TCP-IP readers are seen host-side.
|
|
// See wiki/concepts/entry-exit-readers.md. STUBS only.
|
|
|
|
class StubReader implements ReaderDevice {
|
|
#cb: ((r: ReaderEvent) => void) | null = null;
|
|
constructor(
|
|
readonly driverId: string,
|
|
protected readonly config: DeviceConfig,
|
|
) {}
|
|
async connect(): Promise<void> {
|
|
stubLog(this.driverId, "connect");
|
|
}
|
|
async disconnect(): Promise<void> {
|
|
stubLog(this.driverId, "disconnect");
|
|
}
|
|
async healthCheck(): Promise<DeviceHealth> {
|
|
return { status: "ready", detail: "stub" };
|
|
}
|
|
onRead(cb: (r: ReaderEvent) => void): void {
|
|
this.#cb = cb;
|
|
stubLog(this.driverId, "onRead handler registered");
|
|
}
|
|
/** Test hook for stubs — real drivers emit from hardware events. */
|
|
protected emit(r: ReaderEvent): void {
|
|
this.#cb?.(r);
|
|
}
|
|
}
|
|
|
|
export const wiegandReaderDriver: ReaderDriver = {
|
|
id: "wiegand-reader",
|
|
category: "reader",
|
|
label: "Wiegand reader (into controller)",
|
|
description:
|
|
"RF/optical reader wired Wiegand 26/34 into the access controller's reader port. Autonomous offline decisions.",
|
|
transports: ["wiegand"],
|
|
configFields: [
|
|
{ key: "door", label: "Controller reader port / door", type: "number", required: true, default: 1 },
|
|
{ key: "format", label: "Wiegand format", type: "select", required: true, default: "26", options: [
|
|
{ value: "26", label: "Wiegand 26" },
|
|
{ value: "34", label: "Wiegand 34" },
|
|
] },
|
|
],
|
|
create: (c) => new StubReader("wiegand-reader", c),
|
|
};
|
|
|
|
export const tcpipReaderDriver: ReaderDriver = {
|
|
id: "tcpip-reader",
|
|
category: "reader",
|
|
label: "TCP/IP reader (host-side)",
|
|
description:
|
|
"Network RF/optical reader seen only by the host; host decides and commands the relay.",
|
|
transports: ["tcp-ip"],
|
|
configFields: [hostField, portField(9000)],
|
|
create: (c) => new StubReader("tcpip-reader", c),
|
|
};
|
|
|
|
// GEE/Fondvision QR access reader (e.g. GEE-QR-ER80). A PUSH device: on each scan
|
|
// it HTTP-GETs our backend (/qa/mcardsea.<ext>) carrying its serial (cjihao); the
|
|
// backend resolves the lane by matching that serial to this 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
|
|
// (apps/server routes/qr-reader.ts). See wiki/entities/gee-qr-er80.md.
|
|
export const geeQrReaderDriver: ReaderDriver = {
|
|
id: "gee-qr-reader",
|
|
category: "reader",
|
|
label: "GEE/Fondvision QR reader (HTTP push)",
|
|
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.",
|
|
transports: ["tcp-ip"],
|
|
configFields: [
|
|
{
|
|
key: "serial",
|
|
label: "Device serial (cjihao)",
|
|
type: "string",
|
|
required: true,
|
|
help: "The reader's serial as it reports in each scan (the `cjihao` field). Used to map scans to this lane.",
|
|
},
|
|
],
|
|
create: (c) => new StubReader("gee-qr-reader", c),
|
|
};
|