FitFile
An Elixir wrapper for the Rust fitparser library (v0.10.0) to parse ANT FIT files.
FIT (Flexible and Interoperable Data Transfer) is a file format commonly used by fitness devices from Garmin and other manufacturers to store activity data such as runs, bike rides, and other workouts.
Features
- Parse FIT files from disk or binary data
- Built with Rustler for safe, fast native code execution
- Precompiled binaries available (via rustler_precompiled) - no Rust toolchain required for most users
- Type-safe Elixir structs for parsed data
- Comprehensive error handling
Installation
Add fit_file to your list of dependencies in mix.exs:
def deps do
[
{:fit_file, "~> 0.1.4"}
]
endThen run:
mix deps.getUsage
Parse from a file
case FitFile.from_file("path/to/activity.fit") do
{:ok, records} ->
IO.puts("Successfully parsed #{length(records)} records")
{:error, {reason, message}} ->
IO.puts("Error: #{reason} - #{message}")
endParse from binary data
fit_data = File.read!("path/to/activity.fit")
case FitFile.from_binary(fit_data) do
{:ok, records} ->
# Process records
{:error, {reason, message}} ->
# Handle error
endConvenience parse function
The parse/1 function automatically detects whether you're passing a file path or binary data:
# Parse from file
{:ok, records} = FitFile.parse("activity.fit")
# Parse from binary
{:ok, records} = FitFile.parse(binary_data)Working with Records
Each record contains:
kind: The message type (e.g., "record", "session", "lap", "file_id")fields: A list ofFitFile.DataFieldstructs
Example: Extract specific data
{:ok, records} = FitFile.from_file("activity.fit")
# Filter to get only "record" messages (the actual data points)
data_points = Enum.filter(records, fn r -> r.kind == "record" end)
# Get specific field values
Enum.each(data_points, fn record ->
timestamp = FitFile.DataRecord.get_field_value(record, "timestamp")
speed = FitFile.DataRecord.get_field_value(record, "speed")
heart_rate = FitFile.DataRecord.get_field_value(record, "heart_rate")
IO.puts("Time: #{timestamp}, Speed: #{speed}, HR: #{heart_rate}")
end)Example: Get session summary
{:ok, records} = FitFile.from_file("activity.fit")
session = Enum.find(records, fn r -> r.kind == "session" end)
if session do
total_distance = FitFile.DataRecord.get_field_value(session, "total_distance")
total_time = FitFile.DataRecord.get_field_value(session, "total_elapsed_time")
avg_speed = FitFile.DataRecord.get_field_value(session, "avg_speed")
IO.puts("Distance: #{total_distance}m, Time: #{total_time}s, Avg Speed: #{avg_speed}m/s")
endData Structures
FitFile.DataRecord
%FitFile.DataRecord{
kind: "record",
fields: [%FitFile.DataField{}, ...]
}FitFile.DataField
%FitFile.DataField{
name: "speed",
value: "5.2",
units: "m/s"
}Development
Building from source
If precompiled binaries aren't available for your platform, the library will automatically compile the Rust NIF. You'll need:
- Rust toolchain (install from rustup.rs)
- Elixir 1.18+
To force building from source:
export RUSTLER_PRECOMPILATION_FIT_FILE_BUILD=true
mix deps.get
mix compileRunning tests
mix testReleasing (Maintainers)
This project uses GitHub Actions to automatically build precompiled NIFs for multiple platforms.
Release Process
-
Update the version in
mix.exs -
Update
CHANGELOG.mdwith the new version and changes -
Commit the changes:
git commit -am "Release v0.x.0" -
Create and push a git tag:
git tag v0.x.0 && git push origin v0.x.0 -
GitHub Actions will automatically:
- Build NIFs for all supported platforms (macOS, Linux, Windows)
- Create checksums for each binary
- Create a GitHub release with all artifacts
-
After the release is created, publish to Hex:
mix hex.publish
Supported Platforms
Precompiled binaries are automatically built for:
-
macOS:
aarch64-apple-darwin(Apple Silicon),x86_64-apple-darwin(Intel) -
Linux:
x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu(ARM64) -
Windows:
x86_64-pc-windows-msvc,x86_64-pc-windows-gnu
CI/CD
The project includes two GitHub Actions workflows:
CI (
.github/workflows/ci.yml): Runs on every push/PR- Tests across multiple Elixir/OTP versions
- Runs formatting checks
- Runs Rust linting (clippy, rustfmt)
Release (
.github/workflows/release.yml): Runs on tags and native path changes-
Builds precompiled NIFs for all platforms using
rustler-precompiled-action - Handles cross-compilation automatically (including Linux ARM64)
- Creates GitHub release with artifacts
- Can be triggered manually via workflow_dispatch
-
Builds precompiled NIFs for all platforms using
License
MIT
Credits
This library wraps the excellent fitparser Rust crate by Matthew Stadelman.