react-native-sdk-ble-middleware-v2 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE +20 -0
  2. package/Middleware.podspec +21 -0
  3. package/README.md +187 -0
  4. package/android/build.gradle +77 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/com/middleware/MiddlewareModule.kt +23 -0
  8. package/android/src/main/java/com/middleware/MiddlewarePackage.kt +33 -0
  9. package/ios/Middleware.h +5 -0
  10. package/ios/Middleware.mm +21 -0
  11. package/lib/module/NativeMiddleware.js +3 -0
  12. package/lib/module/NativeMiddleware.js.map +1 -0
  13. package/lib/module/context/BLEContext.js +390 -0
  14. package/lib/module/context/BLEContext.js.map +1 -0
  15. package/lib/module/hooks/index.js +2 -0
  16. package/lib/module/hooks/index.js.map +1 -0
  17. package/lib/module/hooks/useBLE.js +167 -0
  18. package/lib/module/hooks/useBLE.js.map +1 -0
  19. package/lib/module/index.js +12 -0
  20. package/lib/module/index.js.map +1 -0
  21. package/lib/module/services/BLEMiddleware.js +252 -0
  22. package/lib/module/services/BLEMiddleware.js.map +1 -0
  23. package/lib/module/services/MockBLEManager.js +94 -0
  24. package/lib/module/services/MockBLEManager.js.map +1 -0
  25. package/lib/module/services/index.js +2 -0
  26. package/lib/module/services/index.js.map +1 -0
  27. package/lib/module/types/index.js +44 -0
  28. package/lib/module/types/index.js.map +1 -0
  29. package/package.json +179 -0
  30. package/react-native.config.js +8 -0
  31. package/src/NativeMiddleware.ts +7 -0
  32. package/src/context/BLEContext.tsx +487 -0
  33. package/src/hooks/index.ts +1 -0
  34. package/src/hooks/useBLE.ts +190 -0
  35. package/src/index.tsx +21 -0
  36. package/src/services/BLEMiddleware.ts +291 -0
  37. package/src/services/MockBLEManager.ts +96 -0
  38. package/src/services/index.ts +1 -0
  39. package/src/types/index.ts +97 -0
@@ -0,0 +1,487 @@
1
+ import React, { createContext, useContext, useState, useEffect } from 'react';
2
+ import type {
3
+ BLEDevice,
4
+ CharacteristicNotification,
5
+ DeviceConnectionState,
6
+ UserRole,
7
+ } from '../types';
8
+ import bleMiddleware from '../services/BLEMiddleware';
9
+
10
+ /**
11
+ * BLE Context State
12
+ */
13
+ interface BLEContextState {
14
+ // Connection state
15
+ bluetoothEnabled: boolean;
16
+ isScanning: boolean;
17
+ discoveredDevices: BLEDevice[];
18
+ connectedDevices: Map<string, DeviceConnectionState>;
19
+
20
+ // Legacy single device support (for backward compatibility)
21
+ connectedDeviceId: string | null;
22
+ isInfusionRunning: boolean;
23
+ ff01Notification: CharacteristicNotification | null;
24
+ ff21Notification: CharacteristicNotification | null;
25
+ ff31Notification: CharacteristicNotification | null;
26
+ ff41Notification: CharacteristicNotification | null;
27
+ ff02Notification: CharacteristicNotification | null;
28
+
29
+ // Actions
30
+ startScan: () => Promise<void>;
31
+ stopScan: () => Promise<void>;
32
+ connectToDevice: (device: BLEDevice) => Promise<void>;
33
+ disconnectDevice: (deviceId: string) => Promise<void>;
34
+ requestPermissions: () => Promise<void>;
35
+
36
+ // Multi-device queries
37
+ getDeviceState: (deviceId: string) => DeviceConnectionState | undefined;
38
+ isDeviceConnected: (deviceId: string) => boolean;
39
+ getConnectedDeviceIds: () => string[];
40
+
41
+ // Infusion actions
42
+ startInfusion: (deviceId: string) => Promise<void>;
43
+ stopInfusion: (deviceId: string) => Promise<void>;
44
+ setInfusionLevel: (deviceId: string, level: number) => Promise<void>;
45
+
46
+ // Characteristic operations
47
+ readCharacteristic: (
48
+ deviceId: string,
49
+ serviceUuid: string,
50
+ characteristicUuid: string
51
+ ) => Promise<any>;
52
+ writeCharacteristic: (
53
+ deviceId: string,
54
+ serviceUuid: string,
55
+ characteristicUuid: string,
56
+ data: string,
57
+ options?: { withResponse?: boolean }
58
+ ) => Promise<void>;
59
+
60
+ // User role management
61
+ setUserRole: (role: UserRole) => void;
62
+ getUserRole: () => UserRole;
63
+ }
64
+
65
+ const BLEContext = createContext<BLEContextState | undefined>(undefined);
66
+
67
+ /**
68
+ * BLE Provider Component
69
+ * Manages all BLE state and operations
70
+ */
71
+ export const BLEProvider: React.FC<{ children: React.ReactNode }> = ({
72
+ children,
73
+ }) => {
74
+ const [bluetoothEnabled, setBluetoothEnabled] = useState(false);
75
+ const [isScanning, setIsScanning] = useState(false);
76
+ const [discoveredDevices, setDiscoveredDevices] = useState<BLEDevice[]>([]);
77
+ const [connectedDevices, setConnectedDevices] = useState<
78
+ Map<string, DeviceConnectionState>
79
+ >(new Map());
80
+
81
+ // Legacy single device support (tracks the first/primary connected device)
82
+ const [connectedDeviceId, setConnectedDeviceId] = useState<string | null>(
83
+ null
84
+ );
85
+
86
+ // Legacy notification states (for the primary device)
87
+ const [ff01Notification, setFF01Notification] =
88
+ useState<CharacteristicNotification | null>(null);
89
+ const [ff21Notification, setFF21Notification] =
90
+ useState<CharacteristicNotification | null>(null);
91
+ const [ff31Notification, setFF31Notification] =
92
+ useState<CharacteristicNotification | null>(null);
93
+ const [ff41Notification, setFF41Notification] =
94
+ useState<CharacteristicNotification | null>(null);
95
+ const [ff02Notification, setFF02Notification] =
96
+ useState<CharacteristicNotification | null>(null);
97
+
98
+ // Legacy infusion state (for the primary device)
99
+ const [isInfusionRunning, setIsInfusionRunning] = useState(false);
100
+
101
+ useEffect(() => {
102
+ const initialize = async () => {
103
+ // Wait for BLE middleware to initialize first
104
+ await bleMiddleware.waitForInitialization();
105
+
106
+ // Then setup BLE and event listeners
107
+ await setupBLE();
108
+ setupEventListeners();
109
+ };
110
+
111
+ initialize();
112
+
113
+ return () => {
114
+ bleMiddleware.removeAllListeners();
115
+ };
116
+ }, []);
117
+
118
+ const setupBLE = async () => {
119
+ try {
120
+ await requestPermissions();
121
+ const enabled = await bleMiddleware.isBluetoothEnabled();
122
+ setBluetoothEnabled(enabled);
123
+ } catch (error) {
124
+ console.error('Failed to setup BLE:', error);
125
+ }
126
+ };
127
+
128
+ const requestPermissions = async () => {
129
+ try {
130
+ await bleMiddleware.requestPermissions();
131
+ } catch (error) {
132
+ console.error('Failed to request permissions:', error);
133
+ }
134
+ };
135
+
136
+ const setupEventListeners = () => {
137
+ // Scan result event
138
+ bleMiddleware.on('scanResult', ({ device }: any) => {
139
+ setDiscoveredDevices((prev) => {
140
+ const exists = prev.find((d) => d.id === device.id);
141
+ if (exists) {
142
+ return prev.map((d) => (d.id === device.id ? device : d));
143
+ }
144
+ return [...prev, device];
145
+ });
146
+ });
147
+
148
+ // Connected event
149
+ bleMiddleware.on('connected', ({ deviceId }: any) => {
150
+ setConnectedDevices((prev) => {
151
+ const newMap = new Map(prev);
152
+ newMap.set(deviceId, {
153
+ deviceId,
154
+ isConnected: true,
155
+ isInfusionRunning: false,
156
+ infusionLevel: null,
157
+ notifications: {
158
+ ff01: null,
159
+ ff21: null,
160
+ ff31: null,
161
+ ff41: null,
162
+ ff02: null,
163
+ },
164
+ });
165
+ return newMap;
166
+ });
167
+
168
+ // Legacy: Set first connected device as primary
169
+ setConnectedDeviceId((prev) => prev || deviceId);
170
+ console.log('✅ Device connected:', deviceId);
171
+ });
172
+
173
+ // Disconnected event
174
+ bleMiddleware.on('disconnected', ({ deviceId }: any) => {
175
+ setConnectedDevices((prev) => {
176
+ const newMap = new Map(prev);
177
+ newMap.delete(deviceId);
178
+ return newMap;
179
+ });
180
+
181
+ // Legacy: Update primary device
182
+ setConnectedDeviceId((prev) => {
183
+ if (prev === deviceId) {
184
+ // If primary device disconnected, set new primary or null
185
+ const remaining = Array.from(connectedDevices.keys()).filter(
186
+ (id) => id !== deviceId
187
+ );
188
+ const newPrimary = remaining[0] || null;
189
+ // Update legacy infusion state
190
+ if (!newPrimary) {
191
+ setIsInfusionRunning(false);
192
+ }
193
+ return newPrimary;
194
+ }
195
+ return prev;
196
+ });
197
+
198
+ console.log('❌ Device disconnected:', deviceId);
199
+ });
200
+
201
+ // Scan failed event
202
+ bleMiddleware.on('BleManagerScanFailed', ({ error }: any) => {
203
+ console.error('BLE Scan Failed:', error);
204
+ setIsScanning(false);
205
+ });
206
+
207
+ // Bluetooth state changed event
208
+ bleMiddleware.on('bluetoothStateChanged', ({ state }: any) => {
209
+ setBluetoothEnabled(state === 'poweredOn');
210
+ });
211
+
212
+ // Characteristic changed event
213
+ bleMiddleware.on('characteristicChanged', (event: any) => {
214
+ console.log('Characteristic Changed Event:', event);
215
+ const { characteristicUuid, deviceId } = event;
216
+ const uuidUpper = characteristicUuid?.toUpperCase();
217
+
218
+ // Update device-specific notifications
219
+ setConnectedDevices((prev) => {
220
+ const newMap = new Map(prev);
221
+ const deviceState = newMap.get(deviceId);
222
+ if (deviceState) {
223
+ const updatedState = { ...deviceState };
224
+ if (uuidUpper === '0000FF01-0000-1000-8000-00805F9B34FB') {
225
+ updatedState.notifications.ff01 = event;
226
+ } else if (uuidUpper === '0000FF21-0000-1000-8000-00805F9B34FB') {
227
+ updatedState.notifications.ff21 = event;
228
+ } else if (uuidUpper === '0000FF31-0000-1000-8000-00805F9B34FB') {
229
+ updatedState.notifications.ff31 = event;
230
+ } else if (uuidUpper === '0000FF41-0000-1000-8000-00805F9B34FB') {
231
+ updatedState.notifications.ff41 = event;
232
+ } else if (uuidUpper === '0000FF02-0000-1000-8000-00805F9B34FB') {
233
+ updatedState.notifications.ff02 = event;
234
+ }
235
+ newMap.set(deviceId, updatedState);
236
+ }
237
+ return newMap;
238
+ });
239
+
240
+ // Legacy: Update global notifications for primary device
241
+ if (deviceId === connectedDeviceId) {
242
+ if (uuidUpper === '0000FF01-0000-1000-8000-00805F9B34FB') {
243
+ setFF01Notification(event);
244
+ } else if (uuidUpper === '0000FF21-0000-1000-8000-00805F9B34FB') {
245
+ setFF21Notification(event);
246
+ } else if (uuidUpper === '0000FF31-0000-1000-8000-00805F9B34FB') {
247
+ setFF31Notification(event);
248
+ } else if (uuidUpper === '0000FF41-0000-1000-8000-00805F9B34FB') {
249
+ setFF41Notification(event);
250
+ } else if (uuidUpper === '0000FF02-0000-1000-8000-00805F9B34FB') {
251
+ setFF02Notification(event);
252
+ } else {
253
+ console.log('⚠️ Unhandled characteristic:', characteristicUuid);
254
+ }
255
+ }
256
+ });
257
+ };
258
+
259
+ const startScan = async () => {
260
+ console.log('Starting device scan...');
261
+ try {
262
+ setDiscoveredDevices([]);
263
+ setIsScanning(true);
264
+ await bleMiddleware.startScan({ timeout: 10000, allowDuplicates: false });
265
+ } catch (error) {
266
+ console.error('Failed to start scan:', error);
267
+ setIsScanning(false);
268
+ }
269
+ };
270
+
271
+ const stopScan = async () => {
272
+ try {
273
+ await bleMiddleware.stopScan();
274
+ setIsScanning(false);
275
+ } catch (error) {
276
+ console.error('Failed to stop scan:', error);
277
+ }
278
+ };
279
+
280
+ const connectToDevice = async (device: BLEDevice) => {
281
+ console.log('Connecting to device:', device);
282
+ try {
283
+ await bleMiddleware.connect(device.id);
284
+ console.log('Connected successfully');
285
+ } catch (error) {
286
+ console.error('Failed to connect:', error);
287
+ }
288
+ };
289
+
290
+ const disconnectDevice = async (deviceId: string) => {
291
+ try {
292
+ await bleMiddleware.disconnect(deviceId);
293
+ // State will be updated in the 'disconnected' event handler
294
+ console.log('Disconnected from device:', deviceId);
295
+ } catch (error) {
296
+ console.error('Failed to disconnect:', error);
297
+ }
298
+ };
299
+
300
+ // Multi-device query helpers
301
+ const getDeviceState = (
302
+ deviceId: string
303
+ ): DeviceConnectionState | undefined => {
304
+ return connectedDevices.get(deviceId);
305
+ };
306
+
307
+ const isDeviceConnected = (deviceId: string): boolean => {
308
+ return connectedDevices.has(deviceId);
309
+ };
310
+
311
+ const getConnectedDeviceIds = (): string[] => {
312
+ return Array.from(connectedDevices.keys());
313
+ };
314
+
315
+ const startInfusion = async (deviceId: string) => {
316
+ try {
317
+ await bleMiddleware.startInfusion(deviceId);
318
+
319
+ // Update device-specific state
320
+ setConnectedDevices((prev) => {
321
+ const newMap = new Map(prev);
322
+ const deviceState = newMap.get(deviceId);
323
+ if (deviceState) {
324
+ newMap.set(deviceId, {
325
+ ...deviceState,
326
+ isInfusionRunning: true,
327
+ });
328
+ }
329
+ return newMap;
330
+ });
331
+
332
+ // Legacy: Update global state if this is the primary device
333
+ if (deviceId === connectedDeviceId) {
334
+ setIsInfusionRunning(true);
335
+ }
336
+
337
+ console.log('✅ Infusion started successfully for device:', deviceId);
338
+ } catch (error) {
339
+ console.error('Failed to start infusion:', error);
340
+ throw error;
341
+ }
342
+ };
343
+
344
+ const stopInfusion = async (deviceId: string) => {
345
+ try {
346
+ await bleMiddleware.stopInfusion(deviceId);
347
+
348
+ // Update device-specific state
349
+ setConnectedDevices((prev) => {
350
+ const newMap = new Map(prev);
351
+ const deviceState = newMap.get(deviceId);
352
+ if (deviceState) {
353
+ newMap.set(deviceId, {
354
+ ...deviceState,
355
+ isInfusionRunning: false,
356
+ });
357
+ }
358
+ return newMap;
359
+ });
360
+
361
+ // Legacy: Update global state if this is the primary device
362
+ if (deviceId === connectedDeviceId) {
363
+ setIsInfusionRunning(false);
364
+ }
365
+
366
+ console.log('✅ Infusion stopped successfully for device:', deviceId);
367
+ } catch (error) {
368
+ console.error('Failed to stop infusion:', error);
369
+ throw error;
370
+ }
371
+ };
372
+
373
+ const setInfusionLevel = async (deviceId: string, level: number) => {
374
+ try {
375
+ await bleMiddleware.setInfusionLevel(deviceId, level);
376
+
377
+ // Update device-specific state
378
+ setConnectedDevices((prev) => {
379
+ const newMap = new Map(prev);
380
+ const deviceState = newMap.get(deviceId);
381
+ if (deviceState) {
382
+ newMap.set(deviceId, {
383
+ ...deviceState,
384
+ infusionLevel: level,
385
+ });
386
+ }
387
+ return newMap;
388
+ });
389
+
390
+ console.log(
391
+ `✅ Infusion level set to ${level} successfully for device:`,
392
+ deviceId
393
+ );
394
+ } catch (error) {
395
+ console.error('Failed to set infusion level:', error);
396
+ throw error;
397
+ }
398
+ };
399
+
400
+ const readCharacteristic = async (
401
+ deviceId: string,
402
+ serviceUuid: string,
403
+ characteristicUuid: string
404
+ ) => {
405
+ try {
406
+ return await bleMiddleware.readCharacteristic(
407
+ deviceId,
408
+ serviceUuid,
409
+ characteristicUuid
410
+ );
411
+ } catch (error) {
412
+ console.error('Failed to read characteristic:', error);
413
+ throw error;
414
+ }
415
+ };
416
+
417
+ const writeCharacteristic = async (
418
+ deviceId: string,
419
+ serviceUuid: string,
420
+ characteristicUuid: string,
421
+ data: string,
422
+ options?: { withResponse?: boolean }
423
+ ) => {
424
+ try {
425
+ await bleMiddleware.writeCharacteristic(
426
+ deviceId,
427
+ serviceUuid,
428
+ characteristicUuid,
429
+ data,
430
+ options
431
+ );
432
+ } catch (error) {
433
+ console.error('Failed to write characteristic:', error);
434
+ throw error;
435
+ }
436
+ };
437
+
438
+ const setUserRole = (role: UserRole) => {
439
+ bleMiddleware.setUserRole(role);
440
+ };
441
+
442
+ const getUserRole = (): UserRole => {
443
+ return bleMiddleware.getUserRole();
444
+ };
445
+
446
+ const value: BLEContextState = {
447
+ bluetoothEnabled,
448
+ isScanning,
449
+ discoveredDevices,
450
+ connectedDevices,
451
+ connectedDeviceId,
452
+ isInfusionRunning,
453
+ ff01Notification,
454
+ ff21Notification,
455
+ ff31Notification,
456
+ ff41Notification,
457
+ ff02Notification,
458
+ startScan,
459
+ stopScan,
460
+ connectToDevice,
461
+ disconnectDevice,
462
+ requestPermissions,
463
+ getDeviceState,
464
+ isDeviceConnected,
465
+ getConnectedDeviceIds,
466
+ startInfusion,
467
+ stopInfusion,
468
+ setInfusionLevel,
469
+ readCharacteristic,
470
+ writeCharacteristic,
471
+ setUserRole,
472
+ getUserRole,
473
+ };
474
+
475
+ return <BLEContext.Provider value={value}>{children}</BLEContext.Provider>;
476
+ };
477
+
478
+ /**
479
+ * Hook to access BLE context
480
+ */
481
+ export const useBLEContext = (): BLEContextState => {
482
+ const context = useContext(BLEContext);
483
+ if (!context) {
484
+ throw new Error('useBLEContext must be used within a BLEProvider');
485
+ }
486
+ return context;
487
+ };
@@ -0,0 +1 @@
1
+ export * from './useBLE';
@@ -0,0 +1,190 @@
1
+ import { useBLEContext } from '../context/BLEContext';
2
+
3
+ /**
4
+ * Hook to access BLE functionality
5
+ * Provides easy access to BLE operations and state
6
+ */
7
+ export const useBLE = () => {
8
+ const context = useBLEContext();
9
+
10
+ return {
11
+ // State
12
+ bluetoothEnabled: context.bluetoothEnabled,
13
+ isScanning: context.isScanning,
14
+ discoveredDevices: context.discoveredDevices,
15
+
16
+ // Multi-device support
17
+ connectedDevices: context.connectedDevices,
18
+ getDeviceState: context.getDeviceState,
19
+ isDeviceConnected: context.isDeviceConnected,
20
+ getConnectedDeviceIds: context.getConnectedDeviceIds,
21
+
22
+ // Legacy single device support (for backward compatibility)
23
+ connectedDeviceId: context.connectedDeviceId,
24
+ isInfusionRunning: context.isInfusionRunning,
25
+
26
+ // Actions
27
+ startScan: context.startScan,
28
+ stopScan: context.stopScan,
29
+ connectToDevice: context.connectToDevice,
30
+ disconnectDevice: context.disconnectDevice,
31
+ requestPermissions: context.requestPermissions,
32
+
33
+ // Infusion control
34
+ startInfusion: context.startInfusion,
35
+ stopInfusion: context.stopInfusion,
36
+ setInfusionLevel: context.setInfusionLevel,
37
+
38
+ // Characteristic operations
39
+ readCharacteristic: context.readCharacteristic,
40
+ writeCharacteristic: context.writeCharacteristic,
41
+
42
+ // User role management
43
+ setUserRole: context.setUserRole,
44
+ getUserRole: context.getUserRole,
45
+ };
46
+ };
47
+
48
+ /**
49
+ * Hook to access characteristic notifications
50
+ */
51
+ export const useBLENotifications = () => {
52
+ const context = useBLEContext();
53
+
54
+ return {
55
+ ff21Notification: context.ff21Notification,
56
+ ff31Notification: context.ff31Notification,
57
+ ff41Notification: context.ff41Notification,
58
+ ff02Notification: context.ff02Notification,
59
+ };
60
+ };
61
+
62
+ /**
63
+ * Hook to get connection status
64
+ */
65
+ export const useBLEConnection = () => {
66
+ const context = useBLEContext();
67
+
68
+ return {
69
+ isConnected: context.connectedDeviceId !== null,
70
+ connectedDeviceId: context.connectedDeviceId,
71
+ disconnect: context.disconnectDevice,
72
+ };
73
+ };
74
+
75
+ /**
76
+ * Hook to access discovered devices
77
+ */
78
+ export const useBLEDevices = () => {
79
+ const context = useBLEContext();
80
+
81
+ return {
82
+ devices: context.discoveredDevices,
83
+ isScanning: context.isScanning,
84
+ startScan: context.startScan,
85
+ stopScan: context.stopScan,
86
+ };
87
+ };
88
+
89
+ /**
90
+ * Hook for infusion control
91
+ */
92
+ export const useBLEInfusion = () => {
93
+ const context = useBLEContext();
94
+
95
+ return {
96
+ isInfusionRunning: context.isInfusionRunning,
97
+ startInfusion: context.startInfusion,
98
+ stopInfusion: context.stopInfusion,
99
+ setInfusionLevel: context.setInfusionLevel,
100
+ connectedDeviceId: context.connectedDeviceId,
101
+ };
102
+ };
103
+
104
+ /**
105
+ * Hook for characteristic operations
106
+ */
107
+ export const useBLECharacteristics = () => {
108
+ const context = useBLEContext();
109
+
110
+ return {
111
+ readCharacteristic: context.readCharacteristic,
112
+ writeCharacteristic: context.writeCharacteristic,
113
+ connectedDeviceId: context.connectedDeviceId,
114
+ };
115
+ };
116
+
117
+ /**
118
+ * Hook for multi-device management
119
+ * Provides access to all connected devices and their states
120
+ */
121
+ export const useBLEMultiDevice = () => {
122
+ const context = useBLEContext();
123
+
124
+ return {
125
+ connectedDevices: context.connectedDevices,
126
+ getDeviceState: context.getDeviceState,
127
+ isDeviceConnected: context.isDeviceConnected,
128
+ getConnectedDeviceIds: context.getConnectedDeviceIds,
129
+ connectToDevice: context.connectToDevice,
130
+ disconnectDevice: context.disconnectDevice,
131
+ };
132
+ };
133
+
134
+ /**
135
+ * Hook for specific device notifications
136
+ * @param deviceId - The device ID to get notifications for
137
+ */
138
+ export const useBLEDeviceNotifications = (deviceId: string | null) => {
139
+ const context = useBLEContext();
140
+
141
+ if (!deviceId) {
142
+ return {
143
+ ff21Notification: null,
144
+ ff31Notification: null,
145
+ ff41Notification: null,
146
+ ff02Notification: null,
147
+ };
148
+ }
149
+
150
+ const deviceState = context.getDeviceState(deviceId);
151
+
152
+ return {
153
+ ff21Notification: deviceState?.notifications.ff21 || null,
154
+ ff31Notification: deviceState?.notifications.ff31 || null,
155
+ ff41Notification: deviceState?.notifications.ff41 || null,
156
+ ff02Notification: deviceState?.notifications.ff02 || null,
157
+ };
158
+ };
159
+
160
+ /**
161
+ * Hook for specific device infusion control
162
+ * @param deviceId - The device ID to control infusion for
163
+ */
164
+ export const useBLEDeviceInfusion = (deviceId: string | null) => {
165
+ const context = useBLEContext();
166
+
167
+ const deviceState = deviceId ? context.getDeviceState(deviceId) : undefined;
168
+
169
+ return {
170
+ deviceId,
171
+ isConnected: deviceId ? context.isDeviceConnected(deviceId) : false,
172
+ isInfusionRunning: deviceState?.isInfusionRunning || false,
173
+ infusionLevel: deviceState?.infusionLevel || null,
174
+ startInfusion: deviceId
175
+ ? () => context.startInfusion(deviceId)
176
+ : async () => {
177
+ throw new Error('No device selected');
178
+ },
179
+ stopInfusion: deviceId
180
+ ? () => context.stopInfusion(deviceId)
181
+ : async () => {
182
+ throw new Error('No device selected');
183
+ },
184
+ setInfusionLevel: deviceId
185
+ ? (level: number) => context.setInfusionLevel(deviceId, level)
186
+ : async () => {
187
+ throw new Error('No device selected');
188
+ },
189
+ };
190
+ };
package/src/index.tsx ADDED
@@ -0,0 +1,21 @@
1
+ // Export types
2
+ export * from './types';
3
+
4
+ // Export BLE Middleware service
5
+ export { default as bleMiddleware } from './services/BLEMiddleware';
6
+
7
+ // Export Context and Provider
8
+ export { BLEProvider, useBLEContext } from './context/BLEContext';
9
+
10
+ // Export hooks
11
+ export {
12
+ useBLE,
13
+ useBLENotifications,
14
+ useBLEConnection,
15
+ useBLEDevices,
16
+ useBLEInfusion,
17
+ useBLECharacteristics,
18
+ useBLEMultiDevice,
19
+ useBLEDeviceNotifications,
20
+ useBLEDeviceInfusion,
21
+ } from './hooks/useBLE';