ilabs-flir 2.1.38 → 2.1.401
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/android/Flir/src/main/java/flir/android/FlirManager.kt +16 -15
- package/android/Flir/src/main/java/flir/android/FlirSdkManager.java +19 -15
- package/ios/Flir/src/FlirLogger.swift +135 -0
- package/ios/Flir/src/FlirManager.swift +143 -41
- package/ios/Flir/src/FlirModule.m +27 -21
- package/package.json +1 -1
|
@@ -88,14 +88,14 @@ object FlirManager {
|
|
|
88
88
|
// Store react context for event emission if it's a React context
|
|
89
89
|
// Always update if we get a valid ReactContext (in case previous was stale)
|
|
90
90
|
if (context is ReactContext) {
|
|
91
|
-
Log.d(TAG, "Storing ReactContext for event emission: ${context.javaClass.simpleName}")
|
|
91
|
+
Log.d(TAG, "[Flir-BRIDGE-LOAD] Storing ReactContext for event emission: ${context.javaClass.simpleName}")
|
|
92
92
|
reactContext = context
|
|
93
93
|
} else {
|
|
94
|
-
Log.d(TAG, "Context is not ReactContext: ${context.javaClass.simpleName}")
|
|
94
|
+
Log.d(TAG, "[Flir-BRIDGE-LOAD] Context is not ReactContext: ${context.javaClass.simpleName}")
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
if (isInitialized) {
|
|
98
|
-
Log.d(TAG, "Already initialized")
|
|
98
|
+
Log.d(TAG, "[Flir-BRIDGE-LOAD] Already initialized")
|
|
99
99
|
return
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -106,14 +106,14 @@ object FlirManager {
|
|
|
106
106
|
sdkManager?.initialize()
|
|
107
107
|
|
|
108
108
|
isInitialized = true
|
|
109
|
-
Log.i(TAG, "FlirManager initialized")
|
|
109
|
+
Log.i(TAG, "[Flir-BRIDGE-LOAD] FlirManager initialized")
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
113
|
* Start scanning for devices (USB, Network, Emulator - ALL types)
|
|
114
114
|
*/
|
|
115
115
|
fun startDiscovery(retry: Boolean = false) {
|
|
116
|
-
Log.i(TAG, "startDiscovery(retry=$retry)")
|
|
116
|
+
Log.i(TAG, "[Flir-BRIDGE-DISCOVERY] startDiscovery(retry=$retry)")
|
|
117
117
|
|
|
118
118
|
if (!isInitialized && appContext != null) {
|
|
119
119
|
init(appContext!!)
|
|
@@ -141,7 +141,7 @@ object FlirManager {
|
|
|
141
141
|
* Stop scanning
|
|
142
142
|
*/
|
|
143
143
|
fun stopDiscovery() {
|
|
144
|
-
Log.i(TAG, "stopDiscovery")
|
|
144
|
+
Log.i(TAG, "[Flir-BRIDGE-DISCOVERY] stopDiscovery")
|
|
145
145
|
sdkManager?.stop()
|
|
146
146
|
isScanning = false
|
|
147
147
|
}
|
|
@@ -156,9 +156,10 @@ object FlirManager {
|
|
|
156
156
|
val identity = devices.find { it.deviceId == deviceId }
|
|
157
157
|
|
|
158
158
|
if (identity != null) {
|
|
159
|
+
Log.i(TAG, "[Flir-BRIDGE-CONNECTION] Connecting to found device: $deviceId")
|
|
159
160
|
sdkManager?.connect(identity)
|
|
160
161
|
} else {
|
|
161
|
-
Log.e(TAG, "Device not found: $deviceId")
|
|
162
|
+
Log.e(TAG, "[Flir-BRIDGE-ERROR] Device not found: $deviceId")
|
|
162
163
|
emitError("Device not found: $deviceId")
|
|
163
164
|
}
|
|
164
165
|
}
|
|
@@ -191,7 +192,7 @@ object FlirManager {
|
|
|
191
192
|
* Stop streaming
|
|
192
193
|
*/
|
|
193
194
|
fun stopStream() {
|
|
194
|
-
Log.i(TAG, "stopStream")
|
|
195
|
+
Log.i(TAG, "[Flir-BRIDGE-STREAMING] stopStream")
|
|
195
196
|
sdkManager?.stopStream()
|
|
196
197
|
isStreaming = false
|
|
197
198
|
}
|
|
@@ -200,7 +201,7 @@ object FlirManager {
|
|
|
200
201
|
* Disconnect from current device
|
|
201
202
|
*/
|
|
202
203
|
fun disconnect() {
|
|
203
|
-
Log.i(TAG, "disconnect")
|
|
204
|
+
Log.i(TAG, "[Flir-BRIDGE-DISCONNECT] disconnect")
|
|
204
205
|
sdkManager?.disconnect()
|
|
205
206
|
isConnected = false
|
|
206
207
|
isStreaming = false
|
|
@@ -318,7 +319,7 @@ object FlirManager {
|
|
|
318
319
|
}
|
|
319
320
|
|
|
320
321
|
override fun onDisconnected() {
|
|
321
|
-
Log.i(TAG, "Disconnected")
|
|
322
|
+
Log.i(TAG, "[Flir-BRIDGE-DISCONNECT] Disconnected callback")
|
|
322
323
|
isConnected = false
|
|
323
324
|
isStreaming = false
|
|
324
325
|
connectedDeviceId = null
|
|
@@ -354,7 +355,7 @@ object FlirManager {
|
|
|
354
355
|
}
|
|
355
356
|
|
|
356
357
|
override fun onBatteryUpdated(level: Int, isCharging: Boolean) {
|
|
357
|
-
Log.d(TAG, "onBatteryUpdated: level=$level charging=$isCharging")
|
|
358
|
+
Log.d(TAG, "[Flir-BRIDGE-BATTERY] onBatteryUpdated: level=$level charging=$isCharging")
|
|
358
359
|
emitBatteryState(level, isCharging)
|
|
359
360
|
}
|
|
360
361
|
}
|
|
@@ -382,10 +383,10 @@ object FlirManager {
|
|
|
382
383
|
private fun emitDeviceState(state: String) {
|
|
383
384
|
val ctx = reactContext
|
|
384
385
|
if (ctx == null) {
|
|
385
|
-
Log.e(TAG, "Cannot emit FlirDeviceConnected($state) - reactContext is null!")
|
|
386
|
+
Log.e(TAG, "[Flir-BRIDGE-ERROR] Cannot emit FlirDeviceConnected($state) - reactContext is null!")
|
|
386
387
|
return
|
|
387
388
|
}
|
|
388
|
-
Log.d(TAG, "Emitting FlirDeviceConnected: $state")
|
|
389
|
+
Log.d(TAG, "[Flir-BRIDGE-CONNECTION] Emitting FlirDeviceConnected: $state")
|
|
389
390
|
try {
|
|
390
391
|
val params = Arguments.createMap().apply {
|
|
391
392
|
putString("state", state)
|
|
@@ -428,9 +429,9 @@ object FlirManager {
|
|
|
428
429
|
|
|
429
430
|
ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
430
431
|
.emit("FlirDevicesFound", params)
|
|
431
|
-
Log.d(TAG, "Successfully emitted FlirDevicesFound")
|
|
432
|
+
Log.d(TAG, "[Flir-BRIDGE-DISCOVERY] Successfully emitted FlirDevicesFound (${devices.size} devices)")
|
|
432
433
|
} catch (e: Exception) {
|
|
433
|
-
Log.e(TAG, "Failed to emit devices found", e)
|
|
434
|
+
Log.e(TAG, "[Flir-BRIDGE-ERROR] Failed to emit devices found", e)
|
|
434
435
|
}
|
|
435
436
|
}
|
|
436
437
|
|
|
@@ -175,9 +175,9 @@ public class FlirSdkManager {
|
|
|
175
175
|
|
|
176
176
|
ThermalSdkAndroid.init(context);
|
|
177
177
|
isInitialized = true;
|
|
178
|
-
Log.d(TAG, "SDK initialized successfully");
|
|
178
|
+
Log.d(TAG, "[Flir-LOAD] SDK initialized successfully");
|
|
179
179
|
} catch (Exception e) {
|
|
180
|
-
Log.e(TAG, "Failed to initialize SDK", e);
|
|
180
|
+
Log.e(TAG, "[Flir-ERROR] Failed to initialize SDK", e);
|
|
181
181
|
notifyError("SDK initialization failed: " + e.getMessage());
|
|
182
182
|
}
|
|
183
183
|
}
|
|
@@ -208,7 +208,7 @@ public class FlirSdkManager {
|
|
|
208
208
|
isScanning = true;
|
|
209
209
|
discoveredDevices.clear();
|
|
210
210
|
|
|
211
|
-
Log.d(TAG, "Starting discovery for EMULATOR, NETWORK, USB...");
|
|
211
|
+
Log.d(TAG, "[Flir-DISCOVERY] Starting discovery for EMULATOR, NETWORK, USB...");
|
|
212
212
|
|
|
213
213
|
try {
|
|
214
214
|
DiscoveryFactory.getInstance().scan(
|
|
@@ -241,7 +241,7 @@ public class FlirSdkManager {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
isScanning = false;
|
|
244
|
-
Log.d(TAG, "Discovery stopped");
|
|
244
|
+
Log.d(TAG, "[Flir-DISCOVERY] Discovery stopped");
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
/**
|
|
@@ -273,7 +273,7 @@ public class FlirSdkManager {
|
|
|
273
273
|
camera = new Camera();
|
|
274
274
|
camera.connect(identity, connectionStatusListener, new ConnectParameters());
|
|
275
275
|
|
|
276
|
-
Log.d(TAG, "Connected to camera");
|
|
276
|
+
Log.d(TAG, "[Flir-CONNECTION] Connected to camera: " + identity.deviceId);
|
|
277
277
|
|
|
278
278
|
if (listener != null) {
|
|
279
279
|
listener.onConnected(identity);
|
|
@@ -309,7 +309,7 @@ public class FlirSdkManager {
|
|
|
309
309
|
listener.onDisconnected();
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
Log.d(TAG, "Disconnected");
|
|
312
|
+
Log.d(TAG, "[Flir-DISCONNECT] Disconnected");
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
/**
|
|
@@ -397,10 +397,10 @@ public class FlirSdkManager {
|
|
|
397
397
|
notifyError("Stream error: " + error);
|
|
398
398
|
});
|
|
399
399
|
|
|
400
|
-
Log.d(TAG, "Streaming started");
|
|
400
|
+
Log.d(TAG, "[Flir-STREAMING] Streaming started");
|
|
401
401
|
|
|
402
402
|
} catch (Exception e) {
|
|
403
|
-
Log.e(TAG, "Failed to start stream", e);
|
|
403
|
+
Log.e(TAG, "[Flir-ERROR] Failed to start stream", e);
|
|
404
404
|
notifyError("Stream failed: " + e.getMessage());
|
|
405
405
|
}
|
|
406
406
|
});
|
|
@@ -425,7 +425,7 @@ public class FlirSdkManager {
|
|
|
425
425
|
isProcessingFrame = false;
|
|
426
426
|
lastFrameProcessedMs = 0;
|
|
427
427
|
|
|
428
|
-
Log.d(TAG, "Streaming stopped");
|
|
428
|
+
Log.d(TAG, "[Flir-STREAMING] Streaming stopped");
|
|
429
429
|
}
|
|
430
430
|
|
|
431
431
|
/**
|
|
@@ -522,12 +522,13 @@ public class FlirSdkManager {
|
|
|
522
522
|
streamer.withThermalImage(thermalImage -> {
|
|
523
523
|
thermalImage.setPalette(palette);
|
|
524
524
|
});
|
|
525
|
-
Log.d(TAG, "Palette set to: " + paletteName);
|
|
525
|
+
Log.d(TAG, "[Flir-STREAMING] Palette set to: " + paletteName);
|
|
526
526
|
}
|
|
527
527
|
} catch (Exception e) {
|
|
528
528
|
Log.e(TAG, "Error setting palette", e);
|
|
529
529
|
}
|
|
530
530
|
});
|
|
531
|
+
|
|
531
532
|
}
|
|
532
533
|
|
|
533
534
|
/**
|
|
@@ -644,8 +645,8 @@ public class FlirSdkManager {
|
|
|
644
645
|
@Override
|
|
645
646
|
public void onCameraFound(DiscoveredCamera discoveredCamera) {
|
|
646
647
|
Identity identity = discoveredCamera.getIdentity();
|
|
647
|
-
Log.d(TAG,
|
|
648
|
-
" type=" + identity.communicationInterface);
|
|
648
|
+
Log.d(TAG,
|
|
649
|
+
"[Flir-DISCOVERY] Device found: " + identity.deviceId + " type=" + identity.communicationInterface);
|
|
649
650
|
|
|
650
651
|
// Add to list if not already present
|
|
651
652
|
synchronized (discoveredDevices) {
|
|
@@ -669,7 +670,7 @@ public class FlirSdkManager {
|
|
|
669
670
|
|
|
670
671
|
@Override
|
|
671
672
|
public void onCameraLost(Identity identity) {
|
|
672
|
-
Log.d(TAG, "Device lost: " + identity.deviceId);
|
|
673
|
+
Log.d(TAG, "[Flir-DISCOVERY] Device lost: " + identity.deviceId);
|
|
673
674
|
|
|
674
675
|
synchronized (discoveredDevices) {
|
|
675
676
|
discoveredDevices.removeIf(d -> d.deviceId.equals(identity.deviceId));
|
|
@@ -682,13 +683,13 @@ public class FlirSdkManager {
|
|
|
682
683
|
|
|
683
684
|
@Override
|
|
684
685
|
public void onDiscoveryError(CommunicationInterface iface, ErrorCode error) {
|
|
685
|
-
Log.e(TAG, "Discovery error: " + iface + " - " + error);
|
|
686
|
+
Log.e(TAG, "[Flir-ERROR] Discovery error: " + iface + " - " + error);
|
|
686
687
|
notifyError("Discovery error: " + error);
|
|
687
688
|
}
|
|
688
689
|
|
|
689
690
|
@Override
|
|
690
691
|
public void onDiscoveryFinished(CommunicationInterface iface) {
|
|
691
|
-
Log.d(TAG, "Discovery finished for: " + iface);
|
|
692
|
+
Log.d(TAG, "[Flir-DISCOVERY] Discovery finished for: " + iface);
|
|
692
693
|
}
|
|
693
694
|
};
|
|
694
695
|
|
|
@@ -739,6 +740,9 @@ public class FlirSdkManager {
|
|
|
739
740
|
if (level != lastPolledBatteryLevel || charging != lastPolledCharging) {
|
|
740
741
|
lastPolledBatteryLevel = level;
|
|
741
742
|
lastPolledCharging = charging;
|
|
743
|
+
|
|
744
|
+
Log.d(TAG, String.format("[Flir-BATTERY] Level: %d%%, Charging: %b", level, charging));
|
|
745
|
+
|
|
742
746
|
if (listener != null) {
|
|
743
747
|
try {
|
|
744
748
|
listener.onBatteryUpdated(level, charging);
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
//
|
|
2
|
+
// FlirLogger.swift
|
|
3
|
+
// Flir
|
|
4
|
+
//
|
|
5
|
+
// Comprehensive lifecycle logging for FLIR camera operations
|
|
6
|
+
// Helps debug: load → discovery → connection → streaming → frame → battery
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
/// Lifecycle stages for FLIR operations
|
|
12
|
+
@objc public enum FlirLifecycleStage: Int {
|
|
13
|
+
case load // SDK initialization
|
|
14
|
+
case discovery // Device scanning
|
|
15
|
+
case connection // Device pairing/connecting
|
|
16
|
+
case streaming // Stream start/stop
|
|
17
|
+
case frame // Frame receiving
|
|
18
|
+
case battery // Battery polling
|
|
19
|
+
case error // Error states
|
|
20
|
+
case disconnect // Disconnection events
|
|
21
|
+
|
|
22
|
+
var tag: String {
|
|
23
|
+
switch self {
|
|
24
|
+
case .load: return "LOAD"
|
|
25
|
+
case .discovery: return "DISCOVERY"
|
|
26
|
+
case .connection: return "CONNECTION"
|
|
27
|
+
case .streaming: return "STREAMING"
|
|
28
|
+
case .frame: return "FRAME"
|
|
29
|
+
case .battery: return "BATTERY"
|
|
30
|
+
case .error: return "ERROR"
|
|
31
|
+
case .disconnect: return "DISCONNECT"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// Centralized logger for FLIR operations with consistent formatting
|
|
37
|
+
@objc public class FlirLogger: NSObject {
|
|
38
|
+
|
|
39
|
+
/// Frame counter for periodic frame logging
|
|
40
|
+
private static var frameCount: Int = 0
|
|
41
|
+
private static let frameLogInterval: Int = 100 // Log every 100 frames
|
|
42
|
+
|
|
43
|
+
/// Log a message at a specific lifecycle stage
|
|
44
|
+
@objc public static func log(_ stage: FlirLifecycleStage, _ message: String) {
|
|
45
|
+
let timestamp = Date()
|
|
46
|
+
let formatter = DateFormatter()
|
|
47
|
+
formatter.dateFormat = "HH:mm:ss.SSS"
|
|
48
|
+
let timeStr = formatter.string(from: timestamp)
|
|
49
|
+
NSLog("[Flir-\(stage.tag)] [\(timeStr)] \(message)")
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// Log an error with optional Error object
|
|
53
|
+
@objc public static func logError(_ stage: FlirLifecycleStage, _ message: String, error: Error? = nil) {
|
|
54
|
+
let errorDesc = error?.localizedDescription ?? "no error details"
|
|
55
|
+
log(stage, "❌ \(message) - \(errorDesc)")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// Log frame received (rate-limited to avoid log spam)
|
|
59
|
+
@objc public static func logFrame(width: Int, height: Int) {
|
|
60
|
+
logFrame(width: width, height: height, temperature: 0)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Log frame received with temperature (rate-limited to avoid log spam)
|
|
64
|
+
@objc public static func logFrame(width: Int, height: Int, temperature: Double) {
|
|
65
|
+
frameCount += 1
|
|
66
|
+
if frameCount % frameLogInterval == 0 {
|
|
67
|
+
var msg = "Frame #\(frameCount) received (\(width)x\(height))"
|
|
68
|
+
if !temperature.isNaN {
|
|
69
|
+
msg += " temp=\(String(format: "%.1f", temperature))°C"
|
|
70
|
+
}
|
|
71
|
+
log(.frame, msg)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Internal implementation for logFrame with optional temperature
|
|
76
|
+
private static func logFrame(width: Int, height: Int, temperature: Double?) {
|
|
77
|
+
frameCount += 1
|
|
78
|
+
if frameCount % frameLogInterval == 0 {
|
|
79
|
+
var msg = "Frame #\(frameCount) received (\(width)x\(height))"
|
|
80
|
+
if let temp = temperature, !temp.isNaN {
|
|
81
|
+
msg += " temp=\(String(format: "%.1f", temp))°C"
|
|
82
|
+
}
|
|
83
|
+
log(.frame, msg)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Reset frame counter (call on disconnect)
|
|
88
|
+
@objc public static func resetFrameCounter() {
|
|
89
|
+
frameCount = 0
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// Log discovery interface status (important for debugging network vs lightning)
|
|
93
|
+
@objc public static func logDiscoveryInterfaces(lightning: Bool, network: Bool, wireless: Bool, emulator: Bool) {
|
|
94
|
+
var interfaces: [String] = []
|
|
95
|
+
if lightning { interfaces.append("Lightning") }
|
|
96
|
+
if network { interfaces.append("Network") }
|
|
97
|
+
if wireless { interfaces.append("FlirOneWireless") }
|
|
98
|
+
if emulator { interfaces.append("Emulator") }
|
|
99
|
+
|
|
100
|
+
log(.discovery, "Starting discovery on interfaces: \(interfaces.joined(separator: ", "))")
|
|
101
|
+
|
|
102
|
+
if !network {
|
|
103
|
+
log(.discovery, "⚠️ Network discovery DISABLED - requires paid iOS Developer License with NSLocalNetworkUsageDescription")
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/// Log device found with details
|
|
108
|
+
@objc public static func logDeviceFound(deviceId: String, name: String, type: String, isEmulator: Bool) {
|
|
109
|
+
var msg = "Device found: '\(name)' (id=\(deviceId), type=\(type))"
|
|
110
|
+
if isEmulator {
|
|
111
|
+
msg += " [EMULATOR]"
|
|
112
|
+
}
|
|
113
|
+
log(.discovery, msg)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// Log connection attempt
|
|
117
|
+
@objc public static func logConnectionAttempt(deviceId: String) {
|
|
118
|
+
log(.connection, "Attempting connection to: \(deviceId)")
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/// Log connection success with stream info
|
|
122
|
+
@objc public static func logConnectionSuccess(deviceId: String, streamCount: Int, hasThermal: Bool) {
|
|
123
|
+
log(.connection, "✅ Connected to: \(deviceId) - \(streamCount) stream(s), thermal=\(hasThermal)")
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// Log battery state
|
|
127
|
+
@objc public static func logBattery(level: Int, isCharging: Bool) {
|
|
128
|
+
if level >= 0 {
|
|
129
|
+
let chargingStr = isCharging ? "charging" : "not charging"
|
|
130
|
+
log(.battery, "Level: \(level)%, \(chargingStr)")
|
|
131
|
+
} else {
|
|
132
|
+
log(.battery, "Battery info unavailable")
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -75,6 +75,11 @@ import ThermalSDK
|
|
|
75
75
|
private var activeClients: Set<String> = []
|
|
76
76
|
private var shutdownWorkItem: DispatchWorkItem? = nil
|
|
77
77
|
|
|
78
|
+
// Battery polling timer (like Android)
|
|
79
|
+
private var batteryPollingTimer: Timer?
|
|
80
|
+
private var lastPolledBatteryLevel: Int = -1
|
|
81
|
+
private var lastPolledCharging: Bool = false
|
|
82
|
+
|
|
78
83
|
#if FLIR_ENABLED
|
|
79
84
|
private var discovery: FLIRDiscovery?
|
|
80
85
|
private var camera: FLIRCamera?
|
|
@@ -85,7 +90,12 @@ import ThermalSDK
|
|
|
85
90
|
|
|
86
91
|
private override init() {
|
|
87
92
|
super.init()
|
|
88
|
-
|
|
93
|
+
FlirLogger.log(.load, "FlirManager singleton initialized")
|
|
94
|
+
#if FLIR_ENABLED
|
|
95
|
+
FlirLogger.log(.load, "✅ FLIR SDK is ENABLED (ThermalSDK available)")
|
|
96
|
+
#else
|
|
97
|
+
FlirLogger.log(.load, "⚠️ FLIR SDK is DISABLED (FLIR_ENABLED not defined)")
|
|
98
|
+
#endif
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
// MARK: - Public State Accessors
|
|
@@ -335,11 +345,11 @@ import ThermalSDK
|
|
|
335
345
|
// MARK: - Discovery
|
|
336
346
|
|
|
337
347
|
@objc public func startDiscovery() {
|
|
338
|
-
|
|
348
|
+
FlirLogger.log(.discovery, "Starting discovery...")
|
|
339
349
|
|
|
340
350
|
#if FLIR_ENABLED
|
|
341
351
|
if isScanning {
|
|
342
|
-
|
|
352
|
+
FlirLogger.log(.discovery, "Already scanning - skipping")
|
|
343
353
|
return
|
|
344
354
|
}
|
|
345
355
|
|
|
@@ -349,6 +359,7 @@ import ThermalSDK
|
|
|
349
359
|
if discovery == nil {
|
|
350
360
|
discovery = FLIRDiscovery()
|
|
351
361
|
discovery?.delegate = self
|
|
362
|
+
FlirLogger.log(.discovery, "Created FLIRDiscovery instance")
|
|
352
363
|
}
|
|
353
364
|
|
|
354
365
|
// Build interfaces based on available permissions
|
|
@@ -362,19 +373,24 @@ import ThermalSDK
|
|
|
362
373
|
// Only add network discovery if NSLocalNetworkUsageDescription is present
|
|
363
374
|
// This prevents crashes/errors when user doesn't have iOS developer registration
|
|
364
375
|
// or hasn't declared network permission
|
|
365
|
-
|
|
376
|
+
let networkEnabled = shouldEnableNetworkDiscovery()
|
|
377
|
+
if networkEnabled {
|
|
366
378
|
interfaces.insert(.network)
|
|
367
|
-
NSLog("[FlirManager] Network discovery enabled (NSLocalNetworkUsageDescription present)")
|
|
368
|
-
} else {
|
|
369
|
-
NSLog("[FlirManager] Network discovery disabled (no NSLocalNetworkUsageDescription)")
|
|
370
379
|
}
|
|
371
380
|
|
|
381
|
+
// Log which interfaces are enabled (important for debugging)
|
|
382
|
+
FlirLogger.logDiscoveryInterfaces(
|
|
383
|
+
lightning: true,
|
|
384
|
+
network: networkEnabled,
|
|
385
|
+
wireless: true,
|
|
386
|
+
emulator: true
|
|
387
|
+
)
|
|
388
|
+
|
|
372
389
|
discovery?.start(interfaces)
|
|
373
390
|
|
|
374
391
|
emitStateChange("discovering")
|
|
375
|
-
NSLog("[FlirManager] Discovery started on interfaces: Lightning, \(interfaces.contains(.network) ? "Network, " : "")FlirOneWireless, Emulator")
|
|
376
392
|
#else
|
|
377
|
-
|
|
393
|
+
FlirLogger.logError(.discovery, "FLIR SDK not available - discovery disabled")
|
|
378
394
|
delegate?.onError("FLIR SDK not available")
|
|
379
395
|
#endif
|
|
380
396
|
}
|
|
@@ -399,28 +415,28 @@ import ThermalSDK
|
|
|
399
415
|
/// Allow explicit override of network discovery (called from React Native)
|
|
400
416
|
@objc public func setNetworkDiscoveryEnabled(_ enabled: Bool) {
|
|
401
417
|
UserDefaults.standard.set(enabled, forKey: "ilabsFlir.networkDiscoveryEnabled")
|
|
402
|
-
|
|
418
|
+
FlirLogger.log(.discovery, "Network discovery override set to: \(enabled)")
|
|
403
419
|
}
|
|
404
420
|
|
|
405
421
|
@objc public func stopDiscovery() {
|
|
406
|
-
|
|
422
|
+
FlirLogger.log(.discovery, "Stopping discovery...")
|
|
407
423
|
|
|
408
424
|
#if FLIR_ENABLED
|
|
409
425
|
discovery?.stop()
|
|
410
426
|
isScanning = false
|
|
411
|
-
|
|
427
|
+
FlirLogger.log(.discovery, "Discovery stopped")
|
|
412
428
|
#endif
|
|
413
429
|
}
|
|
414
430
|
|
|
415
431
|
// MARK: - Connection
|
|
416
432
|
|
|
417
433
|
@objc public func connectToDevice(_ deviceId: String) {
|
|
418
|
-
|
|
434
|
+
FlirLogger.logConnectionAttempt(deviceId: deviceId)
|
|
419
435
|
|
|
420
436
|
#if FLIR_ENABLED
|
|
421
437
|
// Find the identity for this device
|
|
422
438
|
guard let identity = findIdentity(for: deviceId) else {
|
|
423
|
-
|
|
439
|
+
FlirLogger.logError(.connection, "Device not found in identity map: \(deviceId)")
|
|
424
440
|
delegate?.onError("Device not found: \(deviceId)")
|
|
425
441
|
return
|
|
426
442
|
}
|
|
@@ -429,6 +445,7 @@ import ThermalSDK
|
|
|
429
445
|
self?.performConnection(identity: identity)
|
|
430
446
|
}
|
|
431
447
|
#else
|
|
448
|
+
FlirLogger.logError(.connection, "FLIR SDK not available")
|
|
432
449
|
delegate?.onError("FLIR SDK not available")
|
|
433
450
|
#endif
|
|
434
451
|
}
|
|
@@ -443,14 +460,16 @@ import ThermalSDK
|
|
|
443
460
|
private func performConnection(identity: FLIRIdentity) {
|
|
444
461
|
// Use the proven connection pattern from FLIR SDK samples:
|
|
445
462
|
// FLIROneCameraSwift uses: pair(identity, code:) then connect()
|
|
463
|
+
FlirLogger.log(.connection, "performConnection starting for: \(identity.deviceId())")
|
|
446
464
|
|
|
447
465
|
if camera == nil {
|
|
448
466
|
camera = FLIRCamera()
|
|
449
467
|
camera?.delegate = self
|
|
468
|
+
FlirLogger.log(.connection, "Created new FLIRCamera instance")
|
|
450
469
|
}
|
|
451
470
|
|
|
452
471
|
guard let cam = camera else {
|
|
453
|
-
|
|
472
|
+
FlirLogger.logError(.connection, "Failed to create FLIRCamera instance")
|
|
454
473
|
DispatchQueue.main.async { [weak self] in
|
|
455
474
|
self?.delegate?.onError("Failed to create camera instance")
|
|
456
475
|
}
|
|
@@ -459,27 +478,30 @@ import ThermalSDK
|
|
|
459
478
|
|
|
460
479
|
// Handle authentication for generic cameras (network cameras)
|
|
461
480
|
if identity.cameraType() == .generic {
|
|
481
|
+
FlirLogger.log(.connection, "Generic/network camera - starting authentication...")
|
|
462
482
|
let certName = getCertificateName()
|
|
463
483
|
var status = FLIRAuthenticationStatus.pending
|
|
464
484
|
while status == .pending {
|
|
465
485
|
status = cam.authenticate(identity, trustedConnectionName: certName)
|
|
466
486
|
if status == .pending {
|
|
467
|
-
|
|
487
|
+
FlirLogger.log(.connection, "Waiting for camera authentication approval...")
|
|
468
488
|
Thread.sleep(forTimeInterval: 1.0)
|
|
469
489
|
}
|
|
470
490
|
}
|
|
471
|
-
|
|
491
|
+
FlirLogger.log(.connection, "Authentication status: \(status.rawValue)")
|
|
472
492
|
}
|
|
473
493
|
|
|
474
494
|
do {
|
|
475
495
|
// Step 1: Pair with identity (required for FLIR One devices)
|
|
476
496
|
// The code parameter is for BLE pairing, 0 for direct connection
|
|
497
|
+
FlirLogger.log(.connection, "Step 1: Pairing with device...")
|
|
477
498
|
try cam.pair(identity, code: 0)
|
|
478
|
-
|
|
499
|
+
FlirLogger.log(.connection, "✅ Paired successfully with: \(identity.deviceId())")
|
|
479
500
|
|
|
480
501
|
// Step 2: Connect (no identity parameter - uses paired identity)
|
|
502
|
+
FlirLogger.log(.connection, "Step 2: Connecting to device...")
|
|
481
503
|
try cam.connect()
|
|
482
|
-
|
|
504
|
+
FlirLogger.log(.connection, "✅ Connected successfully to: \(identity.deviceId())")
|
|
483
505
|
|
|
484
506
|
// Update state
|
|
485
507
|
connectedIdentity = identity
|
|
@@ -490,23 +512,27 @@ import ThermalSDK
|
|
|
490
512
|
// Get camera info if available
|
|
491
513
|
if let remoteControl = cam.getRemoteControl(),
|
|
492
514
|
let cameraInfo = try? remoteControl.getCameraInformation() {
|
|
493
|
-
|
|
515
|
+
FlirLogger.log(.connection, "Camera info: \(cameraInfo)")
|
|
494
516
|
}
|
|
495
517
|
|
|
496
518
|
// Get streams
|
|
497
519
|
let streams = cam.getStreams()
|
|
520
|
+
let thermalCount = streams.filter { $0.isThermal }.count
|
|
521
|
+
FlirLogger.logConnectionSuccess(deviceId: identity.deviceId(), streamCount: streams.count, hasThermal: thermalCount > 0)
|
|
522
|
+
|
|
498
523
|
if !streams.isEmpty {
|
|
499
|
-
NSLog("[FlirManager] Found \(streams.count) streams")
|
|
500
|
-
|
|
501
524
|
// Find and start the first thermal stream (preferred) or any stream
|
|
502
525
|
let thermalStream = streams.first { $0.isThermal } ?? streams.first
|
|
503
526
|
if let streamToStart = thermalStream {
|
|
504
527
|
startStreamInternal(streamToStart)
|
|
505
528
|
}
|
|
506
529
|
} else {
|
|
507
|
-
|
|
530
|
+
FlirLogger.log(.streaming, "⚠️ No streams available on camera")
|
|
508
531
|
}
|
|
509
532
|
|
|
533
|
+
// Start battery polling (like Android does)
|
|
534
|
+
startBatteryPolling()
|
|
535
|
+
|
|
510
536
|
// Notify delegate on main thread
|
|
511
537
|
DispatchQueue.main.async { [weak self] in
|
|
512
538
|
guard let self = self else { return }
|
|
@@ -521,7 +547,7 @@ import ThermalSDK
|
|
|
521
547
|
}
|
|
522
548
|
|
|
523
549
|
} catch {
|
|
524
|
-
|
|
550
|
+
FlirLogger.logError(.connection, "Connection failed", error: error)
|
|
525
551
|
_isConnected = false
|
|
526
552
|
camera = nil
|
|
527
553
|
DispatchQueue.main.async { [weak self] in
|
|
@@ -558,7 +584,7 @@ import ThermalSDK
|
|
|
558
584
|
@objc public func startStream() {
|
|
559
585
|
#if FLIR_ENABLED
|
|
560
586
|
guard let streams = camera?.getStreams(), !streams.isEmpty else {
|
|
561
|
-
|
|
587
|
+
FlirLogger.log(.streaming, "⚠️ No streams available")
|
|
562
588
|
return
|
|
563
589
|
}
|
|
564
590
|
startStreamInternal(streams[0])
|
|
@@ -566,7 +592,7 @@ import ThermalSDK
|
|
|
566
592
|
}
|
|
567
593
|
|
|
568
594
|
@objc public func stopStream() {
|
|
569
|
-
|
|
595
|
+
FlirLogger.log(.streaming, "Stopping stream...")
|
|
570
596
|
|
|
571
597
|
#if FLIR_ENABLED
|
|
572
598
|
stream?.stop()
|
|
@@ -574,18 +600,20 @@ import ThermalSDK
|
|
|
574
600
|
streamer = nil
|
|
575
601
|
_isStreaming = false
|
|
576
602
|
emitStateChange("connected")
|
|
603
|
+
FlirLogger.log(.streaming, "Stream stopped")
|
|
577
604
|
#endif
|
|
578
605
|
}
|
|
579
606
|
|
|
580
607
|
#if FLIR_ENABLED
|
|
581
608
|
private func startStreamInternal(_ newStream: FLIRStream) {
|
|
582
|
-
|
|
609
|
+
FlirLogger.log(.streaming, "Starting stream (thermal=\(newStream.isThermal))...")
|
|
583
610
|
|
|
584
611
|
stream?.stop()
|
|
585
612
|
stream = newStream
|
|
586
613
|
|
|
587
614
|
if newStream.isThermal {
|
|
588
615
|
streamer = FLIRThermalStreamer(stream: newStream)
|
|
616
|
+
FlirLogger.log(.streaming, "Created FLIRThermalStreamer for thermal stream")
|
|
589
617
|
}
|
|
590
618
|
|
|
591
619
|
newStream.delegate = self
|
|
@@ -594,9 +622,9 @@ import ThermalSDK
|
|
|
594
622
|
try newStream.start()
|
|
595
623
|
_isStreaming = true
|
|
596
624
|
emitStateChange("streaming")
|
|
597
|
-
|
|
625
|
+
FlirLogger.log(.streaming, "✅ Stream started successfully (thermal=\(newStream.isThermal))")
|
|
598
626
|
} catch {
|
|
599
|
-
|
|
627
|
+
FlirLogger.logError(.streaming, "Stream start failed", error: error)
|
|
600
628
|
stream = nil
|
|
601
629
|
streamer = nil
|
|
602
630
|
delegate?.onError("Stream start failed: \(error.localizedDescription)")
|
|
@@ -607,9 +635,12 @@ import ThermalSDK
|
|
|
607
635
|
// MARK: - Disconnect
|
|
608
636
|
|
|
609
637
|
@objc public func disconnect() {
|
|
610
|
-
|
|
638
|
+
FlirLogger.log(.disconnect, "Disconnecting...")
|
|
611
639
|
|
|
612
640
|
#if FLIR_ENABLED
|
|
641
|
+
// Stop battery polling
|
|
642
|
+
stopBatteryPolling()
|
|
643
|
+
|
|
613
644
|
stopStream()
|
|
614
645
|
camera?.disconnect()
|
|
615
646
|
camera = nil
|
|
@@ -620,14 +651,19 @@ import ThermalSDK
|
|
|
620
651
|
_isStreaming = false
|
|
621
652
|
_latestImage = nil
|
|
622
653
|
|
|
654
|
+
// Reset frame counter for next connection
|
|
655
|
+
FlirLogger.resetFrameCounter()
|
|
656
|
+
|
|
623
657
|
DispatchQueue.main.async { [weak self] in
|
|
624
658
|
self?.delegate?.onDeviceDisconnected()
|
|
625
659
|
self?.emitStateChange("disconnected")
|
|
626
660
|
}
|
|
661
|
+
FlirLogger.log(.disconnect, "Disconnected successfully")
|
|
627
662
|
#endif
|
|
628
663
|
}
|
|
629
664
|
|
|
630
665
|
@objc public func stop() {
|
|
666
|
+
FlirLogger.log(.disconnect, "stop() called - full shutdown")
|
|
631
667
|
stopStream()
|
|
632
668
|
disconnect()
|
|
633
669
|
stopDiscovery()
|
|
@@ -658,10 +694,56 @@ import ThermalSDK
|
|
|
658
694
|
return lastTemperature
|
|
659
695
|
}
|
|
660
696
|
|
|
697
|
+
// MARK: - Battery Polling (like Android)
|
|
698
|
+
|
|
699
|
+
private func startBatteryPolling() {
|
|
700
|
+
FlirLogger.log(.battery, "Starting battery polling timer (5s interval)")
|
|
701
|
+
|
|
702
|
+
// Cancel any existing timer
|
|
703
|
+
stopBatteryPolling()
|
|
704
|
+
|
|
705
|
+
// Schedule timer on main run loop
|
|
706
|
+
DispatchQueue.main.async { [weak self] in
|
|
707
|
+
self?.batteryPollingTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { [weak self] _ in
|
|
708
|
+
self?.pollBatteryState()
|
|
709
|
+
}
|
|
710
|
+
// Run immediately once
|
|
711
|
+
self?.pollBatteryState()
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
private func stopBatteryPolling() {
|
|
716
|
+
if batteryPollingTimer != nil {
|
|
717
|
+
FlirLogger.log(.battery, "Stopping battery polling timer")
|
|
718
|
+
}
|
|
719
|
+
batteryPollingTimer?.invalidate()
|
|
720
|
+
batteryPollingTimer = nil
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
private func pollBatteryState() {
|
|
724
|
+
let level = getBatteryLevel()
|
|
725
|
+
let charging = isBatteryCharging()
|
|
726
|
+
|
|
727
|
+
// Only log and emit if values changed
|
|
728
|
+
if level != lastPolledBatteryLevel || charging != lastPolledCharging {
|
|
729
|
+
lastPolledBatteryLevel = level
|
|
730
|
+
lastPolledCharging = charging
|
|
731
|
+
|
|
732
|
+
FlirLogger.logBattery(level: level, isCharging: charging)
|
|
733
|
+
|
|
734
|
+
// Emit to delegate/RN via notification
|
|
735
|
+
NotificationCenter.default.post(
|
|
736
|
+
name: Notification.Name("FlirBatteryUpdated"),
|
|
737
|
+
object: nil,
|
|
738
|
+
userInfo: ["level": level, "isCharging": charging]
|
|
739
|
+
)
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
661
743
|
// MARK: - Emulator
|
|
662
744
|
|
|
663
745
|
@objc public func startEmulator(type: String) {
|
|
664
|
-
|
|
746
|
+
FlirLogger.log(.connection, "Starting emulator with type: \(type)")
|
|
665
747
|
|
|
666
748
|
#if FLIR_ENABLED
|
|
667
749
|
// Create emulator identity
|
|
@@ -671,6 +753,7 @@ import ThermalSDK
|
|
|
671
753
|
} else if type.lowercased().contains("pro") {
|
|
672
754
|
cameraType = .flirOneEdgePro
|
|
673
755
|
}
|
|
756
|
+
FlirLogger.log(.connection, "Emulator camera type: \(cameraType)")
|
|
674
757
|
|
|
675
758
|
if let emulatorIdentity = FLIRIdentity(emulatorType: cameraType) {
|
|
676
759
|
discoveredDevices.append(FlirDeviceInfo(
|
|
@@ -680,11 +763,15 @@ import ThermalSDK
|
|
|
680
763
|
isEmulator: true
|
|
681
764
|
))
|
|
682
765
|
identityMap[emulatorIdentity.deviceId()] = emulatorIdentity
|
|
766
|
+
FlirLogger.log(.connection, "Emulator identity created: \(emulatorIdentity.deviceId())")
|
|
683
767
|
|
|
684
768
|
// Auto-connect to emulator
|
|
685
769
|
performConnection(identity: emulatorIdentity)
|
|
770
|
+
} else {
|
|
771
|
+
FlirLogger.logError(.connection, "Failed to create emulator identity for type: \(type)")
|
|
686
772
|
}
|
|
687
773
|
#else
|
|
774
|
+
FlirLogger.logError(.connection, "FLIR SDK not available - emulator disabled")
|
|
688
775
|
delegate?.onError("FLIR SDK not available - emulator disabled")
|
|
689
776
|
#endif
|
|
690
777
|
}
|
|
@@ -764,8 +851,12 @@ extension FlirManager: FLIRDiscoveryEventDelegate {
|
|
|
764
851
|
public func cameraDiscovered(_ discoveredCamera: FLIRDiscoveredCamera) {
|
|
765
852
|
let identity = discoveredCamera.identity
|
|
766
853
|
let deviceId = identity.deviceId()
|
|
854
|
+
let displayName = discoveredCamera.displayName ?? deviceId
|
|
855
|
+
let commType = communicationInterfaceName(identity.communicationInterface())
|
|
856
|
+
let isEmulator = identity.communicationInterface() == .emulator
|
|
767
857
|
|
|
768
|
-
|
|
858
|
+
// Use FlirLogger for consistent logging
|
|
859
|
+
FlirLogger.logDeviceFound(deviceId: deviceId, name: displayName, type: commType, isEmulator: isEmulator)
|
|
769
860
|
|
|
770
861
|
// Store identity for later connection
|
|
771
862
|
identityMap[deviceId] = identity
|
|
@@ -773,14 +864,15 @@ extension FlirManager: FLIRDiscoveryEventDelegate {
|
|
|
773
864
|
// Create device info
|
|
774
865
|
let deviceInfo = FlirDeviceInfo(
|
|
775
866
|
deviceId: deviceId,
|
|
776
|
-
name:
|
|
777
|
-
communicationType:
|
|
778
|
-
isEmulator:
|
|
867
|
+
name: displayName,
|
|
868
|
+
communicationType: commType,
|
|
869
|
+
isEmulator: isEmulator
|
|
779
870
|
)
|
|
780
871
|
|
|
781
872
|
// Add to discovered list if not already present
|
|
782
873
|
if !discoveredDevices.contains(where: { $0.deviceId == deviceId }) {
|
|
783
874
|
discoveredDevices.append(deviceInfo)
|
|
875
|
+
FlirLogger.log(.discovery, "Total discovered devices: \(discoveredDevices.count)")
|
|
784
876
|
}
|
|
785
877
|
|
|
786
878
|
// Notify delegate
|
|
@@ -792,13 +884,14 @@ extension FlirManager: FLIRDiscoveryEventDelegate {
|
|
|
792
884
|
|
|
793
885
|
public func cameraLost(_ cameraIdentity: FLIRIdentity) {
|
|
794
886
|
let deviceId = cameraIdentity.deviceId()
|
|
795
|
-
|
|
887
|
+
FlirLogger.log(.discovery, "Camera lost: \(deviceId)")
|
|
796
888
|
|
|
797
889
|
identityMap.removeValue(forKey: deviceId)
|
|
798
890
|
discoveredDevices.removeAll { $0.deviceId == deviceId }
|
|
799
891
|
|
|
800
892
|
// If this was our connected device, handle disconnect
|
|
801
893
|
if connectedDeviceId == deviceId {
|
|
894
|
+
FlirLogger.log(.disconnect, "Lost connected device - triggering disconnect")
|
|
802
895
|
disconnect()
|
|
803
896
|
}
|
|
804
897
|
|
|
@@ -809,7 +902,7 @@ extension FlirManager: FLIRDiscoveryEventDelegate {
|
|
|
809
902
|
}
|
|
810
903
|
|
|
811
904
|
public func discoveryError(_ error: String, netServiceError nsnetserviceserror: Int32, on iface: FLIRCommunicationInterface) {
|
|
812
|
-
|
|
905
|
+
FlirLogger.logError(.discovery, "Discovery error: \(error) (code=\(nsnetserviceserror)) on interface: \(iface)")
|
|
813
906
|
|
|
814
907
|
DispatchQueue.main.async { [weak self] in
|
|
815
908
|
self?.delegate?.onError("Discovery error: \(error)")
|
|
@@ -817,7 +910,7 @@ extension FlirManager: FLIRDiscoveryEventDelegate {
|
|
|
817
910
|
}
|
|
818
911
|
|
|
819
912
|
public func discoveryFinished(_ iface: FLIRCommunicationInterface) {
|
|
820
|
-
|
|
913
|
+
FlirLogger.log(.discovery, "Discovery finished on interface: \(iface)")
|
|
821
914
|
isScanning = false
|
|
822
915
|
}
|
|
823
916
|
}
|
|
@@ -826,13 +919,19 @@ extension FlirManager: FLIRDiscoveryEventDelegate {
|
|
|
826
919
|
|
|
827
920
|
extension FlirManager: FLIRDataReceivedDelegate {
|
|
828
921
|
public func onDisconnected(_ camera: FLIRCamera, withError error: Error?) {
|
|
829
|
-
|
|
922
|
+
FlirLogger.logError(.disconnect, "Camera disconnected callback", error: error)
|
|
923
|
+
|
|
924
|
+
// Stop battery polling
|
|
925
|
+
stopBatteryPolling()
|
|
830
926
|
|
|
831
927
|
_isConnected = false
|
|
832
928
|
_isStreaming = false
|
|
833
929
|
connectedDeviceId = nil
|
|
834
930
|
connectedDeviceName = nil
|
|
835
931
|
|
|
932
|
+
// Reset frame counter
|
|
933
|
+
FlirLogger.resetFrameCounter()
|
|
934
|
+
|
|
836
935
|
DispatchQueue.main.async { [weak self] in
|
|
837
936
|
self?.delegate?.onDeviceDisconnected()
|
|
838
937
|
self?.emitStateChange("disconnected")
|
|
@@ -844,7 +943,7 @@ extension FlirManager: FLIRDataReceivedDelegate {
|
|
|
844
943
|
|
|
845
944
|
extension FlirManager: FLIRStreamDelegate {
|
|
846
945
|
public func onError(_ error: Error) {
|
|
847
|
-
|
|
946
|
+
FlirLogger.logError(.streaming, "Stream error", error: error)
|
|
848
947
|
|
|
849
948
|
DispatchQueue.main.async { [weak self] in
|
|
850
949
|
self?.delegate?.onError("Stream error: \(error.localizedDescription)")
|
|
@@ -884,6 +983,9 @@ extension FlirManager: FLIRStreamDelegate {
|
|
|
884
983
|
}
|
|
885
984
|
}
|
|
886
985
|
|
|
986
|
+
// Rate-limited frame logging
|
|
987
|
+
FlirLogger.logFrame(width: Int(image.size.width), height: Int(image.size.height), temperature: lastTemperature)
|
|
988
|
+
|
|
887
989
|
DispatchQueue.main.async { [weak self] in
|
|
888
990
|
guard let self = self else { return }
|
|
889
991
|
self.delegate?.onFrameReceived(
|
|
@@ -911,7 +1013,7 @@ extension FlirManager: FLIRStreamDelegate {
|
|
|
911
1013
|
}
|
|
912
1014
|
}
|
|
913
1015
|
} catch {
|
|
914
|
-
|
|
1016
|
+
FlirLogger.logError(.frame, "Streamer update error", error: error)
|
|
915
1017
|
}
|
|
916
1018
|
}
|
|
917
1019
|
}
|
|
@@ -136,8 +136,12 @@ RCT_EXPORT_METHOD(removeListeners : (NSInteger)count) {
|
|
|
136
136
|
|
|
137
137
|
+ (void)emitBatteryUpdateWithLevel:(NSInteger)level charging:(BOOL)charging {
|
|
138
138
|
NSDictionary *payload = @{@"level" : @(level), @"isCharging" : @(charging)};
|
|
139
|
-
[
|
|
140
|
-
|
|
139
|
+
NSLog(@"[FlirModule] Emitting battery update - level: %ld, charging: %d", (long)level, charging);
|
|
140
|
+
|
|
141
|
+
// Note: This is a class method, so we need to get the module instance
|
|
142
|
+
// For now, we'll just log - in production you'd need to get the module instance
|
|
143
|
+
// or convert this to an instance method
|
|
144
|
+
// [[FlirModule sharedInstance] sendEventWithName:@"FlirBatteryUpdated" body:payload];
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
#pragma mark - Methods
|
|
@@ -405,9 +409,10 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
|
|
|
405
409
|
objc_msgSend)(d, sel_registerName("toDictionary"))];
|
|
406
410
|
}
|
|
407
411
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
412
|
+
|
|
413
|
+
NSLog(@"[FlirModule] onDevicesFound - emitting FlirDevicesFound with %lu devices", (unsigned long)arr.count);
|
|
414
|
+
[self sendEventWithName:@"FlirDevicesFound"
|
|
415
|
+
body:@{@"devices" : arr, @"count" : @(arr.count)}];
|
|
411
416
|
}
|
|
412
417
|
|
|
413
418
|
- (void)onDeviceConnected:(id)device {
|
|
@@ -425,31 +430,31 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
|
|
|
425
430
|
device, sel_registerName("toDictionary"))];
|
|
426
431
|
}
|
|
427
432
|
|
|
428
|
-
[
|
|
433
|
+
NSLog(@"[FlirModule] onDeviceConnected - emitting FlirDeviceConnected event");
|
|
434
|
+
[self sendEventWithName:@"FlirDeviceConnected" body:body];
|
|
429
435
|
}
|
|
430
436
|
|
|
431
437
|
- (void)onDeviceDisconnected {
|
|
432
|
-
[
|
|
433
|
-
|
|
438
|
+
NSLog(@"[FlirModule] onDeviceDisconnected - emitting FlirDeviceDisconnected event");
|
|
439
|
+
[self sendEventWithName:@"FlirDeviceDisconnected" body:@{}];
|
|
434
440
|
}
|
|
435
441
|
|
|
436
442
|
- (void)onFrameReceived:(UIImage *)image
|
|
437
443
|
width:(NSInteger)width
|
|
438
444
|
height:(NSInteger)height {
|
|
439
445
|
// Also emit event for JS consumers (though slow, some might use it)
|
|
440
|
-
[
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
}];
|
|
446
|
+
[self sendEventWithName:@"FlirFrameReceived"
|
|
447
|
+
body:@{
|
|
448
|
+
@"width" : @(width),
|
|
449
|
+
@"height" : @(height),
|
|
450
|
+
@"timestamp" :
|
|
451
|
+
@([[NSDate date] timeIntervalSince1970] * 1000)
|
|
452
|
+
}];
|
|
448
453
|
}
|
|
449
454
|
|
|
450
455
|
- (void)onFrameReceivedRaw:(NSData *)data width:(NSInteger)width height:(NSInteger)height bytesPerRow:(NSInteger)bytesPerRow timestamp:(double)timestamp {
|
|
451
456
|
// Emit a lightweight event to notify JS that a raw bitmap is available; raw bytes are available via getLatestFrameBitmap()
|
|
452
|
-
[
|
|
457
|
+
[self sendEventWithName:@"FlirFrameBitmapAvailable" body:@{
|
|
453
458
|
@"width": @(width),
|
|
454
459
|
@"height": @(height),
|
|
455
460
|
@"bytesPerRow": @(bytesPerRow),
|
|
@@ -463,9 +468,9 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
|
|
|
463
468
|
self.connectResolve = nil;
|
|
464
469
|
self.connectReject = nil;
|
|
465
470
|
}
|
|
466
|
-
[
|
|
467
|
-
|
|
468
|
-
|
|
471
|
+
NSLog(@"[FlirModule] onError - emitting FlirError: %@", message);
|
|
472
|
+
[self sendEventWithName:@"FlirError"
|
|
473
|
+
body:@{@"error" : message ?: @"Unknown error"}];
|
|
469
474
|
}
|
|
470
475
|
|
|
471
476
|
- (void)onStateChanged:(NSString *)state
|
|
@@ -478,7 +483,8 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
|
|
|
478
483
|
@"isStreaming" : @(isStreaming),
|
|
479
484
|
@"isEmulator" : @(isEmulator)
|
|
480
485
|
};
|
|
481
|
-
[
|
|
486
|
+
NSLog(@"[FlirModule] onStateChanged - state: %@, connected: %d, streaming: %d", state, isConnected, isStreaming);
|
|
487
|
+
[self sendEventWithName:@"FlirStateChanged" body:body];
|
|
482
488
|
}
|
|
483
489
|
|
|
484
490
|
@end
|
package/package.json
CHANGED