UNPKG

bleat

Version:

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

81 lines 19.9 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 - classic specification * * 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,i){"function"==typeof define&&define.amd?define(["bluetooth.helpers"],i):"object"==typeof exports?module.exports=i(require("./bluetooth.helpers")):t.bleat=i(t.bleatHelpers)}(this,function(t){"use strict";var c=null,e={};function s(i,e){return function(t){i&&i(e+": "+t)}}function n(i){return function(){if("function"==typeof i){var t=[].slice.call(arguments);i.apply(this,t)}}}function r(i,t){var e=0,r=!1;this.addCallback=function(t){return e++,r=!0,function(){t&&t.apply(null,arguments),0==--e&&i&&i()}},this.error=function(){t&&t.apply(null,arguments),0==--e&&i&&i()},this.finish=function(){!r&&i&&i()}}function d(t){this._handle=t._handle,this.address=t._handle,this.name=t.name,this.serviceUUIDs=t.uuids,this.adData=t.adData,this.connected=!1,this.services={}}d.prototype.hasService=function(i){return this.serviceUUIDs.some(function(t){return t===i})},d.prototype.connect=function(t,i,e,r){c.connect(this._handle,function(){if(this.connected=!0,"boolean"==typeof e&&(r=e,e=null),r)return n(t)();this.discoverAll(t,e)}.bind(this),function(){this.connected=!1,this.services={},n(i)()}.bind(this),s(e,"connect error"))},d.prototype.disconnect=function(t){c.disconnect(this._handle,s(t,"disconnect error"))},d.prototype.discoverServices=function(t,i,e){if(!1===this.connected)return s(e,"discovery error")("device not connected");"function"==typeof t?(i=t,t=[]):"string"==typeof t&&(t=[t]),c.discoverServices(this._handle,t,function(t){t.forEach(function(t){this.services[t.uuid]=new o(t)},this),i&&i()}.bind(this),s(e,"service discovery error"))},d.prototype.discoverAll=function(t,i){if(!1===this.connected)return s(i,"discovery error")("device not connected");var e=new r(t,i);this.discoverServices(e.addCallback(function(){Object.keys(this.services).forEach(function(t){var i=this.services[t];i.discoverIncludedServices(e.addCallback(),e.error),i.discoverCharacteristics(e.addCallback(function(){Object.keys(i.characteristics).forEach(function(t){i.characteristics[t].discoverDescriptors(e.addCallback(),e.error)},this)}.bind(this)),e.error)},this)}.bind(this)),e.error),e.finish()};var o=function(t){this._handle=t._handle,this.uuid=t.uuid,this.primary=t.primary,this.includedServices={},this.characteristics={}};o.prototype.discoverIncludedServices=function(t,i,e){"function"==typeof t?(i=t,t=[]):"string"==typeof t&&(t=[t]),c.discoverIncludedServices(this._handle,t,function(t){t.forEach(function(t){this.includedServices[t.uuid]=new o(t)},this),i&&i()}.bind(this),s(e,"included service discovery error"))},o.prototype.discoverCharacteristics=function(t,i,e){"function"==typeof t?(i=t,t=[]):"string"==typeof t&&(t=[t]),c.discoverCharacteristics(this._handle,t,function(t){t.forEach(function(t){this.characteristics[t.uuid]=new a(t)},this),i&&i()}.bind(this),s(e,"characteristic discovery error"))};var a=function(t){this._handle=t._handle,this.uuid=t.uuid,this.properties=t.properties,this.descriptors={}};a.prototype.discoverDescriptors=function(t,i,e){"function"==typeof t?(i=t,t=[]):"string"==typeof t&&(t=[t]),c.discoverDescriptors(this._handle,t,function(t){t.forEach(function(t){this.descriptors[t.uuid]=new h(t)},this),i&&i()}.bind(this),s(e,"descriptor discovery error"))},a.prototype.read=function(t,i){c.readCharacteristic(this._handle,n(t),s(i,"read characteristic error"))},a.prototype.write=function(t,i,e){c.writeCharacteristic(this._handle,t,n(i),s(e,"write characteristic error"))},a.prototype.enableNotify=function(t,i,e){c.enableNotify(this._handle,n(t),n(i),s(e,"enable notify error"))},a.prototype.disableNotify=function(t,i){c.disableNotify(this._handle,n(t),s(i,"disable notify error"))};var h=function(t){this._handle=t._handle,this.uuid=t.uuid};return h.prototype.read=function(t,i){c.readDescriptor(this._handle,n(t),s(i,"read descriptor error"))},h.prototype.write=function(t,i,e){c.writeDescriptor(this._handle,t,n(i),s(e,"write descriptor error"))},{_addAdapter:function(t,i){e[t]=i,c=i},startScan:function(t,e,i,r,n){"function"==typeof t?(n=r,r=i,i=e,e=t,t=[]):"string"==typeof t&&(t=[t]),c.stopScan(s(r,"stop scan error"));var o={};c.startScan(t,function(t){var i=new d(t);o[i.address]&&!n||(o[i.address]=i,e&&e(i))}.bind(this),i,s(r,"scan error"))},stopScan:function(t){c.stopScan(s(t,"stop scan error"))}}}); /* @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}});