-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathInterfaceController.swift
332 lines (290 loc) · 11.9 KB
/
InterfaceController.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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
//
// InterfaceController.swift
// DUInterrupt WatchKit Extension
//
// Created by Aditya Bose on 2/24/19.
// Copyright © 2019 Aditya Bose. All rights reserved.
//
import WatchKit
import WatchConnectivity
import Foundation
import HealthKit
import Dispatch
class InterfaceController: WKInterfaceController, HKWorkoutSessionDelegate, WorkoutManagerDelegate {
//private let wc_session = WCSession.default
private let wcSession = WCSession.default
var timerTest = Timer()
var counterTest = 0.0
var bruh = 0.0
var ticker = true
@IBOutlet var heartRateLabel: WKInterfaceLabel!
@IBOutlet var ecgImage: WKInterfaceImage!
@IBOutlet var button: WKInterfaceButton!
let healthStore = HKHealthStore()
let heartRateUnit = HKUnit(from: "count/min")
let heartRateSampleType = HKObjectType.quantityType(forIdentifier: .heartRate)
let workoutConfiguration = HKWorkoutConfiguration()
var workoutActive = false
var session: HKWorkoutSession?
var currentQuery: HKQuery?
var heartRate: Double = -1
var wristRaised = false
let workoutManager = WorkoutManager()
var active = false
var gravityStr = ""
var attitudeStr = ""
var userAccelStr = ""
var rotationRateStr = ""
var timer = Timer()
var counter = 0.0
// MARK: Interface Properties
@IBOutlet weak var titleLabel: WKInterfaceLabel!
@IBOutlet weak var gravityLabel: WKInterfaceLabel!
@IBOutlet weak var userAccelLabel: WKInterfaceLabel!
@IBOutlet weak var rotationLabel: WKInterfaceLabel!
@IBOutlet weak var attitudeLabel: WKInterfaceLabel!
override init() {
// This method runs FIRST at runtime
print("interfaceController: init")
super.init()
wcSession.delegate = self
wcSession.activate()
print("wcSession activated")
workoutManager.delegate = self
workoutConfiguration.activityType = .mixedCardio
workoutConfiguration.locationType = .indoor
}
override func awake(withContext context: Any?) {
super.awake(withContext: context)
// Configure interface objects here.
//heartRateLabel.setText("--")
ecgImage.setImageNamed("ecg_red-")
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
print("About to activate")
guard HKHealthStore.isHealthDataAvailable() == true else { return }
print("health data avail")
guard let quantityType = HKQuantityType.quantityType(forIdentifier: .heartRate) else { return }
print("quantityType init")
let dataTypes = Set(arrayLiteral: quantityType)
healthStore.requestAuthorization(toShare: nil, read: dataTypes) { (success, error) in
if !success { print("healthStore auth req error") }
}
active = true
// On re-activation, update with the cached values.
updateLabels()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
active = false
}
func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
switch toState {
case .running: workoutDidStart()
case .ended: workoutDidEnd()
default: print("unexpected workout state change")
}
}
func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) {
print("workoutSession failure")
}
func workoutDidStart() {
print("workoutDidStart")
// if query in progress, stop
if currentQuery != nil {
healthStore.stop(currentQuery!)
}
// new query
currentQuery = HKObserverQuery(sampleType: heartRateSampleType!, predicate: nil) { (_, _, error) in
if let error = error {
print("currentQuery error: \(error.localizedDescription)")
return
}
self.fetchLatestHeartRateSample() { (sample) in
DispatchQueue.main.async {
let heartRate = sample.quantity.doubleValue(for: self.heartRateUnit)
print("Heart Rate Sample: \(heartRate)")
self.wcSession.transferUserInfo(["message": heartRate])
if self.workoutActive {
self.updateHeartRate(value: heartRate)
}
}
}
}
currentQuery != nil ? healthStore.execute(currentQuery!) : print("error: currentQuery nil")
}
func workoutDidEnd() {
print("workoutDidEnd")
heartRateLabel.setText("--")
self.wcSession.transferUserInfo(["message": 000])
heartRate = -1
}
func fetchLatestHeartRateSample(completionHandler: @escaping (_ sample: HKQuantitySample) -> Void) {
guard let sampleType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate) else {
return
}
let predicate = HKQuery.predicateForSamples(withStart: Date.distantPast, end: Date(), options: .strictEndDate)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: [sortDescriptor]) { (_, results, error) in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
if (results?.isEmpty)! { print("empty results array"); return }
completionHandler(results?[0] as! HKQuantitySample)
}
healthStore.execute(query)
}
func updateHeartRate(value: Double) {
self.heartRateLabel.setText(String(Int(value)))
// update animation if HR moves outside of current bounds
let hrRange = heartRate - 3...heartRate + 3
if !hrRange.contains(value) {
heartRate = value
ecgAnimation()
}
}
func ecgAnimation() {
print("animating")
if 30...210 ~= heartRate {
//new animation with updated HR
ecgImage.stopAnimating()
ecgImage.startAnimatingWithImages(in: NSMakeRange(1, 130), duration: 60.0/heartRate, repeatCount: 0)
} else {
ecgImage.stopAnimating()
}
}
@IBAction func didTouchStartButton() {
if self.workoutActive {
// finish the current session
workoutActive = false
button.setTitle("Start")
heartRateLabel.setText("--")
ecgImage.stopAnimating()
session?.stopActivity(with: Date())
session?.end()
} else {
// start a new session
workoutActive = true
button.setTitle("Stop")
// Configure the workout session.
do {
session = try HKWorkoutSession(healthStore: healthStore, configuration: workoutConfiguration)
session?.delegate = self
} catch {
fatalError("Failed to create a workout session object")
}
session?.startActivity(with: Date())
}
}
// MARK: Interface Bindings
func didUpdateTimerTest(_ manager: WorkoutManager, timerTest: Timer, counterTest: Double) {
DispatchQueue.main.async {
self.timerTest = timerTest
self.counterTest = counterTest
}
}
var doit = false
@IBAction func start() {
titleLabel.setText("Tracking...")
//self.wcSession.transferUserInfo(["reflex" : 7])
doit = false
workoutManager.startTest()
//print(deviceMotion.attitude.pitch);
}
@IBAction func stop() {
titleLabel.setText("Stopped Recording")
workoutManager.stopWorkout()
print("Workout stopped")
timerTest.invalidate();
print(counter)
}
@objc func UpdateTimer() {
//let reaction_time = "Time: "
if(ticker){
let recorded_time = (String)(counterTest)
let pretty_string = ("Time: \(recorded_time)")
self.titleLabel.setText(pretty_string)
counterTest = counterTest + 0.1
}
else{
self.titleLabel.setText("DONE")
self.titleLabel.setText((String)(counterTest))
self.wcSession.transferUserInfo(["reflex" : (Int)(counterTest)])
}
//timeLabel.text = String(format: "%.1f", counter)
}
// MARK: WorkoutManagerDelegate
func didUpdateMotion(_ manager: WorkoutManager, gravityStr: String, rotationRateStr: String, userAccelStr: String, attitudeStr: String) {
DispatchQueue.main.async {
print("IN didUpdate motion")
print("GRAVBONG", gravityStr)
let abc = gravityStr.components(separatedBy: " ")
print("components", gravityStr.components(separatedBy: " "))
print("z-value", abc[(abc.firstIndex(of: "Z") ?? 0) + 5])
self.gravityStr = gravityStr
self.userAccelStr = userAccelStr
self.rotationRateStr = rotationRateStr
self.attitudeStr = attitudeStr
self.updateLabels();
print("IN UPDATE, WRIST RAISED: ", self.wristRaised)
self.titleLabel.setText((String)(self.counterTest))
if(abc[(abc.firstIndex(of: "Z") ?? 0) + 5] == "-0.3"){
print("IN FIRST IF")
self.wristRaised = true;
self.titleLabel.setText("STARTING TIMER")
self.timerTest = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.UpdateTimer), userInfo: nil, repeats: true)
}
if(abc[(abc.firstIndex(of: "Z") ?? 0) + 5] == "-1.0"){
if(self.wristRaised){
self.wristRaised = false
self.titleLabel.setText((String)(self.counterTest))
self.button.setTitle((String)(self.wristRaised))
print("IN SECOND")
self.workoutManager.stopWorkout()
self.titleLabel.setText("Stopped workout")
self.titleLabel.setText((String)(self.counterTest))
self.timerTest.invalidate()
//print("Counter: ", self.counterTest)
self.timerTest.invalidate()
self.ticker = false
self.titleLabel.setText("INvalidated")
}
}
}
}
// MARK: Convenience
func updateLabels() {
if active {
gravityLabel.setText(gravityStr)
userAccelLabel.setText(userAccelStr)
rotationLabel.setText(rotationRateStr)
attitudeLabel.setText(attitudeStr)
}
}
}
/* watch delegation */
extension InterfaceController: WCSessionDelegate {
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
if activationState == .activated {
print("wcSession: activated")
} else {
guard let error = error else { return }
print("wcSession: activation error - \(error.localizedDescription)")
}
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
print("wcSession: message received")
if let _ = message["startWorkout"] {
print("starting workout")
didTouchStartButton()
} else { print("unknown message") }
}
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
print("wcSession: userInfo received")
print(userInfo)
}
}