Sports watches are poorly supported by their manufacturers regarding linux. After I started running I decided on a Garmin FR 410, since it was quite cheap and has all the functionality I wanted. I neglected to look up how it works under linux and for the first couple of months after I got it I had to boot up my XP in VM to transfer data to and from the watch.
Then I came across a nice python tool that made it possible to get data off the watch and upload it to Connect Garmin. The tool is called python_ant_downloader and you can find supported watch models on their github page. It is simple to install through pip (use sudo if needed):
user@host $ sudo pip install python_ant_downloader
Edit 3rd July 2014: If you use Anaconda for virtual python environments as I do, then you might be having issues with python module dbm not being installed when running the ant-downloader:
user@host $ ant-downloader
Traceback (most recent call last):
...
import dbm
ImportError: No module named dbm
If so, you can install it straight from github:
user@host $ sudo pip install git+git://github.com/braiden/python-ant-downloader.git
This gives you a terminal program called ant-downloader that can retrieve data from a connected garmin watch and upload it to garmin. First, I had a problem where my ant+ stick was not getting permissions to mount. In Ubuntu (and derived systems, and probably other distros as well) non-standard usb sticks are not allowed to mount automatically. Those devices follow permission rules that are present in /etc/udev/rules.d/. To generate a rule for our USB Ant+ stick we need to figure out the sticks ID:
user@host $ lsusb
Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 003 Device 002: ID 0fcf:1008 Dynastream Innovations, Inc.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
In my case I identified my USB stick by running the command with it unplugged and then again plugged in. Here the Dynastream Innovation, Inc. is the stick and note the ID : 0fcf:1008. Now we generate a rule for that device:
user@host $ sudo echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="0fcf", ATTR{idProduct}=="1008", MODE="666"' > /etc/udev/rules.d/99-garmin.rules
user@host $ sudo bash -c "echo 'SUBSYSTEM==\"usb\", ATTR{idVendor}==\"0fcf\", ATTR{idProduct}==\"1008\", MODE=\"666\"' > /etc/udev/rules.d/99-garmin.rules"
Edit 3rd July 2014: On Arch based system (I’m using Manjaro at the moment) the command is a bit different:
user@host $ sudo bash -c "echo 'SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0fcf\", ATTRS{idProduct}==\"1008\", MODE=\"666\"' > /etc/udev/rules.d/99-garmin.rules"
Note that the vendor and product attributes use their respective parts of the ID above. Saving this and plugin the USB again should allow you to run
user@host $ ant-downloader
The first time it runs, it generates configs and tries to pair with your watch. After that, you can edit the file ~/.antd/antd.cfg and add your connect.garmin details under the config [antd.connect] (and set enabled = True) for automatic upload to their server. Your workouts are also stored as .tcx files that you can upload to other servers than garmin, you find them in the folder ~/.antd/0xDEVICENR/tcx/ .
Hope this will be of use to someone 🙂 Please let me know of any issues you find with this method.
Binni out.
At my system (Debian Sid), I had to use ATTRS instead of ATTR in the udev-rule.
Nice to know, I also see that some use quite different names, e.g SYS instead of ATTR(S) and some other changes.
Just followed your explanations and got my FR410 up and running in a moment. Thanks a lot!
Happy to hear that 🙂
Hello,
I have tried your procedure but unfortunately It does work for me (ubuntu 12.04.3, Forerunner 410):
sudo ant-downloader gives:
[MainThread] 2014-01-02 14:40:36,109 WARNING Caught exception trying to cleanup resources.
Traceback (most recent call last):
File “/usr/local/lib/python2.7/dist-packages/antd/ant.py”, line 557, in __init__
try: self.close()
File “/usr/local/lib/python2.7/dist-packages/antd/ant.py”, line 577, in close
self.reset_system()
File “/usr/local/lib/python2.7/dist-packages/antd/ant.py”, line 592, in reset_system
cap = self.get_capabilities()
File “/usr/local/lib/python2.7/dist-packages/antd/ant.py”, line 607, in get_capabilities
return self._send(RequestMessage(0, Capabilities.ID))
File “/usr/local/lib/python2.7/dist-packages/antd/ant.py”, line 680, in _send
raise cmd.error
AntTimeoutError: No reply to command. REQUEST_MESSAGE(channel_number=0, msg_id=84)
Traceback (most recent call last):
File “/usr/local/bin/ant-downloader”, line 9, in
load_entry_point(‘python-ant-downloader==13.02.24’, ‘console_scripts’, ‘ant-downloader’)()
File “/usr/local/lib/python2.7/dist-packages/antd/main.py”, line 75, in downloader
host = antd.cfg.create_antfs_host()
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 118, in create_antfs_host
host = antfs.Host(create_ant_session(), keys)
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 105, in create_ant_session
session = ant.Session(create_ant_core())
File “/usr/local/lib/python2.7/dist-packages/antd/ant.py”, line 559, in __init__
finally: raise e
antd.ant.AntTimeoutError: No reply to command. REQUEST_MESSAGE(channel_number=0, msg_id=84)
Thanks a lot for you help!
Try without sudo, does that give some different result?
Did you figure out the usb id and create a udev rule for the ant stick?
Hello binnisb,
First of al : thank you for your help!
lsusb gives: Bus 005 Device 002: ID 0fcf:1008 Dynastream Innovations, Inc.
And today when I want to generate a rule, It return “permission not allowed”:
sudo echo ‘SUBSYSTEM==”usb”, ATTR{idVendor}==”0fcf”, ATTR{idProduct}==”1008″, MODE=”666″‘ > /etc/udev/rules.d/99-garmin.rules
bash: /etc/udev/rules.d/99-garmin.rules: Permission non accordée
Unfortunately, I can’t remember if I had this message last week…
ls /etc/udev/rules.d returns:
70-persistent-cd.rules 70-persistent-net.rules ant-usbstick2.rules README
The command I give in the blogpost is not quite correct. Try running this command to create the garmin rule:
sudo bash -c "echo 'SUBSYSTEM==\"usb\", ATTR{idVendor}==\"0fcf\", ATTR{idProduct}==\"1008\", MODE=\"666\"' > /etc/udev/rules.d/99-garmin.rules"
Thanks a lot!!!!! It works !!! I bought my forerunner 410 1 year ago, and for the first time I have automatically uploaded my tracks on garmin connect without using W….! Note that” False” should be replaced by “true” under the config [antd.connect]. Thank you for your help!
Great to hear that it works 🙂 I included the enabled parameter that you had to change to True in the tutorial.
Hi, I have been following your instructions but I stumble across this error:
patrick@patrick-linux:~$ ant-downloader
Traceback (most recent call last):
File “/usr/local/lib/python2.7/dist-packages/logging-0.4.9.6-py2.7.egg/logging/__init__.py”, line 723, in emit
msg = self.format(record)
File “/usr/local/lib/python2.7/dist-packages/logging-0.4.9.6-py2.7.egg/logging/__init__.py”, line 609, in format
return fmt.format(record)
File “/usr/local/lib/python2.7/dist-packages/logging-0.4.9.6-py2.7.egg/logging/__init__.py”, line 402, in format
s = self._fmt % record.__dict__
KeyError: ‘threadName’
Traceback (most recent call last):
File “/usr/local/lib/python2.7/dist-packages/logging-0.4.9.6-py2.7.egg/logging/__init__.py”, line 723, in emit
msg = self.format(record)
File “/usr/local/lib/python2.7/dist-packages/logging-0.4.9.6-py2.7.egg/logging/__init__.py”, line 609, in format
return fmt.format(record)
File “/usr/local/lib/python2.7/dist-packages/logging-0.4.9.6-py2.7.egg/logging/__init__.py”, line 402, in format
s = self._fmt % record.__dict__
KeyError: ‘threadName’
Traceback (most recent call last):
File “/usr/local/lib/python2.7/dist-packages/logging-0.4.9.6-py2.7.egg/logging/__init__.py”, line 723, in emit
msg = self.format(record)
File “/usr/local/lib/python2.7/dist-packages/logging-0.4.9.6-py2.7.egg/logging/__init__.py”, line 609, in format
return fmt.format(record)
File “/usr/local/lib/python2.7/dist-packages/logging-0.4.9.6-py2.7.egg/logging/__init__.py”, line 402, in format
s = self._fmt % record.__dict__
KeyError: ‘threadName’
Traceback (most recent call last):
File “/usr/local/bin/ant-downloader”, line 9, in
load_entry_point(‘python-ant-downloader==13.02.24’, ‘console_scripts’, ‘ant-downloader’)()
File “/usr/local/lib/python2.7/dist-packages/antd/main.py”, line 75, in downloader
host = antd.cfg.create_antfs_host()
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 118, in create_antfs_host
host = antfs.Host(create_ant_session(), keys)
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 105, in create_ant_session
session = ant.Session(create_ant_core())
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 101, in create_ant_core
return ant.Core(create_hardware())
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 97, in create_hardware
return hw.SerialHardware(tty, 115200)
File “/usr/local/lib/python2.7/dist-packages/antd/hw.py”, line 81, in __init__
self.dev = serial.Serial(port=dev, baudrate=baudrate, timeout=1)
File “/usr/lib/python2.7/dist-packages/serial/serialutil.py”, line 261, in __init__
self.open()
File “/usr/lib/python2.7/dist-packages/serial/serialposix.py”, line 278, in open
raise SerialException(“could not open port %s: %s” % (self._port, msg))
serial.serialutil.SerialException: could not open port /dev/ttyUSB0: [Errno 13] Permission denied: ‘/dev/ttyUSB0’
Any idea what’s the problem?
Thanks in advance
Did you generate the rule to allow you access to the usb stick?
user@host $ sudo bash -c "echo 'SUBSYSTEM==\"usb\", ATTR{idVendor}==\"0fcf\", ATTR{idProduct}==\"1008\", MODE=\"666\"' > /etc/udev/rules.d/99-garmin.rules"
After running this, do
user@host $ ls -al /etc/udev/rules.d/
And make sure it exists
Also, test doing
user@host $ sudo ant-downloader
I have this issue when I run the downloader. Thoughts?
growl@GROWL:~$ ant-downloader
[MainThread] 2014-11-11 17:30:30,911 INFO Found device with vid(0x0fcf) pid(0x1008), but interface already claimed.
[MainThread] 2014-11-11 17:30:30,915 WARNING Failed to find Garmin nRF24AP2 (newer) USB Stick.
Traceback (most recent call last):
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 92, in create_hardware
return hw.UsbHardware(id_vendor, id_product, bulk_endpoint)
File “/usr/local/lib/python2.7/dist-packages/antd/hw.py”, line 61, in __init__
raise NoUsbHardwareFound(errno.ENOENT, “No available device matching vid(0x%04x) pid(0x%04x).” % (id_vendor, id_product))
NoUsbHardwareFound: [Errno 2] No available device matching vid(0x0fcf) pid(0x1008).
[MainThread] 2014-11-11 17:30:30,916 WARNING Looking for nRF24AP1 (older) Serial USB Stick.
Traceback (most recent call last):
File “/usr/local/bin/ant-downloader”, line 9, in
load_entry_point(‘python-ant-downloader==13.02.24’, ‘console_scripts’, ‘ant-downloader’)()
File “/usr/local/lib/python2.7/dist-packages/antd/main.py”, line 75, in downloader
host = antd.cfg.create_antfs_host()
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 118, in create_antfs_host
host = antfs.Host(create_ant_session(), keys)
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 105, in create_ant_session
session = ant.Session(create_ant_core())
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 101, in create_ant_core
return ant.Core(create_hardware())
File “/usr/local/lib/python2.7/dist-packages/antd/cfg.py”, line 97, in create_hardware
return hw.SerialHardware(tty, 115200)
File “/usr/local/lib/python2.7/dist-packages/antd/hw.py”, line 81, in __init__
self.dev = serial.Serial(port=dev, baudrate=baudrate, timeout=1)
File “/usr/lib/python2.7/dist-packages/serial/serialutil.py”, line 261, in __init__
self.open()
File “/usr/lib/python2.7/dist-packages/serial/serialposix.py”, line 278, in open
raise SerialException(“could not open port %s: %s” % (self._port, msg))
serial.serialutil.SerialException: could not open port /dev/ttyUSB0: [Errno 2] No such file or directory: ‘/dev/ttyUSB0’
Not at the computer right now but did you create the garmin rule in /etc/rules/
Is it the same watch?
7 years later: in case someone runs into that issue, I solved it by simply using sudo
sudo ant-downloader
Thanks for a very helpful article! This utility syncs faster than the Garmin bloatware on my Mac and Windows laptops.
Glad to hear that 🙂