Skip to content

Commit

Permalink
Merge pull request #67 from MattJeanes/add-fixedpriceweekly
Browse files Browse the repository at this point in the history
  • Loading branch information
MattJeanes authored Nov 5, 2024
2 parents 5106f2d + 45b38ad commit b641f64
Show file tree
Hide file tree
Showing 8 changed files with 781 additions and 6 deletions.
6 changes: 6 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"tasks": {
"build": "dotnet build",
"test": "dotnet test"
}
}
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ See below for how to configure the environment variables appropriately
### Fixed Price
The Fixed Price provider allows you to use TeslaMateAgile if you have a fixed price for electricity at different times of the day. This is useful if you have a simple time-of-use tariff that isn't supported by the other providers.
```yaml
- TeslaMate__EnergyProvider=FixedPrice
- FixedPrice__TimeZone=Europe/London # IANA (tz database) time zone code, used for below times
Expand All @@ -71,6 +73,23 @@ See below for how to configure the environment variables appropriately
- FixedPrice__Prices__4=06:00-08:00=0.02
```
### Fixed Price (Weekly)
The Fixed Price Weekly provider is similar to the Fixed Price provider but allows you to set different prices for different days of the week. This is useful if your electricity tariff changes on different days of the week but is consistent week-to-week, e.g. a weekday / weekend tariff.
```yaml
- TeslaMate__EnergyProvider=FixedPriceWeekly
- FixedPriceWeekly__TimeZone=Europe/London # IANA (tz database) time zone code, used for below times
- FixedPriceWeekly__Prices__0=Mon-Wed=08:00-13:00=0.1559 # Cost is in your currency e.g. pounds, euros, dollars (not pennies, cents, etc)
- FixedPriceWeekly__Prices__1=Mon-Wed=13:00-08:00=0.05 # Day(s) of the week can be comma separated or a range (e.g. Mon-Fri or Mon,Wed,Fri)
- FixedPriceWeekly__Prices__6=Thu=0.22 # The time range is optional and will be used for the whole day if unspecified
- FixedPriceWeekly__Prices__3=Fri,Sat=08:00-18:00=0.1559 # You can have as many as these as you need
- FixedPriceWeekly__Prices__4=Fri,Sat=18:00-08:00=0.04
- FixedPriceWeekly__Prices__5=Sun=12:00-18:00=0.1559
- FixedPriceWeekly__Prices__7=Sun=18:00-08:00=0.04
- FixedPriceWeekly__Prices__8=Sun=08:00-12:00=0.1559
```
### aWATTar
```yaml
Expand Down
405 changes: 405 additions & 0 deletions TeslaMateAgile.Tests/Services/FixedPriceWeeklyServiceTests.cs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions TeslaMateAgile/Data/Enums/EnergyProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public enum EnergyProvider
Octopus,
Tibber,
FixedPrice,
FixedPriceWeekly,
Awattar,
Energinet,
HomeAssistant,
Expand Down
12 changes: 12 additions & 0 deletions TeslaMateAgile/Data/Options/FixedPriceWeeklyOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;

namespace TeslaMateAgile.Data.Options;

public class FixedPriceWeeklyOptions
{
[Required]
public string TimeZone { get; set; }

[Required]
public List<string> Prices { get; set; }
}
10 changes: 9 additions & 1 deletion TeslaMateAgile/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ string getDatabaseVariable(string variableName)
}
else
{
throw new ArgumentException(databasePortVariable, $"Configuration '{databasePortVariable}' is invalid, must be an integer");
throw new ArgumentException($"Configuration '{databasePortVariable}' is invalid, must be an integer", databasePortVariable);
}
}

Expand Down Expand Up @@ -125,6 +125,14 @@ string getDatabaseVariable(string variableName)
.ValidateOnStart();
services.AddSingleton<IPriceDataService, FixedPriceService>();
}
else if (energyProvider == EnergyProvider.FixedPriceWeekly)
{
services.AddOptions<FixedPriceWeeklyOptions>()
.Bind(config.GetSection("FixedPriceWeekly"))
.ValidateDataAnnotations()
.ValidateOnStart();
services.AddSingleton<IPriceDataService, FixedPriceWeeklyService>();
}
else if (energyProvider == EnergyProvider.Awattar)
{
services.AddOptions<AwattarOptions>()
Expand Down
10 changes: 5 additions & 5 deletions TeslaMateAgile/Services/FixedPriceService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ public FixedPriceService(
IOptions<FixedPriceOptions> options
)
{
_fixedPrices = GetFixedPrices(options.Value);
if (!TZConvert.TryGetTimeZoneInfo(options.Value.TimeZone, out _timeZone))
{
throw new ArgumentException(nameof(options.Value.TimeZone), $"Invalid TimeZone {options.Value.TimeZone}");
throw new ArgumentException($"Invalid TimeZone {options.Value.TimeZone}", nameof(options.Value.TimeZone));
}
_fixedPrices = GetFixedPrices(options.Value);
}

public Task<IEnumerable<Price>> GetPriceData(DateTimeOffset from, DateTimeOffset to)
Expand Down Expand Up @@ -85,7 +85,7 @@ private List<FixedPrice> GetFixedPrices(FixedPriceOptions options)
foreach (var price in options.Prices.OrderBy(x => x))
{
var match = FixedPriceRegex.Match(price);
if (!match.Success) { throw new ArgumentException(nameof(price), $"Failed to parse fixed price: {price}"); }
if (!match.Success) { throw new ArgumentException($"Failed to parse fixed price: {price}", nameof(price)); }
var fromHour = int.Parse(match.Groups[1].Value);
var fromMinute = int.Parse(match.Groups[2].Value);
var toHour = int.Parse(match.Groups[3].Value);
Expand Down Expand Up @@ -113,14 +113,14 @@ private List<FixedPrice> GetFixedPrices(FixedPriceOptions options)

if (lastFixedPrice != null && (fixedPrice.FromHour != lastFixedPrice.ToHour || fixedPrice.FromMinute != lastFixedPrice.ToMinute))
{
throw new ArgumentException(nameof(price), $"Price from time does not match previous to time: {price}");
throw new ArgumentException($"Price from time does not match previous to time: {price}", nameof(price));
}
totalHours += toHours - fromHours;
lastFixedPrice = fixedPrice;
}
if (totalHours != 24)
{
throw new ArgumentException(nameof(totalHours), $"Total hours do not equal 24, currently {totalHours}");
throw new ArgumentException($"Total hours do not equal 24, currently {totalHours}", nameof(totalHours));
}
return fixedPrices;
}
Expand Down
Loading

0 comments on commit b641f64

Please sign in to comment.