UNPKG

node-red-contrib-uhppoted

Version:

A set of nodes for the UHPPOTE Wiegand Access Controller

510 lines (422 loc) 13.3 kB
/** * Lookup table to associate message text to the equivalent internationalisation key. */ // prettier-ignore const map = { 'unknown': 'unknown', // event type 'none': 'eventNone','card swipe': 'eventSwipe', 'door': 'eventDoor', 'alarm': 'eventAlarm', '<overwritten>': 'eventOverwritten', // event direction 'in': 'directionIn', 'out': 'directionOut', // event reason 'no reason': '(none)', 'swipe': 'swipe', 'swipe open': 'swipe open', 'swipe close': 'swipe close', 'swipe:denied (remote access control)': 'swipeDenied', 'no access rights': 'noAccess', 'incorrect password': 'incorrectPassword', 'anti-passback': 'antiPassback', 'more cards': 'moreCards', 'first card open': 'firstCardOpen', 'door is normally closed': 'doorNormallyClosed', 'interlock': 'interlock', 'not in allowed time period': 'notInAllowedTimePeriod', 'invalid timezone': 'invalidTimezone', 'access denied': 'accessDenied', 'push button ok': 'pushbuttonOk', 'door opened': 'doorOpened', 'door closed': 'doorClosed', 'door opened (supervisor password)': 'supervisorDoorOpen', 'controller power on': 'controllerPowerOn', 'controller reset': 'controllerReset', 'pushbutton invalid (door locked)': 'pushbuttonDoorLocked', 'pushbutton invalid (offline)': 'pushbuttonOffline', 'pushbutton invalid (interlock)': 'pushbuttonInterlock', 'pushbutton invalid (threat)': 'pushbuttonThreat', 'door open too long': 'doorOpenTooLong', 'forced open': 'forcedOpen', 'fire': 'fire', 'forced closed': 'forcedClosed', 'theft prevention': 'theftPrevention', '24x7 zone': 'zone24x7', 'emergency': 'emergency', 'remote open door': 'remoteOpenDoor', 'remote open door (USB reader)': 'usbOpenDoor', '(reserved)': 'reserved', // doors 'normally open': 'normallyOpen', 'normally closed': 'normallyClosed', 'controlled': 'controlled', // anti-passback 'disabled': 'antipassbackDisabled', '(1:2);(3:4)': 'antipassback12_34', '(1,3):(2,4)': 'antipassback13_24', '1:(2,3)': 'antipassback1_23', '1:(2,3,4)': 'antipassback1_234', } module.exports = { /** * Expands an event type byte into an object with event code and internationalised * event message. * * @param {array} bytes 64 byte message as a Uint8Array * @param {number} offset Index of event type byte in message * @param {function} translator (optional) function to translate event message. * * @param {object} { code:byte, event:string } * * @exports */ eventType: function (bytes, offset, translator) { const byte = bytes.getUint8(offset, true) const event = { code: byte, } switch (byte) { case 0x00: event.event = translate(translator, 'none') break case 0x01: event.event = translate(translator, 'card swipe') break case 0x02: event.event = translate(translator, 'door') break case 0x03: event.event = translate(translator, 'alarm') break case 0xff: event.event = translate(translator, '<overwritten>') break default: event.event = translate(translator, 'unknown') break } return event }, /** * Expands an event direction byte into an object with event direction and internationalised * direction description. * * @param {array} bytes 64 byte message as a Uint8Array * @param {number} offset Index of event direction byte in message * @param {function} translator (optional) function to translate direction description. * * @param {object} { code: byte, direction: string } * * @exports */ direction: function (bytes, offset, translator) { const byte = bytes.getUint8(offset, true) const direction = { code: byte, } switch (byte) { case 0x01: direction.direction = translate(translator, 'in') break case 0x02: direction.direction = translate(translator, 'out') break default: direction.direction = translate(translator, 'unknown') break } return direction }, /** * Expands an event reason byte into an object with event reason and internationalised * reason description. * * @param {array} bytes 64 byte message as a Uint8Array * @param {number} offset Index of event reason byte in message * @param {function} translator (optional) function to translate reason description. * * @param {object} { code: byte, reason: string } * * @exports */ reason: function (bytes, offset, translator) { const byte = bytes.getUint8(offset, true) const reason = { code: byte, } switch (byte) { case 0: reason.reason = translate(translator, 'no reason') break case 1: reason.reason = translate(translator, 'swipe') break case 2: reason.reason = translate(translator, 'swipe open') break case 3: reason.reason = translate(translator, 'swipe close') break case 5: reason.reason = translate(translator, 'swipe:denied (remote access control)') // Access is managed by the system not the controller break case 6: reason.reason = translate(translator, 'no access rights') // swipe denied break case 7: reason.reason = translate(translator, 'incorrect password') // swipe denied break case 8: reason.reason = translate(translator, 'anti-passback') // swipe denied break case 9: reason.reason = translate(translator, 'more cards') // swipe denied (absolutely no idea what this means :-() break case 10: reason.reason = translate(translator, 'first card open') // swipe denied (no idea what this means either) break case 11: reason.reason = translate(translator, 'door is normally closed') // swipe denied break case 12: reason.reason = translate(translator, 'interlock') // swipe denied break case 13: reason.reason = translate(translator, 'not in allowed time period') // swipe denied break case 15: reason.reason = translate(translator, 'invalid timezone') // swipe denied break case 18: reason.reason = translate(translator, 'access denied') // swipe denied break case 20: reason.reason = translate(translator, 'pushbutton ok') break case 23: reason.reason = translate(translator, 'door opened') break case 24: reason.reason = translate(translator, 'door closed') break case 25: reason.reason = translate(translator, 'door opened (supervisor password)') break case 28: reason.reason = translate(translator, 'controller power on') break case 29: reason.reason = translate(translator, 'controller reset') break case 31: reason.reason = translate(translator, 'pushbutton invalid (door locked)') break case 32: reason.reason = translate(translator, 'pushbutton invalid (offline)') break case 33: reason.reason = translate(translator, 'pushbutton invalid (interlock)') break case 34: reason.reason = translate(translator, 'pushbutton invalid (threat)') break case 37: reason.reason = translate(translator, 'door open too long') break case 38: reason.reason = translate(translator, 'forced open') break case 39: reason.reason = translate(translator, 'fire') break case 40: reason.reason = translate(translator, 'forced closed') break case 41: reason.reason = translate(translator, 'theft prevention') break case 42: reason.reason = translate(translator, '24x7 zone') break case 43: reason.reason = translate(translator, 'emergency') break case 44: reason.reason = translate(translator, 'remote open door') break case 45: reason.reason = translate(translator, 'remote open door (USB reader)') break default: reason.reason = translate(translator, '(reserved)') break } return reason }, /** * Expands a status relay state byte into an object with the relays as keys. * * @param {array} bytes 64 byte message as a Uint8Array * @param {number} offset Index of relay state byte in message * * @param {object} { state: byte, 1: open/closed, 2: open/closed, 3: open/closed, 4: open/closed } * * @exports */ relays: function (bytes, offset) { const byte = bytes.getUint8(offset, true) const relays = { state: byte, relays: { 1: (byte & 0x01) === 1, 2: (byte & 0x02) === 1, 3: (byte & 0x03) === 1, 4: (byte & 0x08) === 1, }, } return relays }, /** * Expands a status input state byte into an object with the inputs as keys. * * @param {array} bytes 64 byte message as a Uint8Array * @param {number} offset Index of relay state byte in message * * @param {object} { state: byte, forceLock: open/closed, fireAlarm: open/closed } * * @exports */ inputs: function (bytes, offset) { const byte = bytes.getUint8(offset, true) const inputs = { state: byte, forceLock: (byte & 0x01) === 0x01, fireAlarm: (byte & 0x02) === 0x02, } return inputs }, /** * Translates a door state Expands a status door state byte into an object with the doors as keys. * * @param {array} bytes 64 byte message as a Uint8Array * @param {number} offset Index of door state byte in message * * @param {object} { value: byte, state: 'normally open', 'normally closed', 'controlled' or 'unknown' } * * @exports */ doorState: function (bytes, offset, translator) { const byte = bytes.getUint8(offset, true) const control = { value: byte, } switch (byte) { case 1: control.state = translate(translator, 'normally open') break case 2: control.state = translate(translator, 'normally closed') break case 3: control.state = translate(translator, 'controlled') break default: control.state = translate(translator, 'unknown') break } return control }, /** * Expands an antipassback byte into an object with antipassback code and internationalised mode * description. * * @param {array} bytes 64 byte message as a Uint8Array * @param {number} offset Index of event direction byte in message * @param {function} translator (optional) function to translate direction description. * * @param {object} { code: byte, mode: string } * * @exports */ antipassback: function (bytes, offset, translator) { const byte = bytes.getUint8(offset, true) const antipassback = { code: byte, } switch (byte) { case 0x00: antipassback.mode = translate(translator, 'disabled') break case 0x01: antipassback.mode = translate(translator, '(1:2);(3:4)') break case 0x02: antipassback.mode = translate(translator, '(1,3):(2,4)') break case 0x03: antipassback.mode = translate(translator, '1:(2,3)') break case 0x04: antipassback.mode = translate(translator, '1:(2,3,4)') break default: antipassback.mode = translate(translator, 'unknown') break } return antipassback }, /** * Expands an event type '0' (no event) into an object with event code and internationalised * event message. * * @param {function} translator (optional) function to translate event message. * * @param {object} { code:byte, event:string } * * @exports */ noEventType: function (translator) { return { code: 0, event: translate(translator, 'none'), } }, /** * Expands an event direction '0' (no event) into an object with event code and internationalised * event message. * * @param {function} translator (optional) function to translate event message. * * @param {object} { code:byte, event:string } * * @exports */ noEventDirection: function (translator) { return { code: 0, direction: translate(translator, 'unknown'), } }, /** * Expands an event reason '0' (no event) into an object with event reason and internationalised * reason description. * * @param {function} translator (optional) function to translate reason description. * * @param {object} { code: byte, reason: string } * * @exports */ noEventReason: function (translator) { return { code: 0, reason: translate(translator, 'no reason'), } }, } function translate(translator, text) { if (translator && Object.keys(map).includes(text)) { return translator(map[text]) } return text }