ilabs-flir 2.2.9 → 2.2.10
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/ios/Flir/src/FlirManager.swift +59 -53
- package/package.json +1 -1
|
@@ -481,16 +481,31 @@ import ThermalSDK
|
|
|
481
481
|
|
|
482
482
|
// MARK: - Connection
|
|
483
483
|
|
|
484
|
+
// Flag to prevent re-entrant connections
|
|
485
|
+
private var isConnecting = false
|
|
486
|
+
|
|
484
487
|
@objc public func connectToDevice(_ deviceId: String) {
|
|
485
488
|
FlirLogger.logConnectionAttempt(deviceId: deviceId)
|
|
486
489
|
|
|
487
490
|
#if FLIR_ENABLED
|
|
488
|
-
// Guard: if already
|
|
489
|
-
|
|
490
|
-
FlirLogger.log(.connection, "⚠️
|
|
491
|
+
// Guard: if already connecting, skip (like demo app's guard pattern)
|
|
492
|
+
guard !isConnecting else {
|
|
493
|
+
FlirLogger.log(.connection, "⚠️ Connection already in progress - skipping")
|
|
494
|
+
return
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Guard: if already connected to this device, skip (matches demo app)
|
|
498
|
+
if _isConnected && connectedDeviceId == deviceId {
|
|
499
|
+
FlirLogger.log(.connection, "⚠️ Already connected to this device - skipping")
|
|
500
|
+
return
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// If connected to a different device, disconnect first but DON'T block
|
|
504
|
+
if _isConnected && connectedDeviceId != deviceId {
|
|
505
|
+
FlirLogger.log(.connection, "⚠️ Connected to different device - disconnecting first...")
|
|
491
506
|
disconnect()
|
|
492
|
-
//
|
|
493
|
-
|
|
507
|
+
// Don't block! The new connection will proceed immediately
|
|
508
|
+
// The disconnect is async and will complete in the background
|
|
494
509
|
}
|
|
495
510
|
|
|
496
511
|
// Find the identity for this device
|
|
@@ -503,33 +518,14 @@ import ThermalSDK
|
|
|
503
518
|
return
|
|
504
519
|
}
|
|
505
520
|
|
|
506
|
-
|
|
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
|
|
513
|
-
self?.performConnection(identity: identity)
|
|
514
|
-
connectionCompleted = true
|
|
515
|
-
}
|
|
521
|
+
isConnecting = true
|
|
516
522
|
|
|
517
|
-
//
|
|
518
|
-
DispatchQueue.global(
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
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
|
-
}
|
|
523
|
+
// Run connection on background thread - simple pattern matching demo app
|
|
524
|
+
// Demo app uses: DispatchQueue.global().async { try pair(); try connect(); try stream.start() }
|
|
525
|
+
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
|
526
|
+
guard let self = self else { return }
|
|
527
|
+
self.performConnection(identity: identity)
|
|
528
|
+
self.isConnecting = false
|
|
533
529
|
}
|
|
534
530
|
#else
|
|
535
531
|
FlirLogger.logError(.connection, "FLIR SDK not available")
|
|
@@ -538,6 +534,7 @@ import ThermalSDK
|
|
|
538
534
|
}
|
|
539
535
|
#endif
|
|
540
536
|
}
|
|
537
|
+
|
|
541
538
|
|
|
542
539
|
#if FLIR_ENABLED
|
|
543
540
|
private func findIdentity(for deviceId: String) -> FLIRIdentity? {
|
|
@@ -566,34 +563,28 @@ import ThermalSDK
|
|
|
566
563
|
}
|
|
567
564
|
|
|
568
565
|
// Handle authentication for generic cameras (network cameras)
|
|
566
|
+
// Note: This uses a polling approach since the SDK doesn't provide async callback
|
|
567
|
+
// Reduced polling frequency to minimize blocking
|
|
569
568
|
if identity.cameraType() == .generic {
|
|
570
|
-
FlirLogger.log(.connection, "
|
|
569
|
+
FlirLogger.log(.connection, "Generic/network camera - attempting authentication...")
|
|
571
570
|
let certName = getCertificateName()
|
|
572
|
-
|
|
573
|
-
var attempts = 0
|
|
574
|
-
let maxAttempts = 10 // 10 seconds max
|
|
575
|
-
let authStartTime = Date()
|
|
576
|
-
|
|
577
|
-
while status == .pending && attempts < maxAttempts {
|
|
578
|
-
status = cam.authenticate(identity, trustedConnectionName: certName)
|
|
579
|
-
if status == .pending {
|
|
580
|
-
FlirLogger.log(.connection, "Waiting for camera authentication approval... (\(attempts + 1)/\(maxAttempts))")
|
|
581
|
-
Thread.sleep(forTimeInterval: 1.0)
|
|
582
|
-
attempts += 1
|
|
583
|
-
}
|
|
584
|
-
}
|
|
571
|
+
let status = cam.authenticate(identity, trustedConnectionName: certName)
|
|
585
572
|
|
|
586
573
|
if status == .pending {
|
|
587
|
-
|
|
588
|
-
FlirLogger.
|
|
574
|
+
// For pending auth, just log and continue - user needs to approve on camera
|
|
575
|
+
FlirLogger.log(.connection, "Authentication pending - camera may require approval")
|
|
576
|
+
// Don't block here - proceed with connection attempt
|
|
577
|
+
// If auth is required, the connect() call will fail appropriately
|
|
578
|
+
} else if status == .notUsed || status == .trusted {
|
|
579
|
+
FlirLogger.log(.connection, "✅ Authentication status: \(status.rawValue)")
|
|
580
|
+
} else {
|
|
581
|
+
FlirLogger.logError(.connection, "Authentication failed with status: \(status.rawValue)")
|
|
589
582
|
DispatchQueue.main.async { [weak self] in
|
|
590
|
-
self?.
|
|
583
|
+
self?.emitStateChange("connection_failed")
|
|
584
|
+
self?.delegate?.onError("Camera authentication failed")
|
|
591
585
|
}
|
|
592
586
|
return
|
|
593
587
|
}
|
|
594
|
-
|
|
595
|
-
let authDuration = Date().timeIntervalSince(authStartTime)
|
|
596
|
-
FlirLogger.log(.connection, "✅ Authentication completed in \(authDuration)s - status: \(status.rawValue)")
|
|
597
588
|
}
|
|
598
589
|
|
|
599
590
|
do {
|
|
@@ -708,9 +699,15 @@ import ThermalSDK
|
|
|
708
699
|
}
|
|
709
700
|
|
|
710
701
|
@objc public func stopStream() {
|
|
702
|
+
#if FLIR_ENABLED
|
|
703
|
+
// Guard: if not streaming, skip to avoid redundant operations
|
|
704
|
+
guard _isStreaming || stream != nil else {
|
|
705
|
+
FlirLogger.log(.streaming, "Not streaming - skipping stopStream")
|
|
706
|
+
return
|
|
707
|
+
}
|
|
708
|
+
|
|
711
709
|
FlirLogger.log(.streaming, "Stopping stream...")
|
|
712
710
|
|
|
713
|
-
#if FLIR_ENABLED
|
|
714
711
|
stream?.stop()
|
|
715
712
|
stream = nil
|
|
716
713
|
streamer = nil
|
|
@@ -743,6 +740,9 @@ import ThermalSDK
|
|
|
743
740
|
FlirLogger.logError(.streaming, "Stream start failed", error: error)
|
|
744
741
|
stream = nil
|
|
745
742
|
streamer = nil
|
|
743
|
+
_isStreaming = false
|
|
744
|
+
// Emit state change so RN knows streaming failed
|
|
745
|
+
emitStateChange("connected") // Fall back to connected (not streaming)
|
|
746
746
|
delegate?.onError("Stream start failed: \(error.localizedDescription)")
|
|
747
747
|
}
|
|
748
748
|
}
|
|
@@ -751,9 +751,15 @@ import ThermalSDK
|
|
|
751
751
|
// MARK: - Disconnect
|
|
752
752
|
|
|
753
753
|
@objc public func disconnect() {
|
|
754
|
+
#if FLIR_ENABLED
|
|
755
|
+
// Guard: if already disconnected, do nothing (prevents re-entrant issues)
|
|
756
|
+
guard _isConnected || stream != nil || camera != nil else {
|
|
757
|
+
FlirLogger.log(.disconnect, "Already disconnected - skipping")
|
|
758
|
+
return
|
|
759
|
+
}
|
|
760
|
+
|
|
754
761
|
FlirLogger.log(.disconnect, "Disconnecting...")
|
|
755
762
|
|
|
756
|
-
#if FLIR_ENABLED
|
|
757
763
|
// Stop battery polling
|
|
758
764
|
stopBatteryPolling()
|
|
759
765
|
|