[
  {
    "path": ".Rbuildignore",
    "content": "^.*\\.Rproj$\n^\\.Rproj\\.user$\ncran-comments.md\n\n"
  },
  {
    "path": ".gitignore",
    "content": ".Rproj.user\n.Rhistory\n.RData\ntest.R\n*.Rproj\ninst/doc\n"
  },
  {
    "path": "DESCRIPTION",
    "content": "Package: fitbitScraper\nTitle: Scrapes Data from Fitbit\nVersion: 0.1.8\nAuthor: Cory Nissen <corynissen@gmail.com> [aut, cre]\nMaintainer: Cory Nissen <corynissen@gmail.com>\nDescription: Scrapes data from Fitbit <http://www.fitbit.com>. This does not use the official\n    API, but instead uses the API that the web dashboard uses to generate the graphs\n    displayed on the dashboard after login at <http://www.fitbit.com>.\nDepends: R (>= 3.0.0)\nLicense: MIT + file LICENSE\nLazyData: true\nImports: \n    httr, \n    stringr, \n    jsonlite, \n    methods, \n    utils\nURL: https://github.com/corynissen/fitbitScraper\nRoxygenNote: 6.0.1\nSuggests: \n    knitr, \n    rmarkdown,\n    ggplot2,\n    ggthemes\nVignetteBuilder: knitr\nNeedsCompilation: no\nPackaged: 2016-05-13 13:41:27 UTC; 60018847\n"
  },
  {
    "path": "LICENSE",
    "content": "YEAR: 2014\nCOPYRIGHT HOLDER: Cory Nissen\n"
  },
  {
    "path": "NAMESPACE",
    "content": "# Generated by roxygen2: do not edit by hand\n\nexport(get_activity_data)\nexport(get_daily_data)\nexport(get_intraday_data)\nexport(get_premium_export)\nexport(get_sleep_data)\nexport(get_weight_data)\nexport(login)\n"
  },
  {
    "path": "NEWS.md",
    "content": "\n### fitbitScraper 0.1.8\n* added minutesSedentary data to 'get_daily_data'  [(14)](https://github.com/corynissen/fitbitScraper/issues/14)  \n* fixed bug in the column names in 'get_daily_data' for getTimeInHeartRateZonesPerDay [(9)](https://github.com/corynissen/fitbitScraper/issues/9)   [(13)](https://github.com/corynissen/fitbitScraper/issues/13)  \n* if login returns a cookie that is character(0), throw error  [(10)](https://github.com/corynissen/fitbitScraper/issues/10)  \n\n\n### fitbitScraper 0.1.7\n* added vignette\n\n### fitbitScraper 0.1.6\n* switch from RJSONIO to jsonlite\n\n### fitbitScraper 0.1.5\n* use real URL in DESCRIPTION\n* added <> around URLs in DESCRIPTION\n* added methods and utils to imports in DESCRIPTION\n* added corresponding methods:: and utils:: in code\n* changed get_activity_data() function to have a working end_date.\n* pull request #7 calories burned vs intake\n* pull request #5 Add check.names=T for creating data.frames\n* pull request #4 slight changes to sleep variable names\n* pull request #3 Update login.R\n\n### fitbitScraper 0.1.4\n* added get_activity_data() function\n* added \"getRestingHeartRateData\" to get_daily_data() function\n* added rememberMe parameter to login function\n* merged pull request #2, a change to the login function\n\n### fitbitScraper 0.1.3\n* Changed the API calls to match changes on fitbit end of things.\n\n### fitbitScraper 0.1.2\n* Added get_sleep_data()\n* Added get_premium_export()\n* Changed output column of get_daily_data(), get_15_min_data(), and get_weight_data() to correspond to the data type requested... for example: \"weight\" instead of \"data\"\", \"steps\" instead of \"data\"\n* Added heart-rate for get_15_min_data() and get_daily_data()\n* added get_intraday_data()\n* Deprecated get_15_min_data(), use get_intraday_data() instead\n\n### fitbitScraper 0.1.1\n* Basic checks included for arguments\n* tz added to the return dataframes as.POSIXct date field\n* documentation cleanup\n\n### fitbitScraper 0.1  \n* No error checking\n* Three functions: login, get_daily_data, get_15_min_data \n"
  },
  {
    "path": "R/get_activity_data.R",
    "content": "#' Get activity data from fitbit.com\n#'\n#' Get activity data from fitbit using cookie returned from login function\n#' @param cookie Cookie returned after login, specifically the \"u\" cookie\n#' @param end_date Date in YYYY-MM-DD format\n#' @keywords data\n#' @export\n#' @return A dataframe with raw output from Fitbit\n#' @examples\n#' \\dontrun{\n#' get_activity_data(cookie, end_date=\"2015-01-20\")\n#' }\n#' get_activity_data\nget_activity_data <- function(cookie, end_date){\n  if(!is.character(cookie)){stop(\"cookie must be a character string\")}\n  if(!is.character(end_date)){stop(\"end_date must be a character string\")}\n  if(!grepl(\"[0-9]{4}-[0-9]{2}-[0-9]{2}\", end_date)){stop('end_date must have format \"YYYY-MM-DD\"')}\n\n  url <- \"https://www.fitbit.com/ajaxapi\"\n \n  request <- paste0('{\"serviceCalls\":[{\"id\":\"GET /api/2/user/activities/logs\",\"name\":\"user\",\"method\":\"getActivitiesLogs\",\"args\":{',\n                    '\"beforeDate\":\"',\n                    end_date,\n                    'T00:00:00\",',\n                    '\"period\":\"day\",\"offset\":0,\"limit\":100}},{\"id\":\"GET /api/2/user/activities/logs/summary\",\"name\":\"user\",\"method\":\"getActivitiesLogsSummary\",\"args\":{\"fromDate\":\"',\n                    end_date,\n                    '\",\"toDate\":\"',\n                    end_date, \n                    '\",\"period\":\"day\",\"offset\":0,\"limit\":10}}],\"template\":\"activities/modules/models/ajax.response.json.jsp\"}'\n  )\n  \n  csrfToken <- stringr::str_extract(cookie,\n    \"[A-Z0-9]{8}\\\\-[A-Z0-9]{4}\\\\-[A-Z0-9]{4}\\\\-[A-Z0-9]{4}\\\\-[0-9A-Z]{12}\")\n  body <- list(request=request, csrfToken = csrfToken)\n  response <- httr::POST(url, body=body, httr::config(cookie=cookie))\n\n  dat_string <- methods::as(response, \"character\")\n  dat_list <- jsonlite::fromJSON(dat_string)\n  \n  if(\"GET /api/2/user/activities/logs\" %in% names(dat_list)){\n    df <- dat_list[[\"GET /api/2/user/activities/logs\"]][\"result\"][[1]]\n  }else{\n    df <- NULL\n    print(\"unable to retrieve activities data\")\n  }\n  \n  tz <- Sys.timezone()\n  if(is.null(tz) | is.na(tz)){tz <- format(Sys.time(),\"%Z\")}\n  df$start_datetime <- as.POSIXct(paste0(df$date, \" \", df$formattedStartTime),\n                                  format=\"%Y-%m-%d %H:%M\", tz=tz)\n  df$end_datetime <- as.POSIXct(paste0(df$date, \" \", df$formattedEndTime),\n                                  format=\"%Y-%m-%d %H:%M\", tz=tz)\n  return(df)\n}\n"
  },
  {
    "path": "R/get_daily_data.R",
    "content": "#' Get daily data from fitbit.com\n#'\n#' Get daily data from fitbit using cookie returned from login function\n#' @param cookie Cookie returned after login, specifically the \"u\" cookie\n#' @param what What data you wish to be returned. Options include \"steps\", \"distance\", \"floors\", \"minutesVery\", \"caloriesBurnedVsIntake\", \"minutesSedentary\", \"getTimeInHeartRateZonesPerDay\", \"getRestingHeartRateData\"\n#' @param start_date Date in YYYY-MM-DD format\n#' @param end_date Date in YYYY-MM-DD format\n#' @keywords data\n#' @export\n#' @return A dataframe with two columns:\n#'  \\item{time}{A POSIXct time value}\n#'  \\item{data}{The data column corresponding to the choice of \"what\"}\n#' @examples\n#' \\dontrun{\n#' get_daily_data(cookie, what=\"steps\", start_date=\"2015-01-13\", end_date=\"2015-01-20\")\n#' }\n#' get_daily_data\nget_daily_data <- function(cookie, what=\"steps\", start_date, end_date){\n  if(!is.character(cookie)){stop(\"cookie must be a character string\")}\n  if(!is.character(what)){stop(\"what must be a character string\")}\n  if(!is.character(start_date)){stop(\"start_date must be a character string\")}\n  if(!is.character(end_date)){stop(\"end_date must be a character string\")}\n  if(!grepl(\"[0-9]{4}-[0-9]{2}-[0-9]{2}\", start_date)){\n    stop('start_date must have format \"YYYY-MM-DD\"')\n  }\n  if(!grepl(\"[0-9]{4}-[0-9]{2}-[0-9]{2}\", end_date)){\n    stop('end_date must have format \"YYYY-MM-DD\"')\n  }\n  if(!what %in% c(\"steps\", \"distance\", \"floors\", \"minutesVery\", \n                  \"caloriesBurnedVsIntake\", \"minutesSedentary\",\n                  \"getTimeInHeartRateZonesPerDay\", \n                  \"getRestingHeartRateData\")){\n    stop('what must be one of \"steps\", \"distance\", \"floors\", \"minutesVery\", \n         \"caloriesBurnedVsIntake\", \"minutesSedentary\", \n         \"getTimeInHeartRateZonesPerDay\", \"getRestingHeartRateData\"')\n  }\n\n  if(what %in% c(\"getTimeInHeartRateZonesPerDay\", \"getRestingHeartRateData\")){\n    url <- \"https://www.fitbit.com/ajaxapi\"\n    request <- paste0('{\"template\":\"/ajaxTemplate.jsp\",\"serviceCalls\":[{\"name\":\"activityTileData\",\"args\":{\"startDate\":\"',\n                      start_date,\n                      '\",\"endDate\":\"',\n                      end_date,\n                      '\"},\"method\":\"',\n                      what,\n                      '\"}]}'\n    )\n    csrfToken <- stringr::str_extract(cookie,\n      \"[A-Z0-9]{8}\\\\-[A-Z0-9]{4}\\\\-[A-Z0-9]{4}\\\\-[A-Z0-9]{4}\\\\-[0-9A-Z]{12}\")\n    body <- list(request=request, csrfToken = csrfToken)\n    response <- httr::POST(url, body=body, httr::config(cookie=cookie))\n  }else{\n    url <- \"https://www.fitbit.com/graph/getNewGraphData\"\n    query <- list(\"type\" = what,\n                  \"dateFrom\" = start_date,\n                  \"dateTo\" = end_date,\n                  \"granularity\" = \"DAILY\",\n                  \"hidePrecreationData\" = \"false\")\n\n    response <- httr::GET(url, query=query, httr::config(cookie=cookie))\n  }\n\n  dat_string <- methods::as(response, \"character\")\n  dat_list <- jsonlite::fromJSON(dat_string)\n\n  if(what==\"getTimeInHeartRateZonesPerDay\"){\n    if(length(dat_list$value)==0){\n      stop(\"No getTimeInHeartRateZonesPerDay available\")\n    }\n    df <- cbind(dat_list$dateTime, dat_list$value, stringsAsFactors=FALSE)\n    names(df)[1] <- \"time\"\n    names(df)[names(df)==\"IN_DEFAULT_ZONE_1\"] <- \"zone1\"\n    names(df)[names(df)==\"IN_DEFAULT_ZONE_2\"] <- \"zone2\"\n    names(df)[names(df)==\"IN_DEFAULT_ZONE_3\"] <- \"zone3\"\n  }else if(what==\"getRestingHeartRateData\"){\n    if(length(dat_list$dataPoints)==0){\n      stop(\"No getRestingHeartRateData available\")\n    }\n    df <- dat_list$dataPoints\n    df <- df[, c(\"date\", \"value\")]\n    names(df)[1:2] <- c(\"time\", \"restingHeartRate\")\n  }else if(what==\"caloriesBurnedVsIntake\"){\n    df_burn <- dat_list[[\"graph\"]][[\"dataSets\"]][[\"activity\"]][[\"dataPoints\"]]\n    df_int <- dat_list[[\"graph\"]][[\"dataSets\"]][[\"caloriesIntake\"]][[\"dataPoints\"]]\n    names(df_burn)[1:2] <- c(\"time\", \"caloriesBurned\")\n    names(df_int)[1:2] <- c(\"time\", \"caloriesIntake\")\n    df <- merge(df_burn, df_int, by=\"time\")\n  }else{\n    df <- dat_list[[\"graph\"]][[\"dataSets\"]][[\"activity\"]][[\"dataPoints\"]]\n    names(df)[1:2] <- c(\"time\", what)\n  }\n\n  if(what==\"getRestingHeartRateData\"){\n    tz <- Sys.timezone()\n    if(is.null(tz)){tz <- format(Sys.time(),\"%Z\")}\n    df$time <- as.POSIXct(df$time, \"%Y-%m-%d\", tz=tz)\n  }else{\n    tz <- Sys.timezone()\n    if(is.null(tz)){tz <- format(Sys.time(),\"%Z\")}\n    df$time <- as.POSIXct(df$time, \"%Y-%m-%d %H:%M:%S\", tz=tz)\n  }\n  return(df)\n}\n"
  },
  {
    "path": "R/get_intraday_data.R",
    "content": "#' Get intraday data from fitbit.com\n#'\n#' Get intraday data from fitbit using cookie returned from login function\n#' @param cookie Cookie returned after login, specifically the \"u\" cookie\n#' @param what What data you wish to be returned. Options include \"steps\", \"distance\", \"floors\", \"active-minutes\", \"calories-burned\", \"heart-rate\"\n#' @param date Date in YYYY-MM-DD format\n#' @keywords data\n#' @export\n#' @return A dataframe with two columns:\n#'  \\item{time}{A POSIXct time value}\n#'  \\item{data}{The data column corresponding to the choice of \"what\"}\n#' @examples\n#' \\dontrun{\n#' get_intraday_data(cookie, what=\"steps\", date=\"2015-01-20\")\n#' }\n#' get_intraday_data\nget_intraday_data <- function(cookie, what=\"steps\", date){\n  if(!is.character(cookie)){stop(\"cookie must be a character string\")}\n  if(!is.character(what)){stop(\"what must be a character string\")}\n  if(!is.character(date)){stop(\"date must be a character string\")}\n  if(!grepl(\"[0-9]{4}-[0-9]{2}-[0-9]{2}\", date)){stop('date must have format \"YYYY-MM-DD\"')}\n  if(!what %in% c(\"steps\", \"distance\", \"floors\", \"active-minutes\", \"calories-burned\",\n                  \"heart-rate\")){\n    stop('what must be one of \"steps\", \"distance\", \"floors\", \"active-minutes\", \"calories-burned\",\n         \"heart-rate\"')\n  }\n\n  url <- \"https://www.fitbit.com/ajaxapi\"\n  request <- paste0('{\"template\":\"/ajaxTemplate.jsp\",\"serviceCalls\":[{\"name\":\"activityTileData\",\"args\":{\"date\":\"',\n                    date,\n                    '\",\"dataTypes\":\"',\n                    what,\n                    '\"},\"method\":\"getIntradayData\"}]}'\n  )\n  csrfToken <- stringr::str_extract(cookie,\n    \"[A-Z0-9]{8}\\\\-[A-Z0-9]{4}\\\\-[A-Z0-9]{4}\\\\-[A-Z0-9]{4}\\\\-[0-9A-Z]{12}\")\n  body <- list(request=request, csrfToken = csrfToken)\n  response <- httr::POST(url, body=body, httr::config(cookie=cookie))\n\n  dat_string <- methods::as(response, \"character\")\n  dat_list <- jsonlite::fromJSON(dat_string)\n  \n  df <- dat_list[[\"dataSets\"]][[\"activity\"]][[\"dataPoints\"]][[1]]\n  if(what==\"heart-rate\"){\n    tz <- Sys.timezone()\n    if(is.null(tz)){tz <- format(Sys.time(),\"%Z\")}\n    df$time <- as.POSIXct(df$dateTime, \"%Y-%m-%d %H:%M:%S\", tz=tz)\n  }else{\n    names(df)[1:2] <- c(\"time\", what)\n    tz <- Sys.timezone()\n    if(is.null(tz)){tz <- format(Sys.time(),\"%Z\")}\n    df$time <- as.POSIXct(df$time, \"%Y-%m-%d %H:%M:%S\", tz=tz)\n  }\n  return(df)\n}\n"
  },
  {
    "path": "R/get_premium_export.R",
    "content": "#' Get official data export from fitbit.com premium\n#'\n#' Get official data export from fitbit premium using cookie returned from login function. This should be used over individual calls to get_daily_data(), etc. if you subscribe to premium and data export is allowed. I'm not subscribed to premium, but it works for me...\n#' @param cookie Cookie returned after login, specifically the \"u\" cookie\n#' @param what What data you wish to be returned. Options include \"BODY\", \"FOODS\", \"ACTIVITIES\", \"SLEEP\"\n#' @param start_date Date in YYYY-MM-DD format\n#' @param end_date Date in YYYY-MM-DD format\n#' @keywords data\n#' @export\n#' @return A list with two things\n#'  \\item{summary}{A list of sleep summary values}\n#'  \\item{df}{A data frame containing various sleep values over time}\n#' @examples\n#' \\dontrun{\n#' get_premium_export(cookie, what=\"ACTIVITIES\", start_date=\"2015-01-13\", end_date=\"2015-01-20\")\n#' }\n#' get_premium_export\nget_premium_export <- function(cookie, what=\"ACTIVITIES\", start_date=\"2015-01-13\", end_date=\"2015-01-20\"){\n  if(!is.character(cookie)){stop(\"cookie must be a character string\")}\n  if(!is.character(what)){stop(\"what must be a character string\")}\n  if(!is.character(start_date)){stop(\"start_date must be a character string\")}\n  if(!is.character(end_date)){stop(\"end_date must be a character string\")}\n  if(!grepl(\"[0-9]{4}-[0-9]{2}-[0-9]{2}\", start_date)){stop('start_date must have format \"YYYY-MM-DD\"')}\n  if(!grepl(\"[0-9]{4}-[0-9]{2}-[0-9]{2}\", end_date)){stop('end_date must have format \"YYYY-MM-DD\"')}\n  if(!what %in% c(\"BODY\", \"FOODS\", \"ACTIVITIES\", \"SLEEP\")){\n    stop('what must be one of \"BODY\", \"FOODS\", \"ACTIVITIES\", \"SLEEP\"')\n  }\n\n  # as of 5/2015-ish, the date format is not MM/DD/YYYY\n  start_date <- format(as.Date(start_date), \"%m/%d/%Y\")\n  end_date <- format(as.Date(end_date), \"%m/%d/%Y\")\n\n  url <- \"https://www.fitbit.com/export/user/data\"\n  header <- list(\"Content-Type\"=\"application/x-www-form-urlencoded\",\n                 \"u\"=cookie,\n                 \"Host\"=\"www.fitbit.com\",\n                 \"Origin\"=\"https://www.fitbit.com\",\n                 \"Referer\"=\"https://www.fitbit.com/export/user/data\",\n                 \"User-Agent\"=\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36\",\n                 \"X-Requested-With\"=\"XMLHttpRequest\")\n  body <- list(\"export\"=\"true\",\n                  \"dataPeriod.periodType\"=\"CUSTOM\",\n                  \"startDate\"=start_date,\n                  \"endDate\"=end_date,\n                \"dataExportType\"=what,\n                  \"fileFormat\"=\"CSV\")\n\n  response <- httr::POST(url, header=header, body=body,\n                         httr::config(cookie=cookie))\n  if(response$status_code!=200){\n    stop(\"problem with request, this may be available only for premium subscribers\")\n  }\n  file_id <- methods::as(response, \"character\")\n  file_id <- jsonlite::fromJSON(file_id)\n  file_id <- file_id[\"fileIdentifier\"]\n\n  # see if file ready for download\n  get_file_status <- function(file_id){\n    is_ready <- httr::GET(paste0(\"https://www.fitbit.com/premium/export?isExportedFileReady=true&fileIdentifier=\",\n                                 file_id))\n    if(\"fileIsReady\" %in% names(httr::content(is_ready))){\n      is_ready <- httr::content(is_ready)$fileIsReady\n    }else{\n      stop(\"file_id not found while retrieving file status\")\n    }\n    return(is_ready)\n  }\n\n  start <- Sys.time()\n  is_ready <- get_file_status(file_id)\n  while(!is_ready){\n    if(Sys.time() - start > 10){\n      stop(\"timeout waiting for file to generate\")\n    }\n    Sys.sleep(.5)\n    is_ready <- get_file_status(file_id)\n  }\n\n  a <- httr::GET(paste0(\"https://www.fitbit.com/premium/export/download/\",\n                        file_id))\n  df <- utils::read.csv(text=methods::as(a, \"character\"), skip=1, \n                        stringsAsFactors=F)\n  return(df)\n}\n"
  },
  {
    "path": "R/get_sleep_data.R",
    "content": "#' Get sleep data from fitbit.com\n#'\n#' Get sleep data from fitbit using cookie returned from login function\n#' @param cookie Cookie returned after login, specifically the \"u\" cookie\n#' @param start_date Date in YYYY-MM-DD format\n#' @param end_date Date in YYYY-MM-DD format\n#' @keywords data\n#' @export\n#' @return A list with two things\n#'  \\item{summary}{A list of sleep summary values}\n#'  \\item{df}{A data frame containing various sleep values over time}\n#' @examples\n#' \\dontrun{\n#' get_sleep_data(cookie, start_date=\"2015-01-13\", end_date=\"2015-01-20\")\n#' }\n#' get_sleep_data\nget_sleep_data <- function(cookie, start_date=\"2015-01-13\", end_date=\"2015-01-20\"){\n  if(!is.character(cookie)){stop(\"cookie must be a character string\")}\n  if(!is.character(start_date)){stop(\"start_date must be a character string\")}\n  if(!is.character(end_date)){stop(\"end_date must be a character string\")}\n  if(!grepl(\"[0-9]{4}-[0-9]{2}-[0-9]{2}\", start_date)){stop('start_date must have format \"YYYY-MM-DD\"')}\n  if(!grepl(\"[0-9]{4}-[0-9]{2}-[0-9]{2}\", end_date)){stop('end_date must have format \"YYYY-MM-DD\"')}\n\n  url <- \"https://www.fitbit.com/ajaxapi\"\n  request <- paste0('{\"template\":\"/ajaxTemplate.jsp\",\"serviceCalls\":[{\"name\":\"activityTileData\",\"args\":{\"dateFrom\":\"',\n                    start_date,\n                    '\",\"dateTo\":\"',\n                    end_date,\n                    '\"},\"method\":\"getSleepTileData\"}]}'\n                    )\n\n  csrfToken <- stringr::str_extract(cookie,\n    \"[A-Z0-9]{8}\\\\-[A-Z0-9]{4}\\\\-[A-Z0-9]{4}\\\\-[A-Z0-9]{4}\\\\-[0-9A-Z]{12}\")\n  body <- list(request=request, csrfToken = csrfToken)\n  response <- httr::POST(url, body=body, httr::config(cookie=cookie))\n\n  dat_string <- methods::as(response, \"character\")\n  dat_list <- jsonlite::fromJSON(dat_string)\n  \n  if(\"hasLoggedSleep\" %in% names(dat_list)){\n    summary <- list(avgSleepDuration = dat_list$avgSleepDuration,\n                    avgSleepTime = dat_list$avgSleepTime,\n                    avgSleepScore = dat_list$avgSleepScore,\n                    avgGraphicPercent = dat_list$avgGraphicPercent)\n    # get individual day data\n    df <- dat_list[[\"entries\"]]\n  }else{\n    stop(\"No sleep data available\")\n  }\n  return(list(summary=summary, df=df))\n}\n\n"
  },
  {
    "path": "R/get_weight_data.R",
    "content": "#' Get weight data from fitbit.com\n#'\n#' Get weight data from fitbit using cookie returned from login function\n#' @param cookie Cookie returned after login, specifically the \"u\" cookie\n#' @param start_date Date in YYYY-MM-DD format\n#' @param end_date Date in YYYY-MM-DD format\n#' @keywords data\n#' @export\n#' @return A dataframe with two columns:\n#'  \\item{time}{A POSIXct time value}\n#'  \\item{weight}{The data column corresponding to weight}\n#' @examples\n#' \\dontrun{\n#' get_weight_data(cookie, start_date=\"2015-01-13\", end_date=\"2015-01-20\")\n#' }\n#' get_weight_data\nget_weight_data <- function(cookie, start_date, end_date){\n  if(!is.character(cookie)){stop(\"cookie must be a character string\")}\n  if(!is.character(start_date)){stop(\"start_date must be a character string\")}\n  if(!is.character(end_date)){stop(\"end_date must be a character string\")}\n  if(!grepl(\"[0-9]{4}-[0-9]{2}-[0-9]{2}\", start_date)){stop('start_date must have format \"YYYY-MM-DD\"')}\n  if(!grepl(\"[0-9]{4}-[0-9]{2}-[0-9]{2}\", end_date)){stop('end_date must have format \"YYYY-MM-DD\"')}\n\n  url <- \"https://www.fitbit.com/graph/getNewGraphData\"\n  query <- list(\"type\" = \"weight\",\n                \"dateFrom\" = start_date,\n                \"dateTo\" = end_date)\n\n  response <- httr::GET(url, query=query, httr::config(cookie=cookie))\n\n  dat_string <- methods::as(response, \"character\")\n  dat_list <- jsonlite::fromJSON(dat_string)\n  df <- dat_list[[\"graph\"]][[\"dataSets\"]][[\"weight\"]][[\"dataPoints\"]]\n  names(df)[1:2] <- c(\"time\", \"weight\")\n  tz <- Sys.timezone()\n  if(is.null(tz)){tz <- format(Sys.time(),\"%Z\")}\n  df$time <- as.POSIXct(df$time, \"%Y-%m-%d %H:%M:%S\", tz=tz)\n  return(df)\n}\n"
  },
  {
    "path": "R/login.R",
    "content": "#' Login to fitbit.com and get cookie\n#'\n#' Get the login cookie after login at www.fitbit.com\n#' @param email Email address used to login to fitbit.com\n#' @param password Password used to login to fitbit.com\n#' @param rememberMe Value for rememberMe during login, default is FALSE, but changing to TRUE may help with login issues\n#' @keywords login\n#' @export\n#' @return A string containing the cookie that is returned after login at www.fitbit.com\n#' @examples\n#' \\dontrun{\n#' cookie <- login(email=\"corynissen<at>gmail.com\", password=\"mypasswordhere\")\n#' }\n#' login\nlogin <- function(email, password, rememberMe=FALSE){\n  if(!is.character(email)){stop(\"email must be a character string\")}\n  if(!is.character(password)){stop(\"password must be a character string\")}\n\n  rememberMe <- ifelse(rememberMe, \"true\", \"false\")\n\n  url <- \"https://www.fitbit.com/login\"\n  headers <- list(\"Host\" = \"www.fitbit.com\",\n                  \"Connection\" = \"keep-alive\",\n                  \"Content-Length\" = \"278\",\n                  \"Cache-Control\" = \"max-age=0\",\n                  \"Accept\" = \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\",\n                  \"Origin\" =  \"https://www.fitbit.com\",\n                  \"User-Agent\" = \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36\",\n                  \"Content-Type\" =  \"application/x-www-form-urlencoded\",\n                  \"Referer\" = \"https://www.fitbit.com/login\",\n                  \"Accept-Encoding\" = \"gzip, deflate\",\n                  \"Accept-Language\" = \"en-US,en;q=0.8\")\n  body <- list(\"email\"=email, \"password\"=password, \"rememberMe\"=rememberMe,\n               \"login\"=\"Log In\")\n\n  a <- httr::POST(url, headers=headers, body=body)\n  cookie <- a$cookies$u\n  if(is.null(cookie)){\n    all_cookies <- a$cookies\n    cookie <- all_cookies[grep(\"^u$\", all_cookies$name, ignore.case=F),\"value\"]\n    if(is.null(cookie) | identical(cookie, character(0))){\n      stop(\"login failed\")\n    }\n  }\n  return(cookie)\n}\n"
  },
  {
    "path": "README.md",
    "content": "\n### fitbitScraper 0.1.8\n\nNew changes: \n* Added minutesSedentary data to 'get_daily_data'\n* fixed bug in the column names in ‘get_daily_data’ for getTimeInHeartRateZonesPerDay  \n* if login returns a cookie that is character(0), throw error  \n\nThis package scrapes data from fitbit.com  \nIt only works if you use email / password to login. Not sure about facebook or google login.  \n\nUsage:  \n\n```R\ninstall.packages(\"fitbitScraper\")\nlibrary(\"fitbitScraper\")\n\ncookie <- login(email=\"corynissen@gmail.com\", password=\"mypassword\")  \n# 15_min_data \"what\" options: \"steps\", \"distance\", \"floors\", \"active-minutes\", \"calories-burned\"   \ndf <- get_intraday_data(cookie, what=\"steps\", date=\"2015-01-21\")  \nlibrary(\"ggplot2\")  \nggplot(df) + geom_bar(aes(x=time, y=data, fill=data), stat=\"identity\") + \n             xlab(\"\") +ylab(\"steps\") + \n             theme(axis.ticks.x=element_blank(), \n                   panel.grid.major.x = element_blank(), \n                   panel.grid.minor.x = element_blank(), \n                   panel.grid.minor.y = element_blank(), \n                   panel.background=element_blank(), \n                   panel.grid.major.y=element_line(colour=\"gray\", size=.1), \n                   legend.position=\"none\") \n\n# daily_data \"what\" options: \"steps\", \"distance\", \"floors\", \"minutesVery\", \"caloriesBurnedVsIntake\"   \ndf <- get_daily_data(cookie, what=\"steps\", start_date=\"2015-01-13\", end_date=\"2015-01-20\")  \nggplot(df) + geom_point(aes(x=time, y=data))  \n```\n"
  },
  {
    "path": "cran-comments.md",
    "content": "\n### fitbitScraper 0.1.8\n* VIGNETTE CAN ONLY BE BUILT ON MY MACHINE AS IT USES MY FITBIT LOGIN CREDENTIALS\n* added minutesSedentary data to 'get_daily_data'  [(14)](https://github.com/corynissen/fitbitScraper/issues/14)  \n* fixed bug in the column names in 'get_daily_data' for getTimeInHeartRateZonesPerDay [(9)](https://github.com/corynissen/fitbitScraper/issues/9)   [(13)](https://github.com/corynissen/fitbitScraper/issues/13)  \n* if login returns a cookie that is character(0), throw error  [(10)](https://github.com/corynissen/fitbitScraper/issues/10)  \n"
  },
  {
    "path": "man/get_activity_data.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/get_activity_data.R\n\\name{get_activity_data}\n\\alias{get_activity_data}\n\\title{Get activity data from fitbit.com}\n\\usage{\nget_activity_data(cookie, end_date)\n}\n\\arguments{\n\\item{cookie}{Cookie returned after login, specifically the \"u\" cookie}\n\n\\item{end_date}{Date in YYYY-MM-DD format}\n}\n\\value{\nA dataframe with raw output from Fitbit\n}\n\\description{\nGet activity data from fitbit using cookie returned from login function\n}\n\\examples{\n\\dontrun{\nget_activity_data(cookie, end_date=\"2015-01-20\")\n}\nget_activity_data\n}\n\\keyword{data}\n"
  },
  {
    "path": "man/get_daily_data.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/get_daily_data.R\n\\name{get_daily_data}\n\\alias{get_daily_data}\n\\title{Get daily data from fitbit.com}\n\\usage{\nget_daily_data(cookie, what = \"steps\", start_date, end_date)\n}\n\\arguments{\n\\item{cookie}{Cookie returned after login, specifically the \"u\" cookie}\n\n\\item{what}{What data you wish to be returned. Options include \"steps\", \"distance\", \"floors\", \"minutesVery\", \"caloriesBurnedVsIntake\", \"minutesSedentary\", \"getTimeInHeartRateZonesPerDay\", \"getRestingHeartRateData\"}\n\n\\item{start_date}{Date in YYYY-MM-DD format}\n\n\\item{end_date}{Date in YYYY-MM-DD format}\n}\n\\value{\nA dataframe with two columns:\n \\item{time}{A POSIXct time value}\n \\item{data}{The data column corresponding to the choice of \"what\"}\n}\n\\description{\nGet daily data from fitbit using cookie returned from login function\n}\n\\examples{\n\\dontrun{\nget_daily_data(cookie, what=\"steps\", start_date=\"2015-01-13\", end_date=\"2015-01-20\")\n}\nget_daily_data\n}\n\\keyword{data}\n"
  },
  {
    "path": "man/get_intraday_data.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/get_intraday_data.R\n\\name{get_intraday_data}\n\\alias{get_intraday_data}\n\\title{Get intraday data from fitbit.com}\n\\usage{\nget_intraday_data(cookie, what = \"steps\", date)\n}\n\\arguments{\n\\item{cookie}{Cookie returned after login, specifically the \"u\" cookie}\n\n\\item{what}{What data you wish to be returned. Options include \"steps\", \"distance\", \"floors\", \"active-minutes\", \"calories-burned\", \"heart-rate\"}\n\n\\item{date}{Date in YYYY-MM-DD format}\n}\n\\value{\nA dataframe with two columns:\n \\item{time}{A POSIXct time value}\n \\item{data}{The data column corresponding to the choice of \"what\"}\n}\n\\description{\nGet intraday data from fitbit using cookie returned from login function\n}\n\\examples{\n\\dontrun{\nget_intraday_data(cookie, what=\"steps\", date=\"2015-01-20\")\n}\nget_intraday_data\n}\n\\keyword{data}\n"
  },
  {
    "path": "man/get_premium_export.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/get_premium_export.R\n\\name{get_premium_export}\n\\alias{get_premium_export}\n\\title{Get official data export from fitbit.com premium}\n\\usage{\nget_premium_export(cookie, what = \"ACTIVITIES\", start_date = \"2015-01-13\",\n  end_date = \"2015-01-20\")\n}\n\\arguments{\n\\item{cookie}{Cookie returned after login, specifically the \"u\" cookie}\n\n\\item{what}{What data you wish to be returned. Options include \"BODY\", \"FOODS\", \"ACTIVITIES\", \"SLEEP\"}\n\n\\item{start_date}{Date in YYYY-MM-DD format}\n\n\\item{end_date}{Date in YYYY-MM-DD format}\n}\n\\value{\nA list with two things\n \\item{summary}{A list of sleep summary values}\n \\item{df}{A data frame containing various sleep values over time}\n}\n\\description{\nGet official data export from fitbit premium using cookie returned from login function. This should be used over individual calls to get_daily_data(), etc. if you subscribe to premium and data export is allowed. I'm not subscribed to premium, but it works for me...\n}\n\\examples{\n\\dontrun{\nget_premium_export(cookie, what=\"ACTIVITIES\", start_date=\"2015-01-13\", end_date=\"2015-01-20\")\n}\nget_premium_export\n}\n\\keyword{data}\n"
  },
  {
    "path": "man/get_sleep_data.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/get_sleep_data.R\n\\name{get_sleep_data}\n\\alias{get_sleep_data}\n\\title{Get sleep data from fitbit.com}\n\\usage{\nget_sleep_data(cookie, start_date = \"2015-01-13\", end_date = \"2015-01-20\")\n}\n\\arguments{\n\\item{cookie}{Cookie returned after login, specifically the \"u\" cookie}\n\n\\item{start_date}{Date in YYYY-MM-DD format}\n\n\\item{end_date}{Date in YYYY-MM-DD format}\n}\n\\value{\nA list with two things\n \\item{summary}{A list of sleep summary values}\n \\item{df}{A data frame containing various sleep values over time}\n}\n\\description{\nGet sleep data from fitbit using cookie returned from login function\n}\n\\examples{\n\\dontrun{\nget_sleep_data(cookie, start_date=\"2015-01-13\", end_date=\"2015-01-20\")\n}\nget_sleep_data\n}\n\\keyword{data}\n"
  },
  {
    "path": "man/get_weight_data.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/get_weight_data.R\n\\name{get_weight_data}\n\\alias{get_weight_data}\n\\title{Get weight data from fitbit.com}\n\\usage{\nget_weight_data(cookie, start_date, end_date)\n}\n\\arguments{\n\\item{cookie}{Cookie returned after login, specifically the \"u\" cookie}\n\n\\item{start_date}{Date in YYYY-MM-DD format}\n\n\\item{end_date}{Date in YYYY-MM-DD format}\n}\n\\value{\nA dataframe with two columns:\n \\item{time}{A POSIXct time value}\n \\item{weight}{The data column corresponding to weight}\n}\n\\description{\nGet weight data from fitbit using cookie returned from login function\n}\n\\examples{\n\\dontrun{\nget_weight_data(cookie, start_date=\"2015-01-13\", end_date=\"2015-01-20\")\n}\nget_weight_data\n}\n\\keyword{data}\n"
  },
  {
    "path": "man/login.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/login.R\n\\name{login}\n\\alias{login}\n\\title{Login to fitbit.com and get cookie}\n\\usage{\nlogin(email, password, rememberMe = FALSE)\n}\n\\arguments{\n\\item{email}{Email address used to login to fitbit.com}\n\n\\item{password}{Password used to login to fitbit.com}\n\n\\item{rememberMe}{Value for rememberMe during login, default is FALSE, but changing to TRUE may help with login issues}\n}\n\\value{\nA string containing the cookie that is returned after login at www.fitbit.com\n}\n\\description{\nGet the login cookie after login at www.fitbit.com\n}\n\\examples{\n\\dontrun{\ncookie <- login(email=\"corynissen<at>gmail.com\", password=\"mypasswordhere\")\n}\nlogin\n}\n\\keyword{login}\n"
  },
  {
    "path": "vignettes/fitbitScraper-examples.Rmd",
    "content": "---\ntitle: \"fitbitScraper Examples\"\nauthor: \"Cory Nissen\"\ndate: \"5/5/2016\"\noutput: rmarkdown::html_vignette\nvignette: >\n  %\\VignetteIndexEntry{fitbitScraper Examples}\n  %\\VignetteEngine{knitr::rmarkdown}\n  %\\VignetteEncoding{UTF-8}\n---\n\n## Installation\nInstall fitbitScraper as you would a normal library. It exists on [CRAN](https://cran.r-project.org/package=fitbitScraper), so a simple `install.packages(\"fitbitScraper\")` should work.  \n\nA development version exists on [Github](https://github.com/corynissen/fitbitScraper), and can be installed via [devtools](https://cran.r-project.org/package=devtools). `devtools::install_github(\"corynissen/fitbitScraper\")`  \n\n## Usage\n\nI've stored my password in an environment variable called \"FBPW\". I'll use this to login to fitbit and generate a cookie that will be used for the subsequent requests. You can type it directly in the password field, but it is generally a best practice to use an environment variable instead. Fitbit allows login via Google and Facebook. This library only works with an email / password based login. \n\n```{r}\nlibrary(\"fitbitScraper\")\ncookie <- login(email=\"corynissen@gmail.com\", password=Sys.getenv(\"FBPW\"))\n```\n\nNow you can run any of the other functions to get your data. Let's start with getting steps on a 15 minute interval for a given week...\n\n```{r, fig.height=4, fig.width=5, message=FALSE, warning=FALSE, fig.align='center'}\ndates <- seq(as.Date(\"2016-04-03\"), as.Date(\"2016-04-09\"), by=\"day\")\ndf_list <- lapply(dates, function(x)\n  get_intraday_data(cookie=cookie, what=\"steps\", as.character(x)))\ndf <- do.call(rbind, df_list)\n\nlibrary(\"ggplot2\")\nlibrary(\"ggthemes\")\nggplot(df) + \n  geom_bar(aes(x=time, y=steps), stat=\"identity\") + \n  theme_tufte() + \n  scale_x_datetime(name=\"date\", date_breaks=\"1 day\", date_labels=\"%b-%d\")\n```\n\nYou can get a daily summary of your data also. Here, I download data for the number of flights of stairs I climbed for the last two months. Then, compute the average number of flights of stairs by day, and graph it. Not surprisingly, I climb more stairs on the weekends when I'm home than I do at work during the week. Note that it is possible to get this data using `get_intraday_data()` for each day, but this is much more efficient using just one call to the fibit API for the entire date range instead of one API call per day.\n\n```{r, fig.height=4, fig.width=5, message=FALSE, warning=FALSE, fig.align='center'}\ndf <- get_daily_data(cookie=cookie, what=\"floors\", start_date=\"2016-02-15\",\n                     end_date=\"2016-05-01\")\ndf$weekday <- format(df$time, \"%A\")\navgs <- by(df$floors, df$weekday, mean)\navgs <- data.frame(day=names(avgs), floors=as.numeric(avgs))\navgs$day <- factor(avgs$day, levels=avgs$day[c(4, 2, 6, 7, 5, 1, 3)])\n\nggplot(avgs) + \n  geom_bar(aes(x=day, y=floors), stat=\"identity\") + \n  theme_tufte() + \n  xlab(\"\") + \n  ylab(\"\") + \n  ggtitle(\"Average Floors by Day 2016-02-15 to 2016-05-01\") + \n  geom_text(aes(x=day,y=floors,label=round(floors, 1)),\n            vjust=1.1, colour=\"white\") + \n  theme(axis.text.y=element_blank(), axis.ticks.y=element_blank()) + \n  theme(plot.title=element_text(vjust=.5)) \n```\n\nAnother thing to look at, especially if you have the [Aria scale](https://www.fitbit.com/aria), is your weight. You can record your weight manually in the fitbit app, which is how I do it, or the Aria scale will sync it automatically. Any how, let's graph my steps vs. weight for a time period and see if there seems to be a correlation. Data is returned for use in a graph on the fitbit page, so if you include a date range larger than two weeks or so, it returns data for a subset of the days in your range. Fitbit seems to play pretty loose with the start and end dates too. I want data from 2015-01-01 to 2015-05-01, so I'll break that into several requests to fitbit.\n\n```{r, fig.height=4, fig.width=5, message=FALSE, warning=FALSE, fig.align='center'}\n# don't do this...\n# mywt <- get_weight_data(cookie, start_date=\"2015-01-01\", end_date=\"2015-05-01\")\nstart_date <- as.Date(\"2015-01-01\")\nend_date <- as.Date(\"2015-05-01\")\nwt_df_list <- list()      # initialize a list to put the weight dataframes into\nin_range <- TRUE          # indicator variable to tell when to exit while loop\ns_date <- start_date      # date to start with during loop\nwhile(in_range){\n  e_date <- s_date + 14\n  new_df <- get_weight_data(cookie, start_date=as.character(s_date),\n                            end_date=as.character(e_date))\n  wt_df_list[[as.character(s_date)]] <- new_df\n  s_date <- e_date + 1\n  if(e_date > end_date) in_range <- FALSE\n}\nwt_df <- do.call(rbind, wt_df_list)\nwt_df <- wt_df[!duplicated(wt_df$time), ]\nwt_df <- wt_df[order(wt_df$time), ]\nwt_df <- wt_df[as.Date(wt_df$time) >= start_date &\n               as.Date(wt_df$time) <= end_date, ]\n\nstep_df <- get_daily_data(cookie=cookie, what=\"steps\", start_date=\"2015-01-01\",\n                          end_date=\"2015-05-01\")\n\n# get common date format to merge data sets...\nwt_df$date <- as.character(as.Date(wt_df$time))\nstep_df$date <- as.character(as.Date(step_df$time))\n\n# merge by date\ndf <- merge(wt_df, step_df, by=\"date\")\n\n# now plot\nggplot(df, aes(x=steps, y=weight)) + \n  geom_point() + \n  stat_smooth(se=FALSE) + \n  theme_tufte()\n```  \n  \nThat last example illustrates one of the limitations of retrieving the data the way this library does. Instead of using the \"official\" fitbit API, this library uses the API intended for their website developer to use to build the visualizations on the web dashboard. So, there's no public documentation. This results in situations like the last one where the weight data returned by that API call is intended to be used in a chart, so they don't need more than 20 points, so that's all that is returned, no matter how large the date range supplied is. Keep this in mind when you request data and use caution that you are being returned data for the same dates that you requested it for.\n\n\n\n\n"
  }
]