@tgwf/co2 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/data/Lean-ICT-Materials-1byte-Model-2018.xlsx +0 -0
- package/data/Lean-ICT-Materials-Forecast-Model-2018.xlsx +0 -0
- package/data/fixtures/url2green.test.json.gz +0 -0
- package/package.json +1 -1
- package/src/1byte.js +13 -4
- package/src/1byte.test.js +16 -0
- package/src/co2.test.js +20 -10
- package/src/hosting-json.js +21 -1
- package/src/hosting-json.test.js +14 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
## Unreleased
|
|
10
10
|
|
|
11
11
|
- Include a new alternative, "Green Byte Model" with the figures after speaking to folks at the IEA and other places.
|
|
12
|
+
|
|
13
|
+
# [0.8.0] - 2021-11-28
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Update further dependencies
|
|
18
|
+
- Fix embarassing order of magnitude typo in 1byte model (thanks @mstaschik!)
|
|
19
|
+
|
|
20
|
+
## Added
|
|
21
|
+
|
|
22
|
+
- Read JSON blob also as gzipped #44 (thanks @soulgalore)
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- The 1bye model will give different numbers now. It's mentioned in `#fixed` but it's worth repeating.
|
|
27
|
+
|
|
12
28
|
## [0.7.0] - 2021-11-28
|
|
13
29
|
|
|
14
30
|
### Fixed
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/src/1byte.js
CHANGED
|
@@ -9,16 +9,25 @@ const CO2_PER_KWH_IN_DC_GREY = 519;
|
|
|
9
9
|
|
|
10
10
|
// The device usage figure combines figures for:
|
|
11
11
|
// 1. the usage for devices (which is small proportion of the energy use)
|
|
12
|
-
// 2. the *making* the device, which is
|
|
12
|
+
// 2. the *making* the device, which is comparatively high.
|
|
13
13
|
|
|
14
|
-
const KWH_PER_BYTE_IN_DC =
|
|
14
|
+
const KWH_PER_BYTE_IN_DC = 7.2e-11;
|
|
15
15
|
|
|
16
16
|
// this is probably best left as something users can define, or
|
|
17
17
|
// a weighted average based on total usage.
|
|
18
|
+
// Using a simple mean for now, as while web traffic to end users might trend
|
|
19
|
+
// towards wifi and mobile,
|
|
20
|
+
// Web traffic between servers is likely wired networks
|
|
21
|
+
|
|
22
|
+
const FIXED_NETWORK_WIRED = 4.29e-10;
|
|
23
|
+
const FIXED_NETWORK_WIFI = 1.52e-10;
|
|
24
|
+
const FOUR_G_MOBILE = 8.84e-10;
|
|
25
|
+
|
|
18
26
|
// Pull requests gratefully accepted
|
|
19
|
-
const KWH_PER_BYTE_FOR_NETWORK =
|
|
27
|
+
const KWH_PER_BYTE_FOR_NETWORK =
|
|
28
|
+
(FIXED_NETWORK_WIRED + FIXED_NETWORK_WIFI + FOUR_G_MOBILE) / 3;
|
|
20
29
|
|
|
21
|
-
const KWH_PER_BYTE_FOR_DEVICES =
|
|
30
|
+
const KWH_PER_BYTE_FOR_DEVICES = 1.3e-10;
|
|
22
31
|
module.exports = {
|
|
23
32
|
KWH_PER_BYTE_IN_DC,
|
|
24
33
|
KWH_PER_BYTE_FOR_NETWORK,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const oneByte = require("./1byte");
|
|
4
|
+
|
|
5
|
+
describe("onebyte", function () {
|
|
6
|
+
describe("perByte", function () {
|
|
7
|
+
it.only("returns a simple average of the different networks", function () {
|
|
8
|
+
// we limit this to 12 figures with toFixed(12), because
|
|
9
|
+
// we have a recurring 333333 afterwards
|
|
10
|
+
// 4.88e-10 is the same as 0.000000000488
|
|
11
|
+
const expected_val = (0.000000000488).toFixed(12);
|
|
12
|
+
|
|
13
|
+
expect(oneByte.KWH_PER_BYTE_FOR_NETWORK.toFixed(12)).toBe(expected_val);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
package/src/co2.test.js
CHANGED
|
@@ -8,13 +8,13 @@ const pagexray = require("pagexray");
|
|
|
8
8
|
|
|
9
9
|
describe("co2", function () {
|
|
10
10
|
let har, co2;
|
|
11
|
-
const TGWF_GREY_VALUE =
|
|
12
|
-
const TGWF_GREEN_VALUE = 0.
|
|
13
|
-
const TGWF_MIXED_VALUE =
|
|
11
|
+
const TGWF_GREY_VALUE = 0.20497;
|
|
12
|
+
const TGWF_GREEN_VALUE = 0.54704;
|
|
13
|
+
const TGWF_MIXED_VALUE = 0.16718;
|
|
14
14
|
|
|
15
15
|
const MILLION = 1000000;
|
|
16
|
-
const MILLION_GREY =
|
|
17
|
-
const MILLION_GREEN =
|
|
16
|
+
const MILLION_GREY = 0.29081;
|
|
17
|
+
const MILLION_GREEN = 0.23196;
|
|
18
18
|
|
|
19
19
|
beforeEach(function () {
|
|
20
20
|
co2 = new CO2();
|
|
@@ -28,12 +28,18 @@ describe("co2", function () {
|
|
|
28
28
|
|
|
29
29
|
describe("perByte", function () {
|
|
30
30
|
it("returns a CO2 number for data transfer using 'grey' power", function () {
|
|
31
|
-
expect(co2.perByte(MILLION)).toBe(
|
|
31
|
+
expect(co2.perByte(MILLION).toPrecision(5)).toBe(
|
|
32
|
+
MILLION_GREY.toPrecision(5)
|
|
33
|
+
);
|
|
32
34
|
});
|
|
33
35
|
|
|
34
36
|
it("returns a lower CO2 number for data transfer from domains using entirely 'green' power", function () {
|
|
35
|
-
expect(co2.perByte(MILLION, false)).toBe(
|
|
36
|
-
|
|
37
|
+
expect(co2.perByte(MILLION, false).toPrecision(5)).toBe(
|
|
38
|
+
MILLION_GREY.toPrecision(5)
|
|
39
|
+
);
|
|
40
|
+
expect(co2.perByte(MILLION, true).toPrecision(5)).toBe(
|
|
41
|
+
MILLION_GREEN.toPrecision(5)
|
|
42
|
+
);
|
|
37
43
|
});
|
|
38
44
|
});
|
|
39
45
|
|
|
@@ -42,7 +48,9 @@ describe("co2", function () {
|
|
|
42
48
|
const pages = pagexray.convert(har);
|
|
43
49
|
const pageXrayRun = pages[0];
|
|
44
50
|
|
|
45
|
-
expect(co2.perPage(pageXrayRun)).toBe(
|
|
51
|
+
expect(co2.perPage(pageXrayRun).toPrecision(5)).toBe(
|
|
52
|
+
TGWF_GREY_VALUE.toPrecision(5)
|
|
53
|
+
);
|
|
46
54
|
});
|
|
47
55
|
it("returns lower CO2 for page served from green site", function () {
|
|
48
56
|
const pages = pagexray.convert(har);
|
|
@@ -75,7 +83,9 @@ describe("co2", function () {
|
|
|
75
83
|
"fonts.gstatic.com",
|
|
76
84
|
"api.thegreenwebfoundation.org",
|
|
77
85
|
];
|
|
78
|
-
expect(co2.perPage(pageXrayRun, green)).toBe(
|
|
86
|
+
expect(co2.perPage(pageXrayRun, green).toPrecision(5)).toBe(
|
|
87
|
+
TGWF_MIXED_VALUE.toPrecision(5)
|
|
88
|
+
);
|
|
79
89
|
});
|
|
80
90
|
});
|
|
81
91
|
describe("perDomain", function () {
|
package/src/hosting-json.js
CHANGED
|
@@ -3,11 +3,31 @@
|
|
|
3
3
|
const log = require("debug")("tgwf:hostingCache");
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const fs = require("fs");
|
|
6
|
+
const zlib = require("zlib");
|
|
6
7
|
const { promisify } = require("util");
|
|
7
8
|
const readFile = promisify(fs.readFile);
|
|
9
|
+
const gunzip = promisify(zlib.gunzip);
|
|
10
|
+
|
|
11
|
+
async function streamToString(stream) {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const chunks = [];
|
|
14
|
+
stream.on("error", reject);
|
|
15
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
16
|
+
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function getGzippedFileAsJson(jsonPath) {
|
|
21
|
+
const readStream = fs.createReadStream(jsonPath);
|
|
22
|
+
const text = await streamToString(readStream);
|
|
23
|
+
const unzipped = await gunzip(text);
|
|
24
|
+
return unzipped.toString();
|
|
25
|
+
}
|
|
8
26
|
|
|
9
27
|
async function loadJSON(jsonPath) {
|
|
10
|
-
const jsonBuffer =
|
|
28
|
+
const jsonBuffer = jsonPath.endsWith(".gz")
|
|
29
|
+
? await getGzippedFileAsJson(jsonPath)
|
|
30
|
+
: await readFile(jsonPath);
|
|
11
31
|
return JSON.parse(jsonBuffer);
|
|
12
32
|
}
|
|
13
33
|
|
package/src/hosting-json.test.js
CHANGED
|
@@ -11,7 +11,13 @@ describe("hostingJSON", function () {
|
|
|
11
11
|
"fixtures",
|
|
12
12
|
"url2green.test.json"
|
|
13
13
|
);
|
|
14
|
-
|
|
14
|
+
const jsonPathGz = path.resolve(
|
|
15
|
+
__dirname,
|
|
16
|
+
"..",
|
|
17
|
+
"data",
|
|
18
|
+
"fixtures",
|
|
19
|
+
"url2green.test.json.gz"
|
|
20
|
+
);
|
|
15
21
|
describe("checking a single domain with #check", function () {
|
|
16
22
|
test("against the list of domains as JSON", async function () {
|
|
17
23
|
const db = await hosting.loadJSON(jsonPath);
|
|
@@ -19,6 +25,13 @@ describe("hostingJSON", function () {
|
|
|
19
25
|
expect(res).toEqual(true);
|
|
20
26
|
});
|
|
21
27
|
});
|
|
28
|
+
describe("checking a single domain with #check", function () {
|
|
29
|
+
test("against the list of domains as JSON loaded from a gzipped JSON", async function () {
|
|
30
|
+
const db = await hosting.loadJSON(jsonPathGz);
|
|
31
|
+
const res = await hosting.check("google.com", db);
|
|
32
|
+
expect(res).toEqual(true);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
22
35
|
describe("implicitly checking multiple domains with #check", function () {
|
|
23
36
|
test("against the list of domains as JSON", async function () {
|
|
24
37
|
const db = await hosting.loadJSON(jsonPath);
|