Skip to content

Commit

Permalink
Parse pump events
Browse files Browse the repository at this point in the history
  • Loading branch information
ps2 committed Jun 17, 2023
1 parent d75eec4 commit fc058d2
Show file tree
Hide file tree
Showing 11 changed files with 240 additions and 55 deletions.
8 changes: 3 additions & 5 deletions Sources/LoopIssueReportParser/Parsers/DoseTypeParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@ struct DoseTypeParser: Parser {
var body: some Parser<Substring, DoseType> {
"LoopKit.DoseType."
OneOf {
"basal".map { DoseType.basal }
"bolus".map { DoseType.bolus }
"resume".map { DoseType.resume }
"suspend".map { DoseType.suspend }
"tempBasal".map { DoseType.tempBasal }
for type in DoseType.allCases {
type.rawValue.map { type }
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,7 @@

import Foundation
import Parsing

public struct ExponentialInsulinModel {
let actionDuration: TimeInterval
let peakActivityTime: TimeInterval
let delay: TimeInterval
}

import LoopKit

struct ExponentialInsulinModelParser: Parser {
// ExponentialInsulinModel(actionDuration: 21600.0, peakActivityTime: 4500.0, delay: 600.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,18 @@
//

import Parsing

public enum ExponentialInsulinModelPreset {
case rapidActingAdult(ExponentialInsulinModel)
case rapidActingChild(ExponentialInsulinModel)
case fiasp(ExponentialInsulinModel)
case lyumjev(ExponentialInsulinModel)
case afrezza(ExponentialInsulinModel)
}
import LoopKit

struct ExponentialInsulinModelPresetParser: Parser {
// rapidActingAdult(ExponentialInsulinModel(actionDuration: 21600.0, peakActivityTime: 4500.0, delay: 600.0))

var body: some Parser<Substring, ExponentialInsulinModelPreset> {
OneOf {
Parse {
"rapidActingAdult("
ExponentialInsulinModelParser()
}.map { ExponentialInsulinModelPreset.rapidActingAdult($0) }
Parse {
"rapidActingChild("
ExponentialInsulinModelParser()
}.map { ExponentialInsulinModelPreset.rapidActingChild($0) }
Parse {
"fiasp("
ExponentialInsulinModelParser()
}.map { ExponentialInsulinModelPreset.fiasp($0) }
Parse {
"lyumjev("
ExponentialInsulinModelParser()
}.map { ExponentialInsulinModelPreset.lyumjev($0) }
Parse {
"afrezza("
ExponentialInsulinModelParser()
}.map { ExponentialInsulinModelPreset.afrezza($0) }
"rapidActingAdult".map { ExponentialInsulinModelPreset.rapidActingAdult }
"rapidActingChild".map { ExponentialInsulinModelPreset.rapidActingChild }
"fiasp".map { ExponentialInsulinModelPreset.fiasp }
"lyumjev".map { ExponentialInsulinModelPreset.lyumjev }
"afrezza".map { ExponentialInsulinModelPreset.afrezza }
}
}
}
10 changes: 3 additions & 7 deletions Sources/LoopIssueReportParser/Parsers/GlucoseTrend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,9 @@ struct GlucoseTrendParser: Parser {
var body: some Parser<Substring, GlucoseTrend> {
"LoopKit.GlucoseTrend."
OneOf {
"upUpUp".map { GlucoseTrend.upUpUp }
"upUp".map { GlucoseTrend.upUp }
"up".map { GlucoseTrend.up }
"flat".map { GlucoseTrend.flat }
"down".map { GlucoseTrend.down }
"downDown".map { GlucoseTrend.downDown }
"downDownDown".map { GlucoseTrend.downDownDown }
for type in GlucoseTrend.allCases {
String(describing: type).map { type }
}
}
}
}
Expand Down
9 changes: 3 additions & 6 deletions Sources/LoopIssueReportParser/Parsers/InsulinTypeParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@ struct InsulinTypeParser: Parser {
var body: some Parser<Substring, InsulinType> {
"LoopKit.InsulinType."
OneOf {
"novolog".map { InsulinType.novolog }
"humalog".map { InsulinType.humalog }
"apidra".map { InsulinType.apidra }
"fiasp".map { InsulinType.fiasp }
"lyumjev".map { InsulinType.lyumjev }
"afrezza".map { InsulinType.afrezza }
for type in InsulinType.allCases {
String(describing: type).map { type }
}
}
}
}
Expand Down
36 changes: 35 additions & 1 deletion Sources/LoopIssueReportParser/Parsers/IssueReportParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public struct IssueReport {
public let loopSettings: LoopSettings
public let cachedGlucoseSamples: [StoredGlucoseSample]
public let cachedCarbEntries: [StoredCarbEntry]
public let pumpEvents: [PersistedPumpEvent]
public let normalizedDoseEntries: [DoseEntry]
public let entriesForSavingToInsulinDeliveryStore: [DoseEntry]
public let cachedDoseEntries: [DoseEntry]
}

Expand Down Expand Up @@ -72,6 +75,34 @@ public struct IssueReportParser: Parser {
} separator: {
Whitespace(.vertical)
}
Skip { PrefixUpTo("### getPumpEventValues") }
"### getPumpEventValues"
Whitespace(.vertical)
Whitespace(.vertical)
Many {
"* "
PersistedPumpEventParser()
} separator: {
Whitespace(.vertical)
}
Skip { PrefixUpTo("### getNormalizedDoseEntries") }
"### getNormalizedDoseEntries"
Whitespace(.vertical)
Whitespace(.vertical)
Many {
"* "
DoseEntryParser()
} separator: {
Whitespace(.vertical)
}
Skip { PrefixUpTo("### getPumpEventDoseEntriesForSavingToInsulinDeliveryStore") }
"### getPumpEventDoseEntriesForSavingToInsulinDeliveryStore"
Whitespace(.vertical)
Many {
DoseEntryParser()
} separator: {
Whitespace(.vertical)
}
Skip { PrefixUpTo("#### cachedDoseEntries") }
"#### cachedDoseEntries"
Whitespace(.vertical)
Expand All @@ -90,7 +121,10 @@ public struct IssueReportParser: Parser {
loopSettings: value.3,
cachedGlucoseSamples: value.4,
cachedCarbEntries: value.5,
cachedDoseEntries: value.6
pumpEvents: value.6,
normalizedDoseEntries: value.7,
entriesForSavingToInsulinDeliveryStore: value.8,
cachedDoseEntries: value.9
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//
// PersistedPumpEventParser.swift
//
//
// Created by Pete Schwamb on 6/16/23.
//

import Parsing
import HealthKit
import LoopKit

//* PersistedPumpEvent(date: 2023-06-15 14:26:41 +0000, persistedDate: 2023-06-15 14:27:04 +0000, dose: Optional(LoopKit.DoseEntry(type: LoopKit.DoseType.tempBasal, startDate: 2023-06-15 14:26:41 +0000, endDate: 2023-06-15 14:27:04 +0000, value: 0.0, unit: LoopKit.DoseUnit.unitsPerHour, deliveredUnits: Optional(0.0), description: nil, insulinType: Optional(LoopKit.InsulinType.novolog), automatic: Optional(true), manuallyEntered: false, syncIdentifier: Optional("a7e2601949dc4e4599ff07eeea3aa473"), isMutable: true, wasProgrammedByPumpUI: false, scheduledBasalRate: nil)), isUploaded: false, objectIDURL: x-coredata://D8510943-8CBA-4D7B-8398-AE7BCA863599/PumpEvent/p520493, raw: Optional(16 bytes), title: Optional("Temp Basal"), type: Optional(LoopKit.PumpEventType.tempBasal), automatic: Optional(true), alarmType: nil)

public struct PersistedPumpEventParser: Parser {

public var body: some Parser<Substring, PersistedPumpEvent> {
let p = Parse {
"PersistedPumpEvent("
AttributeValueParser(name: "date") {
DebugDateParser()
}
", "
AttributeValueParser(name: "persistedDate") {
DebugDateParser()
}
", "
AttributeValueParser(name: "dose") {
OptionalParser {
"LoopKit."
DoseEntryParser()
}
}
", "
AttributeValueParser(name: "isUploaded") {
Bool.parser()
}
", "
AttributeValueParser(name: "objectIDURL") {
Prefix() {
$0 != ","
}
}
", "
AttributeValueParser(name: "raw") {
OptionalParser {
Prefix() {
$0 != ")"
}
}
}
", "
AttributeValueParser(name: "title") {
OptionalParser {
"\""
Prefix { $0 != "\"" }
"\""
}
}
", "
AttributeValueParser(name: "type") {
OptionalParser {
PumpEventTypeParser()
}
}
", "
AttributeValueParser(name: "automatic") {
OptionalParser {
Bool.parser()
}
}
", "
AttributeValueParser(name: "alarmType") {
OptionalParser {
PumpAlarmTypeParser()
}
}
")"
}

p.map { (value) -> PersistedPumpEvent in
let objectIDURL = URL(string: String(value.4)) ?? URL(string: "x-coredata://" + UUID().uuidString)!

return PersistedPumpEvent(
date: value.0,
persistedDate: value.1,
dose: value.2,
isUploaded: value.3,
objectIDURL: objectIDURL,
raw: nil, // Debug print loses this info; need to fix in Loop
title: value.6.map(String.init),
type: value.7,
automatic: value.8,
alarmType: value.9)
}
}
}
33 changes: 33 additions & 0 deletions Sources/LoopIssueReportParser/Parsers/PumpAlarmTypeParser.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// PumpAlarmTypeParser.swift
//
//
// Created by Pete Schwamb on 6/17/23.
//

import Parsing
import LoopKit

// LoopKit.PumpAlarmType.other(\"Custom Alarm\"))

struct PumpAlarmTypeParser: Parser {
var body: some Parser<Substring, PumpAlarmType> {
"LoopKit.PumpAlarmType."
OneOf {
Parse {
"other(\""
Prefix() {
$0 != "\""
}
"\")"
}.map { PumpAlarmType.other(String($0)) }
"autoOff".map { PumpAlarmType.autoOff }
"lowInsulin".map { PumpAlarmType.lowInsulin }
"lowPower".map { PumpAlarmType.lowPower }
"noDelivery".map { PumpAlarmType.noDelivery }
"noInsulin".map { PumpAlarmType.noInsulin }
"noPower".map { PumpAlarmType.noPower }
"occlusion".map { PumpAlarmType.occlusion }
}
}
}
20 changes: 20 additions & 0 deletions Sources/LoopIssueReportParser/Parsers/PumpEventTypeParser.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// PumpEventTypeParser.swift
//
//
// Created by Pete Schwamb on 6/17/23.
//

import Parsing
import LoopKit

struct PumpEventTypeParser: Parser {
var body: some Parser<Substring, PumpEventType> {
"LoopKit.PumpEventType."
OneOf {
for type in PumpEventType.allCases {
String(describing: type).map { type }
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import XCTest
@testable import LoopIssueReportParser
import LoopKit

final class LoopIssueReportParserTests: XCTestCase {
func testParsingSampleLoopV3_2_0() throws {
Expand All @@ -13,7 +14,10 @@ final class LoopIssueReportParserTests: XCTestCase {
XCTAssertEqual(issueReport.generatedAt.description, "2023-03-22 18:12:54 +0000")
XCTAssertEqual(issueReport.buildDetails.appNameAndVersion, "Loop v3.2.0 (3)")
XCTAssertEqual(issueReport.cachedCarbEntries.count, 2)
XCTAssertEqual(issueReport.pumpEvents.count, 2)
XCTAssertEqual(issueReport.cachedDoseEntries.count, 151)
XCTAssertEqual(issueReport.normalizedDoseEntries.count, 151)
XCTAssertEqual(issueReport.entriesForSavingToInsulinDeliveryStore.count, 1)
XCTAssertEqual(issueReport.cachedGlucoseSamples.count, 207)
XCTAssertEqual(issueReport.deviceLogs.count, 256)

Expand All @@ -31,7 +35,6 @@ final class LoopIssueReportParserTests: XCTestCase {
}

func testParsingDoseEntry() {

let text = "DoseEntry(type: LoopKit.DoseType.tempBasal, startDate: 2023-03-21 21:44:49 +0000, endDate: 2023-03-21 21:45:28 +0000, value: 2.0, unit: LoopKit.DoseUnit.unitsPerHour, deliveredUnits: Optional(0.021129271687519168), description: nil, insulinType: Optional(LoopKit.InsulinType.novolog), automatic: Optional(true), manuallyEntered: false, syncIdentifier: Optional(\"b2e6f40441414422b7c8cd1672e0c20e\"), isMutable: false, wasProgrammedByPumpUI: false, scheduledBasalRate: Optional(0.475 IU/hr))"

do {
Expand All @@ -41,6 +44,39 @@ final class LoopIssueReportParserTests: XCTestCase {
print(error)
XCTFail(error.localizedDescription)
}
}

func testPersistedPumpEventParser() {
let text = "PersistedPumpEvent(date: 2023-06-15 14:26:41 +0000, persistedDate: 2023-06-15 14:27:04 +0000, dose: Optional(LoopKit.DoseEntry(type: LoopKit.DoseType.tempBasal, startDate: 2023-06-15 14:26:41 +0000, endDate: 2023-06-15 14:27:04 +0000, value: 0.0, unit: LoopKit.DoseUnit.unitsPerHour, deliveredUnits: Optional(0.0), description: nil, insulinType: Optional(LoopKit.InsulinType.novolog), automatic: Optional(true), manuallyEntered: false, syncIdentifier: Optional(\"a7e2601949dc4e4599ff07eeea3aa473\"), isMutable: true, wasProgrammedByPumpUI: false, scheduledBasalRate: nil)), isUploaded: false, objectIDURL: x-coredata://D8510943-8CBA-4D7B-8398-AE7BCA863599/PumpEvent/p520493, raw: Optional(16 bytes), title: Optional(\"Temp Basal\"), type: Optional(LoopKit.PumpEventType.tempBasal), automatic: Optional(true), alarmType: nil)"
do {
let event = try PersistedPumpEventParser().parse(text)
XCTAssertEqual(true, event.automatic)
} catch {
print(error)
XCTFail(error.localizedDescription)
}
}
//

func testPersistedPumpEventParserWithAlarm() {
let text = "PersistedPumpEvent(date: 2023-06-15 14:26:41 +0000, persistedDate: 2023-06-15 14:27:04 +0000, dose: nil, isUploaded: false, objectIDURL: id://asdf, raw: nil, title: Optional(\"Test Alarm\"), type: Optional(LoopKit.PumpEventType.alarm), automatic: nil, alarmType: Optional(LoopKit.PumpAlarmType.other(\"Custom Alarm\")))"

do {
let event = try PersistedPumpEventParser().parse(text)
XCTAssertEqual(.other("Custom Alarm"), event.alarmType)
} catch {
print(error)
XCTFail(error.localizedDescription)
}
}

func testPumpAlarmTypeParser() {
let text = "LoopKit.PumpAlarmType.other(\"Custom Alarm\")"
XCTAssertEqual(.other("Custom Alarm"), try PumpAlarmTypeParser().parse(text))
}

func testDoseTypeParser() {
XCTAssertEqual(.bolus, try DoseTypeParser().parse("LoopKit.DoseType.bolus"))
}

}
Loading

0 comments on commit fc058d2

Please sign in to comment.