Skip to content

Instantly share code, notes, and snippets.

@ltddev
Created August 6, 2015 23:04
Show Gist options
  • Save ltddev/23542fe783c59978704e to your computer and use it in GitHub Desktop.
Save ltddev/23542fe783c59978704e to your computer and use it in GitHub Desktop.
FitbitSleepAnalyzerController.py
# coding: utf-8
'''
FitbitSleepAnalyzer.py
Sheldon B. Wosnick
July, 2015
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 ==[]: # This will be the result for any data returned from no fitbit data for that day.
return sleepList
# 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 getSleepDataSummaryList(self, datetime):
import fitbit
sleepUnitsDict = self.authd_client.get_sleep(datetime)
sleepSummaryList = sleepUnitsDict['summary']
return sleepSummaryList
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('sheet')#view.present('screen')#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()
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
sleepDataDict = self.fitbitimpl.getSleepDataDictionary(date)
# 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.
# First we save off the critical values to use for matplotlib
strList = []
strList.append('Date: ' + str(sleepDataDict['dateOfSleep']) + '\n')
strList.append('Log Id: ' + str(sleepDataDict['logId']) + '\n')
strList.append('Start Time: ' + str(sleepDataDict['startTime']) + '\n')
self.timeInBed = sleepDataDict['timeInBed']
strList.append('*Time in Bed: ' + str(sleepDataDict['timeInBed']) + ' min\n')
self.minutesAsleep = sleepDataDict['minutesAsleep']
strList.append('*Minutes Asleep: ' + str(sleepDataDict['minutesAsleep']) + ' min\n')
self.awakeDuration = sleepDataDict['awakeDuration']
strList.append('*Awake Duration: ' + str(sleepDataDict['awakeDuration']) + ' min\n')
self.restlessDuration = sleepDataDict['restlessDuration']
strList.append('*Restless Duration: ' + str(sleepDataDict['restlessDuration']) + ' min\n')
strList.append('Minutes to Fall Asleep: ' + str(sleepDataDict['minutesToFallAsleep']) + ' min\n')
strList.append('Main Sleep? ' + str(sleepDataDict['isMainSleep']) + '\n')
strList.append('Restless Count: ' + str(sleepDataDict['restlessCount']) + '\n')
strList.append('Awake Count: ' + str(sleepDataDict['awakeCount']) + '\n\n')
strList.append('Time in bed == Minutes asleep + Awake duration + Restless duration.')
sleepInfo = ''.join(strList)
self.textView.text = sleepInfo
def performGraphTask(self):
from pylab import *
# make a square figure and axes
figure(1, figsize=(6,6))
ax = axes([0.1, 0.1, 0.8, 0.8])
# The slices will be ordered and plotted counter-clockwise.
labels = 'Minutes Asleep', 'Awake Duration', 'Restless Duration'
fracs = [self.minutesAsleep, self.awakeDuration, self.restlessDuration]
#explode=(0, 0.05, 0)
explode=(0, 0, 0)
pie(fracs, explode=explode, labels=labels,
autopct='%1.1f%%', shadow=True, startangle=90)
title('Total Time in Bed', bbox={'facecolor':'0.8', 'pad':5})
#show() will disply image on the console
# Save the plot
savefig('tempimage.jpg')
# assign/bind the image to ui.Image object.
self.graphImageView.image = ui.Image.named('tempimage.jpg')
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