@greenweb/grid-aware-websites
Version:
A library to enable developers to implement grid awareness in their websites
192 lines (170 loc) • 5.94 kB
JavaScript
import { getGridIntensity as electricityMapsGridIntensity } from "./providers/electricity-maps/index.js";
import { averageIntensity } from "@tgwf/co2";
import { codes } from "../utils/countryCodes.js";
import { acceptedProvider } from "./helpers.js";
/**
* @typedef {Object} GridIntensityOptions Configuration options for GridIntensity
* @property {("level"|"average"|"limit")} [mode="level"] - The mode to use for grid intensity checks
* @property {number} [minimumIntensity=400] - The minimum intensity threshold in gCO2/kWh
* @property {string} [dataProvider="electricityMaps"] - The data provider to use
* @property {string} [apiKey] - The API key for the data provider
*/
/**
* Fetch the grid intensity data from the specified provider.
* @param {string|{lat: string, lon: string}} zone The zone for which to fetch the data.
* @param {string} apiKey The API key for the provider.
* @param {string} provider The data provider to use.
* @param {"level"|"average"|"limit"} mode The mode to use for grid intensity checks.
* @returns {Promise<object>} The grid intensity data.
*/
async function fetchByProvider(zone, apiKey, provider, mode) {
switch (provider) {
case "electricityMaps":
return electricityMapsGridIntensity(zone, mode, apiKey);
default:
return {
status: "error",
message: "Invalid data provider",
};
}
}
/**
* A class for checking the grid intensity of a specified zone.
* @class
* @param {GridIntensityOptions} Configuration options
* @throws {Error} An error is thrown if the mode is invalid.
* @throws {Error} An error is thrown if the minimum intensity is not a number.
* @throws {Error} An error is thrown if the data provider is invalid.
*/
class GridIntensity {
constructor(options = {}) {
this.mode = options.mode || "level";
this.dataProvider = options.dataProvider || "electricityMaps";
this.apiKey = options.apiKey || null;
if (this.mode === "limit") {
this.minimumIntensity = options.minimumIntensity || 400;
}
if (options) {
this.setOptions(options);
}
}
/**
* Set the mode for grid intensity checks.
* @param {("level"|"average"|"limit")} mode The mode to use for grid intensity checks.
* @throws {Error} An error is thrown if the mode is not 'average' or 'limit'.
*/
setMode(mode) {
const validModes = ["level", "average", "limit"];
if (!validModes.includes(mode)) {
throw new Error("Invalid mode. Mode must be 'average' or 'limit'.");
}
this.mode = mode;
}
/**
* Set the minimum intensity threshold for grid intensity checks.
* @param {number} minimumIntensity The minimum intensity threshold in gCO2/kWh.
* @throws {Error} An error is thrown if the minimum intensity is not a number.
*/
setMinimumIntensity(minimumIntensity) {
if (isNaN(minimumIntensity)) {
throw new Error(
"Invalid minimumIntensity. minimumIntensity must be a number.",
);
}
this.minimumIntensity = minimumIntensity;
}
/**
* Set the data provider for fetching grid intensity data.
* @param {string} dataProvider The data provider to use.
* @throws {Error} An error is thrown if the data provider is invalid.
*/
setDataProvider(dataProvider) {
if (!acceptedProvider.includes(dataProvider)) {
throw new Error(
`Invalid dataProvider. Data provider must be one of ${acceptedProvider.join(", ")}.`,
);
}
this.dataProvider = dataProvider;
}
/**
* Set the configuration options for the GridIntensity class.
* @param {GridIntensityOptions} options Configuration options for GridIntensity
* @throws {Error} An error is thrown if the mode is invalid.
* @throws {Error} An error is thrown if the minimum intensity is not a number.
* @throws {Error} An error is thrown if the data provider is invalid.
* @returns {void}
*/
setOptions(options) {
if (options.mode) {
this.setMode(options.mode);
}
if (options.minimumIntensity) {
this.setMinimumIntensity(options.minimumIntensity);
}
if (options.dataProvider) {
this.setDataProvider(options.dataProvider);
}
}
/**
* Check the grid intensity of the specified zone.
* @param {string|{lat: string, lon: string}} zone The zone for which to check the grid intensity.
* @returns {Promise<object>} The results of grid-awareness check based on grid intensity and specified mode.
*/
async check(zone) {
const response = await fetchByProvider(
zone,
this.apiKey,
this.dataProvider,
this.mode,
);
if (response.status === "error") {
return response;
}
const { data } = response;
let gridAware = false;
if (this.mode === "level") {
return {
status: "success",
region: data.region,
level: data.data[0].level,
data: {
mode: this.mode,
datetime: data.data[0].datetime,
},
};
} else if (this.mode === "average") {
const zoneCode = codes.find(
(code) => code.alpha2Code === data.region,
)?.alpha3Code;
const zoneAverageIntensity = averageIntensity.data[zoneCode];
if (data.carbonIntensity > zoneAverageIntensity) {
gridAware = true;
}
return {
status: "success",
region: data.region,
gridAware,
data: {
mode: this.mode,
carbonIntensity: data.carbonIntensity,
averageIntensity: zoneAverageIntensity,
},
};
} else {
if (data.carbonIntensity > this.minimumIntensity) {
gridAware = true;
}
return {
status: "success",
region: data.region,
gridAware,
data: {
mode: this.mode,
carbonIntensity: data.carbonIntensity,
minimumIntensity: this.minimumIntensity,
},
};
}
}
}
export { GridIntensity };