From 6c51473d4e76af0e5f3b60303c89ee4409cf7626 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Fri, 31 Jan 2025 18:38:57 +0900 Subject: [PATCH] Support co2_aoer in WattTime Signed-off-by: Yasumasa Suenaga --- .../docs/tutorial-extras/configuration.md | 18 +++++++++++++++++- .../src/Client/WattTimeClient.cs | 10 +++++----- .../ServiceCollectionExtensions.cs | 11 ++++++----- .../WattTimeClientConfiguration.cs | 6 ++++++ .../src/Constants/SignalTypes.cs | 5 +++-- .../test/Client/WattTimeClientTests.cs | 2 +- .../test/Client/WattTimeTestData.cs | 8 ++++---- .../test/WattTimeDataSourceTests.cs | 8 ++++---- 8 files changed, 46 insertions(+), 22 deletions(-) diff --git a/casdk-docs/docs/tutorial-extras/configuration.md b/casdk-docs/docs/tutorial-extras/configuration.md index 416dce2ed..61bfe2c92 100644 --- a/casdk-docs/docs/tutorial-extras/configuration.md +++ b/casdk-docs/docs/tutorial-extras/configuration.md @@ -9,6 +9,7 @@ - [baseUrl](#baseurl) - [Proxy](#proxy) - [WattTime Caching BalancingAuthority](#watttime-caching-balancingauthority) + - [SignalType](#signaltype) - [Json Configuration](#json-configuration) - [ElectricityMaps Configuration](#electricitymaps-configuration) - [API Token Header](#api-token-header) @@ -111,7 +112,8 @@ data provider must also be supplied. "url": "http://10.10.10.1", "username": "proxyUsername", "password": "proxyPassword" - } + }, + "SignalType": "co2_aoer" }, "ElectricityMaps": { "Type": "ElectricityMaps", @@ -187,6 +189,20 @@ recommends not caching for longer than 1 month. DataSources__Configurations__WattTime__BalancingAuthorityCacheTTL="90" ``` +#### SignalType + +WattTime supports 2 signal type. They can be set as a parameter. + +* `co2_moer`: Marginal operating emissions rate +* `co2_aoer`: Average operating emissions rate + +If values other than these are set, an error occurs. +See [WattTime documentation](https://watttime.org/data-science/data-signals/) for details. + +```bash +DataSources__Configurations__WattTime__SignalType=co2_aoer +``` + ### Json Configuration By setting diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/WattTimeClient.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/WattTimeClient.cs index 3dba1c647..5f4abdf8a 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/WattTimeClient.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Client/WattTimeClient.cs @@ -64,7 +64,7 @@ public async Task GetDataAsync(string regionAbbreviat { QueryStrings.Region, regionAbbreviation }, { QueryStrings.StartTime, startTime.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) }, { QueryStrings.EndTime, endTime.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) }, - { QueryStrings.SignalType, SignalTypes.co2_moer}, + { QueryStrings.SignalType, _configuration.SignalType.ToString()}, }; var tags = new Dictionary() @@ -93,7 +93,7 @@ public async Task GetCurrentForecastAsync(string var parameters = new Dictionary() { { QueryStrings.Region, region }, - { QueryStrings.SignalType, SignalTypes.co2_moer } + { QueryStrings.SignalType, _configuration.SignalType.ToString() } }; var tags = new Dictionary() @@ -124,7 +124,7 @@ public Task GetCurrentForecastAsync(RegionRespons { QueryStrings.Region, region }, { QueryStrings.StartTime, requestedAt.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) }, { QueryStrings.EndTime, requestedAt.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) }, - { QueryStrings.SignalType, SignalTypes.co2_moer } + { QueryStrings.SignalType, _configuration.SignalType.ToString() } }; var tags = new Dictionary() @@ -302,14 +302,14 @@ private async Task GetRegionFromCacheAsync(string latitude, stri { { QueryStrings.Latitude, latitude }, { QueryStrings.Longitude, longitude }, - { QueryStrings.SignalType, SignalTypes.co2_moer} + { QueryStrings.SignalType, _configuration.SignalType.ToString()} }; var tags = new Dictionary() { { QueryStrings.Latitude, latitude }, { QueryStrings.Longitude, longitude }, - { QueryStrings.SignalType, SignalTypes.co2_moer } + { QueryStrings.SignalType, _configuration.SignalType.ToString() } }; var result = await this.MakeRequestGetStreamAsync(Paths.RegionFromLocation, parameters, tags); var regionResponse = await JsonSerializer.DeserializeAsync(result, _options) ?? throw new WattTimeClientException($"Error getting Region for latitude {latitude} and longitude {longitude}"); diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/ServiceCollectionExtensions.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/ServiceCollectionExtensions.cs index d05f1a33a..39c025b5d 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/ServiceCollectionExtensions.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/ServiceCollectionExtensions.cs @@ -1,5 +1,6 @@ using CarbonAware.Configuration; using CarbonAware.DataSources.WattTime.Client; +using CarbonAware.DataSources.WattTime.Constants; using CarbonAware.Exceptions; using CarbonAware.Interfaces; using Microsoft.Extensions.Configuration; @@ -24,7 +25,7 @@ public static IServiceCollection AddWattTimeEmissionsDataSource(this IServiceCol services.TryAddSingleton(); return services; } - + private static void AddDependencies(IServiceCollection services, IConfigurationSection configSection) { AddWattTimeClient(services, configSection); @@ -33,10 +34,10 @@ private static void AddDependencies(IServiceCollection services, IConfigurationS private static void AddWattTimeClient(IServiceCollection services, IConfigurationSection configSection) { - services.Configure(c => - { - configSection.Bind(c); - }); + services.AddOptions() + .Bind(configSection) + .Validate(config => Enum.IsDefined(typeof(SignalTypes), config.SignalType), "Invalid SignalType") + .ValidateOnStart(); var httpClientBuilder = services.AddHttpClient(IWattTimeClient.NamedClient); var authenticationClientBuilder = services.AddHttpClient(IWattTimeClient.NamedAuthenticationClient); diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/WattTimeClientConfiguration.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/WattTimeClientConfiguration.cs index a586523ee..5cc063db0 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/WattTimeClientConfiguration.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Configuration/WattTimeClientConfiguration.cs @@ -1,3 +1,4 @@ +using CarbonAware.DataSources.WattTime.Constants; using CarbonAware.Exceptions; using System.Text; @@ -25,6 +26,11 @@ internal class WattTimeClientConfiguration /// public string BaseUrl { get; set; } = "https://api.watttime.org/v3/"; + /// + /// Gets or sets the signal type to use: co2_moer or co2_aoer + /// + public SignalTypes SignalType { get; set; } = SignalTypes.co2_moer; + /// /// Authentication base url. This changed between v2 and v3 /// to be different to the API base url. diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Constants/SignalTypes.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Constants/SignalTypes.cs index 3ff905da5..11861b9c7 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Constants/SignalTypes.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/src/Constants/SignalTypes.cs @@ -1,6 +1,7 @@ namespace CarbonAware.DataSources.WattTime.Constants; -internal class SignalTypes +internal enum SignalTypes { - public const string co2_moer = "co2_moer"; + co2_moer, + co2_aoer } diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Client/WattTimeClientTests.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Client/WattTimeClientTests.cs index 03557348d..21a448c7e 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Client/WattTimeClientTests.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Client/WattTimeClientTests.cs @@ -313,7 +313,7 @@ public async Task GetRegionAsync_DeserializesExpectedResponse() Assert.IsNotNull(regionResponse); Assert.AreEqual(WattTimeTestData.Constants.Region, regionResponse?.Region); Assert.AreEqual(WattTimeTestData.Constants.RegionFullName, regionResponse?.RegionFullName); - Assert.AreEqual(SignalTypes.co2_moer, regionResponse?.SignalType); + Assert.AreEqual(SignalTypes.co2_moer.ToString(), regionResponse?.SignalType); } [Test] diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Client/WattTimeTestData.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Client/WattTimeTestData.cs index d46143e4f..ff6793221 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Client/WattTimeTestData.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/Client/WattTimeTestData.cs @@ -18,7 +18,7 @@ public class Constants public static DateTime Date = new DateTime(2099, 1, 1, 0, 0, 0); public const float Value = 999.99f; public const string Version = "1.0"; - public const string SignalType = SignalTypes.co2_moer; + public const string SignalType = "co2_moer"; public const int Frequency = 300; } @@ -46,10 +46,10 @@ private static GridEmissionsMetaData _GetGridDataMetaResponse() Model = new GridEmissionsModelData() { Date = Constants.Date, - Type = SignalTypes.co2_moer + Type = "co2_moer" }, DataPointPeriodSeconds = 30, - SignalType = SignalTypes.co2_moer, + SignalType = "co2_moer", Units = "co2_moer" }; @@ -122,7 +122,7 @@ private static RegionResponse _GetRegion() { Region = Constants.Region, RegionFullName = Constants.RegionFullName, - SignalType = SignalTypes.co2_moer + SignalType = "co2_moer" }; } } \ No newline at end of file diff --git a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/WattTimeDataSourceTests.cs b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/WattTimeDataSourceTests.cs index 8675ee4da..b4014ab90 100644 --- a/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/WattTimeDataSourceTests.cs +++ b/src/CarbonAware.DataSources/CarbonAware.DataSources.WattTime/test/WattTimeDataSourceTests.cs @@ -48,7 +48,7 @@ public void Setup() this.DataSource = new WattTimeDataSource(this.Logger.Object, this.WattTimeClient.Object, this.LocationSource.Object); this.DefaultLocation = new Location() { Name = "eastus" }; - this.DefaultRegion = new RegionResponse() { Region = "TEST_REGION", RegionFullName = "Test Region Full Name", SignalType = SignalTypes.co2_moer }; + this.DefaultRegion = new RegionResponse() { Region = "TEST_REGION", RegionFullName = "Test Region Full Name", SignalType = "co2_moer" }; this.DefaultDataStartTime = new DateTimeOffset(2022, 4, 18, 12, 32, 42, TimeSpan.FromHours(-6)); MockRegionLocationMapping(); } @@ -297,7 +297,7 @@ private GridEmissionsDataResponse GenerateGridEmissionsResponse(int numberOfData var meta = new GridEmissionsMetaData() { Region = this.DefaultRegion.Region, - SignalType = SignalTypes.co2_moer + SignalType = "co2_moer" }; var response = new GridEmissionsDataResponse() @@ -315,7 +315,7 @@ private HistoricalForecastEmissionsDataResponse GenerateHistoricalForecastRespon var meta = new GridEmissionsMetaData() { Region = this.DefaultRegion.Region, - SignalType = SignalTypes.co2_moer + SignalType = "co2_moer" }; var response = new HistoricalForecastEmissionsDataResponse() @@ -340,7 +340,7 @@ private ForecastEmissionsDataResponse GenerateForecastResponse(int numberOfDatap var meta = new GridEmissionsMetaData() { Region = this.DefaultRegion.Region, - SignalType = SignalTypes.co2_moer + SignalType = "co2_moer" }; var response = new ForecastEmissionsDataResponse()