Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get this the currentStandHour value in Apple Watch iOS?

I want to retrieve the value that indicates whether or not the user has stood this hour. I also want to be able to retrieve the StandHours count for the day.

Here are the Apple links that I've been trying to understand in order get the value from HealthKit. I provide these links to help provide understanding for what I'm looking for and also to help you answer my question.

  • appleStandHour type property: https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/1615539-applestandhour
  • HealthKit category type identifier: https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier
  • HealthKit constants: https://developer.apple.com/documentation/healthkit/healthkit_constants

Bruno's answer is only half of the answer. For example, his standUnit variable is how he pulls the # of hours that the user has stood today. I tested it. Also, I made the assumption that it had to be pulled from within the scope of the summaries variable.

I have found another question on StackOverflow that might provide some clues. I think they managed to pull a value via a HKCategoryTypeIdentifier: Watch os 2.0 beta: access heart beat rate

Here's my attempted code as far as I have been able to get:

import UIKit
import HealthKit
import HealthKitUI

class ViewController: UIViewController {

let hkStoreOnVC : HKHealthStore = HKHealthStore()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    authorizeHealthKit()
    hkTest()
    hkTest2()
}

func authorizeHealthKit() {   //-> Bool {
    print("health kit authorize?")
    
    let healthStore = HKHealthStore()
    
    let objectTypes: Set<HKObjectType> = [
        HKObjectType.activitySummaryType()
    ]
    
    healthStore.requestAuthorization(toShare: nil, read: objectTypes) { (success, error) in
        
        // Authorization request finished, hopefully the user allowed access!
        print("health kit authorized")
    }
}

func hkTest() {
    print("health kit test.")
    
    let calendar = Calendar.autoupdatingCurrent
    
    var dateComponents = calendar.dateComponents(
        [ .year, .month, .day ],
        from: Date()
    )
    
    // This line is required to make the whole thing work
    dateComponents.calendar = calendar
    
    let predicate = HKQuery.predicateForActivitySummary(with: dateComponents)
    
    //----------------------
    
    let query = HKActivitySummaryQuery(predicate: predicate) { (query, summaries, error) in
        print("query")
        guard let summaries = summaries, summaries.count > 0
            else {
                print("no summaries")
                return
        }
        
        // Handle data
        
        for thisSummary in summaries {
            //                print("for each summary")
            let standUnit = HKUnit.count()
            let standHours = thisSummary.appleStandHours.doubleValue(for: standUnit)
            print("stand hours \(standHours)")
        }//end for
    } //end query
}

func hkTest2() {
    var isEnabled = true
    print ("authorize health kit" )
    if HKHealthStore.isHealthDataAvailable() {
        let stepsCount  = NSSet(objects: HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount ) )
        
        for thisValue in stepsCount {
            //              thisValue.
            print("thisValue: \(thisValue)")
        }

        print(" authorize HK - steps count \(stepsCount) ")
    }
    
    // Create the date components for the predicate
    guard let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian) else {
        fatalError("*** This should never fail. ***")
    }
    
    let endDate = NSDate()
    
    guard let startDate = calendar.date(byAdding: .day, value: -7, to: endDate as Date, options: []) else {
        fatalError("*** unable to calculate the start date ***")
    }
    
    let units: NSCalendar.Unit = [.day, .month, .year, .era]
    
    var startDateComponents = calendar.components(units, from: startDate)
    startDateComponents.calendar = calendar as Calendar
    
    var endDateComponents = calendar.components(units, from: endDate as Date)
    endDateComponents.calendar = calendar as Calendar
    
    // Create the predicate for the query
    let summariesWithinRange =  HKQuery.predicate(forActivitySummariesBetweenStart: startDateComponents, end: endDateComponents)
    
    // Build the query
    let query = HKActivitySummaryQuery(predicate: summariesWithinRange) { (query, summaries, error) -> Void in
        guard let activitySummaries = summaries else {
            guard let queryError = error else {
                fatalError("*** Did not return a valid error object. ***")
            }
            
            // Handle the error here...
            return
        }
        
        for thisSummary in activitySummaries {
            //                print("for each summary")
            let standUnit = HKUnit.count()
            let standHours = thisSummary.appleStandHours.doubleValue(for: standUnit)
            //                let stoodThisHourMaybe = thisSummary.appleStandHours.categ //doubleValue(for: standUnit)
            //\(thisSummary.description) //stand unit _\(standUnit)_
            print("day#\(thisSummary.dateComponents(for: calendar as Calendar).day) stand hours \(standHours)  ")
        }//end for
        
        // Do something with the summaries here...
        
        for thisItem in activitySummaries {
            //thisItem.appleStandHours
            
            print("abc \( thisItem.appleStandHours ) " )
        }//end for
    }
    
    // Run the query
    let hkStore : HKHealthStore = HKHealthStore()
    hkStore.execute(query)
    
    //***
    let aStandHour =  HKCategoryType.categoryType(forIdentifier: .appleStandHour)
   
    // This is the type you want updates on. It can be any health kit type, including heart rate.
    //            let distanceType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.distanceWalkingRunning)
    
    // Match samples with a start date after the workout start
    //        let predicate =  .predicat //( , endDate: nil, options: .None)
    //        let theDate : Date =
    let thepredicate =  HKQuery.predicateForCategorySamples(with: .greaterThanOrEqualTo, value: 0) //.predicateForSamplesWithStartDate(startDate , endDate: nil, options: .None)
    //        predicate
    
    //        let predicate = .  //(theDate , endDate: nil, options: .None)
    let hka : HKQueryAnchor = HKQueryAnchor(fromValue: 0)
    let sHourQuery = HKAnchoredObjectQuery(type: aStandHour!, predicate: thepredicate, anchor: hka, limit: 0, resultsHandler: { ( query, samples, deletedObjects, anchor, error) -> Void in
        // Handle when the query first returns results
        // TODO: do whatever you want with samples (note you are not on the main thread)
        print("getting here A?")
        //            for thisSample in samples! {
        //                print("A smpLType \(thisSample.sampleType) thisSample \(thisSample)")
        //            }
    })
    
    // This is called each time a new value is entered into HealthKit (samples may be batched together for efficiency)
    
    sHourQuery.updateHandler = { (query, samples, deletedObjects, anchor, error) -> Void in
        // Handle update notifications after the query has initially run
        // TODO: do whatever you want with samples (note you are not on the main thread)
        print("getting here B?")
        for thisSample in samples! {
            print("B smpLType \(thisSample.sampleType) thisSample \(thisSample)")
        }
    }
    
    // Start the query
    self.hkStoreOnVC.execute(sHourQuery)
    //***
    
}//end func

func myCompletionHandler(bTest: Bool ) {
    print("my completion handler")
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

}//end viewController Class

Here's the code output - the log never prints to "getting here b?":

health kit authorize?
health kit test.
authorize health kit
health kit authorized
thisValue: HKQuantityTypeIdentifierStepCount
 authorize HK - steps count {(
    HKQuantityTypeIdentifierStepCount
)} 
2017-11-04 19:18:30.100562-0500 watchapptest[25048:4695625] refreshPreferences: HangTracerEnabled: 0
2017-11-04 19:18:30.100600-0500 watchapptest[25048:4695625] refreshPreferences: HangTracerDuration: 500
2017-11-04 19:18:30.100615-0500 watchapptest[25048:4695625] refreshPreferences: ActivationLoggingEnabled: 0 ActivationLoggingTaskedOffByDA:0
getting here A?
day#Optional(28) stand hours 14.0  
day#Optional(29) stand hours 14.0  
day#Optional(30) stand hours 14.0  
day#Optional(31) stand hours 14.0  
day#Optional(1) stand hours 16.0  
day#Optional(2) stand hours 13.0  
day#Optional(3) stand hours 15.0  
day#Optional(4) stand hours 13.0  
abc 14 count 
abc 14 count 
abc 14 count 
abc 14 count 
abc 16 count 
abc 13 count 
abc 15 count 
abc 13 count 
like image 908
Neo42 Avatar asked Oct 16 '17 00:10

Neo42


1 Answers

I am new to HealthKit, so there probably is a nicer way to do this. But this seems to work for me. I check the actually standing minutes and call the completion handler with minutes > 0.

    private let store = HKHealthStore()

    func askPermission() {
        let standType = HKQuantityType.quantityType(forIdentifier: .appleStandTime)!
        store.requestAuthorization(toShare: [], read: [standType], completion: { (success, error) in
            self.didStandThisHour { (didStand) in
                print("Did stand this hour: \(didStand)")
            }
        })
    }

    func didStandThisHour(_ didStand: @escaping (Bool) -> ()) {
        let store = HKHealthStore()
        let calendar = Calendar.autoupdatingCurrent
        let dateComponents = calendar.dateComponents([.year, .month, .day, .hour], from: Date())
        let endDate = Date()
        let startDate = calendar.date(from: dateComponents)!
        let standTime = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.appleStandTime)!
        var interval = DateComponents()
        interval.hour = 1
        let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
        let query = HKStatisticsCollectionQuery(quantityType: standTime, quantitySamplePredicate: predicate, options: [.cumulativeSum], anchorDate: startDate, intervalComponents:interval)
        query.initialResultsHandler = { query, results, error in
            guard error == nil, let myResults = results else {
                fatalError("Something is wrong with HealthKit link")
            }
            myResults.enumerateStatistics(from: startDate, to: endDate, with: { (statistics, stop) in
                guard let quantity = statistics.sumQuantity() else {
                    didStand(false)
                    return
                }
                let minutes = quantity.doubleValue(for: .minute())
                didStand(minutes > 0)
            })
        }
        store.execute(query)
    }
like image 95
dacvrijma Avatar answered Sep 20 '22 17:09

dacvrijma