Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,36 @@ 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 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.
It's also possible to stop the discovery process manually by calling `stopDiscovery()`
```
const { HapClient } = require('@homebridge/hap-client');

this.hapClient = new HapClient({
config: { debug: true, autoStartDiscovery: false, discoveryTimeout: 10000 },
pin: config.username,
logger: this.log,
});

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

```
Expand Down
48 changes: 39 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,25 @@ import 'source-map-support/register'

export * from './interfaces'

export interface Config {
debug?: boolean
instanceBlacklist?: string[]
discoveryTimeout?: number
autoStartDiscovery?: boolean
}

export class HapClient extends EventEmitter {
private bonjour = new Bonjour()
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[]
}
private config: Config

private instances: HapInstance[] = []

Expand All @@ -47,8 +54,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()
}
Comment thread
bwp91 marked this conversation as resolved.
Comment thread
bwp91 marked this conversation as resolved.
}

/**
Expand Down Expand Up @@ -114,9 +127,15 @@ export class HapClient extends EventEmitter {
}
}

private async startDiscovery() {
public startDiscovery(discoveryTimeout?: number) {
if (this.discoveryInProgress) {
this.warn(`[HapClient] Discovery :: Already in progress`)
return
}
this.discoveryInProgress = true

const timeout = discoveryTimeout ?? this.config.discoveryTimeout

this.browser = this.bonjour.find({
type: 'hap',
})
Expand All @@ -131,7 +150,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) => {
Expand Down Expand Up @@ -214,6 +233,17 @@ 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`)
Comment thread
bwp91 marked this conversation as resolved.
this.emit('discovery-stopped')
}

/**
* This checks the instance pin matches
*/
Expand Down Expand Up @@ -593,7 +623,7 @@ export class HapClient extends EventEmitter {
/**
* Destroy the HAP client, used by testing when shutting down
*/
public async destroy() {
public destroy() {
this.browser?.stop()
this.hapMonitor?.finish()
this.discoveryInProgress = false
Expand Down
Loading