MikkoAu.FlexLoadOptimizer
0.1.2
dotnet add package MikkoAu.FlexLoadOptimizer --version 0.1.2
NuGet\Install-Package MikkoAu.FlexLoadOptimizer -Version 0.1.2
<PackageReference Include="MikkoAu.FlexLoadOptimizer" Version="0.1.2" />
<PackageVersion Include="MikkoAu.FlexLoadOptimizer" Version="0.1.2" />
<PackageReference Include="MikkoAu.FlexLoadOptimizer" />
paket add MikkoAu.FlexLoadOptimizer --version 0.1.2
#r "nuget: MikkoAu.FlexLoadOptimizer, 0.1.2"
#:package MikkoAu.FlexLoadOptimizer@0.1.2
#addin nuget:?package=MikkoAu.FlexLoadOptimizer&version=0.1.2
#tool nuget:?package=MikkoAu.FlexLoadOptimizer&version=0.1.2
MikkoAu.FlexLoadOptimizer
Constraint-based optimizer for scheduling cyclic loads over time-slotted electricity prices.
Instead of naively picking the cheapest N price slots, FlexLoadOptimizer uses the Google OR-Tools CP-SAT solver (a constraint programming solver) to find the cost-minimizing schedule while respecting real-world operating constraints:
- Minimum run duration: e.g. a heat pump compressor must run for at least 1 hour to avoid short-cycling, which wastes energy and causes mechanical wear
- Minimum rest duration: mandatory off time between runs to prevent too-frequent stop/start cycles, which cause excess wear on motors and compressors
- Maximum off duration: ensures the load doesn't stay off too long, e.g. a house cooling down, a boiler losing heat, or a process requiring periodic operation
Use cases: heat pumps, boilers, water heaters, pool pumps, industrial compressors, or anything with cyclic on/off behaviour where minimum run and rest durations must be respected.
Price Slot Granularity
A price slot is whatever time interval your price data uses; the library makes no assumption about slot length. European day-ahead spot markets (e.g. Nord Pool) publish 15-minute prices, making 96 slots the typical full-day input. Hourly prices (24 slots/day) work equally well, as do weekly schedules or any other granularity. All constraints (SlotsOn, MinContinuousSlotsOn, etc.) are expressed in slot counts, so you scale them to match your interval.
Installation
dotnet add package MikkoAu.FlexLoadOptimizer
Quick Start
using MikkoAu.FlexLoadOptimizer;
// 15-minute slot prices, one per slot (European spot market standard).
// Normal day: 96 slots. DST change days: 92 (spring) or 100 (autumn).
double[] prices = [ /* 96 values for a standard day */ ];
var optimizer = new FlexLoadOptimizer();
var result = optimizer.Optimize(new OptimizerSettings(
SlotPrices: prices,
SlotsOn: 46, // total slots ON (46 × 15 min = 11 h 30 min)
MinContinuousSlotsOn: 3, // minimum run ( 3 × 15 min = 45 min)
MinContinuousSlotsOff: 6, // minimum rest ( 6 × 15 min = 90 min)
MaxContinuousSlotsOff: 16 // max gap (16 × 15 min = 4 h)
));
if (result.Status is OptimizationStatus.Optimal or OptimizationStatus.Feasible)
{
Console.WriteLine($"Avg price selected: {result.Stats.AveragePriceSelectedSlots:F3} c/kWh");
Console.WriteLine($"Savings vs average: {result.Stats.SavingsVsAveragePercent:F1}%");
for (var i = 0; i < result.SlotsOn.Count; i++)
Console.WriteLine($"Slot {i:00} {TimeSpan.FromMinutes(i * 15):h\\:mm}: {(result.SlotsOn[i] ? "ON" : "OFF")}");
}
OptimizerSettings
| Parameter | Description |
|---|---|
SlotPrices |
Price per slot (any consistent unit, e.g. c/kWh). One value per time interval. 15-minute slots give 96 values/day, hourly slots give 24 values/day. |
SlotsOn |
Total ON slots required |
MinContinuousSlotsOn |
Minimum run length per ON period |
MinContinuousSlotsOff |
Minimum rest between ON periods |
MaxContinuousSlotsOff |
Maximum consecutive OFF slots |
FixedInitialSlotCount |
Lock first N slots to a known state |
FixedInitialSlotState |
State for locked initial slots |
Hints |
Warm-start for solver (true = ON slot); e.g. cheapest slots or a previous result (most effective when parameters are similar) |
MaxSolveSeconds |
Solver time budget (default: 10 s) |
OptimizationStatus
| Value | Meaning |
|---|---|
Optimal |
Proven best solution |
Feasible |
Valid schedule found, time limit hit before proving optimality |
Infeasible |
Constraints cannot be satisfied |
Unknown |
Solver error |
Demo
Run the Blazor demo locally:
dotnet run --project demo/MikkoAu.FlexLoadOptimizer.Demo
Opens at https://localhost:5001. Supports live spot price feeds and manual price input.
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. 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. |
-
net8.0
- Google.OrTools (>= 9.14.6206)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.2 | 92 | 5/18/2026 |
| 0.1.1 | 93 | 5/18/2026 |
| 0.1.1-preview.1 | 52 | 5/18/2026 |
| 0.1.0 | 93 | 5/17/2026 |
| 0.1.0-preview.1 | 47 | 5/17/2026 |