Packaging the Carbon Aware SDK
With the addition of the C# Client Library as a way to consume the Carbon Aware SDK, we have also added powershell scripts to package the library, and have included a sample Console App showing how the package can be consumed.
Included Projects
The current package include 8 projects from the SDK:
- "GSF.CarbonAware"
- "CarbonAware"
- "CarbonAware.DataSources.ElectricityMapsFree"
- "CarbonAware.DataSources.ElectricityMaps"
- "CarbonAware.DataSources.Json"
- "CarbonAware.DataSources.Registration"
- "CarbonAware.DataSources.WattTime"
- "CarbonAware.LocationSources"
These 8 projects enable users of the library to consume the current endpoints
exposed by the library. The package that needs to be added to a new C# project
is GSF.CarbonAware
.
Included Scripts
There are 2 scripts included to help the packaging process
create_packages.ps1 <dotnet_solution> <package_destination>
add_packages.ps1 <dotnet_project> <package_destination>
The create_packages
script is called
with 2 parameters: the CarbonAwareSDK dotnet solution file (.sln
) path, and
the output directory destination for the package. The
add_packages
script is also called with
2 parameters: the target project file (.csproj
) path, and the package
destination path.
To see a working example of both scripts being invoked, you can look at the github action detailed in build-packages.yaml.
Running the packaging scripts
The packaging scripts can be run inside a VS Code dev container defined in this project. When running in the dev container you will need:
Alternatively you can run in your local environment using the .NET Core 8.0 SDK.
SDK Configuration
The configuration needed to connect to WattTime, ElectricityMaps, ElectricityMapsFree, or Json data sources can be managed using environment variables or appsettings. More information on data source configuration can be found here
ElectricityMapsFree
Below are the environment variables needed to set up the ElectricityMapsFree data source.
export DataSources__EmissionsDataSource=ElectricityMapsFree
export DataSources__Configurations__ElectricityMapsFree__Type=ElectricityMapsFree
export DataSources__Configurations__ElectricityMapsFree__token=[ElectricityMapsFree APIToken]`
ElectricityMaps
Below are the environment variables needed to set up the ElectricityMaps data source.
export DataSources__ForecastDataSource=ElectricityMaps
export DataSources__Configurations__ElectricityMaps__Type=ElectricityMaps
export DataSources__Configurations__ElectricityMaps__APITokenHeader=[ElectricityMaps APITokenHeader]
export DataSources__Configurations__ElectricityMaps__APIToken=[ElectricityMaps APIToken]`
WattTime
Below are the environment variables needed to set up the WattTime data source.
export DataSources__EmissionsDataSource=WattTime`
export DataSources__ForecastDataSource=WattTime`
export DataSources__Configurations__WattTime__Type=WattTime`
export DataSources__Configurations__WattTime__Username=[WattTime Username]`
export DataSources__Configurations__WattTime__Password=[WattTime Password]`
export DataSources__Configurations__WattTime__BaseURL="https://api2.watttime.org/v2/"`
Json
Below is the environment variable needed to set up the Json data source.
export DataSources__EmissionsDataSource=Json`
export DataSources__Configurations__Json__Type=Json`
export DataSources__Configurations__Json__DataFileLocation="test-data-azure-emissions.json"`
Use Package with Dependency Injection
In order to get access to the handlers in the library, a common practice with C# is through Microsoft.Extensions.DependencyInjection
extensions. This way the whole life cycle of the handler instance is managed by the container’s framework, and it would help to isolate the concrete implementation from the user facing interface. For instance, a consumer would be able to call extensions as:
// Using DI Services (Emissions) to register GSF SDK library
services.AddEmissionsServices(configuration);
// An application Consumer construct should inject a GSF handler like the following example
class ConsumerClass(IEmissionsHandler handler, ILogger<ConsumerClass> logger)
{
....
this._handler = handler;
this._logger = logger;
....
}
And the usage of a method for IEmissionsHandler
async Task<double> GetRating()
{
...
return await this._handler.GetAverageCarbonIntensity(…);
}
Another functionality of the application could just do Forecast data. So, it would be a matter of following the same pattern:
// Using DI Services (Forecast) to register GSF SDK library
services.AddForecastServices(configuration);
class ForecastApp(IForecastHandler handler)
{
...
this._handler = handler;
}
And the usage of a method for IForecastHandler:
async Task<EmissionsData> GetOptimal(…)
{
...
return await this._handler.GetCurrentAsync()...).OptimalDataPoints.First();
}
This way it would fit within the same stack as the rest of the SDK is implemented. Also, it would be easier to integrate later when the current consumers (CLI/WebApi) should be moved to use the library.
Console App Sample
There is a sample console app in the lib integration folder to demonstrate package creation and interaction with Carbon Aware SDK.
Run the Sample Console App
In order to build and run the app, all the dependent packages need to be created first and then imported in the app. Follow the steps below to run the sample console app -
- Run the script commands to create the packages and add them into the app.
- Create the environment variables to connect to the WattTime or Json data sources.