ilabs-flir 2.2.7 → 2.2.9

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.
@@ -361,13 +361,19 @@ import ThermalSDK
361
361
  FlirLogger.log(.discovery, "Starting discovery...")
362
362
 
363
363
  #if FLIR_ENABLED
364
+ // Guard: prevent re-entry if already scanning
364
365
  if isScanning {
365
- FlirLogger.log(.discovery, "Already scanning - skipping")
366
+ FlirLogger.log(.discovery, "⚠️ Discovery already in progress - ignoring duplicate startDiscovery call")
366
367
  return
367
368
  }
368
369
 
370
+ // Cancel any previous timeout and reset state
371
+ discoveryTimeoutWorkItem?.cancel()
372
+ discoveryTimeoutWorkItem = nil
373
+
369
374
  isScanning = true
370
375
  discoveredDevices.removeAll()
376
+ identityMap.removeAll()
371
377
 
372
378
  if discovery == nil {
373
379
  discovery = FLIRDiscovery()
@@ -407,7 +413,7 @@ import ThermalSDK
407
413
  discoveryTimeoutWorkItem?.cancel()
408
414
  let timeoutWork = DispatchWorkItem { [weak self] in
409
415
  guard let self = self, self.isScanning else { return }
410
- FlirLogger.log(.discovery, "⏱ Discovery timeout reached - stopping scan")
416
+ FlirLogger.log(.discovery, "DISCOVERY TIMEOUT triggered (8s) - stopping scan")
411
417
  self.discovery?.stop()
412
418
  self.isScanning = false
413
419
 
@@ -459,6 +465,16 @@ import ThermalSDK
459
465
  discoveryTimeoutWorkItem = nil
460
466
  discovery?.stop()
461
467
  isScanning = false
468
+
469
+ // Emit final device list to RN so UI updates properly
470
+ DispatchQueue.main.async { [weak self] in
471
+ guard let self = self else { return }
472
+ self.delegate?.onDevicesFound(self.discoveredDevices)
473
+ if self.discoveredDevices.isEmpty {
474
+ self.emitStateChange("no_device_found")
475
+ }
476
+ }
477
+
462
478
  FlirLogger.log(.discovery, "Discovery stopped")
463
479
  #endif
464
480
  }
@@ -469,6 +485,14 @@ import ThermalSDK
469
485
  FlirLogger.logConnectionAttempt(deviceId: deviceId)
470
486
 
471
487
  #if FLIR_ENABLED
488
+ // Guard: if already connected, disconnect first
489
+ if _isConnected {
490
+ FlirLogger.log(.connection, "⚠️ Already connected - disconnecting first...")
491
+ disconnect()
492
+ // Give disconnect a moment to complete
493
+ Thread.sleep(forTimeInterval: 0.5)
494
+ }
495
+
472
496
  // Find the identity for this device
473
497
  guard let identity = findIdentity(for: deviceId) else {
474
498
  FlirLogger.logError(.connection, "Device not found in identity map: \(deviceId)")
@@ -479,9 +503,33 @@ import ThermalSDK
479
503
  return
480
504
  }
481
505
 
482
- // Run connection on background thread with timeout monitoring
483
- DispatchQueue.global(qos: .userInitiated).async { [weak self] in
506
+ // Run connection on background thread with overall timeout
507
+ let timeoutSeconds: Double = 15.0
508
+ var connectionCompleted = false
509
+ let connectionQueue = DispatchQueue.global(qos: .userInitiated)
510
+
511
+ // Start connection attempt
512
+ connectionQueue.async { [weak self] in
484
513
  self?.performConnection(identity: identity)
514
+ connectionCompleted = true
515
+ }
516
+
517
+ // Monitor for timeout
518
+ DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + timeoutSeconds) { [weak self] in
519
+ guard let self = self, !connectionCompleted else { return }
520
+
521
+ FlirLogger.logError(.connection, "❌ ⏱ CONNECTION TIMEOUT triggered after \(timeoutSeconds)s - aborting")
522
+
523
+ // Force cleanup
524
+ self.camera = nil
525
+ self._isConnected = false
526
+ self.connectedDeviceId = nil
527
+
528
+ DispatchQueue.main.async {
529
+ FlirLogger.log(.connection, "⏱ Emitting connection_failed to RN due to timeout")
530
+ self.emitStateChange("connection_failed")
531
+ self.delegate?.onError("Connection timeout - device not responding")
532
+ }
485
533
  }
486
534
  #else
487
535
  FlirLogger.logError(.connection, "FLIR SDK not available")
@@ -499,6 +547,8 @@ import ThermalSDK
499
547
  private func performConnection(identity: FLIRIdentity) {
500
548
  // Use the proven connection pattern from FLIR SDK samples:
501
549
  // FLIROneCameraSwift uses: pair(identity, code:) then connect()
550
+ let startTime = Date()
551
+ FlirLogger.log(.connection, "⏱ performConnection STARTED for: \(identity.deviceId())")
502
552
  FlirLogger.log(.connection, "performConnection starting for: \(identity.deviceId())")
503
553
 
504
554
  if camera == nil {
@@ -517,11 +567,12 @@ import ThermalSDK
517
567
 
518
568
  // Handle authentication for generic cameras (network cameras)
519
569
  if identity.cameraType() == .generic {
520
- FlirLogger.log(.connection, "Generic/network camera - starting authentication...")
570
+ FlirLogger.log(.connection, "Generic/network camera - AUTHENTICATION starting...")
521
571
  let certName = getCertificateName()
522
572
  var status = FLIRAuthenticationStatus.pending
523
573
  var attempts = 0
524
574
  let maxAttempts = 10 // 10 seconds max
575
+ let authStartTime = Date()
525
576
 
526
577
  while status == .pending && attempts < maxAttempts {
527
578
  status = cam.authenticate(identity, trustedConnectionName: certName)
@@ -533,36 +584,30 @@ import ThermalSDK
533
584
  }
534
585
 
535
586
  if status == .pending {
536
- FlirLogger.logError(.connection, "Authentication timeout after \(maxAttempts) seconds")
587
+ let authDuration = Date().timeIntervalSince(authStartTime)
588
+ FlirLogger.logError(.connection, "❌ Authentication TIMEOUT after \(authDuration)s (\(maxAttempts) attempts)")
537
589
  DispatchQueue.main.async { [weak self] in
538
590
  self?.delegate?.onError("Camera authentication timeout - device may require approval")
539
591
  }
540
592
  return
541
593
  }
542
594
 
543
- FlirLogger.log(.connection, "Authentication status: \(status.rawValue)")
544
-
545
- if status != .authenticated {
546
- FlirLogger.logError(.connection, "Authentication failed with status: \(status.rawValue)")
547
- DispatchQueue.main.async { [weak self] in
548
- self?.delegate?.onError("Camera authentication failed")
549
- }
550
- return
551
- }
595
+ let authDuration = Date().timeIntervalSince(authStartTime)
596
+ FlirLogger.log(.connection, "✅ Authentication completed in \(authDuration)s - status: \(status.rawValue)")
552
597
  }
553
598
 
554
599
  do {
555
600
  // Step 1: Pair with identity (required for FLIR One devices)
556
601
  // The code parameter is for BLE pairing, 0 for direct connection
557
- FlirLogger.log(.connection, "Step 1: Pairing with device...")
602
+ FlirLogger.log(.connection, "Step 1: PAIRING starting... [time since start: \(Date().timeIntervalSince(startTime))s]")
558
603
  try cam.pair(identity, code: 0)
559
- FlirLogger.log(.connection, "✅ Paired successfully with: \(identity.deviceId())")
604
+ FlirLogger.log(.connection, "✅ Step 1: PAIRED successfully [time: \(Date().timeIntervalSince(startTime))s]")
560
605
 
561
606
  // Step 2: Connect (no identity parameter - uses paired identity)
562
607
  // Note: This can hang on some devices - ensure we have timeout in place
563
- FlirLogger.log(.connection, "Step 2: Connecting to device...")
608
+ FlirLogger.log(.connection, "Step 2: CONNECTING starting... [time: \(Date().timeIntervalSince(startTime))s]")
564
609
  try cam.connect()
565
- FlirLogger.log(.connection, "✅ Connected successfully to: \(identity.deviceId())")
610
+ FlirLogger.log(.connection, "✅ Step 2: CONNECTED successfully [time: \(Date().timeIntervalSince(startTime))s]")
566
611
 
567
612
  // Update state
568
613
  connectedIdentity = identity
@@ -848,6 +893,12 @@ import ThermalSDK
848
893
  // MARK: - State Emission
849
894
 
850
895
  private func emitStateChange(_ state: String) {
896
+ let timestamp = Date()
897
+ let formatter = DateFormatter()
898
+ formatter.dateFormat = "HH:mm:ss.SSS"
899
+ let timeStr = formatter.string(from: timestamp)
900
+ FlirLogger.log(.connection, "⏱ [\(timeStr)] EMITTING STATE to RN: '\(state)'")
901
+
851
902
  DispatchQueue.main.async { [weak self] in
852
903
  guard let self = self else { return }
853
904
  self.delegate?.onStateChanged(
@@ -856,6 +907,7 @@ import ThermalSDK
856
907
  isStreaming: self._isStreaming,
857
908
  isEmulator: self.isEmulator
858
909
  )
910
+ FlirLogger.log(.connection, "✅ [\(timeStr)] State '\(state)' emitted to RN")
859
911
  }
860
912
  }
861
913
 
@@ -204,12 +204,15 @@ RCT_EXPORT_METHOD(setNetworkDiscoveryEnabled : (BOOL)enabled resolver : (
204
204
 
205
205
  RCT_EXPORT_METHOD(startDiscovery : (RCTPromiseResolveBlock)
206
206
  resolve rejecter : (RCTPromiseRejectBlock)reject) {
207
+ NSLog(@"[FlirModule] [%@] ⏱ RN->startDiscovery called", [NSDate date]);
207
208
  dispatch_async(dispatch_get_main_queue(), ^{
208
209
  id manager = flir_manager_shared();
209
210
  if (manager &&
210
211
  [manager respondsToSelector:sel_registerName("startDiscovery")]) {
212
+ NSLog(@"[FlirModule] [%@] ⏱ Calling FlirManager.startDiscovery", [NSDate date]);
211
213
  ((void (*)(id, SEL))objc_msgSend)(manager,
212
214
  sel_registerName("startDiscovery"));
215
+ NSLog(@"[FlirModule] [%@] ⏱ FlirManager.startDiscovery returned", [NSDate date]);
213
216
  }
214
217
  resolve(@(YES));
215
218
  });
@@ -250,13 +253,12 @@ RCT_EXPORT_METHOD(getDiscoveredDevices : (RCTPromiseResolveBlock)
250
253
 
251
254
  RCT_EXPORT_METHOD(connectToDevice : (NSString *)deviceId resolver : (
252
255
  RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject) {
256
+ NSLog(@"[FlirModule] [%@] ⏱ RN->connectToDevice called for: %@", [NSDate date], deviceId);
253
257
  dispatch_async(dispatch_get_main_queue(), ^{
254
- NSLog(@"[FlirModule] connectToDevice called for: %@", deviceId);
255
-
256
258
  id manager = flir_manager_shared();
257
259
  if (manager &&
258
260
  [manager respondsToSelector:sel_registerName("connectToDevice:")]) {
259
- NSLog(@"[FlirModule] Calling FlirManager.connectToDevice");
261
+ NSLog(@"[FlirModule] [%@] ⏱ Calling FlirManager.connectToDevice", [NSDate date]);
260
262
 
261
263
  // Store callbacks for event-driven updates (but don't block on them)
262
264
  self.connectResolve = nil; // Don't use promise for blocking
@@ -266,10 +268,12 @@ RCT_EXPORT_METHOD(connectToDevice : (NSString *)deviceId resolver : (
266
268
  ((void (*)(id, SEL, id))objc_msgSend)(
267
269
  manager, sel_registerName("connectToDevice:"), deviceId);
268
270
 
271
+ NSLog(@"[FlirModule] [%@] ⏱ FlirManager.connectToDevice returned (async started)", [NSDate date]);
272
+
269
273
  // Resolve immediately - connection status will come via events
270
274
  resolve(@(YES));
271
275
  } else {
272
- NSLog(@"[FlirModule] FlirManager not found");
276
+ NSLog(@"[FlirModule] [%@] ❌ FlirManager not found", [NSDate date]);
273
277
  reject(@"ERR_NO_MANAGER", @"FlirManager not found", nil);
274
278
  }
275
279
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilabs-flir",
3
- "version": "2.2.7",
3
+ "version": "2.2.9",
4
4
  "description": "FLIR Thermal SDK for React Native - iOS & Android (bundled at compile time via postinstall)",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",