UNPKG

@ljames8/hormann-hcp-client

Version:

Hormann Communication Protocol v1 garage door serial client

181 lines (180 loc) 8.01 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.HormannGarageDoorOpener = exports.TargetDoorState = exports.CurrentDoorState = exports.SerialHCPClient = exports.MockHCPClient = void 0; exports.createHormannGarageDoorOpener = createHormannGarageDoorOpener; const events_1 = require("events"); const debug_1 = __importDefault(require("debug")); const serialHCPClient_1 = require("./serialHCPClient"); Object.defineProperty(exports, "SerialHCPClient", { enumerable: true, get: function () { return serialHCPClient_1.SerialHCPClient; } }); var mockHCPClient_1 = require("./mockHCPClient"); Object.defineProperty(exports, "MockHCPClient", { enumerable: true, get: function () { return mockHCPClient_1.MockHCPClient; } }); var CurrentDoorState; (function (CurrentDoorState) { CurrentDoorState[CurrentDoorState["OPEN"] = 0] = "OPEN"; CurrentDoorState[CurrentDoorState["CLOSED"] = 1] = "CLOSED"; CurrentDoorState[CurrentDoorState["OPENING"] = 2] = "OPENING"; CurrentDoorState[CurrentDoorState["CLOSING"] = 3] = "CLOSING"; CurrentDoorState[CurrentDoorState["STOPPED"] = 4] = "STOPPED"; CurrentDoorState[CurrentDoorState["VENTING"] = 5] = "VENTING"; })(CurrentDoorState || (exports.CurrentDoorState = CurrentDoorState = {})); var TargetDoorState; (function (TargetDoorState) { TargetDoorState[TargetDoorState["OPEN"] = 0] = "OPEN"; TargetDoorState[TargetDoorState["CLOSED"] = 1] = "CLOSED"; TargetDoorState[TargetDoorState["VENTING"] = 5] = "VENTING"; })(TargetDoorState || (exports.TargetDoorState = TargetDoorState = {})); class GarageDoorOpener extends events_1.EventEmitter { name; manufacturer; model; currentState = null; targetState = null; lightState = null; constructor(name) { super(); this.name = name; } } class HormannGarageDoorOpener extends GarageDoorOpener { hcpClient; logger; broadcastStatus; constructor(name = "Hörmann Garage Door", hcpClient) { super(name); this.hcpClient = hcpClient; this.logger = (0, debug_1.default)(`door:${this.name}`); this.manufacturer = "Hörmann"; this.model = "Supramatic E3"; this.broadcastStatus = new Uint8Array(2); this.hcpClient.on("data", this.onBroadcast.bind(this)); } static targetStateToRequest(targetState) { switch (targetState) { case TargetDoorState.OPEN: { return { flags: [serialHCPClient_1.STATUS_RESPONSE_BYTE0_BITFIELD.OPEN] }; } case TargetDoorState.CLOSED: { return { flags: [serialHCPClient_1.STATUS_RESPONSE_BYTE0_BITFIELD.CLOSE] }; } case TargetDoorState.VENTING: { return { flags: [serialHCPClient_1.STATUS_RESPONSE_BYTE0_BITFIELD.VENTING] }; } } } static broadcastToCurrentState(status) { const bitField = serialHCPClient_1.SerialHCPClient.extractBitfield(status[0]); if (bitField[serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.ERROR_ACTIVE] === true) { return new Error("Error active"); } const lightState = bitField[serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.LIGHT_RELAY_ON]; if (bitField[serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_MOVING] === true) { switch (bitField[serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_DIRECTION]) { case Boolean(serialHCPClient_1.DIRECTION.OPENING): return { door: CurrentDoorState.OPENING, light: lightState }; case Boolean(serialHCPClient_1.DIRECTION.CLOSING): return { door: CurrentDoorState.CLOSING, light: lightState }; } } // if not moving and no error if (bitField[serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_OPENED] === true) { return { door: CurrentDoorState.OPEN, light: lightState }; } else if (bitField[serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_CLOSED] === true) { return { door: CurrentDoorState.CLOSED, light: lightState }; } else if (bitField[serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_VENTING] === true) { return { door: CurrentDoorState.VENTING, light: lightState }; } else { return new Error("Unknown status"); } } onBroadcast(status) { // client 'data' callback, for each broadcast status update if (status[0] != this.broadcastStatus[0]) { // consider only byte 0 as info from byte 1 unknown this.broadcastStatus = status; const newState = HormannGarageDoorOpener.broadcastToCurrentState(status); if (newState instanceof Error) { this.emit("error", newState); // TODO: set current state as STOPPED ? } else { if (this.currentState != newState.door) { this.currentState = newState.door; this.logger(`Current door state now ${CurrentDoorState[this.currentState]}`); this.emit("update_door", newState.door); } if (this.lightState != newState.light) { this.lightState = newState.light; this.logger(`Current light state now ${this.lightState}`); this.emit("update_light", newState.light); } } } } getCurrentState() { if (this.currentState === null) { throw new Error("Current state cannot be retrieved"); } else { return this.currentState; } } getTargetState() { if (this.targetState === null) { throw new Error("Target state is not set"); } else { return this.targetState; } } setTargetState(newState) { if (this.targetState === newState) { this.logger(`Target state already ${TargetDoorState[this.targetState]}(${newState})`); return Promise.resolve(); } else if (this.currentState === newState) { this.logger(`Current state already ${CurrentDoorState[this.currentState]}(${newState})`); this.targetState = newState; return Promise.resolve(); } else { // ask client to operate door const { flags, emergencyStop } = HormannGarageDoorOpener.targetStateToRequest(newState); return this.hcpClient.pushCommand(flags, emergencyStop).then(() => { this.targetState = newState; this.logger(`Target state set to ${TargetDoorState[this.targetState]}`); }); } } getLightOnState() { if (this.lightState === null) { throw new Error("Light state is not set"); } else { return this.lightState; } } setLightOnState(newState) { if (this.lightState === newState) { this.logger(`Light On state already ${newState}`); return Promise.resolve(); } else { // ask client to toggle light return this.hcpClient .pushCommand([serialHCPClient_1.STATUS_RESPONSE_BYTE0_BITFIELD.TOGGLE_LIGHT], false) .then(() => { }); } } } exports.HormannGarageDoorOpener = HormannGarageDoorOpener; function createHormannGarageDoorOpener( /** factory function to create a serial enabled Hormann garage door opener */ name, { path, ...rest }, { packetTimeout = 50, filterBreaks = true, filterMaxLength = true } = {}) { return new HormannGarageDoorOpener(name, new serialHCPClient_1.SerialHCPClient({ path, ...rest }, { packetTimeout, filterBreaks, filterMaxLength })); }