Skip to content

Watt Time v3 Support #532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b9490e4
First draft of the ADR for watt time v3 changes
vaughanknight May 7, 2024
b991bac
Moved ADR to correct location
vaughanknight May 8, 2024
f4bbf52
Further updates for the watt time v2 to v3 upgrade
vaughanknight May 8, 2024
d6ad67c
Further updates for the watt time v2 to v3 upgrade
vaughanknight May 8, 2024
15a6f9c
Merge branch 'wattime-v3-support' of https://github.com/Green-Softwar…
vaughanknight May 8, 2024
cb46877
Update 0016-watt-time-v3.md
vaughanknight May 15, 2024
e324f36
First draft of the ADR for watt time v3 changes
vaughanknight May 7, 2024
be6663c
Moved ADR to correct location
vaughanknight May 8, 2024
17210ed
Further updates for the watt time v2 to v3 upgrade
vaughanknight May 8, 2024
7920786
Update 0016-watt-time-v3.md
vaughanknight May 15, 2024
e4f1494
Create 0016-watt-time-v3.md
vaughanknight May 31, 2024
b443e9e
Added base url to the configuration with validation
vaughanknight May 31, 2024
ab1205d
Updated start and end configuration
vaughanknight May 31, 2024
7c115fa
Balancing Authority Parameter Renamed to Region
vaughanknight May 31, 2024
e047c9a
Updates for historical data API
vaughanknight Jun 17, 2024
aa81382
Removed accidental file
vaughanknight Jun 17, 2024
8640c8c
Lots of test updates
vaughanknight Jun 17, 2024
880fcf7
Historical forecasts updated
vaughanknight Jun 17, 2024
92f8dbc
DCO Remediation Commit for Vaughan Knight <[email protected]>
vaughanknight Jun 17, 2024
39e45a6
Many tests reworked, a few to go
vaughanknight Jun 18, 2024
fbfcac1
Further test updates
vaughanknight Jun 18, 2024
0080ae8
Merge branch 'wattime-v3-support' of https://github.com/Green-Softwar…
vaughanknight Jun 18, 2024
f3fd570
Merge branch 'wattime-v3-support' of https://github.com/Green-Softwar…
vaughanknight Jun 18, 2024
9aabd27
Further updates, just 1 test left to remediate
vaughanknight Jun 18, 2024
8127a92
Updated to add authentication client to the service builder for the t…
vaughanknight Jun 18, 2024
4ff0151
Renaming of Balancing Authority to Region
vaughanknight Jun 18, 2024
d93320f
Fixed spelling error in latitude
vaughanknight Jun 18, 2024
91799f7
Fixed a bug where location sources were loading twice
vaughanknight Jun 19, 2024
4665813
Fixed typo for method name
vaughanknight Jun 19, 2024
b228cf7
DCO Remediation Commit for Vaughan Knight <[email protected]>
vaughanknight Jun 19, 2024
8137659
Updates based on code review for WattTime Tests
vaughanknight Jun 19, 2024
f64ec8e
Cleaned up a lot of the string literals
vaughanknight Jun 19, 2024
daa4503
More cleanup of some of the strings
vaughanknight Jun 20, 2024
903a58f
Updates to documentation and changelog
vaughanknight Jun 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions casdk-docs/docs/architecture/decisions/0016-watt-time-v3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

# 0015. WattTime v3 Changes

## Status

Proposed

## Context
As part of the update to Watt Time v3 we are proposing the changes to the underlying API calls. This needs to be tracked so we understand the impacts, and if multiple options are available, which option was selected and why.

This wll impact the `CarbonAware.DataSources.WattTime` project primarily.

## Decision

The proposal is for the outlined WattTime API mapping and changes.

## WattTime v2, v3 Mapping

The following document and guidelines was used to understand the impact to the Carbon Aware SDK for the WattTime v3 updates. https://docs.watttime.org/#tag/Transitioning-from-APIv2-to-APIv3

### Base URL
The base URL will need to change.
> TODO: Add where this is configured

|Base URL (v2) | Based URL (v3) |
|---|---|
| /v2 | /v3 |


### Paths
The paths will also need to change.

The following is configured at `CarbonAware.DataSources.WattTime/src/Constants/Paths.cs`

| API Endpoint | Description | Path (v2) | Path (v3) | Notes |
|--------------|-------------|-----------|-----------|---|
| Data | Get data | /data | /historical | _Request_ <li> `starttime` is now `start` and mandatory <li> `endtime` is now `end` and mandatory <li> `ba` is now `region` <li> `signal_type` added <br> _Response_ <li> `signal_type` added
| Forecast | Get forecast| /forecast | /forecast | **TODO: CHECK IMPACT** <br> No longer be used for historical data <br> _Request_ <li> `ba` is now `region` <li> `extended_forecast` removed <li> `horizon_hours` added <li> `signal_type` added <li> Historical forecasts are now at `/forecast/historical` <br> _Response_ <li> `signal_type` added
| Historical | Get historical forecast data | /historical (?) | /forecast/historical (?) | **We need to validate why historical was being used for the API, and what historical used to be, and whether this should be the new /forecast/historical or not.**
| Balancing Authority From Location | Get balancing authority from location | /ba-from-loc | /region-from-loc | Check if the CA SDK uses BA at all <br><br> _Request_ <li> `name` is now `region_full_name` <li> `abbrev` is now `region` <li> `signal_type` added <br> _Response_ <li> `id` removed <li> `signal_type` added |
| Login | User login | https://api2.watttime.org/v2/login | https://api.watttime.org/login | Path has changed from being version specific to being no longer related to the API version. <br><br> NOTE: Updated in wattTime client to now have 2 HTTP clients to decouple versions from the login.

### Query Strings

#### Signal Type
Everything call takes an optional `signal_type` parameter that defaults to `co2_moer`.

The following comes from `CarbonAware.DataSources.WattTime/src/Constants/QueryStrings.cs` and the changes are consistent with the discussion above.

| Query String (v2) | Query String if Changed (v3) | Description |
|------------------------------------|----------------------------------|------------------------------|
| `ba` | `region` | Balancing Authority / Region |
| `starttime` | `start` | Start Time |
| `endtime` | `end` | End Time |
| `latitude` | - | Latitude |
| `longitude` | - | Longitude |
| `username` | - | Username |

## Green Impact

Neutral

Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public async Task EmissionsForecasts_RequestedAtOptions_ReturnsExpectedData()
IgnoreTestForDataSource("data source does not implement '--requested-at'", DataSourceType.ElectricityMaps);

// Arrange
_dataSourceMocker.SetupBatchForecastMock();
_dataSourceMocker.SetupHistoricalBatchForecastMock();

// Act
var exitCode = await InvokeCliAsync($"emissions-forecasts -l eastus -r 2022-09-01");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public void SetupDataMock(DateTimeOffset start, DateTimeOffset end, string locat
SetupResponseGivenGetRequest(Paths.PastRange, pastRange);
}

public void SetupBatchForecastMock()
public void SetupHistoricalBatchForecastMock()
{
throw new NotImplementedException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ private static EmissionsForecast ToEmissionsForecast(Location location, Forecast
}

/// <inheritdoc />
public async Task<EmissionsForecast> GetCarbonIntensityForecastAsync(Location location, DateTimeOffset requestedAt)
public async Task<EmissionsForecast> GetHistoricalCarbonIntensityForecastAsync(Location location, DateTimeOffset requestedAt)
{
await Task.Run(() => true);
throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public void SetupForecastMock()
throw new NotImplementedException();
}

public void SetupBatchForecastMock()
public void SetupHistoricalBatchForecastMock()
{
throw new NotImplementedException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void Initialize() { }
public void Reset() { }
public void Dispose() { }

public void SetupBatchForecastMock()
public void SetupHistoricalBatchForecastMock()
{
throw new NotImplementedException();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using CarbonAware.Interfaces;
using CarbonAware.DataSources.WattTime.Constants;
using CarbonAware.DataSources.WattTime.Constants;
using CarbonAware.DataSources.WattTime.Model;
using CarbonAware.Interfaces;
using System.Net;
using System.Net.Mime;
using System.Text.Json;
Expand All @@ -13,11 +13,11 @@ internal class WattTimeDataSourceMocker : IDataSourceMocker
{
protected WireMockServer _server;

private static readonly BalancingAuthority defaultBalancingAuthority = new()
private static readonly RegionResponse defaultRegion = new()
{
Id = 12345,
Abbreviation = "TEST_BA",
Name = "Test Balancing Authority"
Region = "TEST_REGION",
RegionFullName = "Test Region Full Name",
SignalType = SignalTypes.co2_moer
};

private static readonly LoginResult defaultLoginResult = new() { Token = "myDefaultToken123" };
Expand All @@ -26,6 +26,8 @@ public WattTimeDataSourceMocker()
{
_server = WireMockServer.Start();
Environment.SetEnvironmentVariable("DataSources__Configurations__WattTime__BaseURL", _server.Url!);
Environment.SetEnvironmentVariable("DataSources__Configurations__WattTime__AuthenticationBaseUrl", _server.Url!);

Initialize();
}

Expand All @@ -39,20 +41,31 @@ public void SetupDataMock(DateTimeOffset start, DateTimeOffset end, string locat
{
var newDataPoint = new GridEmissionDataPoint()
{
BalancingAuthorityAbbreviation = defaultBalancingAuthority.Abbreviation,
PointTime = pointTime,
Value = 999.99F,
Version = "1.0",
Datatype = "dt",
Frequency = 300,
Market = "mkt",
};


data.Add(newDataPoint);
pointTime = newDataPoint.PointTime + duration;
}

SetupResponseGivenGetRequest(Paths.Data, JsonSerializer.Serialize(data));
var meta = new GridEmissionsMetaData()
{
Region = defaultRegion.Region,
SignalType = SignalTypes.co2_moer
};

var gridEmissionsResponse = new GridEmissionsDataResponse()
{
Data = data,
Meta = meta
};

SetupResponseGivenGetRequest(Paths.Data, JsonSerializer.Serialize(gridEmissionsResponse));
}

public void SetupForecastMock()
Expand All @@ -63,15 +76,13 @@ public void SetupForecastMock()
var start = new DateTimeOffset(((curr.Ticks + d.Ticks - 1) / d.Ticks) * d.Ticks, TimeSpan.Zero);
var end = start + TimeSpan.FromDays(1.0);
var pointTime = start;
var ForecastData = new List<GridEmissionDataPoint>();
var forecastData = new List<GridEmissionDataPoint>();
var currValue = 200.0F;

while (pointTime < end)
{
var newForecastPoint = new GridEmissionDataPoint()
{
BalancingAuthorityAbbreviation = defaultBalancingAuthority.Abbreviation,
Datatype = "dt",
Frequency = 300,
Market = "mkt",
PointTime = start,
Expand All @@ -80,32 +91,39 @@ public void SetupForecastMock()
};
newForecastPoint.PointTime = pointTime;
newForecastPoint.Value = currValue;
ForecastData.Add(newForecastPoint);
forecastData.Add(newForecastPoint);
pointTime = pointTime + TimeSpan.FromMinutes(5);
currValue = currValue + 5.0F;
}

var forecast = new Forecast()
var meta = new GridEmissionsMetaData()
{
ForecastData = ForecastData,
Region = defaultRegion.Region,
SignalType = SignalTypes.co2_moer,
GeneratedAt = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero)
};
SetupResponseGivenGetRequest(Paths.Forecast, JsonSerializer.Serialize(forecast));

var forecastResponse = new ForecastEmissionsDataResponse()
{
Data = forecastData,
Meta = meta
};


SetupResponseGivenGetRequest(Paths.Forecast, JsonSerializer.Serialize(forecastResponse));
}

public void SetupBatchForecastMock()
public void SetupHistoricalBatchForecastMock()
{
var start = new DateTimeOffset(2021, 9, 1, 8, 30, 0, TimeSpan.Zero);
var end = start + TimeSpan.FromDays(1.0);
var pointTime = start;
var ForecastData = new List<GridEmissionDataPoint>();
var forecastData = new List<GridEmissionDataPoint>();
var currValue = 200.0F;
while (pointTime < end)
{
var newForecastPoint = new GridEmissionDataPoint()
{
BalancingAuthorityAbbreviation = defaultBalancingAuthority.Abbreviation,
Datatype = "dt",
Frequency = 300,
Market = "mkt",
PointTime = start,
Expand All @@ -114,19 +132,41 @@ public void SetupBatchForecastMock()
};
newForecastPoint.PointTime = pointTime;
newForecastPoint.Value = currValue;
ForecastData.Add(newForecastPoint);
forecastData.Add(newForecastPoint);
pointTime = pointTime + TimeSpan.FromMinutes(5);
currValue = currValue + 5.0F;
}

var forecastData = new List<Forecast> {
new Forecast()
var meta = new GridEmissionsMetaData()
{
Region = defaultRegion.Region,
SignalType = SignalTypes.co2_moer,
GeneratedAt = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero)
};

//var forecastBatchData = new List<ForecastEmissionsDataResponse> {
// new ForecastEmissionsDataResponse()
// {
// Data = forecastData,
// Meta = meta
// }
//};

var historicalForecastResponse = new HistoricalForecastEmissionsDataResponse()
{
Data = new List<HistoricalEmissionsData>()
{
ForecastData = ForecastData,
GeneratedAt = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero)
}
new HistoricalEmissionsData()
{
Forecast = forecastData,
GeneratedAt = new DateTimeOffset(2099, 1, 1, 0, 0, 0, TimeSpan.Zero)
}
},
Meta = meta
};
SetupResponseGivenGetRequest(Paths.Forecast, JsonSerializer.Serialize(forecastData));


SetupResponseGivenGetRequest(Paths.ForecastHistorical, JsonSerializer.Serialize(historicalForecastResponse));
}

public void Initialize()
Expand Down Expand Up @@ -156,8 +196,8 @@ private void SetupResponseGivenGetRequest(string path, string body)
.WithBody(body)
);
}
private void SetupBaMock(BalancingAuthority? content = null) =>
SetupResponseGivenGetRequest(Paths.BalancingAuthorityFromLocation, JsonSerializer.Serialize(content ?? defaultBalancingAuthority));
private void SetupBaMock(RegionResponse? content = null) =>
SetupResponseGivenGetRequest(Paths.RegionFromLocation, JsonSerializer.Serialize(content ?? defaultRegion));

private void SetupLoginMock(LoginResult? content = null) =>
SetupResponseGivenGetRequest(Paths.Login, JsonSerializer.Serialize(content ?? defaultLoginResult));
Expand Down
Loading
Loading