Skip to content

homegraph/hap-controller

 
 

Repository files navigation

hap-controller

npm GitHub License

This library allows you to build a HomeKit controller, capable of discovering and controlling both Wi-Fi and BLE devices.

Installation

Use npm to install the package:

npm install hap-controller

# OR

yarn add hap-controller

Usage

The IP and BLE APIs are very similar and only differ where it makes sense, given protocol differences.

General notes about "concurrent requests"

Device Discovery

const {BLEDiscovery, IPDiscovery} = require('hap-controller');

const ipDiscovery = new IPDiscovery();
ipDiscovery.on('serviceUp', (service) => {
  // ...
});
ipDiscovery.start();

const bleDiscovery = new BLEDiscovery();
bleDiscovery.on('serviceUp', (service) => {
  // ...
});
bleDiscovery.start();  // pass true if disconnected events are needed

Identify

const {GattClient, HttpClient} = require('hap-controller');

const ipClient = new HttpClient(id, address, port);
ipClient.identify().then(() => {
  // ...
}).catch((e) => console.error(e));

const bleClient = new GattClient(id, peripheral);
bleClient.identify().then(() => {
  // ...
}).catch((e) => console.error(e));

Pair Setup

const {GattClient, HttpClient} = require('hap-controller');

const ipClient = new HttpClient(id, address, port);
ipClient.pairSetup(pin).then(() => {
  // keep this data
  console.log(JSON.stringify(ipClient.getLongTermData(), null, 2));
}).catch((e) => console.error(e));

const bleClient = new GattClient(id, peripheral);
bleClient.pairSetup(pin).then(() => {
  // keep this data
  console.log(JSON.stringify(bleClient.getLongTermData(), null, 2));
}).catch((e) => console.error(e));

Manage Pairings

const {GattClient, HttpClient} = require('hap-controller');

const ipClient = new HttpClient(id, address, port, pairingData);
ipClient.listPairings().then(() => {
  // ...
}).catch((e) => console.error(e));

ipClient.removePairing(identifier).then(() => {
  // ...
}).catch((e) => console.error(e));

const bleClient = new GattClient(id, peripheral, pairingData);
bleClient.listPairings().then(() => {
  // ...
}).catch((e) => console.error(e));

bleClient.removePairing(identifier).then(() => {
  // ...
}).catch((e) => console.error(e));

Accessory Database

const {GattClient, HttpClient} = require('hap-controller');

const ipClient = new HttpClient(id, address, port, pairingData);
ipClient.getAccessories().then((accessories) => {
  // ...
}).catch((e) => console.error(e));

const bleClient = new GattClient(id, peripheral, pairingData);
bleClient.getAccessories().then((accessories) => {
  // ...
}).catch((e) => console.error(e));

Get/Set Characteristics

const {GattClient, GattUtils, HttpClient} = require('hap-controller');

const ipClient = new HttpClient(id, address, port, pairingData);
ipClient.getCharacteristics(
  ['1.10'],
  {
    meta: true,
    perms: true,
    type: true,
    ev: true,
  }
).then((characteristics) => {
  // ...
}).catch((e) => console.error(e));

ipClient.setCharacteristics({'1.10': true}).then(() => {
  // ...
}).catch((e) => console.error(e));

const bleClient = new GattClient(id, peripheral, pairingData);
bleClient.getCharacteristics(
  [
    {
      serviceUuid: '...',         // the "type" property
      characteristicUuid: '...',  // the "type" property
      iid: 10,
      format: 'bool',             // if known
    },
  ],
  {
    meta: true,
    perms: true,
    type: true,
    ev: true,
  }
).then((characteristics) => {
  // ...
}).catch((e) => console.error(e));

bleClient.setCharacteristics(
  [
    {
      serviceUuid: '...',         // the "type" property
      characteristicUuid: '...',  // the "type" property
      iid: 10,
      value: GattUtils.valueToBuffer(true, 'bool'),
    },
  ]
).then(() => {
  // ...
}).catch((e) => console.error(e));

Subscribe/Unsubscribe Characteristics

const {GattClient, HttpClient} = require('hap-controller');

const ipClient = new HttpClient(id, address, port, pairingData);

ipClient.on('event', (ev) => {
  // ...
});

ipClient.on('event-disconnect', (subscribedList) => {
    // ...
});

let connection;
ipClient.subscribeCharacteristics(['1.10']).then((conn) => {
  connection = conn;
  // ...
}).catch((e) => console.error(e));

ipClient.unsubscribeCharacteristics(['1.10'], connection).then(() => {
  // ...
}).catch((e) => console.error(e));

const bleClient = new GattClient(id, peripheral, pairingData);

bleClient.on('event', (ev) => {
  // ...
});

bleClient.on('event-disconnect', (subscribedList) => {
    // ...
});

bleClient.subscribeCharacteristics(
  [
    {
      serviceUuid: '...',         // the "type" property
      characteristicUuid: '...',  // the "type" property
      iid: 10,
      format: 'bool',             // if known
    },
  ]
).then(() => {
  // ...
}).catch((e) => console.error(e));

bleClient.unsubscribeCharacteristics(
  [
    {
      serviceUuid: '...',         // the "type" property
      characteristicUuid: '...',  // the "type" property
    },
  ]
).then(() => {
  // ...
}).catch((e) => console.error(e));

Examples

Examples of all of the APIs can be found in the GitHub repo.

Contributing

Please feel free to open an issue or a pull request if you find something that could use improvement.

Changelog

WORK IN PROGRES

  • (Apollon77) check ble status before start a new scanning process
  • (Apollon77) remember that scanning was stoppen when stop() is called
  • (Apollon77) Fix pot. hanging response if multiple subscriptions are done on same device
  • (Apollon77) Prevent parallel pair verify calls by queuing them

0.6.1 (2021-10-18)

  • (Apollon77) move error class in own file and adjust some typings

0.6.0 (2021-10-17)

  • (Apollon77) Take over library (thanks to @mrstegeman for his great work so far and the ongoing consulting!)
  • (Apollon77) Add automatic detection for PairMethod to use based on discovery details (HTTP) or via extra method to read data from device (BLE)
  • (Apollon77) add getPairingMethod methods to the Client classes (as async for both because for BLE needs to be read from device while in Discovery response for IP devices, also adjust examples - so still not really "automatically resolved" but as method for the user to call and provide response to the pair method
  • (Apollon77) add debug lib and communication and tlv parsing/building logging
  • (Apollon77) add some convenient names to ble service definition to have same fields for "config version" ("c#") and "device id" ("id") for both service types
  • (Apollon77) add availableForPairing to both service objects and adjust the examples
  • (Apollon77) Adjust subscription handling for both transfers to keep the connection internally, so it is not returned anymore. Additionally the library keeps a list of all subscribed characteristics and will also check for duplicates
  • (Apollon77) The "disconnect" event is renamed to "event-disconnect" because it only notifies for disconnection of event subscriptions and returns the former list of subscribed characteristics as array that can directly be used to resubscribe
  • (Apollon77) Added "serviceChanged" events to both Discovery classes to be notified on changed advertisements - changed means that a relevant field of the service data has changed - mainly used to check GSN (for BLE) or "c#" (both)
  • (Apollon77) Added a "disconnect" and "connect" events to GattConnection to match HttpConnection
  • (Apollon77) Make sure getAccessories return UUIDs in all cases for HTTP and BLE
  • (Apollon77) enhance the perms returned from GattClient and add ev-connected, ev-disconnected and ev-broadcast if supported
  • (Apollon77) Define own Error class (HomekitControllerError) to transport enhanced info like statusCode and error body
  • (Apollon77) Allow also other properties to be set for the characteristic on write (like authData, remote and r)
  • (Apollon77) Update service and characteristic lists based on HapNodeJS because official specs are still from 2019
  • (Apollon77) adjustments to logic that was not working for me (mostly BLE things like flagging primary/hidden service in the data))
  • (Apollon77) smaller adjustments and restructuring of docs and type definitions

till 0.5.0 (16.08.2021)

Former versions published by @mrstegeman

About

Node.js library to implement a HAP (HomeKit) controller

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • TypeScript 93.6%
  • JavaScript 6.4%