node-red-contrib-blebeacon-scanner
Version:
121 lines (110 loc) • 3.63 kB
JavaScript
/* ------------------------------------------------------------------
* node-beacon-scanner - parser.js
*
* Copyright (c) 2017-2018, Futomi Hatano, All rights reserved.
* Released under the MIT license
* Date: 2019-11-24
* ---------------------------------------------------------------- */
;
const mIbeacon = require('./parser-ibeacon.js');
const mEstimote = require('./parser-estimote.js');
const mEddystone = require('./parser-eddystone.js');
/* ------------------------------------------------------------------
* Constructor: EstimoteAdvertising()
* ---------------------------------------------------------------- */
const BeaconParser = function () {
// Private properties
this._ESTIMOTE_TELEMETRY_SERVICE_UUID = 'fe9a';
this._ESTIMOTE_COMPANY_ID = 0x015d;
this._EDDYSTONE_SERVICE_UUID = 'feaa';
};
/* ------------------------------------------------------------------
* Method: parse(peripheral)
* - peripheral: `Peripheral` object of the noble
* ---------------------------------------------------------------- */
BeaconParser.prototype.parse = function (peripheral) {
let ad = peripheral.advertisement;
let res = {
id: peripheral.id,
address: peripheral.address,
localName: ad.localName || null,
txPowerLevel: ad.txPowerLevel || null,
rssi: peripheral.rssi
};
let manu = ad.manufacturerData;
let beacon_type = this._detectBeaconType(peripheral);
res['beaconType'] = beacon_type;
let parsed = null;
// iBeacon
if (beacon_type === 'iBeacon') {
parsed = mIbeacon.parse(peripheral);
// Eddystone
} else if (beacon_type === 'eddystoneUid') {
parsed = mEddystone.parseUid(peripheral);
} else if (beacon_type === 'eddystoneUrl') {
parsed = mEddystone.parseUrl(peripheral);
} else if (beacon_type === 'eddystoneTlm') {
parsed = mEddystone.parseTlm(peripheral);
} else if (beacon_type === 'eddystoneEid') {
parsed = mEddystone.parseEid(peripheral);
// Estimote
} else if (beacon_type === 'estimoteTelemetry') {
parsed = mEstimote.parseTelemetry(peripheral);
} else if (beacon_type === 'estimoteNearable') {
parsed = mEstimote.parseNearable(peripheral);
} else if (beacon_type === 'other') {
parsed = manu;
}
if (parsed) {
res[beacon_type] = parsed;
return res;
} else {
return null;
}
};
BeaconParser.prototype._detectBeaconType = function (peripheral) {
let ad = peripheral.advertisement;
let manu = ad.manufacturerData;
// Eddiystone
if (ad.serviceData) {
let eddystone_service = ad.serviceData.find((el) => {
return el.uuid === this._EDDYSTONE_SERVICE_UUID;
});
if (eddystone_service && eddystone_service.data) {
// https://github.com/google/eddystone/blob/master/protocol-specification.md
let frame_type = eddystone_service.data.readUInt8(0) >>> 4;
if (frame_type === 0b0000) {
return 'eddystoneUid';
} else if (frame_type === 0b0001) {
return 'eddystoneUrl';
} else if (frame_type === 0b0010) {
return 'eddystoneTlm';
} else if (frame_type === 0b0011) {
return 'eddystoneEid';
}
}
}
// iBeacon
if (manu && manu.length >= 4 && manu.readUInt32BE(0) === 0x4c000215) {
return 'iBeacon';
}
// Estimote Telemetry
if (ad.serviceData) {
let telemetry_service = ad.serviceData.find((el) => {
return el.uuid === this._ESTIMOTE_TELEMETRY_SERVICE_UUID;
});
if (telemetry_service && telemetry_service.data) {
return 'estimoteTelemetry';
}
}
// Estimote Nearable
if (manu && manu.length >= 2 && manu.readUInt16LE(0) === this._ESTIMOTE_COMPANY_ID) {
return 'estimoteNearable';
}
if (manu) {
return 'other';
}
// Unknown
return '';
};
module.exports = new BeaconParser();