react-native-bluetooth-obd-manager
Version:
A React Native hook library to manage Bluetooth Low Energy connections and communication with ELM327 OBD-II adapters.
2 lines • 23.8 kB
JavaScript
var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.useBluetooth=void 0;var _toConsumableArray2=_interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));var _asyncToGenerator2=_interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));var _react=require("react");var _reactNative=require("react-native");var _reactNativeBleManager=_interopRequireDefault(require("react-native-ble-manager"));var Permissions=_interopRequireWildcard(require("react-native-permissions"));var _BluetoothContext=require("../context/BluetoothContext");var _BluetoothProvider=require("../context/BluetoothProvider");var _constants=require("../constants");function _getRequireWildcardCache(e){if("function"!=typeof WeakMap)return null;var r=new WeakMap(),t=new WeakMap();return(_getRequireWildcardCache=function _getRequireWildcardCache(e){return e?t:r;})(e);}function _interopRequireWildcard(e,r){if(!r&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=_getRequireWildcardCache(r);if(t&&t.has(e))return t.get(e);var n={__proto__:null},a=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in e)if("default"!==u&&{}.hasOwnProperty.call(e,u)){var i=a?Object.getOwnPropertyDescriptor(e,u):null;i&&(i.get||i.set)?Object.defineProperty(n,u,i):n[u]=e[u];}return n.default=e,t&&t.set(e,n),n;}function createDeferredPromise(){var resolveFn;var rejectFn;var promise=new Promise(function(resolve,reject){resolveFn=resolve;rejectFn=reject;});return{promise:promise,resolve:resolveFn,reject:rejectFn};}var handleError=function handleError(error){if(error instanceof Error){return error;}if(typeof error==='object'&&error!==null&&'errorCode'in error&&'message'in error){return new Error(`BLE Error (${error.errorCode}): ${error.message}`);}return new Error(String(error));};var handleStateError=function handleStateError(error){if(!error){return new Error('An unknown error occurred');}return handleError(error);};var useBluetooth=exports.useBluetooth=function useBluetooth(){var state=(0,_BluetoothContext.useBluetoothState)();var dispatch=(0,_BluetoothContext.useBluetoothDispatch)();var _useInternalCommandCo=(0,_BluetoothProvider.useInternalCommandControl)(),currentCommandRef=_useInternalCommandCo.currentCommandRef;var scanPromiseRef=(0,_react.useRef)(null);var connectPromiseRef=(0,_react.useRef)(null);var disconnectPromiseRef=(0,_react.useRef)(null);var checkPermissions=(0,_react.useCallback)((0,_asyncToGenerator2.default)(function*(){console.info('[useBluetooth] Checking permissions...');var requiredPermissions=[];if(_reactNative.Platform.OS==='android'){if(_reactNative.Platform.Version>=31){requiredPermissions=[Permissions.PERMISSIONS.ANDROID.BLUETOOTH_SCAN,Permissions.PERMISSIONS.ANDROID.BLUETOOTH_CONNECT,Permissions.PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION];}else{requiredPermissions=[Permissions.PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION];}}else if(_reactNative.Platform.OS==='ios'){requiredPermissions=[Permissions.PERMISSIONS.IOS.LOCATION_WHEN_IN_USE];}if(requiredPermissions.length===0){console.info('[useBluetooth] No specific permissions require checking on this platform/OS version.');dispatch({type:'SET_PERMISSIONS_STATUS',payload:true});return true;}try{var statuses=yield Permissions.checkMultiple(requiredPermissions);var allGranted=requiredPermissions.every(function(permission){return statuses[permission]===Permissions.RESULTS.GRANTED;});console.info(`[useBluetooth] Permission check result: ${allGranted}`,statuses);dispatch({type:'SET_PERMISSIONS_STATUS',payload:allGranted});return allGranted;}catch(error){var formattedError=handleError(error);console.error('[useBluetooth] Permission check failed:',formattedError);dispatch({type:'SET_PERMISSIONS_STATUS',payload:false});dispatch({type:'SET_ERROR',payload:formattedError});return false;}}),[dispatch]);var requestBluetoothPermissions=(0,_react.useCallback)((0,_asyncToGenerator2.default)(function*(){console.info('[useBluetooth] Requesting permissions...');var permissionsToRequest=[];var iosBlePermissionNeeded=false;if(_reactNative.Platform.OS==='android'){if(_reactNative.Platform.Version>=31){permissionsToRequest=[Permissions.PERMISSIONS.ANDROID.BLUETOOTH_SCAN,Permissions.PERMISSIONS.ANDROID.BLUETOOTH_CONNECT,Permissions.PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION];}else{permissionsToRequest=[Permissions.PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION];}}else if(_reactNative.Platform.OS==='ios'){permissionsToRequest=[Permissions.PERMISSIONS.IOS.LOCATION_WHEN_IN_USE];iosBlePermissionNeeded=true;}if(permissionsToRequest.length===0&&!iosBlePermissionNeeded){console.info('[useBluetooth] No specific permissions require requesting on this platform.');dispatch({type:'SET_PERMISSIONS_STATUS',payload:true});return true;}try{var allGranted=true;var finalStatuses={};if(permissionsToRequest.length>0){var statuses=yield Permissions.requestMultiple(permissionsToRequest);finalStatuses=Object.assign({},statuses);allGranted=permissionsToRequest.every(function(permission){return statuses[permission]===Permissions.RESULTS.GRANTED;});console.info('[useBluetooth] Standard permission request results:',statuses);}var iosBluetoothGranted=true;if(_reactNative.Platform.OS==='ios'&&iosBlePermissionNeeded){console.info('[useBluetooth] Requesting iOS Bluetooth permission...');var blePermission=Permissions.PERMISSIONS.IOS.BLUETOOTH;var bleStatus=yield Permissions.request(blePermission);finalStatuses[blePermission]=bleStatus;iosBluetoothGranted=bleStatus===Permissions.RESULTS.GRANTED||bleStatus===Permissions.RESULTS.UNAVAILABLE;console.info(`[useBluetooth] iOS Bluetooth request result: ${bleStatus}`);}var finalGranted=allGranted&&iosBluetoothGranted;console.info(`[useBluetooth] Overall permission request result: ${finalGranted}`,finalStatuses);dispatch({type:'SET_PERMISSIONS_STATUS',payload:finalGranted});if(!finalGranted){console.warn('[useBluetooth] Not all required permissions were granted.');var blocked=Object.values(finalStatuses).some(function(status){return status===Permissions.RESULTS.BLOCKED;});if(blocked){console.error('[useBluetooth] One or more permissions are blocked. User must enable them in Settings.');}}return finalGranted;}catch(error){var formattedError=handleError(error);console.error('[useBluetooth] Permission request failed:',formattedError);dispatch({type:'SET_PERMISSIONS_STATUS',payload:false});dispatch({type:'SET_ERROR',payload:formattedError});return false;}}),[dispatch]);var promptEnableBluetooth=(0,_react.useCallback)((0,_asyncToGenerator2.default)(function*(){if(state.isBluetoothOn){console.info('[useBluetooth] Bluetooth is already enabled.');return;}if(_reactNative.Platform.OS==='android'){try{console.info('[useBluetooth] Requesting user to enable Bluetooth via native prompt...');yield _reactNativeBleManager.default.enableBluetooth();console.info('[useBluetooth] Bluetooth enable request prompt shown (or Bluetooth enabled).');}catch(error){var formattedError=handleError(error);console.error('[useBluetooth] Failed to request Bluetooth enable (e.g., user denied):',formattedError);throw new Error(`Failed to enable Bluetooth: ${formattedError.message}`);}}else if(_reactNative.Platform.OS==='ios'){console.warn('[useBluetooth] promptEnableBluetooth() has no effect on iOS. Guide user to Settings/Control Center.');return Promise.resolve();}}),[state.isBluetoothOn]);var scanDevices=(0,_react.useCallback)((0,_asyncToGenerator2.default)(function*(){var _scanPromiseRef$curre3;var scanDurationMs=arguments.length>0&&arguments[0]!==undefined?arguments[0]:5000;if(!state.isBluetoothOn){throw new Error('Bluetooth is currently turned off.');}if(!state.hasPermissions){throw new Error('Required Bluetooth/Location permissions are not granted.');}if(state.isScanning){var _scanPromiseRef$curre,_scanPromiseRef$curre2;console.warn('[useBluetooth] Scan already in progress.');return(_scanPromiseRef$curre=(_scanPromiseRef$curre2=scanPromiseRef.current)==null?void 0:_scanPromiseRef$curre2.promise)!=null?_scanPromiseRef$curre:Promise.resolve();}console.info(`[useBluetooth] Starting BLE scan for ${scanDurationMs}ms...`);dispatch({type:'SCAN_START'});scanPromiseRef.current=createDeferredPromise();try{var scanSeconds=Math.max(1,Math.round(scanDurationMs/1000));var timeoutId=setTimeout((0,_asyncToGenerator2.default)(function*(){if(state.isScanning){console.warn('[useBluetooth] Scan timed out.');try{yield _reactNativeBleManager.default.stopScan();}catch(stopError){console.error('[useBluetooth] Error stopping scan on timeout:',stopError);}}}),scanDurationMs+1000);yield _reactNativeBleManager.default.scan([],scanSeconds,false);console.info('[useBluetooth] BleManager.scan initiated.');yield scanPromiseRef.current.promise;clearTimeout(timeoutId);}catch(error){var formattedError=handleError(error);console.error('[useBluetooth] Scan error:',formattedError);if(state.isScanning){try{yield _reactNativeBleManager.default.stopScan();}catch(stopError){console.error('[useBluetooth] Error stopping scan after failure:',stopError);}}dispatch({type:'SET_ERROR',payload:formattedError});dispatch({type:'SCAN_STOP'});if(scanPromiseRef.current){scanPromiseRef.current.reject(handleStateError(state.error));scanPromiseRef.current=null;}throw formattedError;}return(_scanPromiseRef$curre3=scanPromiseRef.current)==null?void 0:_scanPromiseRef$curre3.promise;}),[state.isBluetoothOn,state.hasPermissions,state.isScanning,state.error,dispatch]);var connectToDevice=(0,_react.useCallback)(function(){var _ref6=(0,_asyncToGenerator2.default)(function*(deviceId){if(state.isConnecting){throw new Error('Connection already in progress.');}if(state.connectedDevice){if(state.connectedDevice.id===deviceId){console.warn(`[useBluetooth] Already connected to device ${deviceId}.`);return state.connectedDevice;}else{throw new Error(`Already connected to a different device (${state.connectedDevice.id}). Disconnect first.`);}}console.info(`[useBluetooth] Attempting connection to ${deviceId}...`);dispatch({type:'CONNECT_START'});connectPromiseRef.current=createDeferredPromise();try{var _peripheralInfo$servi;yield _reactNativeBleManager.default.connect(deviceId);console.info(`[useBluetooth] Peripheral ${deviceId} connected. Retrieving services...`);var peripheralInfo=yield _reactNativeBleManager.default.retrieveServices(deviceId);console.info(`[useBluetooth] Services retrieved for ${deviceId}. Found:`,(_peripheralInfo$servi=peripheralInfo.services)==null?void 0:_peripheralInfo$servi.map(function(s){return s.uuid;}));if(!peripheralInfo.services||peripheralInfo.services.length===0){throw new Error('No services found on this device.');}var foundConfig=null;var _loop=function*_loop(){var _peripheralInfo$servi2;var serviceUUIDUpper=target.serviceUUID.toUpperCase();var writeCharUUIDUpper=target.writeCharacteristicUUID.toUpperCase();var notifyCharUUIDUpper=target.notifyCharacteristicUUID.toUpperCase();var foundService=(_peripheralInfo$servi2=peripheralInfo.services)==null?void 0:_peripheralInfo$servi2.find(function(s){return s.uuid.toUpperCase()===serviceUUIDUpper;});if(foundService){var _peripheralInfo$chara,_peripheralInfo$chara2;console.info(`[useBluetooth] Found matching service: ${target.name} (${target.serviceUUID})`);console.info(`[useBluetooth] All characteristics reported by peripheral:`,JSON.stringify(peripheralInfo.characteristics,null,2));var characteristics=(_peripheralInfo$chara=(_peripheralInfo$chara2=peripheralInfo.characteristics)==null?void 0:_peripheralInfo$chara2.filter(function(c){return c.service.toUpperCase()===serviceUUIDUpper;}))!=null?_peripheralInfo$chara:[];console.info(`[useBluetooth] Characteristics filtered for service ${serviceUUIDUpper}:`,JSON.stringify(characteristics,null,2));var writeCharacteristic=characteristics.find(function(c){return c.characteristic.toUpperCase()===writeCharUUIDUpper;});var notifyCharacteristic=characteristics.find(function(c){return c.characteristic.toUpperCase()===notifyCharUUIDUpper;});console.info(`[useBluetooth] Searching for Write Characteristic: ${writeCharUUIDUpper}. Found: ${!!writeCharacteristic}`);console.info(`[useBluetooth] Searching for Notify Characteristic: ${notifyCharUUIDUpper}. Found: ${!!notifyCharacteristic}`);if(writeCharacteristic&¬ifyCharacteristic){console.info(`[useBluetooth] Found matching Write (${writeCharUUIDUpper}) and Notify (${notifyCharUUIDUpper}) characteristics.`);var writeType='WriteWithoutResponse';if(writeCharacteristic.properties.Write){writeType='Write';console.info('[useBluetooth] Characteristic supports Write (with response).');}else{console.info('[useBluetooth] Characteristic supports Write Without Response.');}console.info(`[useBluetooth] Starting notifications for ${notifyCharUUIDUpper}...`);yield _reactNativeBleManager.default.startNotification(deviceId,target.serviceUUID,target.notifyCharacteristicUUID);console.info(`[useBluetooth] Notifications started for ${notifyCharUUIDUpper}.`);foundConfig={serviceUUID:target.serviceUUID,writeCharacteristicUUID:target.writeCharacteristicUUID,notifyCharacteristicUUID:target.notifyCharacteristicUUID,writeType:writeType};return 1;}else{console.info(`[useBluetooth] Service ${target.serviceUUID} found, but required characteristics not present/found.`);}}};for(var target of _constants.KNOWN_ELM327_TARGETS){if(yield*_loop())break;}if(foundConfig){var _connectPromiseRef$cu;console.info(`[useBluetooth] Compatible configuration found and notifications started. Connection successful to ${deviceId}.`);dispatch({type:'CONNECT_SUCCESS',payload:{device:peripheralInfo,config:foundConfig}});(_connectPromiseRef$cu=connectPromiseRef.current)==null?void 0:_connectPromiseRef$cu.resolve(peripheralInfo);connectPromiseRef.current=null;return peripheralInfo;}else{console.error('[useBluetooth] Connection failed: No compatible ELM327 service/characteristic configuration found.');throw new Error('Incompatible OBD device or required services not found.');}}catch(error){var _connectPromiseRef$cu2;var formattedError=handleError(error);console.error(`[useBluetooth] Connection process failed for ${deviceId}:`,formattedError);dispatch({type:'CONNECT_FAILURE',payload:formattedError});try{yield _reactNativeBleManager.default.disconnect(deviceId);console.info(`[useBluetooth] Disconnected device ${deviceId} after connection failure.`);}catch(disconnectError){console.error(`[useBluetooth] Error disconnecting after connection failure for ${deviceId}:`,disconnectError);}(_connectPromiseRef$cu2=connectPromiseRef.current)==null?void 0:_connectPromiseRef$cu2.reject(formattedError);connectPromiseRef.current=null;throw formattedError;}});return function(_x){return _ref6.apply(this,arguments);};}(),[state.isConnecting,state.connectedDevice,dispatch]);var disconnect=(0,_react.useCallback)((0,_asyncToGenerator2.default)(function*(){if(state.isDisconnecting){var _disconnectPromiseRef,_disconnectPromiseRef2;console.warn('[useBluetooth] Disconnection already in progress.');return(_disconnectPromiseRef=(_disconnectPromiseRef2=disconnectPromiseRef.current)==null?void 0:_disconnectPromiseRef2.promise)!=null?_disconnectPromiseRef:Promise.resolve();}if(!state.connectedDevice||!state.activeDeviceConfig){console.warn('[useBluetooth] No device currently connected.');return Promise.resolve();}var deviceId=state.connectedDevice.id;var config=state.activeDeviceConfig;console.info(`[useBluetooth] Disconnecting from ${deviceId}...`);dispatch({type:'DISCONNECT_START'});disconnectPromiseRef.current=createDeferredPromise();try{var _disconnectPromiseRef3;console.info(`[useBluetooth] Stopping notifications for ${config.notifyCharacteristicUUID}...`);yield _reactNativeBleManager.default.stopNotification(deviceId,config.serviceUUID,config.notifyCharacteristicUUID);console.info('[useBluetooth] Notifications stopped.');yield _reactNativeBleManager.default.disconnect(deviceId);console.info(`[useBluetooth] BleManager.disconnect called for ${deviceId}.`);dispatch({type:'DISCONNECT_SUCCESS'});(_disconnectPromiseRef3=disconnectPromiseRef.current)==null?void 0:_disconnectPromiseRef3.resolve();}catch(error){var _disconnectPromiseRef4;var formattedError=handleError(error);console.error(`[useBluetooth] Disconnect failed for ${deviceId}:`,formattedError);dispatch({type:'DISCONNECT_FAILURE',payload:formattedError});(_disconnectPromiseRef4=disconnectPromiseRef.current)==null?void 0:_disconnectPromiseRef4.reject(formattedError);throw formattedError;}finally{disconnectPromiseRef.current=null;}}),[state.connectedDevice,state.activeDeviceConfig,state.isDisconnecting,dispatch]);var executeCommand=(0,_react.useCallback)(function(){var _ref8=(0,_asyncToGenerator2.default)(function*(command,returnType,options){var _options$timeout;if(!state.connectedDevice||!state.activeDeviceConfig){throw new Error('Not connected to a device.');}if(state.isAwaitingResponse){throw new Error('Another command is already in progress.');}if(currentCommandRef.current){console.warn('[useBluetooth] Stale command ref found - clearing.');if(currentCommandRef.current.timeoutId)clearTimeout(currentCommandRef.current.timeoutId);currentCommandRef.current.promise.reject(new Error('Command cancelled due to new command starting.'));currentCommandRef.current=null;}var config=state.activeDeviceConfig;var deviceId=state.connectedDevice.id;var commandTimeoutDuration=(_options$timeout=options==null?void 0:options.timeout)!=null?_options$timeout:_constants.DEFAULT_COMMAND_TIMEOUT;console.info(`[useBluetooth] Sending command: "${command}" (Expect: ${returnType}, Timeout: ${commandTimeoutDuration}ms)`);var deferredPromise=createDeferredPromise();var timeoutId=null;currentCommandRef.current={promise:deferredPromise,timeoutId:null,responseBuffer:[],responseChunks:[],expectedReturnType:returnType};dispatch({type:'SEND_COMMAND_START'});timeoutId=setTimeout(function(){var _currentCommandRef$cu;if(((_currentCommandRef$cu=currentCommandRef.current)==null?void 0:_currentCommandRef$cu.promise)===deferredPromise){var error=new Error(`Command "${command}" timed out after ${commandTimeoutDuration}ms.`);console.error(`[useBluetooth] ${error.message}`);dispatch({type:'COMMAND_TIMEOUT'});deferredPromise.reject(error);currentCommandRef.current=null;}},commandTimeoutDuration);if(currentCommandRef.current){currentCommandRef.current.timeoutId=timeoutId;}try{var commandString=command+_constants.ELM327_COMMAND_TERMINATOR;var commandBytes=Array.from(new TextEncoder().encode(commandString));if(config.writeType==='Write'){yield _reactNativeBleManager.default.write(deviceId,config.serviceUUID,config.writeCharacteristicUUID,commandBytes);}else{yield _reactNativeBleManager.default.writeWithoutResponse(deviceId,config.serviceUUID,config.writeCharacteristicUUID,commandBytes);}console.info(`[useBluetooth] Command "${command}" written. Waiting for response from Provider...`);var response=yield deferredPromise.promise;return response;}catch(error){var _currentCommandRef$cu2,_currentCommandRef$cu3,_currentCommandRef$cu4;var formattedError=handleError(error);console.error(`[useBluetooth] Error during command execution or processing "${command}":`,formattedError);if(((_currentCommandRef$cu2=currentCommandRef.current)==null?void 0:_currentCommandRef$cu2.promise)===deferredPromise&¤tCommandRef.current.timeoutId){clearTimeout(currentCommandRef.current.timeoutId);}if(state.isAwaitingResponse&&((_currentCommandRef$cu3=currentCommandRef.current)==null?void 0:_currentCommandRef$cu3.promise)===deferredPromise){dispatch({type:'COMMAND_FAILURE',payload:formattedError});}if(((_currentCommandRef$cu4=currentCommandRef.current)==null?void 0:_currentCommandRef$cu4.promise)===deferredPromise){currentCommandRef.current=null;}throw formattedError;}});return function(_x2,_x3,_x4){return _ref8.apply(this,arguments);};}(),[state.connectedDevice,state.activeDeviceConfig,state.isAwaitingResponse,dispatch,currentCommandRef]);var sendCommand=(0,_react.useCallback)(function(){var _ref9=(0,_asyncToGenerator2.default)(function*(command,options){var result=yield executeCommand(command,_constants.CommandReturnType.STRING,options);if(typeof result!=='string'){throw new Error('Internal error: Expected string response but received bytes or chunks.');}return result;});return function(_x5,_x6){return _ref9.apply(this,arguments);};}(),[executeCommand]);var sendCommandRaw=(0,_react.useCallback)(function(){var _ref10=(0,_asyncToGenerator2.default)(function*(command,options){var result=yield executeCommand(command,_constants.CommandReturnType.BYTES,options);if(!(result instanceof Uint8Array)){throw new Error('Internal error: Expected byte response but received string or chunks.');}return result;});return function(_x7,_x8){return _ref10.apply(this,arguments);};}(),[executeCommand]);var sendCommandRawChunked=(0,_react.useCallback)(function(){var _ref11=(0,_asyncToGenerator2.default)(function*(command,options){var result=yield executeCommand(command,_constants.CommandReturnType.CHUNKED,options);if(typeof result==='string'||result instanceof Uint8Array){throw new Error('Internal error: Expected chunked response but received string or bytes.');}return result;});return function(_x9,_x10){return _ref11.apply(this,arguments);};}(),[executeCommand]);var setStreaming=(0,_react.useCallback)(function(shouldStream){if(!state.connectedDevice&&shouldStream){console.error('[useBluetooth] Cannot start streaming: No device connected.');return;}if(state.isStreaming!==shouldStream){console.info(`[useBluetooth] Setting streaming status to: ${shouldStream}`);dispatch({type:'SET_STREAMING_STATUS',payload:shouldStream});}else{console.info(`[useBluetooth] Streaming status is already ${shouldStream}. No change.`);}},[state.isStreaming,state.connectedDevice,dispatch]);(0,_react.useEffect)(function(){if(scanPromiseRef.current&&!state.isScanning){if(state.error&&state.error.message.includes('Scan timed out')){scanPromiseRef.current.resolve();}else if(state.error){scanPromiseRef.current.reject(handleStateError(state.error));}else{scanPromiseRef.current.resolve();}scanPromiseRef.current=null;}},[state.isScanning,state.error]);(0,_react.useEffect)(function(){return function(){var _currentCommandRef$cu5;if((_currentCommandRef$cu5=currentCommandRef.current)!=null&&_currentCommandRef$cu5.timeoutId){clearTimeout(currentCommandRef.current.timeoutId);}};},[currentCommandRef]);(0,_react.useEffect)(function(){if(state.isAwaitingResponse&¤tCommandRef.current){var promptIndex=currentCommandRef.current.responseBuffer.indexOf(_constants.ELM327_PROMPT_BYTE);if(promptIndex!==-1){var _currentCommandRef$cu6;console.info('[useBluetooth] Prompt ">" detected in buffer.');var responseBytes=currentCommandRef.current.responseBuffer.slice(0,promptIndex);currentCommandRef.current.responseBuffer=[];if(currentCommandRef.current.timeoutId)clearTimeout(currentCommandRef.current.timeoutId);currentCommandRef.current.timeoutId=null;var responseString='';try{responseString=new TextDecoder().decode(Uint8Array.from(responseBytes)).trim();}catch(e){console.warn('[useBluetooth] TextDecoder failed, falling back to fromCharCode:',e);responseString=String.fromCharCode.apply(String,(0,_toConsumableArray2.default)(responseBytes)).trim();}(_currentCommandRef$cu6=currentCommandRef.current)==null?void 0:_currentCommandRef$cu6.promise.resolve(responseString);}}},[state.isAwaitingResponse,currentCommandRef]);return Object.assign({},state,{checkPermissions:checkPermissions,scanDevices:scanDevices,connectToDevice:connectToDevice,disconnect:disconnect,sendCommand:sendCommand,requestBluetoothPermissions:requestBluetoothPermissions,promptEnableBluetooth:promptEnableBluetooth,sendCommandRaw:sendCommandRaw,sendCommandRawChunked:sendCommandRawChunked,setStreaming:setStreaming});};
//# sourceMappingURL=useBluetooth.js.map