node-red-contrib-power-saver 3.5.7 → 3.6.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/docs/.vuepress/config.js +2 -10
- package/docs/changelog/README.md +5 -0
- package/docs/images/lowest-price-config.png +0 -0
- 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/strategy-lowest-price.html +12 -0
- package/src/strategy-lowest-price.js +11 -2
- package/src/utils.js +5 -2
- 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/power-saver.test.js +6 -0
- package/test/strategy-lowest-price.test.js +88 -31
- package/test/utils.test.js +9 -8
package/docs/.vuepress/config.js
CHANGED
|
@@ -58,16 +58,7 @@ module.exports = {
|
|
|
58
58
|
"/changelog/": [{ text: "Changelog", children: ["/changelog/README.md"] }],
|
|
59
59
|
},
|
|
60
60
|
},
|
|
61
|
-
head: [
|
|
62
|
-
["link", { rel: "shortcut icon", type: "image/x-icon", href: "euro.png" }],
|
|
63
|
-
["script", { async: true, src: "https://www.googletagmanager.com/gtag/js?id=G-Z2QNNCDQZG" }],
|
|
64
|
-
[
|
|
65
|
-
"script",
|
|
66
|
-
{
|
|
67
|
-
src: "window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', 'G-Z2QNNCDQZG');",
|
|
68
|
-
},
|
|
69
|
-
],
|
|
70
|
-
],
|
|
61
|
+
head: [["link", { rel: "shortcut icon", type: "image/x-icon", href: "euro.png" }]],
|
|
71
62
|
plugins: [
|
|
72
63
|
[
|
|
73
64
|
"@vuepress/register-components",
|
|
@@ -76,5 +67,6 @@ module.exports = {
|
|
|
76
67
|
},
|
|
77
68
|
],
|
|
78
69
|
["@vuepress/plugin-search"],
|
|
70
|
+
["@vuepress/google-analytics", { ga: "G-Z2QNNCDQZG" }],
|
|
79
71
|
],
|
|
80
72
|
};
|
package/docs/changelog/README.md
CHANGED
|
@@ -6,6 +6,11 @@ sidebar: "auto"
|
|
|
6
6
|
|
|
7
7
|
List the most significant changes, starting in version 1.0.9.
|
|
8
8
|
|
|
9
|
+
## 3.6.0
|
|
10
|
+
|
|
11
|
+
- New feature `Max price` for Lowest Price node. Can be set to only turn on if prices is below or equal to the max price.
|
|
12
|
+
- New value in output 3 from the Lowest Price and Best Save nodes, `countHours`, telling the number of hours that the value will stay.
|
|
13
|
+
|
|
9
14
|
## 3.5.7
|
|
10
15
|
|
|
11
16
|
- Add day-filter to general-add-tariff node so it can add one tariff for some days, and another tariff for other days.
|
|
Binary file
|
|
@@ -168,11 +168,13 @@ Example of output:
|
|
|
168
168
|
"schedule": [
|
|
169
169
|
{
|
|
170
170
|
"time": "2021-09-30T00:00:00.000+02:00",
|
|
171
|
-
"value": false
|
|
171
|
+
"value": false,
|
|
172
|
+
"countHours": 1
|
|
172
173
|
},
|
|
173
174
|
{
|
|
174
175
|
"time": "2021-09-30T01:00:00.000+02:00",
|
|
175
|
-
"value": true
|
|
176
|
+
"value": true,
|
|
177
|
+
"countHours": 2
|
|
176
178
|
}
|
|
177
179
|
],
|
|
178
180
|
"hours": [
|
|
@@ -18,13 +18,14 @@ The node can work on a specific period from 1 to 24 hours during a 24 hour perio
|
|
|
18
18
|
|
|
19
19
|
| Value | Description |
|
|
20
20
|
| ---------------------- | -------------------------------------------------------------------------------- |
|
|
21
|
-
| From
|
|
22
|
-
| To
|
|
23
|
-
| Hours
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
21
|
+
| From time | The start time of the selected period. |
|
|
22
|
+
| To time | The end time of the selected period. |
|
|
23
|
+
| Hours on | The number of hours that shall be turned on. |
|
|
24
|
+
| Max price | If set, does not turn on if price is over this limit. See below. |
|
|
25
|
+
| Consecutive on-period | Check this if you need the on-period to be consecutive. |
|
|
26
|
+
| Send when rescheduling | Check this to make sure on or off output is sent immediately after rescheduling. |
|
|
27
|
+
| If no schedule, send | What to do if there is no valid schedule any more (turn on or off). |
|
|
28
|
+
| Outside period, send | Select the value to send outside the selected period. |
|
|
28
29
|
| Context storage | Select context storage to save data to, if you want other than the default. |
|
|
29
30
|
|
|
30
31
|
If you want to use a period of 24 hours, set the From Time and To Time to the same value. The time you select is significant in the way that it decides which 24 hours that are considered when finding the hours with lowest price.
|
|
@@ -49,6 +50,18 @@ Unless the period you select is 24 hours (`From Time` and `To Time` are the same
|
|
|
49
50
|
If you select a period for example from 10:00 to 02:00, it may not be possible to calculate before the period starts. This is because electricity prices for the next day (in the Nord Pool area) normally are received around 13:00. The node cannot calculate the period until it has price data for the whole period.
|
|
50
51
|
:::
|
|
51
52
|
|
|
53
|
+
::: warning Max price
|
|
54
|
+
Use this to set a maximum price for hours to be on.
|
|
55
|
+
Leave this blank if you don't understand how it works.!
|
|
56
|
+
If this is set, the number of hours on may be less then configured for `Hours on`.
|
|
57
|
+
|
|
58
|
+
If `Consecutive on period` is off (not checked), hours will be turned on only if the price is below or equal to `Max price`.
|
|
59
|
+
|
|
60
|
+
If `Consecutive on period` is on (checked), hours will be turned on only if the average price for the whole period is below or equal to `Max price`. If the average price for the hours that are supposed to be turned on is higher then `Max price`, then **all hours** will be off. This is to make sure that if the switch (or whatever you have connected) is turned on, it is turned on the whole period.
|
|
61
|
+
|
|
62
|
+
If you leave `Max price` blank, it has no effect.
|
|
63
|
+
:::
|
|
64
|
+
|
|
52
65
|
### Dynamic config
|
|
53
66
|
|
|
54
67
|
It is possible to change config dynamically by sending a config message to the node. The config messages has a payload with a config object like this example:
|
|
@@ -57,12 +70,13 @@ It is possible to change config dynamically by sending a config message to the n
|
|
|
57
70
|
"payload": {
|
|
58
71
|
"config": {
|
|
59
72
|
"contextStorage": "file",
|
|
60
|
-
"fromTime"
|
|
61
|
-
"toTime"
|
|
62
|
-
"hoursOn"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
73
|
+
"fromTime": 10,
|
|
74
|
+
"toTime": 16,
|
|
75
|
+
"hoursOn": 3,
|
|
76
|
+
"maxPrice": null,
|
|
77
|
+
"doNotSplit": false,
|
|
78
|
+
"sendCurrentValueWhenRescheduling": true,
|
|
79
|
+
"outputIfNoSchedule": false,
|
|
66
80
|
"outputOutsidePeriod": false
|
|
67
81
|
}
|
|
68
82
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-power-saver",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "A module for Node-RED that you can use to turn on and off a switch based on power prices",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@vuepress/bundler-vite": "^2.0.0-beta.36",
|
|
49
|
+
"@vuepress/plugin-google-analytics": "^2.0.0-beta.36",
|
|
49
50
|
"@vuepress/plugin-register-components": "^2.0.0-beta.36",
|
|
50
51
|
"@vuepress/plugin-search": "^2.0.0-beta.38",
|
|
51
52
|
"@vuepress/utils": "^2.0.0-beta.35",
|
|
@@ -43,6 +43,14 @@
|
|
|
43
43
|
value: "12",
|
|
44
44
|
required: true,
|
|
45
45
|
},
|
|
46
|
+
maxPrice: {
|
|
47
|
+
value: null,
|
|
48
|
+
required: false,
|
|
49
|
+
validate: function (v) {
|
|
50
|
+
console.log("validating " + v);
|
|
51
|
+
return v == null || v == "" || (!isNaN(parseFloat(v)) && isFinite(v));
|
|
52
|
+
},
|
|
53
|
+
},
|
|
46
54
|
doNotSplit: {
|
|
47
55
|
value: "false",
|
|
48
56
|
required: true,
|
|
@@ -145,6 +153,10 @@
|
|
|
145
153
|
<label for="node-input-hoursOn"><i class="fa fa-arrows-h"></i> Hours on</label>
|
|
146
154
|
<input type="text" id="node-input-hoursOn" style="width: 80px">
|
|
147
155
|
</div>
|
|
156
|
+
<div class="form-row">
|
|
157
|
+
<label for="node-input-maxPrice"><i class="fa fa-minus"></i> Max price</label>
|
|
158
|
+
<input type="text" id="node-input-maxPrice" placeholder="Max price" style="width: 80px">
|
|
159
|
+
</div>
|
|
148
160
|
<div class="form-row">
|
|
149
161
|
<label for="node-input-doNotSplit">Consecutive on-period</label>
|
|
150
162
|
<input type="checkbox" id="node-input-doNotSplit" style="display:inline-block; width:22px; vertical-align:top;">
|
|
@@ -13,6 +13,7 @@ module.exports = function (RED) {
|
|
|
13
13
|
fromTime: config.fromTime,
|
|
14
14
|
toTime: config.toTime,
|
|
15
15
|
hoursOn: parseInt(config.hoursOn),
|
|
16
|
+
maxPrice: config.maxPrice == null || config.maxPrice == "" ? null : parseFloat(config.maxPrice),
|
|
16
17
|
doNotSplit: booleanConfig(config.doNotSplit),
|
|
17
18
|
sendCurrentValueWhenRescheduling: booleanConfig(config.sendCurrentValueWhenRescheduling),
|
|
18
19
|
outputIfNoSchedule: booleanConfig(config.outputIfNoSchedule),
|
|
@@ -22,7 +23,6 @@ module.exports = function (RED) {
|
|
|
22
23
|
node.context().set("config", originalConfig);
|
|
23
24
|
node.contextStorage = originalConfig.contextStorage;
|
|
24
25
|
|
|
25
|
-
|
|
26
26
|
node.on("close", function () {
|
|
27
27
|
clearTimeout(node.schedulingTimeout);
|
|
28
28
|
});
|
|
@@ -123,8 +123,17 @@ function makePlan(node, values, onOff, fromIndex, toIndex) {
|
|
|
123
123
|
const res = node.doNotSplit
|
|
124
124
|
? getBestContinuous(valuesInPeriod, node.hoursOn)
|
|
125
125
|
: getBestX(valuesInPeriod, node.hoursOn);
|
|
126
|
+
const sumPriceOn = res.reduce((p, v, i) => {
|
|
127
|
+
return p + (v ? valuesInPeriod[i] : 0);
|
|
128
|
+
}, 0);
|
|
129
|
+
const average = sumPriceOn / node.hoursOn;
|
|
126
130
|
res.forEach((v, i) => {
|
|
127
|
-
onOff[fromIndex + i] =
|
|
131
|
+
onOff[fromIndex + i] =
|
|
132
|
+
node.maxPrice == null
|
|
133
|
+
? v
|
|
134
|
+
: node.doNotSplit
|
|
135
|
+
? v && average <= node.maxPrice
|
|
136
|
+
: v && valuesInPeriod[i] <= node.maxPrice;
|
|
128
137
|
});
|
|
129
138
|
return onOff;
|
|
130
139
|
}
|
package/src/utils.js
CHANGED
|
@@ -138,13 +138,16 @@ function countAtEnd(arr, value) {
|
|
|
138
138
|
function makeSchedule(onOff, startTimes, initial = null) {
|
|
139
139
|
const res = [];
|
|
140
140
|
let prev = initial;
|
|
141
|
+
let prevRecord;
|
|
141
142
|
for (let i = 0; i < startTimes.length; i++) {
|
|
142
143
|
const value = onOff[i];
|
|
143
|
-
if (value !== prev) {
|
|
144
|
+
if (value !== prev || i === 0) {
|
|
144
145
|
const time = startTimes[i];
|
|
145
|
-
|
|
146
|
+
prevRecord = { time, value, countHours: 0 };
|
|
147
|
+
res.push(prevRecord);
|
|
146
148
|
prev = value;
|
|
147
149
|
}
|
|
150
|
+
prevRecord.countHours++;
|
|
148
151
|
}
|
|
149
152
|
return res;
|
|
150
153
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schedule": [{ "time": "2021-10-11T00:00:00.000+02:00", "value": false, "countHours": 48 }],
|
|
3
|
+
"config": {
|
|
4
|
+
"contextStorage": "default",
|
|
5
|
+
"doNotSplit": true,
|
|
6
|
+
"fromTime": "10",
|
|
7
|
+
"hoursOn": 4,
|
|
8
|
+
"maxPrice": 0.23,
|
|
9
|
+
"outputIfNoSchedule": true,
|
|
10
|
+
"outputOutsidePeriod": false,
|
|
11
|
+
"sendCurrentValueWhenRescheduling": true,
|
|
12
|
+
"toTime": "20"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schedule": [
|
|
3
|
+
{ "time": "2021-10-11T00:00:00.000+02:00", "value": false, "countHours": 11 },
|
|
4
|
+
{ "time": "2021-10-11T11:00:00.000+02:00", "value": true, "countHours": 4 },
|
|
5
|
+
{ "time": "2021-10-11T15:00:00.000+02:00", "value": false, "countHours": 21 },
|
|
6
|
+
{ "time": "2021-10-12T12:00:00.000+02:00", "value": true, "countHours": 4 },
|
|
7
|
+
{ "time": "2021-10-12T16:00:00.000+02:00", "value": false, "countHours": 8 }
|
|
8
|
+
],
|
|
9
|
+
"config": {
|
|
10
|
+
"contextStorage": "default",
|
|
11
|
+
"doNotSplit": true,
|
|
12
|
+
"fromTime": "10",
|
|
13
|
+
"hoursOn": 4,
|
|
14
|
+
"maxPrice": 1,
|
|
15
|
+
"outputIfNoSchedule": true,
|
|
16
|
+
"outputOutsidePeriod": false,
|
|
17
|
+
"sendCurrentValueWhenRescheduling": true,
|
|
18
|
+
"toTime": "20"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schedule": [
|
|
3
|
-
{ "time": "2021-10-11T00:00:00.000+02:00", "value": false },
|
|
4
|
-
{ "time": "2021-10-11T11:00:00.000+02:00", "value": true },
|
|
5
|
-
{ "time": "2021-10-11T15:00:00.000+02:00", "value": false },
|
|
6
|
-
{ "time": "2021-10-12T12:00:00.000+02:00", "value": true },
|
|
7
|
-
{ "time": "2021-10-12T16:00:00.000+02:00", "value": false }
|
|
3
|
+
{ "time": "2021-10-11T00:00:00.000+02:00", "value": false, "countHours": 11 },
|
|
4
|
+
{ "time": "2021-10-11T11:00:00.000+02:00", "value": true, "countHours": 4 },
|
|
5
|
+
{ "time": "2021-10-11T15:00:00.000+02:00", "value": false, "countHours": 21 },
|
|
6
|
+
{ "time": "2021-10-12T12:00:00.000+02:00", "value": true, "countHours": 4 },
|
|
7
|
+
{ "time": "2021-10-12T16:00:00.000+02:00", "value": false, "countHours": 8 }
|
|
8
8
|
],
|
|
9
9
|
"config": {
|
|
10
10
|
"contextStorage": "default",
|
|
11
11
|
"doNotSplit": true,
|
|
12
12
|
"fromTime": "10",
|
|
13
13
|
"hoursOn": 4,
|
|
14
|
+
"maxPrice": null,
|
|
14
15
|
"outputIfNoSchedule": true,
|
|
15
16
|
"outputOutsidePeriod": false,
|
|
16
17
|
"sendCurrentValueWhenRescheduling": true,
|
|
@@ -3,15 +3,18 @@
|
|
|
3
3
|
"schedule": [
|
|
4
4
|
{
|
|
5
5
|
"time": "2021-12-15T00:00:00+01:00",
|
|
6
|
-
"value": false
|
|
6
|
+
"value": false,
|
|
7
|
+
"countHours": 22
|
|
7
8
|
},
|
|
8
9
|
{
|
|
9
10
|
"time": "2021-12-15T22:00:00+01:00",
|
|
10
|
-
"value": true
|
|
11
|
+
"value": true,
|
|
12
|
+
"countHours": 3
|
|
11
13
|
},
|
|
12
14
|
{
|
|
13
15
|
"time": "2021-12-16T01:00:00+01:00",
|
|
14
|
-
"value": false
|
|
16
|
+
"value": false,
|
|
17
|
+
"countHours": 23
|
|
15
18
|
}
|
|
16
19
|
],
|
|
17
20
|
"hours": [
|
|
@@ -310,6 +313,7 @@
|
|
|
310
313
|
"fromTime": "22",
|
|
311
314
|
"toTime": "08",
|
|
312
315
|
"hoursOn": 3,
|
|
316
|
+
"maxPrice": null,
|
|
313
317
|
"doNotSplit": true,
|
|
314
318
|
"sendCurrentValueWhenRescheduling": true,
|
|
315
319
|
"outputIfNoSchedule": false,
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schedule": [
|
|
3
|
-
{ "time": "2021-10-11T00:00:00.000+02:00", "value": true },
|
|
4
|
-
{ "time": "2021-10-11T06:00:00.000+02:00", "value": false },
|
|
5
|
-
{ "time": "2021-10-11T12:00:00.000+02:00", "value": true },
|
|
6
|
-
{ "time": "2021-10-11T14:00:00.000+02:00", "value": false },
|
|
7
|
-
{ "time": "2021-10-12T00:00:00.000+02:00", "value": true },
|
|
8
|
-
{ "time": "2021-10-12T07:00:00.000+02:00", "value": false },
|
|
9
|
-
{ "time": "2021-10-12T14:00:00.000+02:00", "value": true },
|
|
10
|
-
{ "time": "2021-10-12T15:00:00.000+02:00", "value": false }
|
|
3
|
+
{ "time": "2021-10-11T00:00:00.000+02:00", "value": true, "countHours": 6 },
|
|
4
|
+
{ "time": "2021-10-11T06:00:00.000+02:00", "value": false, "countHours": 6 },
|
|
5
|
+
{ "time": "2021-10-11T12:00:00.000+02:00", "value": true, "countHours": 2 },
|
|
6
|
+
{ "time": "2021-10-11T14:00:00.000+02:00", "value": false, "countHours": 10 },
|
|
7
|
+
{ "time": "2021-10-12T00:00:00.000+02:00", "value": true, "countHours": 7 },
|
|
8
|
+
{ "time": "2021-10-12T07:00:00.000+02:00", "value": false, "countHours": 7 },
|
|
9
|
+
{ "time": "2021-10-12T14:00:00.000+02:00", "value": true, "countHours": 1 },
|
|
10
|
+
{ "time": "2021-10-12T15:00:00.000+02:00", "value": false, "countHours": 9 }
|
|
11
11
|
],
|
|
12
12
|
"config": {
|
|
13
13
|
"contextStorage": "default",
|
|
14
14
|
"doNotSplit": false,
|
|
15
15
|
"fromTime": "00",
|
|
16
16
|
"hoursOn": 8,
|
|
17
|
+
"maxPrice": null,
|
|
17
18
|
"outputIfNoSchedule": true,
|
|
18
19
|
"outputOutsidePeriod": false,
|
|
19
20
|
"sendCurrentValueWhenRescheduling": true,
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schedule": [
|
|
3
|
-
{ "time": "2021-10-11T00:00:00.000+02:00", "value": true },
|
|
4
|
-
{ "time": "2021-10-11T10:00:00.000+02:00", "value": false },
|
|
5
|
-
{ "time": "2021-10-11T12:00:00.000+02:00", "value": true },
|
|
6
|
-
{ "time": "2021-10-11T14:00:00.000+02:00", "value": false },
|
|
7
|
-
{ "time": "2021-10-12T00:00:00.000+02:00", "value": true },
|
|
8
|
-
{ "time": "2021-10-12T08:00:00.000+02:00", "value": false },
|
|
9
|
-
{ "time": "2021-10-12T10:00:00.000+02:00", "value": true }
|
|
3
|
+
{ "time": "2021-10-11T00:00:00.000+02:00", "value": true, "countHours": 10 },
|
|
4
|
+
{ "time": "2021-10-11T10:00:00.000+02:00", "value": false, "countHours": 2 },
|
|
5
|
+
{ "time": "2021-10-11T12:00:00.000+02:00", "value": true, "countHours": 2 },
|
|
6
|
+
{ "time": "2021-10-11T14:00:00.000+02:00", "value": false, "countHours": 10 },
|
|
7
|
+
{ "time": "2021-10-12T00:00:00.000+02:00", "value": true, "countHours": 8 },
|
|
8
|
+
{ "time": "2021-10-12T08:00:00.000+02:00", "value": false, "countHours": 2 },
|
|
9
|
+
{ "time": "2021-10-12T10:00:00.000+02:00", "value": true, "countHours": 14 }
|
|
10
10
|
],
|
|
11
11
|
"config": {
|
|
12
12
|
"contextStorage": "default",
|
|
13
13
|
"doNotSplit": false,
|
|
14
14
|
"fromTime": "10",
|
|
15
15
|
"hoursOn": 10,
|
|
16
|
+
"maxPrice": null,
|
|
16
17
|
"outputIfNoSchedule": true,
|
|
17
18
|
"outputOutsidePeriod": false,
|
|
18
19
|
"sendCurrentValueWhenRescheduling": true,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schedule": [
|
|
3
|
+
{ "time": "2021-10-11T00:00:00.000+02:00", "value": false, "countHours": 12 },
|
|
4
|
+
{ "time": "2021-10-11T12:00:00.000+02:00", "value": true, "countHours": 3 },
|
|
5
|
+
{ "time": "2021-10-11T15:00:00.000+02:00", "value": false, "countHours": 21 },
|
|
6
|
+
{ "time": "2021-10-12T12:00:00.000+02:00", "value": true, "countHours": 4 },
|
|
7
|
+
{ "time": "2021-10-12T16:00:00.000+02:00", "value": false, "countHours": 3 },
|
|
8
|
+
{ "time": "2021-10-12T19:00:00.000+02:00", "value": true, "countHours": 1 },
|
|
9
|
+
{ "time": "2021-10-12T20:00:00.000+02:00", "value": false, "countHours": 4 }
|
|
10
|
+
],
|
|
11
|
+
"config": {
|
|
12
|
+
"contextStorage": "default",
|
|
13
|
+
"doNotSplit": false,
|
|
14
|
+
"fromTime": "10",
|
|
15
|
+
"hoursOn": 6,
|
|
16
|
+
"maxPrice": 0.51,
|
|
17
|
+
"outputIfNoSchedule": true,
|
|
18
|
+
"outputOutsidePeriod": false,
|
|
19
|
+
"sendCurrentValueWhenRescheduling": true,
|
|
20
|
+
"toTime": "20"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schedule": [
|
|
3
|
-
{ "time": "2021-10-11T00:00:00.000+02:00", "value": false },
|
|
4
|
-
{ "time": "2021-10-11T11:00:00.000+02:00", "value": true },
|
|
5
|
-
{ "time": "2021-10-11T17:00:00.000+02:00", "value": false },
|
|
6
|
-
{ "time": "2021-10-12T12:00:00.000+02:00", "value": true },
|
|
7
|
-
{ "time": "2021-10-12T16:00:00.000+02:00", "value": false },
|
|
8
|
-
{ "time": "2021-10-12T18:00:00.000+02:00", "value": true },
|
|
9
|
-
{ "time": "2021-10-12T20:00:00.000+02:00", "value": false }
|
|
3
|
+
{ "time": "2021-10-11T00:00:00.000+02:00", "value": false, "countHours": 11 },
|
|
4
|
+
{ "time": "2021-10-11T11:00:00.000+02:00", "value": true, "countHours": 6 },
|
|
5
|
+
{ "time": "2021-10-11T17:00:00.000+02:00", "value": false, "countHours": 19 },
|
|
6
|
+
{ "time": "2021-10-12T12:00:00.000+02:00", "value": true, "countHours": 4 },
|
|
7
|
+
{ "time": "2021-10-12T16:00:00.000+02:00", "value": false, "countHours": 2 },
|
|
8
|
+
{ "time": "2021-10-12T18:00:00.000+02:00", "value": true, "countHours": 2 },
|
|
9
|
+
{ "time": "2021-10-12T20:00:00.000+02:00", "value": false, "countHours": 4 }
|
|
10
10
|
],
|
|
11
11
|
"config": {
|
|
12
12
|
"contextStorage": "default",
|
|
13
13
|
"doNotSplit": false,
|
|
14
14
|
"fromTime": "10",
|
|
15
15
|
"hoursOn": 6,
|
|
16
|
+
"maxPrice": null,
|
|
16
17
|
"outputIfNoSchedule": true,
|
|
17
18
|
"outputOutsidePeriod": false,
|
|
18
19
|
"sendCurrentValueWhenRescheduling": true,
|
|
@@ -2,23 +2,28 @@
|
|
|
2
2
|
"schedule": [
|
|
3
3
|
{
|
|
4
4
|
"time": "2022-01-03T00:00:00+01:00",
|
|
5
|
-
"value": false
|
|
5
|
+
"value": false,
|
|
6
|
+
"countHours": 28
|
|
6
7
|
},
|
|
7
8
|
{
|
|
8
9
|
"time": "2022-01-04T04:00:00+01:00",
|
|
9
|
-
"value": true
|
|
10
|
+
"value": true,
|
|
11
|
+
"countHours": 1
|
|
10
12
|
},
|
|
11
13
|
{
|
|
12
14
|
"time": "2022-01-04T05:00:00+01:00",
|
|
13
|
-
"value": false
|
|
15
|
+
"value": false,
|
|
16
|
+
"countHours": 22
|
|
14
17
|
},
|
|
15
18
|
{
|
|
16
19
|
"time": "2022-01-05T03:00:00+01:00",
|
|
17
|
-
"value": true
|
|
20
|
+
"value": true,
|
|
21
|
+
"countHours": 1
|
|
18
22
|
},
|
|
19
23
|
{
|
|
20
24
|
"time": "2022-01-05T04:00:00+01:00",
|
|
21
|
-
"value": false
|
|
25
|
+
"value": false,
|
|
26
|
+
"countHours": 20
|
|
22
27
|
}
|
|
23
28
|
],
|
|
24
29
|
"hours": [
|
package/test/data/result.js
CHANGED
|
@@ -3,38 +3,47 @@ module.exports = {
|
|
|
3
3
|
{
|
|
4
4
|
time: "2021-06-20T01:50:00.000+02:00",
|
|
5
5
|
value: true,
|
|
6
|
+
countHours: 3,
|
|
6
7
|
},
|
|
7
8
|
{
|
|
8
9
|
time: "2021-06-20T01:50:00.030+02:00",
|
|
9
10
|
value: false,
|
|
11
|
+
countHours: 2,
|
|
10
12
|
},
|
|
11
13
|
{
|
|
12
14
|
time: "2021-06-20T01:50:00.050+02:00",
|
|
13
15
|
value: true,
|
|
16
|
+
countHours: 1,
|
|
14
17
|
},
|
|
15
18
|
{
|
|
16
19
|
time: "2021-06-20T01:50:00.060+02:00",
|
|
17
20
|
value: false,
|
|
21
|
+
countHours: 2,
|
|
18
22
|
},
|
|
19
23
|
{
|
|
20
24
|
time: "2021-06-20T01:50:00.080+02:00",
|
|
21
25
|
value: true,
|
|
26
|
+
countHours: 1,
|
|
22
27
|
},
|
|
23
28
|
{
|
|
24
29
|
time: "2021-06-20T01:50:00.090+02:00",
|
|
25
30
|
value: false,
|
|
31
|
+
countHours: 3,
|
|
26
32
|
},
|
|
27
33
|
{
|
|
28
34
|
time: "2021-06-20T01:50:00.120+02:00",
|
|
29
35
|
value: true,
|
|
36
|
+
countHours: 3,
|
|
30
37
|
},
|
|
31
38
|
{
|
|
32
39
|
time: "2021-06-20T01:50:00.150+02:00",
|
|
33
40
|
value: false,
|
|
41
|
+
countHours: 3,
|
|
34
42
|
},
|
|
35
43
|
{
|
|
36
44
|
time: "2021-06-20T01:50:00.180+02:00",
|
|
37
45
|
value: true,
|
|
46
|
+
countHours: 2,
|
|
38
47
|
},
|
|
39
48
|
],
|
|
40
49
|
hours: [
|
|
@@ -2,19 +2,23 @@
|
|
|
2
2
|
"schedule": [
|
|
3
3
|
{
|
|
4
4
|
"time": "2021-12-14T00:00:00.000+01:00",
|
|
5
|
-
"value": false
|
|
5
|
+
"value": false,
|
|
6
|
+
"countHours": 21
|
|
6
7
|
},
|
|
7
8
|
{
|
|
8
9
|
"time": "2021-12-14T21:00:00.000+01:00",
|
|
9
|
-
"value": true
|
|
10
|
+
"value": true,
|
|
11
|
+
"countHours": 3
|
|
10
12
|
},
|
|
11
13
|
{
|
|
12
14
|
"time": "2021-12-15T00:00:00.000+01:00",
|
|
13
|
-
"value": false
|
|
15
|
+
"value": false,
|
|
16
|
+
"countHours": 21
|
|
14
17
|
},
|
|
15
18
|
{
|
|
16
19
|
"time": "2021-12-15T21:00:00.000+01:00",
|
|
17
|
-
"value": true
|
|
20
|
+
"value": true,
|
|
21
|
+
"countHours": 3
|
|
18
22
|
}
|
|
19
23
|
],
|
|
20
24
|
"hours": [
|
|
@@ -313,6 +317,7 @@
|
|
|
313
317
|
"fromTime": "16",
|
|
314
318
|
"toTime": "00",
|
|
315
319
|
"hoursOn": 3,
|
|
320
|
+
"maxPrice": null,
|
|
316
321
|
"doNotSplit": false,
|
|
317
322
|
"sendCurrentValueWhenRescheduling": true,
|
|
318
323
|
"outputIfNoSchedule": false,
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
"schedule": [
|
|
3
3
|
{
|
|
4
4
|
"time": "2021-12-14T00:00:00.000+01:00",
|
|
5
|
-
"value": false
|
|
5
|
+
"value": false,
|
|
6
|
+
"countHours": 21
|
|
6
7
|
},
|
|
7
8
|
{
|
|
8
9
|
"time": "2021-12-14T21:00:00.000+01:00",
|
|
9
|
-
"value": true
|
|
10
|
+
"value": true,
|
|
11
|
+
"countHours": 3
|
|
10
12
|
}
|
|
11
13
|
],
|
|
12
14
|
"hours": [
|
|
@@ -161,6 +163,7 @@
|
|
|
161
163
|
"fromTime": "16",
|
|
162
164
|
"toTime": "00",
|
|
163
165
|
"hoursOn": 3,
|
|
166
|
+
"maxPrice": null,
|
|
164
167
|
"doNotSplit": false,
|
|
165
168
|
"sendCurrentValueWhenRescheduling": true,
|
|
166
169
|
"outputIfNoSchedule": false,
|
|
@@ -2,59 +2,73 @@
|
|
|
2
2
|
"schedule": [
|
|
3
3
|
{
|
|
4
4
|
"time": "2021-10-11T00:00:00.000+02:00",
|
|
5
|
-
"value": false
|
|
5
|
+
"value": false,
|
|
6
|
+
"countHours": 2
|
|
6
7
|
},
|
|
7
8
|
{
|
|
8
9
|
"time": "2021-10-11T02:00:00.000+02:00",
|
|
9
|
-
"value": true
|
|
10
|
+
"value": true,
|
|
11
|
+
"countHours": 5
|
|
10
12
|
},
|
|
11
13
|
{
|
|
12
14
|
"time": "2021-10-11T07:00:00.000+02:00",
|
|
13
|
-
"value": false
|
|
15
|
+
"value": false,
|
|
16
|
+
"countHours": 4
|
|
14
17
|
},
|
|
15
18
|
{
|
|
16
19
|
"time": "2021-10-11T11:00:00.000+02:00",
|
|
17
|
-
"value": true
|
|
20
|
+
"value": true,
|
|
21
|
+
"countHours": 7
|
|
18
22
|
},
|
|
19
23
|
{
|
|
20
24
|
"time": "2021-10-11T18:00:00.000+02:00",
|
|
21
|
-
"value": false
|
|
25
|
+
"value": false,
|
|
26
|
+
"countHours": 2
|
|
22
27
|
},
|
|
23
28
|
{
|
|
24
29
|
"time": "2021-10-11T20:00:00.000+02:00",
|
|
25
|
-
"value": true
|
|
30
|
+
"value": true,
|
|
31
|
+
"countHours": 1
|
|
26
32
|
},
|
|
27
33
|
{
|
|
28
34
|
"time": "2021-10-11T21:00:00.000+02:00",
|
|
29
|
-
"value": false
|
|
35
|
+
"value": false,
|
|
36
|
+
"countHours": 4
|
|
30
37
|
},
|
|
31
38
|
{
|
|
32
39
|
"time": "2021-10-12T01:00:00.000+02:00",
|
|
33
|
-
"value": true
|
|
40
|
+
"value": true,
|
|
41
|
+
"countHours": 8
|
|
34
42
|
},
|
|
35
43
|
{
|
|
36
44
|
"time": "2021-10-12T09:00:00.000+02:00",
|
|
37
|
-
"value": false
|
|
45
|
+
"value": false,
|
|
46
|
+
"countHours": 4
|
|
38
47
|
},
|
|
39
48
|
{
|
|
40
49
|
"time": "2021-10-12T13:00:00.000+02:00",
|
|
41
|
-
"value": true
|
|
50
|
+
"value": true,
|
|
51
|
+
"countHours": 3
|
|
42
52
|
},
|
|
43
53
|
{
|
|
44
54
|
"time": "2021-10-12T16:00:00.000+02:00",
|
|
45
|
-
"value": false
|
|
55
|
+
"value": false,
|
|
56
|
+
"countHours": 4
|
|
46
57
|
},
|
|
47
58
|
{
|
|
48
59
|
"time": "2021-10-12T20:00:00.000+02:00",
|
|
49
|
-
"value": true
|
|
60
|
+
"value": true,
|
|
61
|
+
"countHours": 2
|
|
50
62
|
},
|
|
51
63
|
{
|
|
52
64
|
"time": "2021-10-12T22:00:00.000+02:00",
|
|
53
|
-
"value": false
|
|
65
|
+
"value": false,
|
|
66
|
+
"countHours": 1
|
|
54
67
|
},
|
|
55
68
|
{
|
|
56
69
|
"time": "2021-10-12T23:00:00.000+02:00",
|
|
57
|
-
"value": true
|
|
70
|
+
"value": true,
|
|
71
|
+
"countHours": 1
|
|
58
72
|
}
|
|
59
73
|
],
|
|
60
74
|
"hours": [
|
package/test/power-saver.test.js
CHANGED
|
@@ -85,14 +85,17 @@ describe("power-saver Node", function () {
|
|
|
85
85
|
{
|
|
86
86
|
time: "2021-06-20T01:50:00.000+02:00",
|
|
87
87
|
value: true,
|
|
88
|
+
countHours: 7,
|
|
88
89
|
},
|
|
89
90
|
{
|
|
90
91
|
time: "2021-06-20T01:50:00.070+02:00",
|
|
91
92
|
value: false,
|
|
93
|
+
countHours: 2,
|
|
92
94
|
},
|
|
93
95
|
{
|
|
94
96
|
time: "2021-06-20T01:50:00.090+02:00",
|
|
95
97
|
value: true,
|
|
98
|
+
countHours: 1,
|
|
96
99
|
},
|
|
97
100
|
];
|
|
98
101
|
const flow = makeFlow(4, 2);
|
|
@@ -121,14 +124,17 @@ describe("power-saver Node", function () {
|
|
|
121
124
|
{
|
|
122
125
|
time: "2021-06-20T01:50:00.000+02:00",
|
|
123
126
|
value: true,
|
|
127
|
+
countHours: 7,
|
|
124
128
|
},
|
|
125
129
|
{
|
|
126
130
|
time: "2021-06-20T01:50:00.070+02:00",
|
|
127
131
|
value: false,
|
|
132
|
+
countHours: 4,
|
|
128
133
|
},
|
|
129
134
|
{
|
|
130
135
|
time: "2021-06-20T01:50:00.110+02:00",
|
|
131
136
|
value: true,
|
|
137
|
+
countHours: 9,
|
|
132
138
|
},
|
|
133
139
|
];
|
|
134
140
|
const flow = makeFlow(4, 2);
|
|
@@ -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
|
|