devices: stub-access driver (bench-test flows without a relay)
A live QR scan reached the app but rejected: 'reader not on an access-equipped lane' — the dispatcher requires an access device on the reader's lane. Add a no-op stub-access driver (access category, no config) whose pulseOpen only logs and does no device I/O, so the QR->permit->accept flow (incl. the beep) can be tested without the Dingtian relay connected. Not for production; registered in the catalog.
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
import type { AccessControlDevice, DeviceHealth } from "../interfaces.js";
|
||||||
|
import type { AccessDriver, DeviceConfig } from "../registry.js";
|
||||||
|
import { stubLog } from "./common.js";
|
||||||
|
|
||||||
|
// Stub access controller — a no-op barrier for BENCH TESTING the entry/exit/permit
|
||||||
|
// flows without real relay hardware. `pulseOpen` just logs "intent to open"; it
|
||||||
|
// performs no device I/O, so it can stand in on a lane while the real
|
||||||
|
// [[dingtian-relay]] isn't connected. NOT for production. See first-run-setup.md.
|
||||||
|
|
||||||
|
class StubAccess implements AccessControlDevice {
|
||||||
|
readonly driverId = "stub-access";
|
||||||
|
constructor(_config: DeviceConfig) {}
|
||||||
|
async connect(): Promise<void> {}
|
||||||
|
async disconnect(): Promise<void> {}
|
||||||
|
async healthCheck(): Promise<DeviceHealth> {
|
||||||
|
return { status: "ready", detail: "stub (no real barrier)" };
|
||||||
|
}
|
||||||
|
async pulseOpen(doorId: number): Promise<void> {
|
||||||
|
stubLog(this.driverId, `pulseOpen door ${doorId} (stub — no relay fired)`);
|
||||||
|
}
|
||||||
|
async getDoorStatus(): Promise<"open" | "closed"> {
|
||||||
|
return "closed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const stubAccessDriver: AccessDriver = {
|
||||||
|
id: "stub-access",
|
||||||
|
category: "access",
|
||||||
|
label: "Stub barrier (bench testing — no relay)",
|
||||||
|
description:
|
||||||
|
"A no-op access controller for testing the flows without hardware. pulseOpen only logs; no relay is fired. Not for production.",
|
||||||
|
transports: ["tcp-ip"],
|
||||||
|
configFields: [],
|
||||||
|
create: (c) => new StubAccess(c),
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import { registry } from "../registry.js";
|
import { registry } from "../registry.js";
|
||||||
import { dingtianDriver } from "./access-dingtian.js";
|
import { dingtianDriver } from "./access-dingtian.js";
|
||||||
|
import { stubAccessDriver } from "./access-stub.js";
|
||||||
import { dahuaDriver, hikvisionDriver } from "./camera.js";
|
import { dahuaDriver, hikvisionDriver } from "./camera.js";
|
||||||
import { rongtaDriver } from "./printer-rongta.js";
|
import { rongtaDriver } from "./printer-rongta.js";
|
||||||
import { geeQrReaderDriver, tcpipReaderDriver, wiegandReaderDriver } from "./reader.js";
|
import { geeQrReaderDriver, tcpipReaderDriver, wiegandReaderDriver } from "./reader.js";
|
||||||
@@ -14,6 +15,7 @@ export function registerBuiltinDrivers(): void {
|
|||||||
if (registered) return;
|
if (registered) return;
|
||||||
registered = true;
|
registered = true;
|
||||||
registry.register(dingtianDriver);
|
registry.register(dingtianDriver);
|
||||||
|
registry.register(stubAccessDriver);
|
||||||
registry.register(wiegandReaderDriver);
|
registry.register(wiegandReaderDriver);
|
||||||
registry.register(tcpipReaderDriver);
|
registry.register(tcpipReaderDriver);
|
||||||
registry.register(geeQrReaderDriver);
|
registry.register(geeQrReaderDriver);
|
||||||
@@ -24,6 +26,7 @@ export function registerBuiltinDrivers(): void {
|
|||||||
|
|
||||||
export {
|
export {
|
||||||
dingtianDriver,
|
dingtianDriver,
|
||||||
|
stubAccessDriver,
|
||||||
wiegandReaderDriver,
|
wiegandReaderDriver,
|
||||||
tcpipReaderDriver,
|
tcpipReaderDriver,
|
||||||
geeQrReaderDriver,
|
geeQrReaderDriver,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export { setDeviceLogSink, type DeviceLogSink } from "./drivers/common.js";
|
|||||||
export {
|
export {
|
||||||
registerBuiltinDrivers,
|
registerBuiltinDrivers,
|
||||||
dingtianDriver,
|
dingtianDriver,
|
||||||
|
stubAccessDriver,
|
||||||
wiegandReaderDriver,
|
wiegandReaderDriver,
|
||||||
tcpipReaderDriver,
|
tcpipReaderDriver,
|
||||||
geeQrReaderDriver,
|
geeQrReaderDriver,
|
||||||
|
|||||||
+10
@@ -681,3 +681,13 @@ guarantee. Recorded in [[dingtian-relay]] (new Hardening section).
|
|||||||
matching permit → status:1 + open; re-scan → exit; unknown card → status:0; unassigned serial →
|
matching permit → status:1 + open; re-scan → exit; unknown card → status:0; unassigned serial →
|
||||||
status:0. Full build 5/5.
|
status:0. Full build 5/5.
|
||||||
- Updated [[gee-qr-er80]] (assignment as-built).
|
- Updated [[gee-qr-er80]] (assignment as-built).
|
||||||
|
|
||||||
|
## [2026-06-16] feature | stub-access driver (bench-test the flows without a relay)
|
||||||
|
- Live QR scan reached the real app (.jsp, serial resolved) but rejected: "reader not on an
|
||||||
|
access-equipped lane" — lane 1 had the reader but no access device. The dispatcher requires an
|
||||||
|
access device on the same lane.
|
||||||
|
- Added a no-op **`stub-access`** driver (access category, no config): `pulseOpen` just logs, no
|
||||||
|
device I/O — stands in on a lane to test QR→permit→accept (incl. the beep) without the
|
||||||
|
[[dingtian-relay]] connected. NOT for production. Registered in the catalog.
|
||||||
|
- To get a live accept: assign Stub barrier to the reader's lane + a permit whose QR = the scanned
|
||||||
|
code → status:1 (2-beep) + logged pulseOpen.
|
||||||
|
|||||||
Reference in New Issue
Block a user