nubli
Version:
Nuki Bluetooth Library
158 lines (157 loc) • 6.23 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const noble_1 = __importDefault(require("noble"));
const smartLockPeripheralFilter_1 = require("./smartLockPeripheralFilter");
const smartLock_1 = require("./smartLock");
const events_1 = __importDefault(require("events"));
class Nubli extends events_1.default.EventEmitter {
constructor(peripheralFilter = new smartLockPeripheralFilter_1.SmartLockPeripheralFilter(), configPath) {
super();
this.noble = noble_1.default;
this.debugEnabled = false;
this._smartlocks = [];
this._configPath = "./config/";
this._scanning = false;
this.activeScanning = false;
this.peripheralFilter = peripheralFilter;
if (configPath) {
this._configPath = configPath;
}
// Override HCI so we can scan passively.
this.noble._bindings._hci.setScanParameters = () => {
var cmd = new Buffer(11);
let HCI_COMMAND_PKT = 0x01;
let OCF_LE_SET_SCAN_PARAMETERS = 0x000b;
let OGF_LE_CTL = 0x08;
let LE_SET_SCAN_PARAMETERS_CMD = OCF_LE_SET_SCAN_PARAMETERS | OGF_LE_CTL << 10;
// header
cmd.writeUInt8(HCI_COMMAND_PKT, 0);
cmd.writeUInt16LE(LE_SET_SCAN_PARAMETERS_CMD, 1);
// length
cmd.writeUInt8(0x07, 3);
if (this.activeScanning) {
cmd.writeUInt8(0x01, 4); // type: 0 -> passive, 1 -> active
}
else {
cmd.writeUInt8(0x00, 4); // type: 0 -> passive, 1 -> active
}
cmd.writeUInt16LE(0x0010, 5); // internal, ms * 1.6
cmd.writeUInt16LE(0x0010, 7); // window, ms * 1.6
cmd.writeUInt8(0x00, 9); // own address type: 0 -> public, 1 -> random
cmd.writeUInt8(0x00, 10); // filter: 0 -> all event types
this.noble._bindings._hci._socket.write(cmd);
};
this.noble.on('discover', (peripheral) => this.peripheralDiscovered(peripheral));
this.noble.on('stateChange', (state) => this.stateChange(state));
this.noble.on('scanStart', () => {
if (!this._scanning) {
this.emit("startedScanning");
this.debug("Started scanning");
}
this._scanning = true;
});
// When we connect to an peripheral, scanning will be stopped.
// This way we make sure to start scanning again after a short delay (500ms).
this.noble.on('scanStop', () => {
if (this._scanning) {
setTimeout(() => {
if (this._scanning) {
this.startScanning();
}
}, 500);
}
else {
this.emit("stoppedScanning");
this.debug("Stopped scanning");
}
});
}
setDebug(debugEnabled) {
this.debugEnabled = debugEnabled;
}
peripheralDiscovered(peripheral) {
for (let smartLock of this._smartlocks) {
if (peripheral.uuid == smartLock.uuid) {
if ("manufacturerData" in peripheral.advertisement && peripheral.advertisement.manufacturerData !== null
&& peripheral.advertisement.manufacturerData !== undefined) {
smartLock.updateManufacturerData(peripheral.advertisement.manufacturerData);
}
return;
}
}
if (!this.peripheralFilter.handle(peripheral))
return;
this.debug("Peripheral matched filter: " + peripheral.id + " - " + peripheral.advertisement.localName);
let smartLock = new smartLock_1.SmartLock(this, peripheral);
this._smartlocks.push(smartLock);
this.emit("smartLockDiscovered", smartLock);
}
get smartlocks() {
return this._smartlocks;
}
stateChange(state) {
this.debug("state change: " + state);
this.emit("state", state);
if (state == "poweredOn") {
this.emit("readyToScan");
}
}
debug(message) {
if (this.debugEnabled) {
console.log(new Date().toLocaleString(), message);
}
}
readyToScan() {
return this.noble.state == "poweredOn";
}
onReadyToScan(timeout = 10) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
if (this.readyToScan()) {
resolve();
}
else {
this.once('readyToScan', () => {
resolve();
});
}
setTimeout(() => {
reject('Adapter still not ready after ' + timeout + " seconds");
}, timeout * 1000);
});
});
}
startActiveScanning() {
this.activeScanning = true;
this.startScanning();
}
startScanning() {
if (!this.readyToScan()) {
throw new Error("Scanning only possible if the adapter is ready.");
}
this.noble.startScanning([], true);
}
stopScanning() {
this._scanning = false;
this.activeScanning = false;
this.noble.stopScanning();
}
get configPath() {
return this._configPath;
}
get scanning() {
return this._scanning;
}
}
exports.Nubli = Nubli;