-
-
Notifications
You must be signed in to change notification settings - Fork 19
/
Electrocardiogram.swift
236 lines (227 loc) · 9.23 KB
/
Electrocardiogram.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
//
// Electrocardiogram.swift
// HealthKitReporter
//
// Created by Victor on 25.09.20.
//
import HealthKit
@available(iOS 14.0, *)
public struct Electrocardiogram: Identifiable, Sample {
public struct Harmonized: Codable {
public let averageHeartRate: Double?
public let averageHeartRateUnit: String
public let samplingFrequency: Double
public let samplingFrequencyUnit: String
public let classification: String
public let symptomsStatus: String
public let count: Int
public let voltageMeasurements: [VoltageMeasurement]
public let metadata: Metadata?
init(
averageHeartRate: Double?,
averageHeartRateUnit: String,
samplingFrequency: Double,
samplingFrequencyUnit: String,
classification: String,
symptomsStatus: String,
count: Int,
voltageMeasurements: [VoltageMeasurement],
metadata: Metadata?
) {
self.averageHeartRate = averageHeartRate
self.averageHeartRateUnit = averageHeartRateUnit
self.samplingFrequency = samplingFrequency
self.samplingFrequencyUnit = samplingFrequencyUnit
self.classification = classification
self.symptomsStatus = symptomsStatus
self.count = count
self.voltageMeasurements = voltageMeasurements
self.metadata = metadata
}
}
public struct VoltageMeasurement: Codable {
public struct Harmonized: Codable {
public let value: Double
public let unit: String
}
public let harmonized: Harmonized
public let timeSinceSampleStart: Double
init(harmonized: Harmonized, timeSinceSampleStart: Double) {
self.harmonized = harmonized
self.timeSinceSampleStart = timeSinceSampleStart
}
init(voltageMeasurement: HKElectrocardiogram.VoltageMeasurement) throws {
self.harmonized = try voltageMeasurement.harmonize()
self.timeSinceSampleStart = voltageMeasurement.timeSinceSampleStart
}
}
public let uuid: String
public let identifier: String
public let startTimestamp: Double
public let endTimestamp: Double
public let device: Device?
public let sourceRevision: SourceRevision
public let numberOfMeasurements: Int
public let harmonized: Harmonized
init(
identifier: String,
startTimestamp: Double,
endTimestamp: Double,
device: Device?,
sourceRevision: SourceRevision,
numberOfMeasurements: Int,
harmonized: Harmonized
) {
self.uuid = UUID().uuidString
self.identifier = identifier
self.startTimestamp = startTimestamp
self.endTimestamp = endTimestamp
self.device = device
self.sourceRevision = sourceRevision
self.numberOfMeasurements = numberOfMeasurements
self.harmonized = harmonized
}
init(
electrocardiogram: HKElectrocardiogram,
voltageMeasurements: [Electrocardiogram.VoltageMeasurement]
) throws {
self.uuid = electrocardiogram.uuid.uuidString
self.identifier = ElectrocardiogramType
.electrocardiogramType
.original?
.identifier ?? "HKDataTypeIdentifierElectrocardiogram"
self.startTimestamp = electrocardiogram.startDate.timeIntervalSince1970
self.endTimestamp = electrocardiogram.endDate.timeIntervalSince1970
self.device = Device(device: electrocardiogram.device)
self.numberOfMeasurements = electrocardiogram.numberOfVoltageMeasurements
self.sourceRevision = SourceRevision(sourceRevision: electrocardiogram.sourceRevision)
self.harmonized = try electrocardiogram.harmonize(voltageMeasurements: voltageMeasurements)
}
}
// MARK: - Payload
@available(iOS 14.0, *)
extension Electrocardiogram.Harmonized: Payload {
public static func make(from dictionary: [String: Any]) throws -> Electrocardiogram.Harmonized {
guard
let averageHeartRateUnit = dictionary["averageHeartRateUnit"] as? String,
let samplingFrequency = dictionary["samplingFrequency"] as? NSNumber,
let samplingFrequencyUnit = dictionary["samplingFrequencyUnit"] as? String,
let classification = dictionary["classification"] as? String,
let symptomsStatus = dictionary["symptomsStatus"] as? String,
let count = dictionary["count"] as? Int
else {
throw HealthKitError.invalidValue("Invalid dictionary: \(dictionary)")
}
let averageHeartRate = dictionary["averageHeartRate"] as? NSNumber
let voltageMeasurements = dictionary["voltageMeasurements"] as? [Any]
let metadata = dictionary["metadata"] as? [String: Any]
return Electrocardiogram.Harmonized(
averageHeartRate: averageHeartRate != nil
? Double(truncating: averageHeartRate!)
: nil,
averageHeartRateUnit: averageHeartRateUnit,
samplingFrequency: Double(truncating: samplingFrequency),
samplingFrequencyUnit: samplingFrequencyUnit,
classification: classification,
symptomsStatus: symptomsStatus,
count: count,
voltageMeasurements: voltageMeasurements != nil
? try Electrocardiogram.VoltageMeasurement.collect(from: voltageMeasurements!)
: [],
metadata: metadata?.asMetadata
)
}
}
// MARK: - Factory
@available(iOS 14.0, *)
extension Electrocardiogram {
static func collect(results: [HKSample]) -> [Electrocardiogram] {
var samples = [Electrocardiogram]()
if let electrocardiograms = results as? [HKElectrocardiogram] {
for electrocardiogram in electrocardiograms {
do {
let sample = try Electrocardiogram(
electrocardiogram: electrocardiogram,
voltageMeasurements: []
)
samples.append(sample)
} catch {
continue
}
}
}
return samples
}
}
// MARK: - Payload
@available(iOS 14.0, *)
extension Electrocardiogram: Payload {
public static func make(from dictionary: [String: Any]) throws -> Electrocardiogram {
guard
let identifier = dictionary["identifier"] as? String,
let startTimestamp = dictionary["startTimestamp"] as? NSNumber,
let endTimestamp = dictionary["endTimestamp"] as? NSNumber,
let sourceRevision = dictionary["sourceRevision"] as? [String: Any],
let numberOfMeasurements = dictionary["numberOfMeasurements"] as? Int,
let harmonized = dictionary["harmonized"] as? [String: Any]
else {
throw HealthKitError.invalidValue("Invalid dictionary: \(dictionary)")
}
let device = dictionary["device"] as? [String: Any]
return Electrocardiogram(
identifier: identifier,
startTimestamp: Double(truncating: startTimestamp),
endTimestamp: Double(truncating: endTimestamp),
device: device != nil
? try Device.make(from: device!)
: nil,
sourceRevision: try SourceRevision.make(from: sourceRevision),
numberOfMeasurements: numberOfMeasurements,
harmonized: try Harmonized.make(from: harmonized)
)
}
}
// MARK: - Payload
@available(iOS 14.0, *)
extension Electrocardiogram.VoltageMeasurement: Payload {
public static func make(from dictionary: [String: Any]) throws -> Electrocardiogram.VoltageMeasurement {
guard
let harmonized = dictionary["harmonized"] as? [String: Any],
let timeSinceSampleStart = dictionary["timeSinceSampleStart"] as? NSNumber
else {
throw HealthKitError.invalidValue("Invalid dictionary: \(dictionary)")
}
return Electrocardiogram.VoltageMeasurement(
harmonized: try Electrocardiogram.VoltageMeasurement.Harmonized.make(from: harmonized),
timeSinceSampleStart: Double(truncating: timeSinceSampleStart)
)
}
static func collect(from array: [Any]) throws -> [Electrocardiogram.VoltageMeasurement] {
var measurements = [Electrocardiogram.VoltageMeasurement]()
for element in array {
if let dictionary = element as? [String: Any] {
let measurement = try Electrocardiogram.VoltageMeasurement.make(from: dictionary)
measurements.append(measurement)
}
}
return measurements
}
}
// MARK: - Payload
@available(iOS 14.0, *)
extension Electrocardiogram.VoltageMeasurement.Harmonized: Payload {
public static func make(
from dictionary: [String: Any]
) throws -> Electrocardiogram.VoltageMeasurement.Harmonized {
guard
let value = dictionary["value"] as? NSNumber,
let unit = dictionary["unit"] as? String
else {
throw HealthKitError.invalidValue("Invalid dictionary: \(dictionary)")
}
return Electrocardiogram.VoltageMeasurement.Harmonized(
value: Double(truncating: value),
unit: unit
)
}
}