Skip to content

Commit

Permalink
HRM: add value filtering and improve average heart rate display
Browse files Browse the repository at this point in the history
  • Loading branch information
liamcharger committed Oct 2, 2024
1 parent 72b4af4 commit 451122b
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 9 deletions.
Binary file modified .DS_Store
Binary file not shown.
42 changes: 37 additions & 5 deletions InfiniLink/BLE/BLEUpdateHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Created by Alex Emry on 10/1/21.
//
//


import CoreBluetooth
import CoreData
Expand All @@ -14,17 +14,22 @@ import SwiftUI
struct BLEUpdatedCharacteristicHandler {
@ObservedObject var healthKitManager = HealthKitManager.shared

@FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \ChartDataPoint.timestamp, ascending: true)], predicate: NSPredicate(format: "chart == 0"))
private var chartPoints: FetchedResults<ChartDataPoint>

let bleManager = BLEManager.shared
let bleManagerVal = BLEManagerVal.shared
let weatherController = WeatherController()
let ble_fs = BLEFSHandler.shared

@AppStorage("filterHRMValues") var filterHRM: Bool = false
@AppStorage("lastHRMValueTimestamp") var lastHRMValueTimestamp: Double = 0

// function to translate heart rate to decimal, copied straight up from this tut: https://www.raywenderlich.com/231-core-bluetooth-tutorial-for-ios-heart-rate-monitor#toc-anchor-014
func heartRate(from characteristic: CBCharacteristic) -> Int {
guard let characteristicData = characteristic.value else { return -1 }
let byteArray = [UInt8](characteristicData)

let firstBitValue = byteArray[0] & 0x01
if firstBitValue == 0 {
// Heart Rate Value Format is in the 2nd byte
Expand All @@ -44,10 +49,30 @@ struct BLEUpdatedCharacteristicHandler {
MusicController.shared.controlMusic(controlNumber: Int(musicControl[0]))
case bleManagerVal.cbuuidList.hrm:
let bpm = heartRate(from: characteristic)
let dataPoints = ChartManager.shared.convert(results: chartPoints)
let lastDataPoint = dataPoints.last

bleManagerVal.heartBPM = Double(bpm)
healthKitManager.writeHeartRate(date: Date(), dataToAdd: bleManagerVal.heartBPM)

if bpm != 0 {
ChartManager.shared.addItem(dataPoint: DataPoint(date: Date(), value: Double(bpm), chart: ChartsAsInts.heart.rawValue))
let currentTime = Date().timeIntervalSince1970
let timeDifference = currentTime - lastHRMValueTimestamp

if let referenceValue = lastDataPoint?.value, filterHRM && (bpm > 40 && bpm < 210) {
let isWithinRange = abs(referenceValue - bleManagerVal.heartBPM) <= 25

if isWithinRange {
updateHeartRate(bpm: bpm)
} else {
if timeDifference <= 10 {
updateHeartRate(bpm: bpm)
} else {
print("Abnormal value, should be filtered")
}
}
} else {
updateHeartRate(bpm: bpm)
}
}
case bleManagerVal.cbuuidList.bat:
guard let value = characteristic.value else {
Expand All @@ -73,7 +98,7 @@ struct BLEUpdatedCharacteristicHandler {

let currentSteps = value
let newSteps = Double(bleManagerVal.stepCount)

let stepsToAdd = newSteps - currentSteps!
healthKitManager.writeSteps(date: Date(), stepsToAdd: stepsToAdd)
}
Expand All @@ -88,4 +113,11 @@ struct BLEUpdatedCharacteristicHandler {
break
}
}

func updateHeartRate(bpm: Int) {
let currentTime = Date().timeIntervalSince1970
lastHRMValueTimestamp = currentTime
healthKitManager.writeHeartRate(date: Date(), dataToAdd: bleManagerVal.heartBPM)
ChartManager.shared.addItem(dataPoint: DataPoint(date: Date(), value: Double(bpm), chart: ChartsAsInts.heart.rawValue))
}
}
13 changes: 11 additions & 2 deletions InfiniLink/Core/Heart/HeartView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,17 @@ struct HeartView: View {
.imageScale(.large)
Text(String(format: "%.0f", bleManagerVal.heartBPM) + " " + NSLocalizedString("bpm", comment: "BPM"))
.font(.system(size: 32).weight(.bold))
Text("Avg: " + String(Int(vDSP.mean(dataPoints.map({ $0.value })))) + " " + NSLocalizedString("bpm", comment: "BPM"))
.foregroundColor(.primary)
if dataPoints.count >= 5 {
let points = dataPoints.map { $0.value }.filter { $0 > 50 && $0 < 200 }

if !points.isEmpty {
let meanValue = vDSP.mean(points)
let formattedAvg = String(Int(meanValue))

Text("Avg: " + formattedAvg + " " + NSLocalizedString("bpm", comment: "BPM"))
.foregroundColor(.primary)
}
}
}
.foregroundColor(.red)
}
Expand Down
6 changes: 4 additions & 2 deletions InfiniLink/Core/Weather/WeatherController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,10 @@ class WeatherController: NSObject, ObservableObject, CLLocationManagerDelegate {
DebugLogManager.shared.debug(error: debugDescription, log: .app, date: Date())
}

bleManagerVal.weatherInformation.icon = Int(getIcon_NWS(description: json["features"][idx]["properties"]["textDescription"].stringValue))
bleManagerVal.weatherInformation.shortDescription = json["features"][idx]["properties"]["textDescription"].stringValue
DispatchQueue.main.async {
self.bleManagerVal.weatherInformation.icon = Int(self.getIcon_NWS(description: json["features"][idx]["properties"]["textDescription"].stringValue))
self.bleManagerVal.weatherInformation.shortDescription = json["features"][idx]["properties"]["textDescription"].stringValue
}
break
}
}
Expand Down

0 comments on commit 451122b

Please sign in to comment.