UNPKG

homebridge-ring

Version:

Homebridge plugin for Ring doorbells, cameras, security alarm system and smart lighting

123 lines (122 loc) 5.51 kB
import { hap } from "./hap.js"; import { BaseDataAccessory } from "./base-data-accessory.js"; import { logError, logInfo } from 'ring-client-api/util'; import { map, throttleTime } from 'rxjs/operators'; export class Intercom extends BaseDataAccessory { unlocking = false; unlockTimeout; device; accessory; config; constructor(device, accessory, config) { super(); this.device = device; this.accessory = accessory; this.config = config; const { Characteristic, Service } = hap, lockService = this.getService(Service.LockMechanism), { LockCurrentState, LockTargetState, ProgrammableSwitchEvent } = Characteristic, programableSwitchService = this.getService(Service.StatelessProgrammableSwitch), onDoorbellPressed = device.onDing.pipe(throttleTime(15000), map(() => ProgrammableSwitchEvent.SINGLE_PRESS)), syncLockState = () => { const state = this.getLockState(); lockService .getCharacteristic(Characteristic.LockCurrentState) .updateValue(state); lockService .getCharacteristic(Characteristic.LockTargetState) .updateValue(state); }, markAsUnlocked = () => { // Mark the lock as unlocked, wait 5 seconds, then mark it as locked again clearTimeout(this.unlockTimeout); this.unlocking = true; // Update current state to reflect that the lock is unlocked syncLockState(); // Leave the door in an "unlocked" state for 5 seconds // After that, set the lock back to "locked" for both current and target state this.unlockTimeout = setTimeout(() => { this.unlocking = false; syncLockState(); }, 5000); }; // Subscribe to unlock events coming from push notifications, which will catch an unlock from the Ring app device.onUnlocked.subscribe(markAsUnlocked); // Lock Service this.registerCharacteristic({ characteristicType: LockCurrentState, serviceType: lockService, getValue: () => this.getLockState(), requestUpdate: () => device.requestUpdate(), }); this.registerCharacteristic({ characteristicType: LockTargetState, serviceType: lockService, getValue: () => this.getLockState(), setValue: async (state) => { clearTimeout(this.unlockTimeout); if (state === LockTargetState.UNSECURED) { logInfo(`Unlocking ${device.name}`); this.unlocking = true; const response = await device.unlock().catch((e) => { logError(e); this.unlocking = false; }); logInfo(`Unlock response: ${JSON.stringify(response)}`); markAsUnlocked(); } else { // If the user locks the door from the home app, we can't do anything but set the states back to "locked" this.unlocking = false; lockService .getCharacteristic(Characteristic.LockCurrentState) .updateValue(this.getLockState()); } }, }); lockService.setPrimaryService(true); // Doorbell Service this.registerObservableCharacteristic({ characteristicType: ProgrammableSwitchEvent, serviceType: Service.Doorbell, onValue: onDoorbellPressed, }); // Programmable Switch Service this.registerObservableCharacteristic({ characteristicType: ProgrammableSwitchEvent, serviceType: programableSwitchService, onValue: onDoorbellPressed, }); // Hide long and double press events by setting max value programableSwitchService .getCharacteristic(ProgrammableSwitchEvent) .setProps({ maxValue: ProgrammableSwitchEvent.SINGLE_PRESS, }); // Battery Service if (device.batteryLevel !== null) { this.registerObservableCharacteristic({ characteristicType: Characteristic.BatteryLevel, serviceType: Service.Battery, onValue: device.onBatteryLevel.pipe(map((batteryLevel) => { return batteryLevel === null ? 100 : batteryLevel; })), requestUpdate: () => device.requestUpdate(), }); } // Accessory Information Service this.registerCharacteristic({ characteristicType: Characteristic.Manufacturer, serviceType: Service.AccessoryInformation, getValue: () => 'Ring', }); this.registerCharacteristic({ characteristicType: Characteristic.Model, serviceType: Service.AccessoryInformation, getValue: () => 'Intercom Handset Audio', }); this.registerCharacteristic({ characteristicType: Characteristic.SerialNumber, serviceType: Service.AccessoryInformation, getValue: (data) => data.device_id || 'Unknown', }); } getLockState() { const { Characteristic: { LockCurrentState: State }, } = hap; return this.unlocking ? State.UNSECURED : State.SECURED; } }