npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

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-player

Using yarn

yarn add react-native-senti-drive-ble-module react-native-permissions react-native-sound-player

iOS Installation

Add react-native-permissions in root project and setup based on react-native-permissions guideline

yarn add react-native-permissions

For iOS, you need to install pods:

cd ios && pod install

Android 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 install

2. 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.wav

5. 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 for
  • config (optional): Scanning configuration

Returns: EventEmitter with the following events:

  • onDeviceFound: Emitted when a device is found
  • onDeviceLost: Emitted when a device is lost
  • onStopped: Emitted when scanning stops
  • onError: 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-player

Types

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 status

Configuration

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 indicator
  • n: 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

  1. Use Targeted Scanning: Always specify a target device ID when possible
  2. Optimize Scan Duration: Use shorter durations (10-15s) for regular monitoring
  3. Implement Smart Intervals: Adjust scanning frequency based on device presence
  4. Enable Kalman Filtering: Use for stable distance readings in noisy environments
  5. 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 off
  • PERMISSION_DENIED: Required permissions are not granted
  • DEVICE_NOT_FOUND: Target device not found during scan
  • SCAN_FAILED: BLE scan operation failed
  • NOT_SUPPORTED: Feature not supported on this device
  • INVALID_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 typecheck

Best 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