Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to support homebridge-gsh #13

Merged
merged 6 commits into from
Nov 8, 2024
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@

</span>

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

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down Expand Up @@ -55,4 +55,4 @@
"ts-node": "^10.9.2",
"typescript": "^5.5.4"
}
}
}
48 changes: 43 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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)
}
}

}
14 changes: 2 additions & 12 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -75,12 +70,7 @@ export interface ServiceType {
setCharacteristic?: (iid: number, value: number | string | boolean) => Promise<ServiceType>;
getCharacteristic?: (type: string) => CharacteristicType;
values: any;
instance: {
ipAddress: string;
port: number;
username: string;
name: string;
};
instance: HapInstance;
uniqueId?: string;
}

Expand Down
3 changes: 3 additions & 0 deletions src/monitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
Loading