Skip to main content

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:

  1. "GSF.CarbonAware"
  2. "CarbonAware"
  3. "CarbonAware.DataSources.ElectricityMapsFree"
  4. "CarbonAware.DataSources.ElectricityMaps"
  5. "CarbonAware.DataSources.Json"
  6. "CarbonAware.DataSources.Registration"
  7. "CarbonAware.DataSources.WattTime"
  8. "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

  1. create_packages.ps1 <dotnet_solution> <package_destination>
  2. 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 -