react-native-flic2 2.0.0-alpha.38 → 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 +733 -13
- package/android/src/main/java/com/flic2/Flic2ButtonListener.kt +6 -10
- package/android/src/main/java/com/flic2/Flic2Module.kt +33 -32
- package/ios/Flic2.h +0 -1
- package/ios/Flic2.mm +211 -183
- package/lib/module/NativeFlic2.js +26 -0
- package/lib/module/NativeFlic2.js.map +1 -1
- package/lib/module/index.bak.js +161 -0
- package/lib/module/index.bak.js.map +1 -0
- package/lib/module/index.js +256 -76
- package/lib/module/index.js.map +1 -1
- package/lib/module/lib/typedEventEmitter.js +39 -0
- package/lib/module/lib/typedEventEmitter.js.map +1 -0
- package/lib/typescript/src/NativeFlic2.d.ts +30 -11
- package/lib/typescript/src/NativeFlic2.d.ts.map +1 -1
- package/lib/typescript/src/index.bak.d.ts +1 -0
- package/lib/typescript/src/index.bak.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +198 -80
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/lib/typedEventEmitter.d.ts +15 -0
- package/lib/typescript/src/lib/typedEventEmitter.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/NativeFlic2.ts +32 -19
- package/src/index.bak.tsx +159 -0
- package/src/index.ts +382 -0
- package/src/lib/typedEventEmitter.ts +63 -0
- package/src/index.tsx +0 -159
package/README.md
CHANGED
|
@@ -1,27 +1,752 @@
|
|
|
1
1
|
# react-native-flic2
|
|
2
2
|
|
|
3
|
-
React Native
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
```
|
|
18
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
|
|
39
|
-
|
|
759
|
+
See [LICENSE](LICENSE)
|