ulfben icon

Fetch Google Fit data to Google Spreadsheet

ulfben | PRO | 07/13/18 08:07:01 PM UTC | 0 ⭐ | 1327 👁️ | Never ⏰ | []
JavaScript |

4.29 KB

|

None

|

0 👍

/

0 👎

// 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(
        '<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');
  }
}

Comments

  • Gyqizv icon
    04/02/26 06:19:45 PM UTC
    text |

    0 B

    |

    0 👍

    /

    0 👎

    Best t33n active cpx link daily updates!
     Copy and paste the link in a new browser tab and then hit enter!
     https://crazyporn.@xxx/members/157354/?asgtbndr=1&play=true&spon=adworld&zone=400
     Remove the @ 
  • Yuizcko icon
    05/18/26 01:09:04 PM UTC
    text |

    0 B

    |

    0 👍

    /

    0 👎

    Best t33n active cpx link daily updates!
     Copy and paste the link in a new browser tab and then hit enter!
     https://crazyporn.xxx/members/157354/?asgtbndr=1&play=true&spon=adworld&zone=400