React Native Bluetooth SDK for MedCase medical device communication
npm install medcase-sdkA React Native Bluetooth SDK for communicating with MedCase medical devices. Works with both Expo and standard React Native projects, with optional TypeScript support.
- 📱 Works with both Expo and React Native
- 🔧 Automatic platform detection and adapter selection
- 📦 Built-in connection management
- 🔀 Data transformation and encoding (URL-encoded UTF-8 format)
- 🎯 Manual connection mode for advanced users
- 📝 Full TypeScript support (optional)
- 🔄 Event-driven architecture
- ⚡ Error handling and retry logic
- 📊 Comprehensive logging
- 🔄 Flutter-compatible data format
``bash`
npm install medcase-sdkor
yarn add medcase-sdk
The SDK automatically detects your environment and uses the appropriate Bluetooth library:
- Expo: react-native-ble-plxreact-native-ble-manager
- React Native:
Install the required dependency for your platform:
`bashFor Expo
npm install react-native-ble-plx
Platform Setup
$3
Add the plugin to your
app.json or app.config.js:`json
{
"expo": {
"plugins": [
[
"react-native-ble-plx",
{
"isBackgroundEnabled": true,
"modes": ["bluetooth"]
}
]
]
}
}
`$3
#### iOS
Add to your
Info.plist:`xml
NSBluetoothAlwaysUsageDescription
This app needs Bluetooth access to communicate with medical devices
NSBluetoothPeripheralUsageDescription
This app needs Bluetooth access to communicate with medical devices
`#### Android
Add to your
AndroidManifest.xml:`xml
`Quick Start
$3
The SDK now provides a streamlined auto-connect approach that eliminates the need for manual scanning and connection steps:
`typescript
import { MedCaseBluetoothSDK } from 'medcase-sdk';const sdk = new MedCaseBluetoothSDK({
boxId: '2A:DC:C3:AF:B9:90', // Specific device to connect to
});
async function connectAndSendData() {
try {
// Initialize SDK and request permissions
const initialized = await sdk.initialize();
if(!initialized) return;
// Auto-connect to device and discover services/characteristics
const result = await sdk.autoConnectAndDiscover();
// Send WiFi credentials with location data
await sdk.sendData({
ssid: 'MyWiFiNetwork',
password: 'MyPassword123',
time: '2023-12-01 10:30:00 123',
lat: '40.7128',
lng: '-74.0060'
});
await sdk.disconnectFromDevice();
} catch (error) {
console.error('Error:', error);
}
}
`API Reference
$3
The Configuration class provides utilities for generating and opening admin URLs for MedCase devices.
#### Constructor
`typescript
const config = new Configuration(boxId: string, phoneNumber: string);
`Parameters:
-
boxId (string): The Bluetooth device ID or MAC address
- phoneNumber (string): The phone number associated with the deviceExample:
`typescript
import { Configuration } from 'medcase-sdk';const config = new Configuration('C8:F0:9E:7A:79:70', '7908075918');
`#### Methods
#####
link(): stringReturns the admin URL as a string.
Returns:
string - The complete admin URLExample:
`typescript
const config = new Configuration('C8:F0:9E:7A:79:70', '7908075918');
const url = config.link();
console.log(url);
// Output: https://admin.medcase.in/admin/partner/C8:F0:9E:7A:79:70/7908075918
`#####
openInBrowser(): PromiseOpens the admin URL in the device's default browser.
Throws: Error if the URL cannot be opened
Example:
`typescript
const config = new Configuration('C8:F0:9E:7A:79:70', '7908075918');
try {
await config.openInBrowser();
console.log('Browser opened successfully');
} catch (error) {
console.error('Failed to open browser:', error.message);
}
`##### Getter Methods
-
getBoxId(): string - Returns the current box ID
- getPhoneNumber(): string - Returns the current phone number##### Setter Methods
-
updateBoxId(boxId: string): void - Updates the box ID
- updatePhoneNumber(phoneNumber: string): void - Updates the phone numberExample:
`typescript
const config = new Configuration('C8:F0:9E:7A:79:70', '7908075918');// Get current values
console.log(config.getBoxId()); // 'C8:F0:9E:7A:79:70'
console.log(config.getPhoneNumber()); // '7908075918'
// Update values
config.updateBoxId('D1:E2:F3:G4:H5:76');
config.updatePhoneNumber('9876543210');
console.log(config.link());
// Output: https://admin.medcase.in/admin/partner/D1:E2:F3:G4:H5:76/9876543210
`#### URL Format
The generated URLs follow this pattern:
`
https://admin.medcase.in/admin/partner/{boxId}/{phoneNumber}
`Where:
-
{boxId} is the device ID/MAC address
- {phoneNumber} is the associated phone number$3
#### Constructor Options
`typescript
interface MedCaseSDKConfig {
autoManageConnection?: boolean; // Default: true
serviceUUID?: string; // Default: '1800'
characteristicUUID?: string; // Default: '2A00'
enableLogging?: boolean; // Default: false
connectionTimeout?: number; // Default: 30000 (ms)
boxId?: string; // Optional: for device name filtering
deviceNamePrefix?: string; // Default: 'MedCase'
dataTransformation?: {
encoding?: 'utf8' | 'base64' | 'hex'; // Default: 'utf8'
delimiter?: string; // Default: '|'
prefix?: string;
suffix?: string;
};
}
`#### Methods
##### Connection Management
-
initialize(): Promise - Initialize SDK and request permissions
- autoConnectAndDiscover(): Promise<{connection, services, characteristics}> - Auto-connect and discover services/characteristics (Recommended)
- scanForDevices(serviceUUIDs?, timeoutMs?): Promise - Scan for devices (Manual approach)
- connectToDevice(deviceId, options?): Promise - Connect to specific device
- disconnectFromDevice(deviceId?): Promise - Disconnect from device
- getCurrentConnection(): BluetoothConnection | null - Get current connection
- isConnected(): boolean - Check if connected##### Data Transmission
-
sendData(values, deviceId?): Promise - Send data with automatic connection
- sendDataToCharacteristic(connection, serviceUUID, characteristicUUID, values): Promise - Send to specific characteristic##### Configuration
-
updateConfig(newConfig): void - Update configuration
- getConfig(): MedCaseSDKConfig - Get current configuration
- cleanup(): Promise - Clean up resources##### Events
-
on(event, listener): void - Add event listener
- off(event, listener): void - Remove event listener#### Events
-
device-discovered - When a matching device is found during scanning
- device-connected - When a device is connected
- device-disconnected - When a device is disconnected
- error - When an error occursNote: The
data-received event and notification listening methods are kept for internal use only and are not exposed in the public API.$3
The SDK uses URL-encoded UTF-8 format that's fully compatible with Flutter apps. When you send data:
`typescript
// Input data
{
ssid: 'MyWiFiNetwork',
password: 'MyPassword123',
time: '2023-12-01 10:30:00 123',
lat: '40.7128',
lng: '-74.0060'
}
`It gets transformed to:
MyWiFiNetwork/MyPassword123/CT:2023-12-01%2010%3A30%3A00%20123/LT:40.7128/LG:-74.0060This matches the Flutter
Uri.encodeComponent() behavior exactly, ensuring seamless communication between React Native and Flutter MedCase apps.#### Data Structure
The SDK expects data with these fields:
-
ssid: WiFi network name
- password: WiFi password
- time: Timestamp with milliseconds
- lat: Latitude coordinate
- lng: Longitude coordinate#### Format Details
The transmitted format follows this pattern:
`
{encodedSSID}/{encodedPassword}/CT:{encodedTime}/LT:{encodedLat}/LG:{encodedLng}
`Where:
- All values are URL-encoded using
encodeURIComponent()
- CT: prefix for Current Time
- LT: prefix for Latitude
- LG: prefix for Longitude
- Separated by / and : charactersFormat Explanation:
-
$encodedSSID/$encodedPassword/CT:$encodedTime/LT:$encodedLat/LG:$encodedLng
- All values are URL encoded to handle special characters
- CT: Current Time, LT: Latitude, LG: Longitude
- Time format should be: yyyy-MM-dd HH:mm:ss SSS$3
The SDK can automatically filter devices by name during scanning:
`typescript
// Default behavior - searches for devices starting with 'MedCase'
const sdk = new MedCaseBluetoothSDK();// Custom prefix
const sdk = new MedCaseBluetoothSDK({
deviceNamePrefix: 'CustomDevice'
});
// Exact match with boxId
const sdk = new MedCaseBluetoothSDK({
deviceNamePrefix: 'MedCase',
boxId: '12345' // Will search for exact name 'MedCase12345'
});
`Usage Workflow
$3
1. Initialize SDK - Request permissions and set up Bluetooth
2. Auto-Connect - Use
autoConnectAndDiscover() to automatically find, connect to, and discover services/characteristics
3. Send Data - Use sendData() to transmit information to the device
4. Cleanup - Call cleanup() when done$3
1. Initialize SDK - Request permissions and set up Bluetooth
2. Scan - Use
scanForDevices() to find available devices
3. Connect - Use connectToDevice() to establish connection
4. Discover Services (Optional) - Use discoverServices() and discoverCharacteristics()
5. Send Data - Use sendData() to transmit information
6. Disconnect - Use disconnectFromDevice() when doneExamples
$3
`typescript
import { Configuration } from 'medcase-sdk';// Create configuration instance
const config = new Configuration('C8:F0:9E:7A:79:70', '7908075918');
// Generate URL link
const adminUrl = config.link();
console.log(adminUrl);
// https://admin.medcase.in/admin/partner/C8:F0:9E:7A:79:70/7908075918
// Open in browser
await config.openInBrowser();
// Update configuration
config.updateBoxId('D1:E2:F3:G4:H5:76');
config.updatePhoneNumber('9876543210');
`$3
`typescript
import React, { useState } from 'react';
import { View, TextInput, Button, Alert } from 'react-native';
import { Configuration } from 'medcase-sdk';const ConfigScreen = () => {
const [boxId, setBoxId] = useState('C8:F0:9E:7A:79:70');
const [phoneNumber, setPhoneNumber] = useState('7908075918');
const handleOpenAdmin = async () => {
try {
const config = new Configuration(boxId, phoneNumber);
await config.openInBrowser();
} catch (error) {
Alert.alert('Error', error.message);
}
};
const handleGenerateLink = () => {
try {
const config = new Configuration(boxId, phoneNumber);
const url = config.link();
Alert.alert('Generated URL', url);
} catch (error) {
Alert.alert('Error', error.message);
}
};
return (
value={boxId}
onChangeText={setBoxId}
placeholder="Box ID"
/>
value={phoneNumber}
onChangeText={setPhoneNumber}
placeholder="Phone Number"
keyboardType="phone-pad"
/>
);
};
`See the
example/ directory for a complete working example app that demonstrates both the auto-connect and manual connection approaches, plus the Configuration class usage.TypeScript Support
The SDK includes full TypeScript definitions. Import types as needed:
`typescript
import {
MedCaseBluetoothSDK,
MedCaseDevice,
BluetoothConnection,
MedCaseData,
Configuration
} from 'medcase-sdk';
`Error Handling
The SDK provides comprehensive error handling:
`typescript
sdk.on('error', (error) => {
console.error('SDK Error:', error.message);
// Handle specific errors
if (error.message.includes('Connection timeout')) {
// Handle timeout
} else if (error.message.includes('Bluetooth permissions')) {
// Handle permission issues
}
});
`Troubleshooting
$3
#### "Cannot read property 'createClient' of null"
Cause: This error occurs when the Bluetooth library is not properly installed or linked.
Solutions:
1. Ensure correct library is installed:
`bash
# For Expo projects
npm install react-native-ble-plx expo-constants
# For React Native projects
npm install react-native-ble-manager
`2. For React Native - Link the library:
`bash
cd ios && pod install && cd ..
`3. For Expo - Configure plugin in app.json:
`json
{
"expo": {
"plugins": [
["react-native-ble-plx", {
"isBackgroundEnabled": true,
"modes": ["bluetooth"]
}]
]
}
}
`4. Clean and rebuild:
`bash
# Expo
expo start -c
# React Native
npx react-native run-android --reset-cache
npx react-native run-ios --reset-cache
`#### Bluetooth Support Check Failed
Cause: The Bluetooth library failed to initialize properly.
Solutions:
1. Check platform compatibility:
- iOS: Ensure iOS 10+ device
- Android: Ensure Bluetooth Low Energy support
2. Verify permissions:
- iOS: Check Info.plist has Bluetooth permissions
- Android: Check AndroidManifest.xml has all required permissions
3. Restart Bluetooth:
- Toggle device Bluetooth off/on
- Restart the app
#### Library Version Mismatches
Cause: Using incompatible versions of Bluetooth libraries.
Solution: Use the recommended versions:
`json
{
"dependencies": {
"react-native-ble-manager": "^12.4.1",
"react-native-ble-plx": "^3.5.0",
"expo-constants": "^16.0.2"
}
}
`$3
Enable detailed logging to troubleshoot issues:
`typescript
const sdk = new MedCaseBluetoothSDK({
enableLogging: true // Enables detailed console logs
});
`$3
If the SDK detects the wrong platform, you can manually check:
`typescript
import { getPlatformInfo } from 'medcase-sdk';const platformInfo = getPlatformInfo();
console.log('Platform:', platformInfo);
// Output: { isExpo: boolean, isReactNative: boolean, platform: 'ios'|'android'|'web' }
`Platform Differences
| Feature | Expo | React Native |
|---------|------|--------------|
| Library | react-native-ble-plx | react-native-ble-manager |
| Permissions | Automatic | Manual setup required |
| iOS Setup | Automatic | Info.plist required |
| Android Setup | Plugin configuration | Manifest permissions required |
Contributing
1. Fork the repository
2. Create your feature branch (
git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add amazing feature')
4. Push to the branch (git push origin feature/amazing-feature`)This project is licensed under the MIT License - see the LICENSE file for details.
For support, please open an issue on GitHub or contact the MedCase team.