Client-side #Python code to summarize data collected in the #GoogleFit data store

 

heart

The Google Fit data store provides a single location to store data collected from a wide variety of health and exercise inputs. The data can be entered from directly from devices such as Android watches, phones or directly on the https://fit.google.com/ web page. This web page also contains high level graphic summaries of recent activities.

However, the site gives no insight into the data series and the formats for these series and therefore offers no way to further analyze or reformat your performance information. This post presents a programmatic way to access the data from the client side using the RESTful interface to the database. It is intended as a next step toward automating the processes presented in the interactive web page: https://developers.google.com/oauthplayground/

This python code runs on Windows 7 and reads the data base using curl, which needs to be installed on your system. You will also need to be familiar with setting creating a project that links to your Google Fit data store. This is outlined in https://developers.google.com/fit/.

To understand the code, you will also need to know the interactions required under OAuth2.0, as described in https://developers.google.com/accounts/docs/OAuth2, to give you access to the data.

The initial part of the code are functions to gain access to the data protected using OAuth2.0. The second part contains code to generate summary statistics for the various data sources.

1. OAuth2.0 access functions. These functions use the information you provide about the project and the permissions you request to give you access to the data.


import json
import pprint
import subprocess
import datetime
import time
import calendar

def getUserCode(clientId, scope):
    step1CodeTemplate= 'curl -d "client_id=<clientId>' +\
    '&scope=<scope>" https://accounts.google.com/o/oauth2/device/code'
    step1= step1CodeTemplate.replace('<clientId>',clientId).replace('<scope>',scope)
    allSources = getAllJSON(step1)
    pprint.pprint(allSources)
    return allSources['device_code'], allSources['user_code'], allSources['verification_url']

def getRefreshToken(clientId, clientSecret, deviceCode):
    step2CodeTemplate = 'curl -d "client_id=<clientId>&client_secret=<clientSecret>' + \
    '&code=<deviceCode>&grant_type=http://oauth.net/grant_type/device/1.0" ' + \
    'https://accounts.google.com/o/oauth2/token'
    step2= step2CodeTemplate.replace('<clientId>',clientId) \
    .replace('<clientSecret>',clientSecret) \
    .replace('<deviceCode>',deviceCode)
    pprint.pprint(step2)
    allSources = getAllJSON(step2)
    pprint.pprint(allSources)
    return allSources['access_token'], allSources['refresh_token']

def getRefreshedAccessCode(clientId, clientSecret, refreshToken):
    step3CodeTemplate = 'curl -d "client_id=<clientId>&client_secret=<clientSecret>' + \
    '&refresh_token=<refreshToken>' + \
    '&grant_type=refresh_token" https://accounts.google.com/o/oauth2/token'
    step3 = step3CodeTemplate.replace('<clientId>',clientId) \
    .replace('<clientSecret>',clientSecret) \
    .replace('<refreshToken>',refreshToken)
    return getTagValue(step3, 'access_token')

2. These functions are called with the data obtained from your Google Fit credentials from https://console.developers.google.com. The following sequences of operations is used to create credentials to access your data:

  • go to https://console.developers.google.com and navigating to the project you have set up
  • select the credentials menu item
  • create a new client Id
  • within the popup window select Installed Application
  • select Other within Installed Application Type
  • get the clientId and clientSecret from the ‘Client ID for native application’
  • enter the clientId and clientSecret in the python code below and run it

 

credentials page

clientId = '<enter the clientId that you obtained above surrounded by single quotes>'
clientSecret = '<enter the clientSecret here surrounded by single quotes>'

# set the scope of the permissions selected - for Google fit, use the following scope

scope = 'email profile+ \
https://www.googleapis.com/auth/fitness.activity.read+ \
https://www.googleapis.com/auth/fitness.activity.write+ \
https://www.googleapis.com/auth/fitness.body.read+ \
https://www.googleapis.com/auth/fitness.body.write+ \
https://www.googleapis.com/auth/fitness.location.read+ \
https://www.googleapis.com/auth/fitness.location.write'

# get user code to be entered into the verification web site

deviceCode, userCode, verificationUrl = getUserCode(clientId, scope)
print('\n******  go  to page ' + verificationUrl + ' and enter ' + userCode + " *****\n")

 

accessesRequested


accessApproved

3. Once you have accessed the above URL from your web browser and entered the userCode, you can execute the following code to obtain an access token. This token gives your permission to retrieve the data. Since the access token has only a limited life space, the routine also returns a refresh token which can be used to generate new access tokens as needed.


# get access and refresh tokens to get access to the data
# run the code below after the userCode has been successefully entered in the verificationUrl

accessToken, refreshToken = getRefreshToken(clientId, clientSecret, deviceCode)	

4. If your access is rejected at some future time, you need only run the code below to generate a new access token.


accessToken = getRefreshedAccessCode(clientId, clientSecret, refreshToken)

5. The next set of code illustrates how you can now access the data store. In this case, we obtain a list of data sources and produce a csv file containing summary information on each data source. The following section shows the functions used to retrieve the information.


 
def getTagValue(stepCode, tagName):
    obj = getAllJSON(stepCode)
    tagValue = obj[tagName]
    print(tagValue)
    return tagValue

def getAllJSON(stepCode):
    fout = subprocess.Popen(stepCode,stdout=subprocess.PIPE)
    inFile = fout.communicate()[0]
    return json.loads(inFile)

def msToTime(ms):
    s = float(ms) / 1000000000.0
    return datetime.datetime.fromtimestamp(s).strftime('%Y-%m-%d %H:%M:%S.%f')

def timeToMs(yyyy, mm, dd, hour, min, sec, dec):
#    now = datetime.datetime(2015,03,10,13,0, 9, 12345)    
    now = datetime.datetime(yyyy, mm, dd, hour, min, sec, dec)
    tt = datetime.datetime.timetuple(now)
    return time.mktime(tt) * 1000000000.0

def getDataTimes(dataInput):
    points = dataInput['point']
        
    startMilliseconds = 0
    endMilliseconds = 0
    for point in points:
        if startMilliseconds < point['startTimeNanos']: 
            startMilliseconds = point['startTimeNanos']
        if endMilliseconds < point['endTimeNanos']: 
            endMilliseconds = point['endTimeNanos']
    return     (len(points), msToTime(startMilliseconds), msToTime(endMilliseconds))

def getInformationSourceList(accessToken):
    step4CodeTemplate = 'curl https://www.googleapis.com/fitness/v1/users/me/dataSources' + \
    '?access_token=<accessToken>'
    step4 = step4CodeTemplate.replace('<accessToken>',accessToken)
    allSources = getAllJSON(step4)
    dataSources = []
    for sourceList in allSources['dataSource']:
        dataSources.append(sourceList['dataStreamId'])
    return dataSources

6. The functions are called as follows


dataSources = getInformationSourceList(accessToken)	
pprint.pprint(dataSources)	

The next post explores how to extract data from the sources.

Advertisements
Comments
One Response to “Client-side #Python code to summarize data collected in the #GoogleFit data store”
Trackbacks
Check out what others are saying...
  1. […] identifying the data sources held by #GoogleFit (see the post), the next step is to extract the information contained within each source in a format that could […]



Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: