-
-
Save abfo/cb96533af64f8c861cb77e790939d827 to your computer and use it in GitHub Desktop.
// add your Google API Project OAuth client ID and client secret here | |
var ClientID = ''; | |
var ClientSecret = ''; | |
function onOpen() { | |
var ui = SpreadsheetApp.getUi(); | |
ui.createMenu('Google Fit') | |
.addItem('Authorize if needed (does nothing if already authorized)', 'showSidebar') | |
.addItem('Get Metrics for Yesterday', 'getMetrics') | |
.addItem('Get Metrics for past 60 days', 'getHistory') | |
.addItem('Reset Settings', 'clearProps') | |
.addToUi(); | |
} | |
function getMetrics() { | |
getMetricsForDays(1, 1, 'Metrics'); | |
} | |
function getHistory() { | |
getMetricsForDays(1, 60, 'History'); | |
} | |
// see step count example at https://developers.google.com/fit/scenarios/read-daily-step-total | |
// adapted below to handle multiple metrics (steps, weight, distance), only logged if present for day | |
function getMetricsForDays(fromDaysAgo, toDaysAgo, tabName) { | |
var start = new Date(); | |
start.setHours(0,0,0,0); | |
start.setDate(start.getDate() - toDaysAgo); | |
var end = new Date(); | |
end.setHours(23,59,59,999); | |
end.setDate(end.getDate() - fromDaysAgo); | |
var fitService = getFitService(); | |
var request = { | |
"aggregateBy": [ | |
{ | |
"dataTypeName": "com.google.step_count.delta", | |
"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps" | |
}, | |
{ | |
"dataTypeName": "com.google.weight.summary", | |
"dataSourceId": "derived:com.google.weight:com.google.android.gms:merge_weight" | |
}, | |
{ | |
"dataTypeName": "com.google.distance.delta", | |
"dataSourceId": "derived:com.google.distance.delta:com.google.android.gms:merge_distance_delta" | |
} | |
], | |
"bucketByTime": { "durationMillis": 86400000 }, | |
"startTimeMillis": start.getTime(), | |
"endTimeMillis": end.getTime() | |
}; | |
var response = UrlFetchApp.fetch('https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate', { | |
headers: { | |
Authorization: 'Bearer ' + fitService.getAccessToken() | |
}, | |
'method' : 'post', | |
'contentType' : 'application/json', | |
'payload' : JSON.stringify(request, null, 2) | |
}); | |
var json = JSON.parse(response.getContentText()); | |
var ss = SpreadsheetApp.getActiveSpreadsheet(); | |
var sheet = ss.getSheetByName(tabName); | |
for(var b = 0; b < json.bucket.length; b++) { | |
// each bucket in our response should be a day | |
var bucketDate = new Date(parseInt(json.bucket[b].startTimeMillis, 10)); | |
var steps = -1; | |
var weight = -1; | |
var distance = -1; | |
if (json.bucket[b].dataset[0].point.length > 0) { | |
steps = json.bucket[b].dataset[0].point[0].value[0].intVal; | |
} | |
if (json.bucket[b].dataset[1].point.length > 0) { | |
weight = json.bucket[b].dataset[1].point[0].value[0].fpVal; | |
} | |
if (json.bucket[b].dataset[2].point.length > 0) { | |
distance = json.bucket[b].dataset[2].point[0].value[0].fpVal; | |
} | |
sheet.appendRow([bucketDate, | |
steps == -1 ? ' ' : steps, | |
weight == -1 ? ' ' : weight, | |
distance == -1 ? ' ' : distance]); | |
} | |
} | |
// functions below adapted from Google OAuth example at https://github.com/googlesamples/apps-script-oauth2 | |
function getFitService() { | |
// Create a new service with the given name. The name will be used when | |
// persisting the authorized token, so ensure it is unique within the | |
// scope of the property store. | |
return OAuth2.createService('fit') | |
// Set the endpoint URLs, which are the same for all Google services. | |
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth') | |
.setTokenUrl('https://accounts.google.com/o/oauth2/token') | |
// Set the client ID and secret, from the Google Developers Console. | |
.setClientId(ClientID) | |
.setClientSecret(ClientSecret) | |
// Set the name of the callback function in the script referenced | |
// above that should be invoked to complete the OAuth flow. | |
.setCallbackFunction('authCallback') | |
// Set the property store where authorized tokens should be persisted. | |
.setPropertyStore(PropertiesService.getUserProperties()) | |
// Set the scopes to request (space-separated for Google services). | |
// see https://developers.google.com/fit/rest/v1/authorization for a list of Google Fit scopes | |
.setScope('https://www.googleapis.com/auth/fitness.activity.read https://www.googleapis.com/auth/fitness.body.read https://www.googleapis.com/auth/fitness.location.read') | |
// Below are Google-specific OAuth2 parameters. | |
// Sets the login hint, which will prevent the account chooser screen | |
// from being shown to users logged in with multiple accounts. | |
.setParam('login_hint', Session.getActiveUser().getEmail()) | |
// Requests offline access. | |
.setParam('access_type', 'offline') | |
// Forces the approval prompt every time. This is useful for testing, | |
// but not desirable in a production application. | |
//.setParam('approval_prompt', 'force'); | |
} | |
function showSidebar() { | |
var fitService = getFitService(); | |
if (!fitService.hasAccess()) { | |
var authorizationUrl = fitService.getAuthorizationUrl(); | |
var template = HtmlService.createTemplate( | |
'<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' + | |
'Close this after you have finished.'); | |
template.authorizationUrl = authorizationUrl; | |
var page = template.evaluate(); | |
SpreadsheetApp.getUi().showSidebar(page); | |
} else { | |
// ... | |
} | |
} | |
function authCallback(request) { | |
var fitService = getFitService(); | |
var isAuthorized = fitService.handleCallback(request); | |
if (isAuthorized) { | |
return HtmlService.createHtmlOutput('Success! You can close this tab.'); | |
} else { | |
return HtmlService.createHtmlOutput('Denied. You can close this tab'); | |
} | |
} | |
function clearProps() { | |
PropertiesService.getUserProperties().deleteAllProperties(); | |
} |
Hi sir, it's me again. I want to get number of steps through my web application. It actually works for me by sending "post" request, and I am getting the current number of steps. But as access token periodically expires I want set "offline access" to the access token as you did in your code above. Do you have an idea how can I do that in my case? Here is also my code -->
data = {
"aggregateBy": [{
"dataTypeName": "com.google.step_count.delta",
"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"
}],
"bucketByTime": { "durationMillis": 86400000 },
"startTimeMillis": 1593640800000,
"endTimeMillis": 1593727199999
}
var options = {
method: 'POST',
body: data,
json: true,
url: 'https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate',
headers: {
'Authorization':'Bearer ya29.a0AfH6SMAAT2yPO27Wdi9s4yr0qju4XknUXcM55wFZyngx-o8a8xhxfMXxtJod4skftKdWAEx6oggdCTm-GGSWqS8dLKPo9V5scfwM6Af8QA8HWekWxbf2JX_wozJ1OIsE9gVecJ-8ADX0kHjHpnJCKG0jzgXHQVFT0Gc'
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body.bucket[0].dataset[0].point[0].value[0].intVal);
}
}
request(options, callback);
You need to save a refresh token and then you can avoid constant reauthentication. Look for an OAuth 2 library for your platform ideally.
Thank you very much, it works now