react-native-mytatva-rn-sdk 1.2.53 → 1.2.55
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/android/src/main/java/com/mytatvarnsdk/CgmTrackyLibModule.kt +10 -11
- package/ios/Database/GlucoseData+CoreDataProperties.h +11 -1
- package/ios/Database/GlucoseData+CoreDataProperties.m +11 -1
- package/ios/Database/KLTBluetoothManager.m +3 -2
- package/ios/Database/KLTDatabaseHandler.m +27 -5
- package/ios/Database/MyTatva.xcdatamodeld/MyTatva.xcdatamodel/contents +12 -1
- package/ios/Support/API.swift +13 -6
- package/ios/Support/Converter/DataConverter.swift +37 -22
- package/ios/ViewControllers/AttachTransmitterViewController.swift +3 -1
- package/ios/ViewControllers/ConnectToSensorViewController.swift +1 -0
- package/ios/ViewModel/FinalViewModel.swift +75 -19
- package/package.json +1 -1
|
@@ -63,7 +63,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
63
63
|
var authenticateSDKService: AuthenticateSDKService
|
|
64
64
|
private val job = Job()
|
|
65
65
|
private val scope = CoroutineScope(Dispatchers.IO + job)
|
|
66
|
-
var prefsHelper: SharedPreferencesLibraryUtil
|
|
66
|
+
var prefsHelper: SharedPreferencesLibraryUtil? = null
|
|
67
67
|
private val apiScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
|
68
68
|
private var debounceJob: Job? = null
|
|
69
69
|
private var isBatchProcessing = false
|
|
@@ -184,18 +184,17 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
)*/
|
|
187
|
-
|
|
188
187
|
val response = Gson().fromJson(apiResponse, CgmSensorResponse::class.java)
|
|
189
188
|
val sensor = response.data?.firstOrNull()
|
|
190
189
|
|
|
190
|
+
|
|
191
191
|
if (sensor != null && !sensor.startDate.isNullOrEmpty() && !sensor.endDate.isNullOrEmpty()) {
|
|
192
192
|
val startDate = sensor.startDate
|
|
193
193
|
val endDate = sensor.endDate
|
|
194
194
|
val sensorId = sensor.sensorId
|
|
195
195
|
val currentPatientId = patientId
|
|
196
|
-
|
|
197
|
-
val
|
|
198
|
-
val lastSensorId = prefsHelper.qrInformation.sensor
|
|
196
|
+
val lastPatientId = prefsHelper?.lastPatientId
|
|
197
|
+
val lastSensorId = prefsHelper?.qrInformation?.sensor
|
|
199
198
|
|
|
200
199
|
if (lastPatientId != null && lastSensorId != null && (lastPatientId != currentPatientId || lastSensorId != sensorId)) {
|
|
201
200
|
mModel.clearAllGlucoseAndDeviceData()
|
|
@@ -216,8 +215,8 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
216
215
|
pocDevice.qrMessage, envType
|
|
217
216
|
)
|
|
218
217
|
} else {
|
|
219
|
-
prefsHelper
|
|
220
|
-
prefsHelper
|
|
218
|
+
prefsHelper?.lastPatientId = currentPatientId
|
|
219
|
+
prefsHelper?.qrInformation?.sensor = sensorId
|
|
221
220
|
}
|
|
222
221
|
} else {
|
|
223
222
|
postEventDataToAPI(
|
|
@@ -425,7 +424,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
425
424
|
val currentTime = System.currentTimeMillis()
|
|
426
425
|
var dataAge = System.currentTimeMillis()
|
|
427
426
|
|
|
428
|
-
val lastSyncData = prefsHelper
|
|
427
|
+
val lastSyncData = prefsHelper?.lastSyncData
|
|
429
428
|
val currentSyncTimeInMillis = lastSyncData?.timeInMillis
|
|
430
429
|
|
|
431
430
|
if (lastSyncData != null) {
|
|
@@ -606,7 +605,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
606
605
|
|
|
607
606
|
Handler(Looper.getMainLooper()).postDelayed({
|
|
608
607
|
try {
|
|
609
|
-
val lastSyncData = prefsHelper
|
|
608
|
+
val lastSyncData = prefsHelper?.lastSyncData
|
|
610
609
|
Log.d("lastSyncData: ", Gson().toJson(lastSyncData).toString())
|
|
611
610
|
|
|
612
611
|
val currentTime = System.currentTimeMillis()
|
|
@@ -720,7 +719,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
720
719
|
lastDeviceStatus = null
|
|
721
720
|
|
|
722
721
|
// Clear any cached data if needed
|
|
723
|
-
prefsHelper
|
|
722
|
+
prefsHelper?.clearQRInformation() // if you have such method
|
|
724
723
|
|
|
725
724
|
// Reset last processed sync time
|
|
726
725
|
lastProcessedSyncTimeInMillis = null
|
|
@@ -915,7 +914,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
915
914
|
it.deviceId,
|
|
916
915
|
it.glucoseId
|
|
917
916
|
)
|
|
918
|
-
prefsHelper
|
|
917
|
+
prefsHelper?.lastSyncData = syncData
|
|
919
918
|
lastProcessedSyncTimeInMillis = null
|
|
920
919
|
Log.d(
|
|
921
920
|
"Sync Metadata",
|
|
@@ -31,7 +31,17 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
31
31
|
@property (nullable, nonatomic, copy) NSNumber *trend;
|
|
32
32
|
@property (nullable, nonatomic, copy) NSNumber *userBG;
|
|
33
33
|
@property (nullable, nonatomic, retain) Device *device;
|
|
34
|
-
|
|
34
|
+
@property (nullable, nonatomic, copy) NSNumber *glucoseId;
|
|
35
|
+
@property (nullable, nonatomic, copy) NSNumber *isDelete;
|
|
36
|
+
@property (nullable, nonatomic, copy) NSNumber *year;
|
|
37
|
+
@property (nullable, nonatomic, copy) NSNumber *countdownDays;
|
|
38
|
+
@property (nullable, nonatomic, copy) NSNumber *countdownHours;
|
|
39
|
+
@property (nullable, nonatomic, copy) NSNumber *countdownMinutes;
|
|
40
|
+
@property (nullable, nonatomic, copy) NSNumber *minute;
|
|
41
|
+
@property (nullable, nonatomic, copy) NSNumber *month;
|
|
42
|
+
@property (nullable, nonatomic, copy) NSNumber *day;
|
|
43
|
+
@property (nullable, nonatomic, copy) NSNumber *hour;
|
|
44
|
+
@property (nullable, nonatomic, copy) NSNumber *error;
|
|
35
45
|
@end
|
|
36
46
|
|
|
37
47
|
NS_ASSUME_NONNULL_END
|
|
@@ -24,11 +24,21 @@
|
|
|
24
24
|
@dynamic initialBeginDate;
|
|
25
25
|
@dynamic iw;
|
|
26
26
|
@dynamic k;
|
|
27
|
+
@dynamic error;
|
|
27
28
|
@dynamic operatingCurrent;
|
|
28
29
|
@dynamic receiveDateTime;
|
|
29
30
|
@dynamic temperature;
|
|
30
31
|
@dynamic trend;
|
|
31
32
|
@dynamic userBG;
|
|
32
33
|
@dynamic device;
|
|
33
|
-
|
|
34
|
+
@dynamic year;
|
|
35
|
+
@dynamic countdownDays;
|
|
36
|
+
@dynamic countdownHours;
|
|
37
|
+
@dynamic countdownMinutes;
|
|
38
|
+
@dynamic isDelete;
|
|
39
|
+
@dynamic glucoseId;
|
|
40
|
+
@dynamic minute;
|
|
41
|
+
@dynamic month;
|
|
42
|
+
@dynamic day;
|
|
43
|
+
@dynamic hour;
|
|
34
44
|
@end
|
|
@@ -383,6 +383,7 @@
|
|
|
383
383
|
#pragma mark - 发射器通用接受数据处理、算法计算处理
|
|
384
384
|
|
|
385
385
|
// 发射器处理单条血糖数据的算法调用保存
|
|
386
|
+
//Is the algorithm used by the transmitter to process a single glucose data point also responsible for saving it?
|
|
386
387
|
- (void)handleCommonCT3GlucoseDataWithReceiveData:(ReceiveData *)receiveData {
|
|
387
388
|
int glucoseId = receiveData.glucoseId.intValue;
|
|
388
389
|
if (glucoseId >= self.eDevice.initNumber - 1) {
|
|
@@ -508,6 +509,7 @@
|
|
|
508
509
|
}
|
|
509
510
|
|
|
510
511
|
// CT3 CT4重传的数据,pullGlucose_series_request 22的返回
|
|
512
|
+
//Retransmitted data from CT3 and CT4, response of pullGlucose_series_request 0x22
|
|
511
513
|
- (void)handleResendDataWithPrefix22:(NSData *)resendData {
|
|
512
514
|
NSArray<Glucose *> *glucoseList = [ProtocalTools getGlucose_series:resendData andEDevice:self.eDevice];
|
|
513
515
|
if (glucoseList.count == 0) {
|
|
@@ -524,8 +526,7 @@
|
|
|
524
526
|
self.isFromPrefix22 = YES;
|
|
525
527
|
[self handleCommonCT3GlucoseDataWithReceiveData:receive];
|
|
526
528
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
+
|
|
529
530
|
[Notification_Center postNotificationName:KLTUpdateDataNotify object:NULL];
|
|
530
531
|
NSLog(@"----------------------------------------------called handleResendDataWithPrefix22 for KLTUpdateDataNotify");
|
|
531
532
|
NSInteger maxGlucoseId = [KLTDatabaseHandler.shared getLatestAndMaxGlucoseIdOfDevice:self.currentDevice];
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
data.countdownHours = @(currentGlucose.countdownHours);
|
|
64
64
|
data.countdownMinutes = @(currentGlucose.countdownMinutes);
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
// [Notification_Center postNotificationName:@"ErrorStatusFromTransmitter" object:data];
|
|
67
67
|
[self.appDelegate saveContext];
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -123,6 +123,8 @@
|
|
|
123
123
|
GlucoseData *glucose = [NSEntityDescription insertNewObjectForEntityForName:@"GlucoseData" inManagedObjectContext:self.context];
|
|
124
124
|
glucose.userBG = data.userBG;
|
|
125
125
|
glucose.dataId = data.glucoseId;
|
|
126
|
+
glucose.device = data.device;
|
|
127
|
+
glucose.isDelete = 0;
|
|
126
128
|
|
|
127
129
|
glucose.receiveDateTime = [NSString stringWithFormat:@"%@-%02d-%02d %02d:%02d",data.year,[data.month intValue],[data.day intValue],[data.hour intValue],[data.minute intValue]];
|
|
128
130
|
glucose.initialBeginDate = data.device.initialBeginDate;
|
|
@@ -177,7 +179,20 @@
|
|
|
177
179
|
data.countdownHours = @(currentGlucose.countdownHours);
|
|
178
180
|
data.countdownMinutes = @(currentGlucose.countdownMinutes);
|
|
179
181
|
|
|
180
|
-
|
|
182
|
+
glucose.countdownDays = @(currentGlucose.countdownDays);
|
|
183
|
+
glucose.countdownHours = @(currentGlucose.countdownHours);
|
|
184
|
+
glucose.countdownMinutes = @(currentGlucose.countdownMinutes);
|
|
185
|
+
glucose.year = data.year;
|
|
186
|
+
glucose.glucoseId = data.glucoseId;
|
|
187
|
+
glucose.month = data.month;
|
|
188
|
+
glucose.day = data.day;
|
|
189
|
+
glucose.minute = data.minute;
|
|
190
|
+
glucose.hour = data.hour;
|
|
191
|
+
glucose.error = data.error;
|
|
192
|
+
|
|
193
|
+
// [Notification_Center postNotificationName:@"ErrorStatusFromTransmitter" object: glucose];
|
|
194
|
+
[Notification_Center postNotificationName:@"CheckErrorStatusFromLastBatchData" object: glucose];
|
|
195
|
+
|
|
181
196
|
[self.appDelegate saveContext];
|
|
182
197
|
return glucose;
|
|
183
198
|
}
|
|
@@ -216,7 +231,7 @@
|
|
|
216
231
|
// 🖨️ Add single-line logging for each GlucoseData entry
|
|
217
232
|
NSLog(@"==== GlucoseData (Fetched %lu records) for Device: %@ ====", (unsigned long)resendDatas.count, currentDevice.identifier);
|
|
218
233
|
for (GlucoseData *g in resendDatas) {
|
|
219
|
-
NSLog(@"[ID:%@] Date:%@ | glu:%@ mmol/L | gluADC:%@ mg/dL | BG:%@ | T:%@°C | Ib:%@ | Iw:%@ | Trend:%@ | Err:%@ | CalStatus:%@",
|
|
234
|
+
NSLog(@"[ID:%@] Date:%@ | glu:%@ mmol/L | gluADC:%@ mg/dL | BG:%@ | T:%@°C | Ib:%@ | Iw:%@ | Trend:%@ | Err:%@ | CalStatus:%@ | countdownMinut:%@ | countdownHours:%@ | countdownDays:%@" ,
|
|
220
235
|
g.dataId,
|
|
221
236
|
g.receiveDateTime,
|
|
222
237
|
g.glu,
|
|
@@ -227,7 +242,11 @@
|
|
|
227
242
|
g.operatingCurrent,
|
|
228
243
|
g.trend,
|
|
229
244
|
g.errorCode,
|
|
230
|
-
g.calibrationStatus
|
|
245
|
+
g.calibrationStatus,
|
|
246
|
+
g.countdownMinutes,
|
|
247
|
+
g.countdownHours,
|
|
248
|
+
g.countdownDays
|
|
249
|
+
|
|
231
250
|
);
|
|
232
251
|
}
|
|
233
252
|
|
|
@@ -396,6 +415,7 @@
|
|
|
396
415
|
}
|
|
397
416
|
|
|
398
417
|
// 查询最近一次连接的最大的血糖ID
|
|
418
|
+
//Query the highest glucose ID from the most recent connection.
|
|
399
419
|
- (NSInteger)getLatestAndMaxGlucoseIdOfDevice:(Device *)currentDevice {
|
|
400
420
|
NSArray *array = [self queryReceiveDataWithDevice:currentDevice needUserBG:NO];
|
|
401
421
|
if (array.count > 0) {
|
|
@@ -406,6 +426,7 @@
|
|
|
406
426
|
}
|
|
407
427
|
|
|
408
428
|
// 获取距离某个设备的到期时间还剩多少数据没有接收完
|
|
429
|
+
//Get how much data remains to be received before the device reaches its expiration time
|
|
409
430
|
- (NSInteger)numberOfLifeCycleSensorWithDevice:(Device *)currentDevice endNumber:(int)endNumber {
|
|
410
431
|
if (currentDevice) {
|
|
411
432
|
NSArray *array = [self queryReceiveDataWithDevice:currentDevice needUserBG:NO];
|
|
@@ -415,7 +436,7 @@
|
|
|
415
436
|
}
|
|
416
437
|
|
|
417
438
|
#pragma mark - APP重启后需要手动调用历史数据
|
|
418
|
-
|
|
439
|
+
//After restarting the app, is it necessary to manually request historical data?
|
|
419
440
|
- (void)reloadQueryHistoryData {
|
|
420
441
|
Device *currentDevice = KLTBluetoothManager.sharedManager.currentDevice;
|
|
421
442
|
if (nil == currentDevice) {
|
|
@@ -459,6 +480,7 @@
|
|
|
459
480
|
data.TsCount = (int)index + 1;
|
|
460
481
|
|
|
461
482
|
// 校准后的点
|
|
483
|
+
//Point after calibration
|
|
462
484
|
NSArray<ReceiveData*> *needUserBgs = [self queryReceiveDataWithDevice:currentDevice needUserBG:YES];
|
|
463
485
|
NSUInteger numberOfUserBgs = needUserBgs.count;
|
|
464
486
|
if (needUserBgs.count > 0) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
2
|
-
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="
|
|
2
|
+
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="23788.4" systemVersion="24F74" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithSwiftData="YES" userDefinedModelVersionIdentifier="">
|
|
3
3
|
<entity name="Advertise" representedClassName="Advertise" syncable="YES">
|
|
4
4
|
<attribute name="advertiseDateTime" optional="YES" attributeType="String"/>
|
|
5
5
|
<attribute name="isConnectable" optional="YES" attributeType="Boolean" usesScalarValueType="NO"/>
|
|
@@ -24,18 +24,29 @@
|
|
|
24
24
|
<entity name="GlucoseData" representedClassName="GlucoseData" syncable="YES">
|
|
25
25
|
<attribute name="blankCurrent" optional="YES" attributeType="Double" defaultValueString="0" usesScalarValueType="NO"/>
|
|
26
26
|
<attribute name="calibrationStatus" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO"/>
|
|
27
|
+
<attribute name="countdownDays" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
|
28
|
+
<attribute name="countdownHours" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
|
29
|
+
<attribute name="countdownMinutes" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
|
27
30
|
<attribute name="dataId" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO"/>
|
|
31
|
+
<attribute name="day" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
|
32
|
+
<attribute name="error" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
|
28
33
|
<attribute name="errorCode" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO"/>
|
|
29
34
|
<attribute name="glu" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO"/>
|
|
30
35
|
<attribute name="gluADC" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO"/>
|
|
36
|
+
<attribute name="glucoseId" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
|
37
|
+
<attribute name="hour" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
|
31
38
|
<attribute name="initialBeginDate" optional="YES" attributeType="String"/>
|
|
39
|
+
<attribute name="isDelete" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
|
32
40
|
<attribute name="iw" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO"/>
|
|
33
41
|
<attribute name="k" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO"/>
|
|
42
|
+
<attribute name="minute" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
|
43
|
+
<attribute name="month" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
|
34
44
|
<attribute name="operatingCurrent" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO"/>
|
|
35
45
|
<attribute name="receiveDateTime" optional="YES" attributeType="String"/>
|
|
36
46
|
<attribute name="temperature" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO"/>
|
|
37
47
|
<attribute name="trend" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO"/>
|
|
38
48
|
<attribute name="userBG" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="NO"/>
|
|
49
|
+
<attribute name="year" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
|
39
50
|
<relationship name="device" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Device"/>
|
|
40
51
|
</entity>
|
|
41
52
|
<entity name="ReceiveDataInfo" representedClassName="ReceiveData" syncable="YES">
|
package/ios/Support/API.swift
CHANGED
|
@@ -10,6 +10,7 @@ import CommonCrypto
|
|
|
10
10
|
|
|
11
11
|
let PROD_API_KEY = "lChjFRJce3bxmoS3TSQk5w=="
|
|
12
12
|
let STAGE_API_KEY = "lChjFRJce3bxmoS3TSQk5w=="
|
|
13
|
+
|
|
13
14
|
let PROD_BASE_URL = "https://api.mytatva.in/api/v8"
|
|
14
15
|
let STAGE_BASE_URL = "https://api-uat.mytatva.in/api/v8"
|
|
15
16
|
|
|
@@ -97,6 +98,7 @@ class API {
|
|
|
97
98
|
|
|
98
99
|
func postCGMData(
|
|
99
100
|
data: Payload,
|
|
101
|
+
environment: TatvaEnvironment,
|
|
100
102
|
token: String = TOKEN,
|
|
101
103
|
encryptionKey: String = PROD_ENC_KEY,
|
|
102
104
|
encryptionIv: String = PROD_ENC_IV,
|
|
@@ -124,6 +126,7 @@ class API {
|
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
let urlString = (envType.lowercased() == "uat" ? STAGE_BASE_URL : PROD_BASE_URL) + "/cgm/logs"
|
|
129
|
+
// let urlString = (environment == .stage ? STAGE_BASE_URL : PROD_BASE_URL) + "/cgm/logs"
|
|
127
130
|
guard let url = URL(string: urlString) else {
|
|
128
131
|
throw URLError(.badURL)
|
|
129
132
|
}
|
|
@@ -131,10 +134,11 @@ class API {
|
|
|
131
134
|
var request = URLRequest(url: url)
|
|
132
135
|
request.httpMethod = "POST"
|
|
133
136
|
request.setValue(envType.lowercased() == "uat" ? STAGE_API_KEY : PROD_API_KEY, forHTTPHeaderField: "api-key")
|
|
137
|
+
// request.setValue(environment == .stage ? STAGE_API_KEY : PROD_API_KEY, forHTTPHeaderField: "api-key")
|
|
134
138
|
request.setValue(token, forHTTPHeaderField: "token")
|
|
135
139
|
request.setValue("text/plain", forHTTPHeaderField: "Content-Type")
|
|
136
140
|
request.httpBody = encrypted.data(using: .utf8)
|
|
137
|
-
|
|
141
|
+
print("===>url:", urlString)
|
|
138
142
|
let (data, response) = try await URLSession.shared.data(for: request)
|
|
139
143
|
|
|
140
144
|
if let httpResponse = response as? HTTPURLResponse {
|
|
@@ -144,7 +148,7 @@ class API {
|
|
|
144
148
|
if let responseStr = String(data: data, encoding: .utf8) {
|
|
145
149
|
print("===>Server Response: \(responseStr)")
|
|
146
150
|
if let decrypted = Crypto.shared.getDecryptedData(cipherText: responseStr, encryptionKey: encryptionKey, encryptionIv: encryptionIv) {
|
|
147
|
-
print("===>Decrypted response (for verification): \(decrypted)")
|
|
151
|
+
print("===>Decrypted post cgm data response (for verification): \(decrypted)")
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
}
|
|
@@ -165,13 +169,16 @@ class API {
|
|
|
165
169
|
//addCT3GlucoseDataWithReceiveData
|
|
166
170
|
//updatePOCAlgoBeforeRef
|
|
167
171
|
func sendStatus(sensorId: String = UserDefaults.standard.string(forKey: "sensorId") ?? "",
|
|
172
|
+
environment: TatvaEnvironment,
|
|
168
173
|
status: CGMConnectionStatus,
|
|
169
174
|
transmitterName: String = KLTBluetoothManager.shared().currentDevice?.advertise?.localName ?? "",
|
|
170
175
|
encryptionKey: String = PROD_ENC_KEY,
|
|
171
176
|
encryptionIv: String = PROD_ENC_IV) {
|
|
172
177
|
if sensorId.isEmpty { return }
|
|
173
|
-
|
|
178
|
+
// let envType = UserDefaults.standard.string(forKey: "envType") ?? "uat"
|
|
179
|
+
print("envType: \(envType.lowercased())")
|
|
174
180
|
let urlString = (envType.lowercased() == "uat" ? STAGE_BASE_URL : PROD_BASE_URL) + "/cgm/connection"
|
|
181
|
+
//let urlString = (environment == .stage ? STAGE_BASE_URL : PROD_BASE_URL) + "/cgm/connection"
|
|
175
182
|
let url = URL(string: urlString)!
|
|
176
183
|
var request = URLRequest(url: url)
|
|
177
184
|
request.httpMethod = "POST"
|
|
@@ -179,15 +186,15 @@ class API {
|
|
|
179
186
|
// Set headers
|
|
180
187
|
request.addValue("text/plain", forHTTPHeaderField: "Content-Type")
|
|
181
188
|
request.setValue(envType.lowercased() == "uat" ? STAGE_API_KEY : PROD_API_KEY, forHTTPHeaderField: "api-key")
|
|
189
|
+
//request.setValue(environment == .stage ? STAGE_API_KEY : PROD_API_KEY, forHTTPHeaderField: "api-key")
|
|
182
190
|
request.addValue(TOKEN, forHTTPHeaderField: "token")
|
|
183
|
-
print("===>url:",
|
|
191
|
+
print("===>url:", urlString)
|
|
184
192
|
print("===>api-key:", PROD_API_KEY)
|
|
185
193
|
print("===>httpmMethod:","POST")
|
|
186
194
|
print("===>ios token:", TOKEN)
|
|
187
195
|
// Set request body
|
|
188
196
|
let json: [String: Any] = [
|
|
189
197
|
"sensorId": sensorId,
|
|
190
|
-
// "sensorName": sensorId,
|
|
191
198
|
"status": status.rawValue,
|
|
192
199
|
"rawData": [
|
|
193
200
|
"transmitterName": transmitterName,
|
|
@@ -222,7 +229,7 @@ class API {
|
|
|
222
229
|
if let responseString = String(data: data, encoding: .utf8) {
|
|
223
230
|
print("===>Server Response: \(responseString)")
|
|
224
231
|
if let decrypted = Crypto.shared.getDecryptedData(cipherText: responseString, encryptionKey: encryptionKey, encryptionIv: encryptionIv) {
|
|
225
|
-
print("===>Decrypted response (for verification): \(decrypted)")
|
|
232
|
+
print("===>Decrypted connection api response (for verification): \(decrypted)")
|
|
226
233
|
}
|
|
227
234
|
}
|
|
228
235
|
}
|
|
@@ -7,28 +7,43 @@
|
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
9
|
|
|
10
|
-
func ReceiveDataToLog(data:
|
|
10
|
+
func ReceiveDataToLog(data: GlucoseData) -> CGMLog {
|
|
11
|
+
let cgmLogs = CGMLog(
|
|
12
|
+
timeInMillis: Double(Date().timeIntervalSince1970 * 1000),
|
|
13
|
+
countdownMinutes: (data.countdownMinutes as? Int) ?? 0,
|
|
14
|
+
countdownDays: (data.countdownDays as? Int) ?? 0,
|
|
15
|
+
hypoglycemiaEarlyWarnMinutes: 0, // still missing, you can map if available
|
|
16
|
+
showGlucoseMG: (data.gluADC as? Int) ?? 0,
|
|
17
|
+
glucoseId: Int(truncating: data.glucoseId ?? 0),
|
|
18
|
+
name: data.device?.advertise?.localName ?? "",
|
|
19
|
+
bytes: [], // still missing: need raw data source
|
|
20
|
+
showGlucose: (data.glu as? Float) ?? 0,
|
|
21
|
+
Ib: (data.blankCurrent as? Float) ?? 0,
|
|
22
|
+
Iw: (data.operatingCurrent as? Float) ?? 0,
|
|
23
|
+
countdownHours: (data.countdownHours as? Int) ?? 0,
|
|
24
|
+
T: (data.temperature as? Float) ?? 0.0,
|
|
25
|
+
year: (data.year as? Int32) ?? 0,
|
|
26
|
+
month: (data.month as? Int32) ?? 0,
|
|
27
|
+
day: (data.day as? Int32) ?? 0,
|
|
28
|
+
hour: (data.hour as? Int32) ?? 0,
|
|
29
|
+
minute: (data.minute as? Int32) ?? 0,
|
|
30
|
+
|
|
31
|
+
trendObject: TrendObject(
|
|
32
|
+
trendId: (data.trend as? Int) ?? 0,
|
|
33
|
+
drawableId: 2103818652, // customize if needed
|
|
34
|
+
widgetImg: -1,
|
|
35
|
+
apsChangeRate: "FLAT" // you could map a real value if available
|
|
36
|
+
),
|
|
37
|
+
|
|
38
|
+
glucoseStatusObject: GlucoseStatusObject(
|
|
39
|
+
statusId: 1 // you may derive this from a field like `calibrationStatus`
|
|
40
|
+
),
|
|
41
|
+
|
|
42
|
+
errorObject: ErrorObject(
|
|
43
|
+
errorId: (data.errorCode as? Int) ?? 0,
|
|
44
|
+
sound: "None"
|
|
45
|
+
)
|
|
46
|
+
)
|
|
11
47
|
|
|
12
|
-
let cgmLogs = CGMLog(timeInMillis: Double(Date().timeIntervalSince1970 * 1000),
|
|
13
|
-
countdownMinutes: (data.countdownMinutes as? Int) ?? 0,
|
|
14
|
-
countdownDays: (data.countdownDays as? Int) ?? 0,
|
|
15
|
-
hypoglycemiaEarlyWarnMinutes: 0, //missing
|
|
16
|
-
showGlucoseMG: (data.gluADC as? Int) ?? 0,
|
|
17
|
-
glucoseId: Int(truncating: data.glucoseId ?? 0),
|
|
18
|
-
name: data.device?.advertise?.localName ?? "",
|
|
19
|
-
bytes: [], //missing
|
|
20
|
-
showGlucose: (data.glu as? Float) ?? 0 ,
|
|
21
|
-
Ib: (data.blankCurrent as? Float) ?? 0,
|
|
22
|
-
Iw: (data.operatingCurrent as? Float) ?? 0,
|
|
23
|
-
countdownHours: (data.countdownHours as? Int) ?? 0,
|
|
24
|
-
T: (data.temperature as? Float) ?? 0.0,
|
|
25
|
-
year: (data.year as? Int32) ?? 0,
|
|
26
|
-
month: (data.month as? Int32) ?? 0,
|
|
27
|
-
day: (data.day as? Int32) ?? 0,
|
|
28
|
-
hour: (data.hour as? Int32) ?? 0,
|
|
29
|
-
minute: (data.minute as? Int32) ?? 0,
|
|
30
|
-
trendObject: TrendObject(trendId: (data.trend as? Int) ?? 0, drawableId: 2103818652, widgetImg: -1, apsChangeRate: "FLAT"), //missing
|
|
31
|
-
glucoseStatusObject: GlucoseStatusObject(statusId: 1), //missing
|
|
32
|
-
errorObject: ErrorObject(errorId: (data.error as? Int) ?? 0, sound: "None"))
|
|
33
48
|
return cgmLogs
|
|
34
49
|
}
|
|
@@ -72,13 +72,15 @@ class AttachTransmitterViewController: UIViewController {
|
|
|
72
72
|
print(data)
|
|
73
73
|
print("===> all data count: ", data.count)
|
|
74
74
|
// KLTDatabaseHandler.shared().reloadQueryHistoryData()
|
|
75
|
+
|
|
75
76
|
if let device = KLTBluetoothManager.shared().currentDevice {
|
|
76
|
-
let arrayFromInitial = KLTDatabaseHandler.shared().
|
|
77
|
+
let arrayFromInitial = KLTDatabaseHandler.shared().queryGlucoseData(with: device) as! [GlucoseData]
|
|
77
78
|
print(arrayFromInitial)
|
|
78
79
|
print("===> arrayFromInitial count: ", arrayFromInitial.count)
|
|
79
80
|
|
|
80
81
|
self.viewModel.uploadData(data: arrayFromInitial)
|
|
81
82
|
}
|
|
83
|
+
|
|
82
84
|
NotificationCenter.default.post(name: Notification.Name("cgmDeviceEvent"), object: nil, userInfo: ["a":"a"])
|
|
83
85
|
if let rootVC = UIApplication.shared.connectedScenes
|
|
84
86
|
.compactMap({ ($0 as? UIWindowScene)?.windows.first?.rootViewController })
|
|
@@ -214,6 +214,7 @@ class ConnectToSensorViewController: UIViewController {
|
|
|
214
214
|
|
|
215
215
|
func connectSensor(value: String, controller: ConnectToSensorViewController) {
|
|
216
216
|
UserDefaults.standard.set(value, forKey: "sensorId")
|
|
217
|
+
|
|
217
218
|
var isMatch = false
|
|
218
219
|
|
|
219
220
|
var regex = #"^[A-Z0-9][0-9](0[1-9]|[1-9][0-9]|[A-Z][1-9A-Z])(00[1-9]|0[1-9][0-9]|[1-9][0-9][0-9]){2}[0-9]{4,5}[0-9A-Z]{3}$"#
|
|
@@ -123,6 +123,8 @@ import Foundation
|
|
|
123
123
|
if device.connectedDateTime == nil && device.disconnectedDateTime == nil {
|
|
124
124
|
viewModel.manager.startScan()
|
|
125
125
|
viewModel.debouncer.update(with: .transmitterDisconnect)
|
|
126
|
+
} else {
|
|
127
|
+
|
|
126
128
|
}
|
|
127
129
|
} else {
|
|
128
130
|
print("⚠️ currentDevice is nil")
|
|
@@ -153,7 +155,7 @@ class FinalViewModel: NSObject {
|
|
|
153
155
|
super.init()
|
|
154
156
|
debouncer.onDebounceSuccess = { value in
|
|
155
157
|
print("Blutooth is------------------->>>>>>>>>> \(value)")
|
|
156
|
-
API.shared.sendStatus(status: value)
|
|
158
|
+
API.shared.sendStatus(environment: .stage, status: value)
|
|
157
159
|
// if value == .errorCommon {
|
|
158
160
|
// self.manager.startScan()
|
|
159
161
|
// }
|
|
@@ -311,11 +313,13 @@ class FinalViewModel: NSObject {
|
|
|
311
313
|
|
|
312
314
|
NotificationCenter.default.addObserver(self, selector: #selector(bluetoothEnable(_:)), name: NSNotification.Name("BluetoothEnable"), object: nil)
|
|
313
315
|
|
|
314
|
-
|
|
316
|
+
// NotificationCenter.default.addObserver(self, selector: #selector(errorStatusFromTransmitter(_:)), name: NSNotification.Name("ErrorStatusFromTransmitter"), object: nil)
|
|
315
317
|
|
|
316
318
|
NotificationCenter.default.addObserver(self, selector: #selector(handleLatestReceiveData(_:)), name: NSNotification.Name(KLTAlertCurrentInInitialNotify), object: nil)
|
|
317
319
|
|
|
318
320
|
NotificationCenter.default.addObserver(self, selector: #selector(updateData(_:)), name: NSNotification.Name(KLTUpdateDataNotify), object: nil)
|
|
321
|
+
|
|
322
|
+
NotificationCenter.default.addObserver(self, selector: #selector(checkErrorStatusFromLastBatchData(_:)), name: NSNotification.Name("CheckErrorStatusFromLastBatchData"), object: nil)
|
|
319
323
|
}
|
|
320
324
|
|
|
321
325
|
func removeAllObservers() {
|
|
@@ -323,15 +327,17 @@ class FinalViewModel: NSObject {
|
|
|
323
327
|
|
|
324
328
|
NotificationCenter.default.removeObserver(self, name: NSNotification.Name("BluetoothEnable"), object: nil)
|
|
325
329
|
|
|
326
|
-
|
|
330
|
+
// NotificationCenter.default.removeObserver(self, name: NSNotification.Name("ErrorStatusFromTransmitter"), object: nil)
|
|
327
331
|
|
|
328
332
|
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(KLTAlertCurrentInInitialNotify), object: nil)
|
|
329
333
|
|
|
330
334
|
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(KLTUpdateDataNotify), object: nil)
|
|
335
|
+
|
|
336
|
+
NotificationCenter.default.removeObserver(self, name: NSNotification.Name("CheckErrorStatusFromLastBatchData"), object: nil)
|
|
331
337
|
}
|
|
332
338
|
|
|
333
339
|
|
|
334
|
-
func uploadData(data: [
|
|
340
|
+
func uploadData(data: [GlucoseData]) {
|
|
335
341
|
let batchSize = 40
|
|
336
342
|
let batches = stride(from: 0, to: data.count, by: batchSize).map {
|
|
337
343
|
Array(data[$0..<min($0 + batchSize, data.count)])
|
|
@@ -340,9 +346,11 @@ class FinalViewModel: NSObject {
|
|
|
340
346
|
uploadBatch(batches: batches, index: 0)
|
|
341
347
|
}
|
|
342
348
|
|
|
343
|
-
private func uploadBatch(batches: [[
|
|
349
|
+
private func uploadBatch(batches: [[GlucoseData]], index: Int) {
|
|
344
350
|
guard index < batches.count else {
|
|
345
|
-
|
|
351
|
+
if index != 0 {
|
|
352
|
+
NotificationCenter.default.post(name: Notification.Name("CheckErrorStatusFromLastBatchData"), object: batches.last?.last)
|
|
353
|
+
}
|
|
346
354
|
print("✅ All batches uploaded")
|
|
347
355
|
return
|
|
348
356
|
}
|
|
@@ -352,7 +360,7 @@ class FinalViewModel: NSObject {
|
|
|
352
360
|
let payload = Payload(logs: cgmLogs)
|
|
353
361
|
|
|
354
362
|
print("====================================> called uploadBatch")
|
|
355
|
-
API.shared.postCGMData(data: payload
|
|
363
|
+
API.shared.postCGMData(data: payload, environment: .stage) {
|
|
356
364
|
print("====================================> uploaded successfully")
|
|
357
365
|
print("✅ Batch \(index + 1) uploaded successfully")
|
|
358
366
|
KLTDatabaseHandler.shared().deleteReceiveDataArray(batch)
|
|
@@ -362,22 +370,50 @@ class FinalViewModel: NSObject {
|
|
|
362
370
|
// Optionally retry or stop here
|
|
363
371
|
}
|
|
364
372
|
}
|
|
365
|
-
|
|
373
|
+
//
|
|
374
|
+
// @objc func updateData(_ notification: Notification) {
|
|
375
|
+
// let data = KLTDatabaseHandler.shared().queryAllReceiveData() as! [ReceiveData]
|
|
376
|
+
// print(data)
|
|
377
|
+
// print("===> all data count: ", data.count)
|
|
378
|
+
//// KLTDatabaseHandler.shared().reloadQueryHistoryData()
|
|
379
|
+
// if let device = KLTBluetoothManager.shared().currentDevice {
|
|
380
|
+
// let arrayFromInitial = KLTDatabaseHandler.shared().queryGlucoseData(with: device) as! [GlucoseData]
|
|
381
|
+
// print(arrayFromInitial)
|
|
382
|
+
// print("======================> arrayFromInitial count: ", arrayFromInitial.count)
|
|
383
|
+
// self.uploadData(data: arrayFromInitial)
|
|
384
|
+
// }
|
|
385
|
+
// }
|
|
386
|
+
|
|
366
387
|
@objc func updateData(_ notification: Notification) {
|
|
367
|
-
|
|
388
|
+
// Safely cast to [ReceiveData]
|
|
389
|
+
guard let data = KLTDatabaseHandler.shared().queryAllReceiveData() as? [ReceiveData] else {
|
|
390
|
+
print("⚠️ Failed to cast queryAllReceiveData() to [ReceiveData]")
|
|
391
|
+
return
|
|
392
|
+
}
|
|
393
|
+
|
|
368
394
|
print(data)
|
|
369
|
-
print("===> all data count:
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
print(
|
|
374
|
-
|
|
375
|
-
|
|
395
|
+
print("===> all data count: \(data.count)")
|
|
396
|
+
|
|
397
|
+
// Ensure device exists
|
|
398
|
+
guard let device = KLTBluetoothManager.shared().currentDevice else {
|
|
399
|
+
print("⚠️ No current device found")
|
|
400
|
+
return
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Get glucose data array
|
|
404
|
+
guard let arrayFromInitial = KLTDatabaseHandler.shared().queryGlucoseData(with: device) else {
|
|
405
|
+
print("⚠️ Failed to cast queryGlucoseData to [GlucoseData]")
|
|
406
|
+
return
|
|
376
407
|
}
|
|
408
|
+
|
|
409
|
+
print("======================> arrayFromInitial count: \(arrayFromInitial.count)")
|
|
410
|
+
|
|
411
|
+
// Call upload
|
|
412
|
+
self.uploadData(data: arrayFromInitial)
|
|
377
413
|
}
|
|
378
|
-
|
|
379
|
-
@objc func
|
|
380
|
-
guard let receiveData = notification.object as?
|
|
414
|
+
|
|
415
|
+
@objc func checkErrorStatusFromLastBatchData(_ notification: Notification) {
|
|
416
|
+
guard let receiveData = notification.object as? GlucoseData else { return }
|
|
381
417
|
|
|
382
418
|
let errorCode = ErrorCode(rawValue: Int32(receiveData.error?.intValue ?? 0))
|
|
383
419
|
if errorCode == ErrorCode.ERROR_CODE_FLOODING_WATER {
|
|
@@ -396,6 +432,26 @@ class FinalViewModel: NSObject {
|
|
|
396
432
|
}
|
|
397
433
|
}
|
|
398
434
|
|
|
435
|
+
// @objc func errorStatusFromTransmitter(_ notification: Notification) {
|
|
436
|
+
// guard let receiveData = notification.object as? ReceiveData else { return }
|
|
437
|
+
//
|
|
438
|
+
// let errorCode = ErrorCode(rawValue: Int32(receiveData.error?.intValue ?? 0))
|
|
439
|
+
// if errorCode == ErrorCode.ERROR_CODE_FLOODING_WATER {
|
|
440
|
+
// debouncer.update(with: CGMConnectionStatus.moistureDetect)
|
|
441
|
+
// //API.shared.sendStatus(status: .moistureDetect)
|
|
442
|
+
// } else if errorCode == ErrorCode.ERROR_CODE_CURRENT_SMALL || errorCode == ErrorCode.ERROR_CODE_NOISE || errorCode == ErrorCode.ERROR_CODE_SENSITIVITY_ATTENUATION {
|
|
443
|
+
// debouncer.update(with: CGMConnectionStatus.weakSignal)
|
|
444
|
+
// //API.shared.sendStatus(status: .weakSignal)
|
|
445
|
+
// } else if errorCode != ErrorCode.ERROR_CODE_NONE {
|
|
446
|
+
// debouncer.update(with: CGMConnectionStatus.errorCommon)
|
|
447
|
+
// //API.shared.sendStatus(status: .errorCommon)
|
|
448
|
+
// }
|
|
449
|
+
// if receiveData.countdownDays == 0 && receiveData.countdownHours == 0 && receiveData.countdownMinutes == 0 {
|
|
450
|
+
// debouncer.update(with: CGMConnectionStatus.expired)
|
|
451
|
+
// //API.shared.sendStatus(status: .expired)
|
|
452
|
+
// }
|
|
453
|
+
// }
|
|
454
|
+
|
|
399
455
|
@objc func handleLatestReceiveData(_ notification: Notification) {
|
|
400
456
|
print("====> handleLatestReceiveData")
|
|
401
457
|
guard let receiveData = notification.object as? ReceiveData else { return }
|