Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
FitbitSleepAnalyzerController.py
# 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
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')
view.present('popover')
self.dateSelected = view['datepicker'].date
# 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 = '66febeae096fe5982d10dd3e92d54de2'
ownerSecret = 'b8b002ddf50d876555f57b9a350051b97'
resourceOwnerKey = '20eb22828f69002ba0f855d07f3gr99'
resourceOwnerSecret = '48eaa2e1e11ea5yt777ygge3579c3274cccd'
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()
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('Battery level: ' + batteryLevel + '\n')
strList.append('Last sync time: ' + lastSyncTime + '\n')
strList.append('MAC Address: ' + macAddress + '\n')
strList.append('Device Type: ' + deviceType + '\n')
strList.append('Device Id: ' + deviceId + '\n')
strList.append('Device Version: ' + deviceVersion)
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)
# Basic error handling.
if sleepDataDict == []:
self.errorMessageString = 'No sleep data found.'
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 of Sleep: ' + 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('Is this the Main Sleep: ' + str(sleepDataDict['isMainSleep']) + '\n')
strList.append('Total Minutes Awake: ' + str(sleepDataDict['minutesAwake']) + ' minutes\n')
strList.append('Total Time in Bed: ' + str(sleepDataDict['timeInBed']) + ' minutes\n')
strList.append('Total 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
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']
'''
@cclauss

This comment has been minimized.

Copy link

@cclauss cclauss commented Aug 2, 2015

You could greatly simplify text report creation from a dict by using multiline format strings:

# create device_fmt and sleep_fmt as global, triple quoted format strings...
device_fmt = '''Battery level: {battery}
Last sync time: {lastSyncTime}
MAC Address: {mac}
Device Type: {type}
Device Id: {id}
Device Version: {deviceVersion}'''

sleep_fmt = '''Date of Sleep:  {dateOfSleep}
Log Id:  {logId}
Start Time:  {startTime}
Minutes to Fall Asleep:  {minutesToFallAsleep} minutes
Is this the Main Sleep:  {isMainSleep}
Total Minutes Awake:  {minutesAwake} minutes
Total Time in Bed:  {timeInBed} minutes
Total Minutes Asleep:  {minutesAsleep} minutes
Restless Duration:  {restlessDuration} minutes
Restless Count:  {restlessCount}
Awake Count:  {awakeCount}'''

# ...then in your program...
self.textView.text = device_fmt.format(**myDevice)
# and
self.textView.text = sleep_fmt.format(**sleepDataDict)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment