{"id":24989117,"url":"https://github.com/engineervix/garmin-activity-share","last_synced_at":"2025-07-23T02:04:21.865Z","repository":{"id":81444611,"uuid":"583266722","full_name":"engineervix/garmin-activity-share","owner":"engineervix","description":"Fetch latest data from your Garmin Connect account and share result via twitter","archived":false,"fork":false,"pushed_at":"2025-07-16T18:35:12.000Z","size":2454,"stargazers_count":0,"open_issues_count":9,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-23T02:03:08.766Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/engineervix.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-29T09:06:30.000Z","updated_at":"2022-12-29T10:26:44.000Z","dependencies_parsed_at":"2025-03-29T11:40:47.672Z","dependency_job_id":"fa4be161-f70a-4d29-b56c-8e00457e8ccf","html_url":"https://github.com/engineervix/garmin-activity-share","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/engineervix/garmin-activity-share","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/engineervix%2Fgarmin-activity-share","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/engineervix%2Fgarmin-activity-share/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/engineervix%2Fgarmin-activity-share/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/engineervix%2Fgarmin-activity-share/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/engineervix","download_url":"https://codeload.github.com/engineervix/garmin-activity-share/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/engineervix%2Fgarmin-activity-share/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266604010,"owners_count":23954725,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-04T12:16:55.112Z","updated_at":"2025-07-23T02:04:21.854Z","avatar_url":"https://github.com/engineervix.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Garmin Activity Share\n\n\u003e Fetch latest data from your Garmin Connect account and share (tweet) results\n\n[![forthebadge](https://forthebadge.com/images/badges/built-by-developers.svg)](https://forthebadge.com)\n[![forthebadge](https://forthebadge.com/images/badges/made-with-python.svg)](https://forthebadge.com)\n\n[![python3](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11-brightgreen.svg)](https://python3statement.org/#sections50-why)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n\n[![Build Status](https://github.com/engineervix/garmin-activity-share/actions/workflows/main.yml/badge.svg)](https://github.com/engineervix/garmin-activity-share/actions/workflows/main.yml)\n[![codecov](https://codecov.io/gh/engineervix/garmin-activity-share/branch/main/graph/badge.svg)](https://codecov.io/gh/engineervix/garmin-activity-share)\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [Garmin Activity Share](#garmin-activity-share)\n  - [Description](#description)\n  - [Running the program](#running-the-program)\n    - [Pre-requisites](#pre-requisites)\n    - [Procedure](#procedure)\n  - [Deployment](#deployment)\n    - [Dokku](#dokku)\n  - [TODO](#todo)\n  - [Assets](#assets)\n    - [Icons](#icons)\n    - [Fonts](#fonts)\n    - [Image backgrounds](#image-backgrounds)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n---\n\n## Description\n\nI was looking for a way to automatically share (primarily tweet, actually) my runs upon completion of a running activity. I could do it from the [Garmin Connect](https://www.garmin.com/en-US/p/125677) app on my phone, but I didn't like the process of selecting a nice image, ensuring proper blending of colours, etc. So I thought automating this would be a fun thing to do!\n\nThe result is this project – a python tool that\n\n1. **Connects to your Garmin Connect account** and obtains the last activity (via [python-garminconnect](https://github.com/cyberjunky/python-garminconnect))\n2. Uses the data from the last activity to **create an image** (via [Pillow](https://pillow.readthedocs.io/en/stable/))\n3. **Sends a tweet** with the image above (via [tweepy](https://www.tweepy.org/))\n\nFor this to work, it needs to run periodically, based on your foreseen run days, perhaps as a [cron job](https://en.wikipedia.org/wiki/Cron).\n\n## Running the program\n\n### Pre-requisites\n\n- You need to have a [Twitter developer acount](https://developer.twitter.com/), and a [Garmin Connect](https://connect.garmin.com/) account.\n- You need to have [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) on your machine:\n\n  ```sh\n  # check that you have docker on your machine\n  docker -v\n  # check that you have docker-compose on your machine\n  docker-compose -v\n  ```\n\n  If you don't have Docker and Docker Compose, then click the respective links above for installation instructions for your platform.\n\n### Procedure\n\n1. Install dev dependencies in your vitual environment\n\n   ```bash\n   # development\n   pip install -r requirements-dev.txt\n   ```\n\n2. build and spin up docker containers (there are only 2 containers, the `bot` container and the `redis` container. Redis is used to store the retrieved data so that we can make comparisons whenever we fetch data from Garmin Connect. This ensures that we do not share the same result multiple times)\n\n   ```bash\n   docker-compose up -d --build\n   ```\n\n3. Setup environment variables. See [`env.sample`](.env.sample) for details. Copy `env.sample` to `.env` and update the new file.\n4. access the `bot` container: `inv exec bot \"bash\"`. This is a shortcut for `docker-compose exec bot bash`\n5. Inside the container, run `inv tweet`.\n\n## Deployment\n\n### Dokku\n\nAssuming you already have a Dokku machine, all you need to do is\n\n1. create an app\n2. install redis and link your app\n3. set environment variables\n4. remove ports (this isn't a web app)\n5. set up persistent storage\n\nThe BASH commands below illustrate the above steps.\n\n```bash\n\n# create app\nsudo dokku apps:create garmin-activity-share\n\n# setup redis | https://github.com/dokku/dokku-redis\nsudo dokku plugin:install https://github.com/dokku/dokku-redis.git redis\nsudo dokku redis:create redis-garmin-activity-share\nsudo dokku redis:link redis-garmin-activity-share garmin-activity-share\n\n# set env variables\nsudo dokku config:set --no-restart garmin-activity-share API_KEY=xxxxx \u0026\u0026 \\\nsudo dokku config:set --no-restart garmin-activity-share API_KEY_SECRET=xxxxx \u0026\u0026 \\\nsudo dokku config:set --no-restart garmin-activity-share BEARER_TOKEN=xxxxx \u0026\u0026 \\\nsudo dokku config:set --no-restart garmin-activity-share ACCESS_TOKEN=xxxxx \u0026\u0026 \\\nsudo dokku config:set --no-restart garmin-activity-share ACCESS_TOKEN_SECRET=xxxxx \u0026\u0026 \\\nsudo dokku config:set --no-restart garmin-activity-share CLIENT_ID=xxxxx \u0026\u0026 \\\nsudo dokku config:set --no-restart garmin-activity-share CLIENT_SECRET=xxxxx \u0026\u0026 \\\nsudo dokku config:set --no-restart garmin-activity-share GARMIN_CONNECT_EMAIL=xxxxx \u0026\u0026 \\\nsudo dokku config:set --no-restart garmin-activity-share GARMIN_CONNECT_AUTH=xxxxx \u0026\u0026 \\\nsudo dokku config:set --no-restart garmin-activity-share MODE=production\n\n# customize Docker Build-time configuration variables\n# https://dokku.com/docs/deployment/builders/dockerfiles/#build-time-configuration-variables\nsudo dokku docker-options:add garmin-activity-share build '--build-arg MODE=production'\n\n# persistent storage\nsudo dokku storage:ensure-directory --chown heroku garmin-activity-share\nsudo dokku storage:mount garmin-activity-share /var/lib/dokku/data/storage/garmin-activity-share:/home/tweepy/assets/dist\n\n# remove ports\nsudo dokku proxy:ports-remove garmin-activity-share http:80:5000\nsudo dokku proxy:ports-remove garmin-activity-share https:443:5000\n```\n\nYou can adjust the cron schedule in [`app.json`](app.json) to suit your preferences. The default setup is as follows\n\n```bash\n# At minute 30 past hour 8 and 20 on every day-of-week from Monday through Saturday.\n30 8,20 * * 1-6\n```\n\n## TODO\n\n- [x] Save session to REDIS, instead of a JSON file\n- [ ] instead of showing the time as UTC on share image, use local time\n- [ ] Fix the PYTHONPATH problem\n- [ ] Write tests\n- [ ] Share to other platforms\n- [ ] Use unsplash API for background images\n- [ ] use an API for random quotes\n- [ ] improve `Dockerfile` configuration. See \u003chttps://stackoverflow.com/questions/43654656/dockerfile-if-else-condition-with-external-arguments\u003e\n- [ ] incorporate cron monitoring\n- [ ] setup sentry\n\n## Assets\n\n### Icons\n\n- Running person icon: \u003chttps://www.svgrepo.com/svg/342791/running\u003e\n- Garmin logo: \u003chttps://creative.garmin.com/styleguide/resources/logos/\u003e\n\n### Fonts\n\n- [Lato](https://fonts.google.com/specimen/Lato/about)\n\n### Image backgrounds\n\n- [`andrew-slifkin-tL50RgKdn3Q-unsplash.jpg`](assets/unsplash_images/andrew-slifkin-tL50RgKdn3Q-unsplash.jpg) by [Andrew Slifkin](https://unsplash.com/@andrewslifkin?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/tL50RgKdn3Q)\n- [`john-t-rPKKiHzLFiY-unsplash.jpg`](assets/unsplash_images/john-t-rPKKiHzLFiY-unsplash.jpg) by [John T](https://unsplash.com/@john_thng?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/rPKKiHzLFiY)\n- [`joshua-sortino-XMcoTHgNcQA-unsplash.jpg`](assets/unsplash_images/joshua-sortino-XMcoTHgNcQA-unsplash.jpg) by [Joshua Sortino](https://unsplash.com/@sortino?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/XMcoTHgNcQA)\n- [`lucas-favre-JnoNcfFwrNA-unsplash.jpg`](assets/unsplash_images/lucas-favre-JnoNcfFwrNA-unsplash.jpg) by [lucas Favre](https://unsplash.com/@we_are_rising?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/JnoNcfFwrNA)\n- [`tara-glaser-WodC5zEcSLQ-unsplash.jpg`](assets/unsplash_images/tara-glaser-WodC5zEcSLQ-unsplash.jpg) by [Tara Glaser](https://unsplash.com/it/@jump2dream?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/WodC5zEcSLQ)\n- [`will-suddreth-NRA25SWe71o-unsplash.jpg`](assets/unsplash_images/will-suddreth-NRA25SWe71o-unsplash.jpg) by [Will Suddreth](https://unsplash.com/@willsudds?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/NRA25SWe71o)\n- [`andrea-leopardi-QVD3Xht9txA-unsplash.jpg`](assets/unsplash_images/andrea-leopardi-QVD3Xht9txA-unsplash.jpg) by [Andrea Leopardi](https://unsplash.com/@whatyouhide?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/QVD3Xht9txA?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)\n- [`gary-butterfield-XGKSeGYGP0A-unsplash.jpg`](assets/unsplash_images/gary-butterfield-XGKSeGYGP0A-unsplash.jpg) by [Gary Butterfield](https://unsplash.com/@garybpt?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/running?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)\n- [`zac-ong-RYvOI54rmPw-unsplash.jpg`](assets/unsplash_images/zac-ong-RYvOI54rmPw-unsplash.jpg) by [Zac Ong](https://unsplash.com/@zacong?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/running?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)\n- [`malik-skydsgaard-zZoE-CCid3g-unsplash.jpg`](assets/unsplash_images/malik-skydsgaard-zZoE-CCid3g-unsplash.jpg) by [Malik Skydsgaard](https://unsplash.com/@malikskyds?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/running?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)\n- [`kevin-andre-M2k-Kd4n-S0-unsplash.jpg`](assets/unsplash_images/kevin-andre-M2k-Kd4n-S0-unsplash.jpg) by [Kevin Andre](https://unsplash.com/de/@kevinandrephotography?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/running?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)\n- [`arek-adeoye-gGZ8ZynljWk-unsplash.jpg`](assets/unsplash_images/arek-adeoye-gGZ8ZynljWk-unsplash.jpg) by [Arek Adeoye](https://unsplash.com/@areksan?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/running?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)\n- [`jim-makos-bYy09RkQW8w-unsplash.jpg`](assets/unsplash_images/jim-makos-bYy09RkQW8w-unsplash.jpg) by [Jim Makos](https://unsplash.com/@jimmakos?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/running?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)\n- [`mike-cox-NrhgewTdfF8-unsplash.jpg`](assets/unsplash_images/mike-cox-NrhgewTdfF8-unsplash.jpg) by [Mike Cox](https://unsplash.com/@iprefermike?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/running?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)\n- [`maxwell-nelson-UvN7K8MM-8k-unsplash.jpg`](assets/unsplash_images/maxwell-nelson-UvN7K8MM-8k-unsplash.jpg) by [Maxwell Nelson](https://unsplash.com/@maxcodes?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/UvN7K8MM-8k?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)\n- [`will-suddreth-1pjRN2kphIs-unsplash.jpg`](assets/unsplash_images/will-suddreth-1pjRN2kphIs-unsplash.jpg) by [Will Suddreth](https://unsplash.com/@willsudds?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/1pjRN2kphIs?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fengineervix%2Fgarmin-activity-share","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fengineervix%2Fgarmin-activity-share","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fengineervix%2Fgarmin-activity-share/lists"}