Created
August 6, 2015 19:23
-
-
Save ltddev/215736a0d8d41862b518 to your computer and use it in GitHub Desktop.
FitbitSleepAnalyzerController.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
''' | |
FitbitSleepAnalyzer.py | |
This script is a simple implentation of the Python Fitbit library, primarily in order to experiment | |
with the api because my children bought me a Fitbit bracelet for fathers day and the device is reputed | |
to capture sleep data based all off its accelerometer. I wear this device all day and all night and | |
sync it regularly. Therefore I am able to perform a better analysis of the sleep data than Fitbit dooes. | |
Currently Fitbit dashboard presents a monthly view of the data but beyond that it does not essentially | |
do anything else. I propose for this app a multi paga/View that uses some as yet conceived algorithm | |
to tuly analze -- as opposed to presenting only. But this is the first initial stab at such an app. | |
''' | |
class FitbitSleepAnalyzer: | |
def __init__(self,ownerKey,ownerSecret,resourceOwnerKey,resourceOwnerSecret): | |
import fitbit | |
# All this because of peculiar format fitbit api requires to get a secure client | |
self.ownerKey = ownerKey | |
self.ownerSecret = ownerSecret | |
self.resourceOwnerKey = resourceOwnerKey | |
self.resourceOwnerSecret =resourceOwnerSecret | |
# Class variable which should be visible to other methods | |
self.authd_client = fitbit.Fitbit(ownerKey,ownerSecret,resource_owner_key=resourceOwnerKey,resource_owner_secret=resourceOwnerSecret) | |
def getCurrentDeviceInfo(self): | |
#Returns potentially multiple devices, let caller determine | |
return self.authd_client.get_devices() | |
def getSleepDataDictionary(self, datetime): | |
import fitbit | |
sleepUnitsDict = self.authd_client.get_sleep(datetime) | |
sleepList = sleepUnitsDict['sleep'] | |
if sleepList==[]: | |
# if list is empty then return just empty dictionary. | |
return[] | |
# if we are here we're good to grab the first item in the list.' | |
sleepDataDict = sleepList[0] # only one item in this list, a dictionary. | |
return sleepDataDict | |
def getSleepSummaryDataDictionary(self, datetime): | |
import fitbit | |
sleepUnitsDict = self.authd_client.get_sleep(datetime) | |
sleepSummaryList = sleepUnitsDict['summary'] | |
print 'summary test:'+ str(sleepUnitsDict) | |
if sleepSummaryList==[]: | |
# if list is empty then return just empty dictionary. | |
return[] | |
sleepSummaryDataDict = sleepSummaryList[0] | |
return sleepDataDict | |
import ui, console,datetime | |
# Bring up UI and control its actions | |
class ViewController(): | |
import datetime | |
import console | |
from FitbitSleepAnalyzerController import FitbitSleepAnalyzer | |
def __init__(self): | |
view = ui.load_view('FitbitSleepAnalyzerView') | |
# Save off the address to use later elsewhere in class. | |
# from other class methods and handlers. | |
self.textView = view['textView'] | |
self.datePicker = view['datepicker'] | |
self.errorMessage = view['noDataLabel'] | |
self.errorMessageString = view['noDataLabel'] | |
imageView = view['imageView'] | |
imageView.image = ui.Image.named('fitbit-1024-blk-onwhite.jpg') | |
self.graphImageView = view['graphImageView'] | |
self.dateSelected = view['datepicker'].date | |
view.present('popover') | |
# We make the connection to secure fitbit here in the __init__ method and cache to use from | |
# other nethod. Some of the numbers have been mixed up in thr final public code;Should be read from a file or passed in anyway -- hardcoding is bad! | |
# Just shown for educational purposes. | |
ownerKey = '66febeae096fe9442d10dd3e92d54de2' | |
ownerSecret = 'b8b002ddf50dd3525f57b9a350051b97' | |
resourceOwnerKey = '20eb22828f652f729002ba0f855d07f3' | |
resourceOwnerSecret = '48eaa2e1e11ea551d1e3579c3274cccd' | |
date = self.dateSelected | |
self.fitbitimpl = FitbitSleepAnalyzer(ownerKey,ownerSecret,resourceOwnerKey,resourceOwnerSecret) | |
def buttonTapped(self, sender): | |
if sender.name=='sleepDataButton': | |
self.performAnalysisTask() | |
elif sender.name == 'deviceButton': | |
self.performDeviceInfoTask() | |
elif sender.name == 'graphDataButton': | |
#self.performGraphTask() | |
self.getSleepSummaryDataDictionary() | |
def handleDatePicked(self, sender): | |
self.dateSelected = sender.date | |
def performDeviceInfoTask(self): | |
# todo get the auth client in the init of the controller to reduce duping. | |
import datetime | |
import console | |
self.dateSelected = self.datePicker.date | |
curDeviceInfoList = self.fitbitimpl.getCurrentDeviceInfo() | |
length = len(curDeviceInfoList) | |
if length==1 or length > 0: | |
myDevice = curDeviceInfoList[0] | |
batteryLevel = myDevice['battery'] | |
lastSyncTime = myDevice['lastSyncTime'] | |
macAddress = myDevice['mac'] | |
deviceType = myDevice['type'] | |
deviceId = myDevice['id'] | |
deviceVersion = myDevice['deviceVersion'] | |
# Trick I read on internet on how to emulate a string buffer in Python. | |
strList = [] | |
strList.append('Version: ' + deviceVersion + '\n') | |
strList.append('Device Type: ' + deviceType + '\n') | |
strList.append('Device Id: ' + deviceId + '\n') | |
strList.append('Battery level: ' + batteryLevel + '\n') | |
strList.append('Last sync: ' + lastSyncTime + '\n') | |
strList.append('MAC Address: ' + macAddress + '\n') | |
deviceInfo = ''.join(strList) | |
self.textView.text = deviceInfo | |
def performAnalysisTask(self): | |
import datetime | |
import console | |
self.dateSelected = self.datePicker.date | |
date = self.dateSelected | |
# This is the crucial call to get the data | |
sleepDataDict = self.fitbitimpl.getSleepDataDictionary(date) | |
#print sleepDataDict | |
# Basic error handling. | |
if sleepDataDict == []: | |
self.errorMessageString = 'No sleep data was found for the date selected.' | |
self.errorMessage.text = self.errorMessageString | |
self.textView.text = '' | |
return | |
else: | |
self.errorMessage.text ='' | |
# continue processing since we have valid date with sleep data | |
# way to mimic a string buffer is to populate list of strings | |
# and then join those strings to create one new imutable string. | |
strList = [] | |
strList.append('Date: ' + str(sleepDataDict['dateOfSleep']) + '\n') | |
strList.append('Log Id: ' + str(sleepDataDict['logId']) + '\n') | |
strList.append('Start Time: ' + str(sleepDataDict['startTime']) + '\n') | |
strList.append('Minutes to Fall Asleep: ' + str(sleepDataDict['minutesToFallAsleep']) + ' minutes\n') | |
strList.append('Main Sleep? ' + str(sleepDataDict['isMainSleep']) + '\n') | |
strList.append('Minutes Awake: ' + str(sleepDataDict['minutesAwake']) + ' minutes\n') | |
strList.append('Time in Bed: ' + str(sleepDataDict['timeInBed']) + ' minutes\n') | |
strList.append('Minutes Asleep: ' + str(sleepDataDict['minutesAsleep']) + ' minutes\n') | |
strList.append('Restless Duration: ' + str(sleepDataDict['restlessDuration']) + ' minutes\n') | |
strList.append('Restless Count: ' + str(sleepDataDict['restlessCount']) + '\n') | |
strList.append('Awake Count: ' + str(sleepDataDict['awakeCount']) + '\n') | |
sleepInfo = ''.join(strList) | |
self.textView.text = sleepInfo | |
def getSleepSummaryDataDictionary(self): | |
self.dateSelected = self.datePicker.date | |
date = self.dateSelected | |
sleepSummaryDataDict = self.fitbitimpl.getSleepSummaryDataDictionary(date) | |
print 'summary test:' + str(sleepSummaryDataDict) | |
# Generates a graph visually comparing total sleep to total awake time as reported by fitbit | |
def performGraphTask(self): | |
# In order to add an image plot to be the image of a ui.Image object a way | |
# suggested by omz was to generate the plot, save to file, map image to | |
# the file. For some reason never yet abble to load .png files only .jpg. | |
import matplotlib.pyplot as plt | |
# todo create real plot information here | |
plt.plot([1, 2, 34, 4]) | |
# Save the plot | |
plt.savefig('tempimage.jpg') | |
# assign/bind the image to ui.Image object. | |
self.graphImageView.image = ui.Image.named('tempimage.jpg') | |
''' | |
# MPL Plot | |
# A simple demo of using matplotlib in Pythonista. | |
import console | |
console.clear() | |
print 'Generating plot... (this may take a little while)' | |
import numpy | |
import matplotlib.pyplot as plt | |
import math | |
plt.grid(True) | |
plt.title('matplotlib Demo') | |
x = numpy.linspace(0.0, 2 * math.pi) | |
p1 = plt.plot(x, numpy.sin(x), lw=2, c='r') | |
p2 = plt.plot(x, numpy.cos(x), lw=2, c='b') | |
plt.legend([p1[0], p2[0]], ['sin(x)', 'cos(x)'], loc=4) | |
plt.show() | |
print 'Tip: You can tap and hold the image to save it to your photo library.'import matplotlib.pyplot as | |
import matplotlib.pyplot as plt | |
plt.plot([1, 2, 3, 4]) | |
plt.savefig('temp.png' | |
''' | |
console.clear() | |
view = ViewController() | |
''' | |
BACKGROUND INFO I HAVE DERIVED FOR MYSELF | |
There is only one single sleep-related call made from an authorized client and that function signature is get_sleep(Datetime dt). This function returns a conglomerate data type of embedded lists and dictionaries. | |
If sleepUnitsDict is the main dictionary returned it has two keys, 'sleep' and 'summary'. sleepUnitsDict['sleep'] returns a list of one element which contains a number of dictionaries. | |
sleepUnitsDict['sleep'] | |
sleepUnitsDict['summary'] | |
The 'sleep' is a dictionary with these 17 keys: | |
logId | |
dateOfSleep | |
minutesToFallAsleep | |
awakeningsCount | |
minutesAwake | |
timeInBed | |
minutesAsleep | |
awakeDuration | |
efficiency | |
isMainSleep | |
startTime | |
restlessCount | |
rduration | |
restlessDuration | |
minuteData | |
minutesAfterWakeup | |
awakeCount | |
Each key has a single value except 'minuteData' which is a dictionary of time values presumably used by other calculations. The 'summary'is another dictionary with these 3 keys: | |
totalTimeInBed | |
totalMinutesAsleep | |
totalSleepRecords | |
Therefore once you get the two parts of returned value you can get at the data directly by using these keys. | |
sleepUnitsDict = authd_client.get_sleep(datetime) | |
sleepList = sleepUnitsDict['sleep']ł | |
summaryDict = sleepUnitsDict['summary'] | |
x = sleepList[0] | |
dataitem = x['one of the sleep keys'] | |
dataitem = summaryDict['one of the 3 summary keys'] | |
''' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment