mirror of
https://github.com/bckelley/tconnectsync.git
synced 2026-08-24 03:34:12 -05:00
api: add user_agent to AndroidApi, move improperly scoped endpoint to tconnectapi
This commit is contained in:
@@ -29,6 +29,8 @@ class AndroidApi:
|
||||
ANDROID_API_USERNAME = base64.b64decode('QzIzMzFDRDYtRDQ1MC00OTVFLTlDMTktNjcyMTUyMzBDODVD').decode()
|
||||
ANDROID_API_PASSWORD = base64.b64decode('dHo0MzNLVzVRREM5VjdmIXo2QF4ybyZZNlNHR1lo').decode()
|
||||
|
||||
ANDROID_USER_AGENT = 'Dalvik/2.1.0 (Linux; U; Android 12; Pixel 4a Build/SP2A.220305.012)'
|
||||
|
||||
# These tokens are separate from the "standard" tdcservices API
|
||||
accessToken = None
|
||||
accessTokenExpiresAt = None
|
||||
@@ -51,7 +53,10 @@ class AndroidApi:
|
||||
'grant_type': 'password',
|
||||
'scope': self.OAUTH_SCOPES
|
||||
},
|
||||
headers={'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
headers={
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'User-Agent': self.ANDROID_USER_AGENT
|
||||
},
|
||||
auth=requests.auth.HTTPBasicAuth(self.ANDROID_API_USERNAME, self.ANDROID_API_PASSWORD)
|
||||
)
|
||||
|
||||
@@ -154,16 +159,3 @@ class AndroidApi:
|
||||
"""
|
||||
def user_profile(self):
|
||||
return self.get('cloud/usersettings/api/UserProfile?userId=%s' % self.userId)
|
||||
|
||||
"""
|
||||
Returns therapy events, used by the webui Therapy Timeline.
|
||||
{'event': [
|
||||
{'type': 'Basal', 'basalRate': ...},
|
||||
{'type': 'Bolus', 'standard': ...},
|
||||
{'type': 'CGM', 'egv': ...}
|
||||
]}
|
||||
"""
|
||||
def therapy_events(self, start_date=None, end_date=None):
|
||||
startDate = parse_date(start_date)
|
||||
endDate = parse_date(end_date)
|
||||
return self.get('tconnect/therapyevents/api/TherapyEvents/%s/%s/false?userId=%s' % (startDate, endDate, self.userId))
|
||||
|
||||
@@ -13,7 +13,7 @@ from .common import parse_date, base_headers, ApiException, ApiLoginException
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ControlIQApi:
|
||||
BASE_URL = 'https://tdcservices.tandemdiabetes.com/tconnect/controliq/api/'
|
||||
BASE_URL = 'https://tdcservices.tandemdiabetes.com/'
|
||||
LOGIN_URL = 'https://tconnect.tandemdiabetes.com/login.aspx?ReturnUrl=%2f'
|
||||
|
||||
userGuid = None
|
||||
@@ -107,7 +107,7 @@ class ControlIQApi:
|
||||
startDate = parse_date(start)
|
||||
endDate = parse_date(end)
|
||||
|
||||
return self.get('therapytimeline/users/%s' % (self.userGuid), {
|
||||
return self.get('tconnect/controliq/api/therapytimeline/users/%s' % (self.userGuid), {
|
||||
"startDate": startDate,
|
||||
"endDate": endDate
|
||||
})
|
||||
@@ -123,7 +123,7 @@ class ControlIQApi:
|
||||
startDate = parse_date(start)
|
||||
endDate = parse_date(end)
|
||||
|
||||
return self.get('summary/users/%s' % (self.userGuid), {
|
||||
return self.get('tconnect/controliq/api/summary/users/%s' % (self.userGuid), {
|
||||
"startDate": startDate,
|
||||
"endDate": endDate
|
||||
})
|
||||
@@ -133,4 +133,17 @@ class ControlIQApi:
|
||||
[{"serialNumber": "11111111", "features": {"controlIQ": {"feature": 1, "dateTimeFirstDetected": "YYYY-MM-DD:THH:MM:SS", "unixTimestamp": 1111111111}}}]
|
||||
"""
|
||||
def pumpfeatures(self):
|
||||
return self.get('pumpfeatures/users/%s' % self.userGuid, {})
|
||||
return self.get('tconnect/controliq/api/pumpfeatures/users/%s' % self.userGuid, {})
|
||||
|
||||
"""
|
||||
Returns therapy events, used by the webui Therapy Timeline.
|
||||
{'event': [
|
||||
{'type': 'Basal', 'basalRate': ...},
|
||||
{'type': 'Bolus', 'standard': ...},
|
||||
{'type': 'CGM', 'egv': ...}
|
||||
]}
|
||||
"""
|
||||
def therapy_events(self, start_date=None, end_date=None):
|
||||
startDate = parse_date(start_date)
|
||||
endDate = parse_date(end_date)
|
||||
return self.get('tconnect/therapyevents/api/TherapyEvents/%s/%s/false?userId=%s' % (startDate, endDate, self.userGuid), {})
|
||||
|
||||
+79
-22
@@ -1,10 +1,15 @@
|
||||
import sys
|
||||
import time
|
||||
import arrow
|
||||
import logging
|
||||
import pkg_resources
|
||||
from datetime import datetime
|
||||
from pprint import pformat
|
||||
|
||||
from .nightscout import NightscoutApi
|
||||
from .parser.nightscout import BASAL_EVENTTYPE, BOLUS_EVENTTYPE
|
||||
from .parser.tconnect import TConnectEntry
|
||||
from .sync.basal import process_ciq_basal_events
|
||||
|
||||
try:
|
||||
__version__ = pkg_resources.require("tconnectsync")[0].version
|
||||
@@ -16,7 +21,7 @@ Attempts to authenticate with each t:connect API,
|
||||
and returns the output of a sample API call from each.
|
||||
Also attempts to connect to the Nightscout API.
|
||||
"""
|
||||
def check_login(tconnect, time_start, time_end, verbose=False):
|
||||
def check_login(tconnect, time_start, time_end, verbose=False, sanitize=False):
|
||||
errors = 0
|
||||
|
||||
loglines = []
|
||||
@@ -70,36 +75,58 @@ def check_login(tconnect, time_start, time_end, verbose=False):
|
||||
log("Logging in to t:connect ControlIQ API...")
|
||||
try:
|
||||
summary = tconnect.controliq.dashboard_summary(time_start, time_end)
|
||||
debug("ControlIQ dashboard summary: %s" % summary)
|
||||
debug("ControlIQ dashboard summary: \n%s" % pformat(summary))
|
||||
except Exception as e:
|
||||
log("Error occurred querying ControlIQ API:")
|
||||
log("Error occurred querying ControlIQ API for dashboard_summary:")
|
||||
log(e)
|
||||
errors += 1
|
||||
|
||||
log("Querying ControlIQ therapy_timeline...")
|
||||
lastBasalTime = None
|
||||
lastBasalDuration = None
|
||||
try:
|
||||
tt = tconnect.controliq.therapy_timeline(time_start, time_end)
|
||||
debug("ControlIQ therapy_timeline: %s" % tt)
|
||||
debug("ControlIQ therapy_timeline: \n%s" % pformat(tt))
|
||||
if tt:
|
||||
processed_tt = process_ciq_basal_events(tt)
|
||||
debug("ControlIQ processed therapy_timeline: \n%s" % pformat(processed_tt))
|
||||
if processed_tt:
|
||||
log("Last ControlIQ processed therapy_timeline event: \n%s" % pformat(processed_tt[-1]))
|
||||
lastBasalTime = processed_tt[-1]['time']
|
||||
lastBasalDuration = processed_tt[-1]['duration_mins']
|
||||
except Exception as e:
|
||||
log("Error occurred querying ControlIQ therapy_timeline:")
|
||||
log(e)
|
||||
errors += 1
|
||||
|
||||
log("Querying ControlIQ therapy_events...")
|
||||
try:
|
||||
androidevents = tconnect.controliq.therapy_events(time_start, time_end)
|
||||
debug("controliq therapy_events: \n%s" % pformat(androidevents))
|
||||
except Exception as e:
|
||||
log("Error occurred querying ControlIQ therapy_events:")
|
||||
log(e)
|
||||
errors += 1
|
||||
|
||||
log("-----")
|
||||
|
||||
log("Logging in to t:connect WS2 API...")
|
||||
try:
|
||||
summary = tconnect.ws2.basaliqtech(time_start, time_end)
|
||||
debug("WS2 basaliq status: %s" % summary)
|
||||
debug("WS2 basaliq status: \n%s" % pformat(summary))
|
||||
except Exception as e:
|
||||
log("Error occurred querying WS2 API:")
|
||||
log(e)
|
||||
errors += 1
|
||||
|
||||
log("Querying WS2 therapy_timeline_csv...")
|
||||
lastReadingTime = None
|
||||
try:
|
||||
ttcsv = tconnect.ws2.therapy_timeline_csv(time_start, time_end)
|
||||
debug("therapy_timeline_csv: %s", ttcsv)
|
||||
debug("therapy_timeline_csv: \n%s" % pformat(ttcsv))
|
||||
if ttcsv and "readingData" in ttcsv and len(ttcsv["readingData"]) > 0:
|
||||
log("Last therapy_timeline_csv reading: \n%s" % pformat(ttcsv["readingData"][-1]))
|
||||
lastReadingTime = TConnectEntry._datetime_parse(ttcsv["readingData"][-1]['EventDateTime'])
|
||||
except Exception as e:
|
||||
log("Error occurred querying WS2 therapy_timeline_csv:")
|
||||
log(e)
|
||||
@@ -108,38 +135,31 @@ def check_login(tconnect, time_start, time_end, verbose=False):
|
||||
log("-----")
|
||||
|
||||
log("Logging in to t:connect Android API...")
|
||||
summary = None
|
||||
try:
|
||||
summary = tconnect.android.user_profile()
|
||||
debug("Android user profile: %s" % summary)
|
||||
debug("Android user profile: \n%s" % pformat(summary))
|
||||
|
||||
event = tconnect.android.last_event_uploaded(PUMP_SERIAL_NUMBER)
|
||||
debug("Android last uploaded event: %s" % event)
|
||||
debug("Android last uploaded event: \n%s" % pformat(event))
|
||||
except Exception as e:
|
||||
log("Error occurred querying Android API:")
|
||||
log(e)
|
||||
errors += 1
|
||||
|
||||
log("Querying Android therapy_events...")
|
||||
try:
|
||||
androidevents = tconnect.android.therapy_events(time_start, time_end)
|
||||
debug("android therapy_events: %s" % androidevents)
|
||||
except Exception as e:
|
||||
log("Error occurred querying Android therapy_events:")
|
||||
log(e)
|
||||
errors += 1
|
||||
|
||||
log("-----")
|
||||
|
||||
log("Logging in to Nightscout...")
|
||||
try:
|
||||
nightscout = NightscoutApi(NS_URL, NS_SECRET)
|
||||
status = nightscout.api_status()
|
||||
debug("Nightscout status: %s" % status)
|
||||
debug("Nightscout status: \n%s" % pformat(status))
|
||||
|
||||
last_upload_basal = nightscout.last_uploaded_entry(BASAL_EVENTTYPE)
|
||||
debug("Nightscout last uploaded basal: %s" % last_upload_basal)
|
||||
debug("Nightscout last uploaded basal: \n%s" % pformat(last_upload_basal))
|
||||
|
||||
last_upload_bolus = nightscout.last_uploaded_entry(BOLUS_EVENTTYPE)
|
||||
debug("Nightscout last uploaded bolus: %s" % last_upload_bolus)
|
||||
debug("Nightscout last uploaded bolus: \n%s" % pformat(last_upload_bolus))
|
||||
except Exception as e:
|
||||
log("Error occurred querying Nightscout API:")
|
||||
log(e)
|
||||
@@ -147,6 +167,15 @@ def check_login(tconnect, time_start, time_end, verbose=False):
|
||||
|
||||
log("-----")
|
||||
|
||||
def time_ago(t):
|
||||
return '%s ago' % (arrow.now() - arrow.get(t)) if t else 'n/a'
|
||||
|
||||
log("Last basal start time: %s (%s)" % (lastBasalTime, time_ago(lastBasalTime)))
|
||||
log("Last basal duration: %s" % lastBasalDuration)
|
||||
log("Last reading time: %s (%s)" % (lastReadingTime, time_ago(lastReadingTime)))
|
||||
|
||||
log("-----")
|
||||
|
||||
if errors == 0:
|
||||
log("No API errors returned!")
|
||||
else:
|
||||
@@ -154,9 +183,37 @@ def check_login(tconnect, time_start, time_end, verbose=False):
|
||||
|
||||
|
||||
with open('tconnectsync-check-output.log', 'w') as f:
|
||||
|
||||
if sanitize:
|
||||
sanitizedData = {
|
||||
'TCONNECT_EMAIL': TCONNECT_EMAIL,
|
||||
'TCONNECT_PASSWORD': TCONNECT_PASSWORD,
|
||||
'PUMP_SERIAL_NUMBER': PUMP_SERIAL_NUMBER,
|
||||
'NS_URL': NS_URL,
|
||||
'NS_SECRET': NS_SECRET
|
||||
}
|
||||
|
||||
if summary:
|
||||
sanitizedData.update({
|
||||
'ANDROID_PROFILE_USERID': summary.get('userID'),
|
||||
'ANDROID_PROFILE_PATIENT_FULLNAME': summary.get('patientFullName'),
|
||||
'ANDROID_PROFILE_CAREGIVER_FULLNAME': summary.get('caregiverFullName')
|
||||
})
|
||||
|
||||
loglines = [run_sanitize(i, sanitizedData) for i in loglines]
|
||||
|
||||
f.writelines(loglines)
|
||||
|
||||
print("Created file tconnectsync-check-output.log containing additional debugging information.")
|
||||
print("For support, you can upload this file to https://github.com/jwoglom/tconnectsync/issues/new")
|
||||
print("Before uploading, look through the file and remove any sensitive data, such as")
|
||||
print("Nightscout URL and pump serial number.")
|
||||
if sanitize:
|
||||
print("The file -- but NOT the output printed above -- has been sanitized to remove sensitive data.")
|
||||
print("Please verify and remove any sensitive data, such as your Nightscout URL/secret and pump serial number,")
|
||||
print("as necessary.")
|
||||
|
||||
def run_sanitize(s, sanitizedData):
|
||||
ret = str(s)
|
||||
for k, v in sanitizedData.items():
|
||||
if v and len(str(v)) > 0:
|
||||
ret = ret.replace(str(v), '[%s]' % k)
|
||||
return ret
|
||||
Reference in New Issue
Block a user