Apollon77 / hap-controller-node

Node.js library to implement a HAP (HomeKit) controller
Mozilla Public License 2.0
55 stars 15 forks source link

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.

Troubleshooting

Known incompatible devices

If you have issues pairing the device with this adapter please try to pair it with the normal iOS Apple Home App. If this do not work then something is weird with the device and then also this adapter can not help. Pot try a reset, but else there is not chance.

This is currently that way for some Tado Door Locks as example. They need to be paired using the Tado App which is somehow registering the device into Apple Home, but not via an official pair process.

Additional also Nuki 3 Locks (BLE) are not possible to pair because they use Hardware Authentication components that are not publicly documented by Apple.

For Netatmo a user found out how pairing could be possible when it had issue. See https://github.com/Apollon77/ioBroker.homekit-controller/issues/233#issuecomment-1311983379

For BLE issues

General advices

Debugging

When you have issues and want to report an Issue (see below) then enhanced debug log is always helpful.

Please start your application using

DEBUG=hap* node myprocess.js

and post the console log also in the issue. This will generate a log on protocol level.

Contributing

Please feel free to open an issue or a pull request if you find something that could use improvement. For Issues please consider to directly provide debug loggins (see above).

Changelog

0.10.2 (2024-10-31)

0.10.1 (2023-11-23)

0.10.0 (2023-09-23)

0.9.3 (2023-02-27)

0.9.2 (2023-01-10)

0.9.1 (2023-01-10)

0.9.0 (2023-01-09)

0.8.4 (2023-01-05)

0.8.3 (2022-12-31)

0.8.2 (2022-12-22)

0.8.1 (2022-06-10)

0.8.0 (2022-06-10)

0.7.4 (2022-05-06)

0.7.2 (2022-01-25)

0.7.0 (2022-01-21)

0.6.1 (2021-10-18)

0.6.0 (2021-10-17)

till 0.5.0 (16.08.2021)

Former versions published by @mrstegeman