Search code examples
androidgoogle-apigoogle-fit

Retrieve HR-bpm with Google-Fit sensor api


I am using an external device which is suppose to send TYPE_HEART_RATE_BPM to the SENSORS_API. I can retrieve steps with this code:

Client

mClient = new GoogleApiClient.Builder(ApLifeAid.getAppContext())
            .addApi(Fitness.SENSORS_API)
            .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ))
            .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

Request

SensorRequest request = new SensorRequest.Builder()
            .setDataType(DataType.TYPE_STEP_COUNT_DELTA)
            .setSamplingRate(1, TimeUnit.SECONDS)
            .build();

And then using Fitness.SensorsApi.add(mClient, request, this);. In this case this is a class dedicated for sensor api in a service.

But I can't seem to get any values at all, onDataPoint() does not run, when I change my request to:

SensorRequest request = new SensorRequest.Builder()
            .setDataType(DataType.TYPE_HEART_RATE_BPM)
            .setSamplingRate(1, TimeUnit.SECONDS)
            .build();

If anybody knows what the problem is please tell me. And if you can see anything else that is weird in my code please tell me that too.

Thanks!


Solution

  • I found a solution. Apparently I need to find and then register the source I want the data to come from.

    so I still use the "same" construction of the client, requests etc. but instead of using SensorsApi.add I use findDataSources. (Also, FITNESS_BODY_READ seemed more accurate and works well)

    private void buildSensors() {
        mClient = new GoogleApiClient.Builder(ApLifeAid.getAppContext())
                .addApi(Fitness.SENSORS_API)
                .addScope(new Scope(Scopes.FITNESS_BODY_READ))
                .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ))
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    
        DataSourcesRequest dataSourcesRequest = new DataSourcesRequest.Builder()
                .setDataTypes(DataType.TYPE_HEART_RATE_BPM/*,
                        DataType.TYPE_STEP_COUNT_DELTA*/)
                .setDataSourceTypes(DataSource.TYPE_RAW) // data type, raw or derived?
                .build();
    
        Fitness.SensorsApi.findDataSources(mClient, dataSourcesRequest).setResultCallback(this);
    }
    

    The setResultCallback(this) then calls the following where I find an eligible source and add a listener and a sampling rate for it.

    @Override
    public void onResult(DataSourcesResult dataSourcesResult) {
        // On New Source Result
        for (final DataSource dataSource : dataSourcesResult.getDataSources()) {
    
            // Request updates from this source, samplingRate
            SensorRequest sensorRequest = new SensorRequest.Builder()
                    .setDataSource(dataSource) // Optional but recommended for custom data sets.
                    .setDataType(dataSource.getDataType()) // Can't be omitted.
                    .setSamplingRate(1, TimeUnit.SECONDS)
                    .build();
    
            Log.i(TAG, "Fitness.SensorsApi.add for " + dataSource.toString() + " and type " + dataSource.getDataType().getName());
            Fitness.SensorsApi.add(mClient, sensorRequest, this)
                    //Can be removed later
                    .setResultCallback(new ResultCallback<Status>() {
                        @Override
                        public void onResult(Status status) { // This might be important later on "Cannot register listener to source"
                            if (status.isSuccess()) {
                                Log.i(TAG, "Listener registered!");
                            } else {
                                Log.e(TAG, "Unable to register listener for source: " + dataSource.toString());
                            }
                        }
                    });
        }
    }
    

    This is now the simplest and cleanest way of reading heart rate that I've found ;)