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.3.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.3-py3-none-any.whl (43.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: garmin_ble-0.2.3.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.3.tar.gz
Algorithm Hash digest
SHA256 e71d33e3c23faf616a3d4f588278b17f71340993facb67f6926d3916daff71a5
MD5 c9e365c6fdae8547f5a4096ac5e4f59b
BLAKE2b-256 fd8cfcb3548c7bff9e78c6e02b5a990194a54a90d21401fbc26cc69255033549

See more details on using hashes here.

Provenance

The following attestation bundles were made for garmin_ble-0.2.3.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.3-py3-none-any.whl.

File metadata

  • Download URL: garmin_ble-0.2.3-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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 36c811cf151bb2e13e6b5b3f957862a8a56942b098057a09a6fea337e64f44a6
MD5 03a0514e2f6d0aefa2c11f066175c51e
BLAKE2b-256 38f422dcf87a5f3a55860d3c10b465dd052f38e07e67d9fbab2ce55b6d8621db

See more details on using hashes here.

Provenance

The following attestation bundles were made for garmin_ble-0.2.3-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