Skip to main content

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
  • Typed Metrics — every reading is a dataclass with named fields, not positional tuples
  • On-Demand Service Registration — subscribing to a metric starts its service; the last unsubscribe stops it
  • 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 and restores subscriptions
  • Keep-Alive Heartbeat — periodic time-sync to maintain the link
  • Simulator & Replay — develop, test, and reproduce bugs with no hardware
  • Frame Tracing — per-session capture files and live protocol diagnostics
  • 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 Watch, metrics

async def main():
    async with Watch.discover() as watch:
        print(f"Connected to {watch.info.name}")

        async for reading in watch.stream(metrics.HEART_RATE):
            print(f"❤️  {reading.bpm} BPM (resting {reading.resting_bpm})")

asyncio.run(main())

The session owns connecting, the GFDI handshake, the keep-alive heartbeat, and reconnection — and leaving the block always disconnects, including on Ctrl+C. Subscribing to a metric registers and starts its service on the watch; the last unsubscribe stops it.

Prefer callbacks? Both sync and async def handlers work:

@watch.on(metrics.HEART_RATE)
async def _(reading: metrics.HeartRate) -> None:
    await store(reading.bpm)

No watch on hand

Swap the factory and the same code runs with no hardware — useful for development, examples, and CI:

async with Watch.simulated(profile="fenix7") as watch:   # in-process watch
async with Watch.replay("session.gble") as watch:        # a recorded session

watch.record(path) writes a capture that Watch.replay reads back, so a protocol bug can be reproduced by someone who does not own the watch.

Reading device state

battery = await watch.battery()          # -> Battery(percent=88, status="ok")
result  = await watch.collect(timeout=60)  # one sample of every metric
print(result)                              # renders a ✅/⏳ checklist

Failures raise: WatchNotFound carries the devices the scan did see, HandshakeError names the stage it stopped at, and ServiceUnavailable is raised when the watch declines a metric rather than leaving a stream that never yields.

[!TIP] Make sure your watch is not connected to your phone via Bluetooth — Garmin watches only allow one BLE connection at a time. Run python examples/scan.py if discovery fails; it lists every device in range and says why none matched.

See the examples/ directory for complete usage patterns — telemetry_basic.py (simplest start), telemetry_advanced.py (every stream at once, reconnection, diagnostics), device_state.py (protobuf in both directions), full_walkthrough.py (verify every feature), and accelerometer_3d.py (live 3D orientation). Most accept --simulate.


Status & Roadmap

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

Release Goal Status
v0.1.0 🏗️ BLE transport & handshake ✅ Done
v0.2.0 📡 Live telemetry streaming ✅ Done
v0.3.0 ⌚ Watch API, transports, simulator & replay ✅ Done
v0.4.0 🧠 Protobuf settings & device state 🔄 In progress
v0.5.0 🔔 Notifications & media control ⏳ Planned
v0.6.0 📁 File transfers (FIT / GPX downloads) ⏳ Planned
v1.0.0 🗄️ Stable release ⏳ 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.

Release files for garmin-ble 0.3.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for garmin-ble 0.3.2
File Size Uploaded
garmin_ble-0.3.2.tar.gz 78.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for garmin-ble 0.3.2
File Interpreter ABI Platform
garmin_ble-0.3.2-py3-none-any.whl Python 3 none any Details

Total release size: 179.9 kB

Release files / garmin_ble-0.3.2.tar.gz

Download URL garmin_ble-0.3.2.tar.gz
Size 78.3 kB
Tags Source
SHA-256 checksum
How to use checksums
5e956ad6ed1ee73de8a169f8566a68502cc08f0b08305153d8dbfdf22399f0cb
BLAKE2b-256 checksum
How to use checksums
4f5dae6680f6e82cfbfaac8afe5b39ee4ac66a8fc02385b778004896bb479c34
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 1, 2026.

Transparency log

Release files / garmin_ble-0.3.2-py3-none-any.whl

Download URL garmin_ble-0.3.2-py3-none-any.whl
Size 101.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0d05e5212de7339eb2245624d7aa465d7885985655643b80ebe458b3b698a0f3
BLAKE2b-256 checksum
How to use checksums
6b08bb73d2e25a9308d8218a473de2a04291390ace2cf3d5cdf87e9f16ae6d32
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.2 This release

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page