mirror of
https://github.com/bckelley/tconnectsync.git
synced 2026-08-24 03:34:12 -05:00
support extended bolus
This commit is contained in:
@@ -109,11 +109,15 @@ def process_bolus_events(bolusdata):
|
|||||||
for b in bolusdata:
|
for b in bolusdata:
|
||||||
parsed = TConnectEntry.parse_bolus_entry(b)
|
parsed = TConnectEntry.parse_bolus_entry(b)
|
||||||
if parsed["completion"] != "Completed":
|
if parsed["completion"] != "Completed":
|
||||||
print("Skipping non-completed bolus data:", b, "parsed:", parsed)
|
if parsed["insulin"] and float(parsed["insulin"]) > 0:
|
||||||
continue
|
# Count non-completed bolus if any insulin was delivered (vs. the amount of insulin requested)
|
||||||
|
parsed["description"] += " (%s)" % parsed["completion"]
|
||||||
|
else:
|
||||||
|
print("Skipping non-completed bolus data:", b, "parsed:", parsed)
|
||||||
|
continue
|
||||||
bolusEvents.append(parsed)
|
bolusEvents.append(parsed)
|
||||||
|
|
||||||
bolusEvents.sort(key=lambda x: arrow.get(x["completion_time"]))
|
bolusEvents.sort(key=lambda event: arrow.get(event["completion_time"] if not event["extended_bolus"] else event["bolex_start_time"]))
|
||||||
|
|
||||||
return bolusEvents
|
return bolusEvents
|
||||||
|
|
||||||
@@ -136,8 +140,8 @@ def ns_write_bolus_events(bolusEvents, pretend=False):
|
|||||||
entry = NightscoutEntry.bolus(
|
entry = NightscoutEntry.bolus(
|
||||||
bolus=event["insulin"],
|
bolus=event["insulin"],
|
||||||
carbs=event["carbs"],
|
carbs=event["carbs"],
|
||||||
created_at=event["completion_time"],
|
created_at=event["completion_time"] if not event["extended_bolus"] else event["bolex_start_time"],
|
||||||
notes="{}{}".format(event["description"], " (Override)" if event["user_override"] == "1" else "")
|
notes="{}{}{}".format(event["description"], " (Override)" if event["user_override"] == "1" else "", " (Extended)" if event["extended_bolus"] == "1" else "")
|
||||||
)
|
)
|
||||||
|
|
||||||
print(" Processing bolus:", event, "entry:", entry)
|
print(" Processing bolus:", event, "entry:", entry)
|
||||||
@@ -191,17 +195,20 @@ def ns_write_iob_events(iobEvents, pretend=False):
|
|||||||
delete_nightscout('activity/{}'.format(last_upload['_id']))
|
delete_nightscout('activity/{}'.format(last_upload['_id']))
|
||||||
|
|
||||||
def process_time_range(tconnect, time_start, time_end, pretend):
|
def process_time_range(tconnect, time_start, time_end, pretend):
|
||||||
print("Reading basal data from t:connect")
|
print("Downloading t:connect ControlIQ data")
|
||||||
try:
|
try:
|
||||||
ciqBasalData = tconnect.therapy_timeline(time_start, time_end)
|
ciqBasalData = tconnect.therapy_timeline(time_start, time_end)
|
||||||
except ApiException as e:
|
except ApiException as e:
|
||||||
|
# The ControlIQ API returns a 404 if the user did not have a ControlIQ enabled
|
||||||
|
# device in the time range which is queried. Since it launched in early 2020,
|
||||||
|
# ignore 404's before February.
|
||||||
if e.status_code == 404 and time_start.date() < datetime.date(2020, 2, 1):
|
if e.status_code == 404 and time_start.date() < datetime.date(2020, 2, 1):
|
||||||
print("Ignoring HTTP 404 for ControlIQ API request before Feb 2020")
|
print("Ignoring HTTP 404 for ControlIQ API request before Feb 2020")
|
||||||
ciqBasalData = None
|
ciqBasalData = None
|
||||||
else:
|
else:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
print("Reading bolus and IOB data from t:connect")
|
print("Downloading t:connect CSV data")
|
||||||
csvdata = tconnect.therapy_timeline_csv(time_start, time_end)
|
csvdata = tconnect.therapy_timeline_csv(time_start, time_end)
|
||||||
|
|
||||||
readingData = csvdata["readingData"]
|
readingData = csvdata["readingData"]
|
||||||
@@ -229,7 +236,7 @@ def parse_args():
|
|||||||
parser = argparse.ArgumentParser(description="Syncs bolus, basal, and IOB data from Tandem Diabetes t:connect to Nightscout.")
|
parser = argparse.ArgumentParser(description="Syncs bolus, basal, and IOB data from Tandem Diabetes t:connect to Nightscout.")
|
||||||
parser.add_argument('--pretend', dest='pretend', action='store_const', const=True, default=False, help='Pretend mode: do not upload any data to Nightscout.')
|
parser.add_argument('--pretend', dest='pretend', action='store_const', const=True, default=False, help='Pretend mode: do not upload any data to Nightscout.')
|
||||||
parser.add_argument('--start-date', dest='start_date', type=str, default=None, help='The oldest date to process data from. Must be specified with --end-date.')
|
parser.add_argument('--start-date', dest='start_date', type=str, default=None, help='The oldest date to process data from. Must be specified with --end-date.')
|
||||||
parser.add_argument('--end-date', dest='end_date', type=str, default=None, help='The newest date to process data until. Must be specified with --start-date.')
|
parser.add_argument('--end-date', dest='end_date', type=str, default=None, help='The newest date to process data until (inclusive). Must be specified with --start-date.')
|
||||||
parser.add_argument('--days', dest='days', type=int, default=1, help='The number of days of t:connect data to read in. Cannot be used with --from-date and --until-date.')
|
parser.add_argument('--days', dest='days', type=int, default=1, help='The number of days of t:connect data to read in. Cannot be used with --from-date and --until-date.')
|
||||||
|
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ class NightscoutEntry:
|
|||||||
return {
|
return {
|
||||||
"eventType": BASAL_EVENTTYPE,
|
"eventType": BASAL_EVENTTYPE,
|
||||||
"reason": reason,
|
"reason": reason,
|
||||||
"duration": int(round(duration_mins)),
|
"duration": int(round(duration_mins)) if duration_mins else None,
|
||||||
"absolute": float(value),
|
"absolute": float(value),
|
||||||
"created_at": created_at,
|
"created_at": created_at,
|
||||||
"carbs": None,
|
"carbs": None,
|
||||||
|
|||||||
@@ -77,13 +77,18 @@ class TConnectEntry:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_bolus_entry(data):
|
def parse_bolus_entry(data):
|
||||||
# RequestDateTime and CompletionDateTime are stored in the user's timezone.
|
# All DateTime's are stored in the user's timezone.
|
||||||
|
extended_bolus = ("extended" in data["Description"].lower())
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"description": data["Description"],
|
"description": data["Description"],
|
||||||
"completion": data["CompletionStatusDesc"],
|
"completion": data["CompletionStatusDesc"] if not extended_bolus else data["BolexCompletionStatusDesc"],
|
||||||
"request_time": TConnectEntry._datetime_parse(data["RequestDateTime"]).format(),
|
"request_time": TConnectEntry._datetime_parse(data["RequestDateTime"]).format() if not extended_bolus else None,
|
||||||
"completion_time": TConnectEntry._datetime_parse(data["CompletionDateTime"]).format(),
|
"completion_time": TConnectEntry._datetime_parse(data["CompletionDateTime"]).format() if not extended_bolus else None,
|
||||||
"insulin": data["InsulinDelivered"],
|
"insulin": data["InsulinDelivered"],
|
||||||
"carbs": data["CarbSize"],
|
"carbs": data["CarbSize"],
|
||||||
"user_override": data["UserOverride"],
|
"user_override": data["UserOverride"],
|
||||||
|
"extended_bolus": "1" if extended_bolus else "",
|
||||||
|
"bolex_completion_time": TConnectEntry._datetime_parse(data["BolexCompletionDateTime"]).format() if extended_bolus else None,
|
||||||
|
"bolex_start_time": TConnectEntry._datetime_parse(data["BolexStartDateTime"]).format() if extended_bolus else None,
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user