Garmin Forerunner (ANT+) mit Ubuntu auslesen

In diesem Artikel zeige ich, wie man eine Garmin-Laufuhr (mit ANT+-Schnittstelle) mit einem Linux-System synchronisieren kann, d.h. auf die aufgezeichneten Tracks im Garmin-eigenen FIT-Format zugreifen kann um sie beispielsweise bei Garmin Connect zu veröffentlichen.
Das Auslesen der Uhr geschieht dabei von der Kommandozeile aus mit dem Python-Tool antfs-cli.

In meinem Fall handelt es sich um ein Garmin Forerunner 610, welche mit einem ANT+-USB-Strick geliefert wurde. Laut Projektseite von antfs-cli sollte die vorgestellte Software auch mit anderen ANT+-fähigen Laufuhren von Garmin funktionieren.
Mein Linux-System ist ein Lenovo Thinkpad auf dem ein Ubuntu 16.04 installiert ist. Die Installationsanleitung ist daher Ubuntu-spezifisch, sollte aber unverändert auf Debian-basierten Systemen funktionieren.

(Dieser Artikel ist eine aktualisierte und erweiterte Version meines Artikels von 2015)

Vorbereitungen

1. Benötigte Software-Pakete müssen vorhanden sein (python, python-setuptools, git, libusb-1.0-0, usbutils). Falls nicht, können sie über das Terminal mit

florian@ubuntu:~$ sudo apt-get update
florian@ubuntu:~$ sudo apt-get install python python-setuptools
florian@ubuntu:~$ sudo apt-get install git libusb-1.0-0 usbutils

installiert werden.

2. ANT+-Stick muss eingesteckt und vom Rechner erkannt werden, was man einfach mit einem Aufruf von lsusb feststellen kann:

florian@ubuntu:~$ lsusb
...
Bus 001 Device 011: ID 0fcf:1009 Dynastream Innovations, Inc. ANTUSB-m Stick
...

Hier muss neben vielen anderen USB-Devices ein ANT+-USB-Stick angezeigt werden.

ANT+-Stick im Laptop
ANT+-Stick im Laptop

3. Aktuelle Versionen von pyusb, openant und antfs-cli von github.com herunterladen und installieren:

# Repositories klonen
git clone https://github.com/walac/pyusb.git     /tmp/pyusb
git clone https://github.com/Tigge/openant.git   /tmp/openant
git clone https://github.com/Tigge/antfs-cli.git /tmp/antfs-cli

# Installieren; Root-Passwort wird benötigt!
(cd /tmp/pyusb     ; sudo python setup.py install)
(cd /tmp/openant   ; sudo python setup.py install)
(cd /tmp/antfs-cli ; sudo python setup.py install)

# Repository-Klone wieder löschen
rm -rf /tmp/pyusb /tmp/openant /tmp/antfs-cli[/code]

Nach erfolgreichem Ausführen dieser Setup-Skripte, sollte es insbesondere ein antfs-cli-Executable in /usr/local/bin/ geben, zudem sollten udev-Regeln für den ANT+USB-Stick in /etc/udev/rules.d/ angelegt worden sein.

Pairing und Synchronisation

Ein erstmaliger Aufruf von antfs-cli führt ein Paring durch, welches man an der Uhr bestätigen muss:

Pairing-Bestätigung am Forerunner 610
Pairing-Bestätigung am Forerunner 610

Danach startet direkt der Download der Daten.
Die Ausgabe im Terminal sollte etwas wie folgt aussehen:

florian@ubuntu:~$ antfs-cli
Driver available: [, , ]
 - Using: ant.base.driver.USB3Driver
Request basic information...
  Capabilities:  array('B', [8, 8, 0, 186, 54, 0, 223])
Starting system...
Key done...
Searching...
Authenticating with Forerunner 610 (3897XXXXXX)
 - Pairing: OK
 - Set time: FAILED
Downloading 158 file(s)
Downloading 2016-03-31_15-50-36_4_108.fit: [..............................] ETA: 0:00:00
...
Transfer-Anzeige am Forerunner 610
Transfer-Anzeige am Forerunner 610

Bei nachfolgenden Aufrufen von antfs-cli entfällt der Pairing-Schritt und der Download beginnt sofort (sofern neue Daten auf der Uhr vorhanden sind).

Die heruntergeladenen Daten landen im Verzeichnis ~/.config/antfs-cli/3897XXXXXX/activities, wobei 3897XXXXXX die Identifikationsnummer des Forerunner ist.

Und dann?

Nach einem Lauf rufe ich immer antfs-cli im Terminal auf, um die neuen Tracks von der Uhr herunterzuladen.

Garmin Connect

Typischerweise lade ich die neuen Tracks dann bei Garmin Connect hoch.
Dazu öffne ich im Browser die Aktivitäts-Seite von Garmin Connect, starte die Funktion „manuell hochladen“ und wähle dann die neue FIT-Datei aus dem Verzeichnis ~/.config/antfs-cli/3897XXXXXX/activities aus.
Voilà, mein neuer Lauf ist auf Garmin Connect verfügbar!

Upload bei Garmin Connect
Upload bei Garmin Connect

Strava

Ein Upload bei Strava funktioniert ähnlich.
Hier ruft man die Upload-Seite auf, klickt auf den Menüpunkt „Datei“, und wählt anschließend die FIT-Datei aus dem Verzeichnis ~/.config/antfs-cli/3897XXXXXX/activities aus.
Bingo! – Der Lauf ist auf Strava!

Man kann sein Strava-Profil auch automatisch von Garmin Connect aus befüllen lassen – wie man das einrichtet, erkläre ich in einem separaten Betrag.

GPSBabel

Mit den Kommandozeilentool gpsbabel lassen sich die FIT-Dateien in weitere Formate konvertieren und anderweitig weiterverwenden.
Eine GPX-Datei erzeugt man bespielsweise so:

gpsbabel -i garmin_fit -f EINGABE.fit -o gpx -F AUSGABE.gpx

EINGABE.fit ist dabei z.B. eine FIT-Datei aus dem Verzeichnis ~/.config/antfs-cli/3897XXXXXX/activities, AUSGABE.gpx ist der Name der zu erzeugenden GPX-Datei.

11 Gedanken zu „Garmin Forerunner (ANT+) mit Ubuntu auslesen“

  1. Hallo, das ist eine sehr schöne Anleitung. Auch als Linux-Anfänger kommt man damit zurecht.
    Leider klappt das Pairing nicht bei mir…
    Vielleicht kannst Du mir helfen? Besten Dank schon jetzt!
    Wolfgang

    Serial information:
    name: /dev/ttyUSB1
    port: /dev/ttyUSB1
    baudrate: 115200
    bytesize: 8
    parity: N
    stopbits: 1
    timeout: None
    writeTimeout: None
    xonxoff: False
    rtscts: False
    dsrdtr: False
    interCharTimeout: None
    Request basic information…
    Capabilities: array(‚B‘, [4, 3, 0, 3])
    Starting system…
    Key done…
    Searching…
    Authenticating with Forerunner 310XT (3872301226)
    – Pairing:

    1. Uh, sorry. Hab deinen Kommentar gar nicht gesehen 🙁
      Ich weiß leider auch nicht, was da schief geht…

      — Florian

  2. Hallo flopp
    danke für Deine Anleitung. Ich habe einen Forerummer 405cx mit ANT+ und bleibe hier stecken….

    Befehl -> antfs-cli
    dann…

    Driver available: [, ]
    – Using: ant.base.driver.USB2Driver
    Request basic information…
    Capabilities: array(‚B‘, [8, 3, 0, 186, 54, 0])
    Starting system…
    Key done…
    Searching…
    Traceback (most recent call last):
    File „build/bdist.linux-x86_64/egg/antfs_cli/program.py“, line 356, in main
    g.start()
    File „/usr/local/lib/python2.7/dist-packages/ant/fs/manager.py“, line 217, in start
    self._main()
    File „/usr/local/lib/python2.7/dist-packages/ant/fs/manager.py“, line 147, in _main
    if self.on_link(beacon):
    File „build/bdist.linux-x86_64/egg/antfs_cli/program.py“, line 159, in on_link
    self.link()
    File „/usr/local/lib/python2.7/dist-packages/ant/fs/manager.py“, line 364, in link
    self._send_command(LinkCommand(self._frequency, 4, self._serial_number))
    File „/usr/local/lib/python2.7/dist-packages/ant/fs/manager.py“, line 193, in _send_command
    self._channel.send_acknowledged_data(data)
    File „/usr/local/lib/python2.7/dist-packages/ant/easy/channel.py“, line 100, in send_acknowledged_data
    self.wait_for_event([Message.Code.EVENT_TRANSFER_TX_COMPLETED])
    File „/usr/local/lib/python2.7/dist-packages/ant/easy/channel.py“, line 51, in wait_for_event
    return wait_for_event(ok_codes, self._node._events, self._node._event_cond)
    File „/usr/local/lib/python2.7/dist-packages/ant/easy/filter.py“, line 72, in wait_for_event
    return wait_for_message(match, process, queue, condition)
    File „/usr/local/lib/python2.7/dist-packages/ant/easy/filter.py“, line 61, in wait_for_message
    raise AntException(„Timed out while waiting for message“)
    AntException: Timed out while waiting for message
    Interrupted: Timed out while waiting for message

    So, für mich als ANfänger sieht dies sehr unklar aus. Kannst Du mir ev einen Tipp geben woran es liegt?

    Gruss Ivica

    1. Hi Ivica,

      oh je, der Artikel ist ja schon Jahre alt – ich weiß gar nicht, ob die Anweisungen dort überhaupt noch aktuell und gültig sind.

  3. Hallo,
    danke für die super Anleitung!

    Ich habe auch eine Garmin 610.
    Als ich 2014 vollständig auf Linux umgestiegen bin, habe ich eine Weile gesucht, ob man die Laufdaten auch von Linux aus auslesen kann. Damals hatte ich leider nichts gefunden und die Sache abgehakt.

    Vor ein paar Wochen bin ich dann auf diesen Blogpost gestoßen 🙂

    Bei mir funktioniert es, ich bin auf Linux Mint 19.3

    Gruß,
    Rene

  4. Hallo Flopp,
    Danke für die Anleitung! Ich habe die Tage eine gebrauchte Forerunner 610 gekauft und gestern ebenfalls die Software-Pakete in Anlehnung an diese Anleitung auf einem Ubuntu-20-HWE übersetzt. Es zeigte sich, dass dort erstaunlicherweise immer noch nur Python2.7 installiert ist. Die Unterstützung für ältere Python-Versionen wurde aus antfs-cli aber mittlerweile entfernt. Daher musste ich zunächst mal die Pakete python3 und python3-setuptools installieren lassen.

  5. Hallo, ich bekomme folgende Fehlermeldung beim Auftruf von antfs-cli:

    File „/usr/local/lib/python2.7/dist-packages/antfs_cli-0.4-py2.7.egg/antfs_cli/program.py“, line 181
    print(“ – Passkey:“, end=“ „)
    SyntaxError: invalid syntax

    Ich nehme an das hat etwas mit der Python Version zu tun? Ich habe daraufhin versucht Python 3 zu installieren mittels
    „sudo apt-get install python3-setuptools “

    Bringt aber keinen Unterschied. Wäre nett, wenn mir jemand einen Tipp geben könnte

    1. Hallo Emil,

      wie oben geschrieben, benötigt antfs-cli Python3. Es arbeitet damit seit 2022-05-20. Die benutzte Ubuntu-Installation ist mittlerweile auf Stand 20.04.1-HWE.

      Stammt diese Meldung vom Pairing-Versuch ?

  6. Die Meldung „SyntaxError: invalid syntax“ kommt bei Pairing-Verusch, aber auch schon bei diesem Schritt der Installation:
    cd /tmp/openant
    ubuntu@ubuntu-akoya:/tmp/openant$ sudo python setup.py install
    /usr/lib/python2.7/distutils/dist.py:267: UserWarning: Unknown distribution option: ‚long_description_content_type‘
    warnings.warn(msg)
    running install
    running build
    running build_py
    running install_lib
    byte-compiling /usr/local/lib/python2.7/dist-packages/ant/easy/node.py to node.pyc
    File „/usr/local/lib/python2.7/dist-packages/ant/easy/node.py“, line 57
    self.serial: Optional[int] = None
    ^
    SyntaxError: invalid syntax

Kommentare sind geschlossen.