feat(devices): radar presence input + button-light output on the controller
Model the entry button (I1) and a Hikvision radar (I2) as named children of the access controller, and drive the button's 12V lamp on a spare relay. - Radar = the existing relays[].presenceInput one-car-one-ticket gate, now labelled presenceKind: loop|radar. A radar may idle opposite the button, so add a per-input active-level override: relays[].presenceActiveLow -> driver inputActiveLow set, inverting just that terminal (pure helper inputActive()). The Dingtian has one board-wide resting level otherwise. - AuxOutputDevice.setAux(channel,on) capability on the device interface (Dingtian latch) so business logic drives a NON-barrier lamp through the interface. Barriers still only pulseOpen — barrier-not-a-door preserved. - ButtonLightController: subscribes to the radar input edge + the camera lane status and drives a 3-state lamp — radar+car=solid, radar-only=blink (~1Hz), else off. Fails OFF on host loss/error; de-duped. A radar detection never opens a barrier on its own (advisory; threat model). - SetupWizard: presence kind + active-low + a button-light relay picker; sq+en i18n. Tests: button-light.test.ts (truth table + blink + fail-OFF + de-dupe), access-dingtian.test.ts (active-level inversion). Workspace build+lint+test green (158 server tests). Wiki: hikvision-radar, button-light-indicator + updates. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -35,6 +35,23 @@ export interface AccessControlDevice extends Device {
|
||||
getDoorStatus(doorId: number): Promise<"open" | "closed">;
|
||||
}
|
||||
|
||||
// --- Auxiliary outputs (non-barrier latched signals) ---------------------
|
||||
// Optional capability for controllers with SPARE relays wired to something that
|
||||
// is NOT a barrier — a button lamp, a "wait"/"go" sign. setAux LATCHES the output
|
||||
// on or off and holds it (unlike pulseOpen, which is momentary). The
|
||||
// barrier-not-a-door rule does NOT apply here: this output never gates a vehicle,
|
||||
// so holding/blinking it is fine. Business logic drives indicators through THIS,
|
||||
// never the driver's own relay methods. See wiki/concepts/button-light-indicator.md.
|
||||
export interface AuxOutputDevice {
|
||||
/** Latch an auxiliary output on/off. 1-based channel (a spare relay). */
|
||||
setAux(channel: number, on: boolean): Promise<void>;
|
||||
}
|
||||
|
||||
/** Feature-detect the aux-output capability on a built device adapter. */
|
||||
export function hasAuxOutput(d: unknown): d is AuxOutputDevice {
|
||||
return typeof (d as Partial<AuxOutputDevice>)?.setAux === "function";
|
||||
}
|
||||
|
||||
// --- Inputs (buttons / dry contacts) -------------------------------------
|
||||
// Optional capability for controllers that expose host-readable inputs SEPARATE
|
||||
// from their relays — e.g. the Dingtian board. This is what enables host-in-the-
|
||||
|
||||
Reference in New Issue
Block a user