react-native-flic2 2.0.0-alpha.39 → 2.0.0-beta.1

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.
package/README.md CHANGED
@@ -1,27 +1,752 @@
1
1
  # react-native-flic2
2
2
 
3
- React Native Flic plugin made with the Flic2 SDK (unofficial)
3
+ React Native library for integrating Flic2 buttons into your React Native application. This library provides a complete interface to discover, connect, and interact with Flic2 buttons on both iOS and Android platforms.
4
4
 
5
- ## Installation
5
+ ## Features
6
+
7
+ - 🔍 Scan and discover Flic2 buttons
8
+ - 🔗 Connect and manage multiple buttons
9
+ - 📱 Receive button events (click, double click, hold)
10
+ - 🔋 Monitor battery status
11
+ - 🏷️ Set custom nicknames for buttons
12
+ - ⚙️ Configure trigger and latency modes
13
+ - 📡 Background connection support
14
+
15
+ > **⚠️ Important Notice**
16
+ >
17
+ > Parts of this project, including documentation and code examples, may have been generated with the assistance of AI tools and may contain errors. Please review all code and documentation carefully before use.
18
+ >
19
+ > This software is provided "AS IS" without warranty of any kind. Please refer to the [LICENSE](LICENSE) file for complete liability disclaimers. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability arising from the use of this software.
6
20
 
21
+ ## Version Information
22
+
23
+ **This is a complete rewrite of react-native-flic2 (version 2.x.x).** This version requires React Native 0.81.x or higher. We do not provide a breaking changes list or migration guide. If you are upgrading from version 1.x.x, you should restart your implementation based on the examples and documentation provided in this README. The API and architecture have been completely redesigned.
24
+
25
+ If you need support for older React Native versions, please use version 1.x.x of this package instead.
26
+
27
+ ## Installation
7
28
 
8
29
  ```sh
9
30
  npm install react-native-flic2
31
+ ```
32
+
33
+ ### iOS Setup
34
+
35
+ 1. **Install CocoaPods dependencies:**
36
+ ```sh
37
+ cd ios && pod install && cd ..
38
+ ```
39
+
40
+ 2. **Add Bluetooth permissions to `Info.plist`:**
41
+ Add the following keys to your `ios/YourApp/Info.plist`:
42
+ ```xml
43
+ <key>NSBluetoothPeripheralUsageDescription</key>
44
+ <string>This app needs Bluetooth to connect to Flic buttons</string>
45
+ <key>NSBluetoothAlwaysUsageDescription</key>
46
+ <string>This app needs Bluetooth to connect to Flic buttons in the background</string>
47
+ ```
48
+
49
+ 3. **Enable Background Modes:**
50
+ - Open your project in Xcode
51
+ - Select your app target
52
+ - Go to "Signing & Capabilities"
53
+ - Add "Background Modes" capability if not already added
54
+ - Check "Uses Bluetooth LE accessories"
55
+
56
+ ### Android Setup
57
+
58
+ The library automatically includes the necessary permissions in `AndroidManifest.xml`. However, you need to request runtime permissions in your app:
59
+
60
+ **For Android 12+ (API 31+):**
61
+ - `BLUETOOTH_SCAN`
62
+ - `BLUETOOTH_CONNECT`
63
+
64
+ **For Android 11 and below:**
65
+ - `ACCESS_FINE_LOCATION`
66
+
67
+ You'll need to request these permissions before scanning for buttons. Use a library like `react-native-permissions` or implement permission requests manually.
68
+
69
+ ## Basic Usage
70
+
71
+ ### 1. Initialize the Library (Global Setup)
72
+
73
+ **Important:** For background usage, initialize Flic2 at the global level (outside of React components), typically in your app's entry point (e.g., `index.js` or `App.js`). Initializing in a `useEffect` is too late for background functionality.
74
+
75
+ ```tsx
76
+ // index.js or App.js (global level, outside components)
77
+ import Flic2, {
78
+ ButtonEvent,
79
+ ManagerStateChangeEvent,
80
+ } from 'react-native-flic2';
81
+
82
+ // Initialize the Flic2 manager when app starts
83
+ (async () => {
84
+ try {
85
+ await Flic2.initialize();
86
+ console.log('Flic2 initialized');
87
+
88
+ // Connect to all previously known buttons
89
+ Flic2.connectAllKnownButtons();
90
+
91
+ // Set up global event listeners for background usage
92
+ Flic2.eventEmitter.on('buttonEvent', (event: ButtonEvent) => {
93
+ console.log('Button event:', event.event, event.button.name);
94
+
95
+ // Handle button events that need to work in background
96
+ if (event.event === 'click') {
97
+ // Your background logic here (e.g., send notification, update database)
98
+ }
99
+ });
100
+
101
+ Flic2.eventEmitter.on('managerStateChange', (event: ManagerStateChangeEvent) => {
102
+ console.log('Manager state:', event.stateName);
103
+ });
104
+ } catch (error) {
105
+ console.error('Failed to initialize Flic2:', error);
106
+ }
107
+ })();
108
+ ```
109
+
110
+ ### 2. Set Up Component-Level Event Listeners (Optional)
111
+
112
+ If you need to update UI based on button events, you can add additional listeners in your components using `useEffect`. These listeners are in addition to the global ones and are useful for UI-specific updates:
113
+
114
+ ```tsx
115
+ import React, { useEffect } from 'react';
116
+ import { Alert } from 'react-native';
117
+ import Flic2, {
118
+ ButtonEvent,
119
+ ScanStatusChangeEvent,
120
+ } from 'react-native-flic2';
121
+
122
+ const MyComponent = () => {
123
+ useEffect(() => {
124
+ // UI-specific listener (only needed if you want to show UI updates)
125
+ const buttonSubscription = Flic2.eventEmitter.on(
126
+ 'buttonEvent',
127
+ (event: ButtonEvent) => {
128
+ if (event.event === 'click' || event.event === 'doubleClick' || event.event === 'hold') {
129
+ // Show UI alert when component is mounted
130
+ Alert.alert(
131
+ event.button.nickname || event.button.name,
132
+ `${event.event} at ${new Date().toLocaleTimeString()}`
133
+ );
134
+ }
135
+ }
136
+ );
137
+
138
+ const scanSubscription = Flic2.eventEmitter.on(
139
+ 'scanStatusChange',
140
+ (event: ScanStatusChangeEvent) => {
141
+ // Update UI based on scan status
142
+ if (event.event === 'started') {
143
+ console.log('Scan started');
144
+ } else if (event.event === 'completion') {
145
+ console.log('Scan completed');
146
+ }
147
+ }
148
+ );
149
+
150
+ // Cleanup subscriptions on unmount
151
+ return () => {
152
+ buttonSubscription.remove();
153
+ scanSubscription.remove();
154
+ };
155
+ }, []);
156
+
157
+ // ... rest of component
158
+ };
159
+ ```
160
+
161
+ **Note:** Global listeners (set up outside components) will continue to work even when components unmount, which is essential for background functionality. Component-level listeners are only active when the component is mounted.
162
+
163
+ ### 3. Complete Example
164
+
165
+ This example shows a component that manages the UI for Flic2 buttons. **Note:** Flic2 should be initialized globally (see section 1) before this component is used. This component only handles UI-specific functionality.
166
+
167
+ **Important:** This is just an example demonstrating the library's API. Some parts (like `Alert.prompt` used in `renameButton`) are iOS-only and need platform-specific implementations for Android. Adapt the UI components to your needs and platform requirements.
168
+
169
+ ```tsx
170
+ import React, { useState, useEffect } from 'react';
171
+ import { View, Text, Button, Alert, StyleSheet } from 'react-native';
172
+ import Flic2, {
173
+ ButtonEvent,
174
+ FlicButton,
175
+ ScanStatusChangeEvent,
176
+ } from 'react-native-flic2';
177
+
178
+ const Flic2Example = () => {
179
+ const [buttons, setButtons] = useState<FlicButton[]>([]);
180
+ const [isScanning, setIsScanning] = useState(false);
181
+
182
+ useEffect(() => {
183
+ // Load existing buttons when component mounts
184
+ // (Flic2 should already be initialized globally)
185
+ loadButtons();
186
+
187
+ // Set up UI-specific event listeners
188
+ // Note: Global listeners should be set up outside components for background usage
189
+ const buttonSubscription = Flic2.eventEmitter.on(
190
+ 'buttonEvent',
191
+ (event: ButtonEvent) => {
192
+ console.log('Button event:', event.event, event.button.name);
193
+
194
+ // Show UI alerts when component is mounted
195
+ if (event.event === 'click' || event.event === 'doubleClick' || event.event === 'hold') {
196
+ Alert.alert(
197
+ event.button.nickname || event.button.name,
198
+ `${event.event} at ${new Date().toLocaleTimeString()}`
199
+ );
200
+ }
201
+ }
202
+ );
203
+
204
+ const scanSubscription = Flic2.eventEmitter.on(
205
+ 'scanStatusChange',
206
+ (event: ScanStatusChangeEvent) => {
207
+ console.log('Scan status:', event.event);
208
+
209
+ // Update UI state based on scan status
210
+ if (event.event === 'started') {
211
+ setIsScanning(true);
212
+ } else if (event.event === 'completion') {
213
+ setIsScanning(false);
214
+ loadButtons(); // Refresh button list after scan
215
+ }
216
+ }
217
+ );
218
+
219
+ // Cleanup subscriptions on unmount
220
+ return () => {
221
+ buttonSubscription.remove();
222
+ scanSubscription.remove();
223
+ };
224
+ }, []);
225
+
226
+ const loadButtons = async () => {
227
+ try {
228
+ const buttonList = await Flic2.getButtons();
229
+ setButtons(buttonList);
230
+ console.log('Loaded buttons:', buttonList.length);
231
+ } catch (error) {
232
+ console.error('Failed to load buttons:', error);
233
+ }
234
+ };
235
+
236
+ const startScan = async () => {
237
+ try {
238
+ // Check if already scanning
239
+ const scanning = await Flic2.isScanning();
240
+ if (scanning) {
241
+ console.log('Already scanning');
242
+ return;
243
+ }
244
+
245
+ // Request permissions here if needed (see Platform Setup)
246
+
247
+ await Flic2.startScan();
248
+ console.log('Scan started');
249
+ } catch (error) {
250
+ console.error('Failed to start scan:', error);
251
+ Alert.alert('Error', 'Failed to start scanning for buttons');
252
+ }
253
+ };
254
+
255
+ const stopScan = async () => {
256
+ try {
257
+ await Flic2.stopScan();
258
+ console.log('Scan stopped');
259
+ } catch (error) {
260
+ console.error('Failed to stop scan:', error);
261
+ }
262
+ };
263
+
264
+ const renameButton = (button: FlicButton) => {
265
+ // Note: Alert.prompt is iOS-only. On Android, use a TextInput in a Modal
266
+ // or a library like react-native-prompt-android for cross-platform support.
267
+ // This is just an example - implement appropriately for your platform needs.
268
+ Alert.prompt(
269
+ 'Rename Button',
270
+ 'Enter a new name for the button',
271
+ [
272
+ { text: 'Cancel', style: 'cancel' },
273
+ {
274
+ text: 'Save',
275
+ onPress: async (value) => {
276
+ if (!value) return;
277
+ try {
278
+ await Flic2.buttonSetNickname(button.uuid, value);
279
+ loadButtons(); // Refresh button list
280
+ } catch (error) {
281
+ console.error('Failed to rename button:', error);
282
+ }
283
+ },
284
+ },
285
+ ],
286
+ 'plain-text',
287
+ button.nickname
288
+ );
289
+ };
290
+
291
+ const forgetButton = (button: FlicButton) => {
292
+ Alert.alert(
293
+ 'Delete Button',
294
+ 'Are you sure you want to delete this button?',
295
+ [
296
+ { text: 'Cancel', style: 'cancel' },
297
+ {
298
+ text: 'Delete',
299
+ style: 'destructive',
300
+ onPress: async () => {
301
+ try {
302
+ await Flic2.forgetButton(button.uuid);
303
+ loadButtons(); // Refresh button list
304
+ } catch (error) {
305
+ console.error('Failed to forget button:', error);
306
+ }
307
+ },
308
+ },
309
+ ]
310
+ );
311
+ };
312
+
313
+ const showButtonOptions = (button: FlicButton) => {
314
+ Alert.alert(
315
+ 'Button Options',
316
+ button.nickname || button.name,
317
+ [
318
+ { text: 'Rename', onPress: () => renameButton(button) },
319
+ { text: 'Delete', onPress: () => forgetButton(button) },
320
+ { text: 'Cancel', style: 'cancel' },
321
+ ]
322
+ );
323
+ };
324
+
325
+ return (
326
+ <View style={styles.container}>
327
+ <Text style={styles.title}>Flic2 Example</Text>
328
+
329
+ <Button
330
+ title={isScanning ? 'Stop Scanning' : 'Scan for Buttons'}
331
+ onPress={isScanning ? stopScan : startScan}
332
+ />
333
+
334
+ <Button title="Refresh Buttons" onPress={loadButtons} />
335
+
336
+ <Text style={styles.count}>
337
+ Buttons: {buttons.length}
338
+ </Text>
339
+
340
+ {buttons.map((button) => (
341
+ <View key={button.uuid} style={styles.buttonItem}>
342
+ <Text style={styles.buttonName}>
343
+ {button.nickname || button.name}
344
+ </Text>
345
+ <Text style={styles.buttonUuid}>{button.uuid}</Text>
346
+ <Button
347
+ title="Options"
348
+ onPress={() => showButtonOptions(button)}
349
+ />
350
+ </View>
351
+ ))}
352
+ </View>
353
+ );
354
+ };
355
+
356
+ const styles = StyleSheet.create({
357
+ container: {
358
+ flex: 1,
359
+ padding: 20,
360
+ },
361
+ title: {
362
+ fontSize: 24,
363
+ fontWeight: 'bold',
364
+ marginBottom: 20,
365
+ },
366
+ count: {
367
+ fontSize: 18,
368
+ marginVertical: 10,
369
+ },
370
+ buttonItem: {
371
+ padding: 10,
372
+ marginVertical: 5,
373
+ backgroundColor: '#f0f0f0',
374
+ borderRadius: 5,
375
+ },
376
+ buttonName: {
377
+ fontSize: 16,
378
+ fontWeight: 'bold',
379
+ },
380
+ buttonUuid: {
381
+ fontSize: 12,
382
+ color: '#666',
383
+ },
384
+ });
385
+
386
+ export default Flic2Example;
387
+ ```
388
+
389
+ ## API Reference
390
+
391
+ ### Initialization
392
+
393
+ #### `initialize(): Promise<boolean>`
394
+
395
+ Initialize the Flic2 manager. This must be called before using any other methods.
396
+
397
+ ```tsx
398
+ await Flic2.initialize();
399
+ ```
400
+
401
+ ### Scanning
402
+
403
+ #### `startScan(): Promise<{ success: boolean; message: string }>`
404
+
405
+ Start scanning for new Flic2 buttons. The scan will emit `scanStatusChange` events.
406
+
407
+ ```tsx
408
+ await Flic2.startScan();
409
+ ```
410
+
411
+ #### `stopScan(): Promise<{ success: boolean; message: string }>`
412
+
413
+ Stop an ongoing scan.
414
+
415
+ ```tsx
416
+ await Flic2.stopScan();
417
+ ```
418
+
419
+ #### `isScanning(): Promise<boolean>`
420
+
421
+ Check if a scan is currently running.
422
+
423
+ ```tsx
424
+ const scanning = await Flic2.isScanning();
425
+ ```
426
+
427
+ ### Button Management
428
+
429
+ #### `getButtons(): Promise<FlicButton[]>`
430
+
431
+ Get all known buttons.
432
+
433
+ ```tsx
434
+ const buttons = await Flic2.getButtons();
435
+ ```
436
+
437
+ #### `getButton(uuid: string): Promise<FlicButton | null>`
10
438
 
439
+ Get a specific button by UUID.
440
+
441
+ ```tsx
442
+ const button = await Flic2.getButton('button-uuid');
443
+ ```
444
+
445
+ #### `connectAllKnownButtons(): Promise<{ success: boolean; message: string }>`
446
+
447
+ Connect to all previously known buttons.
448
+
449
+ ```tsx
450
+ await Flic2.connectAllKnownButtons();
451
+ ```
452
+
453
+ #### `disconnectAllKnownButtons(): Promise<{ success: boolean; message: string }>`
454
+
455
+ Disconnect all connected buttons.
456
+
457
+ ```tsx
458
+ await Flic2.disconnectAllKnownButtons();
459
+ ```
460
+
461
+ #### `forgetButton(uuid: string): Promise<{ success: boolean; message: string }>`
462
+
463
+ Forget (unpair) a specific button.
464
+
465
+ ```tsx
466
+ await Flic2.forgetButton('button-uuid');
467
+ ```
468
+
469
+ #### `forgetAllButtons(): Promise<{ success: boolean; message: string }>`
470
+
471
+ Forget all buttons.
472
+
473
+ ```tsx
474
+ await Flic2.forgetAllButtons();
475
+ ```
476
+
477
+ ### Button Configuration
478
+
479
+ #### `buttonConnect(uuid: string): Promise<{ success: boolean; message: string }>`
480
+
481
+ Connect to a specific button.
482
+
483
+ ```tsx
484
+ await Flic2.buttonConnect('button-uuid');
485
+ ```
486
+
487
+ #### `buttonDisconnect(uuid: string): Promise<{ success: boolean; message: string }>`
488
+
489
+ Disconnect a specific button.
490
+
491
+ ```tsx
492
+ await Flic2.buttonDisconnect('button-uuid');
493
+ ```
494
+
495
+ #### `buttonSetNickname(uuid: string, nickname: string): Promise<{ success: boolean; message: string }>`
496
+
497
+ Set a custom nickname for a button.
498
+
499
+ ```tsx
500
+ await Flic2.buttonSetNickname('button-uuid', 'My Button');
501
+ ```
502
+
503
+ #### `buttonSetTriggerMode(uuid: string, mode: TriggerModeType): Promise<{ success: boolean; message: string }>`
504
+
505
+ Set the trigger mode for a button. Modes:
506
+ - `0`: Click and Hold
507
+ - `1`: Click and Double Click
508
+ - `2`: Click and Double Click and Hold
509
+ - `3`: Click only
510
+
511
+ ```tsx
512
+ await Flic2.buttonSetTriggerMode('button-uuid', 3); // Click only
513
+ ```
514
+
515
+ #### `buttonSetLatencyMode(uuid: string, mode: LatencyModeType): Promise<{ success: boolean; message: string }>`
516
+
517
+ Set the latency mode for a button. Modes:
518
+ - `0`: Normal latency
519
+ - `1`: Low latency
520
+
521
+ ```tsx
522
+ await Flic2.buttonSetLatencyMode('button-uuid', 1); // Low latency
523
+ ```
524
+
525
+ #### `getBatteryHealth(uuid: string): Promise<boolean>`
526
+
527
+ Get the battery health status of a button. Returns `true` if battery voltage is above 2.65V.
528
+
529
+ ```tsx
530
+ const isHealthy = await Flic2.getBatteryHealth('button-uuid');
531
+ ```
532
+
533
+ ## Events
534
+
535
+ The library uses an event emitter pattern to notify your app of button events and state changes.
536
+
537
+ ### `buttonEvent`
538
+
539
+ Emitted when a button event occurs (click, double click, hold, connection, etc.).
540
+
541
+ ```tsx
542
+ Flic2.eventEmitter.on('buttonEvent', (event: ButtonEvent) => {
543
+ console.log('Event:', event.event);
544
+ console.log('Button:', event.button.name);
545
+ console.log('UUID:', event.uuid);
546
+ });
547
+ ```
548
+
549
+ **Event Types:**
550
+ - `'discovered'` - Button was discovered during scan
551
+ - `'connected'` - Button connected successfully
552
+ - `'ready'` - Button is ready to receive events
553
+ - `'disconnected'` - Button disconnected
554
+ - `'connectionFailed'` - Connection attempt failed
555
+ - `'buttonDown'` - Button was pressed down
556
+ - `'buttonUp'` - Button was released
557
+ - `'click'` - Single click detected
558
+ - `'doubleClick'` - Double click detected
559
+ - `'hold'` - Button held down
560
+ - `'unpaired'` - Button was unpaired
561
+ - `'batteryUpdate'` - Battery status updated
562
+ - `'nicknameUpdate'` - Nickname was updated
563
+
564
+ **Event Object:**
565
+ ```tsx
566
+ type ButtonEvent = {
567
+ uuid: string;
568
+ event: string;
569
+ queued?: boolean;
570
+ age?: number;
571
+ nickname?: string;
572
+ voltage?: number;
573
+ batteryVoltageOk?: boolean;
574
+ error?: {
575
+ code: number;
576
+ message: string;
577
+ };
578
+ button: FlicButton;
579
+ };
580
+ ```
581
+
582
+ ### `managerStateChange`
583
+
584
+ Emitted when the Flic2 manager state changes (Bluetooth state, etc.).
585
+
586
+ ```tsx
587
+ Flic2.eventEmitter.on('managerStateChange', (event: ManagerStateChangeEvent) => {
588
+ console.log('State:', event.stateName);
589
+ console.log('State code:', event.state);
590
+ });
591
+ ```
592
+
593
+ **Event Object:**
594
+ ```tsx
595
+ type ManagerStateChangeEvent = {
596
+ event: 'restored' | 'stateChanged';
597
+ state?: number;
598
+ stateName?: string;
599
+ message?: string;
600
+ };
601
+ ```
602
+
603
+ **State Names:**
604
+ - `'unknown'`
605
+ - `'resetting'`
606
+ - `'unsupported'`
607
+ - `'unauthorized'`
608
+ - `'poweredOff'`
609
+ - `'poweredOn'`
610
+
611
+ ### `scanStatusChange`
612
+
613
+ Emitted when the scan status changes.
614
+
615
+ ```tsx
616
+ Flic2.eventEmitter.on('scanStatusChange', (event: ScanStatusChangeEvent) => {
617
+ if (event.event === 'started') {
618
+ console.log('Scan started');
619
+ } else if (event.event === 'completion') {
620
+ console.log('Scan completed', event.result);
621
+ }
622
+ });
623
+ ```
624
+
625
+ **Event Object:**
626
+ ```tsx
627
+ type ScanStatusChangeEvent = {
628
+ event: 'started' | 'completion';
629
+ eventName: 'started' | 'completion';
630
+ result?: ScanResult;
631
+ };
632
+ ```
633
+
634
+ ## Types
635
+
636
+ ### `FlicButton`
637
+
638
+ ```tsx
639
+ type FlicButton = {
640
+ uuid: string;
641
+ identifier: string;
642
+ name: string;
643
+ nickname: string;
644
+ bluetoothAddress: string;
645
+ serialNumber: string;
646
+ state: number;
647
+ stateName: string;
648
+ triggerMode: number; // iOS only, 0 on Android
649
+ triggerModeName: string; // iOS only, empty on Android
650
+ latencyMode: number; // iOS only, 0 on Android
651
+ latencyModeName: string; // iOS only, empty on Android
652
+ pressCount: number;
653
+ firmwareRevision: number;
654
+ isReady: boolean;
655
+ batteryVoltage: number;
656
+ isUnpaired: boolean;
657
+ };
658
+ ```
659
+
660
+ ## Common Use Cases
661
+
662
+ ### Connecting to Buttons on App Start
663
+
664
+ Initialize Flic2 globally when your app starts (not in a component):
665
+
666
+ ```tsx
667
+ // index.js or App.js (global level)
668
+ import Flic2 from 'react-native-flic2';
669
+
670
+ (async () => {
671
+ await Flic2.initialize();
672
+ Flic2.connectAllKnownButtons();
673
+ })();
674
+ ```
675
+
676
+ ### Handling Button Clicks
677
+
678
+ Set up button event listeners globally for background usage:
679
+
680
+ ```tsx
681
+ // Global level (e.g., index.js or App.js)
682
+ Flic2.eventEmitter.on('buttonEvent', (event) => {
683
+ if (event.event === 'click') {
684
+ // Handle single click (works in background)
685
+ console.log('Button clicked:', event.button.name);
686
+ } else if (event.event === 'doubleClick') {
687
+ // Handle double click
688
+ console.log('Button double clicked:', event.button.name);
689
+ } else if (event.event === 'hold') {
690
+ // Handle hold
691
+ console.log('Button held:', event.button.name);
692
+ }
693
+ });
11
694
  ```
12
695
 
696
+ ### Monitoring Battery Status
13
697
 
14
- ## Usage
698
+ ```tsx
699
+ Flic2.eventEmitter.on('buttonEvent', (event) => {
700
+ if (event.event === 'batteryUpdate') {
701
+ const isHealthy = event.batteryVoltageOk;
702
+ console.log('Battery healthy:', isHealthy);
703
+ console.log('Battery voltage:', event.voltage);
704
+ }
705
+ });
706
+ ```
15
707
 
708
+ ### Scanning for New Buttons
16
709
 
17
- ```js
18
- import { multiply } from 'react-native-flic2';
710
+ ```tsx
711
+ const scanForButtons = async () => {
712
+ // Request permissions first (see Platform Setup)
19
713
 
20
- // ...
714
+ Flic2.eventEmitter.on('scanStatusChange', (event) => {
715
+ if (event.event === 'completion') {
716
+ if (event.result === 0) { // ScanResult.SUCCESS
717
+ console.log('Button found and paired!');
718
+ loadButtons();
719
+ } else {
720
+ console.log('Scan failed:', event.result);
721
+ }
722
+ }
723
+ });
21
724
 
22
- const result = multiply(3, 7);
725
+ await Flic2.startScan();
726
+ };
23
727
  ```
24
728
 
729
+ ## Troubleshooting
730
+
731
+ ### Buttons not connecting
732
+
733
+ - Ensure Bluetooth is enabled on the device
734
+ - Check that you've requested the necessary permissions
735
+ - Verify the button is in pairing mode (press and hold for 7 seconds)
736
+ - Make sure the button isn't already connected to another device
737
+
738
+ ### Scan not starting
739
+
740
+ - Verify runtime permissions are granted (especially location permission on Android)
741
+ - Check that Bluetooth is enabled
742
+ - Ensure you're not already scanning (check with `isScanning()`)
743
+
744
+ ### Events not firing
745
+
746
+ - Make sure you've called `initialize()` globally (outside components) before setting up event listeners
747
+ - For background usage, set up listeners at the global level, not in `useEffect`
748
+ - Verify the button is connected and ready (`button.isReady === true`)
749
+ - Check that the button's trigger mode supports the event you're listening for
25
750
 
26
751
  ## Contributing
27
752
 
@@ -31,9 +756,4 @@ const result = multiply(3, 7);
31
756
 
32
757
  ## License
33
758
 
34
- MIT
35
-
36
- ---
37
-
38
- Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
39
-
759
+ See [LICENSE](LICENSE)