Created
July 30, 2015 22:56
-
-
Save ltddev/7072907f7e04826cf7b0 to your computer and use it in GitHub Desktop.
fitbit-sleep
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 | |
# Controller class for sleep analyzer | |
import ui, console,datetime | |
# Bring up UI and control its actions | |
class ViewController(): | |
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 = datetime.date(2015,7, 1) # prime date before selected | |
self.dateSelected = view['datepicker'].date | |
ownerKey = '66febeae096fe9442d10dd3e92d54de2' | |
ownerSecret = 'b8b002ddf50dd3525f57b9a350051b97' | |
resourceOwnerKey = '20eb22828f652f729002ba0f855d07f3' | |
resourceOwnerSecret = '48eaa2e1e11ea551d1e3579c3274cccd' | |
import datetime | |
import console | |
#from FitbitSleepAnalyzerController import * | |
#from FitbitSleepAnalyzerImpl import * | |
date = self.dateSelected | |
# for debug or trace | |
#console.clear() | |
# reduce duplication of getting and using client do it once per session. | |
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. | |
ownerKey = '66febeae096fe9442d10dd3e92d54de2' | |
ownerSecret = 'b8b002ddf50dd3525f57b9a350051b97' | |
resourceOwnerKey = '20eb22828f652f729002ba0f855d07f3' | |
resourceOwnerSecret = '48eaa2e1e11ea551d1e3579c3274cccd' | |
import datetime | |
import console | |
#import FitbitSleepAnalyzer | |
#from FitbitSleepAnalyzerImpl import * | |
self.dateSelected = self.datePicker.date | |
fitbitimpl = FitbitSleepAnalyzer(ownerKey,ownerSecret,resourceOwnerKey,resourceOwnerSecret) | |
curDeviceInfoList = 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'] | |
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): | |
ownerKey = '66febeae096fe9442d10dd3e92d54de2' | |
ownerSecret = 'b8b002ddf50dd3525f57b9a350051b97' | |
resourceOwnerKey = '20eb22828f652f729002ba0f855d07f3' | |
resourceOwnerSecret = '48eaa2e1e11ea551d1e3579c3274cccd' | |
import datetime | |
import console | |
#import FitbitSleepAnalyzer | |
#from FitbitSleepAnalyzerImpl import * | |
#date = datetime.date(2015,7, 23) # Change date here or set up a parameter. | |
self.dateSelected = self.datePicker.date | |
fitbitimpl = FitbitSleepAnalyzer(ownerKey,ownerSecret,resourceOwnerKey,resourceOwnerSecret) | |
console.clear() | |
#fitbitimpl.printAllSleepData(date) temp delete | |
# with this instance we can pull out all important data | |
date = self.dateSelected | |
console.clear() | |
# This is the crucial call to get the data | |
sleepDataDict = fitbitimpl.getSleepDataDictionary(date) | |
# Basic error handling. | |
if sleepDataDict == []: | |
self.errorMessageString = 'No sleep data found.' | |
self.errorMessage.text = self.errorMessageString | |
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 | |
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'] | |
''' | |
#============================================================================== | |
class FitbitSleepAnalyzer: | |
def __init__(self,ownerKey,ownerSecret,resourceOwnerKey,resourceOwnerSecret): | |
import fitbit | |
self.ownerKey = ownerKey | |
self.ownerSecret = ownerSecret | |
self.resourceOwnerKey = resourceOwnerKey | |
self.resourceOwnerSecret =resourceOwnerSecret | |
self.value1 = 0 | |
self.value2 = 0 | |
self.value3 = 0 | |
# 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() | |
# Prints out the name-value pairs fom the minuteData name in sleep data record as the raw data has it. | |
def getSleepDataDictionary(self, datetime): | |
import fitbit | |
authd_client = self.authd_client | |
#fitbit.Fitbit(ownerKey,ownerSecret,resource_owner_key=resourceOwnerKey,resource_owner_secret=resourceOwnerSecret) | |
sleepUnitsDict = authd_client.get_sleep(datetime) | |
sleepList = sleepUnitsDict['sleep'] | |
if sleepList==[]: | |
# if list is empty then return 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 | |
''' | |
todos: | |
1. change to use authn client we got in init; check that its usable if not THEN try to get a fresh one. Do this in all methods that use client. Other error handling to add. | |
''' | |
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
''' | |
FitbitSleepAnalyzerImpl.py (class) | |
This module is meant to utilize all of the capability of the exposed python sleep api to analyze sleep patterns perhaps above and beyond what fitbit itself does. | |
These are my current 4 keys: | |
consumer: "66febeae096fe9442d10dd3e92d54de2" | |
consumer secret: "b8b002ddf50dd3525f57b9a350051b97" | |
reource owner: resource_owner_key='20eb22828f652f729002ba0f855d07f3' | |
resource owner secret: resource_owner_secret='48eaa2e1e11ea551d1e3579c3274cccd') | |
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 | |
duration | |
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'] | |
''' | |
class FitbitSleepAnalyzer: | |
def __init__(self,ownerKey,ownerSecret,resourceOwnerKey,resourceOwnerSecret): | |
import fitbit | |
self.ownerKey = ownerKey | |
self.ownerSecret = ownerSecret | |
self.resourceOwnerKey = resourceOwnerKey | |
self.resourceOwnerSecret =resourceOwnerSecret | |
self.value1 = 0 | |
self.value2 = 0 | |
self.value3 = 0 | |
# Class variable which should be visible to other methods | |
self.authd_client = fitbit.Fitbit(ownerKey,ownerSecret,resource_owner_key=resourceOwnerKey,resource_owner_secret=resourceOwnerSecret) | |
# todo add check for bad dates or no data for a given day and decide how to best handle the situation gracefully. May need to do this in a called method or, make the connection here in the init. Yes get the auth client here and save it as class variable like the others here. Then in each method check if client is null or not usable, if so get it again. | |
def printCurrentDeviceInfo(self): | |
import fitbit | |
authd_client = fitbit.Fitbit(ownerKey,ownerSecret,resource_owner_key=resourceOwnerKey,resource_owner_secret=resourceOwnerSecret) | |
devicesList = authd_client.get_devices() | |
print 'Number of devices:', len(devicesList) | |
myDevice = devicesList[0] # I personally have only one device currently. | |
print 'Device Info' | |
print '===========' | |
# more useful means to populate data fields is to reference by name. | |
batteryLevel = myDevice['battery'] | |
print 'Battery level:',batteryLevel | |
lastSyncTime = myDevice['lastSyncTime'] | |
print 'Last sync time:',lastSyncTime | |
macAddress = myDevice['mac'] | |
print 'MAC Address:', macAddress | |
deviceType = myDevice['type'] | |
print 'Device Type:',deviceType | |
deviceId = myDevice['id'] | |
print 'Device Id:', deviceId | |
deviceVersion = myDevice['deviceVersion'] | |
print 'Device Version: ', deviceVersion | |
# looping useful in case where you don't assume any keys | |
# or you want to process all keys-values | |
for key in myDevice: | |
print key + ': ' + myDevice[key] | |
# Returns the sleep portion of result for a given datetime | |
def sleepData(self,datetime): | |
import fitbit | |
authd_client = fitbit.Fitbit(ownerKey,ownerSecret,resource_owner_key=resourceOwnerKey,resource_owner_secret=resourceOwnerSecret) | |
sleepUnitsDict = authd_client.get_sleep(datetime) | |
sleepList = sleepUnitsDict['sleep'] | |
sleepDict = sleepList[0] #there only is one item in this list, a dictionar | |
return sleepDict | |
# Prints out the name-value pairs fom the minuteData name in sleep data record as the raw data has it. | |
def dumpMinuteDataList(self, datetime): | |
# minutesData is a list with integer indices | |
minutesData = self.getMinutesData(datetime) | |
for i in range(len(minutesData)): | |
print i, minutesData[i] | |
''' | |
todos: | |
1. change to use authn client we got in init; check that its usable if not THEN try to get a fresh one. Do this in all methods that use client. Other error handling to add. | |
''' | |
def dumpMinuteData(self, datetime): | |
# minutesData is a list with integer indices | |
minuteData = self.getMinuteData(datetime) | |
# I am currently unsure what the value that is associated with a dateTime | |
# represents. You see 1,2 or 3 for each minute. What's it mean? | |
''' | |
From the summary dictionary the value 'totalTimeInBed' is derived from the totals of 1, 2 and 3. The value 'totalMinutes Asleep' is derived from the total of type 1, that is 1:454 in example below. So thats where they compute totals though stil unsure of distinctions between types 1, 2 and 3 | |
1. totalTimeInBed: 759 | |
2. totalMinutesAsleep: 454 | |
3. totalSleepRecords: 1 | |
Current Sleep Value Totals = {1: 454, 2: 203, 3: 102} | |
Totals of 1, 2 and 3 = 759. | |
You will notice that the following dictionary values correspond to types 1, 2 and 3 totaled independently and totaled all together. It is these values which have been returned in the (my) result object. | |
timeInBed: 759 | |
minutesAsleep: 454 | |
awakeDuration: 102 | |
restlessDuration: 203 | |
''' | |
for i in range(len(minuteData)): | |
value = minuteData[i]['value'] | |
if value == '1': | |
self.value1 = self.value1 + 1 | |
elif value == '2': | |
self.value2 = self.value2 + 1 | |
elif value == '3': | |
self.value3 = self.value3 + 1 | |
print minuteData[i]['dateTime'], value | |
print 'Minute Value Totals for Given DateTime' | |
print '======================================' | |
print 'Value 1 Total = ' + str(self.value1) | |
print 'Value 2 Total = ' + str(self.value2) | |
print 'Value 3 Total = ' + str(self.value3) | |
# This method returns a dictionary of value to value totals | |
# over the entire sleep period. I am still figuring out what these | |
# values of 1,2 or 3 for each minute in all minutes covered. | |
def getSleepMinuteValuesTotals(self, datetime): | |
# minutesData is a list with integer indices | |
minuteData = self.getMinuteData(datetime) | |
# I am currently unsure what the value that is associated with a dateTime | |
# represents. You see 1,2 or 3 for each minute. What's it mean? | |
for i in range(len(minuteData)): | |
value = minuteData[i]['value'] | |
if value == '1': | |
self.value1 = self.value1 + 1 | |
elif value == '2': | |
self.value2 = self.value2 + 1 | |
elif value == '3': | |
self.value3 = self.value3 + 1 | |
valueTotalsDict ={1:self.value1, 2:self.value2, 3:self.value3} | |
return valueTotalsDict | |
def getMinuteData(self, datetime): | |
import fitbit | |
authd_client = fitbit.Fitbit(ownerKey,ownerSecret,resource_owner_key=resourceOwnerKey,resource_owner_secret=resourceOwnerSecret) | |
sleepUnitsDict = authd_client.get_sleep(datetime) | |
sleepList = sleepUnitsDict['sleep'] | |
sleepDict = sleepList[0] # only is one item in this list. | |
return sleepDict['minuteData'] | |
# Returns the summary part of result for a given datetime | |
def getSleepSummary(self, datetime): | |
import fitbit | |
authd_client = fitbit.Fitbit(ownerKey,ownerSecret,resource_owner_key=resourceOwnerKey,resource_owner_secret=resourceOwnerSecret) | |
sleepDataDict = authd_client.get_sleep(datetime) | |
summaryDict = sleepDataDict['summary'] | |
return summaryDict | |
# There are 3 summary keys and 17 sleep or 20 total keys to grab data | |
# from a results object returned.This method tests them by accessing them. | |
def testAllSleepKeyvalues(self, datetime): #todo better method name | |
import fitbit | |
authd_client = fitbit.Fitbit(ownerKey,ownerSecret,resource_owner_key=resourceOwnerKey,resource_owner_secret=resourceOwnerSecret) | |
sleepUnitsDict = authd_client.get_sleep(datetime) | |
sleepList = sleepUnitsDict['sleep'] | |
summaryDict = sleepUnitsDict['summary'] | |
sleepDataDict = sleepList[0] #only one item in this list which is a dictionary. | |
print 'Sleep Names and Values by Direct Reference (17)' | |
print '===============================================' | |
print '1. logId: ' + str(sleepDataDict['logId']) | |
print '2. dateOfSleep: ' + sleepDataDict['dateOfSleep'] | |
print '3. minutesToFallAsleep: ' + str(sleepDataDict['minutesToFallAsleep']) | |
print '4. awakeningsCount: ' + str(sleepDataDict['awakeningsCount']) | |
print '5. minutesAwake: ' + str(sleepDataDict['minutesAwake']) | |
print '6. timeInBed: ' + str(sleepDataDict['timeInBed']) | |
print '7. minutesAsleep: ' + str(sleepDataDict['minutesAsleep']) | |
print '8. awakeDuration: ' + str(sleepDataDict['awakeDuration']) | |
print '9. efficiency: ' + str(sleepDataDict['isMainSleep']) | |
print '10. isMainSleep: ' + str(sleepDataDict['logId']) | |
print '11. startTime: ' + sleepDataDict['startTime'] | |
print '12. restlessCount: ' + str(sleepDataDict['restlessCount']) | |
print '13. duration: ' + str(sleepDataDict['duration']) | |
print '14. restlessDuration: ' + str(sleepDataDict['restlessDuration']) | |
print '15. minutesAfterWakeup: ' + str(sleepDataDict['minutesAfterWakeup']) | |
print '16. awakeCount: ' + str(sleepDataDict['awakeCount']) | |
print '17. minuteData: ' + str(sleepDataDict['minuteData']) | |
print 'Summary Names and Values by Direct Reference (3)' | |
print '================================================' | |
print '1. totalTimeInBed: ' + str(summaryDict['totalTimeInBed']) | |
print '2. totalMinutesAsleep: ' + str(summaryDict['totalMinutesAsleep']) | |
print '3. totalSleepRecords: ' + str(summaryDict['totalSleepRecords']) | |
# Diagnostic simply prints to screen demonstrating api | |
def dumpSleepData(self,datetime): | |
import fitbit | |
authd_client = fitbit.Fitbit(ownerKey,ownerSecret,resource_owner_key=resourceOwnerKey,resource_owner_secret=resourceOwnerSecret) | |
sleepUnitsDict = authd_client.get_sleep(datetime) | |
sleepList = sleepUnitsDict['sleep'] | |
summaryDict = sleepUnitsDict['summary'] | |
print 'sleepList length: ',len(sleepList) | |
print 'sleepList type:', type(sleepList) | |
print 'summaryDict length: ',len(summaryDict) | |
print 'summaryDict type ',type(summaryDict) | |
sleepDict = sleepList[0] #there only is one item in this list, a dictionary. | |
for key in sleepDict: | |
print key + ':' + str(sleepDict[key]) | |
for key in summaryDict: | |
print key + ':' + str(summaryDict[key]) | |
#___________________________________________________________________________ | |
# Here we instantiate the class then invoke class methods | |
ownerKey = '66febeae096fe9442d10dd3e92d54de2' | |
ownerSecret = 'b8b002ddf50dd3525f57b9a350051b97' | |
resourceOwnerKey = '20eb22828f652f729002ba0f855d07f3' | |
resourceOwnerSecret = '48eaa2e1e11ea551d1e3579c3274cccd' | |
import datetime | |
import console | |
date = datetime.date(2015,7, 23) # Change date here or set up a parameter. | |
# instantiate class then invoke some void methods (no return types) | |
fitbitimpl = FitbitSleepAnalyzer(ownerKey,ownerSecret,resourceOwnerKey,resourceOwnerSecret) | |
console.clear() | |
#fitbitimpl.printAllSleepData(date) | |
#fitbitimpl.sleepSummary(date) | |
fitbitimpl.testAllSleepKeyvalues(date) | |
#fitbitimpl.dumpMinuteData(date) | |
#fitbitimpl.dumpMinuteData(date) | |
#These totals are significant for some purpose, just not sure yet. | |
sleepValuesTotal = fitbitimpl.getSleepMinuteValuesTotals(date) | |
print 'Current Sleep Value Totals = '+ str(sleepValuesTotal) | |
totalMinutesInBed = sleepValuesTotal[1] + sleepValuesTotal[2] + sleepValuesTotal[3] | |
print 'Totals of 1, 2 and 3 = ' + str(totalMinutesInBed) | |
#console.hide_output() | |
#print 'Value 1 Total = ' + str(getSleepMinuteValuesTotals()) | |
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
[{"class":"View","attributes":{"name":"Fitbit Personal Sleep Analysis","background_color":"RGBA(1.000000,1.000000,1.000000,1.000000)","tint_color":"RGBA(0.000000,0.478000,1.000000,1.000000)","enabled":true,"border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","flex":""},"frame":"{{0, 0}, {536, 677}}","nodes":[{"class":"DatePicker","attributes":{"enabled":true,"flex":"","name":"datepicker","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","action":"self.handleDatePicked","mode":1,"uuid":"5A139F13-2F5F-4365-84AA-19D6F2A4BAD3"},"frame":"{{29, 77}, {384.5, 216}}","nodes":[]},{"class":"Label","attributes":{"font_size":17,"enabled":true,"text":"Select a night from the selector below","flex":"","name":"label1","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","alignment":"left","uuid":"6249374E-5F8B-407E-8C39-E39272F16FAC"},"frame":"{{41.5, 20}, {350.5, 31.5}}","nodes":[]},{"class":"Button","attributes":{"font_size":15,"enabled":true,"flex":"","font_bold":false,"name":"sleepDataButton","uuid":"E13208BF-1143-48F3-8545-116ACCB07FDC","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","action":"self.buttonTapped","border_width":1,"title":"Sleep Data"},"frame":"{{192, 338}, {102.5, 35}}","nodes":[]},{"class":"ImageView","attributes":{"name":"imageView","uuid":"E271CC2C-7E1B-4EA8-8E3B-245B4DCF2DC9","enabled":true,"border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","flex":""},"frame":"{{421, 20}, {91, 90.5}}","nodes":[]},{"class":"TextView","attributes":{"alignment":"left","autocorrection_type":"no","font_size":17,"border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","enabled":true,"flex":"","text":"Analysis information will be printed here.","text_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","name":"textView","spellchecking_type":"no","editable":false,"uuid":"B690048C-4D4F-4D1B-BF29-BB82A97AB395"},"frame":"{{29, 393.5}, {483, 270}}","nodes":[]},{"class":"Button","attributes":{"font_size":15,"enabled":true,"flex":"","font_bold":false,"name":"deviceButton","uuid":"BF3D21D1-DCA8-4A7C-82B7-8F6282A9F83C","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","action":"self.buttonTapped","border_width":1,"title":"Device Data"},"frame":"{{72, 338}, {101.5, 35}}","nodes":[]},{"class":"Label","attributes":{"font_size":17,"enabled":true,"text":"","flex":"","name":"noDataLabel","border_color":"RGBA(0.000000,0.000000,0.000000,1.000000)","text_color":"RGBA(1.000000,0.000000,0.000000,1.000000)","alignment":"left","uuid":"6FAD2C86-68D0-47DA-A319-A020F3AF6CF8"},"frame":"{{302.5, 338}, {209.5, 32}}","nodes":[]}]}] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment