diff --git a/libs/bleat/VERSION b/libs/bleat/VERSION index ceddb63..d4492aa 100644 --- a/libs/bleat/VERSION +++ b/libs/bleat/VERSION @@ -1,2 +1,2 @@ -Bleat version 2016-03-08 commit 436c24c6e93874b595f430779506bc50770af21a +Bleat version 2016-03-09 commit 66a9910dd8171824f5d2408f5f5fac60e646f0a6 https://github.com/thegecko/bleat diff --git a/libs/bleat/api.web-bluetooth.js b/libs/bleat/api.web-bluetooth.js index 056ea74..e32384b 100644 --- a/libs/bleat/api.web-bluetooth.js +++ b/libs/bleat/api.web-bluetooth.js @@ -73,6 +73,30 @@ } } + var events = {}; + function createListenerFn(eventTypes) { + return function(type, callback, capture) { + if (eventTypes.indexOf(type) < 0) return; //error + if (!events[this]) events[this] = {}; + if (!events[this][type]) events[this][type] = []; + events[this][type].push(callback); + }; + } + function removeEventListener(type, callback, capture) { + if (!events[this] || !events[this][type]) return; //error + var i = events[this][type].indexOf(callback); + if (i >= 0) events[this][type].splice(i, 1); + if (events[this][type].length === 0) delete events[this][type]; + if (Object.keys(events[this]).length === 0) delete events[this]; + } + function dispatchEvent(event) { + if (!events[this] || !events[this][event.type]) return; //error + event.target = this; + events[this][event.type].forEach(function(callback) { + if (typeof callback === "function") callback(event); + }); + } + function filterDevice(options, deviceInfo) { var valid = false; var validServices = []; @@ -116,76 +140,80 @@ return deviceInfo; } - function scan(options, foundFn, completeFn, errorFn) { - // Must have a filter - if (!options.filters || options.filters.length === 0) { - return errorFn("no filters specified"); - } + var scanner = null; + function requestDevice(options) { + return new Promise(function(resolve, reject) { + if (scanner !== null) return reject("requestDevice error: request in progress"); - // Don't allow empty filters - var emptyFilter = options.filters.some(function(filter) { - return (Object.keys(filter).length === 0); - }); - if (emptyFilter) { - return errorFn("empty filter specified"); - } + if (!options.deviceFound) { + // Must have a filter + if (!options.filters || options.filters.length === 0) { + return reject(new TypeError("requestDevice error: no filters specified")); + } - // Don't allow empty namePrefix - var emptyPrefix = options.filters.some(function(filter) { - return (typeof filter.namePrefix !== "undefined" && filter.namePrefix === ""); - }); - if (emptyPrefix) { - return errorFn("empty namePrefix specified"); - } + // Don't allow empty filters + var emptyFilter = options.filters.some(function(filter) { + return (Object.keys(filter).length === 0); + }); + if (emptyFilter) { + return reject(new TypeError("requestDevice error: empty filter specified")); + } - var searchUUIDs = []; - if (options.filters) { - options.filters.forEach(function(filter) { - if (filter.services) searchUUIDs = searchUUIDs.concat(filter.services.map(helpers.getServiceUUID)); - }); - } - // Unique-ify - searchUUIDs = searchUUIDs.filter(function(item, index, array) { - return array.indexOf(item) === index; - }); + // Don't allow empty namePrefix + var emptyPrefix = options.filters.some(function(filter) { + return (typeof filter.namePrefix !== "undefined" && filter.namePrefix === ""); + }); + if (emptyPrefix) { + return reject(new TypeError("requestDevice error: empty namePrefix specified")); + } + } - var scanTime = options.scanTime || defaultScanTime; - var scanTimeout; - adapter.startScan(searchUUIDs, function(deviceInfo) { - deviceInfo = filterDevice(options, deviceInfo); - if (deviceInfo) foundFn(deviceInfo, scanTimeout); - }, function() { - scanTimeout = setTimeout(function() { - adapter.stopScan(); - completeFn(); - }, scanTime); - }, errorFn); - } + var searchUUIDs = []; + if (options.filters) { + options.filters.forEach(function(filter) { + if (filter.services) searchUUIDs = searchUUIDs.concat(filter.services.map(helpers.getServiceUUID)); + }); + } + // Unique-ify + searchUUIDs = searchUUIDs.filter(function(item, index, array) { + return array.indexOf(item) === index; + }); - var events = {}; + var scanTime = options.scanTime || defaultScanTime; + var completeFn = options.deviceFound ? resolve : function() { + reject("requestDevice error: no devices found"); + }; - function createListenerFn(eventTypes) { - return function(type, callback, capture) { - if (eventTypes.indexOf(type) < 0) return; //error - if (!events[this]) events[this] = {}; - if (!events[this][type]) events[this][type] = []; - events[this][type].push(callback); - }; - } + adapter.startScan(searchUUIDs, function(deviceInfo) { + if (!options.deviceFound) { + deviceInfo = filterDevice(options, deviceInfo); + } - function removeEventListener(type, callback, capture) { - if (!events[this] || !events[this][type]) return; //error - var i = events[this][type].indexOf(callback); - if (i >= 0) events[this][type].splice(i, 1); - if (events[this][type].length === 0) delete events[this][type]; - if (Object.keys(events[this]).length === 0) delete events[this]; + if (deviceInfo) { + var bluetoothDevice = new BluetoothDevice(deviceInfo); + if (!options.deviceFound || options.deviceFound(bluetoothDevice)) { + cancelRequest() + .then(function() { + resolve(bluetoothDevice); + }); + } + } + }, function() { + scanner = setTimeout(function() { + cancelRequest() + .then(completeFn); + }, scanTime); + }, wrapReject(reject, "requestDevice error")); + }); } - - function dispatchEvent(event) { - if (!events[this] || !events[this][event.type]) return; //error - event.target = this; - events[this][event.type].forEach(function(callback) { - if (typeof callback === "function") callback(event); + function cancelRequest() { + return new Promise(function(resolve, reject) { + if (scanner) { + clearTimeout(scanner); + scanner = null; + adapter.stopScan(); + } + resolve(); }); } @@ -229,6 +257,8 @@ }; BluetoothRemoteGATTServer.prototype.connect = function() { return new Promise(function(resolve, reject) { + if (this.connected) return reject("connect error: device already connected"); + adapter.connect(this.device._handle, function() { this.connected = true; resolve(this); @@ -244,7 +274,9 @@ }; BluetoothRemoteGATTServer.prototype.getPrimaryService = function(serviceUUID) { return new Promise(function(resolve, reject) { + if (!this.connected) return reject("getPrimaryService error: device not connected"); if (!serviceUUID) return reject("getPrimaryService error: no service specified"); + this.getPrimaryServices(serviceUUID) .then(function(services) { if (services.length !== 1) return reject("getPrimaryService error: service not found"); @@ -257,6 +289,8 @@ }; BluetoothRemoteGATTServer.prototype.getPrimaryServices = function(serviceUUID) { return new Promise(function(resolve, reject) { + if (!this.connected) return reject("getPrimaryServices error: device not connected"); + function complete() { if (!serviceUUID) return resolve(this._services); var filtered = this._services.filter(function(service) { @@ -291,7 +325,9 @@ }; BluetoothRemoteGATTService.prototype.getCharacteristic = function(characteristicUUID) { return new Promise(function(resolve, reject) { + if (!this.device.gatt.connected) return reject("getCharacteristic error: device not connected"); if (!characteristicUUID) return reject("getCharacteristic error: no characteristic specified"); + this.getCharacteristics(characteristicUUID) .then(function(characteristics) { if (characteristics.length !== 1) return reject("getCharacteristic error: characteristic not found"); @@ -304,6 +340,8 @@ }; BluetoothRemoteGATTService.prototype.getCharacteristics = function(characteristicUUID) { return new Promise(function(resolve, reject) { + if (!this.device.gatt.connected) return reject("getCharacteristics error: device not connected"); + function complete() { if (!characteristicUUID) return resolve(this._characteristics); var filtered = this._characteristics.filter(function(characteristic) { @@ -324,7 +362,9 @@ }; BluetoothRemoteGATTService.prototype.getIncludedService = function(serviceUUID) { return new Promise(function(resolve, reject) { + if (!this.device.gatt.connected) return reject("getIncludedService error: device not connected"); if (!serviceUUID) return reject("getIncludedService error: no service specified"); + this.getIncludedServices(serviceUUID) .then(function(services) { if (services.length !== 1) return reject("getIncludedService error: service not found"); @@ -337,6 +377,8 @@ }; BluetoothRemoteGATTService.prototype.getIncludedServices = function(serviceUUID) { return new Promise(function(resolve, reject) { + if (!this.device.gatt.connected) return reject("getIncludedServices error: device not connected"); + function complete() { if (!serviceUUID) return resolve(this._services); var filtered = this._services.filter(function(service) { @@ -387,7 +429,9 @@ }; BluetoothRemoteGATTCharacteristic.prototype.getDescriptor = function(descriptorUUID) { return new Promise(function(resolve, reject) { + if (!this.service.device.gatt.connected) return reject("getDescriptor error: device not connected"); if (!descriptorUUID) return reject("getDescriptor error: no descriptor specified"); + this.getDescriptors(descriptorUUID) .then(function(descriptors) { if (descriptors.length !== 1) return reject("getDescriptor error: descriptor not found"); @@ -400,6 +444,8 @@ }; BluetoothRemoteGATTCharacteristic.prototype.getDescriptors = function(descriptorUUID) { return new Promise(function(resolve, reject) { + if (!this.service.device.gatt.connected) return reject("getDescriptors error: device not connected"); + function complete() { if (!descriptorUUID) return resolve(this._descriptors); var filtered = this._descriptors.filter(function(descriptor) { @@ -420,6 +466,8 @@ }; BluetoothRemoteGATTCharacteristic.prototype.readValue = function() { return new Promise(function(resolve, reject) { + if (!this.service.device.gatt.connected) return reject("readValue error: device not connected"); + adapter.readCharacteristic(this._handle, function(dataView) { this.value = dataView; resolve(dataView); @@ -428,9 +476,11 @@ }.bind(this)); }; BluetoothRemoteGATTCharacteristic.prototype.writeValue = function(bufferSource) { - var arrayBuffer = bufferSource.buffer || bufferSource; - var dataView = new DataView(arrayBuffer); return new Promise(function(resolve, reject) { + if (!this.service.device.gatt.connected) return reject("writeValue error: device not connected"); + + var arrayBuffer = bufferSource.buffer || bufferSource; + var dataView = new DataView(arrayBuffer); adapter.writeCharacteristic(this._handle, dataView, function() { this.value = dataView; resolve(); @@ -439,6 +489,8 @@ }; BluetoothRemoteGATTCharacteristic.prototype.startNotifications = function() { return new Promise(function(resolve, reject) { + if (!this.service.device.gatt.connected) return reject("startNotifications error: device not connected"); + adapter.enableNotify(this._handle, function(dataView) { this.value = dataView; this.dispatchEvent({ type: "characteristicvaluechanged", bubbles: true }); @@ -447,6 +499,8 @@ }; BluetoothRemoteGATTCharacteristic.prototype.stopNotifications = function() { return new Promise(function(resolve, reject) { + if (!this.service.device.gatt.connected) return reject("stopNotifications error: device not connected"); + adapter.disableNotify(this._handle, resolve, wrapReject(reject, "stopNotifications error")); }.bind(this)); }; @@ -468,6 +522,8 @@ }; BluetoothRemoteGATTDescriptor.prototype.readValue = function() { return new Promise(function(resolve, reject) { + if (!this.characteristic.service.device.gatt.connected) return reject("readValue error: device not connected"); + adapter.readDescriptor(this._handle, function(dataView) { this.value = dataView; resolve(dataView); @@ -475,9 +531,11 @@ }.bind(this)); }; BluetoothRemoteGATTDescriptor.prototype.writeValue = function(bufferSource) { - var arrayBuffer = bufferSource.buffer || bufferSource; - var dataView = new DataView(arrayBuffer); return new Promise(function(resolve, reject) { + if (!this.characteristic.service.device.gatt.connected) return reject("writeValue error: device not connected"); + + var arrayBuffer = bufferSource.buffer || bufferSource; + var dataView = new DataView(arrayBuffer); adapter.writeDescriptor(this._handle, dataView, function() { this.value = dataView; resolve(); @@ -491,29 +549,7 @@ adapters[adapterName] = definition; adapter = definition; }, - requestDevice: function(options) { - return new Promise(function(resolve, reject) { - scan(options, function(deviceInfo, scanTimeout) { - if (scanTimeout) clearTimeout(scanTimeout); - adapter.stopScan(); - resolve(new BluetoothDevice(deviceInfo)); - }, function() { - reject("requestDevice error: no devices found"); - }, wrapReject(reject, "requestDevice error")); - }); - }, - requestDevices: function(options) { - return new Promise(function(resolve, reject) { - var devices = []; - scan(options, function(deviceInfo) { - devices.push(deviceInfo); - }, function() { - if (devices.length === 0) reject("requestDevices error: no devices found"); - else resolve(devices.map(function(deviceInfo) { - return new BluetoothDevice(deviceInfo); - })); - }, wrapReject(reject, "requestDevices error")); - }); - } + requestDevice: requestDevice, + cancelRequest: cancelRequest }; })); \ No newline at end of file diff --git a/libs/bleat/web-bluetooth.evothings.min.js b/libs/bleat/web-bluetooth.evothings.min.js index f053be4..41a0df8 100644 --- a/libs/bleat/web-bluetooth.evothings.min.js +++ b/libs/bleat/web-bluetooth.evothings.min.js @@ -52,4 +52,4 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -function(a,b){"function"==typeof define&&define.amd?a.navigator.bluetooth?define(a.navigator.bluetooth):define(["es6-promise","es6-map","bluetooth.helpers"],b):"object"==typeof exports?module.exports=b(Promise,Map,require("./bluetooth.helpers")):a.bleat=a.navigator.bluetooth||b(a.Promise,a.Map,a.bleatHelpers)}(this,function(a,b,c){"use strict";function d(a,b){return function(c){a(b+": "+c)}}function e(a,b){b&&Object.keys(b).forEach(function(c){b[c]&&a.hasOwnProperty(c)&&("[object Object]"===Object.prototype.toString.call(a[c])?e(a[c],b[c]):"[object Map]"===Object.prototype.toString.call(a[c])&&"[object Object]"===Object.prototype.toString.call(b[c])?Object.keys(b[c]).forEach(function(d){a[c].set(d,b[c][d])}):a[c]=b[c])})}function f(a,b){var d=!1,e=[];return a.filters.forEach(function(a){if(!a.name||a.name===b.name){if(a.namePrefix){if(a.namePrefix.length>b.name.length)return;if(a.namePrefix!==b.name.substr(0,a.namePrefix.length))return}if(a.services){var f=a.services.map(c.getServiceUUID),g=f.every(function(a){return b.uuids.indexOf(a)>-1});if(!g)return;e=e.concat(f)}d=!0}}),d?(a.optionalServices&&(e=e.concat(a.optionalServices.map(c.getServiceUUID))),b._allowedServices=e.filter(function(a,b,c){return c.indexOf(a)===b}),b):!1}function g(a,b,d,e){if(!a.filters||0===a.filters.length)return e("no filters specified");var g=a.filters.some(function(a){return 0===Object.keys(a).length});if(g)return e("empty filter specified");var h=a.filters.some(function(a){return"undefined"!=typeof a.namePrefix&&""===a.namePrefix});if(h)return e("empty namePrefix specified");var i=[];a.filters&&a.filters.forEach(function(a){a.services&&(i=i.concat(a.services.map(c.getServiceUUID)))}),i=i.filter(function(a,b,c){return c.indexOf(a)===b});var j,m=a.scanTime||k;l.startScan(i,function(c){c=f(a,c),c&&b(c,j)},function(){j=setTimeout(function(){l.stopScan(),d()},m)},e)}function h(a){return function(b,c,d){a.indexOf(b)<0||(n[this]||(n[this]={}),n[this][b]||(n[this][b]=[]),n[this][b].push(c))}}function i(a,b,c){if(n[this]&&n[this][a]){var d=n[this][a].indexOf(b);d>=0&&n[this][a].splice(d,1),0===n[this][a].length&&delete n[this][a],0===Object.keys(n[this]).length&&delete n[this]}}function j(a){n[this]&&n[this][a.type]&&(a.target=this,n[this][a.type].forEach(function(b){"function"==typeof b&&b(a)}))}var k=10240,l=null,m={},n={},o=function(a){this._handle=null,this._allowedServices=[],this.id="unknown",this.name=null,this.adData={appearance:null,txPower:null,rssi:null,manufacturerData:new b,serviceData:new b},this.deviceClass=null,this.vendorIDSource="bluetooth",this.vendorID=null,this.productID=null,this.productVersion=null,this.gatt=new p,this.gatt.device=this,this.uuids=[],e(this,a)};o.prototype.addEventListener=h(["gattserverdisconnected"]),o.prototype.removeEventListener=i,o.prototype.dispatchEvent=j;var p=function(){this._services=null,this.device=null,this.connected=!1};p.prototype.connect=function(){return new a(function(a,b){l.connect(this.device._handle,function(){this.connected=!0,a(this)}.bind(this),function(){this.connected=!1,this.device.dispatchEvent({type:"gattserverdisconnected",bubbles:!0})}.bind(this),d(b,"connect error"))}.bind(this))},p.prototype.disconnect=function(){l.disconnect(this.device._handle),this.connected=!1},p.prototype.getPrimaryService=function(b){return new a(function(a,c){return b?void this.getPrimaryServices(b).then(function(b){return 1!==b.length?c("getPrimaryService error: service not found"):void a(b[0])})["catch"](function(a){c(a)}):c("getPrimaryService error: no service specified")}.bind(this))},p.prototype.getPrimaryServices=function(b){return new a(function(a,e){function f(){if(!b)return a(this._services);var d=this._services.filter(function(a){return a.uuid===c.getServiceUUID(b)});return 1!==d.length?e("getPrimaryServices error: service not found"):void a(d)}return this._services?f.call(this):void l.discoverServices(this.device._handle,this.device._allowedServices,function(a){this._services=a.map(function(a){return a.device=this.device,new q(a)}.bind(this)),f.call(this)}.bind(this),d(e,"getPrimaryServices error"))}.bind(this))};var q=function(a){this._handle=null,this._services=null,this._characteristics=null,this.device=null,this.uuid=null,this.isPrimary=!1,e(this,a),this.dispatchEvent({type:"serviceadded",bubbles:!0})};q.prototype.getCharacteristic=function(b){return new a(function(a,c){return b?void this.getCharacteristics(b).then(function(b){return 1!==b.length?c("getCharacteristic error: characteristic not found"):void a(b[0])})["catch"](function(a){c(a)}):c("getCharacteristic error: no characteristic specified")}.bind(this))},q.prototype.getCharacteristics=function(b){return new a(function(a,e){function f(){if(!b)return a(this._characteristics);var d=this._characteristics.filter(function(a){return a.uuid===c.getCharacteristicUUID(b)});return 1!==d.length?e("getCharacteristics error: characteristic not found"):void a(d)}return this._characteristics?f.call(this):void l.discoverCharacteristics(this._handle,[],function(a){this._characteristics=a.map(function(a){return a.service=this,new r(a)}.bind(this)),f.call(this)}.bind(this),d(e,"getCharacteristics error"))}.bind(this))},q.prototype.getIncludedService=function(b){return new a(function(a,c){return b?void this.getIncludedServices(b).then(function(b){return 1!==b.length?c("getIncludedService error: service not found"):void a(b[0])})["catch"](function(a){c(a)}):c("getIncludedService error: no service specified")}.bind(this))},q.prototype.getIncludedServices=function(b){return new a(function(a,e){function f(){if(!b)return a(this._services);var d=this._services.filter(function(a){return a.uuid===c.getServiceUUID(b)});return 1!==d.length?e("getIncludedServices error: service not found"):void a(d)}return this._services?f.call(this):void l.discoverIncludedServices(this._handle,this.device._allowedServices,function(a){this._services=a.map(function(a){return a.device=this.device,new q(a)}.bind(this)),f.call(this)}.bind(this),d(e,"getIncludedServices error"))}.bind(this))},q.prototype.addEventListener=h(["serviceadded","servicechanged","serviceremoved"]),q.prototype.removeEventListener=i,q.prototype.dispatchEvent=j;var r=function(a){this._handle=null,this._descriptors=null,this.service=null,this.uuid=null,this.properties={broadcast:!1,read:!1,writeWithoutResponse:!1,write:!1,notify:!1,indicate:!1,authenticatedSignedWrites:!1,reliableWrite:!1,writableAuxiliaries:!1},this.value=null,e(this,a)};r.prototype.getDescriptor=function(b){return new a(function(a,c){return b?void this.getDescriptors(b).then(function(b){return 1!==b.length?c("getDescriptor error: descriptor not found"):void a(b[0])})["catch"](function(a){c(a)}):c("getDescriptor error: no descriptor specified")}.bind(this))},r.prototype.getDescriptors=function(b){return new a(function(a,e){function f(){if(!b)return a(this._descriptors);var d=this._descriptors.filter(function(a){return a.uuid===c.getDescriptorUUID(b)});return 1!==d.length?e("getDescriptors error: descriptor not found"):void a(d)}return this._descriptors?f.call(this):void l.discoverDescriptors(this._handle,[],function(a){this._descriptors=a.map(function(a){return a.characteristic=this,new s(a)}.bind(this)),f.call(this)}.bind(this),d(e,"getDescriptors error"))}.bind(this))},r.prototype.readValue=function(){return new a(function(a,b){l.readCharacteristic(this._handle,function(b){this.value=b,a(b),this.dispatchEvent({type:"characteristicvaluechanged",bubbles:!0})}.bind(this),d(b,"readValue error"))}.bind(this))},r.prototype.writeValue=function(b){var c=b.buffer||b,e=new DataView(c);return new a(function(a,b){l.writeCharacteristic(this._handle,e,function(){this.value=e,a()}.bind(this),d(b,"writeValue error"))}.bind(this))},r.prototype.startNotifications=function(){return new a(function(a,b){l.enableNotify(this._handle,function(a){this.value=a,this.dispatchEvent({type:"characteristicvaluechanged",bubbles:!0})}.bind(this),a,d(b,"startNotifications error"))}.bind(this))},r.prototype.stopNotifications=function(){return new a(function(a,b){l.disableNotify(this._handle,a,d(b,"stopNotifications error"))}.bind(this))},r.prototype.addEventListener=h(["characteristicvaluechanged"]),r.prototype.removeEventListener=i,r.prototype.dispatchEvent=j;var s=function(a){this._handle=null,this.characteristic=null,this.uuid=null,this.value=null,e(this,a)};return s.prototype.readValue=function(){return new a(function(a,b){l.readDescriptor(this._handle,function(b){this.value=b,a(b)}.bind(this),d(b,"readValue error"))}.bind(this))},s.prototype.writeValue=function(b){var c=b.buffer||b,e=new DataView(c);return new a(function(a,b){l.writeDescriptor(this._handle,e,function(){this.value=e,a()}.bind(this),d(b,"writeValue error"))}.bind(this))},{_addAdapter:function(a,b){m[a]=b,l=b},requestDevice:function(b){return new a(function(a,c){g(b,function(b,c){c&&clearTimeout(c),l.stopScan(),a(new o(b))},function(){c("requestDevice error: no devices found")},d(c,"requestDevice error"))})},requestDevices:function(b){return new a(function(a,c){var e=[];g(b,function(a){e.push(a)},function(){0===e.length?c("requestDevices error: no devices found"):a(e.map(function(a){return new o(a)}))},d(c,"requestDevices error"))})}}}),function(a,b){"function"==typeof define&&define.amd?define(["bleat","bluetooth.helpers"],b.bind(this,a)):"object"==typeof exports?module.exports=function(c){return b(a,c,require("./bluetooth.helpers"))}:b(a,a.bleat,a.bleatHelpers)}(this,function(a,b,c){"use strict";function d(b){a.evothings&&evothings.ble?b():document.addEventListener("deviceready",b)}function e(a){var b=x[a];b&&(evothings.ble.close(b),delete x[a],f(b,y),f(b,z,!0),f(b,A))}function f(a,b,c){for(var d in b)a===b[d]&&(delete b[d],c&&B[d]&&delete B[d])}function g(a,b){var c=x[a];return c?c:(b&&b("Device does not exist for device id: "+a),null)}function h(a,b){var c=y[a];return c?c:(b&&b("Device does not exist for service handle: "+a),null)}function i(a,b){var c=z[a];return c?c:(b&&b("Device does not exist for characteristic handle: "+a),null)}function j(a,b,c,d){function e(b){evothings.ble.writeDescriptor(a,b,new Uint8Array([1,0]),function(){c()},function(a){d(a)})}function f(){w.discoverDescriptors(b,"00002902-0000-1000-8000-00805f9b34fb",function(a){var c=B[b];c?e(c):d("Could not find CCCD for characteristic: "+b)},function(a){d(a)})}var g=B[b];g?e(g):f()}function k(a){var b={};return b._handle=a.address,b.id=a.address,b.name=a.name,b.uuids=[],b.adData={},b.adData.rssi=a.rssi,b.adData.txPower=null,b.adData.serviceData={},b.adData.serviceUUIDs=[],b.adData.manufacturerData=null,a.advertisementData?l(a,b):a.scanRecord&&m(a,b),b}function l(a,b){if(a.advertisementData){if(a.advertisementData.kCBAdvDataLocalName&&(b.name=a.advertisementData.kCBAdvDataLocalName),a.advertisementData.kCBAdvDataTxPowerLevel&&(b.adData.txPower=a.advertisementData.kCBAdvDataTxPowerLevel),a.advertisementData.kCBAdvDataServiceUUIDs&&a.advertisementData.kCBAdvDataServiceUUIDs.forEach(function(a){b.uuids.push(c.getCanonicalUUID(a))}),a.advertisementData.kCBAdvDataServiceData)for(var d in a.advertisementData.kCBAdvDataServiceData){var e=a.advertisementData.kCBAdvDataServiceData[d];b.adData.serviceData[c.getCanonicalUUID(d)]=t(o(e))}a.advertisementData.kCBAdvDataManufacturerData&&(b.adData.manufacturerDataRaw=a.advertisementData.kCBAdvDataManufacturerData)}}function m(a,b){for(var d=o(a.scanRecord),e=0;eg;g+=2)b.adData.serviceUUIDs.push(c.getCanonicalUUID(q(d,e+g).toString(16)));else if(4===h||5===h)for(g=0;f>g;g+=4)b.adData.serviceUUIDs.push(c.getCanonicalUUID(r(d,e+g).toString(16)));else if(6===h||7===h)for(g=0;f>g;g+=16)b.adData.serviceUUIDs.push(c.getCanonicalUUID(s(d,e+g)));e+=f}}function n(a){return a>64&&91>a?a-65:a>96&&123>a?a-71:a>47&&58>a?a+4:43===a?62:47===a?63:0}function o(a,b){for(var c,d,e=a.replace(/[^A-Za-z0-9\+\/]/g,""),f=e.length,g=b?Math.ceil((3*f+1>>2)/b)*b:3*f+1>>2,h=new Uint8Array(g),i=0,j=0,k=0;f>k;k++)if(d=3&k,i|=n(e.charCodeAt(k))<<18-6*d,3===d||f-k===1){for(c=0;3>c&&g>j;c++,j++)h[j]=i>>>(16>>>c&24)&255;i=0}return h}function p(a,b){var c=a[b];return 128&c&&(c-=256),c}function q(a,b){return(a[b+1]<<8)+a[b]}function r(a,b){return(a[b+3]<<24)+(a[b+2]<<16)+(a[b+1]<<8)+a[b]}function s(a,b){for(var c="",d=0;16>d;d++)c+=("00"+a[b+d].toString(16)).slice(-2);return c}function t(a){var b=new Uint8Array(a).buffer;return new DataView(b)}function u(){return a.cordova?a.cordova.platformId:null}function v(){return"ios"===u()}var w={},x={},y={},z={},A={},B={};b._addAdapter("evothings",w),w.startScan=function(a,b,c,e){d(function(){evothings.ble.startScan(function(a){b&&b(k(a))},function(a){e&&e(a)})})},w.stopScan=function(a){d(function(){evothings.ble.stopScan()})},w.connect=function(a,b,c,d){evothings.ble.connect(a,function(d){2===d.state&&b?(x[a]=d.deviceHandle,b()):0===d.state&&b&&(e(a),c())},function(a){d&&d(a)})},w.disconnect=function(a,b){e(a)},w.discoverServices=function(a,b,d,e){var f=g(a,e);f&&evothings.ble.services(f,function(a){var e=[];a.forEach(function(a){var d=c.getCanonicalUUID(a.uuid),g=!b||0===b.length||b.indexOf(d)>=0;g&&(y[a.handle]=f,e.push({_handle:a.handle,uuid:d,primary:!0}))}),d&&d(e)},function(a){e&&e(a)})},w.discoverIncludedServices=function(a,b,c,d){c([])},w.discoverCharacteristics=function(a,b,d,e){var f=h(a,e);f&&evothings.ble.characteristics(f,a,function(a){var e=[];a.forEach(function(a){var d=c.getCanonicalUUID(a.uuid),g=!b||0===b.length||b.indexOf(d)>=0;g&&(z[a.handle]=f,e.push({_handle:a.handle,uuid:d,properties:{broadcast:1&a.property,read:2&a.property,writeWithoutResponse:4&a.property&&1&a.writeType,write:8&a.property,notify:16&a.property,indicate:32&a.property,authenticatedSignedWrites:64&a.property&&4&a.writeType,reliableWrite:!1,writableAuxiliaries:!1}}))}),d&&d(e)},function(a){e&&e(a)})},w.discoverDescriptors=function(a,b,d,e){var f=i(a,e);f&&evothings.ble.descriptors(f,a,function(e){var g=[];e.forEach(function(d){var e=c.getCanonicalUUID(d.uuid);"00002902-0000-1000-8000-00805f9b34fb"===e&&(B[a]=d.handle);var h=!b||0===b.length||b.indexOf(e)>=0;h&&(A[d.handle]=f,g.push({_handle:d.handle,uuid:e}))}),d&&d(g)},function(a){e&&e(a)})},w.readCharacteristic=function(a,b,c){var d=i(a,c);d&&evothings.ble.readCharacteristic(d,a,function(a){b&&b(t(a))},function(a){c&&c(a)})},w.writeCharacteristic=function(a,b,c,d){var e=i(a,d);e&&evothings.ble.writeCharacteristic(e,a,b,function(){c&&c()},function(a){d&&d(a)})},w.enableNotify=function(a,b,c,d){function e(){evothings.ble.enableNotification(f,a,function(a){b&&b(t(a))},function(a){d&&d(a)}),c&&c()}var f=i(a,d);f&&j(f,a,e,function(a){d&&d(a)})},w.disableNotify=function(a,b,c){var d=i(a,c);d&&(evothings.ble.disableNotification(d,a,function(){b&&b()},function(a){c&&c(a)}),v()&&setTimeout(b,0))},w.readDescriptor=function(a,b,c){var d=getDeviceHandleFromDescriptorHandle(a,c);d&&evothings.ble.readDescriptor(d,a,function(a){b&&b(t(a))},function(a){c&&c(a)})},w.writeDescriptor=function(a,b,c,d){var e=getDeviceHandleFromDescriptorHandle(a,d);e&&evothings.ble.writeDescriptor(e,a,b,function(){c&&c()},function(a){d&&d(a)})}}); \ No newline at end of file +function(a,b){"function"==typeof define&&define.amd?a.navigator.bluetooth?define(a.navigator.bluetooth):define(["es6-promise","es6-map","bluetooth.helpers"],b):"object"==typeof exports?module.exports=b(Promise,Map,require("./bluetooth.helpers")):a.bleat=a.navigator.bluetooth||b(a.Promise,a.Map,a.bleatHelpers)}(this,function(a,b,c){"use strict";function d(a,b){return function(c){a(b+": "+c)}}function e(a,b){b&&Object.keys(b).forEach(function(c){b[c]&&a.hasOwnProperty(c)&&("[object Object]"===Object.prototype.toString.call(a[c])?e(a[c],b[c]):"[object Map]"===Object.prototype.toString.call(a[c])&&"[object Object]"===Object.prototype.toString.call(b[c])?Object.keys(b[c]).forEach(function(d){a[c].set(d,b[c][d])}):a[c]=b[c])})}function f(a){return function(b,c,d){a.indexOf(b)<0||(o[this]||(o[this]={}),o[this][b]||(o[this][b]=[]),o[this][b].push(c))}}function g(a,b,c){if(o[this]&&o[this][a]){var d=o[this][a].indexOf(b);d>=0&&o[this][a].splice(d,1),0===o[this][a].length&&delete o[this][a],0===Object.keys(o[this]).length&&delete o[this]}}function h(a){o[this]&&o[this][a.type]&&(a.target=this,o[this][a.type].forEach(function(b){"function"==typeof b&&b(a)}))}function i(a,b){var d=!1,e=[];return a.filters.forEach(function(a){if(!a.name||a.name===b.name){if(a.namePrefix){if(a.namePrefix.length>b.name.length)return;if(a.namePrefix!==b.name.substr(0,a.namePrefix.length))return}if(a.services){var f=a.services.map(c.getServiceUUID),g=f.every(function(a){return b.uuids.indexOf(a)>-1});if(!g)return;e=e.concat(f)}d=!0}}),d?(a.optionalServices&&(e=e.concat(a.optionalServices.map(c.getServiceUUID))),b._allowedServices=e.filter(function(a,b,c){return c.indexOf(a)===b}),b):!1}function j(b){return new a(function(a,e){if(null!==p)return e("requestDevice error: request in progress");if(!b.deviceFound){if(!b.filters||0===b.filters.length)return e(new TypeError("requestDevice error: no filters specified"));var f=b.filters.some(function(a){return 0===Object.keys(a).length});if(f)return e(new TypeError("requestDevice error: empty filter specified"));var g=b.filters.some(function(a){return"undefined"!=typeof a.namePrefix&&""===a.namePrefix});if(g)return e(new TypeError("requestDevice error: empty namePrefix specified"))}var h=[];b.filters&&b.filters.forEach(function(a){a.services&&(h=h.concat(a.services.map(c.getServiceUUID)))}),h=h.filter(function(a,b,c){return c.indexOf(a)===b});var j=b.scanTime||l,n=b.deviceFound?a:function(){e("requestDevice error: no devices found")};m.startScan(h,function(c){if(b.deviceFound||(c=i(b,c)),c){var d=new q(c);b.deviceFound&&!b.deviceFound(d)||k().then(function(){a(d)})}},function(){p=setTimeout(function(){k().then(n)},j)},d(e,"requestDevice error"))})}function k(){return new a(function(a,b){p&&(clearTimeout(p),p=null,m.stopScan()),a()})}var l=10240,m=null,n={},o={},p=null,q=function(a){this._handle=null,this._allowedServices=[],this.id="unknown",this.name=null,this.adData={appearance:null,txPower:null,rssi:null,manufacturerData:new b,serviceData:new b},this.deviceClass=null,this.vendorIDSource="bluetooth",this.vendorID=null,this.productID=null,this.productVersion=null,this.gatt=new r,this.gatt.device=this,this.uuids=[],e(this,a)};q.prototype.addEventListener=f(["gattserverdisconnected"]),q.prototype.removeEventListener=g,q.prototype.dispatchEvent=h;var r=function(){this._services=null,this.device=null,this.connected=!1};r.prototype.connect=function(){return new a(function(a,b){return this.connected?b("connect error: device already connected"):void m.connect(this.device._handle,function(){this.connected=!0,a(this)}.bind(this),function(){this.connected=!1,this.device.dispatchEvent({type:"gattserverdisconnected",bubbles:!0})}.bind(this),d(b,"connect error"))}.bind(this))},r.prototype.disconnect=function(){m.disconnect(this.device._handle),this.connected=!1},r.prototype.getPrimaryService=function(b){return new a(function(a,c){return this.connected?b?void this.getPrimaryServices(b).then(function(b){return 1!==b.length?c("getPrimaryService error: service not found"):void a(b[0])})["catch"](function(a){c(a)}):c("getPrimaryService error: no service specified"):c("getPrimaryService error: device not connected")}.bind(this))},r.prototype.getPrimaryServices=function(b){return new a(function(a,e){function f(){if(!b)return a(this._services);var d=this._services.filter(function(a){return a.uuid===c.getServiceUUID(b)});return 1!==d.length?e("getPrimaryServices error: service not found"):void a(d)}return this.connected?this._services?f.call(this):void m.discoverServices(this.device._handle,this.device._allowedServices,function(a){this._services=a.map(function(a){return a.device=this.device,new s(a)}.bind(this)),f.call(this)}.bind(this),d(e,"getPrimaryServices error")):e("getPrimaryServices error: device not connected")}.bind(this))};var s=function(a){this._handle=null,this._services=null,this._characteristics=null,this.device=null,this.uuid=null,this.isPrimary=!1,e(this,a),this.dispatchEvent({type:"serviceadded",bubbles:!0})};s.prototype.getCharacteristic=function(b){return new a(function(a,c){return this.device.gatt.connected?b?void this.getCharacteristics(b).then(function(b){return 1!==b.length?c("getCharacteristic error: characteristic not found"):void a(b[0])})["catch"](function(a){c(a)}):c("getCharacteristic error: no characteristic specified"):c("getCharacteristic error: device not connected")}.bind(this))},s.prototype.getCharacteristics=function(b){return new a(function(a,e){function f(){if(!b)return a(this._characteristics);var d=this._characteristics.filter(function(a){return a.uuid===c.getCharacteristicUUID(b)});return 1!==d.length?e("getCharacteristics error: characteristic not found"):void a(d)}return this.device.gatt.connected?this._characteristics?f.call(this):void m.discoverCharacteristics(this._handle,[],function(a){this._characteristics=a.map(function(a){return a.service=this,new t(a)}.bind(this)),f.call(this)}.bind(this),d(e,"getCharacteristics error")):e("getCharacteristics error: device not connected")}.bind(this))},s.prototype.getIncludedService=function(b){return new a(function(a,c){return this.device.gatt.connected?b?void this.getIncludedServices(b).then(function(b){return 1!==b.length?c("getIncludedService error: service not found"):void a(b[0])})["catch"](function(a){c(a)}):c("getIncludedService error: no service specified"):c("getIncludedService error: device not connected")}.bind(this))},s.prototype.getIncludedServices=function(b){return new a(function(a,e){function f(){if(!b)return a(this._services);var d=this._services.filter(function(a){return a.uuid===c.getServiceUUID(b)});return 1!==d.length?e("getIncludedServices error: service not found"):void a(d)}return this.device.gatt.connected?this._services?f.call(this):void m.discoverIncludedServices(this._handle,this.device._allowedServices,function(a){this._services=a.map(function(a){return a.device=this.device,new s(a)}.bind(this)),f.call(this)}.bind(this),d(e,"getIncludedServices error")):e("getIncludedServices error: device not connected")}.bind(this))},s.prototype.addEventListener=f(["serviceadded","servicechanged","serviceremoved"]),s.prototype.removeEventListener=g,s.prototype.dispatchEvent=h;var t=function(a){this._handle=null,this._descriptors=null,this.service=null,this.uuid=null,this.properties={broadcast:!1,read:!1,writeWithoutResponse:!1,write:!1,notify:!1,indicate:!1,authenticatedSignedWrites:!1,reliableWrite:!1,writableAuxiliaries:!1},this.value=null,e(this,a)};t.prototype.getDescriptor=function(b){return new a(function(a,c){return this.service.device.gatt.connected?b?void this.getDescriptors(b).then(function(b){return 1!==b.length?c("getDescriptor error: descriptor not found"):void a(b[0])})["catch"](function(a){c(a)}):c("getDescriptor error: no descriptor specified"):c("getDescriptor error: device not connected")}.bind(this))},t.prototype.getDescriptors=function(b){return new a(function(a,e){function f(){if(!b)return a(this._descriptors);var d=this._descriptors.filter(function(a){return a.uuid===c.getDescriptorUUID(b)});return 1!==d.length?e("getDescriptors error: descriptor not found"):void a(d)}return this.service.device.gatt.connected?this._descriptors?f.call(this):void m.discoverDescriptors(this._handle,[],function(a){this._descriptors=a.map(function(a){return a.characteristic=this,new u(a)}.bind(this)),f.call(this)}.bind(this),d(e,"getDescriptors error")):e("getDescriptors error: device not connected")}.bind(this))},t.prototype.readValue=function(){return new a(function(a,b){return this.service.device.gatt.connected?void m.readCharacteristic(this._handle,function(b){this.value=b,a(b),this.dispatchEvent({type:"characteristicvaluechanged",bubbles:!0})}.bind(this),d(b,"readValue error")):b("readValue error: device not connected")}.bind(this))},t.prototype.writeValue=function(b){return new a(function(a,c){if(!this.service.device.gatt.connected)return c("writeValue error: device not connected");var e=b.buffer||b,f=new DataView(e);m.writeCharacteristic(this._handle,f,function(){this.value=f,a()}.bind(this),d(c,"writeValue error"))}.bind(this))},t.prototype.startNotifications=function(){return new a(function(a,b){return this.service.device.gatt.connected?void m.enableNotify(this._handle,function(a){this.value=a,this.dispatchEvent({type:"characteristicvaluechanged",bubbles:!0})}.bind(this),a,d(b,"startNotifications error")):b("startNotifications error: device not connected")}.bind(this))},t.prototype.stopNotifications=function(){return new a(function(a,b){return this.service.device.gatt.connected?void m.disableNotify(this._handle,a,d(b,"stopNotifications error")):b("stopNotifications error: device not connected")}.bind(this))},t.prototype.addEventListener=f(["characteristicvaluechanged"]),t.prototype.removeEventListener=g,t.prototype.dispatchEvent=h;var u=function(a){this._handle=null,this.characteristic=null,this.uuid=null,this.value=null,e(this,a)};return u.prototype.readValue=function(){return new a(function(a,b){return this.characteristic.service.device.gatt.connected?void m.readDescriptor(this._handle,function(b){this.value=b,a(b)}.bind(this),d(b,"readValue error")):b("readValue error: device not connected")}.bind(this))},u.prototype.writeValue=function(b){return new a(function(a,c){if(!this.characteristic.service.device.gatt.connected)return c("writeValue error: device not connected");var e=b.buffer||b,f=new DataView(e);m.writeDescriptor(this._handle,f,function(){this.value=f,a()}.bind(this),d(c,"writeValue error"))}.bind(this))},{_addAdapter:function(a,b){n[a]=b,m=b},requestDevice:j,cancelRequest:k}}),function(a,b){"function"==typeof define&&define.amd?define(["bleat","bluetooth.helpers"],b.bind(this,a)):"object"==typeof exports?module.exports=function(c){return b(a,c,require("./bluetooth.helpers"))}:b(a,a.bleat,a.bleatHelpers)}(this,function(a,b,c){"use strict";function d(b){a.evothings&&evothings.ble?b():document.addEventListener("deviceready",b)}function e(a){var b=x[a];b&&(evothings.ble.close(b),delete x[a],f(b,y),f(b,z,!0),f(b,A))}function f(a,b,c){for(var d in b)a===b[d]&&(delete b[d],c&&B[d]&&delete B[d])}function g(a,b){var c=x[a];return c?c:(b&&b("Device does not exist for device id: "+a),null)}function h(a,b){var c=y[a];return c?c:(b&&b("Device does not exist for service handle: "+a),null)}function i(a,b){var c=z[a];return c?c:(b&&b("Device does not exist for characteristic handle: "+a),null)}function j(a,b,c,d){function e(b){evothings.ble.writeDescriptor(a,b,new Uint8Array([1,0]),function(){c()},function(a){d(a)})}function f(){w.discoverDescriptors(b,"00002902-0000-1000-8000-00805f9b34fb",function(a){var c=B[b];c?e(c):d("Could not find CCCD for characteristic: "+b)},function(a){d(a)})}var g=B[b];g?e(g):f()}function k(a){var b={};return b._handle=a.address,b.id=a.address,b.name=a.name,b.uuids=[],b.adData={},b.adData.rssi=a.rssi,b.adData.txPower=null,b.adData.serviceData={},b.adData.serviceUUIDs=[],b.adData.manufacturerData=null,a.advertisementData?l(a,b):a.scanRecord&&m(a,b),b}function l(a,b){if(a.advertisementData){if(a.advertisementData.kCBAdvDataLocalName&&(b.name=a.advertisementData.kCBAdvDataLocalName),a.advertisementData.kCBAdvDataTxPowerLevel&&(b.adData.txPower=a.advertisementData.kCBAdvDataTxPowerLevel),a.advertisementData.kCBAdvDataServiceUUIDs&&a.advertisementData.kCBAdvDataServiceUUIDs.forEach(function(a){b.uuids.push(c.getCanonicalUUID(a))}),a.advertisementData.kCBAdvDataServiceData)for(var d in a.advertisementData.kCBAdvDataServiceData){var e=a.advertisementData.kCBAdvDataServiceData[d];b.adData.serviceData[c.getCanonicalUUID(d)]=t(o(e))}a.advertisementData.kCBAdvDataManufacturerData&&(b.adData.manufacturerDataRaw=a.advertisementData.kCBAdvDataManufacturerData)}}function m(a,b){for(var d=o(a.scanRecord),e=0;eg;g+=2)b.adData.serviceUUIDs.push(c.getCanonicalUUID(q(d,e+g).toString(16)));else if(4===h||5===h)for(g=0;f>g;g+=4)b.adData.serviceUUIDs.push(c.getCanonicalUUID(r(d,e+g).toString(16)));else if(6===h||7===h)for(g=0;f>g;g+=16)b.adData.serviceUUIDs.push(c.getCanonicalUUID(s(d,e+g)));e+=f}}function n(a){return a>64&&91>a?a-65:a>96&&123>a?a-71:a>47&&58>a?a+4:43===a?62:47===a?63:0}function o(a,b){for(var c,d,e=a.replace(/[^A-Za-z0-9\+\/]/g,""),f=e.length,g=b?Math.ceil((3*f+1>>2)/b)*b:3*f+1>>2,h=new Uint8Array(g),i=0,j=0,k=0;f>k;k++)if(d=3&k,i|=n(e.charCodeAt(k))<<18-6*d,3===d||f-k===1){for(c=0;3>c&&g>j;c++,j++)h[j]=i>>>(16>>>c&24)&255;i=0}return h}function p(a,b){var c=a[b];return 128&c&&(c-=256),c}function q(a,b){return(a[b+1]<<8)+a[b]}function r(a,b){return(a[b+3]<<24)+(a[b+2]<<16)+(a[b+1]<<8)+a[b]}function s(a,b){for(var c="",d=0;16>d;d++)c+=("00"+a[b+d].toString(16)).slice(-2);return c}function t(a){var b=new Uint8Array(a).buffer;return new DataView(b)}function u(){return a.cordova?a.cordova.platformId:null}function v(){return"ios"===u()}var w={},x={},y={},z={},A={},B={};b._addAdapter("evothings",w),w.startScan=function(a,b,c,e){d(function(){evothings.ble.startScan(function(a){b&&b(k(a))},function(a){e&&e(a)})})},w.stopScan=function(a){d(function(){evothings.ble.stopScan()})},w.connect=function(a,b,c,d){evothings.ble.connect(a,function(d){2===d.state&&b?(x[a]=d.deviceHandle,b()):0===d.state&&b&&(e(a),c())},function(a){d&&d(a)})},w.disconnect=function(a,b){e(a)},w.discoverServices=function(a,b,d,e){var f=g(a,e);f&&evothings.ble.services(f,function(a){var e=[];a.forEach(function(a){var d=c.getCanonicalUUID(a.uuid),g=!b||0===b.length||b.indexOf(d)>=0;g&&(y[a.handle]=f,e.push({_handle:a.handle,uuid:d,primary:!0}))}),d&&d(e)},function(a){e&&e(a)})},w.discoverIncludedServices=function(a,b,c,d){c([])},w.discoverCharacteristics=function(a,b,d,e){var f=h(a,e);f&&evothings.ble.characteristics(f,a,function(a){var e=[];a.forEach(function(a){var d=c.getCanonicalUUID(a.uuid),g=!b||0===b.length||b.indexOf(d)>=0;g&&(z[a.handle]=f,e.push({_handle:a.handle,uuid:d,properties:{broadcast:1&a.property,read:2&a.property,writeWithoutResponse:4&a.property&&1&a.writeType,write:8&a.property,notify:16&a.property,indicate:32&a.property,authenticatedSignedWrites:64&a.property&&4&a.writeType,reliableWrite:!1,writableAuxiliaries:!1}}))}),d&&d(e)},function(a){e&&e(a)})},w.discoverDescriptors=function(a,b,d,e){var f=i(a,e);f&&evothings.ble.descriptors(f,a,function(e){var g=[];e.forEach(function(d){var e=c.getCanonicalUUID(d.uuid);"00002902-0000-1000-8000-00805f9b34fb"===e&&(B[a]=d.handle);var h=!b||0===b.length||b.indexOf(e)>=0;h&&(A[d.handle]=f,g.push({_handle:d.handle,uuid:e}))}),d&&d(g)},function(a){e&&e(a)})},w.readCharacteristic=function(a,b,c){var d=i(a,c);d&&evothings.ble.readCharacteristic(d,a,function(a){b&&b(t(a))},function(a){c&&c(a)})},w.writeCharacteristic=function(a,b,c,d){var e=i(a,d);e&&evothings.ble.writeCharacteristic(e,a,b,function(){c&&c()},function(a){d&&d(a)})},w.enableNotify=function(a,b,c,d){function e(){evothings.ble.enableNotification(f,a,function(a){b&&b(t(a))},function(a){d&&d(a)}),c&&c()}var f=i(a,d);f&&j(f,a,e,function(a){d&&d(a)})},w.disableNotify=function(a,b,c){var d=i(a,c);d&&(evothings.ble.disableNotification(d,a,function(){b&&b()},function(a){c&&c(a)}),v()&&setTimeout(b,0))},w.readDescriptor=function(a,b,c){var d=getDeviceHandleFromDescriptorHandle(a,c);d&&evothings.ble.readDescriptor(d,a,function(a){b&&b(t(a))},function(a){c&&c(a)})},w.writeDescriptor=function(a,b,c,d){var e=getDeviceHandleFromDescriptorHandle(a,d);e&&evothings.ble.writeDescriptor(e,a,b,function(){c&&c()},function(a){d&&d(a)})}}); \ No newline at end of file