ilabs-flir 2.1.402 → 2.2.2
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 +32 -20
- package/ios/Flir/src/FlirModule.m +58 -25
- package/package.json +1 -1
|
@@ -174,25 +174,35 @@ import ThermalSDK
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
@objc public func getBatteryLevel() -> Int {
|
|
177
|
-
|
|
178
|
-
if
|
|
179
|
-
|
|
180
|
-
if let batt = cam.value(forKey: "battery") as? NSObject,
|
|
181
|
-
let lv = batt.value(forKey: "level") as? Int { return lv }
|
|
177
|
+
// Emulators don't have battery - return -1 immediately
|
|
178
|
+
if isEmulator {
|
|
179
|
+
return -1
|
|
182
180
|
}
|
|
183
|
-
|
|
181
|
+
|
|
182
|
+
#if FLIR_ENABLED
|
|
183
|
+
// Only try battery access on real hardware (not emulators)
|
|
184
|
+
// Note: KVC can throw NSException which Swift can't catch
|
|
185
|
+
// So we avoid using KVC entirely for battery
|
|
186
|
+
return -1 // TODO: Find safe API to access battery without KVC
|
|
187
|
+
#else
|
|
184
188
|
return -1
|
|
189
|
+
#endif
|
|
185
190
|
}
|
|
186
191
|
|
|
187
192
|
@objc public func isBatteryCharging() -> Bool {
|
|
188
|
-
|
|
189
|
-
if
|
|
190
|
-
|
|
191
|
-
if let batt = cam.value(forKey: "battery") as? NSObject,
|
|
192
|
-
let ch = batt.value(forKey: "charging") as? Bool { return ch }
|
|
193
|
+
// Emulators don't have battery - return false immediately
|
|
194
|
+
if isEmulator {
|
|
195
|
+
return false
|
|
193
196
|
}
|
|
194
|
-
|
|
197
|
+
|
|
198
|
+
#if FLIR_ENABLED
|
|
199
|
+
// Only try battery access on real hardware (not emulators)
|
|
200
|
+
// Note: KVC can throw NSException which Swift can't catch
|
|
201
|
+
// So we avoid using KVC entirely for battery
|
|
202
|
+
return false // TODO: Find safe API to access battery without KVC
|
|
203
|
+
#else
|
|
195
204
|
return false
|
|
205
|
+
#endif
|
|
196
206
|
}
|
|
197
207
|
|
|
198
208
|
@objc public func latestFrameImage() -> UIImage? {
|
|
@@ -509,6 +519,8 @@ import ThermalSDK
|
|
|
509
519
|
connectedDeviceName = identity.deviceId()
|
|
510
520
|
_isConnected = true
|
|
511
521
|
|
|
522
|
+
FlirLogger.log(.connection, "[Flir-BRIDGE-CONNECTION] Connected to: \(identity.deviceId())")
|
|
523
|
+
|
|
512
524
|
// Get camera info if available
|
|
513
525
|
if let remoteControl = cam.getRemoteControl(),
|
|
514
526
|
let cameraInfo = try? remoteControl.getCameraInformation() {
|
|
@@ -542,8 +554,10 @@ import ThermalSDK
|
|
|
542
554
|
communicationType: self.communicationInterfaceName(identity.communicationInterface()),
|
|
543
555
|
isEmulator: identity.communicationInterface() == .emulator
|
|
544
556
|
)
|
|
545
|
-
|
|
557
|
+
|
|
558
|
+
// Emit connected state (matches Android emitDeviceState("connected"))
|
|
546
559
|
self.emitStateChange("connected")
|
|
560
|
+
self.delegate?.onDeviceConnected(deviceInfo)
|
|
547
561
|
}
|
|
548
562
|
|
|
549
563
|
} catch {
|
|
@@ -697,7 +711,10 @@ import ThermalSDK
|
|
|
697
711
|
// MARK: - Battery Polling (like Android)
|
|
698
712
|
|
|
699
713
|
private func startBatteryPolling() {
|
|
700
|
-
|
|
714
|
+
// Don't poll battery on emulators - they don't have batteries
|
|
715
|
+
if isEmulator {
|
|
716
|
+
return
|
|
717
|
+
}
|
|
701
718
|
|
|
702
719
|
// Cancel any existing timer
|
|
703
720
|
stopBatteryPolling()
|
|
@@ -713,9 +730,6 @@ import ThermalSDK
|
|
|
713
730
|
}
|
|
714
731
|
|
|
715
732
|
private func stopBatteryPolling() {
|
|
716
|
-
if batteryPollingTimer != nil {
|
|
717
|
-
FlirLogger.log(.battery, "Stopping battery polling timer")
|
|
718
|
-
}
|
|
719
733
|
batteryPollingTimer?.invalidate()
|
|
720
734
|
batteryPollingTimer = nil
|
|
721
735
|
}
|
|
@@ -724,13 +738,11 @@ import ThermalSDK
|
|
|
724
738
|
let level = getBatteryLevel()
|
|
725
739
|
let charging = isBatteryCharging()
|
|
726
740
|
|
|
727
|
-
// Only
|
|
741
|
+
// Only emit if values changed
|
|
728
742
|
if level != lastPolledBatteryLevel || charging != lastPolledCharging {
|
|
729
743
|
lastPolledBatteryLevel = level
|
|
730
744
|
lastPolledCharging = charging
|
|
731
745
|
|
|
732
|
-
FlirLogger.logBattery(level: level, isCharging: charging)
|
|
733
|
-
|
|
734
746
|
// Emit to delegate/RN via notification
|
|
735
747
|
NotificationCenter.default.post(
|
|
736
748
|
name: Notification.Name("FlirBatteryUpdated"),
|
|
@@ -97,7 +97,9 @@ static BOOL flir_isPreferSdkRotation(void) {
|
|
|
97
97
|
@property(nonatomic, copy) RCTPromiseRejectBlock connectReject;
|
|
98
98
|
@end
|
|
99
99
|
|
|
100
|
-
@implementation FlirModule
|
|
100
|
+
@implementation FlirModule {
|
|
101
|
+
NSInteger _listenerCount;
|
|
102
|
+
}
|
|
101
103
|
|
|
102
104
|
RCT_EXPORT_MODULE(FlirModule);
|
|
103
105
|
|
|
@@ -107,6 +109,7 @@ RCT_EXPORT_MODULE(FlirModule);
|
|
|
107
109
|
|
|
108
110
|
- (instancetype)init {
|
|
109
111
|
if (self = [super init]) {
|
|
112
|
+
_listenerCount = 0;
|
|
110
113
|
// Wire up delegate
|
|
111
114
|
id manager = flir_manager_shared();
|
|
112
115
|
if (manager) {
|
|
@@ -126,7 +129,24 @@ RCT_EXPORT_MODULE(FlirModule);
|
|
|
126
129
|
];
|
|
127
130
|
}
|
|
128
131
|
|
|
132
|
+
- (void)startObserving {
|
|
133
|
+
// Called automatically by RCTEventEmitter when first listener is added
|
|
134
|
+
// This ensures the parent class knows we have listeners
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
- (void)stopObserving {
|
|
138
|
+
// Called automatically by RCTEventEmitter when last listener is removed
|
|
139
|
+
}
|
|
140
|
+
|
|
129
141
|
RCT_EXPORT_METHOD(addListener : (NSString *)eventName) {
|
|
142
|
+
_listenerCount++;
|
|
143
|
+
NSLog(@"[FlirModule] addListener: %@ (count: %ld)", eventName, (long)_listenerCount);
|
|
144
|
+
|
|
145
|
+
// CRITICAL: Call parent to register with RCTEventEmitter's internal tracking
|
|
146
|
+
// Without this, sendEventWithName will show "no listeners registered" warning
|
|
147
|
+
// and may not deliver events properly
|
|
148
|
+
[super addListener:eventName];
|
|
149
|
+
|
|
130
150
|
// When FlirDevicesFound listener is added, immediately emit current device list
|
|
131
151
|
// This handles the case where discovery happened before React Native mounted
|
|
132
152
|
if ([eventName isEqualToString:@"FlirDevicesFound"]) {
|
|
@@ -145,7 +165,12 @@ RCT_EXPORT_METHOD(addListener : (NSString *)eventName) {
|
|
|
145
165
|
}
|
|
146
166
|
|
|
147
167
|
RCT_EXPORT_METHOD(removeListeners : (NSInteger)count) {
|
|
148
|
-
|
|
168
|
+
_listenerCount -= count;
|
|
169
|
+
if (_listenerCount < 0) _listenerCount = 0;
|
|
170
|
+
NSLog(@"[FlirModule] removeListeners: %ld (remaining: %ld)", (long)count, (long)_listenerCount);
|
|
171
|
+
|
|
172
|
+
// CRITICAL: Call parent to unregister with RCTEventEmitter's internal tracking
|
|
173
|
+
[super removeListeners:count];
|
|
149
174
|
}
|
|
150
175
|
|
|
151
176
|
+ (void)emitBatteryUpdateWithLevel:(NSInteger)level charging:(BOOL)charging {
|
|
@@ -226,18 +251,26 @@ RCT_EXPORT_METHOD(getDiscoveredDevices : (RCTPromiseResolveBlock)
|
|
|
226
251
|
RCT_EXPORT_METHOD(connectToDevice : (NSString *)deviceId resolver : (
|
|
227
252
|
RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
228
253
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
229
|
-
|
|
230
|
-
self.connectReject = reject;
|
|
254
|
+
NSLog(@"[FlirModule] connectToDevice called for: %@", deviceId);
|
|
231
255
|
|
|
232
256
|
id manager = flir_manager_shared();
|
|
233
257
|
if (manager &&
|
|
234
258
|
[manager respondsToSelector:sel_registerName("connectToDevice:")]) {
|
|
259
|
+
NSLog(@"[FlirModule] Calling FlirManager.connectToDevice");
|
|
260
|
+
|
|
261
|
+
// Store callbacks for event-driven updates (but don't block on them)
|
|
262
|
+
self.connectResolve = nil; // Don't use promise for blocking
|
|
263
|
+
self.connectReject = nil;
|
|
264
|
+
|
|
265
|
+
// Initiate connection asynchronously
|
|
235
266
|
((void (*)(id, SEL, id))objc_msgSend)(
|
|
236
267
|
manager, sel_registerName("connectToDevice:"), deviceId);
|
|
268
|
+
|
|
269
|
+
// Resolve immediately - connection status will come via events
|
|
270
|
+
resolve(@(YES));
|
|
237
271
|
} else {
|
|
272
|
+
NSLog(@"[FlirModule] FlirManager not found");
|
|
238
273
|
reject(@"ERR_NO_MANAGER", @"FlirManager not found", nil);
|
|
239
|
-
self.connectResolve = nil;
|
|
240
|
-
self.connectReject = nil;
|
|
241
274
|
}
|
|
242
275
|
});
|
|
243
276
|
}
|
|
@@ -269,16 +302,21 @@ RCT_EXPORT_METHOD(stopFlir : (RCTPromiseResolveBlock)
|
|
|
269
302
|
RCT_EXPORT_METHOD(startEmulator : (NSString *)emulatorType resolver : (
|
|
270
303
|
RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
271
304
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
272
|
-
|
|
273
|
-
|
|
305
|
+
NSLog(@"[FlirModule] startEmulator called for type: %@", emulatorType);
|
|
306
|
+
|
|
274
307
|
id manager = flir_manager_shared();
|
|
275
308
|
if (manager && [manager respondsToSelector:sel_registerName(
|
|
276
309
|
"startEmulatorWithType:")]) {
|
|
277
|
-
//
|
|
278
|
-
|
|
279
|
-
|
|
310
|
+
// Store callbacks for event-driven updates (but don't block on them)
|
|
311
|
+
self.connectResolve = nil;
|
|
312
|
+
self.connectReject = nil;
|
|
313
|
+
|
|
314
|
+
// Initiate emulator start asynchronously
|
|
280
315
|
((void (*)(id, SEL, id))objc_msgSend)(
|
|
281
316
|
manager, sel_registerName("startEmulatorWithType:"), emulatorType);
|
|
317
|
+
|
|
318
|
+
// Resolve immediately - connection status will come via events
|
|
319
|
+
resolve(@(YES));
|
|
282
320
|
} else {
|
|
283
321
|
// Fallback if selector assumption wrong/mismatch
|
|
284
322
|
reject(@"ERR_NOT_IMPL",
|
|
@@ -424,18 +462,18 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
|
|
|
424
462
|
}
|
|
425
463
|
}
|
|
426
464
|
|
|
427
|
-
NSLog(@"[FlirModule] onDevicesFound -
|
|
428
|
-
|
|
429
|
-
|
|
465
|
+
NSLog(@"[FlirModule] onDevicesFound - %lu devices, listenerCount: %ld", (unsigned long)arr.count, (long)_listenerCount);
|
|
466
|
+
|
|
467
|
+
if (_listenerCount > 0) {
|
|
468
|
+
NSLog(@"[FlirModule] emitting FlirDevicesFound event");
|
|
469
|
+
[self sendEventWithName:@"FlirDevicesFound"
|
|
470
|
+
body:@{@"devices" : arr, @"count" : @(arr.count)}];
|
|
471
|
+
} else {
|
|
472
|
+
NSLog(@"[FlirModule] ⚠️ No listeners registered yet - devices will be re-emitted when listener is added");
|
|
473
|
+
}
|
|
430
474
|
}
|
|
431
475
|
|
|
432
476
|
- (void)onDeviceConnected:(id)device {
|
|
433
|
-
if (self.connectResolve) {
|
|
434
|
-
self.connectResolve(@(YES));
|
|
435
|
-
self.connectResolve = nil;
|
|
436
|
-
self.connectReject = nil;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
477
|
// device is FlirDeviceInfo
|
|
440
478
|
NSMutableDictionary *body = [NSMutableDictionary new];
|
|
441
479
|
if ([device respondsToSelector:sel_registerName("toDictionary")]) {
|
|
@@ -483,11 +521,6 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
|
|
|
483
521
|
}
|
|
484
522
|
|
|
485
523
|
- (void)onError:(NSString *)message {
|
|
486
|
-
if (self.connectReject) {
|
|
487
|
-
self.connectReject(@"ERR_FLIR", message, nil);
|
|
488
|
-
self.connectResolve = nil;
|
|
489
|
-
self.connectReject = nil;
|
|
490
|
-
}
|
|
491
524
|
NSLog(@"[FlirModule] onError - emitting FlirError: %@", message);
|
|
492
525
|
[self sendEventWithName:@"FlirError"
|
|
493
526
|
body:@{@"error" : message ?: @"Unknown error"}];
|