node-beacon-scanner-duplicates-check
Version:
The node-beacon-scanner is a Node.js module which allows you to scan BLE beacon packets and parse the packet data. This module supports iBeacon, Eddystone, and Estimote.
158 lines (143 loc) • 4.45 kB
JavaScript
/* ------------------------------------------------------------------
* node-beacon-scanner - scanner.js
*
* Copyright (c) 2017-2019, Futomi Hatano, All rights reserved.
* Released under the MIT license
* Date: 2019-10-25
* ---------------------------------------------------------------- */
'use strict';
const mBeaconParser = require('./parser.js');
/* ------------------------------------------------------------------
* Constructor: BeaconScanner(params)
* - params:
* noble : The Nobel object created by the noble module.
* This parameter is optional. If you don't specify
* this parameter, this module automatically creates it.
* ---------------------------------------------------------------- */
const BeaconScanner = function (params) {
// Plublic properties
this.noble = null;
if (params && 'noble' in params) {
if (typeof (params['noble']) === 'object') {
this.noble = params['noble'];
} else {
throw new Error('The value of the "noble" property is invalid.');
}
} else {
try {
this.noble = require('@abandonware/noble');
} catch (e) {
this.noble = require('noble');
}
}
this.onadvertisement = null;
// Private properties
this._initialized = false;
this._is_scanning = false;
this._beacons = {};
};
/* ------------------------------------------------------------------
* Method: stopScan()
* ---------------------------------------------------------------- */
BeaconScanner.prototype.stopScan = function () {
this.noble.removeAllListeners('discover');
this._beacons = {};
clearInterval(this._oldBeaconRemovalInterval);
if(this._is_scanning === true) {
this.noble.stopScanning();
this._is_scanning = false;
}
};
/* ------------------------------------------------------------------
* Method: startScan()
* ---------------------------------------------------------------- */
BeaconScanner.prototype.startScan = function(gracePeriod) {
let promise = new Promise((resolve, reject) => {
this._init().then(() => {
this._prepareScan();
}).then(() => {
resolve();
}).catch((error) => {
reject(error);
});
});
this._gracePeriod = gracePeriod;
this.noDuplicates = (gracePeriod > 0);
if (this.noDuplicates) {
this._oldBeaconRemovalInterval = setInterval(this.oldBeaconRemoval.bind(this), this._gracePeriod / 2);
} else {
if (this._oldBeaconRemovalInterval != null) {
clearInterval(this._oldBeaconRemovalInterval);
}
}
return promise;
};
BeaconScanner.prototype._prepareScan = function () {
let promise = new Promise((resolve, reject) => {
this.noble.startScanning([], true, (error) => {
if (error) {
reject(error);
} else {
this.noble.on('discover', (peripheral) => {
if (this.onadvertisement && typeof (this.onadvertisement) === 'function') {
let parsed = this.parse(peripheral);
if(parsed) {
parsed['lastSeen'] = Date.now();
if (this.noDuplicates) {
let id = parsed['id'];
if (parsed['beaconType'] === 'estimoteTelemetry') {
id = parsed['estimoteTelemetry']['telemetryId'];
}
let oldBeacon = this._beacons[id];
if (!oldBeacon) {
this.onadvertisement(parsed);
this._beacons[id] = parsed;
}
} else {
this.onadvertisement(parsed);
}
}
}
});
this._is_scanning = true;
resolve();
}
});
});
return promise;
};
BeaconScanner.prototype.oldBeaconRemoval = function() {
for (var id in this._beacons) {
if (this._beacons[id]['lastSeen'] < (Date.now() - this._gracePeriod)) {
delete this._beacons[id];
}
}
};
BeaconScanner.prototype._init = function() {
let promise = new Promise((resolve, reject) => {
this._initialized = false;
if (this.noble.state === 'poweredOn') {
this._initialized = true;
resolve();
} else {
this.noble.once('stateChange', (state) => {
if (state === 'poweredOn') {
this._initialized = true;
resolve();
} else {
let err = new Error('Failed to initialize the Noble object: ' + state);
reject(err);
}
});
}
});
return promise;
};
/* ------------------------------------------------------------------
* Method: parse(peripheral)
* - buf: `Peripheral` object of the noble)
* ---------------------------------------------------------------- */
BeaconScanner.prototype.parse = function (peripheral) {
return mBeaconParser.parse(peripheral);
};
module.exports = BeaconScanner;