Created
July 31, 2015 22:57
-
-
Save ltddev/f30ec558d289d9a23f61 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 | |
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'] | |
''' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You could greatly simplify text report creation from a dict by using multiline format strings: