cl2ns (Carelink to Nightscout) is a lightweight Docker container that syncs Medtronic Carelink pump and sensor data to a Nightscout instance. No UI, no database, no web server -- just a single background daemon that polls Carelink and uploads to Nightscout.
This is a personal, open-source project and is NOT an official Medtronic or Nightscout product. This software is provided for educational and informational purposes only. It is not intended for medical purposes, and you cannot use the information it provides to make medical decisions or treatments. Always consult your medical professional and rely on your official medical devices.
- Syncs SGV (sensor glucose values) with trend direction and delta
- Syncs Treatments: Boluses, Correction Boluses, and Meal Carbs (auto-merged if simultaneous)
- Syncs SmartGuard Auto-Basal deliveries as dynamic Temp Basal rates
- Syncs BG check and fingerstick calibrations to Nightscout treatments
- Auto-detects and uploads
Sensor Changetreatment events for Nightscout's SAGE plugin - Uploads complete device status: pump battery, reservoir, active insulin (IOB), suspend state, sensor age, calibration timers, and conduit status
- SHA-256 fingerprint deduplication across all endpoints to eliminate duplicate entries
- Adaptive polling: fast retries when waiting for new readings, then backs off
- Automatic OAuth token refresh with persistent token storage
- Timezone-aware timestamp conversion (auto-detected from Carelink or manually overridden)
- Runs entirely from container logs -- no UI, no ports exposed
You need a set of OAuth tokens from the Carelink mobile app flow. You can generate these using the bundled Python script in the token directory.
- Navigate to the
tokendirectory:cd token - Install the required dependencies:
pip install -r requirements.txt - Run the login script:
python carelink_carepartner_api_login.py(add--usflag if you are in the US region) - A Firefox window will open temporarily to solve a Captcha. Once completed, the script prints the exact Docker Compose environment block and saves
logindata.json.
For modern Carelink Auth0 logins (EU and US default), the required credentials are:
access_token(JWT)refresh_tokenclient_id
(Note: client_secret and mag-identifier are only generated for legacy CA MAG gateways and are not needed or used for Auth0 accounts).
You can run this easily using Docker Compose (or Portainer). Create a docker-compose.yml file:
version: '3.8'
services:
cl2ns:
image: ghcr.io/bigcheesesteak/cl2ns:latest
container_name: cl2ns
restart: unless-stopped
env_file:
- .env
volumes:
- cl2ns_data:/data
volumes:
cl2ns_data:Next, create a .env file in the same directory (see Configuration below) with your credentials, and start the container:
docker compose up -d
docker compose logs -f cl2nsAll configuration is done via environment variables. Copy .env.example to .env and fill in your values.
| Variable | Required | Description |
|---|---|---|
CARELINK_TOKEN |
Yes | JWT access token from Carelink OAuth flow |
CARELINK_REFRESH_TOKEN |
Yes | Refresh token (single-use, auto-rotated) |
CARELINK_CLIENT_ID |
Yes | OAuth client ID (PeAhkbhQWlQRxJiQxWfcFBiGus1lxfe9 on Auth0) |
CARELINK_PATIENT_ID |
No | Target patient username. Auto-detected if omitted for single-patient accounts. |
CARELINK_CLIENT_SECRET |
No | Legacy CA MAG gateway only. Omit for Auth0 accounts. |
CARELINK_MAG_IDENTIFIER |
No | Legacy CA MAG gateway only. Omit for Auth0 accounts. |
NIGHTSCOUT_URL |
Yes | Full URL of your Nightscout instance |
NIGHTSCOUT_API_SECRET |
Yes | Nightscout API secret |
SYNC_INTERVAL |
No | Base polling interval in seconds (default: 60) |
LOG_LEVEL |
No | DEBUG, INFO, WARNING, or ERROR (default: INFO) |
TZ |
No | IANA timezone override (e.g. America/New_York or UTC). Auto-detected from Carelink if not set. |
Carelink Cloud cl2ns Nightscout
| | |
| <-- OAuth token refresh --> | |
| <-- POST /display/message | |
| pump + sensor data --> | |
| | --> POST /api/v1/entries |
| | --> POST /api/v1/treatments |
| | --> POST /api/v1/devicestatus
| | |
| (sleep SYNC_INTERVAL) |
| | |
- Authenticates with the Carelink mobile API using OAuth bearer tokens
- Fetches the latest pump, sensor, and event marker data via the
/display/messageendpoint - Transforms SGV readings into Nightscout
entrieswith trend direction and delta - Transforms insulin, meal, and auto-basal markers into Nightscout
treatments(boluses, carbs, and temp basals) - Builds
devicestatuswith battery, reservoir, IOB, and pump suspend state - Deduplicates using SHA-256 fingerprints to avoid uploading duplicate records across all endpoints
- Sleeps and repeats. Uses fast retries (60s) when waiting for a new reading, then falls back to the configured interval.
Everything is reported through container stdout. Example output:
2026-08-14 17:34:11 [INFO] root: --- Sync Cycle [17:34:11 UTC] ---
2026-08-14 17:34:11 [INFO] root: Device Status: sensorState=NO_ERROR_MESSAGE | conduitInRange=True | pumpComm=True
2026-08-14 17:34:11 [INFO] root: Carelink Data: Glucose=124 mg/dL | Battery=75% | Reservoir=182.5 U
2026-08-14 17:34:11 [INFO] root: Nightscout Upload: SGV entries=1 (skipped=287) | Treatments=2 (skipped=14)
2026-08-14 17:34:11 [INFO] root: New SGV reading received and synced!
2026-08-14 17:34:11 [INFO] root: Next sync check in 60s.
Carelink refresh tokens are single-use. After each refresh, the new token pair is persisted to /data/carelink_tokens.json inside the container volume. This means:
- The container survives restarts without re-authentication
- The initial env var tokens are used on first boot
- Handling prolonged disconnections: If the container is offline for too long and the volume tokens expire/stop working, generate fresh tokens using
token/carelink_carepartner_api_login.py, update.env, and restart the container (docker compose restart cl2ns). On startup, cl2ns checks if the volume tokens fail authentication; if fresh tokens with newer timestamps are detected in the environment variables, it will automatically adopt them and update the volume. - To prevent using stale tokens when Medtronic services are temporarily unreachable, fallback to
.envis only attempted on startup and only when the.envtokens are verified to be newer than the volume's stored tokens.
| Log Message | Meaning |
|---|---|
sensorState=UNKNOWN |
Sensor is not active (warmup, expired, or not inserted) |
conduitInRange=False |
Phone/conduit cannot reach the pump |
systemStatus=BLUETOOTH_OFF |
Bluetooth is disabled on the pump |
Glucose=N/A |
No valid SG readings (all readings are 0 / sensor error) |
Carelink Auth Error |
Token expired and refresh failed. Generate new tokens. |
This logic was built with the help of the following incredible community projects and sources:
- Home-Assistant-Carelink by yo-han
- carelink_carepartner_api_login.py by yo-han
- carelink-python-client by ondrej1024
- carelink-python-client by palmarci
This integration was developed with the assistance of AI. As an experienced developer, I utilized AI tools to accelerate the reverse-engineering of the intercepted API payloads and to scaffold the modern standalone Docker container architecture. All logic, architecture decisions, and final code implementations were manually directed, reviewed, and validated to ensure robustness and compliance with Python and Docker development standards.
