ilabs-flir 2.2.1 → 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.
@@ -174,25 +174,35 @@ import ThermalSDK
174
174
  }
175
175
 
176
176
  @objc public func getBatteryLevel() -> Int {
177
- #if FLIR_ENABLED
178
- if let cam = camera {
179
- if let val = cam.value(forKey: "batteryLevel") as? Int { return val }
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
- #endif
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
- #if FLIR_ENABLED
189
- if let cam = camera {
190
- if let ch = cam.value(forKey: "isCharging") as? Bool { return ch }
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
- #endif
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? {
@@ -701,7 +711,10 @@ import ThermalSDK
701
711
  // MARK: - Battery Polling (like Android)
702
712
 
703
713
  private func startBatteryPolling() {
704
- FlirLogger.log(.battery, "Starting battery polling timer (5s interval)")
714
+ // Don't poll battery on emulators - they don't have batteries
715
+ if isEmulator {
716
+ return
717
+ }
705
718
 
706
719
  // Cancel any existing timer
707
720
  stopBatteryPolling()
@@ -717,9 +730,6 @@ import ThermalSDK
717
730
  }
718
731
 
719
732
  private func stopBatteryPolling() {
720
- if batteryPollingTimer != nil {
721
- FlirLogger.log(.battery, "Stopping battery polling timer")
722
- }
723
733
  batteryPollingTimer?.invalidate()
724
734
  batteryPollingTimer = nil
725
735
  }
@@ -728,13 +738,11 @@ import ThermalSDK
728
738
  let level = getBatteryLevel()
729
739
  let charging = isBatteryCharging()
730
740
 
731
- // Only log and emit if values changed
741
+ // Only emit if values changed
732
742
  if level != lastPolledBatteryLevel || charging != lastPolledCharging {
733
743
  lastPolledBatteryLevel = level
734
744
  lastPolledCharging = charging
735
745
 
736
- FlirLogger.logBattery(level: level, isCharging: charging)
737
-
738
746
  // Emit to delegate/RN via notification
739
747
  NotificationCenter.default.post(
740
748
  name: Notification.Name("FlirBatteryUpdated"),
@@ -129,10 +129,24 @@ RCT_EXPORT_MODULE(FlirModule);
129
129
  ];
130
130
  }
131
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
+
132
141
  RCT_EXPORT_METHOD(addListener : (NSString *)eventName) {
133
142
  _listenerCount++;
134
143
  NSLog(@"[FlirModule] addListener: %@ (count: %ld)", eventName, (long)_listenerCount);
135
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
+
136
150
  // When FlirDevicesFound listener is added, immediately emit current device list
137
151
  // This handles the case where discovery happened before React Native mounted
138
152
  if ([eventName isEqualToString:@"FlirDevicesFound"]) {
@@ -154,6 +168,9 @@ RCT_EXPORT_METHOD(removeListeners : (NSInteger)count) {
154
168
  _listenerCount -= count;
155
169
  if (_listenerCount < 0) _listenerCount = 0;
156
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];
157
174
  }
158
175
 
159
176
  + (void)emitBatteryUpdateWithLevel:(NSInteger)level charging:(BOOL)charging {
@@ -234,18 +251,26 @@ RCT_EXPORT_METHOD(getDiscoveredDevices : (RCTPromiseResolveBlock)
234
251
  RCT_EXPORT_METHOD(connectToDevice : (NSString *)deviceId resolver : (
235
252
  RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject) {
236
253
  dispatch_async(dispatch_get_main_queue(), ^{
237
- self.connectResolve = resolve;
238
- self.connectReject = reject;
254
+ NSLog(@"[FlirModule] connectToDevice called for: %@", deviceId);
239
255
 
240
256
  id manager = flir_manager_shared();
241
257
  if (manager &&
242
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
243
266
  ((void (*)(id, SEL, id))objc_msgSend)(
244
267
  manager, sel_registerName("connectToDevice:"), deviceId);
268
+
269
+ // Resolve immediately - connection status will come via events
270
+ resolve(@(YES));
245
271
  } else {
272
+ NSLog(@"[FlirModule] FlirManager not found");
246
273
  reject(@"ERR_NO_MANAGER", @"FlirManager not found", nil);
247
- self.connectResolve = nil;
248
- self.connectReject = nil;
249
274
  }
250
275
  });
251
276
  }
@@ -277,16 +302,21 @@ RCT_EXPORT_METHOD(stopFlir : (RCTPromiseResolveBlock)
277
302
  RCT_EXPORT_METHOD(startEmulator : (NSString *)emulatorType resolver : (
278
303
  RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject) {
279
304
  dispatch_async(dispatch_get_main_queue(), ^{
280
- self.connectResolve = resolve;
281
- self.connectReject = reject;
305
+ NSLog(@"[FlirModule] startEmulator called for type: %@", emulatorType);
306
+
282
307
  id manager = flir_manager_shared();
283
308
  if (manager && [manager respondsToSelector:sel_registerName(
284
309
  "startEmulatorWithType:")]) {
285
- // Swift: startEmulator(type: String) -> exposed as startEmulatorWithType:
286
- // ? Or startEmulatorWith? Swift default naming: startEmulator(type:) ->
287
- // startEmulatorWithType:
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
288
315
  ((void (*)(id, SEL, id))objc_msgSend)(
289
316
  manager, sel_registerName("startEmulatorWithType:"), emulatorType);
317
+
318
+ // Resolve immediately - connection status will come via events
319
+ resolve(@(YES));
290
320
  } else {
291
321
  // Fallback if selector assumption wrong/mismatch
292
322
  reject(@"ERR_NOT_IMPL",
@@ -444,12 +474,6 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
444
474
  }
445
475
 
446
476
  - (void)onDeviceConnected:(id)device {
447
- if (self.connectResolve) {
448
- self.connectResolve(@(YES));
449
- self.connectResolve = nil;
450
- self.connectReject = nil;
451
- }
452
-
453
477
  // device is FlirDeviceInfo
454
478
  NSMutableDictionary *body = [NSMutableDictionary new];
455
479
  if ([device respondsToSelector:sel_registerName("toDictionary")]) {
@@ -497,11 +521,6 @@ RCT_EXPORT_METHOD(isPreferSdkRotation : (RCTPromiseResolveBlock)
497
521
  }
498
522
 
499
523
  - (void)onError:(NSString *)message {
500
- if (self.connectReject) {
501
- self.connectReject(@"ERR_FLIR", message, nil);
502
- self.connectResolve = nil;
503
- self.connectReject = nil;
504
- }
505
524
  NSLog(@"[FlirModule] onError - emitting FlirError: %@", message);
506
525
  [self sendEventWithName:@"FlirError"
507
526
  body:@{@"error" : message ?: @"Unknown error"}];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ilabs-flir",
3
- "version": "2.2.001",
3
+ "version": "2.2.2",
4
4
  "description": "FLIR Thermal SDK for React Native - iOS & Android (bundled at compile time via postinstall)",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",