node-red-contrib-power-saver 5.0.0-beta.2 → 5.0.0-beta.4

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.
@@ -19,6 +19,38 @@ describe("mostSavedStrategy", () => {
19
19
  expect(isOnOffSequencesOk(onOff, 3, 3, 100)).to.equal(false);
20
20
  expect(isOnOffSequencesOk(onOff, 3, 3, 50)).to.equal(true);
21
21
  expect(isOnOffSequencesOk(onOff, 3, 3, 50, 3)).to.equal(true);
22
+ expect(isOnOffSequencesOk(onOff, 3, 3, 100)).to.equal(false);
23
+ expect(isOnOffSequencesOk(onOff, 3, 3, 90)).to.equal(false);
24
+ });
25
+ it("evaluates onOff sequences correct with strange input", () => {
26
+ const onOff = [true, true, false, false, false, true, true, false];
27
+ expect(isOnOffSequencesOk(onOff, 3, 3, 100, null)).to.equal(false);
28
+ expect(isOnOffSequencesOk(onOff, 3, 3, 100, "")).to.equal(false);
29
+
30
+ });
31
+
32
+ it("evaluates a long onOff sequence correct", () => {
33
+ const minutesSetting = [
34
+ { count: 465, value: true },
35
+ { count: 75, value: false },
36
+ { count: 541, value: true },
37
+ { count: 74, value: false },
38
+ { count: 15, value: true },
39
+ { count: 75, value: false },
40
+ { count: 1335, value: true },
41
+ { count: 75, value: false },
42
+ { count: 315, value: true },
43
+ ];
44
+
45
+ const minutes = [];
46
+ minutesSetting.forEach((ms) => {
47
+ for (let i = 0; i < ms.count; i++) {
48
+ minutes.push(ms.value);
49
+ }
50
+ });
51
+
52
+ expect(isOnOffSequencesOk(minutes, 75, 15, 85)).to.equal(false);
53
+
22
54
  });
23
55
 
24
56
  it("saves correct hours", () => {
@@ -0,0 +1,53 @@
1
+ const cloneDeep = require("lodash.clonedeep");
2
+ const { DateTime } = require("luxon");
3
+ const expect = require("chai").expect;
4
+ const helper = require("node-red-node-test-helper");
5
+ const bestSave = require("../src/strategy-best-save.js");
6
+ const input = require("./data/bug-232-input.json");
7
+ const output = require("./data/bug-232-output.json");
8
+ const { testPlan: plan, equalPlan } = require("./test-utils");
9
+ const { makeFlow } = require("./strategy-best-save-test-utils");
10
+ const { version } = require("../package.json");
11
+
12
+ helper.init(require.resolve("node-red"));
13
+
14
+ describe("ps-strategy-best-save bug-232", function () {
15
+ beforeEach(function (done) {
16
+ helper.startServer(done);
17
+ });
18
+
19
+ afterEach(function (done) {
20
+ helper.unload().then(function () {
21
+ helper.stopServer(done);
22
+ });
23
+ });
24
+
25
+ it.skip("find bug", function (done) {
26
+ const flow = makeFlow(output.config.maxMinutesOff, output.config.minMinutesOff, output.config.recoveryPercentage , output.config.recoveryMaxMinutes);
27
+ flow[0].minSaving = output.config.minSaving;
28
+ flow[0].outputIfNoSchedule = output.config.outputIfNoSchedule;
29
+ const expected = cloneDeep(output);
30
+ expected.version = output.version;
31
+ expected.time = output.time;
32
+ expected.source = output.source;
33
+ expected.current = false;
34
+ helper.load(bestSave, flow, function () {
35
+ const n1 = helper.getNode("n1");
36
+ const n2 = helper.getNode("n2");
37
+ n2.on("input", function (msg) {
38
+ expect(equalPlan(expected, msg.payload)).to.equal(true);
39
+ n1.warn.should.not.be.called;
40
+ setTimeout(() => {
41
+ done();
42
+ }, 900);
43
+ });
44
+ n1.receive({ payload: makePayload()})
45
+ });
46
+ });
47
+ });
48
+
49
+ function makePayload() {
50
+ const payload = cloneDeep(input);
51
+ payload.time = output.time;
52
+ return payload;
53
+ }
@@ -151,7 +151,10 @@ describe("ps-strategy-heat-capacitor node", function () {
151
151
  const n1 = helper.getNode("n1");
152
152
  n1.receive({ payload: multiTrade });
153
153
  n1.receive({ payload: prices });
154
- expect(n1.priceData.length).to.equal(72);
154
+ const latestStart = DateTime.fromISO(n1.priceData[n1.priceData.length - 1].start);
155
+ const cutoff = latestStart.minus({ hours: 72 });
156
+ const allWithinRange = n1.priceData.every((entry) => DateTime.fromISO(entry.start) >= cutoff);
157
+ expect(allWithinRange).to.equal(true);
155
158
  done();
156
159
  });
157
160
  });
@@ -11,6 +11,51 @@ const {
11
11
  const converted_prices = require("./data/converted-prices.json");
12
12
  const decreasing_end_prices = require("./data/tibber-decreasing2-24h.json");
13
13
 
14
+ function buildMinutePriceVectorForTests(priceData) {
15
+ if (!Array.isArray(priceData) || priceData.length === 0) {
16
+ return { minutePrices: [], startDate: null };
17
+ }
18
+
19
+ const sorted = priceData
20
+ .slice()
21
+ .sort((a, b) => DateTime.fromISO(a.start).toMillis() - DateTime.fromISO(b.start).toMillis());
22
+
23
+ const minutePrices = [];
24
+ let previousIntervalMinutes = 60;
25
+
26
+ for (let i = 0; i < sorted.length; i++) {
27
+ const currentStart = DateTime.fromISO(sorted[i].start);
28
+ let intervalMinutes = previousIntervalMinutes;
29
+
30
+ if (sorted[i + 1]) {
31
+ intervalMinutes = DateTime.fromISO(sorted[i + 1].start).diff(currentStart, "minutes").minutes;
32
+ } else if (sorted[i].end) {
33
+ intervalMinutes = DateTime.fromISO(sorted[i].end).diff(currentStart, "minutes").minutes;
34
+ }
35
+
36
+ intervalMinutes = Math.max(1, Math.round(intervalMinutes));
37
+ previousIntervalMinutes = intervalMinutes;
38
+
39
+ for (let m = 0; m < intervalMinutes; m++) {
40
+ minutePrices.push(sorted[i].value);
41
+ }
42
+ }
43
+
44
+ return { minutePrices, startDate: DateTime.fromISO(sorted[0].start) };
45
+ }
46
+
47
+ function buildMinutePricesFromValues(values, startIso) {
48
+ if (!Array.isArray(values) || values.length === 0) {
49
+ return [];
50
+ }
51
+ const baseDate = startIso ? DateTime.fromISO(startIso) : DateTime.fromISO(converted_prices.priceData[0].start);
52
+ const priceData = values.map((value, idx) => ({
53
+ value,
54
+ start: baseDate.plus({ hours: idx }).toISO(),
55
+ }));
56
+ return buildMinutePriceVectorForTests(priceData).minutePrices;
57
+ }
58
+
14
59
  describe("ps-strategy-heat-capacitor-functions", () => {
15
60
  let prices, decreasing_24h_prices, start_date, buy_pattern, sell_pattern;
16
61
 
@@ -24,15 +69,16 @@ describe("ps-strategy-heat-capacitor-functions", () => {
24
69
  const minSavings = 0.1;
25
70
 
26
71
  before(function () {
27
- prices = converted_prices.priceData.slice(0, 1).map((p) => p.value);
28
- decreasing_24h_prices = decreasing_end_prices.priceData.slice(0, 1).map((p) => p.value);
29
- start_date = DateTime.fromISO(converted_prices.priceData[0].start);
72
+ const convertedSingleHour = buildMinutePriceVectorForTests(converted_prices.priceData.slice(0, 1));
73
+ prices = convertedSingleHour.minutePrices;
74
+ decreasing_24h_prices = buildMinutePriceVectorForTests(decreasing_end_prices.priceData).minutePrices;
75
+ start_date = convertedSingleHour.startDate;
30
76
  buy_pattern = Array(Math.round(timeHeat1C * maxTempAdjustment * 2)).fill(1);
31
77
  sell_pattern = Array(Math.round(timeCool1C * maxTempAdjustment * 2)).fill(1);
32
78
  });
33
79
 
34
80
  it("Can calculate procurement opportunities", () => {
35
- const my_prices = prices.slice(0, 1);
81
+ const my_prices = prices.slice();
36
82
  const my_buy_pattern = Array(5).fill(1);
37
83
  //Calculate what it will cost to procure/sell 1 kWh as a function of time
38
84
  let result = calculateOpportunities(my_prices, my_buy_pattern, 1);
@@ -43,7 +89,7 @@ describe("ps-strategy-heat-capacitor-functions", () => {
43
89
 
44
90
  it("Can find procurement pattern", () => {
45
91
  //Use a simple price list
46
- const my_prices = [1, 2, 2, 1, 8, 1];
92
+ const my_prices = buildMinutePricesFromValues([1, 2, 2, 1, 8, 1], start_date.toISO());
47
93
 
48
94
  const buy_prices = calculateOpportunities(my_prices, buy_pattern, 1);
49
95
  const sell_prices = calculateOpportunities(my_prices, sell_pattern, 1);
@@ -57,7 +103,7 @@ describe("ps-strategy-heat-capacitor-functions", () => {
57
103
  });
58
104
 
59
105
  it("DictList test", () => {
60
- const my_prices = [1, 2, 2, 1, 8, 1];
106
+ const my_prices = buildMinutePricesFromValues([1, 2, 2, 1, 8, 1], start_date.toISO());
61
107
  const my_buy_sell_indexes = [
62
108
  [0, 173],
63
109
  [131, 251],
@@ -70,7 +116,7 @@ describe("ps-strategy-heat-capacitor-functions", () => {
70
116
  });
71
117
 
72
118
  it("DictList test at decreasing end", () => {
73
- const my_prices = decreasing_end_prices.priceData.map((p) => p.value);
119
+ const my_prices = decreasing_24h_prices;
74
120
  const buy_prices = calculateOpportunities(my_prices, buy_pattern, 1);
75
121
  const sell_prices = calculateOpportunities(my_prices, sell_pattern, 1);
76
122
 
@@ -91,7 +137,7 @@ describe("ps-strategy-heat-capacitor-functions", () => {
91
137
  });
92
138
 
93
139
  it("Check removal of low benefit buy-sell pairs", () => {
94
- const my_prices = [1, 2, 1, 1.05, 1, 2];
140
+ const my_prices = buildMinutePricesFromValues([1, 2, 1, 1.05, 1, 2], start_date.toISO());
95
141
  const buy_prices = calculateOpportunities(my_prices, buy_pattern, 1);
96
142
  const sell_prices = calculateOpportunities(my_prices, sell_pattern, 1);
97
143
  const my_buy_sell = findBestBuySellPattern(buy_prices, buy_pattern.length, sell_prices, sell_pattern.length);