From c7e3fb4c2fd0cbf57b103f8da1707ce0d14fd4fd Mon Sep 17 00:00:00 2001 From: Patrik Kovalovszky Date: Tue, 24 Feb 2026 17:02:17 +0100 Subject: [PATCH 1/7] feat: added more granular control for the discovery process --- CHANGELOG.md | 6 ++++++ README.md | 27 +++++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- src/index.ts | 21 +++++++++++++++++---- 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d337ad..2da6dc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to `@homebridge/hap-client` will be documented in this file. This project tries to adhere to [Semantic Versioning](http://semver.org/). +## v3.4.0 (2026-02-24) + +### Changed + +- more granular control for the discovery process + ## v3.3.0 (2026-02-14) ### Changed diff --git a/README.md b/README.md index 3b67738..ba35035 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,33 @@ this.hapClient = new HapClient({ this.monitor = await this.hapClient.monitorCharacteristics(services?: ServiceType[]); // Creates event monitors for all event capabable Homebridge services. If a list of services is, this list is used rather than all ``` +The discovery timeout can be configured by setting the `discoveryTimeout` property in the `config` object. +``` +const { HapClient } = require('@homebridge/hap-client'); + +this.hapClient = new HapClient({ + config: { debug: true, discoveryTimeout: 5000 }, + pin: config.username, + logger: this.log, +}); + +// the discovery process will auto-start now with the timout of 5 seconds +``` + +It's possible to control the discovery process manually, by settings the `autoStartDiscovery` property to `false` and then calling `this.hapClient.startDiscovery(discoveryTimeout?: number)` when ready. If no timeout is provided to the function, the `discoverTimeout` property will be used from the `config` object, and if that is not provided either, the default discovery timeout (60 seconds) will be used. +``` +const { HapClient } = require('@homebridge/hap-client'); + +this.hapClient = new HapClient({ + config: { debug: true, autoStartDiscovery: false, discoveryTimeout: 10000 }, + pin: config.username, + logger: this.log, +}); + +await this.hapClient.startDiscovery(); // use the timeout provided in the config, 10000 ms +await this.hapClient.startDiscovery(5000); // use the argument as timeout, 5000 ms +``` + ## hap-client Events ``` diff --git a/package-lock.json b/package-lock.json index 7b89522..6cf0f34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@homebridge/hap-client", - "version": "3.3.0", + "version": "3.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@homebridge/hap-client", - "version": "3.3.0", + "version": "3.4.0", "license": "MIT", "dependencies": { "axios": "1.13.5", diff --git a/package.json b/package.json index bec3d21..745aa10 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@homebridge/hap-client", - "version": "3.3.0", + "version": "3.4.0", "description": "A client for HAP-NodeJS.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/index.ts b/src/index.ts index dbfb287..ffb6a3c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,12 +21,17 @@ export class HapClient extends EventEmitter { private browser: Browser private discoveryInProgress = false + private readonly defaultDiscoveryTimeout: number = 60000 + private readonly defaultAutoStartDiscovery: boolean = true + private logger: any private pin: string private debugEnabled: boolean = false private config: { debug?: boolean instanceBlacklist?: string[] + discoveryTimeout: number + autoStartDiscovery: boolean } private instances: HapInstance[] = [] @@ -47,8 +52,14 @@ export class HapClient extends EventEmitter { this.pin = opts.pin this.logger = opts.logger || console // Fallback to console if no logger is provided this.debugEnabled = !!opts.config.debug - this.config = opts.config - this.startDiscovery() + this.config = { + ...opts.config, + discoveryTimeout: opts.config.discoveryTimeout ?? this.defaultDiscoveryTimeout, + autoStartDiscovery: opts.config.autoStartDiscovery ?? this.defaultAutoStartDiscovery, + } + if (this.config.autoStartDiscovery) { + this.startDiscovery() + } } /** @@ -114,9 +125,11 @@ export class HapClient extends EventEmitter { } } - private async startDiscovery() { + public async startDiscovery(discoveryTimeout?: number) { this.discoveryInProgress = true + const timeout = discoveryTimeout ?? this.config.discoveryTimeout + this.browser = this.bonjour.find({ type: 'hap', }) @@ -131,7 +144,7 @@ export class HapClient extends EventEmitter { this.debug(`[HapClient] Discovery :: Ended`) this.discoveryInProgress = false this.emit('discovery-ended') - }, 60000) + }, timeout) // service found this.browser.on('up', async (device: Service) => { From afea82f73daad6fdc437690d7a444217c8c0f34e Mon Sep 17 00:00:00 2001 From: Kovalovszky Patrik Date: Tue, 24 Feb 2026 19:28:25 +0100 Subject: [PATCH 2/7] Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ba35035..d1298ce 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ this.hapClient = new HapClient({ // the discovery process will auto-start now with the timout of 5 seconds ``` -It's possible to control the discovery process manually, by settings the `autoStartDiscovery` property to `false` and then calling `this.hapClient.startDiscovery(discoveryTimeout?: number)` when ready. If no timeout is provided to the function, the `discoverTimeout` property will be used from the `config` object, and if that is not provided either, the default discovery timeout (60 seconds) will be used. +It's possible to control the discovery process manually, by settings the `autoStartDiscovery` property to `false` and then calling `this.hapClient.startDiscovery(discoveryTimeout?: number)` when ready. If no timeout is provided to the function, the `discoveryTimeout` property will be used from the `config` object, and if that is not provided either, the default discovery timeout (60 seconds) will be used. ``` const { HapClient } = require('@homebridge/hap-client'); From df499916ab2cc39263cfb2d1c2393cd73a8516eb Mon Sep 17 00:00:00 2001 From: Patrik Kovalovszky Date: Tue, 24 Feb 2026 19:48:24 +0100 Subject: [PATCH 3/7] chore: revert version bump --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6cf0f34..7b89522 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@homebridge/hap-client", - "version": "3.4.0", + "version": "3.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@homebridge/hap-client", - "version": "3.4.0", + "version": "3.3.0", "license": "MIT", "dependencies": { "axios": "1.13.5", diff --git a/package.json b/package.json index 745aa10..bec3d21 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@homebridge/hap-client", - "version": "3.4.0", + "version": "3.3.0", "description": "A client for HAP-NodeJS.", "main": "dist/index.js", "types": "dist/index.d.ts", From 547fd7e1f626a54a50bd721db5f182b74cd8b6e8 Mon Sep 17 00:00:00 2001 From: Kovalovszky Patrik Date: Wed, 25 Feb 2026 08:54:32 +0100 Subject: [PATCH 4/7] chore: fix typo in readme Co-authored-by: Ben <43026681+bwp91@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d1298ce..ba53beb 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ this.hapClient = new HapClient({ logger: this.log, }); -// the discovery process will auto-start now with the timout of 5 seconds +// the discovery process will auto-start now with the timeout of 5 seconds ``` It's possible to control the discovery process manually, by settings the `autoStartDiscovery` property to `false` and then calling `this.hapClient.startDiscovery(discoveryTimeout?: number)` when ready. If no timeout is provided to the function, the `discoveryTimeout` property will be used from the `config` object, and if that is not provided either, the default discovery timeout (60 seconds) will be used. From ed1a160e4508f73e4c12d10656e53eee86993e4e Mon Sep 17 00:00:00 2001 From: Patrik Kovalovszky Date: Wed, 25 Feb 2026 20:11:08 +0100 Subject: [PATCH 5/7] fix: created type for config, destroying if discovery already in progress, deleted async keywords --- src/index.ts | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/index.ts b/src/index.ts index ffb6a3c..3bbde45 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,13 @@ import 'source-map-support/register' export * from './interfaces' +export type Config = { + debug?: boolean + instanceBlacklist?: string[] + discoveryTimeout: number + autoStartDiscovery: boolean +} + export class HapClient extends EventEmitter { private bonjour = new Bonjour() private browser: Browser @@ -27,12 +34,7 @@ export class HapClient extends EventEmitter { private logger: any private pin: string private debugEnabled: boolean = false - private config: { - debug?: boolean - instanceBlacklist?: string[] - discoveryTimeout: number - autoStartDiscovery: boolean - } + private config: Config private instances: HapInstance[] = [] @@ -125,7 +127,11 @@ export class HapClient extends EventEmitter { } } - public async startDiscovery(discoveryTimeout?: number) { + public startDiscovery(discoveryTimeout?: number) { + if (this.discoveryInProgress) { + this.debug(`[HapClient] Discovery :: Already in progress, destroying`) + this.destroy() + } this.discoveryInProgress = true const timeout = discoveryTimeout ?? this.config.discoveryTimeout @@ -604,9 +610,11 @@ export class HapClient extends EventEmitter { } /** - * Destroy the HAP client, used by testing when shutting down + * Destroy the HAP client + * Used in `startDiscovery` if there is a discovery already in progress + * And in tests */ - public async destroy() { + public destroy() { this.browser?.stop() this.hapMonitor?.finish() this.discoveryInProgress = false From 7298ed12b5f57d8281f9323132c0025f0d01fb7e Mon Sep 17 00:00:00 2001 From: Patrik Kovalovszky Date: Wed, 25 Feb 2026 22:15:12 +0100 Subject: [PATCH 6/7] fix: early return in startDiscovery if discovery already in progress, stopDiscovery method --- README.md | 7 +++++-- src/index.ts | 22 +++++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ba53beb..e6cb3a1 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ this.hapClient = new HapClient({ ``` It's possible to control the discovery process manually, by settings the `autoStartDiscovery` property to `false` and then calling `this.hapClient.startDiscovery(discoveryTimeout?: number)` when ready. If no timeout is provided to the function, the `discoveryTimeout` property will be used from the `config` object, and if that is not provided either, the default discovery timeout (60 seconds) will be used. +It's also possible to stop the discovery process manually by calling `stopDiscovery()` ``` const { HapClient } = require('@homebridge/hap-client'); @@ -50,8 +51,10 @@ this.hapClient = new HapClient({ logger: this.log, }); -await this.hapClient.startDiscovery(); // use the timeout provided in the config, 10000 ms -await this.hapClient.startDiscovery(5000); // use the argument as timeout, 5000 ms +this.hapClient.startDiscovery(); // use the timeout provided in the config, 10000 ms +this.hapClient.startDiscovery(5000); // use the argument as timeout, 5000 ms + +this.hapClient.stopDiscovery(); // stop the discovery process manually ``` ## hap-client Events diff --git a/src/index.ts b/src/index.ts index 3bbde45..8b93fde 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,8 +19,8 @@ export * from './interfaces' export type Config = { debug?: boolean instanceBlacklist?: string[] - discoveryTimeout: number - autoStartDiscovery: boolean + discoveryTimeout?: number + autoStartDiscovery?: boolean } export class HapClient extends EventEmitter { @@ -129,8 +129,8 @@ export class HapClient extends EventEmitter { public startDiscovery(discoveryTimeout?: number) { if (this.discoveryInProgress) { - this.debug(`[HapClient] Discovery :: Already in progress, destroying`) - this.destroy() + this.warn(`[HapClient] Discovery :: Already in progress`) + return } this.discoveryInProgress = true @@ -233,6 +233,16 @@ export class HapClient extends EventEmitter { }) } + public stopDiscovery() { + this.discoveryInProgress = false + this.browser?.stop() + if (this.startDiscoveryTimeout) { + clearTimeout(this.startDiscoveryTimeout) + this.startDiscoveryTimeout = undefined + } + this.debug(`[HapClient] Discovery :: Stopped`) + } + /** * This checks the instance pin matches */ @@ -610,9 +620,7 @@ export class HapClient extends EventEmitter { } /** - * Destroy the HAP client - * Used in `startDiscovery` if there is a discovery already in progress - * And in tests + * Destroy the HAP client, used by testing when shutting down */ public destroy() { this.browser?.stop() From aa586b0086b6a8579263133ec7baad30f4356c7e Mon Sep 17 00:00:00 2001 From: Patrik Kovalovszky Date: Thu, 26 Feb 2026 08:39:18 +0100 Subject: [PATCH 7/7] fix: use interface, emit event when discovery stopped --- src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 8b93fde..6c74d6e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,7 +16,7 @@ import 'source-map-support/register' export * from './interfaces' -export type Config = { +export interface Config { debug?: boolean instanceBlacklist?: string[] discoveryTimeout?: number @@ -241,6 +241,7 @@ export class HapClient extends EventEmitter { this.startDiscoveryTimeout = undefined } this.debug(`[HapClient] Discovery :: Stopped`) + this.emit('discovery-stopped') } /**