@nebulae/angular-ble
Version:
A Web Bluetooth (Bluetooth Low Energy) module for angular (v2+)
2 lines • 18.7 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@angular/core"),require("aes-js"),require("rxjs/operators"),require("rxjs"),require("@angular/common")):"function"==typeof define&&define.amd?define("@nebulae/angular-ble",["exports","@angular/core","aes-js","rxjs/operators","rxjs","@angular/common"],t):t((e.nebulae=e.nebulae||{},e.nebulae["angular-ble"]={}),e.ng.core,null,e.rxjs.operators,e.rxjs,e.ng.common)}(this,function(e,o,l,c,a,r){"use strict";var s=function(){function e(){this._ble=navigator.bluetooth,this._ble||console.log("error cargando bluetooth")}return e.prototype.requestDevice=function(e){return this._ble.requestDevice(e)},e.decorators=[{type:o.Injectable}],e.ctorParameters=function(){return[]},e}(),u=function(e,t){return(u=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])})(e,t)};var p={GENERIC_ACCESS:{SERVICE:"generic_access",DEVICE_NAME:"device_name",APPEARANCE:"appearance",PRIVACY_FLAG:"privacy_flag",RECONNECTION_ADDRESS:"reconnection_address",PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS:"peripheral_preferred_connection_parameters"},BATTERY:{SERVICE:"battery_service",BATTERY_LEVEL:"battery_level"},DEVICE_INFORMATION:{SERVICE:"device_information",MANUFACTURER_NAME:"manufacturer_name_string",MODEL_NUMBER:"model_number_string",SERIAL_NUMBER:"serial_number_string",HARDWARE_REVISION:"hardware_revision_string",FIRMWARE_REVISION:"firmware_revision_string",SOFTWARE_REVISION:"software_revision_string",SYSTEM_ID:"system_id",PNP_ID:"pnp_id"}},t=(Object.keys(p).map(function(e){return p[e].SERVICE}),function(){function e(){this.masterKey=[],this.initialVector=[],this.encryptMethod="CBC",this.isStaticInitialVector=!0,this.isConfigExecuted=!1}return e.prototype.config=function(e,t,r,n,i){void 0===t&&(t=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),void 0===r&&(r="CBC"),void 0===n&&(n={}),void 0===i&&(i=!0),this.isConfigExecuted=!0,this.masterKey=e,this.initialVector=t,this.encryptMethod=r,this.isStaticInitialVector=i,this.additionalEncryptMethodParams=n,i||(this.enctrypMethodInstance=this.generateEncryptMethodInstance())},e.prototype.encrypt=function(e){if(!this.isConfigExecuted)throw new Error("Must configurate cypher-aes before call this method, use the method config()");return"CBC"!==this.encryptMethod&&"ECB"!==this.encryptMethod||(e=this.addPadding(e)),this.isStaticInitialVector?this.generateEncryptMethodInstance().encrypt(e):this.enctrypMethodInstance.encrypt(e)},e.prototype.decrypt=function(e){if(!this.isConfigExecuted)throw new Error("Must configurate cypher-aes before call this method, use the method config()");return this.isStaticInitialVector?this.generateEncryptMethodInstance().decrypt(e):this.enctrypMethodInstance.decrypt(e)},e.prototype.changeInitialVector=function(e){this.isStaticInitialVector||(this.enctrypMethodInstance=this.generateEncryptMethodInstance()),this.initialVector=e},e.prototype.changeEncryptMethod=function(e){this.isStaticInitialVector||(this.enctrypMethodInstance=this.generateEncryptMethodInstance()),this.encryptMethod=e},e.prototype.changeStaticInitialVector=function(e){e||(this.enctrypMethodInstance=this.generateEncryptMethodInstance()),this.isStaticInitialVector=e},e.prototype.changeMasterKey=function(e){this.isStaticInitialVector||(this.enctrypMethodInstance=this.generateEncryptMethodInstance()),this.masterKey=e},e.prototype.addPadding=function(e){var t=16*Math.ceil(Array.from(e).length/16),r=new Array(t-Array.from(e).length).fill(0);return new Uint8Array(Array.from(e).concat(r))},e.prototype.generateEncryptMethodInstance=function(){var e;switch(this.encryptMethod){case"CBC":e=new l.ModeOfOperation.cbc(this.masterKey,this.initialVector);break;case"CTR":if(!this.additionalEncryptMethodParams.counter)throw new Error("additionalEncryptMethodParams.counter is required to use encrypt method CTR");e=new l.ModeOfOperation.ctr(this.masterKey,this.initialVector,new l.Counter(this.additionalEncryptMethodParams.counter));break;case"CFB":if(!this.additionalEncryptMethodParams.segmentSize)throw new Error("additionalEncryptMethodParams.segmentSize is required to use encrypt method CFB");e=new l.ModeOfOperation.cfb(this.masterKey,this.initialVector,this.additionalEncryptMethodParams.segmentSize);break;case"OFB":e=new l.ModeOfOperation.ofb(this.masterKey,this.initialVector);break;case"ECB":e=new l.ModeOfOperation.ecb(this.masterKey)}return e},e.prototype.textToBytes=function(e){return l.utils.utf8.toBytes(e)},e.prototype.bytesToText=function(e){return l.utils.utf8.fromBytes(e)},e.prototype.bytesTohex=function(e){return l.utils.hex.fromBytes(e)},e.prototype.hexToBytes=function(e){return l.utils.hex.toBytes(e)},e.prototype.generateSubkeys=function(e){var t=new Uint8Array(16),r=new Buffer("00000000000000000000000000000087","hex"),n=new l.ModeOfOperation.cbc(e,new Uint8Array(16)).encrypt(t),i=new Buffer(this.bytesTohex(n),"hex"),o=this.bitShiftLeft(i);128&i[0]&&(o=this.xor(o,r));var c=this.bitShiftLeft(o);return 128&o[0]&&(c=this.xor(c,r)),{subkey1:o,subkey2:c}},e.prototype.aesCmac=function(e,t){console.log("INICIA CIFRADO!!!!!!!!!!!!!!!!");var r,n,i,o=this.generateSubkeys(e),c=Math.ceil(t.length/16);r=0===c?!(c=1):t.length%16==0,i=c-1,n=r?this.xor(this.getMessageBlock(t,i),o.subkey1):this.xor(this.getPaddedMessageBlock(t,i),o.subkey2);for(var a,s,u=new Buffer("00000000000000000000000000000000","hex"),p=0;p<i;p++){s=new l.ModeOfOperation.cbc(e,new Uint8Array(16)),a=this.xor(u,this.getMessageBlock(t,p));var f=s.encrypt(a);console.log("X normal ===============> ",this.bytesTohex(a)),console.log("X encrypted ==============> ",this.bytesTohex(f)),u=new Buffer(this.bytesTohex(f),"hex")}a=this.xor(n,u);var h=(s=new l.ModeOfOperation.cbc(e,new Uint8Array(16))).encrypt(a);return console.log("Y normal ==============> ",this.bytesTohex(a)),console.log("Y encrypted ==============> ",this.bytesTohex(h)),h},e.prototype.getMessageBlock=function(e,t){for(var r=new Buffer(16),n=16*t,i=n+16,o=0,c=n;c<i;c++)r[o]=e[c],o++;return r},e.prototype.getPaddedMessageBlock=function(e,t){var r=new Buffer(16),n=16*t,i=e.length;r.fill(0);for(var o=0,c=n;c<i;c++)r[o]=e[c],o++;return r[i-n]=128,r},e.prototype.bitShiftLeft=function(e){for(var t=new Buffer(e.length),r=e.length-1,n=0;n<r;n++)t[n]=e[n]<<1,128&e[n+1]&&(t[n]+=1);return t[r]=e[r]<<1,t},e.prototype.xor=function(e,t){for(var r=Math.min(e.length,t.length),n=new Buffer(r),i=0;i<r;i++)n[i]=e[i]^t[i];return n},e.decorators=[{type:o.Injectable,args:[{providedIn:"root"}]}],e.ctorParameters=function(){return[]},e.ngInjectableDef=o.defineInjectable({factory:function(){return new e},token:e,providedIn:"root"}),e}()),f=function(){function e(){}return e.prototype.log=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];console.log.apply(console,e)},e.prototype.error=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];console.error.apply(console,e)},e.prototype.warn=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];console.warn.apply(console,e)},e.decorators=[{type:o.Injectable,args:[{providedIn:"root"}]}],e.ngInjectableDef=o.defineInjectable({factory:function(){return new e},token:e,providedIn:"root"}),e}(),n=function(){function e(){}return e.prototype.log=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t]},e.prototype.error=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t]},e.prototype.warn=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t]},e.decorators=[{type:o.Injectable,args:[{providedIn:"root"}]}],e.ngInjectableDef=o.defineInjectable({factory:function(){return new e},token:e,providedIn:"root"}),e}(),i=function(i){function e(e,t,r){var n=i.call(this)||this;return n._webBle=e,n.cypherAesService=t,n._console=r,n.serviceCharacteristicVsSubscriptionList={},n.notifierSubject=new a.Subject,n.notifierStartedSubject=new a.Subject,n.bluetoothAvailable=!1,n._device$=new o.EventEmitter,e._ble&&(n.bluetoothAvailable=!0),n}return function n(e,t){function r(){this.constructor=e}u(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}(e,i),e.prototype.isBluetoothAvailable=function(){return this.bluetoothAvailable},e.prototype.getDevice$=function(){return this._device$},e.prototype.getNotifierStartedSubject$=function(){return this.notifierStartedSubject},e.prototype.startNotifierListener$=function(t,r,e){var n=this;return a.defer(function(){return a.of(t).pipe(c.tap(function(){return n._console.log("Inicia el notifier con la instancia: ",n.serviceCharacteristicVsSubscriptionList)}),c.filter(function(e){return-1===Object.keys(n.serviceCharacteristicVsSubscriptionList).indexOf(t+"-"+r)})).subscribe(function(){n.serviceCharacteristicVsSubscriptionList[t+"-"+r]=n.buildNotifierListener$(t,r,e).subscribe(function(e){n.notifierSubject.next(e)})},function(e){n._console.log("[BLE::Info] Error in notifier: ",e)},function(){}),a.of("notifier as subscribed: service= "+t+", characteristic= "+r)})},e.prototype.stopNotifierListener$=function(e,t){var r=this;return a.defer(function(){return delete r.serviceCharacteristicVsSubscriptionList[e+"-"+t],a.of("the notifier of the characteristic "+t+" as been stopped")})},e.prototype.buildNotifierListener$=function(e,r,n){var i=this;return this.getPrimaryService$(e).pipe(c.tap(function(e){return i._console.log("toma exitosamente el servicio ================> "+e)}),c.mergeMap(function(e){return i.getCharacteristic$(e,r).pipe(c.tap(function(e){return i._console.log("toma exitosamente la caracteristica ================> "+e)}))}),c.mergeMap(function(t){return a.defer(function(){return t.startNotifications()}).pipe(c.retryWhen(function(e){return e.pipe(c.tap(function(){return i._console.log("ERROR EN EL startNotifications ================> ")}),c.delay(1e3),c.take(5))}),c.tap(function(){i.notifierStartedSubject.next(!0),i._console.log("incia las notifiaciones de la caracteristica 2 ================> "+r)}),c.mergeMap(function(e){return a.fromEvent(t,"characteristicvaluechanged").pipe(c.takeUntil(a.fromEvent(t,"gattserverdisconnected")),c.map(function(e){return{startByteMatches:!1,stopByteMatches:!1,lengthMatches:!1,messageLength:0,timestamp:Date.now(),data:Array.from(new Uint8Array(e.target.value.buffer))}}),c.scan(function(e,t){return e.timestamp=0===e.timestamp?t.timestamp:e.timestamp,(e.lengthMatches&&e.startByteMatches&&e.stopByteMatches||e.timestamp+1e3<Date.now())&&(e={startByteMatches:!1,stopByteMatches:!1,lengthMatches:!1,messageLength:0,timestamp:0,data:[]}),e.startByteMatches||t.data[0]!==n.startByte||(e.messageLength=new DataView(new Uint8Array(t.data.slice(n.lengthPosition.start,n.lengthPosition.end)).buffer).getInt16(0,!1)+(n.lengthPosition.lengthPadding?n.lengthPosition.lengthPadding:0),e.startByteMatches=!0),e.stopByteMatches||t.data[t.data.length-1]!==n.stopByte||(e.stopByteMatches=!0),e.startByteMatches&&(e.data=e.data.concat(t.data)),e.lengthMatches=e.startByteMatches&&e.stopByteMatches&&e.messageLength===e.data.length,e},{startByteMatches:!1,stopByteMatches:!1,lengthMatches:!1,messageLength:0,timestamp:0,data:[]}),c.filter(function(e){return e.lengthMatches&&e.startByteMatches&&e.stopByteMatches}),c.map(function(e){return e.data}))}))}))},e.prototype.sendAndWaitResponse$=function(e,t,r,n,i){return this._console.log("[BLE::Info] Send message to device: ",this.cypherAesService.bytesTohex(e)),a.forkJoin(this.subscribeToNotifierListener(n,i).pipe(c.take(1)),this.sendToNotifier$(e,t,r)).pipe(c.map(function(e){var t=function s(e,t){var r="function"==typeof Symbol&&e[Symbol.iterator];if(!r)return e;var n,i,o=r.call(e),c=[];try{for(;(void 0===t||0<t--)&&!(n=o.next()).done;)c.push(n.value)}catch(a){i={error:a}}finally{try{n&&!n.done&&(r=o["return"])&&r.call(o)}finally{if(i)throw i.error}}return c}(e,2),r=t[0];t[1];return r}),c.timeout(3e3))},e.prototype.subscribeToNotifierListener=function(u,i){var o=this;return this.notifierSubject.pipe(c.map(function(e){var t=e;if(i){var r=new DataView(new Uint8Array(t.slice(1,3)).buffer).getInt16(0,!1);o.cypherAesService.config(i);var n=Array.from(o.cypherAesService.decrypt(e.slice(3,r+3)));t=e.slice(0,3).concat(n).concat(e.slice(-2))}return o._console.log("[BLE::Info] Notification reived from device: ",o.cypherAesService.bytesTohex(t)),t}),c.filter(function(e){var t,r,n=!1;try{for(var i=function a(e){var t="function"==typeof Symbol&&e[Symbol.iterator],r=0;return t?t.call(e):{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}}}(u),o=i.next();!o.done;o=i.next()){var c=o.value;if(e[c.position]!==c.byteToMatch){n=!1;break}n=!0}}catch(s){t={error:s}}finally{try{o&&!o.done&&(r=i["return"])&&r.call(i)}finally{if(t)throw t.error}}return n}))},e.prototype.discoverDevice$=function(e){var t=this;return void 0===e&&(e={}),a.defer(function(){return t._webBle.requestDevice(e)}).pipe(c.mergeMap(function(e){return t.device=e,t._device$.emit(e),t.configureDeviceDisconnection$(e).pipe(c.mapTo(e))}))},e.prototype.configureDeviceDisconnection$=function(r){var n=this;return a.Observable.create(function(t){a.of(r).pipe(c.mergeMap(function(e){return a.fromEvent(r,"gattserverdisconnected")}),c.take(1)).subscribe(function(){n._console.log("Se desconecta disp en OnDevice disconnected!!!!!!!"),n.device=null,n._device$.emit(null)},function(e){n._console.log("[BLE::Info] Error in notifier: ",e),t.error(e)},function(){}),t.next("DisconnectionEvent as been register")})},e.prototype.connectDevice$=function(e){return e?e.optionalServices||(e.optionalServices=[]):e={acceptAllDevices:!0,optionalServices:[]},e.optionalServices.push(p.GENERIC_ACCESS.SERVICE),e.optionalServices.push(p.BATTERY.SERVICE),e.optionalServices.push(p.DEVICE_INFORMATION.SERVICE),this.discoverDevice$(e).pipe(c.mergeMap(function(e){return a.defer(function(){return e.gatt.connect()})}))},e.prototype.disconnectDevice=function(){this.device&&(this._console.log("se deconecta dispositivo"),this.device.gatt.disconnect())},e.prototype.readDeviceValue$=function(e,t){var r=this;if(!this.device)throw new Error("Must start a connection to a device before read the device value");return this.getPrimaryService$(e).pipe(c.mergeMap(function(e){return r.getCharacteristic$(e,t)}),c.mergeMap(function(e){return r.readValue$(e)}))},e.prototype.writeDeviceValue$=function(e,t,r){var n=this;if(!this.device)throw new Error("Must start a connection to a device before read the device value");return this.getPrimaryService$(e).pipe(c.mergeMap(function(e){return n.getCharacteristic$(e,t)}),c.mergeMap(function(e){return n.writeValue$(e,r)}))},e.prototype.getPrimaryService$=function(t){return a.of(this.device).pipe(c.mergeMap(function(e){return e.gatt.getPrimaryService(t)}))},e.prototype.getCharacteristic$=function(e,t){return a.defer(function(){return e.getCharacteristic(t)})},e.prototype.readValue$=function(e){return a.from(e.readValue().then(function(e){return Promise.resolve(e)},function(e){return Promise.reject(""+e.message)}))},e.prototype.writeValue$=function(e,t){return a.defer(function(){return e.writeValue(t)})},e.prototype.enableCharacteristic$=function(e,t,r){return r=r||new Uint8Array([1]),this.setCharacteristicState$(e,t,r)},e.prototype.disbaleCharacteristic$=function(e,t,r){return r=r||new Uint8Array([0]),this.setCharacteristicState$(e,t,r)},e.prototype.setCharacteristicState$=function(e,t,r){var n=this;return this.getPrimaryService$(e).pipe(c.mergeMap(function(e){return n.getCharacteristic$(e,t)}),c.map(function(e){return n.writeValue$(e,r)}))},e.prototype.sendToNotifier$=function(r,e,t){var n=this;return this.getPrimaryService$(e).pipe(c.mergeMap(function(e){return n.getCharacteristic$(e,t)}),c.mergeMap(function(e){if(16<r.length){for(var t=a.of(undefined);16<r.length;)t=t.pipe(c.concat(n.writeValue$(e,r.slice(0,16)))),r=r.slice(16,r.length);return 0<r.length&&(t=t.pipe(c.concat(n.writeValue$(e,r)))),t}return n.writeValue$(e,r)}))},e.prototype.getBatteryLevel$=function(){return this.readDeviceValue$(p.BATTERY.SERVICE,p.BATTERY.BATTERY_LEVEL).pipe(c.map(function(e){return e.getUint8(0)}))},e.prototype.getManufacturerName$=function(){var t=this;return this.readDeviceValue$(p.DEVICE_INFORMATION.SERVICE,p.DEVICE_INFORMATION.MANUFACTURER_NAME).pipe(c.map(function(e){return t.cypherAesService.bytesToText(new Uint8Array(e.buffer))}))},e.prototype.getModelNumber$=function(){var t=this;return this.readDeviceValue$(p.DEVICE_INFORMATION.SERVICE,p.DEVICE_INFORMATION.MODEL_NUMBER).pipe(c.map(function(e){return t.cypherAesService.bytesToText(new Uint8Array(e.buffer))}))},e.prototype.getSerialNumber$=function(){var t=this;return this.readDeviceValue$(p.DEVICE_INFORMATION.SERVICE,p.DEVICE_INFORMATION.SERIAL_NUMBER).pipe(c.map(function(e){return t.cypherAesService.bytesToText(new Uint8Array(e.buffer))}))},e.prototype.getHardwareRevision$=function(){var t=this;return this.readDeviceValue$(p.DEVICE_INFORMATION.SERVICE,p.DEVICE_INFORMATION.HARDWARE_REVISION).pipe(c.map(function(e){return t.cypherAesService.bytesToText(new Uint8Array(e.buffer))}))},e.prototype.getFirmwareRevision$=function(){var t=this;return this.readDeviceValue$(p.DEVICE_INFORMATION.SERVICE,p.DEVICE_INFORMATION.FIRMWARE_REVISION).pipe(c.map(function(e){return t.cypherAesService.bytesToText(new Uint8Array(e.buffer))}))},e.prototype.getSoftwareRevision$=function(){var t=this;return this.readDeviceValue$(p.DEVICE_INFORMATION.SERVICE,p.DEVICE_INFORMATION.SOFTWARE_REVISION).pipe(c.map(function(e){return t.cypherAesService.bytesToText(new Uint8Array(e.buffer))}))},e.prototype.getSystemId$=function(){return this.readDeviceValue$(p.DEVICE_INFORMATION.SERVICE,p.DEVICE_INFORMATION.SYSTEM_ID)},e.prototype.getPnpId$=function(){return this.readDeviceValue$(p.DEVICE_INFORMATION.SERVICE,p.DEVICE_INFORMATION.PNP_ID)},e.decorators=[{type:o.Injectable,args:[{providedIn:"root"}]}],e.ctorParameters=function(){return[{type:s},{type:t},{type:f}]},e.ngInjectableDef=o.defineInjectable({factory:function(){return new e(o.inject(s),o.inject(t),o.inject(f))},token:e,providedIn:"root"}),e}(a.Subject);function h(){return new s}function y(e){return e&&e.enableTracing?new f:new n}function d(){return new o.InjectionToken("AWBOptions")}var g=function(){function t(){}return t.forRoot=function(e){return void 0===e&&(e={}),{ngModule:t,providers:[i,{provide:s,useFactory:h},{provide:d,useValue:e},{provide:f,useFactory:y,deps:[d]}]}},t.decorators=[{type:o.NgModule,args:[{imports:[r.CommonModule]}]}],t}();e.BrowserWebBluetooth=s,e.browserWebBluetooth=h,e.consoleLoggerServiceConfig=y,e.makeMeTokenInjector=d,e.AngularBleModule=g,e.CypherAesService=t,e.BluetoothService=i,e.ɵa=f,Object.defineProperty(e,"__esModule",{value:!0})});
//# sourceMappingURL=nebulae-angular-ble.umd.min.js.map