diff --git a/CHANGELOG.md b/CHANGELOG.md index a0424f0..0199631 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to `@homebridge/hap-client` will be documented in this file. This project tries to adhere to [Semantic Versioning](http://semver.org/). +## v2.0.4 (2024-11-07) + +### Changed + +- Added public method destroy, to be used for testing +- Update public method monitorCharacteristics to allow passing of a filtered services array. + ## v2.0.2 (2024-08-31) ### Changed diff --git a/README.md b/README.md index ebf28f5..678aa38 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,14 @@ -A client for an insecure HAP-NodeJS instance. +A client for an insecure HAP-NodeJS instance. Provides a Typescript based interface based on the homekit accessory protocol, allowing the creation of clients able to connect to and control Homebridge devices. + +# Dependant Applications + +- homebridge-config-ui-x +- homebridge-gsh + +- [NPM Dependants](https://www.npmjs.com/package/@homebridge/hap-client?activeTab=dependents) ## Credits diff --git a/package-lock.json b/package-lock.json index 293e049..9712c67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@homebridge/hap-client", - "version": "2.0.2", + "version": "2.0.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@homebridge/hap-client", - "version": "2.0.2", + "version": "2.0.4", "license": "MIT", "dependencies": { "axios": "1.7.6", diff --git a/package.json b/package.json index 4c2cb51..952cd71 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@homebridge/hap-client", - "version": "2.0.2", + "version": "2.0.4", "description": "A client for HAP-NodeJS.", "main": "./dist/index.js", "scripts": { @@ -55,4 +55,4 @@ "ts-node": "^10.9.2", "typescript": "^5.5.4" } -} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 8cfd9c8..7c81742 100644 --- a/src/index.ts +++ b/src/index.ts @@ -37,6 +37,10 @@ export class HapClient extends EventEmitter { Characteristics.Name, ]; + private resetInstancePoolTimeout: NodeJS.Timeout | undefined = undefined; + private startDiscoveryTimeout: NodeJS.Timeout | undefined = undefined; + private hapMonitor: HapMonitor; + constructor(opts: { pin: string; logger?: any; @@ -57,6 +61,9 @@ export class HapClient extends EventEmitter { } } + /** + * resetInstancePool - Reset the instance pool, useful for when a Homebridge instance is restarted + */ public resetInstancePool() { if (this.discoveryInProgress) { this.browser.stop(); @@ -66,11 +73,14 @@ export class HapClient extends EventEmitter { this.instances = []; - setTimeout(() => { + this.resetInstancePoolTimeout = setTimeout(() => { this.refreshInstances(); }, 6000); } + /** + * refreshInstances - Refresh the instance pool + */ public refreshInstances() { if (!this.discoveryInProgress) { this.startDiscovery(); @@ -94,7 +104,7 @@ export class HapClient extends EventEmitter { this.debug(`[HapClient] Discovery :: Started`); // stop discovery after 20 seconds - setTimeout(() => { + this.startDiscoveryTimeout = setTimeout(() => { this.browser.stop(); this.debug(`[HapClient] Discovery :: Ended`); this.discoveryInProgress = false; @@ -225,11 +235,24 @@ export class HapClient extends EventEmitter { return accessories; } - public async monitorCharacteristics() { - const services = await this.getAllServices(); - return new HapMonitor(this.logger, this.debug.bind(this), this.pin, services); + /** + * monitorCharacteristics + * @param services - Optional array of services to monitor + * + * Creates connections to all Homebridge instances and monitors all characteristics for changes. Will emit `service-update` events when characteristics change, which can be listened to. + * @returns + */ + public async monitorCharacteristics(services?: ServiceType[]) { + // If `services` is not provided, retrieve all services + services = services ?? await this.getAllServices(); + this.hapMonitor = new HapMonitor(this.logger, this.debug.bind(this), this.pin, services); + return this.hapMonitor; } + /** + * + * @returns Array of all services from all Homebridge instances + */ public async getAllServices() { /* Get Accessories from HAP */ const accessories = await this.getAccessories(); @@ -447,4 +470,19 @@ export class HapClient extends EventEmitter { return titleize(decamelize(string)); } + /** + * Destroy the HAP client, used by testing when shutting down + */ + public async destroy() { + this.browser?.stop(); + this.hapMonitor?.finish(); + this.discoveryInProgress = false; + if (this.resetInstancePoolTimeout) { + clearTimeout(this.resetInstancePoolTimeout) + } + if (this.startDiscoveryTimeout) { + clearTimeout(this.startDiscoveryTimeout) + } + } + } diff --git a/src/interfaces.ts b/src/interfaces.ts index 79d4f60..30d69f2 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -20,12 +20,7 @@ export interface HapEvInstance { export interface HapAccessoriesRespType { accessories: Array<{ - instance: { - ipAddress: string; - port: number; - username: string; - name: string; - }; + instance: HapInstance; aid: number; services: Array<{ iid: number; @@ -75,12 +70,7 @@ export interface ServiceType { setCharacteristic?: (iid: number, value: number | string | boolean) => Promise; getCharacteristic?: (type: string) => CharacteristicType; values: any; - instance: { - ipAddress: string; - port: number; - username: string; - name: string; - }; + instance: HapInstance; uniqueId?: string; } diff --git a/src/monitor.ts b/src/monitor.ts index f384540..9015c7a 100644 --- a/src/monitor.ts +++ b/src/monitor.ts @@ -3,6 +3,9 @@ import { EventEmitter } from 'node:events'; import { ServiceType, HapEvInstance } from './interfaces'; import { createConnection, parseMessage } from './eventedHttpClient'; +/** + * HapMonitor - Creates a monitor to watch for changes in accessory characteristics. And generates 'service-update' events when they change. + */ export class HapMonitor extends EventEmitter { private pin; private evInstances: HapEvInstance[];