ilabs-flir 2.2.24 → 2.2.27

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.
@@ -180,8 +180,10 @@ object FlirManager {
180
180
  }
181
181
 
182
182
  fun getTemperatureAtNormalized(nx: Double, ny: Double): Double? {
183
- // Not implemented in simplified version
184
- return null
183
+ val bitmap = latestBitmap ?: return null
184
+ val px = (nx * bitmap.width).toInt().coerceIn(0, bitmap.width - 1)
185
+ val py = (ny * bitmap.height).toInt().coerceIn(0, bitmap.height - 1)
186
+ return getTemperatureAt(px, py)
185
187
  }
186
188
 
187
189
  fun getTemperatureAtPoint(x: Int, y: Int): Double? = getTemperatureAt(x, y)
@@ -255,9 +257,9 @@ object FlirManager {
255
257
  return
256
258
  }
257
259
 
258
- // THROTTLE: Limit to ~15 FPS to prevent UI thread flooding
260
+ // THROTTLE: Limit to ~30 FPS for smoother streaming
259
261
  val now = System.currentTimeMillis()
260
- if (now - lastEmitMs.get() < 66) { // 66ms ~= 15 FPS
262
+ if (now - lastEmitMs.get() < 33) { // 33ms ~= 30 FPS
261
263
  return
262
264
  }
263
265
  lastEmitMs.set(now)
@@ -67,6 +67,16 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
67
67
  promise.reject("ERR_FLIR_SAMPLE", e)
68
68
  }
69
69
  }
70
+
71
+ @ReactMethod
72
+ fun getTemperatureAtNormalized(nx: Double, ny: Double, promise: Promise) {
73
+ try {
74
+ val temp = FlirManager.getTemperatureAtNormalized(nx, ny)
75
+ if (temp != null) promise.resolve(temp) else promise.resolve(null)
76
+ } catch (e: Exception) {
77
+ promise.reject("ERR_FLIR_TEMP_NORM", e)
78
+ }
79
+ }
70
80
 
71
81
  @ReactMethod
72
82
  fun isEmulator(promise: Promise) {
@@ -1,6 +1,7 @@
1
1
  package flir.android;
2
2
 
3
3
  import android.content.Context;
4
+ import android.content.SharedPreferences;
4
5
  import android.graphics.Bitmap;
5
6
  import android.util.Log;
6
7
 
@@ -9,6 +10,7 @@ import com.flir.thermalsdk.androidsdk.ThermalSdkAndroid;
9
10
  import com.flir.thermalsdk.androidsdk.image.BitmapAndroid;
10
11
  import com.flir.thermalsdk.image.Point;
11
12
  import com.flir.thermalsdk.image.ThermalValue;
13
+ import com.flir.thermalsdk.live.AuthenticationResponse;
12
14
  import com.flir.thermalsdk.live.Camera;
13
15
  import com.flir.thermalsdk.live.CommunicationInterface;
14
16
  import com.flir.thermalsdk.live.ConnectParameters;
@@ -25,6 +27,7 @@ import java.util.Collections;
25
27
  import java.util.List;
26
28
  import java.util.concurrent.Executor;
27
29
  import java.util.concurrent.Executors;
30
+ import java.util.concurrent.atomic.AtomicBoolean;
28
31
 
29
32
  /**
30
33
  * Simplified FLIR SDK Manager - matches sample app pattern
@@ -45,6 +48,8 @@ public class FlirSdkManager {
45
48
  private Stream activeStream;
46
49
  private final List<Identity> discoveredDevices = Collections.synchronizedList(new ArrayList<>());
47
50
  private volatile Bitmap latestBitmap;
51
+ private final AtomicBoolean isProcessingFrame = new AtomicBoolean(false);
52
+ private boolean useHalfScale = false;
48
53
 
49
54
  // Listener
50
55
  private Listener listener;
@@ -173,6 +178,57 @@ public class FlirSdkManager {
173
178
 
174
179
  Log.d(TAG, "Connecting to: " + identity.deviceId);
175
180
  camera = new Camera();
181
+
182
+ // ── Authenticate for NETWORK cameras (required by FLIR SDK) ──
183
+ // Matches the official NetworkCamera sample app pattern.
184
+ // The FLIR One Edge Pro is a network camera and will reject
185
+ // connections without prior authentication + trust approval.
186
+ if (identity.communicationInterface == CommunicationInterface.NETWORK) {
187
+ Log.d(TAG, "Network camera detected — authenticating...");
188
+
189
+ // Use a persistent application name (workaround for camera bug
190
+ // where re-auth with a different name conflicts). Same pattern
191
+ // as CameraAuthName in the NetworkCamera sample.
192
+ SharedPreferences prefs = context.getSharedPreferences(
193
+ "flir_auth", Context.MODE_PRIVATE);
194
+ String authName = prefs.getString("auth_name", null);
195
+ if (authName == null) {
196
+ authName = context.getPackageName() + "-" +
197
+ (System.currentTimeMillis() % 10000);
198
+ prefs.edit().putString("auth_name", authName).apply();
199
+ }
200
+
201
+ AuthenticationResponse response;
202
+ int attempts = 0;
203
+ final int MAX_AUTH_ATTEMPTS = 30; // 30 seconds max wait
204
+ do {
205
+ response = camera.authenticate(identity, authName,
206
+ 41 * 1000); // 41-second timeout per attempt
207
+ Log.d(TAG, "Auth attempt " + (attempts + 1) +
208
+ " status: " + response.authenticationStatus);
209
+
210
+ if (response.authenticationStatus ==
211
+ AuthenticationResponse.AuthenticationStatus.PENDING) {
212
+ // Camera is waiting for user to press "Trust" on its screen
213
+ Thread.sleep(1000);
214
+ }
215
+ attempts++;
216
+ } while (response.authenticationStatus ==
217
+ AuthenticationResponse.AuthenticationStatus.PENDING
218
+ && attempts < MAX_AUTH_ATTEMPTS);
219
+
220
+ if (response.authenticationStatus !=
221
+ AuthenticationResponse.AuthenticationStatus.APPROVED) {
222
+ Log.e(TAG, "Authentication rejected/timed out: " +
223
+ response.authenticationStatus);
224
+ camera = null;
225
+ notifyError("Camera authentication failed. " +
226
+ "Check the camera screen for a trust prompt.");
227
+ return;
228
+ }
229
+ Log.d(TAG, "Authentication approved");
230
+ }
231
+
176
232
  camera.connect(identity, connectionStatusListener, new ConnectParameters());
177
233
  Log.d(TAG, "Connected to: " + identity.deviceId);
178
234
 
@@ -221,6 +277,15 @@ public class FlirSdkManager {
221
277
  executor.execute(this::startStreamInternal);
222
278
  }
223
279
 
280
+ public void setUseHalfScale(boolean useHalfScale) {
281
+ this.useHalfScale = useHalfScale;
282
+ executor.execute(() -> {
283
+ if (streamer != null) {
284
+ // We'll apply this when the streamer is created or updated
285
+ }
286
+ });
287
+ }
288
+
224
289
  private void startStreamInternal() {
225
290
  if (camera == null) {
226
291
  notifyError("Not connected");
@@ -258,22 +323,27 @@ public class FlirSdkManager {
258
323
  // Start stream with simple callback (matches sample app)
259
324
  thermalStream.start(
260
325
  unused -> {
261
- executor.execute(() -> {
262
- try {
263
- if (streamer != null && activeStream != null) {
264
- streamer.update();
265
- Bitmap bitmap = BitmapAndroid.createBitmap(streamer.getImage()).getBitMap();
266
- if (bitmap != null) {
267
- latestBitmap = bitmap;
268
- if (listener != null) {
269
- listener.onFrame(bitmap);
326
+ // Skip if previous frame still processing
327
+ if (isProcessingFrame.compareAndSet(false, true)) {
328
+ executor.execute(() -> {
329
+ try {
330
+ if (streamer != null && activeStream != null) {
331
+ streamer.update();
332
+ Bitmap bitmap = BitmapAndroid.createBitmap(streamer.getImage()).getBitMap();
333
+ if (bitmap != null) {
334
+ latestBitmap = bitmap;
335
+ if (listener != null) {
336
+ listener.onFrame(bitmap);
337
+ }
270
338
  }
271
339
  }
340
+ } catch (Exception e) {
341
+ Log.e(TAG, "Frame error", e);
342
+ } finally {
343
+ isProcessingFrame.set(false);
272
344
  }
273
- } catch (Exception e) {
274
- Log.e(TAG, "Frame error", e);
275
- }
276
- });
345
+ });
346
+ }
277
347
  },
278
348
  error -> {
279
349
  executor.execute(() -> {