mirror of
https://github.com/sstent/containers.git
synced 2025-12-06 08:01:51 +00:00
first
This commit is contained in:
14
fitbit-collect/Dockerfile
Normal file
14
fitbit-collect/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM alpine:latest
|
||||
|
||||
RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/repositories
|
||||
|
||||
RUN apk add --no-cache python3 && \
|
||||
python3 -m ensurepip && \
|
||||
rm -r /usr/lib/python*/ensurepip && \
|
||||
pip3 install --upgrade pip setuptools && \
|
||||
if [ ! -e /usr/bin/pip ]; then ln -s pip3 /usr/bin/pip ; fi && \
|
||||
if [[ ! -e /usr/bin/python ]]; then ln -sf /usr/bin/python3 /usr/bin/python; fi
|
||||
ADD requirements.txt .
|
||||
RUN pip3 install -r requirements.txt
|
||||
ADD * ./
|
||||
ENTRYPOINT ["python","./run_collect.py"]
|
||||
1
fitbit-collect/README.md
Normal file
1
fitbit-collect/README.md
Normal file
@@ -0,0 +1 @@
|
||||
[](http://droneci.service.dc1.consul/sstent/fitbit-collect)
|
||||
1
fitbit-collect/client_details.json
Normal file
1
fitbit-collect/client_details.json
Normal file
@@ -0,0 +1 @@
|
||||
{"client_id": "22BQMP", "client_secret": "280a9e3702af04f687a84862c3f6f6ac"}
|
||||
1
fitbit-collect/credentials.json
Normal file
1
fitbit-collect/credentials.json
Normal file
@@ -0,0 +1 @@
|
||||
{"installed":{"client_id":"182877671696-qj1oq6pi50s6v7nk16m59ulmg28klo0r.apps.googleusercontent.com","project_id":"quickstart-1588344492360","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"oSI3LMMY9caNiGgH0NKSO3oS","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}
|
||||
1
fitbit-collect/fitbit_data.json
Normal file
1
fitbit-collect/fitbit_data.json
Normal file
@@ -0,0 +1 @@
|
||||
{"weight": [{"bmi": 28.25, "date": "2020-04-02", "fat": 25.09000015258789, "logId": 1585811810000, "source": "Aria", "time": "07:16:50", "weight": 214}, {"bmi": 28.15, "date": "2020-04-03", "fat": 25.065000534057617, "logId": 1585899007000, "source": "Aria", "time": "07:30:07", "weight": 213.2}, {"bmi": 27.96, "date": "2020-04-04", "fat": 24.951000213623047, "logId": 1585987894000, "source": "Aria", "time": "08:11:34", "weight": 211.8}, {"bmi": 27.86, "date": "2020-04-05", "fat": 24.893999099731445, "logId": 1586075240000, "source": "Aria", "time": "08:27:20", "weight": 211}, {"bmi": 28.15, "date": "2020-04-07", "fat": 24.836999893188477, "logId": 1586243500000, "source": "Aria", "time": "07:11:40", "weight": 213.2}, {"bmi": 28.15, "date": "2020-04-08", "fat": 24.450000762939453, "logId": 1586330108000, "source": "Aria", "time": "07:15:08", "weight": 213.2}, {"bmi": 27.99, "date": "2020-04-09", "fat": 24.375999450683594, "logId": 1586420024000, "source": "Aria", "time": "08:13:44", "weight": 212}, {"bmi": 27.92, "date": "2020-04-10", "fat": 24.42300033569336, "logId": 1586502607000, "source": "Aria", "time": "07:10:07", "weight": 211.5}, {"bmi": 27.87, "date": "2020-04-11", "fat": 24.47100067138672, "logId": 1586589049000, "source": "Aria", "time": "07:10:49", "weight": 211.2}, {"bmi": 27.76, "date": "2020-04-12", "fat": 24.447999954223633, "logId": 1586676059000, "source": "Aria", "time": "07:20:59", "weight": 210.3}, {"bmi": 27.92, "date": "2020-04-13", "fat": 24.461000442504883, "logId": 1586764670000, "source": "Aria", "time": "07:57:50", "weight": 211.5}, {"bmi": 27.96, "date": "2020-04-14", "fat": 24.388999938964844, "logId": 1586849081000, "source": "Aria", "time": "07:24:41", "weight": 211.8}, {"bmi": 27.91, "date": "2020-04-15", "fat": 24.343000411987305, "logId": 1586935775000, "source": "Aria", "time": "07:29:35", "weight": 211.4}, {"bmi": 27.74, "date": "2020-04-16", "fat": 24.270999908447266, "logId": 1587021443000, "source": "Aria", "time": "07:17:23", "weight": 210.1}, {"bmi": 27.71, "date": "2020-04-17", "fat": 24.204999923706055, "logId": 1587108701000, "source": "Aria", "time": "07:31:41", "weight": 209.9}, {"bmi": 27.59, "date": "2020-04-18", "fat": 24.158000946044922, "logId": 1587194397000, "source": "Aria", "time": "07:19:57", "weight": 209}, {"bmi": 27.62, "date": "2020-04-19", "fat": 24.12299919128418, "logId": 1587284042000, "source": "Aria", "time": "08:14:02", "weight": 209.2}, {"bmi": 27.91, "date": "2020-04-20", "fat": 24.052000045776367, "logId": 1587367302000, "source": "Aria", "time": "07:21:42", "weight": 211.4}]}
|
||||
158
fitbit-collect/gather_keys_oauth2.py
Normal file
158
fitbit-collect/gather_keys_oauth2.py
Normal file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Note: This file was adapted from the unoffiicial Python Fitbit client Git repo:
|
||||
https://raw.githubusercontent.com/orcasgit/python-fitbit/master/gather_keys_oauth2.py
|
||||
"""
|
||||
import cherrypy
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import webbrowser
|
||||
import json
|
||||
|
||||
from urllib.parse import urlparse
|
||||
# import urllib.parse as urlparse
|
||||
from base64 import b64encode
|
||||
from fitbit.api import Fitbit, FitbitOauth2Client
|
||||
from oauthlib.oauth2.rfc6749.errors import MismatchingStateError, MissingTokenError
|
||||
|
||||
CLIENT_DETAILS_FILE = 'client_details.json' # configuration for for the client
|
||||
USER_DETAILS_FILE = 'user_details.json' # user details file
|
||||
|
||||
|
||||
class OAuth2Server:
|
||||
def __init__(self, client_id, client_secret,
|
||||
redirect_uri='http://127.0.0.1:8080/'):
|
||||
""" Initialize the FitbitOauth2Client """
|
||||
self.success_html = """
|
||||
<h1>You are now authorized to access the Fitbit API!</h1>
|
||||
<br/><h3>You can close this window</h3>"""
|
||||
self.failure_html = """
|
||||
<h1>ERROR: %s</h1><br/><h3>You can close this window</h3>%s"""
|
||||
|
||||
self.fitbit = Fitbit(
|
||||
client_id,
|
||||
client_secret,
|
||||
redirect_uri=redirect_uri,
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
self.redirect_uri = redirect_uri
|
||||
self.oauth = FitbitOauth2Client(client_id, client_secret)
|
||||
|
||||
|
||||
def headless_authorize(self):
|
||||
"""
|
||||
Authorize without a display using only TTY.
|
||||
"""
|
||||
url, _ = self.oauth.authorize_token_url(redirect_uri=self.redirect_uri)
|
||||
# Ask the user to open this url on a system with browser
|
||||
print('\n-------------------------------------------------------------------------')
|
||||
print('\t\tOpen the below URL in your browser\n')
|
||||
print(url)
|
||||
print('\n-------------------------------------------------------------------------\n')
|
||||
print('NOTE: After authenticating on Fitbit website, you will redirected to a URL which ')
|
||||
print('throws an ERROR. This is expected! Just copy the full redirected here.\n')
|
||||
redirected_url = input('Full redirected URL: ')
|
||||
params = urlparse.parse_qs(urlparse.urlparse(redirected_url).query)
|
||||
print(params['code'][0])
|
||||
self.authenticate_code(code=params['code'][0])
|
||||
|
||||
def browser_authorize(self):
|
||||
"""
|
||||
Open a browser to the authorization url and spool up a CherryPy
|
||||
server to accept the response
|
||||
"""
|
||||
url, _ = self.fitbit.client.authorize_token_url()
|
||||
# Open the web browser in a new thread for command-line browser support
|
||||
threading.Timer(1, webbrowser.open, args=(url,)).start()
|
||||
print()
|
||||
print('URL for authenticating is:')
|
||||
print(url)
|
||||
print()
|
||||
|
||||
# Same with redirect_uri hostname and port.
|
||||
urlparams = urlparse(self.redirect_uri)
|
||||
cherrypy.config.update({'server.socket_host': '0.0.0.0',
|
||||
'server.socket_port': urlparams.port})
|
||||
|
||||
cherrypy.quickstart(self)
|
||||
|
||||
def authenticate_code(self, code=None):
|
||||
"""
|
||||
Final stage of authentication using the code from Fitbit.
|
||||
"""
|
||||
try:
|
||||
self.oauth.fetch_access_token(code, self.redirect_uri)
|
||||
except MissingTokenError:
|
||||
error = self._fmt_failure(
|
||||
'Missing access token parameter.</br>Please check that '
|
||||
'you are using the correct client_secret'
|
||||
)
|
||||
except MismatchingStateError:
|
||||
error = self._fmt_failure('CSRF Warning! Mismatching state')
|
||||
|
||||
@cherrypy.expose
|
||||
|
||||
def index(self, state, code=None, error=None):
|
||||
"""
|
||||
Receive a Fitbit response containing a verification code. Use the code
|
||||
to fetch the access_token.
|
||||
"""
|
||||
error = None
|
||||
if code:
|
||||
try:
|
||||
self.fitbit.client.fetch_access_token(code)
|
||||
except MissingTokenError:
|
||||
error = self._fmt_failure(
|
||||
'Missing access token parameter.</br>Please check that '
|
||||
'you are using the correct client_secret')
|
||||
except MismatchingStateError:
|
||||
error = self._fmt_failure('CSRF Warning! Mismatching state')
|
||||
else:
|
||||
error = self._fmt_failure('Unknown error while authenticating')
|
||||
# Use a thread to shutdown cherrypy so we can return HTML first
|
||||
self._shutdown_cherrypy()
|
||||
return error if error else self.success_html
|
||||
|
||||
def _fmt_failure(self, message):
|
||||
tb = traceback.format_tb(sys.exc_info()[2])
|
||||
tb_html = '<pre>%s</pre>' % ('\n'.join(tb)) if tb else ''
|
||||
return self.failure_html % (message, tb_html)
|
||||
|
||||
def _shutdown_cherrypy(self):
|
||||
""" Shutdown cherrypy in one second, if it's running """
|
||||
if cherrypy.engine.state == cherrypy.engine.states.STARTED:
|
||||
threading.Timer(1, cherrypy.engine.exit).start()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not (len(sys.argv) == 3):
|
||||
print("Arguments: client_id and client_secret")
|
||||
sys.exit(1)
|
||||
|
||||
client_id = sys.argv[1]
|
||||
client_secret = sys.argv[2]
|
||||
server = OAuth2Server(client_id, client_secret)
|
||||
# server.headless_authorize()
|
||||
server.browser_authorize()
|
||||
|
||||
profile = server.fitbit.user_profile_get()
|
||||
print('You are authorized to access data for the user: {}'.format(
|
||||
profile['user']['fullName']))
|
||||
|
||||
print('TOKEN\n=====\n')
|
||||
for key, value in server.fitbit.client.session.token.items():
|
||||
print('{} = {}'.format(key, value))
|
||||
|
||||
print("Writing client details to file for usage on next collection.")
|
||||
client_details = {'client_id': client_id, 'client_secret': client_secret} # Details of application
|
||||
with open(CLIENT_DETAILS_FILE, 'w') as f:
|
||||
json.dump(client_details, f)
|
||||
|
||||
print("Writing user details to file for usage on next collection.")
|
||||
with open(USER_DETAILS_FILE, 'w') as f:
|
||||
json.dump(server.fitbit.client.session.token, f)
|
||||
|
||||
71
fitbit-collect/googlesheet.py
Normal file
71
fitbit-collect/googlesheet.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from __future__ import print_function
|
||||
import pickle
|
||||
import os.path
|
||||
from googleapiclient.discovery import build
|
||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||
from google.auth.transport.requests import Request
|
||||
|
||||
# If modifying these scopes, delete the file token.pickle.
|
||||
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
|
||||
|
||||
# The ID and range of a sample spreadsheet.
|
||||
SAMPLE_SPREADSHEET_ID = '1YkMf_3m2YroHhtyS2FrdLzm3HnJDk4-q8r4cSagYrrg'
|
||||
SAMPLE_RANGE_NAME = 'fitbit_export!A2:E'
|
||||
|
||||
def UpdateSheet():
|
||||
"""Shows basic usage of the Sheets API.
|
||||
Prints values from a sample spreadsheet.
|
||||
"""
|
||||
creds = None
|
||||
# The file token.pickle stores the user's access and refresh tokens, and is
|
||||
# created automatically when the authorization flow completes for the first
|
||||
# time.
|
||||
if os.path.exists('token.pickle'):
|
||||
with open('token.pickle', 'rb') as token:
|
||||
creds = pickle.load(token)
|
||||
# If there are no (valid) credentials available, let the user log in.
|
||||
if not creds or not creds.valid:
|
||||
if creds and creds.expired and creds.refresh_token:
|
||||
creds.refresh(Request())
|
||||
else:
|
||||
flow = InstalledAppFlow.from_client_secrets_file(
|
||||
'credentials.json', SCOPES)
|
||||
creds = flow.run_local_server(port=0)
|
||||
# Save the credentials for the next run
|
||||
with open('token.pickle', 'wb') as token:
|
||||
pickle.dump(creds, token)
|
||||
|
||||
service = build('sheets', 'v4', credentials=creds)
|
||||
|
||||
# Call the Sheets API
|
||||
sheet = service.spreadsheets()
|
||||
result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
|
||||
range=SAMPLE_RANGE_NAME).execute()
|
||||
values = result.get('values', [])
|
||||
|
||||
if not values:
|
||||
print('No data found.')
|
||||
else:
|
||||
print('Name, Major:')
|
||||
for row in values:
|
||||
# Print columns A and E, which correspond to indices 0 and 4.
|
||||
print('%s, %s' % (row[0], row[4]))
|
||||
|
||||
values = [
|
||||
[
|
||||
"TEST", "TEST"
|
||||
],
|
||||
]
|
||||
body = {
|
||||
'values': values
|
||||
}
|
||||
result = service.spreadsheets().values().append(
|
||||
spreadsheetId=SAMPLE_SPREADSHEET_ID,range=SAMPLE_RANGE_NAME,
|
||||
valueInputOption='RAW', body=body).execute()
|
||||
print('{0} cells appended.'.format(result \
|
||||
.get('updates') \
|
||||
.get('updatedCells')))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
47
fitbit-collect/jsonconsul.py
Normal file
47
fitbit-collect/jsonconsul.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import consul
|
||||
import json
|
||||
|
||||
USER_DETAILS_FILE = 'user_details.json' # user details file
|
||||
|
||||
|
||||
c = consul.Consul(host='192.168.1.237')
|
||||
|
||||
# def _get_user_details():
|
||||
# """
|
||||
# The specific user that you want to retrieve data for.
|
||||
# """
|
||||
# with open(USER_DETAILS_FILE) as f:
|
||||
# fitbit_user = json.load(f)
|
||||
# access_token = fitbit_user['access_token']
|
||||
# refresh_token = fitbit_user['refresh_token']
|
||||
# expires_at = fitbit_user['expires_at']
|
||||
|
||||
# return access_token, refresh_token, expires_at
|
||||
|
||||
def _set_user_details(access_token, refresh_token, expires_at):
|
||||
c.kv.put('access_token', access_token)
|
||||
c.kv.put('refresh_token', refresh_token)
|
||||
c.kv.put('expires_at', str(expires_at))
|
||||
|
||||
def _get_user_details():
|
||||
access_token = c.kv.get('access_token')[1]["Value"].decode("utf-8")
|
||||
refresh_token = c.kv.get('refresh_token')[1]["Value"].decode("utf-8")
|
||||
expires_at = c.kv.get('expires_at')[1]["Value"].decode("utf-8")
|
||||
return access_token, refresh_token, expires_at
|
||||
|
||||
|
||||
|
||||
|
||||
# access_token, refresh_token, expires_at = _get_user_details()
|
||||
# store_user_details(access_token, refresh_token, expires_at)
|
||||
|
||||
access_token, refresh_token, expires_at = _get_user_details()
|
||||
|
||||
print(access_token)
|
||||
print(expires_at)
|
||||
print(refresh_token)
|
||||
|
||||
# print(access_token[1]["Value"].decode("utf-8"))
|
||||
# print(refresh_token[1]["Value"].decode("utf-8"))
|
||||
# print(expires_at[1]["Value"].decode("utf-8"))
|
||||
|
||||
58
fitbit-collect/plot.py
Normal file
58
fitbit-collect/plot.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
|
||||
def plot_steps(data):
|
||||
steps = data['activities-log-steps']
|
||||
|
||||
x = [datetime.strptime(d['dateTime'], '%Y-%M-%d').strftime("%A") for d in steps]
|
||||
y = [float(d['value']) for d in steps]
|
||||
|
||||
plt.bar(x,y)
|
||||
plt.title('Steps last 7 days')
|
||||
plt.show()
|
||||
|
||||
|
||||
def plot_sleep(data):
|
||||
sleep = data['sleep']
|
||||
x = [datetime.strptime(d['dateOfSleep'], '%Y-%M-%d').strftime("%A") for d in sleep][::-1]
|
||||
|
||||
deep = [float(d['levels']['summary']['deep']['minutes'])/60.0 for d in sleep][::-1]
|
||||
light = [float(d['levels']['summary']['light']['minutes'])/60.0 for d in sleep][::-1]
|
||||
rem = [float(d['levels']['summary']['rem']['minutes'])/60.0 for d in sleep][::-1]
|
||||
awake = [float(d['levels']['summary']['wake']['minutes'])/60.0 for d in sleep][::-1]
|
||||
|
||||
barWidth = 0.15
|
||||
|
||||
r1 = np.arange(len(deep))
|
||||
r2 = [x + barWidth for x in r1]
|
||||
r3 = [x + barWidth for x in r2]
|
||||
r4 = [x + barWidth for x in r3]
|
||||
|
||||
# Make the plot
|
||||
plt.bar(r1, awake, color='#ffa600', width=barWidth, edgecolor='white', label='Awake')
|
||||
plt.bar(r2, rem, color='#ff6361', width=barWidth, edgecolor='white', label='REM')
|
||||
plt.bar(r3, light, color='#bc5090', width=barWidth, edgecolor='white', label='Light')
|
||||
plt.bar(r4, deep, color='#003f5c', width=barWidth, edgecolor='white', label='Deep')
|
||||
|
||||
# Add xticks on the middle of the group bars
|
||||
plt.xlabel('Day', fontweight='bold')
|
||||
plt.ylabel('Hours', fontweight='bold')
|
||||
plt.xticks([r + barWidth for r in range(len(deep))], x)
|
||||
|
||||
# Create legend & Show graphic
|
||||
plt.legend()
|
||||
plt.show()
|
||||
|
||||
if __name__ == '__main__':
|
||||
with open('fitbit_data.json') as f:
|
||||
data = json.load(f)
|
||||
|
||||
#plot_steps(data)
|
||||
plot_sleep(data)
|
||||
|
||||
|
||||
|
||||
7
fitbit-collect/requirements.txt
Normal file
7
fitbit-collect/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
fitbit==0.3.1
|
||||
google-api-python-client
|
||||
google-auth-httplib2
|
||||
google-auth-oauthlib
|
||||
python-consul
|
||||
# cherrypy==18.6.0
|
||||
# matplotlib==3.2.1
|
||||
260
fitbit-collect/run_collect.py
Normal file
260
fitbit-collect/run_collect.py
Normal file
@@ -0,0 +1,260 @@
|
||||
"""
|
||||
Script to retrieve Fitbit data for the given user
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import json
|
||||
from pprint import pprint
|
||||
from fitbit import Fitbit
|
||||
import pickle
|
||||
import os.path
|
||||
from googleapiclient.discovery import build
|
||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||
from google.auth.transport.requests import Request
|
||||
from datetime import date, timedelta
|
||||
|
||||
import consul
|
||||
|
||||
dt = date.today() - timedelta(7)
|
||||
|
||||
|
||||
|
||||
c = consul.Consul(host='consul.service.dc1.consul')
|
||||
|
||||
# If modifying these scopes, delete the file token.pickle.
|
||||
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
|
||||
|
||||
# The ID and range of a sample spreadsheet.
|
||||
SAMPLE_SPREADSHEET_ID = '1YkMf_3m2YroHhtyS2FrdLzm3HnJDk4-q8r4cSagYrrg'
|
||||
SAMPLE_RANGE_NAME = 'fitbit_export!A2:E'
|
||||
|
||||
|
||||
|
||||
FITBIT_API = 'https://api.fitbit.com'
|
||||
|
||||
CLIENT_DETAILS_FILE = 'client_details.json' # configuration for for the client
|
||||
USER_DETAILS_FILE = 'user_details.json' # user details file
|
||||
|
||||
RESULT_FILE = 'fitbit_data.json' # The place where we will place the results
|
||||
|
||||
|
||||
# def refresh_callback(token):
|
||||
# """
|
||||
# This method is only called when the authenticate token is out of date
|
||||
# and a new token has been issued which needs to be stored somewhere for
|
||||
# the next run
|
||||
# param (token): A dictionary with the new details
|
||||
# """
|
||||
# print('CALLBACK: The token has been updated since last run')
|
||||
# with open(USER_DETAILS_FILE, 'w') as f:
|
||||
# json.dump(token, f)
|
||||
# print('Successfully written update refresh token')
|
||||
|
||||
def refresh_callback(token):
|
||||
c.kv.put('access_token', token["access_token"])
|
||||
c.kv.put('refresh_token', token["refresh_token"])
|
||||
c.kv.put('expires_at', str(token["expires_at"]))
|
||||
|
||||
# def _get_user_details():
|
||||
# """
|
||||
# The specific user that you want to retrieve data for.
|
||||
# """
|
||||
# with open(USER_DETAILS_FILE) as f:
|
||||
# fitbit_user = json.load(f)
|
||||
# access_token = fitbit_user['access_token']
|
||||
# refresh_token = fitbit_user['refresh_token']
|
||||
# expires_at = fitbit_user['expires_at']
|
||||
|
||||
# print(type(expires_at))
|
||||
# return access_token, refresh_token, expires_at
|
||||
|
||||
|
||||
|
||||
def _get_user_details():
|
||||
access_token = c.kv.get('access_token')[1]["Value"].decode("utf-8")
|
||||
refresh_token = c.kv.get('refresh_token')[1]["Value"].decode("utf-8")
|
||||
expires_at = float(c.kv.get('expires_at')[1]["Value"].decode("utf-8"))
|
||||
return access_token, refresh_token, expires_at
|
||||
|
||||
|
||||
def _get_client_details():
|
||||
"""The client is the application which requires access"""
|
||||
with open(CLIENT_DETAILS_FILE) as f:
|
||||
client_details = json.load(f)
|
||||
client_id = client_details['client_id']
|
||||
client_secret = client_details['client_secret']
|
||||
|
||||
return client_id, client_secret
|
||||
|
||||
|
||||
def _write_results(json_response):
|
||||
with open(RESULT_FILE, 'w') as f:
|
||||
json.dump(json_response, f)
|
||||
print(f'Successfully written result data to file {RESULT_FILE}')
|
||||
|
||||
|
||||
def _get_api_call():
|
||||
"""
|
||||
Date Api in this format:
|
||||
GET /<api-version>/user/<user-id>/<resource-path>/date/<base-date>/<end-date>.<response-format>
|
||||
<user-id> can be left as - to get the current user
|
||||
date format is '%Y-%m-%d' for example 2020-04-01
|
||||
Some examples below
|
||||
"""
|
||||
# # Steps in the last 7 days
|
||||
# steps_last_seven_days = '/1/user/-/activities/log/steps/date/today/7d.json'
|
||||
# # Steps between two dates
|
||||
# steps_dates = '/1/user/-/activities/log/steps/date/2020-04-12/2020-04-18.json'
|
||||
# # calories last 7 days
|
||||
# calories_last_seven_days = '/1/user/-/activities/log/calories/date/today/7d.json'
|
||||
# # profile info
|
||||
# profile_info = '/1/user/-/profile.json'
|
||||
# # Sleep between two dates
|
||||
# sleep_dates = '/1.2/user/-/sleep/date/2020-04-13/2020-04-17.json'
|
||||
weight = '/1.2/user/-/body/log/weight/date/' + str(date_start) + '/' + str(date_end) + '.json'
|
||||
|
||||
return weight
|
||||
|
||||
|
||||
def ReadSheet():
|
||||
"""Shows basic usage of the Sheets API.
|
||||
Prints values from a sample spreadsheet.
|
||||
"""
|
||||
creds = None
|
||||
# The file token.pickle stores the user's access and refresh tokens, and is
|
||||
# created automatically when the authorization flow completes for the first
|
||||
# time.
|
||||
if os.path.exists('token.pickle'):
|
||||
with open('token.pickle', 'rb') as token:
|
||||
creds = pickle.load(token)
|
||||
# If there are no (valid) credentials available, let the user log in.
|
||||
if not creds or not creds.valid:
|
||||
if creds and creds.expired and creds.refresh_token:
|
||||
creds.refresh(Request())
|
||||
else:
|
||||
flow = InstalledAppFlow.from_client_secrets_file(
|
||||
'credentials.json', SCOPES)
|
||||
creds = flow.run_local_server(port=0)
|
||||
# Save the credentials for the next run
|
||||
with open('token.pickle', 'wb') as token:
|
||||
pickle.dump(creds, token)
|
||||
|
||||
service = build('sheets', 'v4', credentials=creds)
|
||||
|
||||
# Call the Sheets API
|
||||
sheet = service.spreadsheets()
|
||||
result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
|
||||
range=SAMPLE_RANGE_NAME).execute()
|
||||
curr_values = result.get('values', [])
|
||||
return curr_values
|
||||
|
||||
|
||||
def UpdateSheet(values):
|
||||
"""Shows basic usage of the Sheets API.
|
||||
Prints values from a sample spreadsheet.
|
||||
"""
|
||||
creds = None
|
||||
# The file token.pickle stores the user's access and refresh tokens, and is
|
||||
# created automatically when the authorization flow completes for the first
|
||||
# time.
|
||||
if os.path.exists('token.pickle'):
|
||||
with open('token.pickle', 'rb') as token:
|
||||
creds = pickle.load(token)
|
||||
# If there are no (valid) credentials available, let the user log in.
|
||||
if not creds or not creds.valid:
|
||||
if creds and creds.expired and creds.refresh_token:
|
||||
creds.refresh(Request())
|
||||
else:
|
||||
flow = InstalledAppFlow.from_client_secrets_file(
|
||||
'credentials.json', SCOPES)
|
||||
creds = flow.run_local_server(port=0)
|
||||
# Save the credentials for the next run
|
||||
with open('token.pickle', 'wb') as token:
|
||||
pickle.dump(creds, token)
|
||||
|
||||
service = build('sheets', 'v4', credentials=creds)
|
||||
|
||||
# Call the Sheets API
|
||||
# sheet = service.spreadsheets()
|
||||
# result = sheet.values().get(spreadsheetId=SAMPLE_SPREADSHEET_ID,
|
||||
# range=SAMPLE_RANGE_NAME).execute()
|
||||
# values = result.get('values', [])
|
||||
|
||||
# if not values:
|
||||
# print('No data found.')
|
||||
# else:
|
||||
# print('Name, Major:')
|
||||
# for row in values:
|
||||
# # Print columns A and E, which correspond to indices 0 and 4.
|
||||
# print('%s, %s' % (row[0], row[4]))
|
||||
|
||||
# values = [
|
||||
# [
|
||||
# "TEST", "TEST"
|
||||
# ],
|
||||
# ]
|
||||
body = {
|
||||
'values': values
|
||||
}
|
||||
result = service.spreadsheets().values().append(
|
||||
spreadsheetId=SAMPLE_SPREADSHEET_ID,range=SAMPLE_RANGE_NAME,
|
||||
valueInputOption='RAW', body=body).execute()
|
||||
print('{0} cells appended.'.format(result \
|
||||
.get('updates') \
|
||||
.get('updatedCells')))
|
||||
|
||||
|
||||
|
||||
def run():
|
||||
client_id, client_secret = _get_client_details()
|
||||
access_token, refresh_token, expires_at = _get_user_details()
|
||||
|
||||
#print(f'Running Fitbit request with details: {client_id} {client_secret}'
|
||||
# f' {access_token} {refresh_token} {expires_at}')
|
||||
auth2_client = Fitbit(client_id, client_secret, oauth2=True,
|
||||
access_token=access_token,
|
||||
refresh_token=refresh_token, expires_at=expires_at,
|
||||
refresh_cb=refresh_callback)
|
||||
|
||||
fitbit_url = FITBIT_API + _get_api_call()
|
||||
json_response = auth2_client.make_request(fitbit_url)
|
||||
# _write_results(json_response)
|
||||
# pprint(json_response["weight"])
|
||||
values = []
|
||||
sheet_values = ReadSheet()
|
||||
# pprint(sheet_values)
|
||||
|
||||
for row in json_response["weight"]:
|
||||
row_exists = 0
|
||||
for sheetrow in sheet_values:
|
||||
if sheetrow[0] == row["date"]:
|
||||
row_exists = 1
|
||||
if row_exists == 0:
|
||||
if 'fat' in row.keys():
|
||||
row_list = [row["date"],row["weight"],row["fat"],row["bmi"]]
|
||||
else:
|
||||
row_list = [row["date"],row["weight"],"0",row["bmi"]]
|
||||
values.append(row_list)
|
||||
pprint(date_start)
|
||||
pprint(values)
|
||||
UpdateSheet(values)
|
||||
# sheet_values = ReadSheet()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
|
||||
date_start = date.today() - timedelta(31)
|
||||
# date_end = date.today()
|
||||
# run()
|
||||
|
||||
###Bulk import
|
||||
# date_start = date(2015, 8, 1)
|
||||
end_date = date(2019, 10, 1)
|
||||
|
||||
while date_start != end_date:
|
||||
# date_end = date.today() + timedelta(30)
|
||||
date_end = date_start + timedelta(30)
|
||||
# date_start = date.today() - timedelta(31)
|
||||
run()
|
||||
# time.sleep(60)
|
||||
date_start = date_start - timedelta(29)
|
||||
BIN
fitbit-collect/token.pickle
Normal file
BIN
fitbit-collect/token.pickle
Normal file
Binary file not shown.
1
fitbit-collect/user_details.json
Normal file
1
fitbit-collect/user_details.json
Normal file
@@ -0,0 +1 @@
|
||||
{"access_token": "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyMkJRTVAiLCJzdWIiOiIyRk5WTkYiLCJpc3MiOiJGaXRiaXQiLCJ0eXAiOiJhY2Nlc3NfdG9rZW4iLCJzY29wZXMiOiJyc29jIHJhY3QgcnNldCBybG9jIHJ3ZWkgcmhyIHJudXQgcnBybyByc2xlIiwiZXhwIjoxNTg4MzcxNjE0LCJpYXQiOjE1ODgzNDI4MTR9.yi2T21Qt8L9kvY_9QLLh_iOaYuz1BP4ywuILmJVOQhk", "expires_in": 28800, "refresh_token": "c2e0e5c952e7063ab7bd17745b6df50793afb281f0b6172a0abc88d98e279eca", "scope": ["activity", "nutrition", "social", "weight", "heartrate", "profile", "settings", "sleep", "location"], "token_type": "Bearer", "user_id": "2FNVNF", "expires_at": 1588371583.8789062}
|
||||
Reference in New Issue
Block a user