// add your Google API Project OAuth client ID and client secret here var ClientID = ''; var ClientSecret = ''; var NANOSECONDS_TO_MILLISECONDS = 1.0 / 1000000.0; var LOCAL_UTC_OFFSET = 2 * (60 * 60 * 1000); //Sweden is UTC+2 during summer. var SHEET_NAME = '2018'; //the name of your spreadsheet tab function onOpen() { var ui = SpreadsheetApp.getUi(); ui.createMenu('Google Fit') .addItem('Authorize if needed (does nothing if already authorized)', 'showSidebar') .addItem('Get todays weight', 'getWeight') .addToUi(); } function getWeight() { var start = new Date(); start.setHours(0,0,0,0); var end = new Date(); end.setHours(23,59,59,999); var fitService = getFitService(); var request = { "aggregateBy": [{ "dataTypeName": "com.google.weight.summary", "dataSourceId": "derived:com.google.weight:com.google.android.gms:merge_weight" }], "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 weight = parseFloat(json.bucket[0].dataset[0].point[0].value[0].fpVal); var measuredAt = parseInt(json.bucket[0].dataset[0].point[0].endTimeNanos) * NANOSECONDS_TO_MILLISECONDS; measuredAt += LOCAL_UTC_OFFSET; var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheetByName(SHEET_NAME); var dateString = new Date(measuredAt).toISOString().split("T")[0]; sheet.appendRow([dateString, weight]); } // functions below adapted from Google OAuth example at https://github.com/googlesamples/apps-script-oauth2 function getFitService() { 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 your 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') // 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( 'Authorize. ' + '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'); } }