Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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"}
  ]
end

Then run:

mix deps.get

Usage

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}")
end

Parse 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
end

Convenience 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 of FitFile.DataField structs

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")
end

Data 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 compile

Running tests

mix test

Releasing (Maintainers)

This project uses GitHub Actions to automatically build precompiled NIFs for multiple platforms.

Release Process

  1. Update the version in mix.exs
  2. Update CHANGELOG.md with the new version and changes
  3. Commit the changes: git commit -am "Release v0.x.0"
  4. Create and push a git tag: git tag v0.x.0 && git push origin v0.x.0
  5. 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
  6. 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

License

MIT

Credits

This library wraps the excellent fitparser Rust crate by Matthew Stadelman.

About

A FIT file parser for Elixir

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages