node-red-contrib-power-saver 3.5.6 → 3.6.1
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/docs/.vuepress/config.js +1 -0
- package/docs/changelog/README.md +15 -0
- package/docs/examples/example-grid-tariff-capacity-part.md +272 -0
- package/docs/images/lowest-price-config.png +0 -0
- package/docs/nodes/ps-general-add-tariff.md +15 -1
- package/docs/nodes/ps-strategy-best-save.md +4 -2
- package/docs/nodes/ps-strategy-lowest-price.md +27 -13
- package/package.json +2 -1
- package/src/elvia/elvia-add-tariff.html +1 -1
- package/src/elvia/elvia-add-tariff.js +4 -2
- package/src/general-add-tariff-functions.js +3 -1
- package/src/general-add-tariff.html +54 -3
- package/src/general-add-tariff.js +1 -0
- package/src/power-saver.html +1 -1
- package/src/receive-price.html +1 -1
- package/src/strategy-best-save-functions.js +5 -1
- package/src/strategy-best-save.html +1 -1
- package/src/strategy-heat-capacitor.html +1 -3
- package/src/strategy-lowest-price.html +13 -1
- package/src/strategy-lowest-price.js +11 -2
- package/src/utils.js +5 -2
- package/test/data/best-save-overlap-prices.json +197 -0
- package/test/data/best-save-overlap-result.json +357 -0
- package/test/data/lowest-price-result-cont-max-fail.json +14 -0
- package/test/data/lowest-price-result-cont-max.json +20 -0
- package/test/data/lowest-price-result-cont.json +6 -5
- package/test/data/lowest-price-result-missing-end.json +7 -3
- package/test/data/lowest-price-result-split-allday.json +9 -8
- package/test/data/lowest-price-result-split-allday10.json +8 -7
- package/test/data/lowest-price-result-split-max.json +22 -0
- package/test/data/lowest-price-result-split.json +8 -7
- package/test/data/nordpool-3-days-result.json +10 -5
- package/test/data/result.js +9 -0
- package/test/data/tibber-result-end-0-24h.json +9 -4
- package/test/data/tibber-result-end-0.json +5 -2
- package/test/data/tibber-result.json +28 -14
- package/test/general-add-tariff-functions.test.js +2 -0
- package/test/general-add-tariff.test.js +40 -1
- package/test/power-saver.test.js +6 -0
- package/test/strategy-best-save-overlap.test.js +52 -0
- package/test/strategy-lowest-price.test.js +88 -31
- package/test/utils.test.js +9 -8
|
@@ -91,6 +91,55 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
91
91
|
n1.receive({ payload: makePayload(prices, time) });
|
|
92
92
|
});
|
|
93
93
|
});
|
|
94
|
+
it("should plan correct continuous schedule with max price ok", function (done) {
|
|
95
|
+
const resultContinuousMax = require("./data/lowest-price-result-cont-max.json");
|
|
96
|
+
const flow = makeFlow(4, 1.0);
|
|
97
|
+
helper.load(lowestPrice, flow, function () {
|
|
98
|
+
const n1 = helper.getNode("n1");
|
|
99
|
+
const n2 = helper.getNode("n2");
|
|
100
|
+
n2.on("input", function (msg) {
|
|
101
|
+
expect(msg.payload).toHaveProperty("schedule", resultContinuousMax.schedule);
|
|
102
|
+
expect(msg.payload).toHaveProperty("config", resultContinuousMax.config);
|
|
103
|
+
n1.warn.should.not.be.called;
|
|
104
|
+
done();
|
|
105
|
+
});
|
|
106
|
+
const time = DateTime.fromISO(prices.priceData[10].start);
|
|
107
|
+
n1.receive({ payload: makePayload(prices, time) });
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
it("should plan correct continuous schedule with max price too high", function (done) {
|
|
111
|
+
const resultContinuousMax = require("./data/lowest-price-result-cont-max-fail.json");
|
|
112
|
+
const flow = makeFlow(4, 0.23);
|
|
113
|
+
helper.load(lowestPrice, flow, function () {
|
|
114
|
+
const n1 = helper.getNode("n1");
|
|
115
|
+
const n2 = helper.getNode("n2");
|
|
116
|
+
n2.on("input", function (msg) {
|
|
117
|
+
expect(msg.payload).toHaveProperty("schedule", resultContinuousMax.schedule);
|
|
118
|
+
expect(msg.payload).toHaveProperty("config", resultContinuousMax.config);
|
|
119
|
+
n1.warn.should.not.be.called;
|
|
120
|
+
done();
|
|
121
|
+
});
|
|
122
|
+
const time = DateTime.fromISO(prices.priceData[10].start);
|
|
123
|
+
n1.receive({ payload: makePayload(prices, time) });
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
it("should plan correct splitted schedule with max price", function (done) {
|
|
127
|
+
const resultSplittedMax = require("./data/lowest-price-result-split-max.json");
|
|
128
|
+
const flow = makeFlow(6, 0.51);
|
|
129
|
+
flow[0].doNotSplit = false;
|
|
130
|
+
helper.load(lowestPrice, flow, function () {
|
|
131
|
+
const n1 = helper.getNode("n1");
|
|
132
|
+
const n2 = helper.getNode("n2");
|
|
133
|
+
n2.on("input", function (msg) {
|
|
134
|
+
expect(msg.payload).toHaveProperty("schedule", resultSplittedMax.schedule);
|
|
135
|
+
expect(msg.payload).toHaveProperty("config", resultSplittedMax.config);
|
|
136
|
+
n1.warn.should.not.be.called;
|
|
137
|
+
done();
|
|
138
|
+
});
|
|
139
|
+
const time = DateTime.fromISO(prices.priceData[10].start);
|
|
140
|
+
n1.receive({ payload: makePayload(prices, time) });
|
|
141
|
+
});
|
|
142
|
+
});
|
|
94
143
|
it("should plan correct for all day period - 00-00", function (done) {
|
|
95
144
|
const resultAllDay = require("./data/lowest-price-result-split-allday.json");
|
|
96
145
|
const flow = makeFlow(8);
|
|
@@ -186,12 +235,14 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
186
235
|
const schedule = cloneDeep(resultSplitted.schedule);
|
|
187
236
|
const config = cloneDeep(resultSplitted.config);
|
|
188
237
|
schedule[0].value = true;
|
|
189
|
-
schedule.splice(1, 0, { time: "2021-10-11T10:00:00.000+02:00", value: false });
|
|
190
|
-
schedule.splice(4, 0, { time: "2021-10-11T20:00:00.000+02:00", value: true });
|
|
191
|
-
schedule.splice(5, 0, { time: "2021-10-12T10:00:00.000+02:00", value: false });
|
|
238
|
+
schedule.splice(1, 0, { time: "2021-10-11T10:00:00.000+02:00", value: false, countHours: 10 });
|
|
239
|
+
schedule.splice(4, 0, { time: "2021-10-11T20:00:00.000+02:00", value: true, countHours: 14 });
|
|
240
|
+
schedule.splice(5, 0, { time: "2021-10-12T10:00:00.000+02:00", value: false, countHours: 14 });
|
|
192
241
|
schedule.splice(schedule.length - 1, 1);
|
|
193
242
|
config.outputOutsidePeriod = true;
|
|
194
|
-
|
|
243
|
+
const res = msg.payload.schedule.map((s) => ({ time: s.time, value: s.value }));
|
|
244
|
+
const exp = schedule.map((s) => ({ time: s.time, value: s.value }));
|
|
245
|
+
expect(res).toEqual(exp);
|
|
195
246
|
expect(msg.payload).toHaveProperty("config", config);
|
|
196
247
|
n1.warn.should.not.be.called;
|
|
197
248
|
done();
|
|
@@ -218,7 +269,9 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
218
269
|
schedule.splice(schedule.length, 0, { time: "2021-10-12T20:00:00.000+02:00", value: true });
|
|
219
270
|
// schedule.splice(schedule.length - 1, 1);
|
|
220
271
|
config.outputOutsidePeriod = true;
|
|
221
|
-
|
|
272
|
+
const res = msg.payload.schedule.map((s) => ({ time: s.time, value: s.value }));
|
|
273
|
+
const exp = schedule.map((s) => ({ time: s.time, value: s.value }));
|
|
274
|
+
expect(res).toEqual(exp);
|
|
222
275
|
expect(msg.payload).toHaveProperty("config", config);
|
|
223
276
|
n1.warn.should.not.be.called;
|
|
224
277
|
done();
|
|
@@ -228,7 +281,7 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
228
281
|
});
|
|
229
282
|
});
|
|
230
283
|
it("should work with 0 hours on", function (done) {
|
|
231
|
-
const result = [{ time: "2021-10-11T00:00:00.000+02:00", value: false }];
|
|
284
|
+
const result = [{ time: "2021-10-11T00:00:00.000+02:00", value: false, countHours: 48 }];
|
|
232
285
|
const flow = makeFlow(0);
|
|
233
286
|
helper.load(lowestPrice, flow, function () {
|
|
234
287
|
const n1 = helper.getNode("n1");
|
|
@@ -244,11 +297,11 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
244
297
|
});
|
|
245
298
|
it("should work with 0 hours on outside on", function (done) {
|
|
246
299
|
const result = [
|
|
247
|
-
{ time: "2021-10-11T00:00:00.000+02:00", value: true },
|
|
248
|
-
{ time: "2021-10-11T10:00:00.000+02:00", value: false },
|
|
249
|
-
{ time: "2021-10-11T20:00:00.000+02:00", value: true },
|
|
250
|
-
{ time: "2021-10-12T10:00:00.000+02:00", value: false },
|
|
251
|
-
{ time: "2021-10-12T20:00:00.000+02:00", value: true },
|
|
300
|
+
{ time: "2021-10-11T00:00:00.000+02:00", value: true, countHours: 10 },
|
|
301
|
+
{ time: "2021-10-11T10:00:00.000+02:00", value: false, countHours: 10 },
|
|
302
|
+
{ time: "2021-10-11T20:00:00.000+02:00", value: true, countHours: 14 },
|
|
303
|
+
{ time: "2021-10-12T10:00:00.000+02:00", value: false, countHours: 10 },
|
|
304
|
+
{ time: "2021-10-12T20:00:00.000+02:00", value: true, countHours: 4 },
|
|
252
305
|
];
|
|
253
306
|
const flow = makeFlow(0);
|
|
254
307
|
flow[0].outputOutsidePeriod = true;
|
|
@@ -266,11 +319,11 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
266
319
|
});
|
|
267
320
|
it("should work with 1 hours on", function (done) {
|
|
268
321
|
const result = [
|
|
269
|
-
{ time: "2021-10-11T00:00:00.000+02:00", value: false },
|
|
270
|
-
{ time: "2021-10-11T12:00:00.000+02:00", value: true },
|
|
271
|
-
{ time: "2021-10-11T13:00:00.000+02:00", value: false },
|
|
272
|
-
{ time: "2021-10-12T14:00:00.000+02:00", value: true },
|
|
273
|
-
{ time: "2021-10-12T15:00:00.000+02:00", value: false },
|
|
322
|
+
{ time: "2021-10-11T00:00:00.000+02:00", value: false, countHours: 12 },
|
|
323
|
+
{ time: "2021-10-11T12:00:00.000+02:00", value: true, countHours: 1 },
|
|
324
|
+
{ time: "2021-10-11T13:00:00.000+02:00", value: false, countHours: 25 },
|
|
325
|
+
{ time: "2021-10-12T14:00:00.000+02:00", value: true, countHours: 1 },
|
|
326
|
+
{ time: "2021-10-12T15:00:00.000+02:00", value: false, countHours: 9 },
|
|
274
327
|
];
|
|
275
328
|
const flow = makeFlow(1);
|
|
276
329
|
helper.load(lowestPrice, flow, function () {
|
|
@@ -287,11 +340,11 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
287
340
|
});
|
|
288
341
|
it("should work with 24 hours on", function (done) {
|
|
289
342
|
const result = [
|
|
290
|
-
{ time: "2021-10-11T00:00:00.000+02:00", value: false },
|
|
291
|
-
{ time: "2021-10-11T10:00:00.000+02:00", value: true },
|
|
292
|
-
{ time: "2021-10-11T20:00:00.000+02:00", value: false },
|
|
293
|
-
{ time: "2021-10-12T10:00:00.000+02:00", value: true },
|
|
294
|
-
{ time: "2021-10-12T20:00:00.000+02:00", value: false },
|
|
343
|
+
{ time: "2021-10-11T00:00:00.000+02:00", value: false, countHours: 10 },
|
|
344
|
+
{ time: "2021-10-11T10:00:00.000+02:00", value: true, countHours: 10 },
|
|
345
|
+
{ time: "2021-10-11T20:00:00.000+02:00", value: false, countHours: 14 },
|
|
346
|
+
{ time: "2021-10-12T10:00:00.000+02:00", value: true, countHours: 10 },
|
|
347
|
+
{ time: "2021-10-12T20:00:00.000+02:00", value: false, countHours: 4 },
|
|
295
348
|
];
|
|
296
349
|
const flow = makeFlow(24);
|
|
297
350
|
helper.load(lowestPrice, flow, function () {
|
|
@@ -311,9 +364,9 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
311
364
|
const oneDayPrices = {};
|
|
312
365
|
oneDayPrices.priceData = prices.priceData.filter((d) => d.start.startsWith("2021-10-11"));
|
|
313
366
|
const result = [
|
|
314
|
-
{ time: "2021-10-11T00:00:00.000+02:00", value: false },
|
|
315
|
-
{ time: "2021-10-11T12:00:00.000+02:00", value: true },
|
|
316
|
-
{ time: "2021-10-11T13:00:00.000+02:00", value: false },
|
|
367
|
+
{ time: "2021-10-11T00:00:00.000+02:00", value: false, countHours: 12 },
|
|
368
|
+
{ time: "2021-10-11T12:00:00.000+02:00", value: true, countHours: 1 },
|
|
369
|
+
{ time: "2021-10-11T13:00:00.000+02:00", value: false, countHours: 11 },
|
|
317
370
|
];
|
|
318
371
|
const flow = makeFlow(1);
|
|
319
372
|
helper.load(lowestPrice, flow, function () {
|
|
@@ -340,7 +393,7 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
340
393
|
});
|
|
341
394
|
|
|
342
395
|
it("should handle hours on > period", function (done) {
|
|
343
|
-
const result = [{ time: "2021-10-11T00:00:00.000+02:00", value: true }];
|
|
396
|
+
const result = [{ time: "2021-10-11T00:00:00.000+02:00", value: true, countHours: 48 }];
|
|
344
397
|
const flow = [
|
|
345
398
|
{
|
|
346
399
|
id: "n1",
|
|
@@ -388,11 +441,11 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
388
441
|
});
|
|
389
442
|
it("should handle hours on > period, false outside", function (done) {
|
|
390
443
|
const result = [
|
|
391
|
-
{ time: "2021-10-11T00:00:00.000+02:00", value: false },
|
|
392
|
-
{ time: "2021-10-11T17:00:00.000+02:00", value: true },
|
|
393
|
-
{ time: "2021-10-11T22:00:00.000+02:00", value: false },
|
|
394
|
-
{ time: "2021-10-12T17:00:00.000+02:00", value: true },
|
|
395
|
-
{ time: "2021-10-12T22:00:00.000+02:00", value: false },
|
|
444
|
+
{ time: "2021-10-11T00:00:00.000+02:00", value: false, countHours: 17 },
|
|
445
|
+
{ time: "2021-10-11T17:00:00.000+02:00", value: true, countHours: 5 },
|
|
446
|
+
{ time: "2021-10-11T22:00:00.000+02:00", value: false, countHours: 19 },
|
|
447
|
+
{ time: "2021-10-12T17:00:00.000+02:00", value: true, countHours: 5 },
|
|
448
|
+
{ time: "2021-10-12T22:00:00.000+02:00", value: false, countHours: 2 },
|
|
396
449
|
];
|
|
397
450
|
const flow = [
|
|
398
451
|
{
|
|
@@ -451,6 +504,7 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
451
504
|
fromTime: "16",
|
|
452
505
|
toTime: "00",
|
|
453
506
|
hoursOn: 3,
|
|
507
|
+
maxPrice: null,
|
|
454
508
|
doNotSplit: false,
|
|
455
509
|
sendCurrentValueWhenRescheduling: true,
|
|
456
510
|
outputIfNoSchedule: false,
|
|
@@ -485,6 +539,7 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
485
539
|
fromTime: "16",
|
|
486
540
|
toTime: "00",
|
|
487
541
|
hoursOn: 3,
|
|
542
|
+
maxPrice: null,
|
|
488
543
|
doNotSplit: false,
|
|
489
544
|
sendCurrentValueWhenRescheduling: true,
|
|
490
545
|
outputIfNoSchedule: false,
|
|
@@ -519,6 +574,7 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
519
574
|
fromTime: "22",
|
|
520
575
|
toTime: "08",
|
|
521
576
|
hoursOn: 3,
|
|
577
|
+
maxPrice: null,
|
|
522
578
|
doNotSplit: true,
|
|
523
579
|
sendCurrentValueWhenRescheduling: true,
|
|
524
580
|
outputIfNoSchedule: false,
|
|
@@ -544,7 +600,7 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
544
600
|
});
|
|
545
601
|
});
|
|
546
602
|
|
|
547
|
-
function makeFlow(hoursOn) {
|
|
603
|
+
function makeFlow(hoursOn, maxPrice = null) {
|
|
548
604
|
return [
|
|
549
605
|
{
|
|
550
606
|
id: "n1",
|
|
@@ -553,6 +609,7 @@ function makeFlow(hoursOn) {
|
|
|
553
609
|
fromTime: "10",
|
|
554
610
|
toTime: "20",
|
|
555
611
|
hoursOn: hoursOn,
|
|
612
|
+
maxPrice: maxPrice,
|
|
556
613
|
doNotSplit: true,
|
|
557
614
|
sendCurrentValueWhenRescheduling: true,
|
|
558
615
|
outputIfNoSchedule: true,
|
package/test/utils.test.js
CHANGED
|
@@ -70,18 +70,19 @@ describe("utils", () => {
|
|
|
70
70
|
"2021-06-20T09:00:00+02:00",
|
|
71
71
|
];
|
|
72
72
|
expect(makeSchedule(onOff, startTimes)).toEqual([
|
|
73
|
-
{ time: "2021-06-20T05:00:00+02:00", value: false },
|
|
74
|
-
{ time: "2021-06-20T07:00:00+02:00", value: true },
|
|
75
|
-
{ time: "2021-06-20T09:00:00+02:00", value: false },
|
|
73
|
+
{ time: "2021-06-20T05:00:00+02:00", value: false, countHours: 2 },
|
|
74
|
+
{ time: "2021-06-20T07:00:00+02:00", value: true, countHours: 2 },
|
|
75
|
+
{ time: "2021-06-20T09:00:00+02:00", value: false, countHours: 1 },
|
|
76
76
|
]);
|
|
77
77
|
expect(makeSchedule(onOff, startTimes, true)).toEqual([
|
|
78
|
-
{ time: "2021-06-20T05:00:00+02:00", value: false },
|
|
79
|
-
{ time: "2021-06-20T07:00:00+02:00", value: true },
|
|
80
|
-
{ time: "2021-06-20T09:00:00+02:00", value: false },
|
|
78
|
+
{ time: "2021-06-20T05:00:00+02:00", value: false, countHours: 2 },
|
|
79
|
+
{ time: "2021-06-20T07:00:00+02:00", value: true, countHours: 2 },
|
|
80
|
+
{ time: "2021-06-20T09:00:00+02:00", value: false, countHours: 1 },
|
|
81
81
|
]);
|
|
82
82
|
expect(makeSchedule(onOff, startTimes, false)).toEqual([
|
|
83
|
-
{ time: "2021-06-
|
|
84
|
-
{ time: "2021-06-
|
|
83
|
+
{ time: "2021-06-20T05:00:00+02:00", value: false, countHours: 2 }, // Right???
|
|
84
|
+
{ time: "2021-06-20T07:00:00+02:00", value: true, countHours: 2 },
|
|
85
|
+
{ time: "2021-06-20T09:00:00+02:00", value: false, countHours: 1 },
|
|
85
86
|
]);
|
|
86
87
|
});
|
|
87
88
|
|