Skip to content

Commit 6200ff4

Browse files
authored
Merge pull request LoopKit#1 from tidepool-org/ps2/LOOP-4688/diy-sync
LOOP-4688 DIY Sync
2 parents 3781e2e + ae97529 commit 6200ff4

File tree

8 files changed

+80
-71
lines changed

8 files changed

+80
-71
lines changed

G7SensorKit/G7CGMManager/G7CGMManager.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,14 +247,14 @@ public class G7CGMManager: CGMManager {
247247
sensor.scanForNewSensor()
248248
}
249249

250-
public var device: HKDevice? {
250+
private var device: HKDevice? {
251251
return HKDevice(
252-
name: "CGMBLEKit",
252+
name: state.sensorID ?? "Unknown",
253253
manufacturer: "Dexcom",
254254
model: "G7",
255255
hardwareVersion: nil,
256256
firmwareVersion: nil,
257-
softwareVersion: String(G7SensorKitVersionNumber),
257+
softwareVersion: "CGMBLEKit" + String(G7SensorKitVersionNumber),
258258
localIdentifier: nil,
259259
udiDeviceIdentifier: "00386270001863"
260260
)

G7SensorKit/G7CGMManager/G7PeripheralManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ extension G7PeripheralManager {
131131
self.log.error("No delegate set configured")
132132
}
133133
} catch let error {
134-
self.log.error("Error applying peripheral configuration: %@", String(describing: error))
134+
self.log.error("Error applying peripheral configuration: %{public}@", String(describing: error))
135135
// Will retry
136136
}
137137

G7SensorKit/G7CGMManager/G7Sensor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public final class G7Sensor: G7BluetoothManagerDelegate {
123123
}
124124

125125
private func handleGlucoseMessage(message: G7GlucoseMessage, peripheralManager: G7PeripheralManager) {
126-
activationDate = Date().addingTimeInterval(-TimeInterval(message.glucoseTimestamp))
126+
activationDate = Date().addingTimeInterval(-TimeInterval(message.messageTimestamp))
127127
peripheralManager.perform { (peripheral) in
128128
self.log.debug("Listening for backfill responses")
129129
// Subscribe to backfill updates

G7SensorKit/Messages/G7GlucoseMessage.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public struct G7GlucoseMessage: SensorMessage, Equatable {
2020
public let sequence: UInt16
2121
public let trend: Double?
2222
public let data: Data
23-
public let age: UInt8 // Amount of time elapsed (seconds) from sensor reading to BLE comms
23+
public let age: UInt16 // Amount of time elapsed (seconds) from sensor reading to BLE comms
2424

2525
public var hasReliableGlucose: Bool {
2626
return algorithmState.hasReliableGlucose
@@ -68,12 +68,12 @@ public struct G7GlucoseMessage: SensorMessage, Equatable {
6868
}
6969

7070
init?(data: Data) {
71-
// 0 1 2 3 4 5 6 7 8 9 10 11 1213 14 15 1617 18
72-
// TTTTTTTT SQSQ AG BGBG SS TR PRPR C
73-
// 0x4e 00 d5070000 0900 00 01 05 00 6100 06 01 ffff 0e
71+
// 0 1 2 3 4 5 6 7 8 9 1011 1213 14 15 1617 18
72+
// TTTTTTTT SQSQ AGAG BGBG SS TR PRPR C
73+
// 0x4e 00 d5070000 0900 00 01 0500 6100 06 01 ffff 0e
7474
// TTTTTTTT = timestamp
7575
// SQSQ = sequence
76-
// AG = age
76+
// AGAG = age
7777
// BGBG = glucose
7878
// SS = algorithm state
7979
// TR = trend
@@ -92,7 +92,7 @@ public struct G7GlucoseMessage: SensorMessage, Equatable {
9292

9393
sequence = data[6..<8].to(UInt16.self)
9494

95-
age = data[10]
95+
age = data[10..<12].to(UInt16.self)
9696

9797
let glucoseData = data[12..<14].to(UInt16.self)
9898
if glucoseData != 0xffff {

G7SensorKitTests/G7GlucoseMessageTests.swift

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,13 @@ final class G7GlucoseMessageTests: XCTestCase {
7676
XCTAssertEqual(1400, messages[5].glucoseTimestamp)
7777
XCTAssertEqual(1700, messages[6].glucoseTimestamp)
7878
XCTAssertEqual(2000, messages[7].glucoseTimestamp)
79-
XCTAssertEqual(934777, messages[8].glucoseTimestamp)
79+
XCTAssertEqual(907385, messages[8].glucoseTimestamp)
8080
}
8181

8282
func testG7MessageDataDetails() {
8383
// 0 1 2 3 4 5 6 7 8 9 10 11 1213 14 15 16 17 18
84-
// TTTTTTTT SQSQ AG BGBG SS C
85-
// 4e 00 a89c0000 8800 00 01 04 00 8d00 06 03 8a 00 0f
84+
// TTTTTTTT SQSQ AGAG BGBG SS C
85+
// 4e 00 a89c0000 8800 00 01 0400 8d00 06 03 8a 00 0f
8686

8787
//2022-09-12 09:18:06.821253 readEGV(txTime=40104,seq=136,session=1,age=4,value=141,pred=138,algo=6,subAlgo=15,rate=3)
8888
let data = Data(hexadecimalString: "4e00a89c00008800000104008d0006038a000f")!
@@ -110,51 +110,74 @@ final class G7GlucoseMessageTests: XCTestCase {
110110
let message = G7GlucoseMessage(data: data)!
111111
XCTAssertNil(message.trend)
112112
}
113+
114+
func testTwoByteAge() {
115+
let data = Data(hexadecimalString: "4e00f9590200030200012a018f000610d9000f")!
116+
let message = G7GlucoseMessage(data: data)!
117+
XCTAssertEqual(298, message.age)
118+
XCTAssertEqual(154105, message.messageTimestamp)
119+
XCTAssertEqual(153807, message.glucoseTimestamp)
120+
}
121+
122+
func testTwoByteAgeOnExpiredSensor() {
123+
let data = Data(hexadecimalString: "4e004d440e00d40b0001d46b650018036a000e")!
124+
let message = G7GlucoseMessage(data: data)!
125+
XCTAssertEqual(27604, message.age) // 7 hours after expiration
126+
XCTAssertEqual(934989, message.messageTimestamp)
127+
XCTAssertEqual(907385, message.glucoseTimestamp)
128+
}
129+
130+
func testBackfill() {
131+
let data = Data(hexadecimalString: "cf5802008f00060f10")!
132+
let message = G7BackfillMessage(data: data)!
133+
XCTAssertEqual(153807, message.timestamp)
134+
}
135+
113136
}
114137

115138

116139

117140
// Activated 2022-09-24 17:39:31 +0000
118141

119-
// 0 1 2 3 4 5 6 7 8 9 10 11 1213 14 15 16 17 18
120-
// TTTTTTTT BGBG SS C
121-
// 2022-09-24 17:47:23 4e 00 ea010000 04 00 00 01 05 00 6c00 02 7e ff ff 02
122-
// 2022-09-24 17:52:27 4e 00 1a030000 05 00 00 01 09 00 5300 02 7e ff ff 02
123-
// 2022-09-24 17:57:25 4e 00 44040000 06 00 00 01 07 00 4500 02 e7 ff ff 02
124-
// 2022-09-24 18:02:27 4e 00 73050000 07 00 00 01 0a 00 3a00 02 f4 ff ff 02
125-
// 2022-09-24 18:07:21 4e 00 99060000 08 00 00 01 04 00 4800 06 02 ff ff 0e
126-
// 2022-09-24 18:22:26 4e 00 220a0000 0b 00 00 01 09 00 4f00 06 fe ff ff 0e
142+
// 0 1 2 3 4 5 6 7 8 9 1011 1213 14 15 16 17 18
143+
// TTTTTTTT AGAG BGBG SS C
144+
// 2022-09-24 17:47:23 4e 00 ea010000 04 00 00 01 0500 6c00 02 7e ff ff 02
145+
// 2022-09-24 17:52:27 4e 00 1a030000 05 00 00 01 0900 5300 02 7e ff ff 02
146+
// 2022-09-24 17:57:25 4e 00 44040000 06 00 00 01 0700 4500 02 e7 ff ff 02
147+
// 2022-09-24 18:02:27 4e 00 73050000 07 00 00 01 0a00 3a00 02 f4 ff ff 02
148+
// 2022-09-24 18:07:21 4e 00 99060000 08 00 00 01 0400 4800 06 02 ff ff 0e
149+
// 2022-09-24 18:22:26 4e 00 220a0000 0b 00 00 01 0900 4f00 06 fe ff ff 0e
127150

128-
// 2022-09-24 18:27:22 4e 00 4a0b0000 0c 00 00 01 05 00 4900 06 f9 37 00 0f
151+
// 2022-09-24 18:27:22 4e 00 4a0b0000 0c 00 00 01 0500 4900 06 f9 37 00 0f
129152
// 2022-09-24 18:27:23 (txInfo: 7815(379013053518), SW13354, 73 mg⁠/⁠dL, Predictive: 55 mg⁠/⁠dL, Rate: -0.7 @ 2022-09-24T13:27:17-05:00, sessionInfo: Optional(Start: 2022-09-24T12:40:17-05:00, End: 2022-10-05T00:40:17-05:00)), isTimeCertain: true
130153

131-
// 2022-09-24 22:32:24 4e 00 b7440000 3d 00 00 01 06 00 7f00 06 03 83 00 0f
154+
// 2022-09-24 22:32:24 4e 00 b7440000 3d 00 00 01 0600 7f00 06 03 83 00 0f
132155
//2022-09-24 17:32:27.248461 -0500 info 388 <Missing Description> Dexcom G7 DisplayState: displayingGlucose(txInfo: 7815(379013053518), SW13354, 127 mg⁠/⁠dL, Predictive: 131 mg⁠/⁠dL, Rate: 0.3 @ 2022-09-24T17:32:18-05:00, sessionInfo: Optional(Start: 2022-09-24T12:40:18-05:00, End: 2022-10-05T00:40:18-05:00)), isTimeCertain: true
133156

134157

135158

136159

137-
// 0 1 2 3 4 5 6 7 8 9 10 11 1213 14 15 16 17 18
138-
// TTTTTTTT BGBG SS C
139-
// 2022-10-04 23:27:39 106 timestamp:902888 4e 00 e8c60d00 c5 0b 00 01 03 00 6a00 06 01 6a 00 0f
140-
// 2022-10-04 23:32:40 101 timestamp:903189 4e 00 15c80d00 c6 0b 00 01 04 00 6500 06 fe 61 00 0f
141-
// 2022-10-04 23:37:39 98 timestamp:903488 4e 00 40c90d00 c7 0b 00 01 03 00 6200 06 fc 5e 00 0f
142-
// 2022-10-04 23:42:39 100 timestamp:903789 4e 00 6dca0d00 c8 0b 00 01 04 00 6400 06 ff 5e 00 0f
143-
// 2022-10-04 23:47:41 97 timestamp:904090 4e 00 9acb0d00 c9 0b 00 01 05 00 6100 06 fd 5c 00 0f
160+
// 0 1 2 3 4 5 6 7 8 9 1011 1213 14 15 16 17 18
161+
// TTTTTTTT AGAG BGBG SS C
162+
// 2022-10-04 23:27:39 106 timestamp:902888 4e 00 e8c60d00 c5 0b 00 01 0300 6a00 06 01 6a 00 0f
163+
// 2022-10-04 23:32:40 101 timestamp:903189 4e 00 15c80d00 c6 0b 00 01 0400 6500 06 fe 61 00 0f
164+
// 2022-10-04 23:37:39 98 timestamp:903488 4e 00 40c90d00 c7 0b 00 01 0300 6200 06 fc 5e 00 0f
165+
// 2022-10-04 23:42:39 100 timestamp:903789 4e 00 6dca0d00 c8 0b 00 01 0400 6400 06 ff 5e 00 0f
166+
// 2022-10-04 23:47:41 97 timestamp:904090 4e 00 9acb0d00 c9 0b 00 01 0500 6100 06 fd 5c 00 0f
144167

145-
// 2022-10-04 23:52:41 97 timestamp:904390 4e 00 c6cc0d00 ca 0b 00 01 05 00 6100 06 fe 5b 00 0f
168+
// 2022-10-04 23:52:41 97 timestamp:904390 4e 00 c6cc0d00 ca 0b 00 01 0500 6100 06 fe 5b 00 0f
146169

147170
// 2022-10-04 23:52:41.100991 -0500 info 289 <Missing Description> Dexcom G7 calBounds(signature=65,lastBG=100,lastBGTime=901259,processing=completeHigh,permitted=true,lastDisplay=phone,lastProcessingTime=901565)
148171
// 2022-10-04 23:52:41.260740 -0500 info 289 <Missing Description> Dexcom G7 DisplayState: displayingGlucose(txInfo: 7815(379013053518), SW13354, 97 mg⁠/⁠dL, Predictive: 91 mg⁠/⁠dL, Rate: -0.2 @ 2022-10-04T23:52:36-05:00, sessionInfo: Optional(Start: 2022-09-24T12:40:36-05:00, End: 2022-10-05T00:40:36-05:00)), isTimeCertain: true
149172
//
150173

151-
// 2022-10-04 23:57:52 98 timestamp:904701 4e 00 fdcd0d00 cb 0b 00 01 10 00 6200 06 00 5c 00 0f
152-
// 2022-10-05 00:02:40 96 timestamp:904989 4e 00 1dcf0d00 cc 0b 00 01 04 00 6000 06 fe 5b 00 0f
153-
// 2022-10-05 00:07:39 95 timestamp:905288 4e 00 48d00d00 cd 0b 00 01 03 00 5f00 06 fe 5a 00 0f
154-
// 2022-10-05 08:17:43 101 timestamp:934692 4e 00 24430e00 d4 0b 00 01 ab 6a 6500 18 03 6a 00 0e
155-
// 2022-10-05 08:22:40 101 timestamp:934989 4e 00 4d440e00 d4 0b 00 01 d4 6b 6500 18 03 6a 00 0e
156-
// 2022-10-05 08:27:40 101 timestamp:935289 4e 00 79450e00 d4 0b 00 01 00 6d 6500 18 03 6a 00 0e
157-
// 2022-10-05 08:32:42 101 timestamp:935590 4e 00 a6460e00 d4 0b 00 01 2d 6e 6500 18 03 6a 00 0e
158-
// 2022-10-05 08:37:42 101 timestamp:935890 4e 00 d2470e00 d4 0b 00 01 59 6f 6500 18 03 6a 00 0e
159-
// 2022-10-05 08:42:39 101 timestamp:936188 4e 00 fc480e00 d4 0b 00 01 83 70 6500 18 03 6a 00 0e
160-
// 2022-10-05 08:47:39 101 timestamp:936488 4e 00 284a0e00 d4 0b 00 01 af 71 6500 18 03 6a 00 0e
174+
// 2022-10-04 23:57:52 98 timestamp:904701 4e 00 fdcd0d00 cb 0b 00 01 1000 6200 06 00 5c 00 0f
175+
// 2022-10-05 00:02:40 96 timestamp:904989 4e 00 1dcf0d00 cc 0b 00 01 0400 6000 06 fe 5b 00 0f
176+
// 2022-10-05 00:07:39 95 timestamp:905288 4e 00 48d00d00 cd 0b 00 01 0300 5f00 06 fe 5a 00 0f
177+
// 2022-10-05 08:17:43 101 timestamp:934692 4e 00 24430e00 d4 0b 00 01 ab6a 6500 18 03 6a 00 0e
178+
// 2022-10-05 08:22:40 101 timestamp:934989 4e 00 4d440e00 d4 0b 00 01 d46b 6500 18 03 6a 00 0e
179+
// 2022-10-05 08:27:40 101 timestamp:935289 4e 00 79450e00 d4 0b 00 01 006d 6500 18 03 6a 00 0e
180+
// 2022-10-05 08:32:42 101 timestamp:935590 4e 00 a6460e00 d4 0b 00 01 2d6e 6500 18 03 6a 00 0e
181+
// 2022-10-05 08:37:42 101 timestamp:935890 4e 00 d2470e00 d4 0b 00 01 596f 6500 18 03 6a 00 0e
182+
// 2022-10-05 08:42:39 101 timestamp:936188 4e 00 fc480e00 d4 0b 00 01 8370 6500 18 03 6a 00 0e
183+
// 2022-10-05 08:47:39 101 timestamp:936488 4e 00 284a0e00 d4 0b 00 01 af71 6500 18 03 6a 00 0e

G7SensorKitUI/G7CGMManager/G7CGMManager+UI.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,20 @@ public struct G7DeviceStatusHighlight: DeviceStatusHighlight, Equatable {
2323
}
2424

2525
extension G7CGMManager: CGMManagerUI {
26+
2627
public static var onboardingImage: UIImage? {
2728
return nil
2829
}
2930

30-
public static func setupViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) -> SetupUIResult<CGMManagerViewController, CGMManagerUI> {
31-
32-
let vc = G7UICoordinator(colorPalette: colorPalette, displayGlucoseUnitObservable: displayGlucoseUnitObservable, allowDebugFeatures: allowDebugFeatures)
31+
public static func setupViewController(bluetoothProvider: LoopKit.BluetoothProvider, displayGlucosePreference: DisplayGlucosePreference, colorPalette: LoopKitUI.LoopUIColorPalette, allowDebugFeatures: Bool, prefersToSkipUserInteraction: Bool) -> LoopKitUI.SetupUIResult<LoopKitUI.CGMManagerViewController, LoopKitUI.CGMManagerUI>
32+
{
33+
let vc = G7UICoordinator(colorPalette: colorPalette, displayGlucosePreference: displayGlucosePreference, allowDebugFeatures: allowDebugFeatures)
3334
return .userInteractionRequired(vc)
3435
}
3536

36-
public func settingsViewController(bluetoothProvider: BluetoothProvider, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) ->CGMManagerViewController {
37+
public func settingsViewController(bluetoothProvider: BluetoothProvider, displayGlucosePreference: DisplayGlucosePreference, colorPalette: LoopUIColorPalette, allowDebugFeatures: Bool) ->CGMManagerViewController {
3738

38-
return G7UICoordinator(cgmManager: self, colorPalette: colorPalette, displayGlucoseUnitObservable: displayGlucoseUnitObservable, allowDebugFeatures: allowDebugFeatures)
39+
return G7UICoordinator(cgmManager: self, colorPalette: colorPalette, displayGlucosePreference: displayGlucosePreference, allowDebugFeatures: allowDebugFeatures)
3940
}
4041

4142
public var smallImage: UIImage? {

G7SensorKitUI/G7CGMManager/G7UICoordinator.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@ class G7UICoordinator: UINavigationController, CGMManagerOnboarding, CompletionN
1414
var cgmManagerOnboardingDelegate: LoopKitUI.CGMManagerOnboardingDelegate?
1515
var completionDelegate: LoopKitUI.CompletionDelegate?
1616
var cgmManager: G7CGMManager?
17-
var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable
17+
var displayGlucosePreference: DisplayGlucosePreference
1818

1919
var colorPalette: LoopUIColorPalette
2020

2121
init(cgmManager: G7CGMManager? = nil,
2222
colorPalette: LoopUIColorPalette,
23-
displayGlucoseUnitObservable: DisplayGlucoseUnitObservable,
23+
displayGlucosePreference: DisplayGlucosePreference,
2424
allowDebugFeatures: Bool)
2525
{
2626
self.cgmManager = cgmManager
2727
self.colorPalette = colorPalette
28-
self.displayGlucoseUnitObservable = displayGlucoseUnitObservable
28+
self.displayGlucosePreference = displayGlucosePreference
2929
super.init(navigationBarClass: UINavigationBar.self, toolbarClass: UIToolbar.self)
3030
}
3131

@@ -75,7 +75,7 @@ class G7UICoordinator: UINavigationController, CGMManagerOnboarding, CompletionN
7575
}
7676
}
7777
},
78-
viewModel: G7SettingsViewModel(cgmManager: cgmManager!, displayGlucoseUnitObservable: displayGlucoseUnitObservable)
78+
viewModel: G7SettingsViewModel(cgmManager: cgmManager!, displayGlucosePreference: displayGlucosePreference)
7979
)
8080
let hostingController = DismissibleHostingController(rootView: view, colorPalette: colorPalette)
8181
return hostingController

G7SensorKitUI/Views/G7SettingsViewModel.swift

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class G7SettingsViewModel: ObservableObject {
2929
}
3030
}
3131

32-
var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable
32+
let displayGlucosePreference: DisplayGlucosePreference
3333

3434
private var lastReading: G7GlucoseMessage?
3535

@@ -40,15 +40,6 @@ class G7SettingsViewModel: ObservableObject {
4040
return formatter
4141
}()
4242

43-
private lazy var glucoseFormatter: QuantityFormatter = {
44-
let formatter = QuantityFormatter()
45-
formatter.setPreferredNumberFormatter(for: displayGlucoseUnitObservable.displayGlucoseUnit)
46-
formatter.numberFormatter.notANumberSymbol = ""
47-
return formatter
48-
}()
49-
50-
private let quantityFormatter = QuantityFormatter()
51-
5243
private var cgmManager: G7CGMManager
5344

5445
var progressBarState: G7ProgressBarState {
@@ -68,9 +59,9 @@ class G7SettingsViewModel: ObservableObject {
6859
}
6960
}
7061

71-
init(cgmManager: G7CGMManager, displayGlucoseUnitObservable: DisplayGlucoseUnitObservable) {
62+
init(cgmManager: G7CGMManager, displayGlucosePreference: DisplayGlucosePreference) {
7263
self.cgmManager = cgmManager
73-
self.displayGlucoseUnitObservable = displayGlucoseUnitObservable
64+
self.displayGlucosePreference = displayGlucosePreference
7465
updateValues()
7566

7667
self.cgmManager.addStateObserver(self, queue: DispatchQueue.main)
@@ -188,19 +179,13 @@ class G7SettingsViewModel: ObservableObject {
188179
case .some(.aboveRange):
189180
return LocalizedString("HIGH", comment: "String displayed instead of a glucose value above the CGM range")
190181
default:
191-
quantityFormatter.setPreferredNumberFormatter(for: displayGlucoseUnitObservable.displayGlucoseUnit)
192-
let valueStr = quantityFormatter.string(from: quantity, for: displayGlucoseUnitObservable.displayGlucoseUnit, includeUnit: false) ?? ""
193-
return String(format: "%@ %@", valueStr, displayGlucoseUnitObservable.displayGlucoseUnit.shortLocalizedUnitString())
182+
return displayGlucosePreference.formatter.string(from: quantity)!
194183
}
195184
}
196185

197186
var lastGlucoseTrendString: String {
198187
if let lastReading = lastReading, lastReading.hasReliableGlucose, let trendRate = lastReading.trendRate {
199-
let glucoseUnitPerMinute = displayGlucoseUnitObservable.displayGlucoseUnit.unitDivided(by: .minute())
200-
// This seemingly strange replacement of glucose units is only to display the unit string correctly
201-
let trendPerMinute = HKQuantity(unit: displayGlucoseUnitObservable.displayGlucoseUnit, doubleValue: trendRate.doubleValue(for: glucoseUnitPerMinute))
202-
let formatted = glucoseFormatter.string(from: trendPerMinute, for: displayGlucoseUnitObservable.displayGlucoseUnit)!
203-
return String(format: LocalizedString("%@/min", comment: "Format string for glucose trend per minute. (1: glucose value and unit)"), formatted)
188+
return displayGlucosePreference.minuteRateFormatter.string(from: trendRate)!
204189
} else {
205190
return ""
206191
}

0 commit comments

Comments
 (0)