ilabs-flir 2.2.12 → 2.2.13

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.
@@ -4,7 +4,6 @@ import android.content.Context
4
4
  import android.graphics.Bitmap
5
5
  import android.util.Log
6
6
  import com.facebook.react.bridge.Arguments
7
- import com.facebook.react.bridge.ReactApplicationContext
8
7
  import com.facebook.react.bridge.ReactContext
9
8
  import com.facebook.react.bridge.WritableArray
10
9
  import com.facebook.react.bridge.WritableMap
@@ -17,17 +16,15 @@ import java.util.concurrent.atomic.AtomicLong
17
16
 
18
17
  /**
19
18
  * Simplified FlirManager - bridge between React Native and FlirSdkManager
20
- * No filtering - returns ALL discovered devices (USB, Network, Emulator)
21
- * Let React Native handle any filtering logic
19
+ * Matches the simplified pattern: scan -> connect -> stream -> disconnect
22
20
  */
23
21
  object FlirManager {
24
22
  private const val TAG = "FlirManager"
25
23
 
26
24
  private var sdkManager: FlirSdkManager? = null
27
25
  private var reactContext: ReactContext? = null
28
- private var appContext: Context? = null
29
26
 
30
- // Frame rate limiting
27
+ // Frame rate limiting for RN events
31
28
  private val lastEmitMs = AtomicLong(0)
32
29
  private val minEmitIntervalMs = 100L // ~10 fps max for RN events
33
30
 
@@ -39,7 +36,7 @@ object FlirManager {
39
36
  private var connectedDeviceId: String? = null
40
37
  private var connectedDeviceName: String? = null
41
38
 
42
- // Latest bitmap for texture updates
39
+ // Latest bitmap
43
40
  private var latestBitmap: Bitmap? = null
44
41
 
45
42
  // Callbacks
@@ -47,82 +44,49 @@ object FlirManager {
47
44
  fun onTextureUpdate(bitmap: Bitmap, textureUnit: Int)
48
45
  }
49
46
 
50
- interface TemperatureCallback {
51
- fun onTemperatureData(temperature: Double, x: Int, y: Int)
52
- }
53
-
54
47
  private var textureCallback: TextureUpdateCallback? = null
55
- private var temperatureCallback: TemperatureCallback? = null
56
48
 
57
49
  fun setTextureCallback(callback: TextureUpdateCallback?) {
58
50
  textureCallback = callback
59
51
  }
60
52
 
61
- fun setTemperatureCallback(callback: TemperatureCallback?) {
62
- temperatureCallback = callback
63
- }
64
-
65
53
  fun getLatestBitmap(): Bitmap? = latestBitmap
66
54
 
67
- // Preference: ask SDK to deliver oriented/rotated frames (if SDK supports it)
68
- fun setPreferSdkRotation(prefer: Boolean) {
69
- sdkManager?.setPreferSdkRotation(prefer)
70
- }
71
-
72
- fun isPreferSdkRotation(): Boolean {
73
- return sdkManager?.isPreferSdkRotation() ?: false
74
- }
75
-
76
- fun getBatteryLevel(): Int {
77
- return sdkManager?.getBatteryLevel() ?: -1
78
- }
79
-
80
- fun isBatteryCharging(): Boolean {
81
- return sdkManager?.isBatteryCharging() ?: false
82
- }
55
+ // Stubs for removed features
56
+ fun setPreferSdkRotation(prefer: Boolean) { /* No-op */ }
57
+ fun isPreferSdkRotation(): Boolean = false
58
+ fun getBatteryLevel(): Int = -1
59
+ fun isBatteryCharging(): Boolean = false
60
+ fun setPalette(name: String) { /* No-op */ }
61
+ fun getAvailablePalettes(): List<String> = emptyList()
83
62
 
84
63
  /**
85
64
  * Initialize the FLIR SDK
86
65
  */
87
66
  fun init(context: Context) {
88
- // Store react context for event emission if it's a React context
89
- // Always update if we get a valid ReactContext (in case previous was stale)
90
67
  if (context is ReactContext) {
91
- Log.d(TAG, "[Flir-BRIDGE-LOAD] Storing ReactContext for event emission: ${context.javaClass.simpleName}")
92
68
  reactContext = context
93
- } else {
94
- Log.d(TAG, "[Flir-BRIDGE-LOAD] Context is not ReactContext: ${context.javaClass.simpleName}")
95
69
  }
96
70
 
97
- if (isInitialized) {
98
- Log.d(TAG, "[Flir-BRIDGE-LOAD] Already initialized")
99
- return
100
- }
101
-
102
- appContext = context.applicationContext
71
+ if (isInitialized) return
103
72
 
104
73
  sdkManager = FlirSdkManager.getInstance(context)
105
74
  sdkManager?.setListener(sdkListener)
106
75
  sdkManager?.initialize()
107
76
 
108
77
  isInitialized = true
109
- Log.i(TAG, "[Flir-BRIDGE-LOAD] FlirManager initialized")
78
+ Log.i(TAG, "FlirManager initialized")
110
79
  }
111
80
 
112
81
  /**
113
- * Start scanning for devices (USB, Network, Emulator - ALL types)
82
+ * Start scanning
114
83
  */
115
84
  fun startDiscovery(retry: Boolean = false) {
116
- Log.i(TAG, "[Flir-BRIDGE-DISCOVERY] startDiscovery(retry=$retry)")
117
-
118
- if (!isInitialized && appContext != null) {
119
- init(appContext!!)
85
+ if (!isInitialized && reactContext != null) {
86
+ init(reactContext!!)
120
87
  }
121
88
 
122
- if (isScanning && !retry) {
123
- Log.d(TAG, "Already scanning")
124
- return
125
- }
89
+ if (isScanning && !retry) return
126
90
 
127
91
  isScanning = true
128
92
  emitDeviceState("discovering")
@@ -141,13 +105,12 @@ object FlirManager {
141
105
  * Stop scanning
142
106
  */
143
107
  fun stopDiscovery() {
144
- Log.i(TAG, "[Flir-BRIDGE-DISCOVERY] stopDiscovery")
145
- sdkManager?.stop()
108
+ sdkManager?.stopScan()
146
109
  isScanning = false
147
110
  }
148
111
 
149
112
  /**
150
- * Connect to a device by ID
113
+ * Connect to a device
151
114
  */
152
115
  fun connectToDevice(deviceId: String) {
153
116
  Log.i(TAG, "connectToDevice: $deviceId")
@@ -156,52 +119,17 @@ object FlirManager {
156
119
  val identity = devices.find { it.deviceId == deviceId }
157
120
 
158
121
  if (identity != null) {
159
- Log.i(TAG, "[Flir-BRIDGE-CONNECTION] Connecting to found device: $deviceId")
160
122
  sdkManager?.connect(identity)
161
123
  } else {
162
- Log.e(TAG, "[Flir-BRIDGE-ERROR] Device not found: $deviceId")
124
+ Log.e(TAG, "Device not found: $deviceId")
163
125
  emitError("Device not found: $deviceId")
164
126
  }
165
127
  }
166
128
 
167
129
  /**
168
- * Switch to a different device
169
- */
170
- fun switchToDevice(deviceId: String) {
171
- if (deviceId == connectedDeviceId) {
172
- Log.d(TAG, "Already connected to: $deviceId")
173
- return
174
- }
175
-
176
- // Disconnect current and connect new
177
- if (isConnected) {
178
- sdkManager?.disconnect()
179
- }
180
- connectToDevice(deviceId)
181
- }
182
-
183
- /**
184
- * Start streaming from connected device
185
- */
186
- fun startStream() {
187
- Log.i(TAG, "startStream")
188
- sdkManager?.startStream()
189
- }
190
-
191
- /**
192
- * Stop streaming
193
- */
194
- fun stopStream() {
195
- Log.i(TAG, "[Flir-BRIDGE-STREAMING] stopStream")
196
- sdkManager?.stopStream()
197
- isStreaming = false
198
- }
199
-
200
- /**
201
- * Disconnect from current device
130
+ * Disconnect
202
131
  */
203
132
  fun disconnect() {
204
- Log.i(TAG, "[Flir-BRIDGE-DISCONNECT] disconnect")
205
133
  sdkManager?.disconnect()
206
134
  isConnected = false
207
135
  isStreaming = false
@@ -213,49 +141,32 @@ object FlirManager {
213
141
  * Stop everything
214
142
  */
215
143
  fun stop() {
216
- Log.i(TAG, "stop")
217
- stopStream()
218
144
  disconnect()
219
145
  stopDiscovery()
220
146
  latestBitmap = null
221
147
  }
222
148
 
149
+ // Stub legacy methods
150
+ fun startStream() { /* handled automatically by connect */ }
151
+ fun stopStream() { sdkManager?.stopStream() }
152
+
223
153
  /**
224
- * Get temperature at point in image coordinates
154
+ * Get temperature
225
155
  */
226
156
  fun getTemperatureAt(x: Int, y: Int): Double? {
227
- return sdkManager?.getTemperatureAt(x, y)?.takeIf { !it.isNaN() }
157
+ val temp = sdkManager?.getTemperatureAt(x, y)
158
+ return if (temp != null && !temp.isNaN()) temp else null
228
159
  }
229
160
 
230
- /**
231
- * Get temperature at normalized coordinates (0.0 to 1.0)
232
- */
233
- fun getTemperatureAtNormalized(normalizedX: Double, normalizedY: Double): Double? {
234
- return sdkManager?.getTemperatureAtNormalized(normalizedX, normalizedY)?.takeIf { !it.isNaN() }
161
+ fun getTemperatureAtNormalized(nx: Double, ny: Double): Double? {
162
+ // Not implemented in simplified version
163
+ return null
235
164
  }
236
165
 
237
- /**
238
- * Alias for getTemperatureAt
239
- */
240
166
  fun getTemperatureAtPoint(x: Int, y: Int): Double? = getTemperatureAt(x, y)
241
167
 
242
168
  /**
243
- * Set palette
244
- */
245
- fun setPalette(name: String) {
246
- Log.d(TAG, "setPalette: $name")
247
- sdkManager?.setPalette(name)
248
- }
249
-
250
- /**
251
- * Get available palettes
252
- */
253
- fun getAvailablePalettes(): List<String> {
254
- return sdkManager?.availablePalettes ?: emptyList()
255
- }
256
-
257
- /**
258
- * Get list of discovered devices
169
+ * Get discovered devices
259
170
  */
260
171
  fun getDiscoveredDevices(): List<Identity> {
261
172
  return sdkManager?.discoveredDevices ?: emptyList()
@@ -269,14 +180,11 @@ object FlirManager {
269
180
  fun isEmulator(): Boolean = connectedDeviceName?.contains("EMULAT", ignoreCase = true) == true
270
181
  fun isDeviceConnected(): Boolean = isConnected
271
182
 
272
- /**
273
- * Get connected device info
274
- */
275
183
  fun getConnectedDeviceInfo(): String {
276
184
  return connectedDeviceName ?: "Not connected"
277
185
  }
278
186
 
279
- /**
187
+ /**
280
188
  * Get latest frame as file path (for RN)
281
189
  */
282
190
  fun getLatestFramePath(): String? {
@@ -288,7 +196,6 @@ object FlirManager {
288
196
  }
289
197
  file.absolutePath
290
198
  } catch (t: Throwable) {
291
- Log.e(TAG, "Failed to save frame", t)
292
199
  null
293
200
  }
294
201
  }
@@ -296,30 +203,24 @@ object FlirManager {
296
203
  // SDK Listener
297
204
  private val sdkListener = object : FlirSdkManager.Listener {
298
205
  override fun onDeviceFound(identity: Identity) {
299
- Log.i(TAG, "Device found: ${identity.deviceId}")
206
+ // Devices updated event handles the list, but we can log unique finds
300
207
  }
301
208
 
302
209
  override fun onDeviceListUpdated(devices: List<Identity>) {
303
- Log.i(TAG, "Devices updated: ${devices.size} found")
304
- devices.forEach {
305
- Log.d(TAG, " - ${it.deviceId} (${it.communicationInterface})")
306
- }
210
+ Log.d(TAG, "Devices found: ${devices.size}")
307
211
  emitDevicesFound(devices)
308
212
  }
309
213
 
310
- override fun onConnected(identity: Identity?) {
311
- Log.i(TAG, "Connected to: ${identity?.deviceId}")
214
+ override fun onConnected(identity: Identity) {
215
+ Log.i(TAG, "Connected to: ${identity.deviceId}")
312
216
  isConnected = true
313
- connectedDeviceId = identity?.deviceId
314
- connectedDeviceName = identity?.deviceId
217
+ connectedDeviceId = identity.deviceId
218
+ connectedDeviceName = identity.deviceId
315
219
  emitDeviceState("connected")
316
-
317
- // Auto-start streaming when connected
318
- startStream()
319
220
  }
320
221
 
321
222
  override fun onDisconnected() {
322
- Log.i(TAG, "[Flir-BRIDGE-DISCONNECT] Disconnected callback")
223
+ Log.i(TAG, "Disconnected")
323
224
  isConnected = false
324
225
  isStreaming = false
325
226
  connectedDeviceId = null
@@ -328,52 +229,23 @@ object FlirManager {
328
229
  }
329
230
 
330
231
  override fun onFrame(bitmap: Bitmap) {
331
- if (bitmap.isRecycled || bitmap.width <= 0 || bitmap.height <= 0) {
332
- return
333
- }
334
-
335
232
  latestBitmap = bitmap
336
233
  isStreaming = true
337
234
 
338
- // Notify texture callback (for GL rendering)
339
- if (textureCallback != null) {
340
- textureCallback?.onTextureUpdate(bitmap, 0)
341
- } else {
342
- // Log only occasionally to avoid spam
343
- if (System.currentTimeMillis() % 5000 < 100) {
344
- Log.w(TAG, "⚠️ Frame received but textureCallback is null - texture won't update!")
345
- }
346
- }
235
+ // Notify GL callback
236
+ textureCallback?.onTextureUpdate(bitmap, 0)
347
237
 
348
- // Rate-limited RN event
238
+ // Notify RN
349
239
  emitFrameToReactNative(bitmap)
350
240
  }
351
241
 
352
242
  override fun onError(message: String) {
353
- Log.e(TAG, "Error: $message")
354
-
355
- // Parse error code if present (format: "CODE: message")
356
- val parts = message.split(": ", limit = 2)
357
- val errorCode = if (parts.size == 2) parts[0] else "FLIR_ERROR"
358
- val errorMessage = if (parts.size == 2) parts[1] else message
359
-
360
- // Auto-disable streaming on critical errors to allow retry
361
- if (errorCode.contains("NATIVE") || errorCode.contains("INIT")) {
362
- Log.w(TAG, "[Flir-BRIDGE-ERROR] Critical error detected, stopping stream")
363
- isStreaming = false
364
- stopStream()
365
- }
366
-
367
- emitError(errorCode, errorMessage)
368
- }
369
-
370
- override fun onBatteryUpdated(level: Int, isCharging: Boolean) {
371
- Log.d(TAG, "[Flir-BRIDGE-BATTERY] onBatteryUpdated: level=$level charging=$isCharging")
372
- emitBatteryState(level, isCharging)
243
+ emitError(message)
373
244
  }
374
245
  }
375
246
 
376
- // React Native event emitters
247
+ // React Native Emitters
248
+
377
249
  private fun emitFrameToReactNative(bitmap: Bitmap) {
378
250
  val now = System.currentTimeMillis()
379
251
  if (now - lastEmitMs.get() < minEmitIntervalMs) return
@@ -388,18 +260,11 @@ object FlirManager {
388
260
  }
389
261
  ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
390
262
  .emit("FlirFrameReceived", params)
391
- } catch (e: Exception) {
392
- // Ignore
393
- }
263
+ } catch (e: Exception) { }
394
264
  }
395
265
 
396
266
  private fun emitDeviceState(state: String) {
397
- val ctx = reactContext
398
- if (ctx == null) {
399
- Log.e(TAG, "[Flir-BRIDGE-ERROR] Cannot emit FlirDeviceConnected($state) - reactContext is null!")
400
- return
401
- }
402
- Log.d(TAG, "[Flir-BRIDGE-CONNECTION] Emitting FlirDeviceConnected: $state")
267
+ val ctx = reactContext ?: return
403
268
  try {
404
269
  val params = Arguments.createMap().apply {
405
270
  putString("state", state)
@@ -407,28 +272,20 @@ object FlirManager {
407
272
  putBoolean("isStreaming", isStreaming)
408
273
  putBoolean("isEmulator", isEmulator())
409
274
  connectedDeviceName?.let { putString("deviceName", it) }
410
- connectedDeviceId?.let { putString("deviceId", it) }
411
275
  }
412
276
  ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
413
277
  .emit("FlirDeviceConnected", params)
414
- } catch (e: Exception) {
415
- Log.e(TAG, "Failed to emit device state", e)
416
- }
278
+ } catch (e: Exception) { }
417
279
  }
418
280
 
419
281
  private fun emitDevicesFound(devices: List<Identity>) {
420
- val ctx = reactContext
421
- if (ctx == null) {
422
- Log.e(TAG, "Cannot emit FlirDevicesFound - reactContext is null!")
423
- return
424
- }
425
- Log.d(TAG, "Emitting FlirDevicesFound with ${devices.size} devices")
282
+ val ctx = reactContext ?: return
426
283
  try {
427
284
  val params = Arguments.createMap()
428
285
  val devicesArray: WritableArray = Arguments.createArray()
429
286
 
430
287
  devices.forEach { identity ->
431
- val deviceMap: WritableMap = Arguments.createMap().apply {
288
+ val deviceMap = Arguments.createMap().apply {
432
289
  putString("id", identity.deviceId)
433
290
  putString("name", identity.deviceId)
434
291
  putString("communicationType", identity.communicationInterface.name)
@@ -442,97 +299,34 @@ object FlirManager {
442
299
 
443
300
  ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
444
301
  .emit("FlirDevicesFound", params)
445
- Log.d(TAG, "[Flir-BRIDGE-DISCOVERY] Successfully emitted FlirDevicesFound (${devices.size} devices)")
446
- } catch (e: Exception) {
447
- Log.e(TAG, "[Flir-BRIDGE-ERROR] Failed to emit devices found", e)
448
- }
449
- }
450
-
451
- private fun emitBatteryState(level: Int, isCharging: Boolean) {
452
- val ctx = reactContext
453
- if (ctx == null) {
454
- Log.w(TAG, "Cannot emit FlirBatteryUpdated - reactContext is null!")
455
- return
456
- }
457
- try {
458
- val params = Arguments.createMap().apply {
459
- putInt("level", level)
460
- putBoolean("isCharging", isCharging)
461
- }
462
- ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
463
- .emit("FlirBatteryUpdated", params)
464
- } catch (e: Exception) {
465
- Log.e(TAG, "Failed to emit battery state", e)
466
- }
302
+ } catch (e: Exception) { }
467
303
  }
468
304
 
469
305
  private fun emitError(message: String) {
470
- emitError("FLIR_ERROR", message)
471
- }
472
-
473
- private fun emitError(errorCode: String, message: String) {
474
306
  val ctx = reactContext ?: return
475
307
  try {
476
308
  val params = Arguments.createMap().apply {
477
- putString("code", errorCode)
478
309
  putString("error", message)
479
- putString("message", message) // For backward compatibility
480
- putBoolean("canRetry", errorCode.contains("NATIVE") || errorCode.contains("INIT"))
310
+ putString("message", message)
481
311
  }
482
312
  ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
483
313
  .emit("FlirError", params)
484
- Log.d(TAG, "[Flir-BRIDGE-ERROR] Emitted FlirError: [$errorCode] $message")
485
- } catch (e: Exception) {
486
- Log.e(TAG, "Failed to emit error", e)
487
- }
314
+ } catch (e: Exception) { }
488
315
  }
489
316
 
490
- // Legacy compatibility
491
- @JvmStatic
492
- fun getInstance(): FlirManager = this
317
+ // Legacy methods placeholders
318
+ @JvmStatic fun getInstance(): FlirManager = this
493
319
 
494
320
  interface DiscoveryCallback {
495
321
  fun onDeviceFound(deviceName: String)
496
322
  fun onDiscoveryTimeout()
497
323
  fun onEmulatorEnabled()
498
324
  }
499
-
500
- private var discoveryCallback: DiscoveryCallback? = null
501
-
502
- fun setDiscoveryCallback(callback: DiscoveryCallback?) {
503
- discoveryCallback = callback
504
- }
505
-
506
- // Legacy methods - no-ops or simple forwards
507
- fun setEmulatorMode(enabled: Boolean) {
508
- Log.d(TAG, "setEmulatorMode($enabled) - legacy, use startDiscovery() instead")
509
- if (enabled) {
510
- startDiscovery(retry = true)
511
- }
512
- }
513
-
514
- fun enableEmulatorMode() = setEmulatorMode(true)
515
-
516
- fun forceEmulatorMode(type: String = "FLIR_ONE_EDGE") {
517
- Log.d(TAG, "forceEmulatorMode($type) - legacy, use startDiscovery() instead")
518
- startDiscovery(retry = true)
519
- }
520
-
521
- fun setPreferredEmulatorType(type: String) {
522
- Log.d(TAG, "setPreferredEmulatorType($type) - legacy, no longer used")
523
- }
524
-
525
- fun updateAcol(value: Float) {
526
- // No-op - not used in simplified version
527
- }
528
-
529
- /**
530
- * Cleanup
531
- */
532
- fun destroy() {
533
- stop()
534
- sdkManager?.destroy()
535
- sdkManager = null
536
- isInitialized = false
537
- }
325
+ fun setDiscoveryCallback(callback: DiscoveryCallback?) { /* No-op */ }
326
+ fun setEmulatorMode(enabled: Boolean) { startDiscovery() }
327
+ fun enableEmulatorMode() = startDiscovery()
328
+ fun forceEmulatorMode(type: String = "FLIR_ONE_EDGE") { startDiscovery() }
329
+ fun setPreferredEmulatorType(type: String) { }
330
+ fun updateAcol(value: Float) { }
331
+ fun destroy() { stop() }
538
332
  }