node-red-contrib-power-saver 3.0.0 → 3.0.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/changelog/README.md +6 -0
- package/docs/contribute/README.md +1 -1
- package/docs/guide/README.md +10 -1
- package/package.json +1 -1
- package/src/elvia/elvia-config.html +3 -1
- package/src/elvia/elvia-config.js +7 -13
- package/src/elvia/elvia-tariff-types.js +8 -6
- package/src/elvia/elvia-tariff.js +1 -5
- package/src/handle-input.js +7 -4
- package/src/power-saver.html +8 -8
- package/src/strategy-best-save.html +8 -8
- package/src/strategy-lowest-price.html +10 -10
- package/test/strategy-lowest-price.test.js +134 -0
package/docs/changelog/README.md
CHANGED
|
@@ -6,6 +6,12 @@ sidebar: "auto"
|
|
|
6
6
|
|
|
7
7
|
List the most significant changes, starting in version 1.0.9.
|
|
8
8
|
|
|
9
|
+
## 3.0.1
|
|
10
|
+
|
|
11
|
+
- Fix so elvia subscripion key is stored as credential
|
|
12
|
+
- Fix bug on config for strategy nodes. Config was not saved properly.
|
|
13
|
+
- Remove double output bug, and better handling when hoursOn > period
|
|
14
|
+
|
|
9
15
|
## 3.0.0
|
|
10
16
|
|
|
11
17
|
- Deprecating old Power Saver node, adding multiple new nodes.
|
|
@@ -32,7 +32,7 @@ It would be very nice to get more examples into the documentation. If you have m
|
|
|
32
32
|
|
|
33
33
|
## Bug reports
|
|
34
34
|
|
|
35
|
-
If you find a bug, please describe it thouroghly and make a [GitHub issue](https://github.com/ottopaulsen/node-red-contrib-power-saver/issues). If the bug is related to the scheduling, please provide the full output from output 3 on the strategy node.
|
|
35
|
+
If you find a bug, please describe it thouroghly and make a [GitHub issue](https://github.com/ottopaulsen/node-red-contrib-power-saver/issues). If the bug is related to the scheduling, **please provide the full output from output 3** on the strategy node.
|
|
36
36
|
|
|
37
37
|
## Ideas
|
|
38
38
|
|
package/docs/guide/README.md
CHANGED
|
@@ -174,6 +174,15 @@ Example using Home Assistant:
|
|
|
174
174
|
|
|
175
175
|

|
|
176
176
|
|
|
177
|
+
::: tip Use output
|
|
178
|
+
There are many ways you can use the output:
|
|
179
|
+
|
|
180
|
+
- Turn on/off a switch
|
|
181
|
+
- Set a termostat up, down or to specific values
|
|
182
|
+
- Change setting of a dimmer
|
|
183
|
+
- Send a notification
|
|
184
|
+
:::
|
|
185
|
+
|
|
177
186
|
### Display schedule
|
|
178
187
|
|
|
179
188
|
**Output 3** can be used to print or dispay the calculated schedule. If you just want to see it, send it to a debug node. You can also use it to display the result as graphs in HA.
|
|
@@ -190,4 +199,4 @@ The `Power Saver` node from v2 is still here, and it is working exactly as befor
|
|
|
190
199
|
|
|
191
200
|

|
|
192
201
|
|
|
193
|
-
See more details in the [documentation for the `
|
|
202
|
+
See more details in the [documentation for the `ps-strategy-best-save`](../nodes/ps-strategy-best-save.md) node.
|
package/package.json
CHANGED
|
@@ -4,22 +4,16 @@ module.exports = function (RED) {
|
|
|
4
4
|
function ElviaConfigNode(config) {
|
|
5
5
|
RED.nodes.createNode(this, config);
|
|
6
6
|
|
|
7
|
+
this.elviaConfig = RED.nodes.getNode(config.elviaConfig);
|
|
8
|
+
|
|
7
9
|
// Store config in global configList
|
|
8
10
|
const configList = this.context().global.get("elviaConfigList") || [];
|
|
9
11
|
configList.push(config);
|
|
10
12
|
this.context().global.set("elviaConfigList", configList);
|
|
11
|
-
|
|
12
|
-
const node = this;
|
|
13
|
-
|
|
14
|
-
RED.httpAdmin.get("/elvia-tariff-types", RED.auth.needsPermission("ps-elvia-config.read"), function (req, res) {
|
|
15
|
-
const configList = node.context().global.get("elviaConfigList") || [];
|
|
16
|
-
const configId = req.query.configId;
|
|
17
|
-
const key = configList.find((c) => c.id == configId)?.elviaSubscriptionKey;
|
|
18
|
-
console.log("Getting tariff types for key " + key);
|
|
19
|
-
getTariffTypes(null, key).then((json) => {
|
|
20
|
-
res.json(json);
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
13
|
}
|
|
24
|
-
RED.nodes.registerType("ps-elvia-config", ElviaConfigNode
|
|
14
|
+
RED.nodes.registerType("ps-elvia-config", ElviaConfigNode, {
|
|
15
|
+
credentials: {
|
|
16
|
+
elviaSubscriptionKey: { type: "text" },
|
|
17
|
+
},
|
|
18
|
+
});
|
|
25
19
|
};
|
|
@@ -4,19 +4,21 @@ module.exports = function (RED) {
|
|
|
4
4
|
function PsElviaTariffTypesNode(config) {
|
|
5
5
|
RED.nodes.createNode(this, config);
|
|
6
6
|
this.elviaConfig = RED.nodes.getNode(config.elviaConfig);
|
|
7
|
+
const key = this.elviaConfig.credentials.elviaSubscriptionKey;
|
|
7
8
|
const node = this;
|
|
8
|
-
|
|
9
|
-
const configList = node.context().global.get("elviaConfigList") || [];
|
|
10
|
-
const key = configList.find((c) => c.id == node.elviaConfig.id)?.elviaSubscriptionKey;
|
|
11
9
|
ping(node, key);
|
|
12
10
|
|
|
13
|
-
node.on("input", function (
|
|
14
|
-
const configList = node.context().global.get("elviaConfigList") || [];
|
|
15
|
-
const key = configList.find((c) => c.id == node.elviaConfig.id)?.elviaSubscriptionKey;
|
|
11
|
+
node.on("input", function () {
|
|
16
12
|
getTariffTypes(node, key).then((json) => {
|
|
17
13
|
node.send([{ payload: json }]);
|
|
18
14
|
});
|
|
19
15
|
});
|
|
16
|
+
|
|
17
|
+
RED.httpAdmin.get("/elvia-tariff-types", RED.auth.needsPermission("ps-elvia-config.read"), function (req, res) {
|
|
18
|
+
getTariffTypes(null, key).then((json) => {
|
|
19
|
+
res.json(json);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
RED.nodes.registerType("ps-elvia-tariff-types", PsElviaTariffTypesNode);
|
|
@@ -5,17 +5,13 @@ module.exports = function (RED) {
|
|
|
5
5
|
function PsElviaTariffNode(config) {
|
|
6
6
|
RED.nodes.createNode(this, config);
|
|
7
7
|
this.elviaConfig = RED.nodes.getNode(config.elviaConfig);
|
|
8
|
+
const key = this.elviaConfig.credentials.elviaSubscriptionKey;
|
|
8
9
|
this.tariffKey = config.tariffKey;
|
|
9
10
|
this.range = config.range;
|
|
10
11
|
const node = this;
|
|
11
|
-
|
|
12
|
-
const configList = node.context().global.get("elviaConfigList") || [];
|
|
13
|
-
const key = configList.find((c) => c.id == node.elviaConfig.id)?.elviaSubscriptionKey;
|
|
14
12
|
ping(node, key);
|
|
15
13
|
|
|
16
14
|
node.on("input", function () {
|
|
17
|
-
const configList = node.context().global.get("elviaConfigList") || [];
|
|
18
|
-
const key = configList.find((c) => c.id == node.elviaConfig.id)?.elviaSubscriptionKey;
|
|
19
15
|
getTariff(node, key, node.tariffKey, node.range).then((json) => {
|
|
20
16
|
node.send([{ payload: json }]);
|
|
21
17
|
});
|
package/src/handle-input.js
CHANGED
|
@@ -45,7 +45,8 @@ function handleStrategyInput(node, msg, doPlanning) {
|
|
|
45
45
|
// Find current output, and set output (if configured to do)
|
|
46
46
|
const pastSchedule = plan.schedule.filter((entry) => DateTime.fromISO(entry.time) <= planFromTime);
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
const sendNow = node.sendCurrentValueWhenRescheduling && pastSchedule.length > 0;
|
|
49
|
+
if (sendNow) {
|
|
49
50
|
const currentValue = pastSchedule[pastSchedule.length - 1].value;
|
|
50
51
|
output1 = currentValue ? { payload: true } : null;
|
|
51
52
|
output2 = currentValue ? null : { payload: false };
|
|
@@ -58,7 +59,7 @@ function handleStrategyInput(node, msg, doPlanning) {
|
|
|
58
59
|
node.send([output1, output2, output3]);
|
|
59
60
|
|
|
60
61
|
// Run schedule
|
|
61
|
-
node.schedulingTimeout = runSchedule(node, plan.schedule, planFromTime);
|
|
62
|
+
node.schedulingTimeout = runSchedule(node, plan.schedule, planFromTime, sendNow);
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
function getPriceData(node, msg) {
|
|
@@ -71,7 +72,7 @@ function getPriceData(node, msg) {
|
|
|
71
72
|
return priceData;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
function runSchedule(node, schedule, time) {
|
|
75
|
+
function runSchedule(node, schedule, time, currentSent = false) {
|
|
75
76
|
let currentTime = time;
|
|
76
77
|
let remainingSchedule = schedule.filter((entry) => {
|
|
77
78
|
return DateTime.fromISO(entry.time) > DateTime.fromISO(time);
|
|
@@ -94,7 +95,9 @@ function runSchedule(node, schedule, time) {
|
|
|
94
95
|
const message = "No schedule";
|
|
95
96
|
node.warn(message);
|
|
96
97
|
node.status({ fill: "red", shape: "dot", text: message });
|
|
97
|
-
|
|
98
|
+
if (!currentSent) {
|
|
99
|
+
sendSwitch(node, node.outputIfNoSchedule);
|
|
100
|
+
}
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
103
|
|
package/src/power-saver.html
CHANGED
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
// validate: RED.validators.number(),
|
|
26
26
|
align: "left",
|
|
27
27
|
},
|
|
28
|
-
outputIfNoSchedule: { value: true, required: true, align: "left" },
|
|
28
|
+
outputIfNoSchedule: { value: "true", required: true, align: "left" },
|
|
29
29
|
scheduleOnlyFromCurrentTime: {
|
|
30
|
-
value: true,
|
|
30
|
+
value: "true",
|
|
31
31
|
required: true,
|
|
32
32
|
align: "left",
|
|
33
33
|
},
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
{
|
|
47
47
|
value: "onoff",
|
|
48
48
|
options: [
|
|
49
|
-
{ value: true, label: "On" },
|
|
50
|
-
{ value: false, label: "Off" },
|
|
49
|
+
{ value: "true", label: "On" },
|
|
50
|
+
{ value: "false", label: "Off" },
|
|
51
51
|
],
|
|
52
52
|
},
|
|
53
53
|
],
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
{
|
|
58
58
|
value: "nowOrStart",
|
|
59
59
|
options: [
|
|
60
|
-
{ value: false, label: "Whole data set" },
|
|
61
|
-
{ value: true, label: "From current hour" },
|
|
60
|
+
{ value: "false", label: "Whole data set" },
|
|
61
|
+
{ value: "true", label: "From current hour" },
|
|
62
62
|
],
|
|
63
63
|
},
|
|
64
64
|
],
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
</div>
|
|
91
91
|
<div class="form-row">
|
|
92
92
|
<label for="node-input-scheduleOnlyFromCurrentTime">Schedule for</label>
|
|
93
|
-
<input type="
|
|
93
|
+
<input type="text" id="node-input-scheduleOnlyFromCurrentTime" style="width: 160px">
|
|
94
94
|
</label>
|
|
95
95
|
</div>
|
|
96
96
|
<h3>Output</h3>
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
</div>
|
|
105
105
|
<div class="form-row">
|
|
106
106
|
<label for="node-input-outputIfNoSchedule">If no schedule, send</label>
|
|
107
|
-
<input type="
|
|
107
|
+
<input type="text" id="node-input-outputIfNoSchedule" style="width: 80px">
|
|
108
108
|
</label>
|
|
109
109
|
</div>
|
|
110
110
|
</script>
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
// validate: RED.validators.number(),
|
|
26
26
|
align: "left",
|
|
27
27
|
},
|
|
28
|
-
outputIfNoSchedule: { value: true, required: true, align: "left" },
|
|
28
|
+
outputIfNoSchedule: { value: "true", required: true, align: "left" },
|
|
29
29
|
scheduleOnlyFromCurrentTime: {
|
|
30
|
-
value: true,
|
|
30
|
+
value: "true",
|
|
31
31
|
required: true,
|
|
32
32
|
align: "left",
|
|
33
33
|
},
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
{
|
|
47
47
|
value: "onoff",
|
|
48
48
|
options: [
|
|
49
|
-
{ value: true, label: "On" },
|
|
50
|
-
{ value: false, label: "Off" },
|
|
49
|
+
{ value: "true", label: "On" },
|
|
50
|
+
{ value: "false", label: "Off" },
|
|
51
51
|
],
|
|
52
52
|
},
|
|
53
53
|
],
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
{
|
|
58
58
|
value: "nowOrStart",
|
|
59
59
|
options: [
|
|
60
|
-
{ value: false, label: "Whole data set" },
|
|
61
|
-
{ value: true, label: "From current hour" },
|
|
60
|
+
{ value: "false", label: "Whole data set" },
|
|
61
|
+
{ value: "true", label: "From current hour" },
|
|
62
62
|
],
|
|
63
63
|
},
|
|
64
64
|
],
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
</div>
|
|
91
91
|
<div class="form-row">
|
|
92
92
|
<label for="node-input-scheduleOnlyFromCurrentTime">Schedule for</label>
|
|
93
|
-
<input type="
|
|
93
|
+
<input type="text" id="node-input-scheduleOnlyFromCurrentTime" style="width: 160px">
|
|
94
94
|
</label>
|
|
95
95
|
</div>
|
|
96
96
|
<h3>Output</h3>
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
</div>
|
|
105
105
|
<div class="form-row">
|
|
106
106
|
<label for="node-input-outputIfNoSchedule">If no schedule, send</label>
|
|
107
|
-
<input type="
|
|
107
|
+
<input type="text" id="node-input-outputIfNoSchedule" style="width: 80px">
|
|
108
108
|
</label>
|
|
109
109
|
</div>
|
|
110
110
|
</script>
|
|
@@ -44,17 +44,17 @@
|
|
|
44
44
|
required: true,
|
|
45
45
|
},
|
|
46
46
|
doNotSplit: {
|
|
47
|
-
value: false,
|
|
47
|
+
value: "false",
|
|
48
48
|
required: true,
|
|
49
49
|
align: "left",
|
|
50
50
|
},
|
|
51
51
|
sendCurrentValueWhenRescheduling: {
|
|
52
|
-
value: true,
|
|
52
|
+
value: "true",
|
|
53
53
|
required: true,
|
|
54
54
|
align: "left",
|
|
55
55
|
},
|
|
56
|
-
outputIfNoSchedule: { value: true, required: true, align: "left" },
|
|
57
|
-
outputOutsidePeriod: { value: false, required: true, align: "left" },
|
|
56
|
+
outputIfNoSchedule: { value: "true", required: true, align: "left" },
|
|
57
|
+
outputOutsidePeriod: { value: "false", required: true, align: "left" },
|
|
58
58
|
},
|
|
59
59
|
inputs: 1,
|
|
60
60
|
outputs: 3,
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
{
|
|
71
71
|
value: "onoff",
|
|
72
72
|
options: [
|
|
73
|
-
{ value: true, label: "On" },
|
|
74
|
-
{ value: false, label: "Off" },
|
|
73
|
+
{ value: "true", label: "On" },
|
|
74
|
+
{ value: "false", label: "Off" },
|
|
75
75
|
],
|
|
76
76
|
},
|
|
77
77
|
],
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
{
|
|
82
82
|
value: "onoff",
|
|
83
83
|
options: [
|
|
84
|
-
{ value: true, label: "On" },
|
|
85
|
-
{ value: false, label: "Off" },
|
|
84
|
+
{ value: "true", label: "On" },
|
|
85
|
+
{ value: "false", label: "Off" },
|
|
86
86
|
],
|
|
87
87
|
},
|
|
88
88
|
],
|
|
@@ -151,12 +151,12 @@
|
|
|
151
151
|
</div>
|
|
152
152
|
<div class="form-row">
|
|
153
153
|
<label for="node-input-outputIfNoSchedule">If no schedule, send</label>
|
|
154
|
-
<input type="
|
|
154
|
+
<input type="text" id="node-input-outputIfNoSchedule" style="width: 80px">
|
|
155
155
|
</label>
|
|
156
156
|
</div>
|
|
157
157
|
<div class="form-row">
|
|
158
158
|
<label for="node-input-outputIfNoSchedule">Outside period, send</label>
|
|
159
|
-
<input type="
|
|
159
|
+
<input type="text" id="node-input-outputOutsidePeriod" style="width: 80px">
|
|
160
160
|
</label>
|
|
161
161
|
</div>
|
|
162
162
|
</script>
|
|
@@ -4,6 +4,7 @@ const expect = require("expect");
|
|
|
4
4
|
const helper = require("node-red-node-test-helper");
|
|
5
5
|
const lowestPrice = require("../src/strategy-lowest-price.js");
|
|
6
6
|
const prices = require("./data/converted-prices.json");
|
|
7
|
+
const { testPlan: plan } = require("./test-utils");
|
|
7
8
|
|
|
8
9
|
helper.init(require.resolve("node-red"));
|
|
9
10
|
|
|
@@ -304,6 +305,139 @@ describe("ps-strategy-lowest-price node", function () {
|
|
|
304
305
|
n1.receive({ payload: makePayload(prices, time) });
|
|
305
306
|
});
|
|
306
307
|
});
|
|
308
|
+
|
|
309
|
+
it("should work with data for only current day", function (done) {
|
|
310
|
+
const oneDayPrices = {};
|
|
311
|
+
oneDayPrices.priceData = prices.priceData.filter((d) => d.start.startsWith("2021-10-11"));
|
|
312
|
+
const result = [
|
|
313
|
+
{ time: "2021-10-11T00:00:00.000+02:00", value: false },
|
|
314
|
+
{ time: "2021-10-11T12:00:00.000+02:00", value: true },
|
|
315
|
+
{ time: "2021-10-11T13:00:00.000+02:00", value: false },
|
|
316
|
+
];
|
|
317
|
+
const flow = makeFlow(1);
|
|
318
|
+
helper.load(lowestPrice, flow, function () {
|
|
319
|
+
const n1 = helper.getNode("n1");
|
|
320
|
+
const n2 = helper.getNode("n2");
|
|
321
|
+
const n3 = helper.getNode("n3");
|
|
322
|
+
const n4 = helper.getNode("n4");
|
|
323
|
+
n2.on("input", function (msg) {
|
|
324
|
+
expect(msg.payload).toHaveProperty("schedule", result);
|
|
325
|
+
n1.warn.should.not.be.called;
|
|
326
|
+
done();
|
|
327
|
+
});
|
|
328
|
+
n3.on("input", function (msg) {
|
|
329
|
+
console.log("n3 inout: " + msg);
|
|
330
|
+
expect(msg.payload).toEqual(true);
|
|
331
|
+
});
|
|
332
|
+
n4.on("input", function (msg) {
|
|
333
|
+
console.log("n4 inout: " + msg);
|
|
334
|
+
expect(msg.payload).toEqual(false);
|
|
335
|
+
});
|
|
336
|
+
const time = DateTime.fromISO(prices.priceData[10].start);
|
|
337
|
+
n1.receive({ payload: makePayload(oneDayPrices, time) });
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("should handle hours on > period", function (done) {
|
|
342
|
+
const result = [{ time: "2021-10-11T00:00:00.000+02:00", value: true }];
|
|
343
|
+
const flow = [
|
|
344
|
+
{
|
|
345
|
+
id: "n1",
|
|
346
|
+
type: "ps-strategy-lowest-price",
|
|
347
|
+
name: "test name",
|
|
348
|
+
fromTime: "17",
|
|
349
|
+
toTime: "22",
|
|
350
|
+
hoursOn: 6,
|
|
351
|
+
doNotSplit: true,
|
|
352
|
+
sendCurrentValueWhenRescheduling: true,
|
|
353
|
+
outputIfNoSchedule: false,
|
|
354
|
+
outputOutsidePeriod: true,
|
|
355
|
+
wires: [["n3"], ["n4"], ["n2"]],
|
|
356
|
+
},
|
|
357
|
+
{ id: "n2", type: "helper" },
|
|
358
|
+
{ id: "n3", type: "helper" },
|
|
359
|
+
{ id: "n4", type: "helper" },
|
|
360
|
+
];
|
|
361
|
+
helper.load(lowestPrice, flow, function () {
|
|
362
|
+
const n1 = helper.getNode("n1");
|
|
363
|
+
const n2 = helper.getNode("n2");
|
|
364
|
+
const n3 = helper.getNode("n3");
|
|
365
|
+
const n4 = helper.getNode("n4");
|
|
366
|
+
let countOn = 0;
|
|
367
|
+
let countOff = 0;
|
|
368
|
+
n2.on("input", function (msg) {
|
|
369
|
+
expect(msg.payload).toHaveProperty("schedule", result);
|
|
370
|
+
n1.warn.should.not.be.called;
|
|
371
|
+
setTimeout(() => {
|
|
372
|
+
expect(countOn).toEqual(1);
|
|
373
|
+
expect(countOff).toEqual(0);
|
|
374
|
+
done();
|
|
375
|
+
}, 100);
|
|
376
|
+
});
|
|
377
|
+
n3.on("input", function (msg) {
|
|
378
|
+
countOn++;
|
|
379
|
+
});
|
|
380
|
+
n4.on("input", function (msg) {
|
|
381
|
+
countOff++;
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
const time = DateTime.fromISO(prices.priceData[10].start);
|
|
385
|
+
n1.receive({ payload: makePayload(prices, time) });
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
it("should handle hours on > period, false outside", function (done) {
|
|
389
|
+
const result = [
|
|
390
|
+
{ time: "2021-10-11T00:00:00.000+02:00", value: false },
|
|
391
|
+
{ time: "2021-10-11T17:00:00.000+02:00", value: true },
|
|
392
|
+
{ time: "2021-10-11T22:00:00.000+02:00", value: false },
|
|
393
|
+
{ time: "2021-10-12T17:00:00.000+02:00", value: true },
|
|
394
|
+
{ time: "2021-10-12T22:00:00.000+02:00", value: false },
|
|
395
|
+
];
|
|
396
|
+
const flow = [
|
|
397
|
+
{
|
|
398
|
+
id: "n1",
|
|
399
|
+
type: "ps-strategy-lowest-price",
|
|
400
|
+
name: "test name",
|
|
401
|
+
fromTime: "17",
|
|
402
|
+
toTime: "22",
|
|
403
|
+
hoursOn: 6,
|
|
404
|
+
doNotSplit: true,
|
|
405
|
+
sendCurrentValueWhenRescheduling: true,
|
|
406
|
+
outputIfNoSchedule: true,
|
|
407
|
+
outputOutsidePeriod: false,
|
|
408
|
+
wires: [["n3"], ["n4"], ["n2"]],
|
|
409
|
+
},
|
|
410
|
+
{ id: "n2", type: "helper" },
|
|
411
|
+
{ id: "n3", type: "helper" },
|
|
412
|
+
{ id: "n4", type: "helper" },
|
|
413
|
+
];
|
|
414
|
+
helper.load(lowestPrice, flow, function () {
|
|
415
|
+
const n1 = helper.getNode("n1");
|
|
416
|
+
const n2 = helper.getNode("n2");
|
|
417
|
+
const n3 = helper.getNode("n3");
|
|
418
|
+
const n4 = helper.getNode("n4");
|
|
419
|
+
let countOn = 0;
|
|
420
|
+
let countOff = 0;
|
|
421
|
+
n2.on("input", function (msg) {
|
|
422
|
+
expect(msg.payload).toHaveProperty("schedule", result);
|
|
423
|
+
n1.warn.should.not.be.called;
|
|
424
|
+
setTimeout(() => {
|
|
425
|
+
expect(countOn).toEqual(0);
|
|
426
|
+
expect(countOff).toEqual(1);
|
|
427
|
+
done();
|
|
428
|
+
}, 100);
|
|
429
|
+
});
|
|
430
|
+
n3.on("input", function (msg) {
|
|
431
|
+
countOn++;
|
|
432
|
+
});
|
|
433
|
+
n4.on("input", function (msg) {
|
|
434
|
+
countOff++;
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
const time = DateTime.fromISO(prices.priceData[10].start);
|
|
438
|
+
n1.receive({ payload: makePayload(prices, time) });
|
|
439
|
+
});
|
|
440
|
+
});
|
|
307
441
|
});
|
|
308
442
|
|
|
309
443
|
function makeFlow(hoursOn) {
|