UNPKG

homebridge-virtual-accessories

Version:
199 lines 10.9 kB
/* eslint-disable brace-style */ import { Accessory } from './accessory.js'; import { Utils } from '../utils/utils.js'; /** * Lock - Accessory implementation */ export class Lock extends Accessory { static ACCESSORY_TYPE_NAME = 'Lock'; static UNSECURED = 0; // Characteristic.LockCurrentState.UNSECURED static SECURED = 1; // Characteristic.LockCurrentState.SECURED static JAMMED = 2; // Characteristic.LockCurrentState.JAMMED static UNKNOWN = 3; // Characteristic.LockCurrentState.UNKNOWN static SECURED_REMOTELY = 6; // Characteristic.LockLastKnownAction.SECURED_REMOTELY static UNSECURED_REMOTELY = 7; // Characteristic.LockLastKnownAction.UNSECURED_REMOTELY static SECURED_BY_AUTO_SECURE_TIMEOUT = 8; // Characteristic.LockLastKnownAction.SECURED_BY_AUTO_SECURE_TIMEOUT stateStorageKey = 'LockState'; securityTimeoutStorageKey = 'LockAutoSecurityTimeout'; lastKnownAction = 'LockLastKnownAction'; securityTimerId; states = { LockCurrentState: Lock.SECURED, LockTargetState: Lock.SECURED, LockManagementAutoSecurityTimeout: 0, LockLastKnownAction: Lock.UNSECURED_REMOTELY, }; constructor(platform, accessory, accessoryConfiguration) { super(platform, accessory, accessoryConfiguration); // First configure the device based on the accessory details this.defaultState = this.accessoryConfiguration.lock.defaultState === 'unlocked' ? Lock.UNSECURED : Lock.SECURED; const autoSecurityTimeout = this.accessoryConfiguration.lock.autoSecurityTimeout; this.states.LockCurrentState = this.defaultState; this.states.LockManagementAutoSecurityTimeout = autoSecurityTimeout; this.states.LockLastKnownAction = Lock.UNSECURED_REMOTELY; // There is no "unknown" value // If the accessory is stateful retrieve stored state if (this.accessoryConfiguration.accessoryIsStateful) { const accessoryState = this.loadAccessoryState(this.storagePath); const cachedState = accessoryState[this.stateStorageKey]; const cachedSecurityTimeout = accessoryState[this.securityTimeoutStorageKey]; const cachedLastKnownAction = accessoryState[this.lastKnownAction]; if (cachedState !== undefined) { this.states.LockCurrentState = cachedState; } if (cachedSecurityTimeout !== undefined) { this.states.LockManagementAutoSecurityTimeout = cachedSecurityTimeout; } if (cachedLastKnownAction !== undefined) { this.states.LockLastKnownAction = cachedLastKnownAction; } } this.states.LockTargetState = this.states.LockCurrentState; this.service = this.accessory.getService(this.platform.Service.LockMechanism) || this.accessory.addService(this.platform.Service.LockMechanism); this.service.setCharacteristic(this.platform.Characteristic.Name, this.accessoryConfiguration.accessoryName); // Update the initial state of the accessory this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Setting Lock Current State: ${Lock.getStateName(this.states.LockCurrentState)}`); this.service.updateCharacteristic(this.platform.Characteristic.LockCurrentState, (this.states.LockCurrentState)); this.service.updateCharacteristic(this.platform.Characteristic.LockTargetState, (this.states.LockTargetState)); // register handlers this.service.getCharacteristic(this.platform.Characteristic.LockCurrentState) .onGet(this.getLockCurrentState.bind(this)); // GET - bind to the 'handleLockCurrentStateGet` method below this.service.getCharacteristic(this.platform.Characteristic.LockTargetState) .onSet(this.setLockTargetState.bind(this)) // SET - bind to the `handleLockTargetStateSet` method below .onGet(this.getLockTargetState.bind(this)); // GET - bind to the `handleLockTargetStateGet` method below /** * Creating multiple services of the same type. * * To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error, * when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id: * this.accessory.getService('NAME') || this.accessory.addService(this.platform.Service.Lightbulb, 'NAME', 'USER_DEFINED_SUBTYPE_ID'); * * The USER_DEFINED_SUBTYPE must be unique to the platform accessory (if you platform exposes multiple accessories, each accessory * can use the same subtype id.) */ // Creating Lock Management service const lockManagementServiceName = `${this.accessoryConfiguration.accessoryName} Management`; const lockManagementService = this.accessory.getService(lockManagementServiceName) || this.accessory.addService(this.platform.Service.LockManagement, lockManagementServiceName, this.accessory.UUID + '-LMS'); lockManagementService.getCharacteristic(this.platform.Characteristic.LockControlPoint) .onSet(this.setLockControlPoint.bind(this)); lockManagementService.getCharacteristic(this.platform.Characteristic.Version) .onGet(this.getVersion.bind(this)); lockManagementService.getCharacteristic(this.platform.Characteristic.LockManagementAutoSecurityTimeout) .onSet(this.setLockManagementAutoSecurityTimeout.bind(this)) .onGet(this.getLockManagementAutoSecurityTimeout.bind(this)) .setProps({ minValue: 0, maxValue: 3600, minStep: 1, unit: "seconds" /* Units.SECONDS */, }); lockManagementService.getCharacteristic(this.platform.Characteristic.LockLastKnownAction) .onGet(this.getLockLastKnownAction.bind(this)); } // Handlers async getLockCurrentState() { const lockState = this.states.LockCurrentState; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Current State: ${Lock.getStateName(lockState)}`); return lockState; } async setLockTargetState(value) { this.states.LockTargetState = value; this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Target State: ${Lock.getStateName(this.states.LockTargetState)}`); this.states.LockCurrentState = this.states.LockTargetState; this.service.setCharacteristic(this.platform.Characteristic.LockCurrentState, (this.states.LockCurrentState)); this.states.LockLastKnownAction = (this.states.LockCurrentState === Lock.SECURED) ? Lock.SECURED_REMOTELY : Lock.UNSECURED_REMOTELY; this.storeState(); this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Current State: ${Lock.getStateName(this.states.LockCurrentState)}`); // Run auto lock timeout this.startAutoSecurityTimeout(); } async getLockTargetState() { const lockState = this.states.LockTargetState; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Target State: ${Lock.getStateName(lockState)}`); return lockState; } // Lock Management Service handlers async setLockControlPoint(value) { const lockControlPoint = value; this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Lock Control Point: ${lockControlPoint}`); } async getVersion() { const version = '1.0.0'; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Lock Management Version: ${version}`); return version; } async setLockManagementAutoSecurityTimeout(value) { this.states.LockManagementAutoSecurityTimeout = value; // eslint-disable-next-line max-len this.log.info(`[${this.accessoryConfiguration.accessoryName}] Setting Lock Management Auto Security Timeout: ${this.states.LockManagementAutoSecurityTimeout}`); } async getLockManagementAutoSecurityTimeout() { const lockManagementAutoSecurityTimeout = this.states.LockManagementAutoSecurityTimeout; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Lock Management Auto Security Timeout: ${lockManagementAutoSecurityTimeout}`); return lockManagementAutoSecurityTimeout; } async getLockLastKnownAction() { const lockLastKnownAction = this.states.LockLastKnownAction; this.log.debug(`[${this.accessoryConfiguration.accessoryName}] Getting Lock Last Known Action: ${lockLastKnownAction}`); return lockLastKnownAction; } getJsonState() { const json = JSON.stringify({ [this.stateStorageKey]: this.states.LockCurrentState, [this.securityTimeoutStorageKey]: this.states.LockManagementAutoSecurityTimeout, [this.lastKnownAction]: this.states.LockLastKnownAction, }); return json; } getAccessoryTypeName() { return Lock.ACCESSORY_TYPE_NAME; } static getStateName(state) { let stateName; switch (state) { case undefined: { stateName = 'undefined'; break; } case Lock.UNSECURED: { stateName = 'UNSECURED'; break; } case Lock.SECURED: { stateName = 'SECURED'; break; } case Lock.JAMMED: { stateName = 'JAMMED'; break; } case Lock.UNKNOWN: { stateName = 'UNKNOWN'; break; } default: { stateName = state.toString(); } } return stateName; } startAutoSecurityTimeout() { if (this.states.LockTargetState !== this.defaultState && this.states.LockManagementAutoSecurityTimeout > 0) { const securityTimeoutMillis = this.states.LockManagementAutoSecurityTimeout * 1000; this.securityTimerId = setTimeout(() => { // Reset timer clearTimeout(this.securityTimerId); this.service.setCharacteristic(this.platform.Characteristic.LockTargetState, (this.defaultState)); this.states.LockLastKnownAction = Lock.SECURED_BY_AUTO_SECURE_TIMEOUT; }, securityTimeoutMillis); const timeout = Utils.secondsToHHmmss(this.states.LockManagementAutoSecurityTimeout); this.log.info(`[${this.accessoryConfiguration.accessoryName}] Security Timeout in ${timeout}`); } else { this.log.info(`[${this.accessoryConfiguration.accessoryName}] No Security Timeout defined`); } } } //# sourceMappingURL=virtualAccessoryLock.js.map