diff --git a/.do/app.yaml b/.do/app.yaml new file mode 100644 index 0000000..c8ab60b --- /dev/null +++ b/.do/app.yaml @@ -0,0 +1,8 @@ +name: dm2nsc +services: +- environment_slug: dm2nsc + github: + branch: master + deploy_on_push: true + repo: dlinah/dm2nsc + name: dm2nsc \ No newline at end of file diff --git a/.do/deploy.template.yaml b/.do/deploy.template.yaml new file mode 100644 index 0000000..0d0349c --- /dev/null +++ b/.do/deploy.template.yaml @@ -0,0 +1,7 @@ +spec: + name: dm2nsc + services: + - name: dm2nsc + git: + branch: master + repo_clone_url: https://github.com/dlinah/dm2nsc.git \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..20c988c --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,10 @@ +name: Node.js Package +on: + release: + types: + - created +jobs: + build: + runs-on: ubuntu-latest + steps: + - run: echo yay \ No newline at end of file diff --git a/.gitignore b/.gitignore index eb43008..a0a2d8f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -*.json __pycache__ __pycache__/* *.pyc diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..625d6ac --- /dev/null +++ b/Pipfile @@ -0,0 +1,17 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] +autopep8 = "*" +pylint = "*" + +[packages] +apscheduler = "*" +requests = "*" +arrow = "*" +cloudscraper = "*" + +[requires] +python_version = "3.7" diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..2d94f47 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +clock: python cronjob.py diff --git a/README.md b/README.md index 782094a..6a88153 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,19 @@ dm2nsc ====== +## build.io + +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://app.build.io/admin/deploy?template=https%3A%2F%2Fgithub.com%2Fdlinah%2Fdm2nsc) +## heroku + +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) +## DigitalOcean + +Click this button to deploy the app to the DigitalOcean App Platform. If you are not logged in, you will be prompted to log in with your DigitalOcean account. + +[![Deploy to DigitalOcean](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/digitalocean/sample-python/tree/main) Data conversion tool for uploading Diabetes-M log data to Nightscout. -Install python3 requirements with `pip install -r requirements.txt`, update and rename `secret.py-example` to `secret.py`, and run `getdata.py` (potentially as a cronjob). \ No newline at end of file +click deploy to heroku and add requiered config + +data will sync every 10 min diff --git a/app.json b/app.json new file mode 100644 index 0000000..45b23e7 --- /dev/null +++ b/app.json @@ -0,0 +1,26 @@ +{ + "name": "Diabetes m to Nightscout", + "logo":"https://seeklogo.com/images/V/vimeo-icon-logo-441934AEB1-seeklogo.com.png", + "description": "send data from dm to nsc", + "repository": "https://github.com/dlinah/dm2nsc", + "formation": { + "clock": { + "quantity": 1, + "size": "free" + } + }, + "env": { + "USERNAME": { + "description": "diabetes-m username" + }, + "PASSWORD": { + "description": "diabetes-m password" + }, + "NS_URL": { + "description": "http://your-nightscout-host-with-trailing-slash/" + }, + "NS_SECRET": { + "description": "nightscout-secret-key" + } + } +} diff --git a/cronjob.py b/cronjob.py new file mode 100644 index 0000000..9394b42 --- /dev/null +++ b/cronjob.py @@ -0,0 +1,15 @@ +# Package Scheduler. +from apscheduler.schedulers.blocking import BlockingScheduler + +# Main cronjob function. +from getdata import main + + +# run job for the first time +main() + +# Create an instance of scheduler and add function. +scheduler = BlockingScheduler(timezone='utc') +scheduler.add_job(main, 'interval', seconds=600) + +scheduler.start() \ No newline at end of file diff --git a/getdata.py b/getdata.py index de03237..ea60341 100644 --- a/getdata.py +++ b/getdata.py @@ -1,4 +1,4 @@ -from secret import USERNAME, PASSWORD, NS_URL, NS_SECRET +import os import requests, json, arrow, hashlib, urllib, datetime import cloudscraper @@ -20,8 +20,8 @@ def get_login(): index = sess.get(DBM_HOST + '/login') return sess.post(DBM_HOST + '/api/v1/user/authentication/login', json={ - 'username': USERNAME, - 'password': PASSWORD, + 'username': os.environ['USERNAME'], + 'password': os.environ['PASSWORD'], 'device': '' }, headers={ 'origin': DBM_HOST, @@ -51,26 +51,54 @@ def to_mgdl(mmol): def convert_nightscout(entries, start_time=None): out = [] + for entry in entries: bolus = entry["carb_bolus"] + entry["correction_bolus"] time = arrow.get(int(entry["entry_time"])/1000).to(entry["timezone"]) + + #Fill notes varable notes = entry["notes"] + #save notes data to a variable used to skip uploads from nightscoute + noteskip = entry["notes"] + + # Check if there is any data for basal, proteins or fats and if notes are empty + if (entry["basal"]+ entry["proteins"]+ entry["fats"]) != 0 and len(notes)!=0: + + #Build the string of additional data to be pushed into notes field on nightscout if notes there are notes + notes = "%s Basal: %s Proteins: %s Fats: %s" % (entry["notes"], entry["basal"], entry["proteins"], entry["fats"]) + + # Check if there is any data for basal, proteins or fats and if notes are not empty + if (entry["basal"]+ entry["proteins"]+ entry["fats"]) != 0 and len(notes) == 0: + + #Build the string of additional data to be pushed into notes field on nightscout of there are no notes + notes = "Basal: %s Proteins: %s Fats: %s" % (entry["basal"], entry["proteins"], entry["fats"]) + if start_time and start_time >= time: + continue author = NS_AUTHOR + # if from nightscout, skip + if noteskip == "[Nightscout]": + continue + # You can do some custom processing here, if necessary dat = { "eventType": "Meal Bolus", "created_at": time.format(), - "carbs": entry["carbs"], + "carbs": entry["carbs"], + "fats": entry["fats"], + "proteins": entry["proteins"], + "basal": entry["basal"], "insulin": bolus, "notes": notes, "enteredBy": author } + + if entry["glucose"]: bgEvent = { "eventType": "BG Check", @@ -85,13 +113,13 @@ def convert_nightscout(entries, start_time=None): # this is due to a UI display issue with Nightscout (it will show mg/dL units always for # bg-only readings, but convert to the NS default unit otherwise) if unit_mmol and not (entry["carbs"] or bolus): - bgEvent["units"] = "mmol" - # save the mmol/L value from DB-M - bgEvent["glucose"] = entry["glucose"] - else: bgEvent["units"] = "mg/dL" # convert mmol/L -> mg/dL bgEvent["glucose"] = to_mgdl(entry["glucose"]) + else: + bgEvent["units"] = "mmol" + # save the mmol/L value from DB-M + bgEvent["glucose"] = entry["glucose"] dat.update(bgEvent) @@ -100,15 +128,15 @@ def convert_nightscout(entries, start_time=None): return out def upload_nightscout(ns_format): - upload = requests.post(NS_URL + 'api/v1/treatments?api_secret=' + NS_SECRET, json=ns_format, headers={ + upload = requests.post(os.environ['NS_URL'] + 'api/v1/treatments?api_secret=' + os.environ['NS_SECRET'], json=ns_format, headers={ 'Accept': 'application/json', 'Content-Type': 'application/json', - 'api-secret': hashlib.sha1(NS_SECRET.encode()).hexdigest() + 'api-secret': hashlib.sha1(os.environ['NS_SECRET'].encode()).hexdigest() }) print("Nightscout upload status:", upload.status_code, upload.text) def get_last_nightscout(): - last = requests.get(NS_URL + 'api/v1/treatments?count=1000&find[enteredBy]='+urllib.parse.quote(NS_AUTHOR)) + last = requests.get(os.environ['NS_URL'] + 'api/v1/treatments?count=1&find[enteredBy]='+urllib.parse.quote(NS_AUTHOR)) if last.status_code == 200: js = last.json() if len(js) > 0: @@ -136,8 +164,3 @@ def main(): print("Uploading", len(ns_format), "entries to Nightscout...") upload_nightscout(ns_format) - - -if __name__ == '__main__': - main() - diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index b728ad0..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -requests -arrow -cloudscraper \ No newline at end of file diff --git a/runtime.txt b/runtime.txt new file mode 100644 index 0000000..d9c98d7 --- /dev/null +++ b/runtime.txt @@ -0,0 +1 @@ +python-3.7.12