SensorKit example / How to obtain data

Hi, We are a research team that is just beginning to use SensorKit to collect data for our research. Currently, We've gotten far enough through the process of setting up and using sensorKit to be able to start collecting data through the OS and we've created an SRFetchRequest, but we're just unsure of how to actually go about retrieving the data in a usable form and being able to write it to a file or upload it to a server. We're specifically lost when it comes to SRFetchResult and what to do with that. If anyone was able to provide an example from their own code/somewhere we can find an example, or anything that might help, that would be greatly appreciated.

Thank you!

Replies

Not sure this will work exactly - but this is the basic gist after gutting our model to an MVP. This assumes you've already requested permissions. You have to create a SRSensorReader with the sensor you want. Set a delegate for the reader's callbacks. Request the devices for the sensor. On the callback with devices, then you can request samples by creating an SRFetchRequest. Then when the data starts coming back, then you have to cast the sample into a type you're looking for and then extract the data from the sample. FWIW, the readers do not appear to be threadsafe - i.e., you can only be working with one reader at a time - don't attempt to read in parallel from different sensors.

class SensorKitDataExtractor : NSObject {
    
    let reader: SRSensorReader
    let fetchRequest = SRFetchRequest()
    
    init() {
        reader = SRSensorReader(sensor: .ambientLightSensor)
        reader.delegate = self
        reader.fetchDevices()
    }
}

extension SensorKitDataExtractor : SRSensorReaderDelegate {
    func sensorReader(_ reader: SRSensorReader, didFetch devices: [SRDevice]) {
        fetchSamples(device: devices.first(where: { $0.model == self.queryRule.sensorType.device.rawValue }))
    }
    
    func sensorReader(_ reader: SRSensorReader, fetchDevicesDidFailWithError error: Error) {
        print("Error fetching devices: \(error)")
    }
    
    func sensorReader(_ reader: SRSensorReader, fetching fetchRequest: SRFetchRequest, didFetchResult result: SRFetchResult<AnyObject>) -> Bool {
        switch result.sampleObject {
        case let lightSample as SRAmbientLightSample:
            // do something with the data
        default:
            print("Unhandled sample type: \(result.sampleObject)")
            return false
        }
        return true
    }

    func sensorReader(_ reader: SRSensorReader, didCompleteFetch fetchRequest: SRFetchRequest) {
        print("Reader did complete fetch")
    }
    
    func sensorReader(_ reader: SRSensorReader, fetching fetchRequest: SRFetchRequest, failedWithError error: Error) {
        print("Reader fetch failed: \(error)")
    }
    
    private func fetchSamples(device: SRDevice?) {
        guard let device = device else {
            print("No device found for this sensor")
            return
        }
        fetchRequest.device = device
        fetchRequest.from = SRAbsoluteTime.fromCFAbsoluteTime(_cf: fromDate)
        fetchRequest.to = SRAbsoluteTime.fromCFAbsoluteTime(_cf: toDate)
        reader.fetch(fetchRequest)
    }
}

what entitlement/permission did you have to request in order to access this feature?

For the ambient light in this example, the entitlement looks like this:

...
	<key>com.apple.developer.sensorkit.reader.allow</key>
	<array>
		<string>ambient-light-sensor</string>
	</array>
...

@eschramm Hello, I have a question about fetchRequest. For the optical environment sensor, I need real-time data to judge whether the current is dark or bright. What time period should be passed for the fetchRequest from and to to get effective values? Please help me

I'm sorry @tongxingx, but I don't think you are able to get real-time data for ambient light, at least from SensorKit. I believe Apple purposefully makes data available after 2 hours for privacy.