homebridge-nest-accfactory
Version:
Homebridge support for Nest/Google devices including HomeKit Secure Video (HKSV) support for doorbells and cameras
121 lines (101 loc) • 5.14 kB
JavaScript
// Nest Doorbell(s)
// Part of homebridge-nest-accfactory
//
// Code version 2025/03/19
// Mark Hulskamp
'use strict';
// Define nodejs module requirements
import { setTimeout, clearTimeout } from 'node:timers';
// Define external module requirements
import NestCamera from './camera.js';
export default class NestDoorbell extends NestCamera {
doorbellTimer = undefined; // Cooldown timer for doorbell events
switchService = undefined; // HomeKit switch for enabling/disabling chime
constructor(accessory, api, log, eventEmitter, deviceData) {
super(accessory, api, log, eventEmitter, deviceData);
}
// Class functions
addServices() {
// Call parent to setup the common camera things. Once we return, we can add in the specifics for our doorbell
// We pass in the HAP Doorbell controller constructor function here also
let postSetupDetails = super.addServices(this.hap.DoorbellController);
this.switchService = this.accessory.getService(this.hap.Service.Switch);
if (this.deviceData.has_indoor_chime === true && this.deviceData.chimeSwitch === true) {
// Add service to allow automation and enabling/disabling indoor chiming.
// This needs to be explically enabled via a configuration option for the device
if (this.switchService === undefined) {
this.switchService = this.accessory.addService(this.hap.Service.Switch, '', 1);
}
// Setup set callback for this switch service
this.switchService.getCharacteristic(this.hap.Characteristic.On).onSet((value) => {
if (value !== this.deviceData.indoor_chime_enabled) {
// only change indoor chime status value if different than on-device
this.set({ uuid: this.deviceData.nest_google_uuid, indoor_chime_enabled: value });
this?.log?.info && this.log.info('Indoor chime on "%s" was turned', this.deviceData.description, value === true ? 'on' : 'off');
}
});
this.switchService.getCharacteristic(this.hap.Characteristic.On).onGet(() => {
return this.deviceData.indoor_chime_enabled === true;
});
}
if (this.switchService !== undefined && (this.deviceData.has_indoor_chime === false || this.deviceData.chimeSwitch === false)) {
// No longer required to have the switch service
// This is to handle Homebridge cached restored accessories and if configuration options have changed
this.accessory.removeService(this.switchService);
this.switchService = undefined;
}
// Create extra details for output
this.switchService !== undefined && postSetupDetails.push('Chime switch');
return postSetupDetails;
}
removeServices() {
super.removeServices();
clearTimeout(this.doorbellTimer);
this.doorbellTimer = undefined;
if (this.switchService !== undefined) {
this.accessory.removeService(this.switchService);
}
this.switchService = undefined;
}
updateServices(deviceData) {
if (typeof deviceData !== 'object' || this.controller === undefined) {
return;
}
// Get the camera class todo all its updates first, then we'll handle the doorbell specific stuff
super.updateServices(deviceData);
if (this.switchService !== undefined) {
// Update status of indoor chime enable/disable switch
this.switchService.updateCharacteristic(this.hap.Characteristic.On, deviceData.indoor_chime_enabled);
}
deviceData.alerts.forEach((event) => {
// Handle doorbell event, should always be handled first
if (event.types.includes('doorbell') === true && this.doorbellTimer === undefined) {
// Cooldown for doorbell button being pressed (filters out constant pressing for time period)
// Start this before we process further
this.doorbellTimer = setTimeout(() => {
this.doorbellTimer = undefined; // No doorbell timer active
}, this.deviceData.doorbellCooldown * 1000);
if (deviceData.indoor_chime_enabled === false || deviceData.quiet_time_enabled === true) {
// Indoor chime is disabled or quiet time is enabled, so we won't 'ring' the doorbell
this?.log?.warn && this.log.warn('Doorbell rung at "%s" but indoor chime is silenced', deviceData.description);
}
if (deviceData.indoor_chime_enabled === true && deviceData.quiet_time_enabled === false) {
// Indoor chime is enabled and quiet time isn't enabled, so 'ring' the doorbell
this?.log?.info && this.log.info('Doorbell rung at "%s"', deviceData.description);
this.controller.ringDoorbell();
}
if (this.controller?.doorbellService !== undefined && typeof this.historyService?.addHistory === 'function') {
// Record a doorbell press and unpress event to our history
this.historyService.addHistory(this.controller.doorbellService, {
time: Math.floor(Date.now() / 1000),
status: 1,
});
this.historyService.addHistory(this.controller.doorbellService, {
time: Math.floor(Date.now() / 1000),
status: 0,
});
}
}
});
}
}