ilabs-flir 2.2.4 → 2.2.6
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.
|
@@ -74,9 +74,8 @@ import ThermalSDK
|
|
|
74
74
|
// Client lifecycle for discovery/connection ownership
|
|
75
75
|
private var activeClients: Set<String> = []
|
|
76
76
|
private var shutdownWorkItem: DispatchWorkItem? = nil
|
|
77
|
-
// Discovery
|
|
77
|
+
// Discovery timeout to prevent infinite scanning
|
|
78
78
|
private var discoveryTimeoutWorkItem: DispatchWorkItem? = nil
|
|
79
|
-
private var streamWatchdogWorkItem: DispatchWorkItem? = nil
|
|
80
79
|
|
|
81
80
|
// Battery polling timer (like Android)
|
|
82
81
|
private var batteryPollingTimer: Timer?
|
|
@@ -89,6 +88,7 @@ import ThermalSDK
|
|
|
89
88
|
private var stream: FLIRStream?
|
|
90
89
|
private var streamer: FLIRThermalStreamer?
|
|
91
90
|
private var connectedIdentity: FLIRIdentity?
|
|
91
|
+
private var identityMap: [String: FLIRIdentity] = [:]
|
|
92
92
|
#endif
|
|
93
93
|
|
|
94
94
|
private override init() {
|
|
@@ -402,27 +402,26 @@ import ThermalSDK
|
|
|
402
402
|
discovery?.start(interfaces)
|
|
403
403
|
|
|
404
404
|
emitStateChange("discovering")
|
|
405
|
-
|
|
406
|
-
//
|
|
407
|
-
// the UI doesn't remain stuck when discovery yields no devices.
|
|
405
|
+
|
|
406
|
+
// Set timeout to prevent infinite scanning (matches Android's 8-second timeout)
|
|
408
407
|
discoveryTimeoutWorkItem?.cancel()
|
|
409
|
-
let
|
|
410
|
-
guard let self = self else { return }
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
408
|
+
let timeoutWork = DispatchWorkItem { [weak self] in
|
|
409
|
+
guard let self = self, self.isScanning else { return }
|
|
410
|
+
FlirLogger.log(.discovery, "⏱ Discovery timeout reached - stopping scan")
|
|
411
|
+
self.discovery?.stop()
|
|
412
|
+
self.isScanning = false
|
|
413
|
+
|
|
414
|
+
// Emit final device list and state
|
|
415
|
+
DispatchQueue.main.async {
|
|
416
|
+
self.delegate?.onDevicesFound(self.discoveredDevices)
|
|
417
|
+
if self.discoveredDevices.isEmpty {
|
|
419
418
|
self.emitStateChange("no_device_found")
|
|
420
|
-
self.delegate?.onError("
|
|
419
|
+
self.delegate?.onError("No FLIR devices found")
|
|
421
420
|
}
|
|
422
421
|
}
|
|
423
422
|
}
|
|
424
|
-
discoveryTimeoutWorkItem =
|
|
425
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + 8.0, execute:
|
|
423
|
+
discoveryTimeoutWorkItem = timeoutWork
|
|
424
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 8.0, execute: timeoutWork)
|
|
426
425
|
#else
|
|
427
426
|
FlirLogger.logError(.discovery, "FLIR SDK not available - discovery disabled")
|
|
428
427
|
delegate?.onError("FLIR SDK not available")
|
|
@@ -458,6 +457,10 @@ import ThermalSDK
|
|
|
458
457
|
#if FLIR_ENABLED
|
|
459
458
|
discoveryTimeoutWorkItem?.cancel()
|
|
460
459
|
discoveryTimeoutWorkItem = nil
|
|
460
|
+
discovery?.stop()
|
|
461
|
+
isScanning = false
|
|
462
|
+
FlirLogger.log(.discovery, "Discovery stopped")
|
|
463
|
+
#endif
|
|
461
464
|
}
|
|
462
465
|
|
|
463
466
|
// MARK: - Connection
|
|
@@ -483,8 +486,6 @@ import ThermalSDK
|
|
|
483
486
|
}
|
|
484
487
|
|
|
485
488
|
#if FLIR_ENABLED
|
|
486
|
-
private var identityMap: [String: FLIRIdentity] = [:]
|
|
487
|
-
|
|
488
489
|
private func findIdentity(for deviceId: String) -> FLIRIdentity? {
|
|
489
490
|
return identityMap[deviceId]
|
|
490
491
|
}
|
|
@@ -508,29 +509,19 @@ import ThermalSDK
|
|
|
508
509
|
return
|
|
509
510
|
}
|
|
510
511
|
|
|
511
|
-
//
|
|
512
|
+
// Handle authentication for generic cameras (network cameras)
|
|
512
513
|
if identity.cameraType() == .generic {
|
|
513
514
|
FlirLogger.log(.connection, "Generic/network camera - starting authentication...")
|
|
514
515
|
let certName = getCertificateName()
|
|
515
|
-
var
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
if authStatus == .pending {
|
|
521
|
-
FlirLogger.log(.connection, "Authentication pending... attempt \(attempts + 1)")
|
|
516
|
+
var status = FLIRAuthenticationStatus.pending
|
|
517
|
+
while status == .pending {
|
|
518
|
+
status = cam.authenticate(identity, trustedConnectionName: certName)
|
|
519
|
+
if status == .pending {
|
|
520
|
+
FlirLogger.log(.connection, "Waiting for camera authentication approval...")
|
|
522
521
|
Thread.sleep(forTimeInterval: 1.0)
|
|
523
|
-
attempts += 1
|
|
524
522
|
}
|
|
525
523
|
}
|
|
526
|
-
FlirLogger.log(.connection, "Authentication status: \(
|
|
527
|
-
if authStatus == .pending {
|
|
528
|
-
FlirLogger.logError(.connection, "Authentication timed out for device: \(identity.deviceId())")
|
|
529
|
-
DispatchQueue.main.async { [weak self] in
|
|
530
|
-
self?.delegate?.onError("Authentication timed out")
|
|
531
|
-
}
|
|
532
|
-
return
|
|
533
|
-
}
|
|
524
|
+
FlirLogger.log(.connection, "Authentication status: \(status.rawValue)")
|
|
534
525
|
}
|
|
535
526
|
|
|
536
527
|
do {
|
|
@@ -544,7 +535,6 @@ import ThermalSDK
|
|
|
544
535
|
FlirLogger.log(.connection, "Step 2: Connecting to device...")
|
|
545
536
|
try cam.connect()
|
|
546
537
|
FlirLogger.log(.connection, "✅ Connected successfully to: \(identity.deviceId())")
|
|
547
|
-
|
|
548
538
|
|
|
549
539
|
// Update state
|
|
550
540
|
connectedIdentity = identity
|
|
@@ -642,9 +632,10 @@ import ThermalSDK
|
|
|
642
632
|
FlirLogger.log(.streaming, "Stopping stream...")
|
|
643
633
|
|
|
644
634
|
#if FLIR_ENABLED
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
635
|
+
stream?.stop()
|
|
636
|
+
stream = nil
|
|
637
|
+
streamer = nil
|
|
638
|
+
_isStreaming = false
|
|
648
639
|
emitStateChange("connected")
|
|
649
640
|
FlirLogger.log(.streaming, "Stream stopped")
|
|
650
641
|
#endif
|
|
@@ -669,28 +660,6 @@ import ThermalSDK
|
|
|
669
660
|
_isStreaming = true
|
|
670
661
|
emitStateChange("streaming")
|
|
671
662
|
FlirLogger.log(.streaming, "✅ Stream started successfully (thermal=\(newStream.isThermal))")
|
|
672
|
-
|
|
673
|
-
// Schedule a short watchdog to detect silent no-frame scenarios.
|
|
674
|
-
streamWatchdogWorkItem?.cancel()
|
|
675
|
-
let watch = DispatchWorkItem { [weak self] in
|
|
676
|
-
guard let self = self else { return }
|
|
677
|
-
if self._latestImage == nil {
|
|
678
|
-
FlirLogger.logError(.streaming, "No frames received within watchdog period after stream start")
|
|
679
|
-
// Attempt a soft restart
|
|
680
|
-
do {
|
|
681
|
-
self.stream?.stop()
|
|
682
|
-
try self.stream?.start()
|
|
683
|
-
FlirLogger.log(.streaming, "Attempted stream restart")
|
|
684
|
-
} catch {
|
|
685
|
-
FlirLogger.logError(.streaming, "Stream restart failed", error: error)
|
|
686
|
-
DispatchQueue.main.async {
|
|
687
|
-
self.delegate?.onError("No frames received after starting stream")
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
streamWatchdogWorkItem = watch
|
|
693
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0, execute: watch)
|
|
694
663
|
} catch {
|
|
695
664
|
FlirLogger.logError(.streaming, "Stream start failed", error: error)
|
|
696
665
|
stream = nil
|
|
@@ -970,35 +939,44 @@ extension FlirManager: FLIRDiscoveryEventDelegate {
|
|
|
970
939
|
public func discoveryError(_ error: String, netServiceError nsnetserviceserror: Int32, on iface: FLIRCommunicationInterface) {
|
|
971
940
|
FlirLogger.logError(.discovery, "Discovery error: \(error) (code=\(nsnetserviceserror)) on interface: \(iface)")
|
|
972
941
|
|
|
973
|
-
// Stop scanning and
|
|
942
|
+
// Stop scanning and cancel timeout on error
|
|
943
|
+
discoveryTimeoutWorkItem?.cancel()
|
|
944
|
+
discoveryTimeoutWorkItem = nil
|
|
974
945
|
discovery?.stop()
|
|
975
946
|
isScanning = false
|
|
947
|
+
|
|
948
|
+
// Emit current device list (could be empty) so RN/UI can recover
|
|
976
949
|
DispatchQueue.main.async { [weak self] in
|
|
977
|
-
self
|
|
978
|
-
self
|
|
950
|
+
guard let self = self else { return }
|
|
951
|
+
self.delegate?.onDevicesFound(self.discoveredDevices)
|
|
952
|
+
self.delegate?.onError("Discovery error: \(error)")
|
|
979
953
|
}
|
|
980
954
|
}
|
|
981
955
|
|
|
982
956
|
public func discoveryFinished(_ iface: FLIRCommunicationInterface) {
|
|
983
957
|
FlirLogger.log(.discovery, "Discovery finished on interface: \(iface)")
|
|
984
958
|
isScanning = false
|
|
985
|
-
|
|
959
|
+
|
|
960
|
+
// Cancel timeout since discovery finished normally
|
|
961
|
+
discoveryTimeoutWorkItem?.cancel()
|
|
962
|
+
discoveryTimeoutWorkItem = nil
|
|
963
|
+
|
|
964
|
+
// CRITICAL: Emit final device list so RN layer doesn't hang waiting for results
|
|
986
965
|
DispatchQueue.main.async { [weak self] in
|
|
987
966
|
guard let self = self else { return }
|
|
988
967
|
self.delegate?.onDevicesFound(self.discoveredDevices)
|
|
989
|
-
// If no devices were found, emit
|
|
968
|
+
// If no devices were found, emit explicit state so UI can show "no devices"
|
|
990
969
|
if self.discoveredDevices.isEmpty {
|
|
991
970
|
self.emitStateChange("no_device_found")
|
|
992
971
|
}
|
|
993
972
|
}
|
|
994
|
-
// Cancel the timeout if discovery finished normally
|
|
995
|
-
discoveryTimeoutWorkItem?.cancel()
|
|
996
|
-
discoveryTimeoutWorkItem = nil
|
|
997
973
|
}
|
|
998
974
|
}
|
|
975
|
+
#endif
|
|
999
976
|
|
|
1000
977
|
// MARK: - FLIRDataReceivedDelegate
|
|
1001
978
|
|
|
979
|
+
#if FLIR_ENABLED
|
|
1002
980
|
extension FlirManager: FLIRDataReceivedDelegate {
|
|
1003
981
|
public func onDisconnected(_ camera: FLIRCamera, withError error: Error?) {
|
|
1004
982
|
FlirLogger.logError(.disconnect, "Camera disconnected callback", error: error)
|
|
@@ -1020,9 +998,12 @@ extension FlirManager: FLIRDataReceivedDelegate {
|
|
|
1020
998
|
}
|
|
1021
999
|
}
|
|
1022
1000
|
}
|
|
1001
|
+
#endif
|
|
1023
1002
|
|
|
1024
1003
|
// MARK: - FLIRStreamDelegate
|
|
1025
1004
|
|
|
1005
|
+
#if FLIR_ENABLED
|
|
1006
|
+
|
|
1026
1007
|
extension FlirManager: FLIRStreamDelegate {
|
|
1027
1008
|
public func onError(_ error: Error) {
|
|
1028
1009
|
FlirLogger.logError(.streaming, "Stream error", error: error)
|
|
@@ -155,14 +155,9 @@ RCT_EXPORT_METHOD(addListener : (NSString *)eventName) {
|
|
|
155
155
|
if (manager) {
|
|
156
156
|
NSArray *devices = ((NSArray * (*)(id, SEL))
|
|
157
157
|
objc_msgSend)(manager, sel_registerName("getDiscoveredDevices"));
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (devices) {
|
|
161
|
-
NSLog(@"[FlirModule] addListener - re-emitting discovered devices (count=%lu)", (unsigned long)devices.count);
|
|
158
|
+
if (devices && devices.count > 0) {
|
|
159
|
+
NSLog(@"[FlirModule] addListener - re-emitting %lu discovered devices", (unsigned long)devices.count);
|
|
162
160
|
[self onDevicesFound:devices];
|
|
163
|
-
} else {
|
|
164
|
-
NSLog(@"[FlirModule] addListener - no discovered devices available to re-emit");
|
|
165
|
-
[self onDevicesFound:@[]];
|
|
166
161
|
}
|
|
167
162
|
}
|
|
168
163
|
});
|