ilabs-flir 1.0.0
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/Flir.podspec +31 -0
- package/README.md +1271 -0
- package/android/Flir/build.gradle.kts +80 -0
- package/android/Flir/libs/flir-stubs.jar +0 -0
- package/android/Flir/src/main/AndroidManifest.xml +31 -0
- package/android/Flir/src/main/java/flir/android/CameraHandler.java +194 -0
- package/android/Flir/src/main/java/flir/android/FlirController.kt +11 -0
- package/android/Flir/src/main/java/flir/android/FlirDownloadManager.kt +75 -0
- package/android/Flir/src/main/java/flir/android/FlirDownloadPackage.kt +16 -0
- package/android/Flir/src/main/java/flir/android/FlirFrameCache.kt +6 -0
- package/android/Flir/src/main/java/flir/android/FlirManager.kt +248 -0
- package/android/Flir/src/main/java/flir/android/FlirModule.kt +74 -0
- package/android/Flir/src/main/java/flir/android/FlirPackage.kt +16 -0
- package/android/Flir/src/main/java/flir/android/FlirSDKLoader.kt +191 -0
- package/android/Flir/src/main/java/flir/android/FlirStatus.kt +12 -0
- package/android/Flir/src/main/java/flir/android/FlirView.kt +48 -0
- package/android/Flir/src/main/java/flir/android/FlirViewManager.kt +13 -0
- package/android/Flir/src/main/java/flir/android/FrameDataHolder.java +14 -0
- package/app.plugin.js +264 -0
- package/expo-module.config.json +6 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRBattery.h +76 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRCalibration.h +108 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRCamera.h +156 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRCameraDeviceInfo.h +53 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRCameraEvent.h +132 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRCameraImport.h +204 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRColorDistributionSettings.h +204 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRColorizer.h +82 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRDiscoveredCamera.h +44 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRDiscovery.h +132 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRDisplaySettings.h +29 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRFocus.h +70 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRFusion.h +192 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRFusionController.h +136 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRFusionTransformation.h +35 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRIdentity.h +264 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRImageBase.h +196 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRImageColorizer.h +26 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRImageStatistics.h +61 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRIsotherms.h +208 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementArea.h +38 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementCollection.h +147 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementDelta.h +62 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementDimensions.h +33 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementEllipse.h +49 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementLine.h +66 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementMarker.h +69 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementParameters.h +41 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementRectangle.h +36 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementReference.h +27 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementShape.h +46 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementSpot.h +33 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementsController.h +160 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRMeterLinkSensorPoll.h +247 -0
- package/ios/Flir/Framework/ThermalSDK/FLIROverlayController.h +27 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRPalette.h +60 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRPaletteController.h +36 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRPaletteManager.h +97 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRQuantification.h +55 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRRemoteControl.h +393 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRRenderer.h +35 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRRendererImpl.h +17 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRScale.h +99 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRScaleController.h +44 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRStream.h +109 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRStreamer.h +124 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRSystem.h +40 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRTemperatureRange.h +43 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRThermalDelta.h +77 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRThermalImage.h +331 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRThermalImageFile.h +56 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRThermalParameters.h +31 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRThermalValue.h +92 -0
- package/ios/Flir/Framework/ThermalSDK/FLIRWirelessCameraDetails.h +88 -0
- package/ios/Flir/Framework/ThermalSDK/ThermalSDK.h +73 -0
- package/ios/Flir/SDKLoader/FlirSDKLoader.m +13 -0
- package/ios/Flir/SDKLoader/FlirSDKLoader.swift +175 -0
- package/ios/Flir/src/FlirEventEmitter.h +12 -0
- package/ios/Flir/src/FlirEventEmitter.m +33 -0
- package/ios/Flir/src/FlirModule.h +10 -0
- package/ios/Flir/src/FlirModule.m +381 -0
- package/ios/Flir/src/FlirPreviewView.h +13 -0
- package/ios/Flir/src/FlirPreviewView.m +24 -0
- package/ios/Flir/src/FlirState.h +20 -0
- package/ios/Flir/src/FlirState.m +79 -0
- package/ios/Flir/src/FlirViewManager.h +9 -0
- package/ios/Flir/src/FlirViewManager.m +16 -0
- package/package.json +61 -0
- package/react-native.config.js +14 -0
- package/scripts/copy_ios_libs.sh +32 -0
- package/scripts/download-sdk.js +62 -0
- package/scripts/prepare-binaries.sh +171 -0
- package/sdk-manifest.json +30 -0
- package/src/FlirDownload.ts +78 -0
- package/src/index.d.ts +17 -0
- package/src/index.js +7 -0
- package/src/index.ts +7 -0
|
@@ -0,0 +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
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
|
|
3
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
4
|
+
|
|
5
|
+
@interface FlirPreviewView : UIView
|
|
6
|
+
|
|
7
|
+
@property (nonatomic, assign) double lastTemperature;
|
|
8
|
+
|
|
9
|
+
- (void)updateWithFrameImage:(UIImage *)image temperature:(double)temperature;
|
|
10
|
+
|
|
11
|
+
@end
|
|
12
|
+
|
|
13
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#import "FlirPreviewView.h"
|
|
2
|
+
#import "FlirState.h"
|
|
3
|
+
|
|
4
|
+
@implementation FlirPreviewView
|
|
5
|
+
|
|
6
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
7
|
+
{
|
|
8
|
+
if (self = [super initWithFrame:frame]) {
|
|
9
|
+
self.backgroundColor = [UIColor blackColor];
|
|
10
|
+
_lastTemperature = NAN;
|
|
11
|
+
}
|
|
12
|
+
return self;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
- (void)updateWithFrameImage:(UIImage *)image temperature:(double)temperature
|
|
16
|
+
{
|
|
17
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
18
|
+
self.layer.contents = (id)image.CGImage;
|
|
19
|
+
self.lastTemperature = temperature;
|
|
20
|
+
[FlirState shared].lastTemperature = temperature;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
4
|
+
|
|
5
|
+
@interface FlirState : NSObject
|
|
6
|
+
|
|
7
|
+
@property (nonatomic, assign) double lastTemperature;
|
|
8
|
+
@property (nonatomic, copy, nullable) void (^onTemperatureUpdate)(double temperature, int x, int y);
|
|
9
|
+
@property (nonatomic, copy, nullable) void (^onTextureUpdate)(UIImage *_Nonnull image, int textureUnit);
|
|
10
|
+
@property (nonatomic, strong, nullable) UIImage *latestImage;
|
|
11
|
+
|
|
12
|
+
+ (instancetype)shared;
|
|
13
|
+
- (double)getTemperatureAt:(int)x y:(int)y;
|
|
14
|
+
- (void)updateFrame:(UIImage *_Nonnull)image;
|
|
15
|
+
- (void)updateFrame:(UIImage *_Nonnull)image withTemperatureData:(NSArray<NSNumber *> *_Nullable)tempData;
|
|
16
|
+
- (double)queryTemperatureAtPoint:(int)x y:(int)y;
|
|
17
|
+
|
|
18
|
+
@end
|
|
19
|
+
|
|
20
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#import "FlirState.h"
|
|
2
|
+
|
|
3
|
+
static FlirState *_sharedState = nil;
|
|
4
|
+
|
|
5
|
+
@implementation FlirState {
|
|
6
|
+
NSArray<NSNumber *> *_temperatureData; // Flattened array of temperature values
|
|
7
|
+
int _imageWidth;
|
|
8
|
+
int _imageHeight;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
+ (instancetype)shared
|
|
12
|
+
{
|
|
13
|
+
static dispatch_once_t onceToken;
|
|
14
|
+
dispatch_once(&onceToken, ^{
|
|
15
|
+
_sharedState = [FlirState new];
|
|
16
|
+
_sharedState.lastTemperature = NAN;
|
|
17
|
+
_sharedState.latestImage = nil;
|
|
18
|
+
_sharedState->_temperatureData = nil;
|
|
19
|
+
_sharedState->_imageWidth = 0;
|
|
20
|
+
_sharedState->_imageHeight = 0;
|
|
21
|
+
});
|
|
22
|
+
return _sharedState;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
- (double)getTemperatureAt:(int)x y:(int)y
|
|
26
|
+
{
|
|
27
|
+
// Return cached temperature (will be updated by thermal SDK callbacks)
|
|
28
|
+
// In production, this would query the actual thermal image data at (x,y)
|
|
29
|
+
return self.lastTemperature;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
- (void)updateFrame:(UIImage *)image
|
|
33
|
+
{
|
|
34
|
+
[self updateFrame:image withTemperatureData:nil];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
- (void)updateFrame:(UIImage *)image withTemperatureData:(NSArray<NSNumber *> *)tempData
|
|
38
|
+
{
|
|
39
|
+
self.latestImage = image;
|
|
40
|
+
|
|
41
|
+
if (tempData != nil) {
|
|
42
|
+
_temperatureData = tempData;
|
|
43
|
+
_imageWidth = (int)image.size.width;
|
|
44
|
+
_imageHeight = (int)image.size.height;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Invoke texture callback for native Metal filters (texture unit 7)
|
|
48
|
+
if (self.onTextureUpdate) {
|
|
49
|
+
self.onTextureUpdate(image, 7);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Sample temperature at center point and invoke callback
|
|
53
|
+
if (self.onTemperatureUpdate) {
|
|
54
|
+
double temp = [self getTemperatureAt:80 y:60];
|
|
55
|
+
self.onTemperatureUpdate(temp, 80, 60);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (double)queryTemperatureAtPoint:(int)x y:(int)y
|
|
60
|
+
{
|
|
61
|
+
if (_temperatureData == nil || _imageWidth == 0 || _imageHeight == 0) {
|
|
62
|
+
return NAN;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Bounds check
|
|
66
|
+
if (x < 0 || x >= _imageWidth || y < 0 || y >= _imageHeight) {
|
|
67
|
+
return NAN;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Access flattened array: index = y * width + x
|
|
71
|
+
NSInteger index = y * _imageWidth + x;
|
|
72
|
+
if (index < 0 || index >= (NSInteger)[_temperatureData count]) {
|
|
73
|
+
return NAN;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return [_temperatureData[index] doubleValue];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#import "FlirViewManager.h"
|
|
2
|
+
#import "FlirPreviewView.h"
|
|
3
|
+
#import <React/RCTBridge.h>
|
|
4
|
+
#import <React/RCTUIManager.h>
|
|
5
|
+
|
|
6
|
+
@implementation FlirViewManager
|
|
7
|
+
|
|
8
|
+
RCT_EXPORT_MODULE(FlirView)
|
|
9
|
+
|
|
10
|
+
- (UIView *)view
|
|
11
|
+
{
|
|
12
|
+
FlirPreviewView *v = [[FlirPreviewView alloc] initWithFrame:CGRectZero];
|
|
13
|
+
return v;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@end
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ilabs-flir",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "FLIR Thermal SDK for React Native - On-Demand Download",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"download-sdk": "node scripts/download-sdk.js",
|
|
9
|
+
"typecheck": "tsc --noEmit"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"src/",
|
|
13
|
+
"android/Flir/src/",
|
|
14
|
+
"android/Flir/build.gradle.kts",
|
|
15
|
+
"android/Flir/libs/",
|
|
16
|
+
"ios/Flir/src/",
|
|
17
|
+
"ios/Flir/SDKLoader/",
|
|
18
|
+
"ios/Flir/libs/.gitkeep",
|
|
19
|
+
"ios/Flir/Framework/",
|
|
20
|
+
"app.plugin.js",
|
|
21
|
+
"Flir.podspec",
|
|
22
|
+
"sdk-manifest.json",
|
|
23
|
+
"scripts/",
|
|
24
|
+
"expo-module.config.json",
|
|
25
|
+
"react-native.config.js"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"flir",
|
|
29
|
+
"thermal",
|
|
30
|
+
"thermal-camera",
|
|
31
|
+
"react-native",
|
|
32
|
+
"expo",
|
|
33
|
+
"expo-plugin",
|
|
34
|
+
"config-plugin",
|
|
35
|
+
"flir-one",
|
|
36
|
+
"thermal-imaging",
|
|
37
|
+
"infrared"
|
|
38
|
+
],
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/PraveenOjha/flir.git"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/PraveenOjha/flir#readme",
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/PraveenOjha/flir/issues"
|
|
46
|
+
},
|
|
47
|
+
"author": "Praveen Ojha",
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"react": "*",
|
|
51
|
+
"react-native": ">=0.60.0"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@expo/config-plugins": "^7.0.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"typescript": "^5.0.0",
|
|
58
|
+
"@types/react": "*",
|
|
59
|
+
"@types/react-native": "*"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
dependency: {
|
|
3
|
+
platforms: {
|
|
4
|
+
android: {
|
|
5
|
+
sourceDir: './android/Flir',
|
|
6
|
+
packageImportPath: 'import flir.android.FlirPackage;',
|
|
7
|
+
packageInstance: 'new FlirPackage()',
|
|
8
|
+
},
|
|
9
|
+
ios: {
|
|
10
|
+
podspecPath: './Flir.podspec',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Script to copy necessary iOS frameworks into ios/Flir/libs
|
|
5
|
+
# by default ThermalSDK.framework is located under ios/Flir/
|
|
6
|
+
|
|
7
|
+
DEST_DIR="$(pwd)/ios/Flir/libs"
|
|
8
|
+
mkdir -p "$DEST_DIR"
|
|
9
|
+
|
|
10
|
+
# copy ThermalSDK.framework if it exists
|
|
11
|
+
SRC_THERMAL="$PWD/ios/Flir/ThermalSDK.framework"
|
|
12
|
+
if [ -d "$SRC_THERMAL" ]; then
|
|
13
|
+
echo "Copying ThermalSDK.framework -> $DEST_DIR"
|
|
14
|
+
rm -rf "$DEST_DIR/ThermalSDK.framework"
|
|
15
|
+
cp -R "$SRC_THERMAL" "$DEST_DIR/"
|
|
16
|
+
else
|
|
17
|
+
echo "Warning: $SRC_THERMAL not found. Please add ThermalSDK.framework to ios/Flir/libs manually or place it at ios/Flir/"
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Optionally copy FFmpeg-ish frameworks if present in project root (paths in sample PBX):
|
|
21
|
+
for lib in libswscale.5.dylib.framework libavfilter.7.dylib.framework liblive666.dylib.framework libavdevice.58.dylib.framework libavcodec.58.dylib.framework libavformat.58.dylib.framework libswresample.3.dylib.framework libavutil.56.dylib.framework; do
|
|
22
|
+
SRC_LIB="$PWD/../$lib"
|
|
23
|
+
if [ -d "$SRC_LIB" ]; then
|
|
24
|
+
echo "Copying $lib -> $DEST_DIR"
|
|
25
|
+
rm -rf "$DEST_DIR/$lib"
|
|
26
|
+
cp -R "$SRC_LIB" "$DEST_DIR/"
|
|
27
|
+
else
|
|
28
|
+
echo "Note: $lib not found at $SRC_LIB. Add it to ios/Flir/libs if required."
|
|
29
|
+
fi
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
echo "Done copying frameworks. The podspec references `ios/Flir/libs` — run 'pod install' from ios after adding frameworks."
|