Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jwoglom/tconnectsync
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v2.1.5
Choose a base ref
...
head repository: jwoglom/tconnectsync
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on Oct 17, 2024

  1. Copy the full SHA
    2892eb8 View commit details
  2. Copy the full SHA
    54ba2ed View commit details
  3. v2.1.6

    jwoglom committed Oct 17, 2024
    Copy the full SHA
    9a2a4ca View commit details

Commits on Dec 10, 2024

  1. eventparser: move baseevent

    jwoglom committed Dec 10, 2024
    Copy the full SHA
    e82d311 View commit details
  2. Copy the full SHA
    98b7edc View commit details
  3. Copy the full SHA
    dd2dcd1 View commit details

Commits on Dec 11, 2024

  1. Copy the full SHA
    2b367d4 View commit details
  2. Copy the full SHA
    650fb60 View commit details
  3. Copy the full SHA
    e5259a7 View commit details

Commits on Dec 12, 2024

  1. add unit test

    jwoglom committed Dec 12, 2024
    Copy the full SHA
    8082490 View commit details
  2. Copy the full SHA
    24a635c View commit details
  3. Copy the full SHA
    9493b65 View commit details
  4. v2.1.7

    jwoglom committed Dec 12, 2024
    Copy the full SHA
    1ed3d35 View commit details
  5. fix flake8

    jwoglom committed Dec 12, 2024
    Copy the full SHA
    00023c6 View commit details
  6. fix codecov

    jwoglom committed Dec 12, 2024
    Copy the full SHA
    093b42f View commit details
  7. v2.1.8

    jwoglom committed Dec 12, 2024
    Copy the full SHA
    a028cdf View commit details
  8. add processdevicestatus

    jwoglom committed Dec 12, 2024
    Copy the full SHA
    3f6010f View commit details
  9. v2.1.9

    jwoglom committed Dec 12, 2024
    Copy the full SHA
    2339b45 View commit details
  10. catch iso8601 date errors

    jwoglom committed Dec 12, 2024
    Copy the full SHA
    fb9588f View commit details

Commits on Dec 13, 2024

  1. Copy the full SHA
    d1341e0 View commit details
  2. Copy the full SHA
    4bda0a2 View commit details
  3. Copy the full SHA
    1f0fbd7 View commit details
  4. Copy the full SHA
    c7ade49 View commit details

Commits on Dec 14, 2024

  1. fix non-autoupdate

    jwoglom committed Dec 14, 2024
    Copy the full SHA
    29d08a7 View commit details
  2. v2.2.0

    jwoglom committed Dec 14, 2024
    Copy the full SHA
    b1f8263 View commit details

Commits on Dec 31, 2024

  1. Copy the full SHA
    997ab7b View commit details
  2. v2.2.1

    jwoglom committed Dec 31, 2024
    Copy the full SHA
    67b9f42 View commit details
  3. fix tests

    jwoglom committed Dec 31, 2024
    Copy the full SHA
    07aaea9 View commit details
  4. v2.2.2

    jwoglom committed Dec 31, 2024
    Copy the full SHA
    ea84b0b View commit details

Commits on Jan 3, 2025

  1. Copy the full SHA
    934d90e View commit details

Commits on Jan 15, 2025

  1. Copy the full SHA
    7a0f947 View commit details
  2. Copy the full SHA
    4a8da39 View commit details

Commits on Jan 16, 2025

  1. stop running pipenv check

    jwoglom committed Jan 16, 2025
    Copy the full SHA
    fd96b08 View commit details
Showing with 2,071 additions and 180 deletions.
  1. +2 −2 .codecov.yml
  2. +3 −3 .github/workflows/publish-docker.yml
  3. +19 −19 .github/workflows/python-package.yml
  4. +1 −0 Pipfile
  5. +0 −6 codecov.yml
  6. +1 −1 setup.cfg
  7. +1 −1 tconnectsync/__init__.py
  8. +27 −6 tconnectsync/api/tandemsource.py
  9. +1 −0 tconnectsync/domain/tandemsource/event_class.py
  10. +3 −0 tconnectsync/domain/tandemsource/pump_settings.py
  11. +38 −14 tconnectsync/eventparser/build_events.py
  12. +67 −0 tconnectsync/eventparser/custom_events.json
  13. +1,113 −64 tconnectsync/eventparser/events.py
  14. +7 −1 tconnectsync/eventparser/generic.py
  15. +32 −0 tconnectsync/eventparser/raw_event.py
  16. +12 −1 tconnectsync/eventparser/transforms.py
  17. +2 −0 tconnectsync/features.py
  18. +39 −0 tconnectsync/nightscout.py
  19. +27 −8 tconnectsync/parser/nightscout.py
  20. +3 −0 tconnectsync/secret.py
  21. +13 −8 tconnectsync/sync/tandemsource/autoupdate.py
  22. +20 −0 tconnectsync/sync/tandemsource/cli_helpers.py
  23. +1 −1 tconnectsync/sync/tandemsource/heroku_helpers.py
  24. +14 −14 tconnectsync/sync/tandemsource/process.py
  25. +11 −2 tconnectsync/sync/tandemsource/process_alarm.py
  26. +2 −2 tconnectsync/sync/tandemsource/process_basal.py
  27. +1 −1 tconnectsync/sync/tandemsource/process_basal_resume.py
  28. +1 −1 tconnectsync/sync/tandemsource/process_basal_suspension.py
  29. +4 −4 tconnectsync/sync/tandemsource/process_bolus.py
  30. +3 −3 tconnectsync/sync/tandemsource/process_cartridge.py
  31. +3 −3 tconnectsync/sync/tandemsource/process_cgm_alert.py
  32. +1 −1 tconnectsync/sync/tandemsource/process_cgm_reading.py
  33. +3 −3 tconnectsync/sync/tandemsource/process_cgm_start_join_stop.py
  34. +78 −0 tconnectsync/sync/tandemsource/process_device_status.py
  35. +6 −6 tconnectsync/sync/tandemsource/process_user_mode.py
  36. +8 −5 tconnectsync/sync/tandemsource/update_profiles.py
  37. +3 −0 tests/nightscout_fake.py
  38. 0 tests/sync/tandemsource/__init__.py
  39. +65 −0 tests/sync/tandemsource/test_process_alarm.py
  40. +154 −0 tests/sync/tandemsource/test_process_device_status.py
  41. +282 −0 tests/sync/tandemsource/test_process_user_mode.py
4 changes: 2 additions & 2 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -5,9 +5,9 @@ coverage:
project:
default: false
tconnectsync:
paths:
paths:
- "tconnectsync/"
target: '75%'
target: '60%'
threshold: '5%'
tests:
paths:
6 changes: 3 additions & 3 deletions .github/workflows/publish-docker.yml
Original file line number Diff line number Diff line change
@@ -38,13 +38,13 @@ jobs:
steps:
- name: Check out the repo
uses: actions/checkout@v2

- name: Log in to Docker Hub
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
@@ -55,7 +55,7 @@ jobs:
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push Docker image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
38 changes: 19 additions & 19 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
@@ -28,25 +28,25 @@ jobs:
python -m pip install --upgrade pip
python -m pip install flake8 pytest pipenv
pipenv install --system
- name: Run pipenv check
run: |
# DDoS attacks in wheel and setuptools packages, not relevant
# root certificate store, not relevant
pipenv check \
--ignore 51499 \
--ignore 52495 \
--ignore 52365 \
--ignore 59956 \
--ignore 58755 \
--ignore 67895 \
--ignore 61893 \
--ignore 61601 \
--ignore 62044 \
--ignore 67599 \
--ignore 72083 \
--ignore 71064 \
--ignore 71608 \
--ignore 72236
# - name: Run pipenv check
# run: |
# # DDoS attacks in wheel and setuptools packages, not relevant
# # root certificate store, not relevant
# pipenv check \
# --ignore 51499 \
# --ignore 52495 \
# --ignore 52365 \
# --ignore 59956 \
# --ignore 58755 \
# --ignore 67895 \
# --ignore 61893 \
# --ignore 61601 \
# --ignore 62044 \
# --ignore 67599 \
# --ignore 72083 \
# --ignore 71064 \
# --ignore 71608 \
# --ignore 72236
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -27,3 +27,4 @@ typing-extensions = "*"
tconnectsync = "python3 main.py"
test = "python3 -m unittest discover -vv"
build_events = "bash -c 'cd tconnectsync/eventparser && python3 build_events.py > events.py'"
lint = "bash -c 'flake8 . --count --select=E9,F63,F7,F82 && flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 && echo PASS'"
6 changes: 0 additions & 6 deletions codecov.yml

This file was deleted.

2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = tconnectsync
version = 2.1.5
version = 2.2.2
author = James Woglom
author_email = j@wogloms.net
description = Syncs Tandem Source (formerly t:connect) insulin pump data to Nightscout for the t:slim X2
2 changes: 1 addition & 1 deletion tconnectsync/__init__.py
Original file line number Diff line number Diff line change
@@ -120,7 +120,7 @@ def main(*args, **kwargs):
sys.exit(u.process(tconnect, nightscout, time_start, time_end, args.pretend, features=args.features))
else:
tconnectDevice = TandemSourceChooseDevice(secret, tconnect).choose()
added, last_event_id = TandemSourceProcessTimeRange(tconnect, nightscout, tconnectDevice, pretend=args.pretend, features=args.features).process(time_start, time_end)
added, last_event_id = TandemSourceProcessTimeRange(tconnect, nightscout, tconnectDevice, pretend=args.pretend, secret=secret, features=args.features).process(time_start, time_end)

# return exit code 0 if processed events
sys.exit(0 if added>0 else 1)
33 changes: 27 additions & 6 deletions tconnectsync/api/tandemsource.py
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
from ..util import timeago, cap_length
from .common import parse_ymd_date, base_headers, base_session, ApiException, ApiLoginException
from ..secret import CACHE_CREDENTIALS, CACHE_CREDENTIALS_PATH
from ..eventparser.generic import Events, decode_raw_events, EVENT_LEN

logger = logging.getLogger(__name__)

@@ -357,22 +358,42 @@ def pumper_info(self):
def pump_event_metadata(self):
return self.get('api/reports/reportsfacade/%s/pumpeventmetadata' % (self.pumperId), {})

DEFAULT_EVENT_IDS = [229,5,28,4,26,99,279,3,16,59,21,55,20,280,64,65,66,61,33,371,171,369,460,172,370,461,372,399,256,213,406,394,212,404,214,405,447,313,60,14,6,90,230,140,12,11,53,13,63,203,307,191]

"""
Returns raw unparsed string for pump events
tconnect_device_id is "tconnectDeviceId" from pump_event_metadata()
"""
def pump_events_raw(self, tconnect_device_id, min_date=None, max_date=None):
def pump_events_raw(self, tconnect_device_id, min_date=None, max_date=None, event_ids_filter=DEFAULT_EVENT_IDS):
minDate = parse_ymd_date(min_date)
maxDate = parse_ymd_date(max_date)
logger.debug(f'pump_events_raw({minDate}, {maxDate})')
logger.debug(f'pump_events_raw({tconnect_device_id}, {minDate}, {maxDate})')

# 229,5,28,4,26,99,279,3,16,59,21,55,20,280,64,65,66,61,33,371,171,369,460,172,370,461,372,399,256,213,406,394,212,404,214,405,447,313,60,14,6,90,230,140,12,11,53,13,63,203,307,191
eventIdsFilter = '229%2C5%2C28%2C4%2C26%2C99%2C279%2C3%2C16%2C59%2C21%2C55%2C20%2C280%2C64%2C65%2C66%2C61%2C33%2C371%2C171%2C369%2C460%2C172%2C370%2C461%2C372%2C399%2C256%2C213%2C406%2C394%2C212%2C404%2C214%2C405%2C447%2C313%2C60%2C14%2C6%2C90%2C230%2C140%2C12%2C11%2C53%2C13%2C63%2C203%2C307%2C191'
return self.get('api/reports/reportsfacade/pumpevents/%s/%s?minDate=%s&maxDate=%s&eventIds=%s' % (
# default: 229,5,28,4,26,99,279,3,16,59,21,55,20,280,64,65,66,61,33,371,171,369,460,172,370,461,372,399,256,213,406,394,212,404,214,405,447,313,60,14,6,90,230,140,12,11,53,13,63,203,307,191
eventIdsFilter = '%2C'.join(map(str, event_ids_filter)) if event_ids_filter else None
return self.get('api/reports/reportsfacade/pumpevents/%s/%s?minDate=%s&maxDate=%s%s' % (
self.pumperId,
tconnect_device_id,
minDate,
maxDate,
eventIdsFilter
'&eventIds=%s' % eventIdsFilter if eventIdsFilter else ''
), {})

"""
Fetch and decode pump events using eventparser.
Default of fetch_all_events=False will filter to the same eventids used in the Tandem Source backend.
If fetch_all_events=True, then all event types from the history log will be returned.
"""
def pump_events(self, tconnect_device_id, min_date=None, max_date=None, fetch_all_event_types=False):
pump_events_raw = self.pump_events_raw(
tconnect_device_id,
min_date,
max_date,
event_ids_filter=None if fetch_all_event_types else self.DEFAULT_EVENT_IDS
)

pump_events_decoded = decode_raw_events(pump_events_raw)
logger.info(f"Read {len(pump_events_decoded)} bytes (est. {len(pump_events_decoded)/EVENT_LEN} events)")
return Events(pump_events_decoded)


1 change: 1 addition & 0 deletions tconnectsync/domain/tandemsource/event_class.py
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ class EventClass(set, Enum):
CGM_START_JOIN_STOP = {*_CGM_START, *_CGM_JOIN, *_CGM_STOP}
CGM_READING = {events.LidCgmDataGxb, events.LidCgmDataG7, events.LidCgmDataFsl2}
USER_MODE = {events.LidAaUserModeChange}
DEVICE_STATUS = {events.LidDailyBasal}

@staticmethod
def for_event(evt):
3 changes: 3 additions & 0 deletions tconnectsync/domain/tandemsource/pump_settings.py
Original file line number Diff line number Diff line change
@@ -25,6 +25,9 @@ class PumpProfile:
carbEntry: int # 1 / 0
maxBolus: int # milliunits

def __post_init__(self):
self.tDependentSegs = [i for i in self.tDependentSegs if not i.skip]

@dataclass_json
@dataclass
class PumpProfiles:
52 changes: 38 additions & 14 deletions tconnectsync/eventparser/build_events.py
Original file line number Diff line number Diff line change
@@ -3,18 +3,12 @@
import logging
from dataclasses import dataclass
from enum import Enum, IntFlag
from .raw_event import RawEvent
from .raw_event import RawEvent, BaseEvent
logger = logging.getLogger(__name__)
EVENT_LEN = 26
@dataclass
class BaseEvent:
@staticmethod
def build(raw):
raise NotImplemented
'''

TYPE_TO_STRUCT = {
@@ -67,9 +61,22 @@ def eventTimestamp(self):
return self.raw.timestamp
@property
def eventId(self):
def seqNum(self):
return self.raw.seqNum
@property
def eventId(self):
return self.ID
def todict(self):
return dict(
id=self.ID,
name=self.NAME,
seqNum=self.seqNum,
eventTimestamp=str(self.eventTimestamp),
{fields_dict}
)
'''

def firstLower(text):
@@ -85,20 +92,28 @@ def eventNameFormat(text):
def fieldNameFormat(text):
if not text or all([i.isupper() for i in text]):
return text
return firstLower(text.replace('_', ' ').title().replace(' ', ''))
return firstLower(text.replace('_', ' ').title().replace(' ', '')).replace('raw', 'Raw')


def build_fields(event_def):
ret = []
for name, field in event_def["data"].items():
suffix = 'Raw' if "transform" in field else ''
suffix = 'Raw' if "transform" in field and name[-3:] != 'Raw' else ''
f = f'{fieldNameFormat(name)}{suffix}: {TYPE_TO_PYOBJ[field["type"]]}'
if "uom" in field:
f += ' # ' + field['uom']
ret.append(f)
return '\n'.join([f'{" "*4}{f}' for f in ret])


def build_fields_dict(event_def):
ret = []
for name, field in event_def["data"].items():
suffix = 'Raw' if "transform" in field and name[-3:] != 'Raw' else ''
f = f'{fieldNameFormat(name)}{suffix}=self.{fieldNameFormat(name)}{suffix},'
ret.append(f)
return '\n'.join([f'{" "*12}{f}' for f in ret])


def build_decode(event_def):
p1s = []
@@ -107,7 +122,7 @@ def build_decode(event_def):
p1 = f'{fieldNameFormat(name)}, = {unpack_command_for(field)}'
p1s.append(p1)

suffix = 'Raw' if "transform" in field else ''
suffix = 'Raw' if "transform" in field and name[-3:] != 'Raw' else ''

p2 = f'{fieldNameFormat(name)}{suffix} = {fieldNameFormat(name)},'
p2s.append(p2)
@@ -136,6 +151,7 @@ def build_event(event_id, event_def):
return TEMPLATE.format(
name = eventNameFormat(event_def["name"]),
fields = build_fields(event_def),
fields_dict = build_fields_dict(event_def),
build_p1 = build_decode(event_def)[0],
build_p2 = build_decode(event_def)[1],
transform_funcs = build_transform_funcs(event_def),
@@ -160,13 +176,21 @@ def build_events_map(events):

if __name__ == '__main__':
import json
merged_events = {}

output = f'{header}'
with open("events.json", "r") as f:
j = json.loads(f.read())
for event_id, event_def in j["events"].items():
output += build_event(event_id, event_def)
merged_events.update(j["events"])

with open("custom_events.json", "r") as f:
j = json.loads(f.read())
merged_events.update(j["events"])

for event_id, event_def in merged_events.items():
output += build_event(event_id, event_def)

output += build_events_map(merged_events)

output += build_events_map(j["events"])

print(output)
67 changes: 67 additions & 0 deletions tconnectsync/eventparser/custom_events.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"events": {
"81": {
"name": "LID_DAILY_BASAL",
"data": {
"dailyTotalBasal": {
"type": "float32",
"offset": 0,
"uom": "units"
},
"lastBasalRate": {
"type": "float32",
"offset": 4,
"uom": "units/hour"
},
"iob": {
"type": "float32",
"offset": 8,
"uom": "units"
},
"batteryChargePercentMSBRaw": {
"type": "uint8",
"offset": 12
},
"batteryChargePercentLSBRaw": {
"type": "uint8",
"offset": 13,
"transform": [["battery_charge_percent", ""]]
},
"batteryLipoMilliVolts": {
"type": "uint16",
"offset": 14
}
}
},
"48": {
"name": "LID_CARBS_ENTERED",
"data": {
"carbs": {
"type": "float32",
"offset": 0,
"uom": "carbs"
}
}
},
"36": {
"name": "LID_USB_CONNECTED",
"data": {
"negotiatedCurrent": {
"type": "float32",
"offset": 0,
"uom": "mA"
}
}
},
"37": {
"name": "LID_USB_DISCONNECTED",
"data": {
"negotiatedCurrent": {
"type": "float32",
"offset": 0,
"uom": "mA"
}
}
}
}
}
Loading