UNPKG

bleat

Version:

Abstraction library following Web Bluetooth specification for hiding differences in JavaScript BLE APIs

81 lines 26.2 kB
/* @license * * BLE Abstraction Tool: bluetooth helpers * * The MIT License (MIT) * * Copyright (c) 2016 Rob Moran * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ !function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.bleatHelpers=t()}(this,function(){"use strict";var t={alert_notification:6161,automation_io:6165,battery_service:6159,blood_pressure:6160,body_composition:6171,bond_management:6174,continuous_glucose_monitoring:6175,current_time:6149,cycling_power:6168,cycling_speed_and_cadence:6166,device_information:6154,environmental_sensing:6170,generic_access:6144,generic_attribute:6145,glucose:6152,health_thermometer:6153,heart_rate:6157,human_interface_device:6162,immediate_alert:6146,indoor_positioning:6177,internet_protocol_support:6176,link_loss:6147,location_and_navigation:6169,next_dst_change:6151,phone_alert_status:6158,pulse_oximeter:6178,reference_time_update:6150,running_speed_and_cadence:6164,scan_parameters:6163,tx_power:6148,user_data:6172,weight_scale:6173},r={aerobic_heart_rate_lower_limit:10878,aerobic_heart_rate_upper_limit:10884,aerobic_threshold:10879,age:10880,aggregate:10842,alert_category_id:10819,alert_category_id_bit_mask:10818,alert_level:10758,alert_notification_control_point:10820,alert_status:10815,altitude:10931,anaerobic_heart_rate_lower_limit:10881,anaerobic_heart_rate_upper_limit:10882,anaerobic_threshold:10883,analog:10840,apparent_wind_direction:10867,apparent_wind_speed:10866,"gap.appearance":10753,barometric_pressure_trend:10915,battery_level:10777,blood_pressure_feature:10825,blood_pressure_measurement:10805,body_composition_feature:10907,body_composition_measurement:10908,body_sensor_location:10808,bond_management_control_point:10916,bond_management_feature:10917,boot_keyboard_input_report:10786,boot_keyboard_output_report:10802,boot_mouse_input_report:10803,"gap.central_address_resolution_support":10918,cgm_feature:10920,cgm_measurement:10919,cgm_session_run_time:10923,cgm_session_start_time:10922,cgm_specific_ops_control_point:10924,cgm_status:10921,csc_feature:10844,csc_measurement:10843,current_time:10795,cycling_power_control_point:10854,cycling_power_feature:10853,cycling_power_measurement:10851,cycling_power_vector:10852,database_change_increment:10905,date_of_birth:10885,date_of_threshold_assessment:10886,date_time:10760,day_date_time:10762,day_of_week:10761,descriptor_value_changed:10877,"gap.device_name":10752,dew_point:10875,digital:10838,dst_offset:10765,elevation:10860,email_address:10887,exact_time_256:10764,fat_burn_heart_rate_lower_limit:10888,fat_burn_heart_rate_upper_limit:10889,firmware_revision_string:10790,first_name:10890,five_zone_heart_rate_limits:10891,floor_number:10930,gender:10892,glucose_feature:10833,glucose_measurement:10776,glucose_measurement_context:10804,gust_factor:10868,hardware_revision_string:10791,heart_rate_control_point:10809,heart_rate_max:10893,heart_rate_measurement:10807,heat_index:10874,height:10894,hid_control_point:10828,hid_information:10826,hip_circumference:10895,humidity:10863,"ieee_11073-20601_regulatory_certification_data_list":10794,indoor_positioning_configuration:10925,intermediate_blood_pressure:10806,intermediate_temperature:10782,irradiance:10871,language:10914,last_name:10896,latitude:10926,ln_control_point:10859,ln_feature:10858,"local_east_coordinate.xml":10929,local_north_coordinate:10928,local_time_information:10767,location_and_speed:10855,location_name:10933,longitude:10927,magnetic_declination:10796,magnetic_flux_density_2D:10912,magnetic_flux_density_3D:10913,manufacturer_name_string:10793,maximum_recommended_heart_rate:10897,measurement_interval:10785,model_number_string:10788,navigation:10856,new_alert:10822,"gap.peripheral_preferred_connection_parameters":10756,"gap.peripheral_privacy_flag":10754,plx_continuous_measurement:10847,plx_features:10848,plx_spot_check_measurement:10846,pnp_id:10832,pollen_concentration:10869,position_quality:10857,pressure:10861,protocol_mode:10830,rainfall:10872,"gap.reconnection_address":10755,record_access_control_point:10834,reference_time_information:10772,report:10829,report_map:10827,resting_heart_rate:10898,ringer_control_point:10816,ringer_setting:10817,rsc_feature:10836,rsc_measurement:10835,sc_control_point:10837,scan_interval_window:10831,scan_refresh:10801,sensor_location:10845,serial_number_string:10789,"gatt.service_changed":10757,software_revision_string:10792,sport_type_for_aerobic_and_anaerobic_thresholds:10899,supported_new_alert_category:10823,supported_unread_alert_category:10824,system_id:10787,temperature:10862,temperature_measurement:10780,temperature_type:10781,three_zone_heart_rate_limits:10900,time_accuracy:10770,time_source:10771,time_update_control_point:10774,time_update_state:10775,time_with_dst:10769,time_zone:10766,true_wind_direction:10865,true_wind_speed:10864,two_zone_heart_rate_limit:10901,tx_power_level:10759,uncertainty:10932,unread_alert_status:10821,user_control_point:10911,user_index:10906,uv_index:10870,vo2_max:10902,waist_circumference:10903,weight:10904,weight_measurement:10909,weight_scale_feature:10910,wind_chill:10873},_={"gatt.characteristic_extended_properties":10496,"gatt.characteristic_user_description":10497,"gatt.client_characteristic_configuration":10498,"gatt.server_characteristic_configuration":10499,"gatt.characteristic_presentation_format":10500,"gatt.characteristic_aggregate_format":10501,valid_range:10502,external_report_reference:10503,report_reference:10504,number_of_digitals:10505,value_trigger_setting:10506,es_configuration:10507,es_measurement:10508,es_trigger_setting:10509,time_trigger_setting:10510};function a(e){return"number"==typeof e&&(e=e.toString(16)),(e=e.toLowerCase()).length<=8&&(e=("00000000"+e).slice(-8)+"-0000-1000-8000-00805f9b34fb"),32===e.length&&(e=e.match(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/).splice(1).join("-")),e}return{Services:t,Characteristics:r,Descriptors:_,getCanonicalUUID:a,getServiceUUID:function(e){return t[e]&&(e=t[e]),a(e)},getCharacteristicUUID:function(e){return r[e]&&(e=r[e]),a(e)},getDescriptorUUID:function(e){return _[e]&&(e=_[e]),a(e)}}}); /* @license * * BLE Abstraction Tool: core functionality - web bluetooth specification * * The MIT License (MIT) * * Copyright (c) 2017 Rob Moran * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ !function(e,t){"function"==typeof define&&define.amd?define(["es6-promise","es6-map","bluetooth.helpers"],t):"object"==typeof exports?module.exports=t(Promise,Map,require("./bluetooth.helpers")):e.bleat=t(e.Promise,e.Map,e.bleatHelpers)}(this,function(t,i,o){"use strict";var u=null,r={};function a(t,i){return function(e){t(i+": "+e)}}function n(i,r){r&&Object.keys(r).forEach(function(t){r[t]&&i.hasOwnProperty(t)&&("[object Object]"===Object.prototype.toString.call(i[t])?n(i[t],r[t]):"[object Map]"===Object.prototype.toString.call(i[t])&&"[object Object]"===Object.prototype.toString.call(r[t])?Object.keys(r[t]).forEach(function(e){i[t].set(e,r[t][e])}):i[t]=r[t])})}function e(r){return function(e,t,i){r.indexOf(e)<0||(this.__events||(this.__events={}),this.__events[e]||(this.__events[e]=[]),this.__events[e].push(t))}}function c(e,t,i){if(this.__events&&this.__events[e]){var r=this.__events[e].indexOf(t);0<=r&&this.__events[e].splice(r,1),0===this.__events[e].length&&delete this.__events[e],0===Object.keys(this.__events).length&&delete this.__events}}function s(t){this.__events&&this.__events[t.type]&&(t.target=this).__events[t.type].forEach(function(e){"function"==typeof e&&e(t)})}var d=null;function h(){return new t(function(e,t){d&&(clearTimeout(d),d=null,u.stopScan()),e()})}function f(e){this._handle=null,this._allowedServices=[],this.id="unknown",this.name=null,this.adData={appearance:null,txPower:null,rssi:null,manufacturerData:new i,serviceData:new i},this.gatt=new v,(this.gatt.device=this).uuids=[],n(this,e)}f.prototype.addEventListener=e(["gattserverdisconnected"]),f.prototype.removeEventListener=c,f.prototype.dispatchEvent=s;var v=function(){this._services=null,this.device=null,this.connected=!1};v.prototype.connect=function(){return new t(function(e,t){if(this.connected)return t("connect error: device already connected");u.connect(this.device._handle,function(){this.connected=!0,e(this)}.bind(this),function(){this._services=null,this.connected=!1,this.device.dispatchEvent({type:"gattserverdisconnected",bubbles:!0})}.bind(this),a(t,"connect error"))}.bind(this))},v.prototype.disconnect=function(){u.disconnect(this.device._handle),this.connected=!1},v.prototype.getPrimaryService=function(e){return new t(function(t,i){return this.connected?e?void this.getPrimaryServices(e).then(function(e){if(1!==e.length)return i("getPrimaryService error: service not found");t(e[0])}).catch(function(e){i(e)}):i("getPrimaryService error: no service specified"):i("getPrimaryService error: device not connected")}.bind(this))},v.prototype.getPrimaryServices=function(n){return new t(function(t,i){if(!this.connected)return i("getPrimaryServices error: device not connected");function r(){if(!n)return t(this._services);var e=this._services.filter(function(e){return e.uuid===o.getServiceUUID(n)});if(1!==e.length)return i("getPrimaryServices error: service not found");t(e)}if(this._services)return r.call(this);u.discoverServices(this.device._handle,this.device._allowedServices,function(e){this._services=e.map(function(e){return e.device=this.device,new l(e)}.bind(this)),r.call(this)}.bind(this),a(i,"getPrimaryServices error"))}.bind(this))};var l=function(e){this._handle=null,this._services=null,this._characteristics=null,this.device=null,this.uuid=null,this.isPrimary=!1,n(this,e),this.dispatchEvent({type:"serviceadded",bubbles:!0})};l.prototype.getCharacteristic=function(e){return new t(function(t,i){return this.device.gatt.connected?e?void this.getCharacteristics(e).then(function(e){if(1!==e.length)return i("getCharacteristic error: characteristic not found");t(e[0])}).catch(function(e){i(e)}):i("getCharacteristic error: no characteristic specified"):i("getCharacteristic error: device not connected")}.bind(this))},l.prototype.getCharacteristics=function(n){return new t(function(t,i){if(!this.device.gatt.connected)return i("getCharacteristics error: device not connected");function r(){if(!n)return t(this._characteristics);var e=this._characteristics.filter(function(e){return e.uuid===o.getCharacteristicUUID(n)});if(1!==e.length)return i("getCharacteristics error: characteristic not found");t(e)}if(this._characteristics)return r.call(this);u.discoverCharacteristics(this._handle,[],function(e){this._characteristics=e.map(function(e){return e.service=this,new p(e)}.bind(this)),r.call(this)}.bind(this),a(i,"getCharacteristics error"))}.bind(this))},l.prototype.getIncludedService=function(e){return new t(function(t,i){return this.device.gatt.connected?e?void this.getIncludedServices(e).then(function(e){if(1!==e.length)return i("getIncludedService error: service not found");t(e[0])}).catch(function(e){i(e)}):i("getIncludedService error: no service specified"):i("getIncludedService error: device not connected")}.bind(this))},l.prototype.getIncludedServices=function(n){return new t(function(t,i){if(!this.device.gatt.connected)return i("getIncludedServices error: device not connected");function r(){if(!n)return t(this._services);var e=this._services.filter(function(e){return e.uuid===o.getServiceUUID(n)});if(1!==e.length)return i("getIncludedServices error: service not found");t(e)}if(this._services)return r.call(this);u.discoverIncludedServices(this._handle,this.device._allowedServices,function(e){this._services=e.map(function(e){return e.device=this.device,new l(e)}.bind(this)),r.call(this)}.bind(this),a(i,"getIncludedServices error"))}.bind(this))},l.prototype.addEventListener=e(["serviceadded","servicechanged","serviceremoved"]),l.prototype.removeEventListener=c,l.prototype.dispatchEvent=s;var p=function(e){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,n(this,e)};p.prototype.getDescriptor=function(e){return new t(function(t,i){return this.service.device.gatt.connected?e?void this.getDescriptors(e).then(function(e){if(1!==e.length)return i("getDescriptor error: descriptor not found");t(e[0])}).catch(function(e){i(e)}):i("getDescriptor error: no descriptor specified"):i("getDescriptor error: device not connected")}.bind(this))},p.prototype.getDescriptors=function(n){return new t(function(t,i){if(!this.service.device.gatt.connected)return i("getDescriptors error: device not connected");function r(){if(!n)return t(this._descriptors);var e=this._descriptors.filter(function(e){return e.uuid===o.getDescriptorUUID(n)});if(1!==e.length)return i("getDescriptors error: descriptor not found");t(e)}if(this._descriptors)return r.call(this);u.discoverDescriptors(this._handle,[],function(e){this._descriptors=e.map(function(e){return e.characteristic=this,new g(e)}.bind(this)),r.call(this)}.bind(this),a(i,"getDescriptors error"))}.bind(this))},p.prototype.readValue=function(){return new t(function(t,e){if(!this.service.device.gatt.connected)return e("readValue error: device not connected");u.readCharacteristic(this._handle,function(e){this.value=e,t(e),this.dispatchEvent({type:"characteristicvaluechanged",bubbles:!0})}.bind(this),a(e,"readValue error"))}.bind(this))},p.prototype.writeValue=function(n){return new t(function(e,t){if(!this.service.device.gatt.connected)return t("writeValue error: device not connected");var i=n.buffer||n,r=new DataView(i);u.writeCharacteristic(this._handle,r,function(){this.value=r,e()}.bind(this),a(t,"writeValue error"))}.bind(this))},p.prototype.startNotifications=function(){return new t(function(e,t){if(!this.service.device.gatt.connected)return t("startNotifications error: device not connected");u.enableNotify(this._handle,function(e){this.value=e,this.dispatchEvent({type:"characteristicvaluechanged",bubbles:!0})}.bind(this),function(){e(this)}.bind(this),a(t,"startNotifications error"))}.bind(this))},p.prototype.stopNotifications=function(){return new t(function(e,t){if(!this.service.device.gatt.connected)return t("stopNotifications error: device not connected");u.disableNotify(this._handle,function(){e(this)}.bind(this),a(t,"stopNotifications error"))}.bind(this))},p.prototype.addEventListener=e(["characteristicvaluechanged"]),p.prototype.removeEventListener=c,p.prototype.dispatchEvent=s;var g=function(e){this._handle=null,this.characteristic=null,this.uuid=null,this.value=null,n(this,e)};return g.prototype.readValue=function(){return new t(function(t,e){if(!this.characteristic.service.device.gatt.connected)return e("readValue error: device not connected");u.readDescriptor(this._handle,function(e){this.value=e,t(e)}.bind(this),a(e,"readValue error"))}.bind(this))},g.prototype.writeValue=function(n){return new t(function(e,t){if(!this.characteristic.service.device.gatt.connected)return t("writeValue error: device not connected");var i=n.buffer||n,r=new DataView(i);u.writeDescriptor(this._handle,r,function(){this.value=r,e()}.bind(this),a(t,"writeValue error"))}.bind(this))},{_addAdapter:function(e,t){r[e]=t,u=t},requestDevice:function(s){return new t(function(n,e){if(null!==d)return e("requestDevice error: request in progress");if(!s.acceptAllDevices&&!s.deviceFound){if(!s.filters||0===s.filters.length)return e(new TypeError("requestDevice error: no filters specified"));if(s.filters.some(function(e){return 0===Object.keys(e).length}))return e(new TypeError("requestDevice error: empty filter specified"));if(s.filters.some(function(e){return void 0!==e.namePrefix&&""===e.namePrefix}))return e(new TypeError("requestDevice error: empty namePrefix specified"))}var t=[];s.filters&&s.filters.forEach(function(e){e.services&&(t=t.concat(e.services.map(o.getServiceUUID)))}),t=t.filter(function(e,t,i){return i.indexOf(e)===t});var c=!1;u.startScan(t,function(e){var t=[];function i(e){h().then(function(){n(e)})}if(s.filters&&(e=function(e,i,r){var n=!1;return e.filters.forEach(function(e){if(!e.name||e.name===i.name){if(e.namePrefix){if(!i.name||e.namePrefix.length>i.name.length)return;if(e.namePrefix!==i.name.substr(0,e.namePrefix.length))return}if(e.services){var t=e.services.map(o.getServiceUUID);if(!t.every(function(e){return-1<i.uuids.indexOf(e)}))return;r=r.concat(t)}n=!0}}),!!n&&i}(s,e,t)),e){c=!0,s.optionalServices&&(t=t.concat(s.optionalServices.map(o.getServiceUUID))),e._allowedServices=t.filter(function(e,t,i){return i.indexOf(e)===t});var r=new f(e);s.deviceFound&&!s.deviceFound(r,function(){i(r)})||i(r)}},function(){d=setTimeout(function(){h().then(function(){c||e("requestDevice error: no devices found")})},s.scanTime||10240)},a(e,"requestDevice error"))})},cancelRequest:h}}); /* @license * * BLE Abstraction Tool: Evothings BLE plugin adapter * * The MIT License (MIT) * * Copyright (c) 2016 Rob Moran * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ !function(t,n){"function"==typeof define&&define.amd?define(["bleat","bluetooth.helpers"],n.bind(this,t)):"object"==typeof exports?module.exports=function(e){return n(t,e,require("./bluetooth.helpers"))}:n(t,t.bleat,t.bleatHelpers)}(this,function(t,e,f){"use strict";if(e._addAdapter){var o={},r={},c={},u={},s={},d={};e._addAdapter("evothings",o),o.startScan=function(e,t,n,a){i(function(){evothings.ble.stopScan(),evothings.ble.startScan(e,function(e){t&&t(function(e){var t={};t._handle=e.address,t.id=e.address,t.name=e.name,t.uuids=[],t.adData={},t.adData.rssi=e.rssi,t.adData.txPower=null,t.adData.serviceData={},t.adData.manufacturerData=null,e.advertisementData?function(e,t){if(e.advertisementData){if(e.advertisementData.kCBAdvDataLocalName&&(t.name=e.advertisementData.kCBAdvDataLocalName),e.advertisementData.kCBAdvDataTxPowerLevel&&(t.adData.txPower=e.advertisementData.kCBAdvDataTxPowerLevel),e.advertisementData.kCBAdvDataServiceUUIDs&&e.advertisementData.kCBAdvDataServiceUUIDs.forEach(function(e){t.uuids.push(f.getCanonicalUUID(e))}),e.advertisementData.kCBAdvDataServiceData)for(var n in e.advertisementData.kCBAdvDataServiceData){var a=e.advertisementData.kCBAdvDataServiceData[n];t.adData.serviceData[f.getCanonicalUUID(n)]=g(D(a))}e.advertisementData.kCBAdvDataManufacturerData&&(t.adData.manufacturerDataRaw=e.advertisementData.kCBAdvDataManufacturerData)}}(e,t):e.scanRecord&&function(e,t){var n=D(e.scanRecord),a=0;for(;a<n.length;){var i=n[a++];if(0===i)break;i-=1;var r,o=n[a++];if(8===o||9===o)t.name=evothings.ble.fromUtf8(new Uint8Array(n.buffer,a,i)).replace("\0","");else if(10===o)t.adData.txPower=h(n,a);else if(2===o||3===o)for(r=0;r<i;r+=2)t.uuids.push(f.getCanonicalUUID((((s=n)[(d=a+r)+1]<<8)+s[d]).toString(16)));else if(4===o||5===o)for(r=0;r<i;r+=4)t.uuids.push(f.getCanonicalUUID((((c=n)[(u=a+r)+3]<<24)+(c[u+2]<<16)+(c[u+1]<<8)+c[u]).toString(16)));else if(6===o||7===o)for(r=0;r<i;r+=16)t.uuids.push(f.getCanonicalUUID(p(n,a+r)));a+=i}var c,u;var s,d}(e,t);return t}(e))},function(e){a&&a(e)}),n&&n()})},o.stopScan=function(e){i(function(){evothings.ble.stopScan()})},o.connect=function(t,n,a,i){r[t]?i&&i("device already connected"):evothings.ble.connect(t,function(e){2===e.state&&n?(r[t]=e.deviceHandle,n()):0===e.state&&a&&(v(t),a())},function(e){i&&i(e)})},o.disconnect=function(e,t){v(e)},o.discoverServices=function(e,a,t,n){var i=function(e,t){var n=r[e];if(n)return n;t&&t("Device does not exist for device id: "+e);return null}(e,n);i&&evothings.ble.services(i,function(e){var n=[];e.forEach(function(e){var t=f.getCanonicalUUID(e.uuid);(!a||0===a.length||0<=a.indexOf(t))&&(c[e.handle]=i,n.push({_handle:e.handle,uuid:t,primary:!0}))}),t&&t(n)},function(e){n&&n(e)})},o.discoverIncludedServices=function(e,t,n,a){n([])},o.discoverCharacteristics=function(e,a,t,n){var i=function(e,t){var n=c[e];if(n)return n;t&&t("Device does not exist for service handle: "+e);return null}(e,n);i&&evothings.ble.characteristics(i,e,function(e){var n=[];e.forEach(function(e){var t=f.getCanonicalUUID(e.uuid);(!a||0===a.length||0<=a.indexOf(t))&&(u[e.handle]=i,n.push({_handle:e.handle,uuid:t,properties:{broadcast:1&e.property,read:2&e.property,writeWithoutResponse:4&e.property&&1&e.writeType,write:8&e.property,notify:16&e.property,indicate:32&e.property,authenticatedSignedWrites:64&e.property&&4&e.writeType,reliableWrite:!1,writableAuxiliaries:!1}}))}),t&&t(n)},function(e){n&&n(e)})},o.discoverDescriptors=function(a,i,t,n){var r=l(a,n);r&&evothings.ble.descriptors(r,a,function(e){var n=[];e.forEach(function(e){var t=f.getCanonicalUUID(e.uuid);"00002902-0000-1000-8000-00805f9b34fb"===t&&(d[a]=e.handle),(!i||0===i.length||0<=i.indexOf(t))&&(s[e.handle]=r,n.push({_handle:e.handle,uuid:t}))}),t&&t(n)},function(e){n&&n(e)})},o.readCharacteristic=function(e,t,n){var a=l(e,n);a&&evothings.ble.readCharacteristic(a,e,function(e){t&&t(g(e))},function(e){n&&n(e)})},o.writeCharacteristic=function(e,t,n,a){var i=l(e,a);i&&evothings.ble.writeCharacteristic(i,e,t,function(){n&&n()},function(e){a&&a(e)})},o.enableNotify=function(e,t,n,a){var i=l(e,a);i&&function(t,n,a,i){var e=d[n];e?r(e):o.discoverDescriptors(n,"00002902-0000-1000-8000-00805f9b34fb",function(e){var t=d[n];t?r(t):i("Could not find CCCD for characteristic: "+n)},function(e){i(e)});function r(e){evothings.ble.writeDescriptor(t,e,new Uint8Array([1,0]),function(){a()},function(e){i(e)})}}(i,e,function(){evothings.ble.enableNotification(i,e,function(e){t&&t(g(e))},function(e){a&&a(e)}),n&&n()},function(e){a&&a(e)})},o.disableNotify=function(e,t,n){var a=l(e,n);a&&(evothings.ble.disableNotification(a,e,function(){t&&t()},function(e){n&&n(e)}),"ios"===b()&&setTimeout(t,0))},o.readDescriptor=function(e,t,n){var a=getDeviceHandleFromDescriptorHandle(e,n);a&&evothings.ble.readDescriptor(a,e,function(e){t&&t(g(e))},function(e){n&&n(e)})},o.writeDescriptor=function(e,t,n,a){var i=getDeviceHandleFromDescriptorHandle(e,a);i&&evothings.ble.writeDescriptor(i,e,t,function(){n&&n()},function(e){a&&a(e)})}}function i(e){t.evothings&&evothings.ble?e():document.addEventListener("deviceready",e)}function v(e){var t=r[e];t&&(evothings.ble.close(t),delete r[e],n(t,c),n(t,u,!0),n(t,s))}function n(e,t,n){for(var a in t)e===t[a]&&(delete t[a],n&&d[a]&&delete d[a])}function l(e,t){var n=u[e];return n||(t&&t("Device does not exist for characteristic handle: "+e),null)}function D(e,t){for(var n,a,i,r=e.replace(/[^A-Za-z0-9\+\/]/g,""),o=r.length,c=t?Math.ceil((3*o+1>>2)/t)*t:3*o+1>>2,u=new Uint8Array(c),s=0,d=0,f=0;f<o;f++)if(a=3&f,s|=(64<(i=r.charCodeAt(f))&&i<91?i-65:96<i&&i<123?i-71:47<i&&i<58?i+4:43===i?62:47===i?63:0)<<18-6*a,3==a||o-f==1){for(n=0;n<3&&d<c;n++,d++)u[d]=s>>>(16>>>n&24)&255;s=0}return u}function h(e,t){var n=e[t];return 128&n&&(n-=256),n}function p(e,t){for(var n="",a=0;a<16;a++)n+=("00"+e[t+a].toString(16)).slice(-2);return n}function g(e){var t=new Uint8Array(e).buffer;return new DataView(t)}function b(){return t.cordova?t.cordova.platformId:null}});