react-native-senti-driver-ble
v1.0.0
Published
A React Native module for Bluetooth Low Energy (BLE) device scanning and management with distance estimation and device tracking capabilities
Maintainers
Readme
React Native Senti Drive BLE Module
A comprehensive React Native module for Bluetooth Low Energy (BLE) device scanning and management, specifically designed for finding lost vehicles equipped with BLE 5.0 devices (boitiers). This module provides advanced features like distance estimation, device tracking, automatic device loss detection, and intelligent proximity alerts with sound and vibration.
Features
- BLE Device Scanning: High-performance scanning for nearby BLE devices with configurable parameters
- Distance Estimation: Accurate distance calculation using RSSI and path loss models with Kalman filtering
- Device Tracking: Intelligent device loss/found detection with customizable timeout settings
- Smart Alerts: Dynamic proximity-based alerts with sound and vibration patterns
- Permission Management: Seamless handling of Bluetooth and location permissions across platforms
- Real-time Events: Event-driven architecture with comprehensive error handling and state management
- Targeted Scanning: Filter scanning for specific device IDs or scan all nearby devices
- Status Monitoring: Real-time Bluetooth adapter status monitoring with automatic reconnection
- Kalman Filtering: Advanced RSSI noise reduction for stable distance measurements
- Cross-platform: Full support for both iOS (Core Bluetooth) and Android (BLE APIs)
- Audio Alerts: Configurable sound alerts with custom audio files
- Haptic Feedback: Intelligent vibration patterns based on proximity
Installation
Using npm
npm install react-native-senti-drive-ble-module react-native-permissions react-native-sound-playerUsing yarn
yarn add react-native-senti-drive-ble-module react-native-permissions react-native-sound-playeriOS Installation
Add react-native-permissions in root project and setup based on react-native-permissions guideline
yarn add react-native-permissionsFor iOS, you need to install pods:
cd ios && pod installAndroid Installation
For Android, ensure you have the following permissions in your android/app/src/main/AndroidManifest.xml:
<!-- For Android 12+ -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!-- For Android 11 and below -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- Location permission (for Android 6–11) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />Manual Installation
Android Manual Linking
- Add the module to your
android/app/src/main/java/com/yourapp/MainApplication.java:
import com.senti_drive_ble.SentiDriveBleModulePackage;
// In getPackages():
packages.add(new SentiDriveBleModulePackage());Quick Start Guide
1. Install Dependencies
# Install the module
yarn add react-native-senti-drive-ble-module
# Install required dependencies
yarn add react-native-permissions react-native-sound-player
# For iOS
cd ios && pod install2. Add Permissions (Android)
Add to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />3. Add Permissions (iOS)
Add to ios/YourApp/Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to find your lost vehicle</string>4. Setup Sound Files (Optional)
For audio alerts, add sound files to your app bundle:
Android: Place files in android/app/src/main/res/raw/
iOS: Add files to your iOS project bundle via Xcode
// Example sound file setup
import { setSoundFileName } from 'react-native-senti-drive-ble-module';
// Set the sound file (without extension)
setSoundFileName('beep.mp3'); // for beep.mp3 or beep.wav5. Basic Implementation
import {
initializeBluetooth,
startScan,
stopScan,
setSoundFileName
} from 'react-native-senti-drive-ble-module';
// Initialize and start scanning
const scanForDevices = async () => {
try {
await initializeBluetooth();
// Optional: Set up sound alerts
setSoundFileName('alert_sound'); // Your sound file name
const emitter = startScan();
emitter.addListener('onDeviceFound', (device) => {
console.log('Found device:', device.name, 'at', device.estimatedDistance, 'm');
});
} catch (error) {
console.error('Scan failed:', error);
}
};Detailed Usage Examples
Basic Usage
1. Initialize Bluetooth
import { initializeBluetooth } from 'react-native-senti-drive-ble-module';
try {
await initializeBluetooth();
console.log('Bluetooth initialized successfully');
} catch (error) {
console.error('Failed to initialize Bluetooth:', error);
}2. Start Scanning for Devices
import { startScan, stopScan } from 'react-native-senti-drive-ble-module';
// Start scanning with default configuration
const emitter = startScan();
// Listen for found devices
emitter.addListener('onDeviceFound', (device) => {
console.log('Device found:', device);
console.log('Estimated distance:', device.estimatedDistance, 'meters');
});
// Listen for scan completion
emitter.addListener('onStopped', () => {
console.log('Scan completed');
});
// Stop scanning when done
stopScan();3. Scan with Custom Configuration
import { startScan } from 'react-native-senti-drive-ble-module';
const config = {
scanDuration: 30000, // 30 seconds
enableVibration: true, // Enable vibration alerts
distanceThreshold: 2, // Alert when device is within 2 meters
txPower: -59, // Transmit power of target device
n: 2 // Path loss exponent
};
const emitter = startScan('target-device-id', config);
emitter.addListener('onDeviceFound', (device) => {
if (device.estimatedDistance < config.distanceThreshold) {
console.log('Device is nearby!');
}
});4. Monitor Bluetooth Status
import { onBluetoothStatusChange, getBluetoothStatus } from 'react-native-senti-drive-ble-module';
// Get current status
const currentStatus = await getBluetoothStatus();
console.log('Current Bluetooth status:', currentStatus);
// Listen for status changes
const unsubscribe = onBluetoothStatusChange((status) => {
console.log('Bluetooth status changed to:', status);
switch (status) {
case 'on':
console.log('Bluetooth is enabled');
break;
case 'off':
console.log('Bluetooth is disabled');
break;
case 'unauthorized':
console.log('Bluetooth permission denied');
break;
}
});
// Cleanup when done
unsubscribe();5. Handle Device Loss Detection
import { startScan } from 'react-native-senti-drive-ble-module';
const emitter = startScan();
// Listen for when devices are lost
emitter.addListener('onDeviceLost', (device) => {
console.log(`Device ${device.name} (${device.id}) was lost`);
console.log('Last seen at:', new Date(device.lastSeenAt));
});
// Listen for found devices
emitter.addListener('onDeviceFound', (device) => {
console.log(`Device ${device.name} found at distance: ${device.estimatedDistance}m`);
});Advanced Features
1. Distance-Based Proximity Alerts
Configure different alert patterns based on distance to your target device:
import { startScan, setSoundFileName } from 'react-native-senti-drive-ble-module';
// Set up audio file for alerts
setSoundFileName('beep.mp3'); // File should be in your app bundle
const advancedConfig = {
scanConfig: {
scanDuration: 60000, // 60 second scan
enableVibration: true, // Enable vibration alerts
enableSound: true, // Enable sound alerts
txPower: -59, // Device transmit power
n: 2 // Path loss exponent
},
// Define proximity-based alert patterns
pulseConfigs: [
{ distance: 20, intervalMs: 10000 }, // Far: alert every 10s
{ distance: 10, intervalMs: 5000 }, // Medium: alert every 5s
{ distance: 5, intervalMs: 2000 }, // Close: alert every 2s
{ distance: 2, intervalMs: 1000 }, // Very close: alert every 1s
{ distance: 1, intervalMs: 500 }, // Immediate: alert every 500ms
]
};
const emitter = startScan('target-device-id', advancedConfig);2. RSSI Filtering with Kalman Filter
Reduce noise in distance measurements for more stable tracking:
const kalmanConfig = {
rssiFilter: {
enableKalmanFilter: true,
kalmanProcessNoise: 0.01, // Lower = more stable, less responsive
kalmanMeasurementNoise: 0.25 // Higher = more smoothing
},
scanConfig: {
scanDuration: 30000,
txPower: -59,
n: 2
}
};
const emitter = startScan(null, kalmanConfig);
emitter.addListener('onDeviceFound', (device) => {
// Distance is now smoothed and more stable
console.log('Filtered distance:', device.estimatedDistance.toFixed(2), 'm');
});3. Device Loss Detection
Automatically detect when devices go out of range:
const emitter = startScan();
emitter.addListener('onDeviceFound', (device) => {
console.log(`Found: ${device.name} at ${device.estimatedDistance.toFixed(1)}m`);
});
emitter.addListener('onDeviceLost', (device) => {
console.log(`Lost: ${device.name} - last seen at ${new Date(device.lastSeenAt)}`);
// Device hasn't been seen for 5 seconds (configurable timeout)
});4. Targeted vs. Broadcast Scanning
// Scan for a specific device (more efficient)
const targetEmitter = startScan('AA:BB:CC:DD:EE:FF', config, true);
// Scan for all devices but filter by name in JavaScript
const broadcastEmitter = startScan();
broadcastEmitter.addListener('onDeviceFound', (device) => {
if (device.name.includes('SentiDrive') || device.name.includes('MyVehicle')) {
console.log('Target vehicle found!', device);
}
});5. Multiple Device Tracking
Track multiple vehicles simultaneously:
const vehicleTargets = [
{ id: 'AA:BB:CC:DD:EE:FF', name: 'Car 1' },
{ id: 'BB:CC:DD:EE:FF:AA', name: 'Car 2' },
{ id: 'CC:DD:EE:FF:AA:BB', name: 'Motorcycle' }
];
const emitter = startScan(); // Scan all devices
emitter.addListener('onDeviceFound', (device) => {
const vehicle = vehicleTargets.find(v => v.id === device.id);
if (vehicle) {
console.log(`${vehicle.name} found at ${device.estimatedDistance.toFixed(1)}m`);
}
});6. Battery-Optimized Scanning
Implement smart scanning patterns to conserve battery:
let scanCount = 0;
const MAX_SCANS = 5;
const performSmartScan = () => {
if (scanCount >= MAX_SCANS) {
console.log('Max scans reached, stopping to save battery');
return;
}
const config = {
scanConfig: {
// Reduce scan duration for battery optimization
scanDuration: scanCount < 3 ? 10000 : 5000,
enableVibration: scanCount < 3, // Reduce vibration after first few scans
enableSound: true
}
};
const emitter = startScan('target-device', config);
scanCount++;
emitter.addListener('onStopped', () => {
// Wait before next scan (exponential backoff)
setTimeout(performSmartScan, Math.pow(2, scanCount) * 1000);
});
emitter.addListener('onDeviceFound', (device) => {
if (device.estimatedDistance < 10) {
console.log('Device found nearby, stopping smart scan');
stopScan();
}
});
};Redux Integration Example
Here's a complete example of how to integrate this module with Redux Toolkit:
1. Redux Store Setup
// src/redux/store.ts
import { configureStore } from '@reduxjs/toolkit';
import bleDevicesSlice from './bleDevicesSlice';
export const store = configureStore({
reducer: {
bleDevices: bleDevicesSlice.reducer,
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;2. BLE Devices Slice
// src/redux/bleDevicesSlice.ts
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import {
BluetoothStatus,
DeviceFoundEvent,
ErrorEvent,
} from 'react-native-senti-drive-ble-module';
import {
initializeBluetooth as initializeBluetoothModule,
startScan,
stopScan,
onBluetoothStatusChange,
getBluetoothStatus,
} from 'react-native-senti-drive-ble-module';
interface BLEState {
devices: Record<string, DeviceFoundEvent>;
isScanning: boolean;
error?: string;
initialized: boolean;
bluetoothStatus?: BluetoothStatus;
}
const initialState: BLEState = {
devices: {},
isScanning: false,
initialized: false,
};
// Initialize Bluetooth
const initializeBluetooth = createAsyncThunk(
'bleDevices/initializeBluetooth',
async (_, { dispatch, rejectWithValue }) => {
try {
await initializeBluetoothModule();
dispatch(bleDevicesSlice.actions.setInitialized(true));
const status = await getBluetoothStatus();
dispatch(bleDevicesSlice.actions.setBluetoothStatus(status));
// Listen for status changes
onBluetoothStatusChange((status) => {
dispatch(bleDevicesSlice.actions.setBluetoothStatus(status));
});
return undefined;
} catch (error: any) {
const message = error.message || 'Bluetooth initialization failed';
dispatch(bleDevicesSlice.actions.setError(message));
return rejectWithValue(message);
}
}
);
// Start BLE scan
const startBleScan = createAsyncThunk(
'bleDevices/startScan',
async (payload: { targetId?: string; config?: any }, { dispatch, getState }) => {
const state = getState() as RootState;
if (!state.bleDevices.initialized) {
const result = await dispatch(initializeBluetooth());
if (result.meta.requestStatus === 'rejected') {
throw new Error('Bluetooth not initialized');
}
}
await dispatch(stopScanning());
dispatch(bleDevicesSlice.actions.clearDevices());
dispatch(bleDevicesSlice.actions.setScanning(true));
const emitter = startScan(payload.targetId, payload.config);
// Listen for scan events
emitter.addListener('onStopped', () => {
dispatch(stopScanning());
});
emitter.addListener('onDeviceFound', (device: DeviceFoundEvent) => {
dispatch(bleDevicesSlice.actions.addDevice(device));
});
emitter.addListener('onError', (err: ErrorEvent) => {
dispatch(bleDevicesSlice.actions.setError(err.message));
dispatch(stopScanning());
});
emitter.addListener('onDeviceLost', (device) => {
dispatch(bleDevicesSlice.actions.removeDevice(device.id));
});
}
);
// Stop scanning
const stopScanning = createAsyncThunk(
'bleDevices/stopScan',
async (_, { dispatch }) => {
dispatch(bleDevicesSlice.actions.setScanning(false));
stopScan();
}
);
const bleDevicesSlice = createSlice({
name: 'bleDevices',
initialState,
reducers: {
addDevice: (state, action: PayloadAction<DeviceFoundEvent>) => {
state.devices[action.payload.id] = action.payload;
},
removeDevice: (state, action: PayloadAction<string>) => {
delete state.devices[action.payload];
},
clearDevices: (state) => {
state.devices = {};
},
setError: (state, action: PayloadAction<string | undefined>) => {
state.error = action.payload;
},
setBluetoothStatus: (state, action: PayloadAction<BluetoothStatus>) => {
state.bluetoothStatus = action.payload;
},
setScanning: (state, action: PayloadAction<boolean>) => {
state.isScanning = action.payload;
},
setInitialized: (state, action: PayloadAction<boolean>) => {
state.initialized = action.payload;
},
},
});
export const bleDeviceActions = {
...bleDevicesSlice.actions,
startBleScan,
stopScanning,
initializeBluetoothAsync: initializeBluetooth,
};
export default bleDevicesSlice;3. React Component Usage
// src/components/BLEScanner.tsx
import React, { useEffect, useState } from 'react';
import { View, Text, TouchableOpacity, FlatList, Alert } from 'react-native';
import { useAppDispatch, useAppSelector } from '../redux/store';
import { bleDeviceActions } from '../redux/bleDevicesSlice';
export const BLEScanner: React.FC = () => {
const dispatch = useAppDispatch();
const { devices, isScanning, error, bluetoothStatus, initialized } = useAppSelector(
(state) => state.bleDevices
);
useEffect(() => {
// Initialize Bluetooth when component mounts
dispatch(bleDeviceActions.initializeBluetoothAsync());
}, [dispatch]);
const handleStartScan = () => {
const config = {
scanDuration: 30000,
enableVibration: true,
distanceThreshold: 3,
txPower: -59,
n: 2,
};
dispatch(bleDeviceActions.startBleScan({ config }));
};
const handleStopScan = () => {
dispatch(bleDeviceActions.stopScanning());
};
const renderDevice = ({ item }: { item: any }) => (
<View style={{ padding: 16, borderBottomWidth: 1, borderBottomColor: '#eee' }}>
<Text style={{ fontSize: 16, fontWeight: 'bold' }}>{item.name || 'Unknown Device'}</Text>
<Text>ID: {item.id}</Text>
<Text>Distance: {item.estimatedDistance.toFixed(2)}m</Text>
<Text>RSSI: {item.rssi} dBm</Text>
</View>
);
return (
<View style={{ flex: 1, padding: 16 }}>
<Text style={{ fontSize: 24, fontWeight: 'bold', marginBottom: 16 }}>
BLE Device Scanner
</Text>
<Text>Bluetooth Status: {bluetoothStatus || 'Unknown'}</Text>
<Text>Initialized: {initialized ? 'Yes' : 'No'}</Text>
{error && (
<Text style={{ color: 'red', marginVertical: 8 }}>Error: {error}</Text>
)}
<View style={{ flexDirection: 'row', marginVertical: 16 }}>
<TouchableOpacity
style={{
backgroundColor: isScanning ? '#ccc' : '#007AFF',
padding: 12,
borderRadius: 8,
marginRight: 8,
}}
onPress={handleStartScan}
disabled={isScanning}
>
<Text style={{ color: 'white' }}>
{isScanning ? 'Scanning...' : 'Start Scan'}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
backgroundColor: '#FF3B30',
padding: 12,
borderRadius: 8,
}}
onPress={handleStopScan}
disabled={!isScanning}
>
<Text style={{ color: 'white' }}>Stop Scan</Text>
</TouchableOpacity>
</View>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 8 }}>
Found Devices ({Object.keys(devices).length})
</Text>
<FlatList
data={Object.values(devices)}
renderItem={renderDevice}
keyExtractor={(item) => item.id}
style={{ flex: 1 }}
/>
</View>
);
};API Reference
Functions
initializeBluetooth(): Promise<void>
Initializes Bluetooth and requests necessary permissions. Must be called before scanning.
startScan(targetId?: string, config?: ScanConfigs): EventEmitter
Starts scanning for BLE devices. Returns an event emitter for listening to scan events.
Parameters:
targetId(optional): Specific device ID to scan forconfig(optional): Scanning configuration
Returns: EventEmitter with the following events:
onDeviceFound: Emitted when a device is foundonDeviceLost: Emitted when a device is lostonStopped: Emitted when scanning stopsonError: Emitted when an error occurs
stopScan(): void
Stops the current BLE scan.
getBluetoothStatus(): Promise<BluetoothStatus>
Returns the current Bluetooth status.
onBluetoothStatusChange(callback: (status: BluetoothStatus) => void): () => void
Listens for Bluetooth status changes. Returns an unsubscribe function.
openBluetoothSettings(): void
Opens the device's Bluetooth settings.
setSoundFileName(fileName: string): void
Sets the sound file name for audio alerts. Requires react-native-sound-player.
Parameters:
fileName: Name of sound file without extension (e.g., 'beep' for beep.mp3)
Note: Sound files must be added to the app bundle:
- Android: Place in
android/app/src/main/res/raw/ - iOS: Add to project bundle via Xcode
Dependencies
This module requires the following peer dependencies:
- react-native-permissions: For handling Bluetooth and location permissions
- react-native-sound-player: For audio alert functionality
- React Native: >=0.68.0 recommended
yarn add react-native-permissions react-native-sound-playerTypes
ScanConfigs
interface ScanConfigs {
scanDuration?: number; // Scan duration in milliseconds
enableVibration?: boolean; // Enable vibration alerts
distanceThreshold?: number; // Distance threshold for alerts (meters)
txPower?: number; // Transmit power of target device
n?: number; // Path loss exponent
}DeviceFoundEvent
interface DeviceFoundEvent {
id: string; // Device identifier
name: string; // Device name
rssi: number; // Signal strength indicator
estimatedDistance: number; // Estimated distance in meters
}BluetoothStatus
type BluetoothStatus =
| 'on' // Bluetooth is enabled
| 'off' // Bluetooth is disabled
| 'turningOff' // Bluetooth is turning off
| 'turningOn' // Bluetooth is turning on
| 'unauthorized' // Bluetooth permission denied
| 'unsupported' // Bluetooth not supported
| 'resetting' // Bluetooth is resetting
| 'unknown'; // Unknown statusConfiguration
Android Permissions
Add the following permissions to your android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />iOS Permissions
Add the following keys to your ios/YourApp/Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to scan for nearby devices</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app uses Bluetooth to connect to nearby devices</string>Distance Estimation
The module uses the following formula to estimate distance:
distance = 10^((txPower - rssi) / (10 * n))Where:
txPower: Transmit power of the target device (default: -59 dBm)rssi: Received signal strength indicatorn: Path loss exponent (default: 2)
You can customize these values in the scan configuration for more accurate distance estimation.
Troubleshooting
Common Issues and Solutions
1. Permission Denied Errors
// Handle permission errors gracefully
try {
await initializeBluetooth();
} catch (error) {
if (error.message.includes('PERMISSION_DENIED')) {
// Guide user to enable permissions
Alert.alert(
'Permissions Required',
'Please enable Bluetooth and Location permissions in device settings',
[{ text: 'Open Settings', onPress: () => openBluetoothSettings() }]
);
}
}2. iOS Foreground Requirement
On iOS, BLE scanning requires the app to be in foreground:
import { AppState } from 'react-native';
AppState.addEventListener('change', (nextAppState) => {
if (nextAppState === 'background') {
stopScan(); // Stop scanning when app goes to background
} else if (nextAppState === 'active') {
// Restart scanning when app becomes active
startScan();
}
});3. Distance Estimation Accuracy
For better distance accuracy, calibrate the txPower value:
// Measure RSSI at 1 meter distance and use as txPower
const calibratedConfig = {
scanConfig: {
txPower: -65, // Measured RSSI at 1m for your specific device
n: 2.2 // Adjust based on environment (indoor: 2-3, outdoor: 2)
}
};4. Device Not Found
const emitter = startScan('target-device-id');
let deviceFoundTimeout;
emitter.addListener('onDeviceFound', (device) => {
clearTimeout(deviceFoundTimeout);
console.log('Device found successfully');
});
// Set timeout for device discovery
deviceFoundTimeout = setTimeout(() => {
console.log('Device not found after 30 seconds');
stopScan();
// Try scanning without device filter
startScan(); // Scan all devices
}, 30000);5. High Battery Consumption
// Implement intelligent scanning intervals
const SCAN_INTERVALS = {
immediate: 5000, // 5 seconds when device was recently found
normal: 15000, // 15 seconds for regular scanning
extended: 60000 // 1 minute when device hasn't been found
};
let lastDeviceFound = 0;
const smartInterval = () => {
const timeSinceFound = Date.now() - lastDeviceFound;
if (timeSinceFound < 60000) return SCAN_INTERVALS.immediate;
if (timeSinceFound < 300000) return SCAN_INTERVALS.normal;
return SCAN_INTERVALS.extended;
};6. Sound Not Playing
import { setSoundFileName } from 'react-native-senti-drive-ble-module';
// Ensure sound file is properly set up
try {
setSoundFileName('beep.mp3'); // Make sure beep.mp3 exists in bundle
console.log('Sound file configured successfully');
} catch (error) {
console.error('Sound setup failed:', error);
}
// For Android: Check that file is in android/app/src/main/res/raw/
// For iOS: Check that file is added to Xcode project bundle
// Test sound independently
import SoundPlayer from 'react-native-sound-player';
try {
SoundPlayer.playSoundFile('beep', 'mp3');
} catch (e) {
console.error('Sound player test failed:', e);
}Performance Tips
- Use Targeted Scanning: Always specify a target device ID when possible
- Optimize Scan Duration: Use shorter durations (10-15s) for regular monitoring
- Implement Smart Intervals: Adjust scanning frequency based on device presence
- Enable Kalman Filtering: Use for stable distance readings in noisy environments
- Handle App State Changes: Pause scanning when app is backgrounded
Platform-Specific Considerations
Android
- Requires location permission even for BLE scanning
- Scanning may be limited in background (varies by Android version)
- Some devices may have different BLE chipset behaviors
iOS
- Scanning is automatically paused when app goes to background
- Core Bluetooth requires app to be in foreground for active scanning
- UUID format required for device identification (not MAC addresses)
Error Handling
The module provides comprehensive error handling with specific error codes:
BT_OFF: Bluetooth is turned offPERMISSION_DENIED: Required permissions are not grantedDEVICE_NOT_FOUND: Target device not found during scanSCAN_FAILED: BLE scan operation failedNOT_SUPPORTED: Feature not supported on this deviceINVALID_TARGET_ID: Invalid target device ID provided
Development
Building the Module
This module uses react-native-builder-bob for building and packaging. To build the module:
# Install dependencies
yarn install
# Build the module
yarn build
# Clean build artifacts
yarn clean
# Type checking
yarn typecheckBest Practices
1. Memory Management
// Always clean up event listeners
useEffect(() => {
const emitter = startScan();
const onDeviceFound = (device) => { /* handle device */ };
const onError = (error) => { /* handle error */ };
emitter.addListener('onDeviceFound', onDeviceFound);
emitter.addListener('onError', onError);
return () => {
// Clean up on unmount
emitter.removeListener('onDeviceFound', onDeviceFound);
emitter.removeListener('onError', onError);
stopScan();
};
}, []);2. State Synchronization
// Keep scan state synchronized with UI
const [isScanning, setIsScanning] = useState(false);
const handleStartScan = () => {
setIsScanning(true);
const emitter = startScan();
emitter.addListener('onStopped', () => {
setIsScanning(false);
});
};3. Error Recovery
// Implement automatic retry with exponential backoff
const retryScanning = async (attempt = 1, maxAttempts = 3) => {
try {
await initializeBluetooth();
startScan();
} catch (error) {
if (attempt < maxAttempts) {
const delay = Math.pow(2, attempt) * 1000;
setTimeout(() => retryScanning(attempt + 1, maxAttempts), delay);
} else {
console.error('Failed to initialize after', maxAttempts, 'attempts');
}
}
};Development Setup
# Clone the repository
git clone https://github.com/Ant-Tech-Agency/react-native-senti-drive-ble-module.git
# Install dependencies
cd react-native-senti-drive-ble-module
yarn install
# Run example app
cd example
yarn install
yarn android # or yarn ios