@ljames8/hormann-hcp-client
Version:
Hormann Communication Protocol v1 garage door serial client
126 lines (125 loc) • 5.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockHCPClient = void 0;
const events_1 = require("events");
const garageDoor_1 = require("./garageDoor");
const serialHCPClient_1 = require("./serialHCPClient");
const parser_1 = require("./parser");
// TODO: write some doc
class MockHCPClient extends events_1.EventEmitter {
pushCommandMock;
// keeping track of the parent garageState can be useful
mockState = { door: garageDoor_1.CurrentDoorState.CLOSED, light: false };
constructor(pushCommandMock = () => new Promise((resolve) => {
// just a dummy packet return after 30ms
setTimeout(() => {
resolve(parser_1.HCPPacket.fromData(0x80, 0x01, [0xff, 0xff]));
}, 30);
})) {
super();
this.pushCommandMock = pushCommandMock;
}
inferPushCommandMock(flags, emergencyStop) {
/** smarter pushCommandMock method that infers what to emit based on command and mockState */
let callback = null;
if (emergencyStop === true) {
callback = () => {
this.emitDoorState(garageDoor_1.CurrentDoorState.STOPPED);
};
}
else {
// infer next state
const nextState = MockHCPClient.responseStatusToNextState(flags, this.mockState);
callback = () => {
this.emitGarageState(nextState);
};
}
return new Promise((resolve) => {
// TODO: parametrize timeout values
// confirm command received after 30ms
setTimeout(() => {
resolve(parser_1.HCPPacket.fromData(0x80, 0x01, [0xff, 0xff]));
// emit next door state after 100ms
setTimeout(callback, 100);
}, 30);
});
}
pushCommand(flags, emergencyStop = false) {
return this.pushCommandMock(flags, emergencyStop);
}
static doorStateToBroadcastStatusByte(state) {
switch (state) {
case garageDoor_1.CurrentDoorState.CLOSED:
return 1 << serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_CLOSED;
case garageDoor_1.CurrentDoorState.OPEN:
return 1 << serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_OPENED;
case garageDoor_1.CurrentDoorState.CLOSING: {
// set direction
return ((1 << serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_MOVING) |
((1 << serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_DIRECTION) * serialHCPClient_1.DIRECTION.CLOSING));
}
case garageDoor_1.CurrentDoorState.OPENING: {
// set direction
return ((1 << serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_MOVING) |
((1 << serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_DIRECTION) * serialHCPClient_1.DIRECTION.OPENING));
}
case garageDoor_1.CurrentDoorState.VENTING:
return 1 << serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.DOOR_VENTING;
case garageDoor_1.CurrentDoorState.STOPPED:
return 1 << serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.ERROR_ACTIVE;
}
}
static lightStateToBroadcastStatusByte(state) {
return state === true ? 1 << serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.LIGHT_RELAY_ON : 0;
}
static garageStateToBroadcastStatus(state) {
const status = new Uint8Array(2);
// set arbitrary 2nd status byte value
status[1] = 0xff;
status[0] = MockHCPClient.doorStateToBroadcastStatusByte(state.door);
status[0] |= MockHCPClient.lightStateToBroadcastStatusByte(state.light);
return status;
}
static responseStatusToNextState(flags, currentState) {
/** guess logical next state from input command and current state */
const nextState = currentState;
if (flags.includes(serialHCPClient_1.STATUS_RESPONSE_BYTE0_BITFIELD.TOGGLE_LIGHT)) {
nextState.light = !currentState.light;
}
if (flags.includes(serialHCPClient_1.STATUS_RESPONSE_BYTE0_BITFIELD.VENTING)) {
nextState.door = garageDoor_1.CurrentDoorState.VENTING;
}
else if (flags.includes(serialHCPClient_1.STATUS_RESPONSE_BYTE0_BITFIELD.CLOSE)) {
nextState.door =
currentState.door === garageDoor_1.CurrentDoorState.CLOSED
? garageDoor_1.CurrentDoorState.CLOSED
: garageDoor_1.CurrentDoorState.CLOSING;
}
else if (flags.includes(serialHCPClient_1.STATUS_RESPONSE_BYTE0_BITFIELD.OPEN)) {
nextState.door =
currentState.door === garageDoor_1.CurrentDoorState.OPEN
? garageDoor_1.CurrentDoorState.OPEN
: garageDoor_1.CurrentDoorState.OPENING;
}
return nextState;
}
emitGarageState(state) {
const nextState = MockHCPClient.garageStateToBroadcastStatus(state);
const success = this.emit("data", nextState);
if (success === true)
this.mockState = state;
return success;
}
emitDoorError() {
const status = new Uint8Array(2);
status[0] = 1 << serialHCPClient_1.BROADCAST_STATUS_BYTE0_BITFIELD.ERROR_ACTIVE;
return this.emit("data", status);
}
emitDoorState(state) {
return this.emitGarageState({ door: state, light: this.mockState.light });
}
emitLightState(state) {
return this.emitGarageState({ door: this.mockState.door, light: state });
}
}
exports.MockHCPClient = MockHCPClient;