Skip to main content

A Python library for interacting with Garmin proprietary BLE protocols.

Project description

garmin-ble logo garmin-ble

PyPI Python Version License

A clean-room Python implementation of Garmin's proprietary BLE protocol (GFDI V2). Stream live telemetry from your Garmin watch directly to your computer: no cloud, no phone, no Garmin Connect required.


Features

  • Live Telemetry — stream real-time sensor data over BLE without Garmin Connect:
    • ❤️ Heart Rate & Resting Heart Rate
    • 🚶 Daily Steps & Goal
    • 📊 Heart Rate Variability (HRV)
    • 🫁 Blood Oxygen (SpO2)
    • 🌬️ Respiration Rate
    • 🔥 Calories (total & active)
    • ⚡ Intensity Minutes
    • 🧘 Stress Level
    • 🔋 Body Battery
    • ⌚ Accelerometer
  • On-Demand Service Registration — telemetry services start only when you ask. No unwanted data streaming.
  • Protocol Decoding — full implementation of the Garmin GFDI V2 stack:
    • Automated handshake (CLOSE_ALL, REGISTER_ML)
    • MLR (Multi-Link Routing) packet multiplexing
    • COBS (Consistent Overhead Byte Stuffing) encoding/decoding
    • Compiled Protobufs for gdi_smart_proto
    • CRC16 integrity checking
  • Automatic Reconnection — survives BLE drops with exponential backoff
  • Keep-Alive Heartbeat — periodic time-sync to maintain the link
  • Hackable — pure Python, no binary blobs, no proprietary SDKs

Installation

pip install garmin-ble

Or install from source with dev dependencies:

git clone https://github.com/gwerneckp/garmin-ble.git
cd garmin-ble
pip install -e ".[dev]"

Quick Start

import asyncio
from garmin_ble import GarminClient, GarminService

def on_heart_rate(hr, resting_hr):
    print(f"❤️  {hr} BPM (Resting: {resting_hr} BPM)")

async def main():
    client = GarminClient()
    client.on("hr", on_heart_rate)

    if await client.connect():
        # Register and start only the services you want
        await client.register_and_start_service(GarminService.REALTIME_HR)
        print("Connected! Streaming data...")
        await client.start_sync_loop()

asyncio.run(main())

[!TIP] Make sure your watch is not connected to your phone via Bluetooth — Garmin watches only allow one BLE connection at a time.

[!IMPORTANT] Telemetry services are not auto-started. Use register_and_start_service() for each service you need (e.g., GarminService.REALTIME_STEPS, GarminService.REALTIME_ACCELEROMETER). Only the GFDI control channel is registered automatically.

See the examples/ directory for more complete usage patterns — including basic_telemetry.py (simple start), full_demo.py (advanced features), and tilt_volume.py (accelerometer-driven Mac volume control).


Status & Roadmap

See the GitHub Issues for the full breakdown of planned features, known gaps, and in-progress work. Milestones map to release versions:

Phase Goal Status
1 🏗️ BLE transport & handshake ✅ Done
2 📡 Live telemetry streaming ✅ Done
3 🧠 Protobuf settings & device state 🔄 In progress
4 🔔 Notifications & media control ⏳ Planned
5 📁 File transfers (FIT / GPX downloads) ⏳ Planned
6 🗄️ Persistence & dashboard ⏳ Planned

Design Philosophy

garmin-ble is a wire-protocol library, not a feature-complete application. It knows how to encode, send, decode, and respond to Garmin's BLE protobufs — and nothing more.

This means:

  • The library does not fetch weather from OpenWeatherMap, sync calendars via CalDAV, or play sounds when the watch says "find my phone".
  • Instead it provides the building blocks — protobuf encode/decode, callbacks for incoming messages, and transport helpers.
  • Callers wire up the OS integration, external APIs, and user-facing features.

This keeps the library focused, testable, and free of the endless feature creep that plagues integration-heavy projects.

Consider using Gadgetbridge instead if: you want a full-featured open-source replacement for the Garmin Connect app on your Android phone.

Project Mission

Own your data. Garmin devices capture a wealth of physiological data, but Garmin Connect locks it behind a cloud service. This library gives you direct, programmatic access to your watch over BLE — no internet required.


Acknowledgements & License

This project builds on the extraordinary reverse-engineering work of the Gadgetbridge team. The protocol logic, COBS decoding, and .proto schemas are derived from their open-source Java implementation.

Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0) — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

garmin_ble-0.2.2.tar.gz (33.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

garmin_ble-0.2.2-py3-none-any.whl (43.6 kB view details)

Uploaded Python 3

File details

Details for the file garmin_ble-0.2.2.tar.gz.

File metadata

  • Download URL: garmin_ble-0.2.2.tar.gz
  • Upload date:
  • Size: 33.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for garmin_ble-0.2.2.tar.gz
Algorithm Hash digest
SHA256 8567fa1b1d85c88410fae58a6360ffc457103f3a3dc57f34935f5f57828ad6ff
MD5 1c39666563157aff514b3e03f50e3df1
BLAKE2b-256 818c73553c5a443ad290163a2a0f00a22e9ba2c5f2ad4968406cc0e6e97e663d

See more details on using hashes here.

Provenance

The following attestation bundles were made for garmin_ble-0.2.2.tar.gz:

Publisher: publish.yml on gwerneckp/garmin-ble

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file garmin_ble-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: garmin_ble-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 43.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for garmin_ble-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 ca81346a3d2c25ba1b5f632b019882eec6d2c3faf58cd1addd3ba9850145a43f
MD5 bd914cd3596e50139a2d8191b504e81b
BLAKE2b-256 fdb87b853435e718d046482d238b73f7320bd6bdd0916429b2af797a49cf92ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for garmin_ble-0.2.2-py3-none-any.whl:

Publisher: publish.yml on gwerneckp/garmin-ble

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page