Adding the code to parse the FITBIT sleep data for API version 1.2
Co-authored-by: JulioV <juliovhz@gmail.com>pull/95/head
parent
78514c6170
commit
e952e27350
|
@ -1,7 +1,9 @@
|
||||||
import json
|
import json
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import numpy as np
|
||||||
|
import dateutil.parser
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
SLEEP_CODE2LEVEL = ["asleep", "restless", "awake"]
|
SLEEP_CODE2LEVEL = ["asleep", "restless", "awake"]
|
||||||
|
|
||||||
|
@ -29,6 +31,37 @@ SLEEP_INTRADAY_COLUMNS = ("device_id",
|
||||||
"local_day_of_week", "local_time", "local_hour", "local_minute",
|
"local_day_of_week", "local_time", "local_hour", "local_minute",
|
||||||
"local_day_segment")
|
"local_day_segment")
|
||||||
|
|
||||||
|
def mergeLongAndShortData(data_summary):
|
||||||
|
longData = pd.DataFrame(columns=['dateTime', 'level', 'seconds'])
|
||||||
|
shortData = pd.DataFrame(columns=['dateTime','level', 'seconds'])
|
||||||
|
|
||||||
|
windowLength = 30
|
||||||
|
|
||||||
|
for data in data_summary['data']:
|
||||||
|
origEntry = data
|
||||||
|
counter = 0
|
||||||
|
numberOfSplits = origEntry['seconds']//windowLength
|
||||||
|
for times in range(numberOfSplits):
|
||||||
|
newRow = {'dateTime':dateutil.parser.parse(origEntry['dateTime'])+timedelta(seconds=counter*windowLength),'level':origEntry['level'],'seconds':windowLength}
|
||||||
|
longData = longData.append(newRow, ignore_index = True)
|
||||||
|
counter = counter + 1
|
||||||
|
|
||||||
|
for data in data_summary['shortData']:
|
||||||
|
origEntry = data
|
||||||
|
counter = 0
|
||||||
|
numberOfSplits = origEntry['seconds']//windowLength
|
||||||
|
for times in range(numberOfSplits):
|
||||||
|
newRow = {'dateTime':dateutil.parser.parse(origEntry['dateTime'])+timedelta(seconds=counter*windowLength),'level':origEntry['level'],'seconds':windowLength}
|
||||||
|
shortData = shortData.append(newRow,ignore_index = True)
|
||||||
|
counter = counter + 1
|
||||||
|
longData.set_index('dateTime',inplace=True)
|
||||||
|
shortData.set_index('dateTime',inplace=True)
|
||||||
|
longData['level'] = np.where(longData.index.isin(shortData.index) == True,'wake',longData['level'])
|
||||||
|
|
||||||
|
longData.reset_index(inplace=True)
|
||||||
|
|
||||||
|
return longData.values.tolist()
|
||||||
|
|
||||||
# Parse one record for sleep API version 1
|
# Parse one record for sleep API version 1
|
||||||
def parseOneRecordForV1(record, device_id, d_is_main_sleep, records_summary, records_intraday, HOUR2EPOCH):
|
def parseOneRecordForV1(record, device_id, d_is_main_sleep, records_summary, records_intraday, HOUR2EPOCH):
|
||||||
|
|
||||||
|
@ -81,8 +114,74 @@ def parseOneRecordForV1(record, device_id, d_is_main_sleep, records_summary, rec
|
||||||
return records_summary, records_intraday
|
return records_summary, records_intraday
|
||||||
|
|
||||||
# Parse one record for sleep API version 1.2
|
# Parse one record for sleep API version 1.2
|
||||||
def parseOneRecordForV12(record, d_is_main_sleep, records_summary, records_intraday):
|
def parseOneRecordForV12(record, device_id, d_is_main_sleep, records_summary, records_intraday, HOUR2EPOCH):
|
||||||
return None
|
|
||||||
|
# Summary data
|
||||||
|
sleep_record_type = record['type']
|
||||||
|
|
||||||
|
d_start_datetime = datetime.strptime(record["startTime"][:18], "%Y-%m-%dT%H:%M:%S")
|
||||||
|
d_end_datetime = datetime.strptime(record["endTime"][:18], "%Y-%m-%dT%H:%M:%S")
|
||||||
|
|
||||||
|
row_summary = (device_id, record["efficiency"],
|
||||||
|
record["minutesAfterWakeup"], record["minutesAsleep"], record["minutesAwake"], record["minutesToFallAsleep"], record["timeInBed"],
|
||||||
|
d_is_main_sleep, sleep_record_type,
|
||||||
|
d_start_datetime, d_end_datetime,
|
||||||
|
d_start_datetime.date(), d_end_datetime.date(),
|
||||||
|
HOUR2EPOCH[d_start_datetime.hour], HOUR2EPOCH[d_end_datetime.hour])
|
||||||
|
|
||||||
|
records_summary.append(row_summary)
|
||||||
|
if sleep_record_type == 'classic':
|
||||||
|
# Intraday data
|
||||||
|
start_date = d_start_datetime.date()
|
||||||
|
end_date = d_end_datetime.date()
|
||||||
|
is_before_midnight = True
|
||||||
|
curr_date = start_date
|
||||||
|
data_summary = record['levels']
|
||||||
|
for data in data_summary['data']:
|
||||||
|
# For overnight episodes, use end_date once we are over midnight
|
||||||
|
d_time = dateutil.parser.parse(data["dateTime"]).time()
|
||||||
|
if is_before_midnight and d_time.hour == 0:
|
||||||
|
curr_date = end_date
|
||||||
|
d_datetime = datetime.combine(curr_date, d_time)
|
||||||
|
|
||||||
|
d_original_level = data["level"]
|
||||||
|
|
||||||
|
d_unified_level = 0 if d_original_level == "awake" or d_original_level == "restless" else 1
|
||||||
|
|
||||||
|
row_intraday = (device_id,
|
||||||
|
d_original_level, d_unified_level, d_is_main_sleep, sleep_record_type,
|
||||||
|
d_datetime, d_datetime.date(), d_datetime.month, d_datetime.day,
|
||||||
|
d_datetime.weekday(), d_datetime.time(), d_datetime.hour, d_datetime.minute,
|
||||||
|
HOUR2EPOCH[d_datetime.hour])
|
||||||
|
records_intraday.append(row_intraday)
|
||||||
|
else:
|
||||||
|
## for sleep type "stages"
|
||||||
|
start_date = d_start_datetime.date()
|
||||||
|
end_date = d_end_datetime.date()
|
||||||
|
is_before_midnight = True
|
||||||
|
curr_date = start_date
|
||||||
|
data_summary = record['levels']
|
||||||
|
dataList = mergeLongAndShortData(data_summary)
|
||||||
|
for data in dataList:
|
||||||
|
|
||||||
|
d_time = data[0].time()
|
||||||
|
if is_before_midnight and d_time.hour == 0:
|
||||||
|
curr_date = end_date
|
||||||
|
d_datetime = datetime.combine(curr_date, d_time)
|
||||||
|
|
||||||
|
d_original_level = data[1]
|
||||||
|
|
||||||
|
d_unified_level = 1 if d_original_level == "deep" or d_original_level == "light" or d_original_level == "rem" else 0
|
||||||
|
|
||||||
|
row_intraday = (device_id,
|
||||||
|
d_original_level, d_unified_level, d_is_main_sleep, sleep_record_type,
|
||||||
|
d_datetime, d_datetime.date(), d_datetime.month, d_datetime.day,
|
||||||
|
d_datetime.weekday(), d_datetime.time(), d_datetime.hour, d_datetime.minute,
|
||||||
|
HOUR2EPOCH[d_datetime.hour])
|
||||||
|
|
||||||
|
records_intraday.append(row_intraday)
|
||||||
|
|
||||||
|
return records_summary, records_intraday
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,6 +203,6 @@ def parseSleepData(sleep_data, HOUR2EPOCH):
|
||||||
# For sleep API version 1.2
|
# For sleep API version 1.2
|
||||||
else:
|
else:
|
||||||
SLEEP_SUMMARY_COLUMNS = SLEEP_SUMMARY_COLUMNS_V1_2
|
SLEEP_SUMMARY_COLUMNS = SLEEP_SUMMARY_COLUMNS_V1_2
|
||||||
raise ValueError("Sleep data for API v1.2 is not supported yet.")
|
records_summary, records_intraday = parseOneRecordForV12(record, device_id, d_is_main_sleep, records_summary, records_intraday, HOUR2EPOCH)
|
||||||
|
|
||||||
return pd.DataFrame(data=records_summary, columns=SLEEP_SUMMARY_COLUMNS), pd.DataFrame(data=records_intraday, columns=SLEEP_INTRADAY_COLUMNS)
|
return pd.DataFrame(data=records_summary, columns=SLEEP_SUMMARY_COLUMNS), pd.DataFrame(data=records_intraday, columns=SLEEP_INTRADAY_COLUMNS)
|
||||||
|
|
Loading…
Reference in New Issue