Search code examples
iosswiftnspredicatehealthkithkhealthstore

Getting all steps of today but truncating manually added steps, from Health kit using swift


I am getting today steps from healthkit using below code.

    func retrieveStepCount(completion: (stepRetrieved: Double) -> Void) {
         let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount) 

    let date = NSDate()
    let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
    let newDate = cal.startOfDayForDate(NSDate())

    let predicate = HKQuery.predicateForSamplesWithStartDate(newDate, endDate: NSDate(), options: .None) // Our search predicate which will fetch all steps taken today
    let interval: NSDateComponents = NSDateComponents()
    interval.day = 1

    let query = HKStatisticsCollectionQuery(quantityType: type!, quantitySamplePredicate: predicate, options: .CumulativeSum, anchorDate: newDate as NSDate, intervalComponents:interval as NSDateComponents)

    query.initialResultsHandler = { query, results, error in

        if error != nil {

            print("Something went Wrong")
            return
        }
        if let myResults = results{
            myResults.enumerateStatisticsFromDate(newDate, toDate: NSDate()) {
                statistics, stop in
                if let quantity = statistics.sumQuantityForSource(HKSource.defaultSource()) {

                    let steps = quantity.doubleValueForUnit(HKUnit.countUnit())

                    print("Steps = \(Int(steps))")
                    completion(stepRetrieved: steps)
                }
            }
        }
    }
    executeQuery(query)
}

Now lets say I have these steps in total

enter image description here

From which I have some steps which were auto detected by device. and some were added by some other application to heathkit.

enter image description here

I do want both of them and I m getting both of them but the problem comes when user some some manuall steps to the healthkit.

enter image description here

I do not want to get these manually added steps. So basically I want to get (5,793 - 2300) = 3493 steps.

How can I do that ? I have tried to get name of HKSource I do know that when user enter steps manually, name of the source is "Health" but how do I filter steps on this base ? Please guide me about this and what am I missing here ? Thanks in advance


Solution

  • This might not be the best solution, But I believe it will work. What you can do is get all the steps which were added manually using HKSampleQuery. here is an example.

     func todayManuallyAddedStepsSteps(completion: (Double, NSError?) -> () )
        {
    
        let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount) // The type of data we are requesting
    
        let date = NSDate()
        let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
        let newDate = cal.startOfDayForDate(date)
        let predicate = HKQuery.predicateForSamplesWithStartDate(newDate, endDate: NSDate(), options: .None) // Our search predicate which will fetch all steps taken today
    
        // The actual HealthKit Query which will fetch all of the steps and add them up for us.
    
        let query = HKSampleQuery(sampleType: type!, predicate: predicate, limit: 0, sortDescriptors: nil) { query, results, error in
            var steps: Double = 0
    
            if results?.count > 0
            {
                for result in results as! [HKQuantitySample]
                {
                    print("Steps \(result.quantity.doubleValueForUnit(HKUnit.countUnit()))")
                    print()
    
                    // checking and adding manually added steps
                    if result.sourceRevision.source.name == "Health" {
                        // these are manually added steps
                        print(result.sourceRevision.source.name)
                        print("Steps \(result.quantity.doubleValueForUnit(HKUnit.countUnit()))")
                        steps += result.quantity.doubleValueForUnit(HKUnit.countUnit())
                    }
                    else{
                        // these are auto detected steps which we do not want from using HKSampleQuery
                    }
                }
                print(steps)
            }
            completion(steps, error)
        }
    
        executeQuery(query)
    }
    

    and then get the today total steps using HKStatisticsCollectionQuery like below

    func TodayTotalSteps(completion: (stepRetrieved: Double) -> Void) {
    
        let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount) // The type of data we are requesting
    
        let calendar = NSCalendar.currentCalendar()
        let interval = NSDateComponents()
        interval.day = 1
    
        let anchorComponents = calendar.components([.Day , .Month , .Year], fromDate: NSDate())
        anchorComponents.hour = 0
        let anchorDate = calendar.dateFromComponents(anchorComponents)
    
        let stepsQuery = HKStatisticsCollectionQuery(quantityType: type!, quantitySamplePredicate: nil, options: .CumulativeSum, anchorDate: anchorDate!, intervalComponents: interval)
    
        stepsQuery.initialResultsHandler = {query, results, error in
            let endDate = NSDate()
            let startDate = calendar.dateByAddingUnit(.Day, value: 0, toDate: endDate, options: [])
            if let myResults = results{  myResults.enumerateStatisticsFromDate(startDate!, toDate: endDate) { statistics, stop in
                if let quantity = statistics.sumQuantity(){
                    let date = statistics.startDate
                    let steps = quantity.doubleValueForUnit(HKUnit.countUnit())
                    print("\(date): steps = \(steps)")
                    completion(stepRetrieved: steps)
                }
                }
            }
        }
        executeQuery(stepsQuery)
    }
    

    Now you can call these methods and subtract manually added steps like below

    todayManuallyAddedSteps({ (steps , error) in
                if error != nil{
                    print(error)
                }
                else{
                    // truncating manuall steps
                    TodayTotalSteps({ (stepRetrieved) in
                        // steps without manuall steps
                        print(Int(stepRetrieved - steps))
    
                    })
                }
            })