diff --git a/examples/fatBeacon/index.html b/examples/fatBeacon/index.html new file mode 100644 index 0000000..3ab5790 --- /dev/null +++ b/examples/fatBeacon/index.html @@ -0,0 +1,11 @@ + + + Fat Beacon Demo + + + + +

HelloWorld

+ + + \ No newline at end of file diff --git a/examples/fatBeacon/simple.js b/examples/fatBeacon/simple.js new file mode 100644 index 0000000..4f3239b --- /dev/null +++ b/examples/fatBeacon/simple.js @@ -0,0 +1,12 @@ +// Simplest way to create a Eddystone-FatBeacon + +// might want to include something like this https://www.npmjs.com/package/html-minify + +var eddystoneBeacon = require('./../../index'); +var fs = require('fs'); + +fs.readFile('index.html', function(err, data){ + if (!err) { + eddystoneBeacon.advertiseFatBeacon('Fat Beacon Demo', {html: data}); + } +}); diff --git a/lib/HTMLCharacteristic.js b/lib/HTMLCharacteristic.js new file mode 100644 index 0000000..4c63bc5 --- /dev/null +++ b/lib/HTMLCharacteristic.js @@ -0,0 +1,60 @@ +/** +* Copyright 2016 IBM Corp. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +**/ +var bleno = require('bleno'); +var util = require('util'); + +function HTMLCharacteristic(html) { + this._currentMTU = 0; + this._queueOffset = 0; + this._html = html; + this._buffer = new Buffer(this._html, 'utf8'); + bleno.Characteristic.call(this, { + uuid: 'd1a517f0249946ca9ccc809bc1c966fa', + properties: ['read'], + descriptors: [ + new bleno.Descriptor({ + uuid: '2901', + value: 'HTML' + }) + ] + }); + + bleno.on('mtuChange', function(mtu) { + this._currentMTU = mtu; + }.bind(this)); + + bleno.on('disconnect', function(){ + this._queueOffset = 0; + }.bind(this)); +} + +util.inherits(HTMLCharacteristic,bleno.Characteristic); + +HTMLCharacteristic.prototype.onReadRequest = function(offset, callback) { + if (this._queueOffset < this._buffer.length) { + var transfer = this._currentMTU - 5; + var end = this._queueOffset + transfer >= this._buffer.length ? this._buffer.length: this._queueOffset + transfer; + var slice = this._buffer.slice(this._queueOffset, end); + callback(this.RESULT_SUCCESS, slice); + this._queueOffset = end; + } else if (this._queueOffset === this._buffer.length) { + callback(this.RESULT_SUCCESS, new Buffer()); + this._queueOffset++; + } + +} + +module.exports = HTMLCharacteristic; diff --git a/lib/beacon.js b/lib/beacon.js index 5df8193..6483946 100644 --- a/lib/beacon.js +++ b/lib/beacon.js @@ -4,6 +4,8 @@ var bleno = require('bleno'); var AdvertisementData = require('./util/advertisement-data'); +var HTMLCharacteristic = require('./HTMLCharacteristic'); + var TICK_INTERVAL = 100; // ms var DEFAULT_TX_POWER_LEVEL = -21; // dBm @@ -19,6 +21,7 @@ function Beacon() { this._temperature = -128; this._secCnt = 0; this._advCnt = 0; + this._html = null; setInterval(this._tick.bind(this), TICK_INTERVAL); } @@ -45,6 +48,38 @@ Beacon.prototype.advertiseUrl = function(url, options) { this._advertiseWhenPoweredOn(); }; +Beacon.prototype.advertiseFatBeacon = function(title, options) { + + this._parseOptions(options); + + var htmlCharacteristic = new HTMLCharacteristic(this._html); + var fatBeaconService = new bleno.PrimaryService({ + uuid: 'ae5946d4e5874ba8b6a5a97cca6affd3', + characteristics: [htmlCharacteristic] + }); + + var services = [fatBeaconService]; + + if (options.services) { + services = services.concat(options.services); + } + + bleno.once('advertisingStart', function(err) { + if (err) { + throw err; + } + + bleno.setServices(services); + }); + + this._advertisementData = AdvertisementData.makeFatBeaconBuffer(title, this._txPowerLevel); + this._removeFlagsIfOsX(); + + this._mainAdvertisementData = this._advertisementData; + + this._advertiseWhenPoweredOn(); +}; + Beacon.prototype.advertiseTlm = function() { this._advertisementData = AdvertisementData.makeTlmBuffer(this._batteryVoltage, this._temperature, this._advCnt, this._secCnt); @@ -76,6 +111,13 @@ Beacon.prototype._parseOptions = function(options) { this._parseTxPowerLevelOption(options.txPowerLevel); this._parseTlmOptions(options); this._parseNameOption(options.name); + this._parseFatBeaconOption(options.html); +}; + +Beacon.prototype._parseFatBeaconOption = function(html) { + if (html) { + this._html = html; + } }; Beacon.prototype._parseNameOption = function(name) { diff --git a/lib/util/advertisement-data.js b/lib/util/advertisement-data.js index f541224..f6c453d 100644 --- a/lib/util/advertisement-data.js +++ b/lib/util/advertisement-data.js @@ -52,6 +52,19 @@ var makeUrlBuffer = function (url, txPowerLevel) { return makeEddystoneBuffer(URL_FRAME_TYPE, data); }; +var makeFatBeaconBuffer = function (title, txPowerLevel) { + var txPowerLevelData = makeTxPowerLevelBuffer(txPowerLevel); + + var data = Buffer.concat([ + txPowerLevelData, + new Buffer([0x0E]), + new Buffer(title) + ]); + + return makeEddystoneBuffer(URL_FRAME_TYPE, data); +}; + + var makeTlmBuffer = function (vBatt, temp, advCnt, secCnt) { var tlmData = new Buffer(13); @@ -99,5 +112,6 @@ var hexStringIdToBuffer = function(hexStringId) { module.exports = { makeUidBuffer: makeUidBuffer, makeUrlBuffer: makeUrlBuffer, - makeTlmBuffer: makeTlmBuffer + makeTlmBuffer: makeTlmBuffer, + makeFatBeaconBuffer: makeFatBeaconBuffer };