GarminRunerz.Workout.Services 1.0.0

dotnet add package GarminRunerz.Workout.Services --version 1.0.0
                    
NuGet\Install-Package GarminRunerz.Workout.Services -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GarminRunerz.Workout.Services" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GarminRunerz.Workout.Services" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="GarminRunerz.Workout.Services" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GarminRunerz.Workout.Services --version 1.0.0
                    
#r "nuget: GarminRunerz.Workout.Services, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GarminRunerz.Workout.Services@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GarminRunerz.Workout.Services&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=GarminRunerz.Workout.Services&version=1.0.0
                    
Install as a Cake Tool

GarminRunerz.Workout.Services

A .NET library providing high-level services for generating and building Garmin workout structures. This library builds upon the GarminRunerz.Workout.Models foundation to offer a fluent API for workout construction and intelligent workout generation from training plans.

Overview

GarminRunerz.Workout.Services is designed to simplify the creation of complex Garmin workout structures through two main approaches:

  1. Fluent Workout Builder: A chainable API for manually constructing workouts with warm-ups, intervals, and cool-downs
  2. Workout Generator Service: An intelligent service that generates complete workouts from training plan specifications

Features

  • Fluent API: Intuitive, chainable methods for workout construction
  • Training Plan Integration: Generate workouts from structured training data
  • Built-in Pace Constants: Pre-defined pace zones for common training intensities
  • Dependency Injection Ready: Full support for .NET dependency injection
  • Comprehensive Logging: Integrated logging for workout generation processes
  • Automatic Calculations: Smart estimation of workout duration and distance
  • NuGet Package: Available as a .NET package for easy integration

Installation

Install the package via NuGet Package Manager:

Install-Package GarminRunerz.Workout.Services

Or via .NET CLI:

dotnet add package GarminRunerz.Workout.Services

Dependencies

This package depends on:

  • GarminRunerz.Workout.Models - Core workout data models
  • Microsoft.Extensions.DependencyInjection.Abstractions - Dependency injection support
  • Microsoft.Extensions.Logging.Abstractions - Logging support

Quick Start

Dependency Injection Setup

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using GarminRunerz.Workout.Services;

var services = new ServiceCollection();

// Add logging
services.AddLogging(builder => builder.AddConsole());

// Register services
services.AddScoped<IWorkoutBuilder, WorkoutBuilder>();
services.AddScoped<IWorkoutGeneratorService, WorkoutGeneratorService>();

var serviceProvider = services.BuildServiceProvider();

Fluent Workout Builder

using GarminRunerz.Workout.Services;
using GarminRunerz.Workout.Models;

// Create a workout using the fluent builder
var builder = serviceProvider.GetRequiredService<IWorkoutBuilder>();

var workout = builder
    .Reset("5K Interval Training")
    .WithSport("running")
    .AddWarmUp(600) // 10 minutes warm-up
    .AddIntervals(
        repetitions: 5,
        runSeconds: 180,  // 3 minutes hard
        restSeconds: 90,  // 1.5 minutes recovery
        targetPaceMinPerKm: 4.0m, // 4:00 min/km target pace
        toleranceMinPerKm: 0.15m  // ±9 seconds tolerance
    )
    .AddCoolDown(600) // 10 minutes cool-down
    .WithEstimates(durationSecs: 2250, distanceMeters: 8000)
    .Build();

Console.WriteLine($"Workout: {workout.WorkoutName}");
Console.WriteLine($"Estimated Duration: {workout.EstimatedDurationInSecs} seconds");
Console.WriteLine($"Estimated Distance: {workout.EstimatedDistanceInMeters} meters");

Workout Generator Service

using GarminRunerz.Workout.Services;
using GarminRunerz.Workout.Services.Models;

// Create a custom workout specification
var customWorkout = new CustomWorkout
{
    WeekNumber = 4,
    RunType = RunType.Intervals,
    Repetitions = 6,
    RunDuration = 240,      // 4 minutes hard intervals
    CoolDownDuration = 120, // 2 minutes recovery
    Pace = 3.85m,          // 3:51 min/km (close to VMA pace)
    Description = "Week 4 VMA intervals"
};

// Generate the complete workout
var generator = serviceProvider.GetRequiredService<IWorkoutGeneratorService>();
var workout = generator.GenerateWorkoutsFromPlanning(customWorkout);

Console.WriteLine($"Generated: {workout.WorkoutName}");
Console.WriteLine($"Description: {workout.Description}");

API Reference

IWorkoutBuilder

The fluent builder interface for constructing workouts step by step.

Methods

IWorkoutBuilder Reset(string workoutName)

  • Initializes a new workout with the given name
  • Resets all previous state
  • Returns the builder for chaining

IWorkoutBuilder WithAuthor(Author author)

  • Sets the workout author information
  • Returns the builder for chaining

IWorkoutBuilder WithSport(string sportTypeKey = "running", int sportTypeId = 1, int displayOrder = 1)

  • Configures the sport type for the workout
  • Defaults to running if not specified
  • Returns the builder for chaining

IWorkoutBuilder WithTimestamps(DateTime utcNow)

  • Sets creation and update timestamps
  • Returns the builder for chaining

IWorkoutBuilder WithEstimates(int durationSecs, int distanceMeters)

  • Sets estimated duration and distance
  • Returns the builder for chaining

IWorkoutBuilder AddWarmUp(double durationSeconds)

  • Adds a warm-up step with no specific target
  • Creates a "lap button" end condition
  • Returns the builder for chaining

IWorkoutBuilder AddIntervals(int repetitions, double runSeconds, double restSeconds, decimal targetPaceMinPerKm, decimal toleranceMinPerKm = 0.15m)

  • Adds a repeat group containing interval and rest steps
  • Creates pace-targeted intervals with the specified tolerance
  • Returns the builder for chaining

IWorkoutBuilder AddCoolDown(double durationSeconds)

  • Adds a cool-down step with no specific target
  • Creates a "lap button" end condition
  • Returns the builder for chaining

Workout Build()

  • Returns the completed workout object
  • Does not reset the builder state

IWorkoutGeneratorService

Service interface for generating workouts from training plan data.

Methods

Workout GenerateWorkoutsFromPlanning(CustomWorkout customWorkout, int? estimatedDuration = null, int? estimatedDistance = null)

  • Generates a complete workout from training plan specifications
  • Automatically calculates duration and distance if not provided
  • Includes standard 15-minute warm-up and 10-minute cool-down
  • Returns a fully constructed workout
Built-in Pace Constants

The WorkoutGeneratorService includes pre-defined pace constants for common training zones:

public static readonly decimal MarathonPace = 4.66m;   // 4:40 min/km
public static readonly decimal HalfMarathonPace = 4.25m; // 4:15 min/km  
public static readonly decimal VMAPace = 3.93m;         // 3:55 min/km
public static readonly decimal EFPace = 6.0m;           // 6:00 min/km (Easy/Recovery)

Models

CustomWorkout

Represents a training plan specification that can be converted into a Garmin workout.

Properties:

  • Id: Unique identifier
  • WeekNumber: Training plan week number
  • RunType: Type of run (see RunType enum)
  • TotalDuration: Total planned duration
  • Repetitions: Number of interval repetitions
  • RunDuration: Duration of each work interval (seconds)
  • CoolDownDuration: Duration of each rest interval (seconds)
  • Pace: Target pace in minutes per kilometer
  • Speed: Target speed (calculated)
  • Description: Human-readable description

RunType Enum

Defines different types of training runs:

public enum RunType
{
    [Description("VMA")]
    Intervals = 1,        // High-intensity intervals
    
    [Description("EF")]
    Easy = 2,            // Easy/endurance pace
    
    [Description("Recovery")]
    Recovery = 4,        // Recovery runs
    
    [Description("Active Recovery")]
    Steady = 8,          // Steady state runs
    
    [Description("Tempo")]
    Tempo = 16,          // Tempo/threshold runs
    
    [Description("Long run")]
    LongRun = 32,        // Long endurance runs
    
    [Description("Race")]
    Race = 64,           // Race pace runs
    
    Other = 128          // Other types
}

Advanced Usage

Custom Author Information

var customAuthor = new Author
{
    UserProfilePk = 12345,
    DisplayName = "CoachAI",
    FullName = "Training Coach",
    UserPro = true,
    VivokidUser = false
};

var workout = builder
    .Reset("Custom Authored Workout")
    .WithAuthor(customAuthor)
    .AddWarmUp(300)
    .Build();

Multi-Sport Workouts

// Currently, the builder focuses on single-sport workouts
// For multi-sport, you would need to create multiple segments manually
var workout = builder
    .Reset("Triathlon Brick Workout")
    .WithSport("cycling")
    .AddWarmUp(600)
    .AddIntervals(3, 1200, 300, 2.5m) // Cycling intervals
    .Build();

// Then create a separate running workout
var runWorkout = builder
    .Reset("Triathlon Run")
    .WithSport("running") 
    .AddIntervals(2, 600, 120, 4.2m) // Running intervals
    .Build();

Pace Calculations

The services automatically handle pace conversions from minutes/km to meters/second for Garmin compatibility:

// Input: 4:00 min/km pace with ±0:15 tolerance
// Automatically converts to:
// - Low target: ~4.17 m/s (3:45 min/km)
// - High target: ~3.85 m/s (4:15 min/km)

var workout = builder
    .AddIntervals(5, 300, 180, 4.0m, 0.25m) // 4:00 ± 0:15
    .Build();

Logging Integration

The generator service provides detailed logging for troubleshooting:

// Configure logging to see generation details
services.AddLogging(builder => 
{
    builder.AddConsole();
    builder.SetMinimumLevel(LogLevel.Information);
});

// Logs will include:
// - Workout generation parameters
// - Calculation results
// - Warning for edge cases (e.g., zero repetitions)

Requirements

  • .NET 9.0 or higher
  • GarminRunerz.Workout.Models package
  • Microsoft.Extensions.DependencyInjection.Abstractions
  • Microsoft.Extensions.Logging.Abstractions

Best Practices

1. Use Dependency Injection

Always register services in your DI container rather than creating instances manually:

// ✅ Good
services.AddScoped<IWorkoutBuilder, WorkoutBuilder>();
var builder = serviceProvider.GetRequiredService<IWorkoutBuilder>();

// ❌ Avoid
var builder = new WorkoutBuilder();

2. Reset Builder Between Workouts

The WorkoutBuilder is stateful. Always call Reset() when starting a new workout:

// ✅ Good
var workout1 = builder.Reset("Workout 1").AddWarmUp(300).Build();
var workout2 = builder.Reset("Workout 2").AddWarmUp(600).Build();

// ❌ Problematic - state carries over
var workout1 = builder.AddWarmUp(300).Build();
var workout2 = builder.AddWarmUp(600).Build(); // Contains both warm-ups

3. Validate Input Data

Always validate CustomWorkout data before generating:

if (customWorkout.Repetitions <= 0)
{
    throw new ArgumentException("Repetitions must be positive");
}

if (customWorkout.Pace <= 0)
{
    throw new ArgumentException("Pace must be positive");
}

4. Use Built-in Pace Constants

Leverage the pre-defined pace constants for consistency:

// ✅ Good - uses built-in constant
var workout = generator.GenerateWorkoutsFromPlanning(new CustomWorkout
{
    Pace = WorkoutGeneratorService.VMAPace,
    // ... other properties
});

// ✅ Also good - custom pace with explanation
var workout = generator.GenerateWorkoutsFromPlanning(new CustomWorkout
{
    Pace = 3.75m, // Custom race pace
    // ... other properties
});

Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.

License

This project is open source. Please refer to the license file for more information.

  • GarminRunerz.Workout.Models - Core data models for Garmin workouts
  • Other libraries in the GarminRunerz ecosystem for working with Garmin fitness data
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 2 9/16/2025

Initial release of GarminRunerz.Workout.Services with fluent workout builder and intelligent workout generation capabilities.