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, "
|
|
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, "⏱
|
|
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
|
|
483
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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, "✅
|
|
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:
|
|
608
|
+
FlirLogger.log(.connection, "⏱ Step 2: CONNECTING starting... [time: \(Date().timeIntervalSince(startTime))s]")
|
|
564
609
|
try cam.connect()
|
|
565
|
-
FlirLogger.log(.connection, "✅
|
|
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
|
});
|