ilabs-flir 1.0.2 → 1.0.4

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.
Files changed (126) hide show
  1. package/Flir.podspec +31 -31
  2. package/README.md +1271 -1271
  3. package/android/Flir/build.gradle.kts +85 -80
  4. package/android/Flir/libs/flir-stubs.jar +0 -0
  5. package/android/Flir/src/main/AndroidManifest.xml +31 -31
  6. package/android/Flir/src/main/java/com/flir/thermalsdk/ErrorCode.java +13 -0
  7. package/android/Flir/src/main/java/com/flir/thermalsdk/ErrorCodeException.java +14 -0
  8. package/android/Flir/src/main/java/com/flir/thermalsdk/ThermalSdkAndroid.java +16 -0
  9. package/android/Flir/src/main/java/com/flir/thermalsdk/androidsdk/image/BitmapAndroid.java +20 -0
  10. package/android/Flir/src/main/java/com/flir/thermalsdk/image/ImageBuffer.java +11 -0
  11. package/android/Flir/src/main/java/com/flir/thermalsdk/image/JavaImageBuffer.java +35 -0
  12. package/android/Flir/src/main/java/com/flir/thermalsdk/image/Palette.java +15 -0
  13. package/android/Flir/src/main/java/com/flir/thermalsdk/image/PaletteManager.java +16 -0
  14. package/android/Flir/src/main/java/com/flir/thermalsdk/image/Point.java +11 -0
  15. package/android/Flir/src/main/java/com/flir/thermalsdk/image/ThermalImage.java +23 -0
  16. package/android/Flir/src/main/java/com/flir/thermalsdk/image/ThermalValue.java +9 -0
  17. package/android/Flir/src/main/java/com/flir/thermalsdk/live/Camera.java +26 -0
  18. package/android/Flir/src/main/java/com/flir/thermalsdk/live/CameraType.java +8 -0
  19. package/android/Flir/src/main/java/com/flir/thermalsdk/live/CommunicationInterface.java +16 -0
  20. package/android/Flir/src/main/java/com/flir/thermalsdk/live/ConnectParameters.java +16 -0
  21. package/android/Flir/src/main/java/com/flir/thermalsdk/live/Identity.java +23 -0
  22. package/android/Flir/src/main/java/com/flir/thermalsdk/live/IpSettings.java +9 -0
  23. package/android/Flir/src/main/java/com/flir/thermalsdk/live/RemoteControl.java +16 -0
  24. package/android/Flir/src/main/java/com/flir/thermalsdk/live/connectivity/ConnectionStatusListener.java +7 -0
  25. package/android/Flir/src/main/java/com/flir/thermalsdk/live/discovery/DiscoveryEventListener.java +14 -0
  26. package/android/Flir/src/main/java/com/flir/thermalsdk/live/discovery/DiscoveryFactory.java +33 -0
  27. package/android/Flir/src/main/java/com/flir/thermalsdk/live/remote/OnReceived.java +5 -0
  28. package/android/Flir/src/main/java/com/flir/thermalsdk/live/remote/OnRemoteError.java +7 -0
  29. package/android/Flir/src/main/java/com/flir/thermalsdk/live/streaming/Stream.java +8 -0
  30. package/android/Flir/src/main/java/com/flir/thermalsdk/live/streaming/ThermalStreamer.java +28 -0
  31. package/android/Flir/src/main/java/com/flir/thermalsdk/live/streaming/VisualStreamer.java +18 -0
  32. package/android/Flir/src/main/java/flir/android/FlirCommands.java +136 -0
  33. package/android/Flir/src/main/java/flir/android/FlirDownloadManager.kt +76 -75
  34. package/android/Flir/src/main/java/flir/android/FlirDownloadPackage.kt +16 -16
  35. package/android/Flir/src/main/java/flir/android/FlirFrameCache.kt +6 -6
  36. package/android/Flir/src/main/java/flir/android/FlirManager.kt +477 -248
  37. package/android/Flir/src/main/java/flir/android/FlirModule.kt +74 -74
  38. package/android/Flir/src/main/java/flir/android/FlirPackage.kt +19 -19
  39. package/android/Flir/src/main/java/flir/android/FlirSDKLoader.kt +165 -117
  40. package/android/Flir/src/main/java/flir/android/FlirSdkManager.java +1511 -0
  41. package/android/Flir/src/main/java/flir/android/FlirStatus.kt +12 -12
  42. package/android/Flir/src/main/java/flir/android/FlirView.kt +48 -48
  43. package/android/Flir/src/main/java/flir/android/FlirViewManager.kt +13 -13
  44. package/app.plugin.js +264 -264
  45. package/expo-module.config.json +5 -5
  46. package/ios/Flir/Framework/ThermalSDK/FLIRBattery.h +76 -76
  47. package/ios/Flir/Framework/ThermalSDK/FLIRCalibration.h +108 -108
  48. package/ios/Flir/Framework/ThermalSDK/FLIRCamera.h +156 -156
  49. package/ios/Flir/Framework/ThermalSDK/FLIRCameraDeviceInfo.h +53 -53
  50. package/ios/Flir/Framework/ThermalSDK/FLIRCameraEvent.h +132 -132
  51. package/ios/Flir/Framework/ThermalSDK/FLIRCameraImport.h +204 -204
  52. package/ios/Flir/Framework/ThermalSDK/FLIRColorDistributionSettings.h +204 -204
  53. package/ios/Flir/Framework/ThermalSDK/FLIRColorizer.h +82 -82
  54. package/ios/Flir/Framework/ThermalSDK/FLIRDiscoveredCamera.h +44 -44
  55. package/ios/Flir/Framework/ThermalSDK/FLIRDiscovery.h +132 -132
  56. package/ios/Flir/Framework/ThermalSDK/FLIRDisplaySettings.h +29 -29
  57. package/ios/Flir/Framework/ThermalSDK/FLIRFocus.h +70 -70
  58. package/ios/Flir/Framework/ThermalSDK/FLIRFusion.h +192 -192
  59. package/ios/Flir/Framework/ThermalSDK/FLIRFusionController.h +136 -136
  60. package/ios/Flir/Framework/ThermalSDK/FLIRFusionTransformation.h +35 -35
  61. package/ios/Flir/Framework/ThermalSDK/FLIRIdentity.h +264 -264
  62. package/ios/Flir/Framework/ThermalSDK/FLIRImageBase.h +196 -196
  63. package/ios/Flir/Framework/ThermalSDK/FLIRImageColorizer.h +26 -26
  64. package/ios/Flir/Framework/ThermalSDK/FLIRImageStatistics.h +61 -61
  65. package/ios/Flir/Framework/ThermalSDK/FLIRIsotherms.h +208 -208
  66. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementArea.h +38 -38
  67. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementCollection.h +147 -147
  68. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementDelta.h +62 -62
  69. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementDimensions.h +33 -33
  70. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementEllipse.h +49 -49
  71. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementLine.h +66 -66
  72. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementMarker.h +69 -69
  73. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementParameters.h +41 -41
  74. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementRectangle.h +36 -36
  75. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementReference.h +27 -27
  76. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementShape.h +46 -46
  77. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementSpot.h +33 -33
  78. package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementsController.h +160 -160
  79. package/ios/Flir/Framework/ThermalSDK/FLIRMeterLinkSensorPoll.h +247 -247
  80. package/ios/Flir/Framework/ThermalSDK/FLIROverlayController.h +27 -27
  81. package/ios/Flir/Framework/ThermalSDK/FLIRPalette.h +60 -60
  82. package/ios/Flir/Framework/ThermalSDK/FLIRPaletteController.h +36 -36
  83. package/ios/Flir/Framework/ThermalSDK/FLIRPaletteManager.h +97 -97
  84. package/ios/Flir/Framework/ThermalSDK/FLIRQuantification.h +55 -55
  85. package/ios/Flir/Framework/ThermalSDK/FLIRRemoteControl.h +393 -393
  86. package/ios/Flir/Framework/ThermalSDK/FLIRRenderer.h +35 -35
  87. package/ios/Flir/Framework/ThermalSDK/FLIRRendererImpl.h +17 -17
  88. package/ios/Flir/Framework/ThermalSDK/FLIRScale.h +99 -99
  89. package/ios/Flir/Framework/ThermalSDK/FLIRScaleController.h +44 -44
  90. package/ios/Flir/Framework/ThermalSDK/FLIRStream.h +109 -109
  91. package/ios/Flir/Framework/ThermalSDK/FLIRStreamer.h +124 -124
  92. package/ios/Flir/Framework/ThermalSDK/FLIRSystem.h +40 -40
  93. package/ios/Flir/Framework/ThermalSDK/FLIRTemperatureRange.h +43 -43
  94. package/ios/Flir/Framework/ThermalSDK/FLIRThermalDelta.h +77 -77
  95. package/ios/Flir/Framework/ThermalSDK/FLIRThermalImage.h +331 -331
  96. package/ios/Flir/Framework/ThermalSDK/FLIRThermalImageFile.h +56 -56
  97. package/ios/Flir/Framework/ThermalSDK/FLIRThermalParameters.h +31 -31
  98. package/ios/Flir/Framework/ThermalSDK/FLIRThermalValue.h +92 -92
  99. package/ios/Flir/Framework/ThermalSDK/FLIRWirelessCameraDetails.h +88 -88
  100. package/ios/Flir/Framework/ThermalSDK/ThermalSDK.h +73 -73
  101. package/ios/Flir/SDKLoader/FlirSDKLoader.m +13 -13
  102. package/ios/Flir/SDKLoader/FlirSDKLoader.swift +175 -175
  103. package/ios/Flir/src/FlirEventEmitter.h +12 -12
  104. package/ios/Flir/src/FlirEventEmitter.m +33 -33
  105. package/ios/Flir/src/FlirModule.h +10 -10
  106. package/ios/Flir/src/FlirModule.m +381 -381
  107. package/ios/Flir/src/FlirPreviewView.h +13 -13
  108. package/ios/Flir/src/FlirPreviewView.m +24 -24
  109. package/ios/Flir/src/FlirState.h +20 -20
  110. package/ios/Flir/src/FlirState.m +79 -79
  111. package/ios/Flir/src/FlirViewManager.h +9 -9
  112. package/ios/Flir/src/FlirViewManager.m +16 -16
  113. package/package.json +60 -60
  114. package/react-native.config.js +14 -14
  115. package/scripts/copy_ios_libs.sh +32 -32
  116. package/scripts/create_stubs.py +174 -174
  117. package/scripts/download-sdk.js +62 -62
  118. package/scripts/prepare-binaries.sh +171 -171
  119. package/sdk-manifest.json +37 -30
  120. package/src/FlirDownload.ts +78 -78
  121. package/src/index.d.ts +17 -17
  122. package/src/index.js +7 -7
  123. package/src/index.ts +7 -7
  124. package/android/Flir/src/main/java/flir/android/CameraHandler.java +0 -194
  125. package/android/Flir/src/main/java/flir/android/FlirController.kt +0 -11
  126. package/android/Flir/src/main/java/flir/android/FrameDataHolder.java +0 -14
@@ -1,381 +1,381 @@
1
- #import "FlirModule.h"
2
- #import "FlirEventEmitter.h"
3
- #import "FlirState.h"
4
- #import <ThermalSDK/ThermalSDK.h>
5
- #import <React/RCTLog.h>
6
-
7
- #ifndef F1_gen3
8
- #define F1_gen3 FLIRCameraType_flirOne
9
- #endif
10
-
11
-
12
- @interface FlirModule() <FLIRDiscoveryEventDelegate>
13
- @property (nonatomic, strong) FLIRDiscovery *discovery;
14
- @property (nonatomic, strong) FLIRCamera *camera;
15
- @property (nonatomic, strong) FLIRIdentity *connectedIdentity;
16
- @property (nonatomic, assign) BOOL isEmulatorMode;
17
- @property (nonatomic, assign) BOOL isPhysicalDeviceConnected;
18
- @end
19
-
20
- @implementation FlirModule
21
-
22
- RCT_EXPORT_MODULE(FlirIOS);
23
-
24
- RCT_EXPORT_METHOD(startDiscovery)
25
- {
26
- // Hook into ThermalSDK discovery when ready. For now, emit an event to JS.
27
- dispatch_async(dispatch_get_main_queue(), ^{
28
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{ @"msg": @"discovery-started" }];
29
- RCTLogInfo(@"FLIR discovery started (placeholder)");
30
- });
31
- }
32
-
33
- RCT_EXPORT_METHOD(stopDiscovery)
34
- {
35
- dispatch_async(dispatch_get_main_queue(), ^{
36
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{ @"msg": @"discovery-stopped" }];
37
- RCTLogInfo(@"FLIR discovery stopped (placeholder)");
38
- });
39
- }
40
-
41
- RCT_EXPORT_METHOD(connect:(NSDictionary *)identity resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
42
- {
43
- // TODO: implement real connect using ThermalSDK and identity info
44
- dispatch_async(dispatch_get_main_queue(), ^{
45
- RCTLogInfo(@"Flir connect called (placeholder)");
46
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{ @"identity": identity ?: @{} }];
47
- resolve(@(YES));
48
- });
49
- }
50
-
51
- RCT_EXPORT_METHOD(disconnect)
52
- {
53
- dispatch_async(dispatch_get_main_queue(), ^{
54
- RCTLogInfo(@"Flir disconnect called (placeholder)");
55
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{}];
56
- });
57
- }
58
-
59
- RCT_EXPORT_METHOD(getTemperatureAt:(nonnull NSNumber *)x y:(nonnull NSNumber *)y resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
60
- // Return the last sampled temperature from the preview/state singleton
61
- dispatch_async(dispatch_get_main_queue(), ^{
62
- double t = [FlirState shared].lastTemperature;
63
- if (isnan(t)) {
64
- resolve([NSNull null]);
65
- } else {
66
- resolve(@(t));
67
- }
68
- });
69
- }
70
-
71
- RCT_EXPORT_METHOD(isEmulator:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
72
- dispatch_async(dispatch_get_main_queue(), ^{
73
- resolve(@(self.isEmulatorMode));
74
- });
75
- }
76
-
77
- RCT_EXPORT_METHOD(isDeviceConnected:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
78
- dispatch_async(dispatch_get_main_queue(), ^{
79
- resolve(@(self.isPhysicalDeviceConnected));
80
- });
81
- }
82
-
83
- RCT_EXPORT_METHOD(getConnectedDeviceInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
84
- dispatch_async(dispatch_get_main_queue(), ^{
85
- if (self.connectedIdentity == nil) {
86
- resolve(@"Not connected");
87
- } else if (self.isEmulatorMode) {
88
- resolve([NSString stringWithFormat:@"Emulator (%@)", [self.connectedIdentity deviceId]]);
89
- } else {
90
- resolve([NSString stringWithFormat:@"Physical device (%@)", [self.connectedIdentity deviceId]]);
91
- }
92
- });
93
- }
94
-
95
- RCT_EXPORT_METHOD(startEmulatorMode:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
96
- dispatch_async(dispatch_get_main_queue(), ^{
97
- [self initializeEmulatorMode];
98
- resolve(@(YES));
99
- });
100
- }
101
-
102
- - (void)initializeEmulatorMode
103
- {
104
- if (!self.discovery) {
105
- self.discovery = [[FLIRDiscovery alloc] init];
106
- self.discovery.delegate = self;
107
- }
108
-
109
- // Create emulator identity for testing; use FLIRCameraType for compatibility
110
- FLIRIdentity *emulatorIdentity = [[FLIRIdentity alloc] initWithEmulatorType:FLIRCameraType_flirOne];
111
- if (emulatorIdentity) {
112
- self.connectedIdentity = emulatorIdentity;
113
- self.isEmulatorMode = YES;
114
- self.isPhysicalDeviceConnected = NO;
115
-
116
- // Start discovery for emulator
117
- [self.discovery start:FLIRCommunicationInterfaceEmulator cameraType:FLIRCameraType_flirOne];
118
-
119
- // Emit connection event
120
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{
121
- @"identity": @{
122
- @"deviceId": [emulatorIdentity deviceId] ?: @"Emulator",
123
- @"isEmulator": @(YES)
124
- },
125
- @"deviceType": @"emulator",
126
- @"isEmulator": @(YES)
127
- }];
128
- }
129
- }
130
-
131
- #pragma mark - FLIRDiscoveryEventDelegate
132
-
133
- - (void)cameraDiscovered:(FLIRDiscoveredCamera *)discoveredCamera {
134
- FLIRIdentity *identity = discoveredCamera.identity;
135
-
136
- BOOL isRealDevice = ([identity communicationInterface] != FLIRCommunicationInterfaceEmulator);
137
-
138
- if (isRealDevice && !self.isPhysicalDeviceConnected) {
139
- self.connectedIdentity = identity;
140
- self.isEmulatorMode = NO;
141
- self.isPhysicalDeviceConnected = YES;
142
- [self connectToDevice:identity];
143
- } else if (!isRealDevice && !self.isPhysicalDeviceConnected) {
144
- self.connectedIdentity = identity;
145
- self.isEmulatorMode = YES;
146
- self.isPhysicalDeviceConnected = NO;
147
- [self connectToDevice:identity];
148
- }
149
- }
150
-
151
- #pragma mark - Helper Methods
152
-
153
- - (void)connectToDevice:(FLIRIdentity *)identity {
154
- if (!self.camera) {
155
- self.camera = [[FLIRCamera alloc] init];
156
- }
157
-
158
- NSError *error;
159
- BOOL connected = [self.camera connect:identity error:&error];
160
-
161
- if (connected) {
162
- NSString *deviceType = self.isEmulatorMode ? @"emulator" : @"device";
163
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{
164
- @"identity": @{
165
- @"deviceId": [identity deviceId] ?: @"Unknown",
166
- @"isEmulator": @(self.isEmulatorMode)
167
- },
168
- @"deviceType": deviceType,
169
- @"isEmulator": @(self.isEmulatorMode)
170
- }];
171
- } else {
172
- RCTLogError(@"Failed to connect to FLIR device: %@", error.localizedDescription);
173
- }
174
- }
175
-
176
- #pragma mark - FLIRDiscoveryEventDelegate
177
-
178
- - (void)cameraFound:(FLIRIdentity *)identity
179
- {
180
- self.connectedIdentity = identity;
181
- self.isEmulatorMode = ([identity communicationInterface] == FLIRCommunicationInterfaceEmulator);
182
- self.isPhysicalDeviceConnected = !self.isEmulatorMode;
183
-
184
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{
185
- @"identity": @{
186
- @"deviceId": [identity deviceId] ?: @"Unknown",
187
- @"isEmulator": @(self.isEmulatorMode)
188
- },
189
- @"deviceType": self.isEmulatorMode ? @"emulator" : @"physical",
190
- @"isEmulator": @(self.isEmulatorMode)
191
- }];
192
- }
193
-
194
- - (void)cameraLost:(FLIRIdentity *)identity
195
- {
196
- self.connectedIdentity = nil;
197
- self.isEmulatorMode = NO;
198
- self.isPhysicalDeviceConnected = NO;
199
-
200
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{
201
- @"identity": @{
202
- @"deviceId": [identity deviceId] ?: @"Unknown",
203
- @"isEmulator": @([identity communicationInterface] == FLIRCommunicationInterfaceEmulator)
204
- },
205
- @"wasEmulator": @([identity communicationInterface] == FLIRCommunicationInterfaceEmulator)
206
- }];
207
- }
208
-
209
- - (void)discoveryError:(NSString *)error netServiceError:(int)nsnetserviceserror on:(FLIRCommunicationInterface)iface
210
- {
211
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirError" body:@{
212
- @"error": error ?: @"Unknown discovery error",
213
- @"type": @"discovery",
214
- @"interface": @(iface)
215
- }];
216
- }
217
-
218
- @end
219
- #import "FlirModule.h"
220
- #import "FlirEventEmitter.h"
221
- #import "FlirState.h"
222
- #import <ThermalSDK/ThermalSDK.h>
223
- #ifndef F1_gen3
224
- #define F1_gen3 FLIRCameraType_flirOne
225
- #endif
226
- #import <React/RCTLog.h>
227
-
228
-
229
- @interface FlirModule()
230
- <FLIRDiscoveryEventDelegate>
231
- @property (nonatomic, strong) FLIRDiscovery *discovery;
232
- @property (nonatomic, strong) FLIRCamera *camera;
233
- @property (nonatomic, strong) FLIRIdentity *connectedIdentity;
234
- @property (nonatomic, assign) BOOL isEmulatorMode;
235
- @property (nonatomic, assign) BOOL isPhysicalDeviceConnected;
236
- @end
237
-
238
- @implementation FlirModule
239
-
240
- RCT_EXPORT_MODULE(FlirIOS);
241
-
242
- RCT_EXPORT_METHOD(startDiscovery)
243
- {
244
- // Hook into ThermalSDK discovery when ready. For now, emit an event to JS.
245
- dispatch_async(dispatch_get_main_queue(), ^{
246
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{ @"msg": @"discovery-started" }];
247
- RCTLogInfo(@"FLIR discovery started (placeholder)");
248
- });
249
- }
250
-
251
- RCT_EXPORT_METHOD(stopDiscovery)
252
- {
253
- dispatch_async(dispatch_get_main_queue(), ^{
254
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{ @"msg": @"discovery-stopped" }];
255
- RCTLogInfo(@"FLIR discovery stopped (placeholder)");
256
- });
257
- }
258
-
259
- RCT_EXPORT_METHOD(connect:(NSDictionary *)identity resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
260
- {
261
- // TODO: implement real connect using ThermalSDK and identity info
262
- dispatch_async(dispatch_get_main_queue(), ^{
263
- RCTLogInfo(@"Flir connect called (placeholder)");
264
- // emit a connected event
265
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{ @"identity": identity ?: @{} }];
266
- resolve(@(YES));
267
- });
268
- }
269
-
270
- RCT_EXPORT_METHOD(disconnect)
271
- {
272
- dispatch_async(dispatch_get_main_queue(), ^{
273
- RCTLogInfo(@"Flir disconnect called (placeholder)");
274
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{}];
275
- });
276
- }
277
-
278
- RCT_EXPORT_METHOD(getTemperatureAt:(nonnull NSNumber *)x y:(nonnull NSNumber *)y resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\n{\n // Return the last sampled temperature from the preview/state singleton\n dispatch_async(dispatch_get_main_queue(), ^{\n double t = [FlirState shared].lastTemperature;\n if (isnan(t)) {\n resolve([NSNull null]);\n } else {\n resolve(@(t));\n }\n });\n}\n\nRCT_EXPORT_METHOD(isEmulator:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\n{\n dispatch_async(dispatch_get_main_queue(), ^{\n resolve(@(self.isEmulatorMode));\n });\n}\n\nRCT_EXPORT_METHOD(isDeviceConnected:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\n{\n dispatch_async(dispatch_get_main_queue(), ^{\n resolve(@(self.isPhysicalDeviceConnected));\n });\n}\n\nRCT_EXPORT_METHOD(getConnectedDeviceInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\n{\n dispatch_async(dispatch_get_main_queue(), ^{\n if (self.connectedIdentity == nil) {\n resolve(@\"Not connected\");\n } else if (self.isEmulatorMode) {\n resolve([NSString stringWithFormat:@\"Emulator (%@)\", self.connectedIdentity.deviceId]);\n } else {\n resolve([NSString stringWithFormat:@\"Physical device (%@)\", self.connectedIdentity.deviceId]);\n }\n });\n}\n\nRCT_EXPORT_METHOD(startEmulatorMode:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\n{\n dispatch_async(dispatch_get_main_queue(), ^{\n [self initializeEmulatorMode];\n resolve(@(YES));\n });\n}\n\n- (void)initializeEmulatorMode\n{\n if (!self.discovery) {\n self.discovery = [[FLIRDiscovery alloc] init];\n self.discovery.delegate = self;\n }\n \n // Create emulator identity for testing\n FLIRIdentity *emulatorIdentity = [[FLIRIdentity alloc] initWithEmulatorType:F1_gen3];\n if (emulatorIdentity) {\n self.connectedIdentity = emulatorIdentity;\n self.isEmulatorMode = YES;\n self.isPhysicalDeviceConnected = NO;\n \n // Start discovery for emulator\n [self.discovery start:FLIRCommunicationInterfaceEmulator cameraType:F1_gen3];\n \n // Emit connection event\n [[FlirEventEmitter shared] sendDeviceEvent:@\"FlirDeviceConnected\" body:@{\n @\"identity\": @{\n @\"deviceId\": emulatorIdentity.deviceId ?: @\"Emulator\",\n @\"isEmulator\": @(YES)\n },\n @\"deviceType\": @\"emulator\",\n @\"isEmulator\": @(YES)\n }];\n }\n}
279
-
280
- #pragma mark - FLIRDiscoveryEventDelegate
281
-
282
- - (void)cameraDiscovered:(FLIRDiscoveredCamera *)discoveredCamera {
283
- FLIRIdentity *identity = discoveredCamera.identity;
284
-
285
- // Check if this is a real device or emulator
286
- BOOL isRealDevice = (identity.communicationInterface != FLIRCommunicationInterfaceEmulator);
287
-
288
- if (isRealDevice && !self.isPhysicalDeviceConnected) {
289
- // Prioritize real device over emulator
290
- self.connectedIdentity = identity;
291
- self.isEmulatorMode = NO;
292
- self.isPhysicalDeviceConnected = YES;
293
-
294
- // Connect to real device
295
- [self connectToDevice:identity];
296
- } else if (!isRealDevice && !self.isPhysicalDeviceConnected) {
297
- // Use emulator if no real device found
298
- self.connectedIdentity = identity;
299
- self.isEmulatorMode = YES;
300
- self.isPhysicalDeviceConnected = NO;
301
-
302
- // Connect to emulator
303
- [self connectToDevice:identity];
304
- }
305
- }
306
-
307
- #pragma mark - Helper Methods
308
-
309
- - (void)connectToDevice:(FLIRIdentity *)identity {
310
- if (!self.camera) {
311
- self.camera = [[FLIRCamera alloc] init];
312
- }
313
-
314
- NSError *error;
315
- BOOL connected = [self.camera connect:identity error:&error];
316
-
317
- if (connected) {
318
- NSString *deviceType = self.isEmulatorMode ? @"emulator" : @"device";
319
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{
320
- @"identity": @{
321
- @"deviceId": identity.deviceId ?: @"Unknown",
322
- @"isEmulator": @(self.isEmulatorMode)
323
- },
324
- @"deviceType": deviceType,
325
- @"isEmulator": @(self.isEmulatorMode)
326
- }];
327
- } else {
328
- RCTLogError(@"Failed to connect to FLIR device: %@", error.localizedDescription);
329
- }
330
- }
331
-
332
- #pragma mark - FLIRDiscoveryEventDelegate
333
-
334
- - (void)cameraFound:(FLIRIdentity *)identity
335
- {
336
- // Store the found camera identity
337
- self.connectedIdentity = identity;
338
-
339
- // Check if this is an emulator
340
- self.isEmulatorMode = (identity.communicationInterface == FLIRCommunicationInterfaceEmulator);
341
- self.isPhysicalDeviceConnected = !self.isEmulatorMode;
342
-
343
- // Emit connection event
344
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{
345
- @"identity": @{
346
- @"deviceId": identity.deviceId ?: @"Unknown",
347
- @"isEmulator": @(self.isEmulatorMode)
348
- },
349
- @"deviceType": self.isEmulatorMode ? @"emulator" : @"physical",
350
- @"isEmulator": @(self.isEmulatorMode)
351
- }];
352
- }
353
-
354
- - (void)cameraLost:(FLIRIdentity *)identity
355
- {
356
- // Clear connection state
357
- self.connectedIdentity = nil;
358
- self.isEmulatorMode = NO;
359
- self.isPhysicalDeviceConnected = NO;
360
-
361
- // Emit disconnection event
362
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{
363
- @"identity": @{
364
- @"deviceId": identity.deviceId ?: @"Unknown",
365
- @"isEmulator": @(identity.communicationInterface == FLIRCommunicationInterfaceEmulator)
366
- },
367
- @"wasEmulator": @(identity.communicationInterface == FLIRCommunicationInterfaceEmulator)
368
- }];
369
- }
370
-
371
- - (void)discoveryError:(NSString *)error netServiceError:(int)nsnetserviceserror on:(FLIRCommunicationInterface)iface
372
- {
373
- // Emit error event
374
- [[FlirEventEmitter shared] sendDeviceEvent:@"FlirError" body:@{
375
- @"error": error ?: @"Unknown discovery error",
376
- @"type": @"discovery",
377
- @"interface": @(iface)
378
- }];
379
- }
380
-
381
- @end
1
+ #import "FlirModule.h"
2
+ #import "FlirEventEmitter.h"
3
+ #import "FlirState.h"
4
+ #import <ThermalSDK/ThermalSDK.h>
5
+ #import <React/RCTLog.h>
6
+
7
+ #ifndef F1_gen3
8
+ #define F1_gen3 FLIRCameraType_flirOne
9
+ #endif
10
+
11
+
12
+ @interface FlirModule() <FLIRDiscoveryEventDelegate>
13
+ @property (nonatomic, strong) FLIRDiscovery *discovery;
14
+ @property (nonatomic, strong) FLIRCamera *camera;
15
+ @property (nonatomic, strong) FLIRIdentity *connectedIdentity;
16
+ @property (nonatomic, assign) BOOL isEmulatorMode;
17
+ @property (nonatomic, assign) BOOL isPhysicalDeviceConnected;
18
+ @end
19
+
20
+ @implementation FlirModule
21
+
22
+ RCT_EXPORT_MODULE(FlirIOS);
23
+
24
+ RCT_EXPORT_METHOD(startDiscovery)
25
+ {
26
+ // Hook into ThermalSDK discovery when ready. For now, emit an event to JS.
27
+ dispatch_async(dispatch_get_main_queue(), ^{
28
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{ @"msg": @"discovery-started" }];
29
+ RCTLogInfo(@"FLIR discovery started (placeholder)");
30
+ });
31
+ }
32
+
33
+ RCT_EXPORT_METHOD(stopDiscovery)
34
+ {
35
+ dispatch_async(dispatch_get_main_queue(), ^{
36
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{ @"msg": @"discovery-stopped" }];
37
+ RCTLogInfo(@"FLIR discovery stopped (placeholder)");
38
+ });
39
+ }
40
+
41
+ RCT_EXPORT_METHOD(connect:(NSDictionary *)identity resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
42
+ {
43
+ // TODO: implement real connect using ThermalSDK and identity info
44
+ dispatch_async(dispatch_get_main_queue(), ^{
45
+ RCTLogInfo(@"Flir connect called (placeholder)");
46
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{ @"identity": identity ?: @{} }];
47
+ resolve(@(YES));
48
+ });
49
+ }
50
+
51
+ RCT_EXPORT_METHOD(disconnect)
52
+ {
53
+ dispatch_async(dispatch_get_main_queue(), ^{
54
+ RCTLogInfo(@"Flir disconnect called (placeholder)");
55
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{}];
56
+ });
57
+ }
58
+
59
+ RCT_EXPORT_METHOD(getTemperatureAt:(nonnull NSNumber *)x y:(nonnull NSNumber *)y resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
60
+ // Return the last sampled temperature from the preview/state singleton
61
+ dispatch_async(dispatch_get_main_queue(), ^{
62
+ double t = [FlirState shared].lastTemperature;
63
+ if (isnan(t)) {
64
+ resolve([NSNull null]);
65
+ } else {
66
+ resolve(@(t));
67
+ }
68
+ });
69
+ }
70
+
71
+ RCT_EXPORT_METHOD(isEmulator:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
72
+ dispatch_async(dispatch_get_main_queue(), ^{
73
+ resolve(@(self.isEmulatorMode));
74
+ });
75
+ }
76
+
77
+ RCT_EXPORT_METHOD(isDeviceConnected:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
78
+ dispatch_async(dispatch_get_main_queue(), ^{
79
+ resolve(@(self.isPhysicalDeviceConnected));
80
+ });
81
+ }
82
+
83
+ RCT_EXPORT_METHOD(getConnectedDeviceInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
84
+ dispatch_async(dispatch_get_main_queue(), ^{
85
+ if (self.connectedIdentity == nil) {
86
+ resolve(@"Not connected");
87
+ } else if (self.isEmulatorMode) {
88
+ resolve([NSString stringWithFormat:@"Emulator (%@)", [self.connectedIdentity deviceId]]);
89
+ } else {
90
+ resolve([NSString stringWithFormat:@"Physical device (%@)", [self.connectedIdentity deviceId]]);
91
+ }
92
+ });
93
+ }
94
+
95
+ RCT_EXPORT_METHOD(startEmulatorMode:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
96
+ dispatch_async(dispatch_get_main_queue(), ^{
97
+ [self initializeEmulatorMode];
98
+ resolve(@(YES));
99
+ });
100
+ }
101
+
102
+ - (void)initializeEmulatorMode
103
+ {
104
+ if (!self.discovery) {
105
+ self.discovery = [[FLIRDiscovery alloc] init];
106
+ self.discovery.delegate = self;
107
+ }
108
+
109
+ // Create emulator identity for testing; use FLIRCameraType for compatibility
110
+ FLIRIdentity *emulatorIdentity = [[FLIRIdentity alloc] initWithEmulatorType:FLIRCameraType_flirOne];
111
+ if (emulatorIdentity) {
112
+ self.connectedIdentity = emulatorIdentity;
113
+ self.isEmulatorMode = YES;
114
+ self.isPhysicalDeviceConnected = NO;
115
+
116
+ // Start discovery for emulator
117
+ [self.discovery start:FLIRCommunicationInterfaceEmulator cameraType:FLIRCameraType_flirOne];
118
+
119
+ // Emit connection event
120
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{
121
+ @"identity": @{
122
+ @"deviceId": [emulatorIdentity deviceId] ?: @"Emulator",
123
+ @"isEmulator": @(YES)
124
+ },
125
+ @"deviceType": @"emulator",
126
+ @"isEmulator": @(YES)
127
+ }];
128
+ }
129
+ }
130
+
131
+ #pragma mark - FLIRDiscoveryEventDelegate
132
+
133
+ - (void)cameraDiscovered:(FLIRDiscoveredCamera *)discoveredCamera {
134
+ FLIRIdentity *identity = discoveredCamera.identity;
135
+
136
+ BOOL isRealDevice = ([identity communicationInterface] != FLIRCommunicationInterfaceEmulator);
137
+
138
+ if (isRealDevice && !self.isPhysicalDeviceConnected) {
139
+ self.connectedIdentity = identity;
140
+ self.isEmulatorMode = NO;
141
+ self.isPhysicalDeviceConnected = YES;
142
+ [self connectToDevice:identity];
143
+ } else if (!isRealDevice && !self.isPhysicalDeviceConnected) {
144
+ self.connectedIdentity = identity;
145
+ self.isEmulatorMode = YES;
146
+ self.isPhysicalDeviceConnected = NO;
147
+ [self connectToDevice:identity];
148
+ }
149
+ }
150
+
151
+ #pragma mark - Helper Methods
152
+
153
+ - (void)connectToDevice:(FLIRIdentity *)identity {
154
+ if (!self.camera) {
155
+ self.camera = [[FLIRCamera alloc] init];
156
+ }
157
+
158
+ NSError *error;
159
+ BOOL connected = [self.camera connect:identity error:&error];
160
+
161
+ if (connected) {
162
+ NSString *deviceType = self.isEmulatorMode ? @"emulator" : @"device";
163
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{
164
+ @"identity": @{
165
+ @"deviceId": [identity deviceId] ?: @"Unknown",
166
+ @"isEmulator": @(self.isEmulatorMode)
167
+ },
168
+ @"deviceType": deviceType,
169
+ @"isEmulator": @(self.isEmulatorMode)
170
+ }];
171
+ } else {
172
+ RCTLogError(@"Failed to connect to FLIR device: %@", error.localizedDescription);
173
+ }
174
+ }
175
+
176
+ #pragma mark - FLIRDiscoveryEventDelegate
177
+
178
+ - (void)cameraFound:(FLIRIdentity *)identity
179
+ {
180
+ self.connectedIdentity = identity;
181
+ self.isEmulatorMode = ([identity communicationInterface] == FLIRCommunicationInterfaceEmulator);
182
+ self.isPhysicalDeviceConnected = !self.isEmulatorMode;
183
+
184
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{
185
+ @"identity": @{
186
+ @"deviceId": [identity deviceId] ?: @"Unknown",
187
+ @"isEmulator": @(self.isEmulatorMode)
188
+ },
189
+ @"deviceType": self.isEmulatorMode ? @"emulator" : @"physical",
190
+ @"isEmulator": @(self.isEmulatorMode)
191
+ }];
192
+ }
193
+
194
+ - (void)cameraLost:(FLIRIdentity *)identity
195
+ {
196
+ self.connectedIdentity = nil;
197
+ self.isEmulatorMode = NO;
198
+ self.isPhysicalDeviceConnected = NO;
199
+
200
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{
201
+ @"identity": @{
202
+ @"deviceId": [identity deviceId] ?: @"Unknown",
203
+ @"isEmulator": @([identity communicationInterface] == FLIRCommunicationInterfaceEmulator)
204
+ },
205
+ @"wasEmulator": @([identity communicationInterface] == FLIRCommunicationInterfaceEmulator)
206
+ }];
207
+ }
208
+
209
+ - (void)discoveryError:(NSString *)error netServiceError:(int)nsnetserviceserror on:(FLIRCommunicationInterface)iface
210
+ {
211
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirError" body:@{
212
+ @"error": error ?: @"Unknown discovery error",
213
+ @"type": @"discovery",
214
+ @"interface": @(iface)
215
+ }];
216
+ }
217
+
218
+ @end
219
+ #import "FlirModule.h"
220
+ #import "FlirEventEmitter.h"
221
+ #import "FlirState.h"
222
+ #import <ThermalSDK/ThermalSDK.h>
223
+ #ifndef F1_gen3
224
+ #define F1_gen3 FLIRCameraType_flirOne
225
+ #endif
226
+ #import <React/RCTLog.h>
227
+
228
+
229
+ @interface FlirModule()
230
+ <FLIRDiscoveryEventDelegate>
231
+ @property (nonatomic, strong) FLIRDiscovery *discovery;
232
+ @property (nonatomic, strong) FLIRCamera *camera;
233
+ @property (nonatomic, strong) FLIRIdentity *connectedIdentity;
234
+ @property (nonatomic, assign) BOOL isEmulatorMode;
235
+ @property (nonatomic, assign) BOOL isPhysicalDeviceConnected;
236
+ @end
237
+
238
+ @implementation FlirModule
239
+
240
+ RCT_EXPORT_MODULE(FlirIOS);
241
+
242
+ RCT_EXPORT_METHOD(startDiscovery)
243
+ {
244
+ // Hook into ThermalSDK discovery when ready. For now, emit an event to JS.
245
+ dispatch_async(dispatch_get_main_queue(), ^{
246
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{ @"msg": @"discovery-started" }];
247
+ RCTLogInfo(@"FLIR discovery started (placeholder)");
248
+ });
249
+ }
250
+
251
+ RCT_EXPORT_METHOD(stopDiscovery)
252
+ {
253
+ dispatch_async(dispatch_get_main_queue(), ^{
254
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{ @"msg": @"discovery-stopped" }];
255
+ RCTLogInfo(@"FLIR discovery stopped (placeholder)");
256
+ });
257
+ }
258
+
259
+ RCT_EXPORT_METHOD(connect:(NSDictionary *)identity resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
260
+ {
261
+ // TODO: implement real connect using ThermalSDK and identity info
262
+ dispatch_async(dispatch_get_main_queue(), ^{
263
+ RCTLogInfo(@"Flir connect called (placeholder)");
264
+ // emit a connected event
265
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{ @"identity": identity ?: @{} }];
266
+ resolve(@(YES));
267
+ });
268
+ }
269
+
270
+ RCT_EXPORT_METHOD(disconnect)
271
+ {
272
+ dispatch_async(dispatch_get_main_queue(), ^{
273
+ RCTLogInfo(@"Flir disconnect called (placeholder)");
274
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{}];
275
+ });
276
+ }
277
+
278
+ RCT_EXPORT_METHOD(getTemperatureAt:(nonnull NSNumber *)x y:(nonnull NSNumber *)y resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\n{\n // Return the last sampled temperature from the preview/state singleton\n dispatch_async(dispatch_get_main_queue(), ^{\n double t = [FlirState shared].lastTemperature;\n if (isnan(t)) {\n resolve([NSNull null]);\n } else {\n resolve(@(t));\n }\n });\n}\n\nRCT_EXPORT_METHOD(isEmulator:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\n{\n dispatch_async(dispatch_get_main_queue(), ^{\n resolve(@(self.isEmulatorMode));\n });\n}\n\nRCT_EXPORT_METHOD(isDeviceConnected:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\n{\n dispatch_async(dispatch_get_main_queue(), ^{\n resolve(@(self.isPhysicalDeviceConnected));\n });\n}\n\nRCT_EXPORT_METHOD(getConnectedDeviceInfo:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\n{\n dispatch_async(dispatch_get_main_queue(), ^{\n if (self.connectedIdentity == nil) {\n resolve(@\"Not connected\");\n } else if (self.isEmulatorMode) {\n resolve([NSString stringWithFormat:@\"Emulator (%@)\", self.connectedIdentity.deviceId]);\n } else {\n resolve([NSString stringWithFormat:@\"Physical device (%@)\", self.connectedIdentity.deviceId]);\n }\n });\n}\n\nRCT_EXPORT_METHOD(startEmulatorMode:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\n{\n dispatch_async(dispatch_get_main_queue(), ^{\n [self initializeEmulatorMode];\n resolve(@(YES));\n });\n}\n\n- (void)initializeEmulatorMode\n{\n if (!self.discovery) {\n self.discovery = [[FLIRDiscovery alloc] init];\n self.discovery.delegate = self;\n }\n \n // Create emulator identity for testing\n FLIRIdentity *emulatorIdentity = [[FLIRIdentity alloc] initWithEmulatorType:F1_gen3];\n if (emulatorIdentity) {\n self.connectedIdentity = emulatorIdentity;\n self.isEmulatorMode = YES;\n self.isPhysicalDeviceConnected = NO;\n \n // Start discovery for emulator\n [self.discovery start:FLIRCommunicationInterfaceEmulator cameraType:F1_gen3];\n \n // Emit connection event\n [[FlirEventEmitter shared] sendDeviceEvent:@\"FlirDeviceConnected\" body:@{\n @\"identity\": @{\n @\"deviceId\": emulatorIdentity.deviceId ?: @\"Emulator\",\n @\"isEmulator\": @(YES)\n },\n @\"deviceType\": @\"emulator\",\n @\"isEmulator\": @(YES)\n }];\n }\n}
279
+
280
+ #pragma mark - FLIRDiscoveryEventDelegate
281
+
282
+ - (void)cameraDiscovered:(FLIRDiscoveredCamera *)discoveredCamera {
283
+ FLIRIdentity *identity = discoveredCamera.identity;
284
+
285
+ // Check if this is a real device or emulator
286
+ BOOL isRealDevice = (identity.communicationInterface != FLIRCommunicationInterfaceEmulator);
287
+
288
+ if (isRealDevice && !self.isPhysicalDeviceConnected) {
289
+ // Prioritize real device over emulator
290
+ self.connectedIdentity = identity;
291
+ self.isEmulatorMode = NO;
292
+ self.isPhysicalDeviceConnected = YES;
293
+
294
+ // Connect to real device
295
+ [self connectToDevice:identity];
296
+ } else if (!isRealDevice && !self.isPhysicalDeviceConnected) {
297
+ // Use emulator if no real device found
298
+ self.connectedIdentity = identity;
299
+ self.isEmulatorMode = YES;
300
+ self.isPhysicalDeviceConnected = NO;
301
+
302
+ // Connect to emulator
303
+ [self connectToDevice:identity];
304
+ }
305
+ }
306
+
307
+ #pragma mark - Helper Methods
308
+
309
+ - (void)connectToDevice:(FLIRIdentity *)identity {
310
+ if (!self.camera) {
311
+ self.camera = [[FLIRCamera alloc] init];
312
+ }
313
+
314
+ NSError *error;
315
+ BOOL connected = [self.camera connect:identity error:&error];
316
+
317
+ if (connected) {
318
+ NSString *deviceType = self.isEmulatorMode ? @"emulator" : @"device";
319
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{
320
+ @"identity": @{
321
+ @"deviceId": identity.deviceId ?: @"Unknown",
322
+ @"isEmulator": @(self.isEmulatorMode)
323
+ },
324
+ @"deviceType": deviceType,
325
+ @"isEmulator": @(self.isEmulatorMode)
326
+ }];
327
+ } else {
328
+ RCTLogError(@"Failed to connect to FLIR device: %@", error.localizedDescription);
329
+ }
330
+ }
331
+
332
+ #pragma mark - FLIRDiscoveryEventDelegate
333
+
334
+ - (void)cameraFound:(FLIRIdentity *)identity
335
+ {
336
+ // Store the found camera identity
337
+ self.connectedIdentity = identity;
338
+
339
+ // Check if this is an emulator
340
+ self.isEmulatorMode = (identity.communicationInterface == FLIRCommunicationInterfaceEmulator);
341
+ self.isPhysicalDeviceConnected = !self.isEmulatorMode;
342
+
343
+ // Emit connection event
344
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceConnected" body:@{
345
+ @"identity": @{
346
+ @"deviceId": identity.deviceId ?: @"Unknown",
347
+ @"isEmulator": @(self.isEmulatorMode)
348
+ },
349
+ @"deviceType": self.isEmulatorMode ? @"emulator" : @"physical",
350
+ @"isEmulator": @(self.isEmulatorMode)
351
+ }];
352
+ }
353
+
354
+ - (void)cameraLost:(FLIRIdentity *)identity
355
+ {
356
+ // Clear connection state
357
+ self.connectedIdentity = nil;
358
+ self.isEmulatorMode = NO;
359
+ self.isPhysicalDeviceConnected = NO;
360
+
361
+ // Emit disconnection event
362
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirDeviceDisconnected" body:@{
363
+ @"identity": @{
364
+ @"deviceId": identity.deviceId ?: @"Unknown",
365
+ @"isEmulator": @(identity.communicationInterface == FLIRCommunicationInterfaceEmulator)
366
+ },
367
+ @"wasEmulator": @(identity.communicationInterface == FLIRCommunicationInterfaceEmulator)
368
+ }];
369
+ }
370
+
371
+ - (void)discoveryError:(NSString *)error netServiceError:(int)nsnetserviceserror on:(FLIRCommunicationInterface)iface
372
+ {
373
+ // Emit error event
374
+ [[FlirEventEmitter shared] sendDeviceEvent:@"FlirError" body:@{
375
+ @"error": error ?: @"Unknown discovery error",
376
+ @"type": @"discovery",
377
+ @"interface": @(iface)
378
+ }];
379
+ }
380
+
381
+ @end