import { Service, CharacteristicGetCallback, PlatformAccessory, } from "homebridge"; import { Monitor, IStateChangeEventArgs } from "./monitor/monitor"; import { HomeLocationPlatform } from "./homeLocationPlatform"; import { IRoom } from "./config"; const defaultDetectionTimeout = 180000; interface IMotionDetectionService { service: Service; detectionTimeout: NodeJS.Timeout | null; } /** * Platform Accessory * An instance of this class is created for each accessory your platform registers * Each accessory may expose multiple services of different service types. */ export class LocationAccessory { private _services: Array; constructor( private readonly _platform: HomeLocationPlatform, private readonly _accessory: PlatformAccessory, private _monitor: Monitor, private _room: IRoom ) { this._services = []; // set accessory information this._accessory .getService(this._platform.Service.AccessoryInformation)! .setCharacteristic( this._platform.Characteristic.Manufacturer, "Brandon Watson" ) .setCharacteristic( this._platform.Characteristic.Model, "Person Location Sensor" ) .setCharacteristic( this._platform.Characteristic.SerialNumber, "123-456-789" ); //Init motion services for (const label of this._monitor.labels) { const newService = this._accessory.getService(label) || this._accessory.addService( this._platform.Service.MotionSensor, label, this._room + label ); newService .getCharacteristic(this._platform.Characteristic.MotionDetected) .on("get", (callback: CharacteristicGetCallback) => this.onMotionDetectedGet(label, callback) ); this._services.push({ service: newService, detectionTimeout: null, }); } //Register monitor state change events this._monitor.stateChangedEvent.push(this.onMonitorStateChange.bind(this)); } private onMotionDetectedGet = ( label: string, callback: CharacteristicGetCallback ) => { this._platform.log.debug("Triggered GET MotionDetected"); // set this to a valid value for MotionDetected const currentValue = this._monitor.getState(label) === this._room.name ? 1 : 0; callback(null, currentValue); }; private onMonitorStateChange = ( sender: Monitor, args: IStateChangeEventArgs ) => { const motionService = this._services.find( (motionService) => motionService.service.displayName == args.label ); if (motionService) { //Set accessory state motionService.service.setCharacteristic( this._platform.Characteristic.MotionDetected, args.new === this._room.name ); //Reset detectionTimeout clearTimeout(motionService.detectionTimeout!); motionService.detectionTimeout = setTimeout( () => this.onDetectionTimeout(motionService), this._platform.config.detectionTimeout ?? defaultDetectionTimeout ); } }; private onDetectionTimeout = (motionService: IMotionDetectionService) => { //Set accessory state motionService.service.setCharacteristic( this._platform.Characteristic.MotionDetected, 0 ); this._monitor.resetState(motionService.service.displayName); }; }