node-red-contrib-power-saver 1.0.6 → 2.0.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.
@@ -0,0 +1,351 @@
1
+ {
2
+ "schedule": [
3
+ {
4
+ "time": "2021-10-11T00:00:00.000+02:00",
5
+ "value": false
6
+ },
7
+ {
8
+ "time": "2021-10-11T02:00:00.000+02:00",
9
+ "value": true
10
+ },
11
+ {
12
+ "time": "2021-10-11T07:00:00.000+02:00",
13
+ "value": false
14
+ },
15
+ {
16
+ "time": "2021-10-11T11:00:00.000+02:00",
17
+ "value": true
18
+ },
19
+ {
20
+ "time": "2021-10-11T18:00:00.000+02:00",
21
+ "value": false
22
+ },
23
+ {
24
+ "time": "2021-10-11T20:00:00.000+02:00",
25
+ "value": true
26
+ },
27
+ {
28
+ "time": "2021-10-11T21:00:00.000+02:00",
29
+ "value": false
30
+ },
31
+ {
32
+ "time": "2021-10-12T01:00:00.000+02:00",
33
+ "value": true
34
+ },
35
+ {
36
+ "time": "2021-10-12T09:00:00.000+02:00",
37
+ "value": false
38
+ },
39
+ {
40
+ "time": "2021-10-12T13:00:00.000+02:00",
41
+ "value": true
42
+ },
43
+ {
44
+ "time": "2021-10-12T16:00:00.000+02:00",
45
+ "value": false
46
+ },
47
+ {
48
+ "time": "2021-10-12T20:00:00.000+02:00",
49
+ "value": true
50
+ },
51
+ {
52
+ "time": "2021-10-12T22:00:00.000+02:00",
53
+ "value": false
54
+ },
55
+ {
56
+ "time": "2021-10-12T23:00:00.000+02:00",
57
+ "value": true
58
+ }
59
+ ],
60
+ "hours": [
61
+ {
62
+ "price": 0.2494,
63
+ "onOff": false,
64
+ "start": "2021-10-11T00:00:00.000+02:00",
65
+ "saving": 0.0395
66
+ },
67
+ {
68
+ "price": 0.2209,
69
+ "onOff": false,
70
+ "start": "2021-10-11T01:00:00.000+02:00",
71
+ "saving": 0.011
72
+ },
73
+ {
74
+ "price": 0.2099,
75
+ "onOff": true,
76
+ "start": "2021-10-11T02:00:00.000+02:00",
77
+ "saving": null
78
+ },
79
+ {
80
+ "price": 0.219,
81
+ "onOff": true,
82
+ "start": "2021-10-11T03:00:00.000+02:00",
83
+ "saving": null
84
+ },
85
+ {
86
+ "price": 0.2614,
87
+ "onOff": true,
88
+ "start": "2021-10-11T04:00:00.000+02:00",
89
+ "saving": null
90
+ },
91
+ {
92
+ "price": 0.4426,
93
+ "onOff": true,
94
+ "start": "2021-10-11T05:00:00.000+02:00",
95
+ "saving": null
96
+ },
97
+ {
98
+ "price": 0.5433,
99
+ "onOff": true,
100
+ "start": "2021-10-11T06:00:00.000+02:00",
101
+ "saving": null
102
+ },
103
+ {
104
+ "price": 0.5667,
105
+ "onOff": false,
106
+ "start": "2021-10-11T07:00:00.000+02:00",
107
+ "saving": 0.0543
108
+ },
109
+ {
110
+ "price": 0.5847,
111
+ "onOff": false,
112
+ "start": "2021-10-11T08:00:00.000+02:00",
113
+ "saving": 0.0723
114
+ },
115
+ {
116
+ "price": 0.5762,
117
+ "onOff": false,
118
+ "start": "2021-10-11T09:00:00.000+02:00",
119
+ "saving": 0.0638
120
+ },
121
+ {
122
+ "price": 0.5391,
123
+ "onOff": false,
124
+ "start": "2021-10-11T10:00:00.000+02:00",
125
+ "saving": 0.0267
126
+ },
127
+ {
128
+ "price": 0.5124,
129
+ "onOff": true,
130
+ "start": "2021-10-11T11:00:00.000+02:00",
131
+ "saving": null
132
+ },
133
+ {
134
+ "price": 0.504,
135
+ "onOff": true,
136
+ "start": "2021-10-11T12:00:00.000+02:00",
137
+ "saving": null
138
+ },
139
+ {
140
+ "price": 0.5057,
141
+ "onOff": true,
142
+ "start": "2021-10-11T13:00:00.000+02:00",
143
+ "saving": null
144
+ },
145
+ {
146
+ "price": 0.5066,
147
+ "onOff": true,
148
+ "start": "2021-10-11T14:00:00.000+02:00",
149
+ "saving": null
150
+ },
151
+ {
152
+ "price": 0.5136,
153
+ "onOff": true,
154
+ "start": "2021-10-11T15:00:00.000+02:00",
155
+ "saving": null
156
+ },
157
+ {
158
+ "price": 0.5143,
159
+ "onOff": true,
160
+ "start": "2021-10-11T16:00:00.000+02:00",
161
+ "saving": null
162
+ },
163
+ {
164
+ "price": 0.5306,
165
+ "onOff": true,
166
+ "start": "2021-10-11T17:00:00.000+02:00",
167
+ "saving": null
168
+ },
169
+ {
170
+ "price": 0.5534,
171
+ "onOff": false,
172
+ "start": "2021-10-11T18:00:00.000+02:00",
173
+ "saving": 0.0043
174
+ },
175
+ {
176
+ "price": 0.5511,
177
+ "onOff": false,
178
+ "start": "2021-10-11T19:00:00.000+02:00",
179
+ "saving": 0.002
180
+ },
181
+ {
182
+ "price": 0.5491,
183
+ "onOff": true,
184
+ "start": "2021-10-11T20:00:00.000+02:00",
185
+ "saving": null
186
+ },
187
+ {
188
+ "price": 0.5485,
189
+ "onOff": false,
190
+ "start": "2021-10-11T21:00:00.000+02:00",
191
+ "saving": 0.1289
192
+ },
193
+ {
194
+ "price": 0.5481,
195
+ "onOff": false,
196
+ "start": "2021-10-11T22:00:00.000+02:00",
197
+ "saving": 0.1285
198
+ },
199
+ {
200
+ "price": 0.5218,
201
+ "onOff": false,
202
+ "start": "2021-10-11T23:00:00.000+02:00",
203
+ "saving": 0.1022
204
+ },
205
+ {
206
+ "price": 0.4533,
207
+ "onOff": false,
208
+ "start": "2021-10-12T00:00:00.000+02:00",
209
+ "saving": 0.0337
210
+ },
211
+ {
212
+ "price": 0.4196,
213
+ "onOff": true,
214
+ "start": "2021-10-12T01:00:00.000+02:00",
215
+ "saving": null
216
+ },
217
+ {
218
+ "price": 0.4037,
219
+ "onOff": true,
220
+ "start": "2021-10-12T02:00:00.000+02:00",
221
+ "saving": null
222
+ },
223
+ {
224
+ "price": 0.3829,
225
+ "onOff": true,
226
+ "start": "2021-10-12T03:00:00.000+02:00",
227
+ "saving": null
228
+ },
229
+ {
230
+ "price": 0.4555,
231
+ "onOff": true,
232
+ "start": "2021-10-12T04:00:00.000+02:00",
233
+ "saving": null
234
+ },
235
+ {
236
+ "price": 0.4721,
237
+ "onOff": true,
238
+ "start": "2021-10-12T05:00:00.000+02:00",
239
+ "saving": null
240
+ },
241
+ {
242
+ "price": 0.4903,
243
+ "onOff": true,
244
+ "start": "2021-10-12T06:00:00.000+02:00",
245
+ "saving": null
246
+ },
247
+ {
248
+ "price": 0.5028,
249
+ "onOff": true,
250
+ "start": "2021-10-12T07:00:00.000+02:00",
251
+ "saving": null
252
+ },
253
+ {
254
+ "price": 0.5163,
255
+ "onOff": true,
256
+ "start": "2021-10-12T08:00:00.000+02:00",
257
+ "saving": null
258
+ },
259
+ {
260
+ "price": 0.5264,
261
+ "onOff": false,
262
+ "start": "2021-10-12T09:00:00.000+02:00",
263
+ "saving": 0.0219
264
+ },
265
+ {
266
+ "price": 0.5346,
267
+ "onOff": false,
268
+ "start": "2021-10-12T10:00:00.000+02:00",
269
+ "saving": 0.0301
270
+ },
271
+ {
272
+ "price": 0.5224,
273
+ "onOff": false,
274
+ "start": "2021-10-12T11:00:00.000+02:00",
275
+ "saving": 0.0179
276
+ },
277
+ {
278
+ "price": 0.5071,
279
+ "onOff": false,
280
+ "start": "2021-10-12T12:00:00.000+02:00",
281
+ "saving": 0.0026
282
+ },
283
+ {
284
+ "price": 0.5045,
285
+ "onOff": true,
286
+ "start": "2021-10-12T13:00:00.000+02:00",
287
+ "saving": null
288
+ },
289
+ {
290
+ "price": 0.5024,
291
+ "onOff": true,
292
+ "start": "2021-10-12T14:00:00.000+02:00",
293
+ "saving": null
294
+ },
295
+ {
296
+ "price": 0.5038,
297
+ "onOff": true,
298
+ "start": "2021-10-12T15:00:00.000+02:00",
299
+ "saving": null
300
+ },
301
+ {
302
+ "price": 0.5118,
303
+ "onOff": false,
304
+ "start": "2021-10-12T16:00:00.000+02:00",
305
+ "saving": 0.0076
306
+ },
307
+ {
308
+ "price": 0.5111,
309
+ "onOff": false,
310
+ "start": "2021-10-12T17:00:00.000+02:00",
311
+ "saving": 0.0069
312
+ },
313
+ {
314
+ "price": 0.5108,
315
+ "onOff": false,
316
+ "start": "2021-10-12T18:00:00.000+02:00",
317
+ "saving": 0.0066
318
+ },
319
+ {
320
+ "price": 0.5055,
321
+ "onOff": false,
322
+ "start": "2021-10-12T19:00:00.000+02:00",
323
+ "saving": 0.0013
324
+ },
325
+ {
326
+ "price": 0.5042,
327
+ "onOff": true,
328
+ "start": "2021-10-12T20:00:00.000+02:00",
329
+ "saving": null
330
+ },
331
+ {
332
+ "price": 0.5259,
333
+ "onOff": true,
334
+ "start": "2021-10-12T21:00:00.000+02:00",
335
+ "saving": null
336
+ },
337
+ {
338
+ "price": 0.5282,
339
+ "onOff": false,
340
+ "start": "2021-10-12T22:00:00.000+02:00",
341
+ "saving": 0.003
342
+ },
343
+ {
344
+ "price": 0.5252,
345
+ "onOff": true,
346
+ "start": "2021-10-12T23:00:00.000+02:00",
347
+ "saving": null
348
+ }
349
+ ],
350
+ "source": "Tibber"
351
+ }
@@ -6,7 +6,7 @@ const prices = require("./data/prices");
6
6
  describe("mostSavedStrategy", () => {
7
7
  it("saves correct hours", () => {
8
8
  const values = prices.today.map((p) => p.value);
9
- expect(mostSavedStrategy.calculate(values, 6, 3, 1, 0.001)).toEqual([
9
+ expect(mostSavedStrategy.calculate(values, 3, 1, 0.001)).toEqual([
10
10
  true,
11
11
  true,
12
12
  false,
@@ -18,11 +18,11 @@ describe("mostSavedStrategy", () => {
18
18
  true,
19
19
  true,
20
20
  ]);
21
- expect(mostSavedStrategy.calculate(values, 4, 3, 1, 0.001)).toEqual([
22
- true,
21
+ expect(mostSavedStrategy.calculate(values, 3, 1, 0.001)).toEqual([
23
22
  true,
24
23
  true,
25
24
  false,
25
+ false,
26
26
  true,
27
27
  false,
28
28
  false,
@@ -30,19 +30,19 @@ describe("mostSavedStrategy", () => {
30
30
  true,
31
31
  true,
32
32
  ]);
33
- expect(mostSavedStrategy.calculate(values, 5, 2, 1, 0.001)).toEqual([
33
+ expect(mostSavedStrategy.calculate(values, 2, 1, 0.001)).toEqual([
34
+ true,
34
35
  true,
35
36
  true,
36
37
  false,
37
38
  false,
38
39
  true,
39
- true,
40
40
  false,
41
41
  false,
42
42
  true,
43
43
  true,
44
44
  ]);
45
- expect(mostSavedStrategy.calculate(values, 5, 2, 3, 0.001)).toEqual([
45
+ expect(mostSavedStrategy.calculate(values, 2, 3, 0.001)).toEqual([
46
46
  true,
47
47
  true,
48
48
  true,
@@ -54,37 +54,21 @@ describe("mostSavedStrategy", () => {
54
54
  true,
55
55
  true,
56
56
  ]);
57
- expect(mostSavedStrategy.calculate(values, 5, 2, 0, 0.001)).toEqual([
57
+ expect(mostSavedStrategy.calculate(values, 2, 0, 0.001)).toEqual([
58
+ true,
58
59
  true,
59
60
  true,
60
61
  false,
61
62
  false,
62
63
  true,
63
- true,
64
64
  false,
65
65
  false,
66
66
  true,
67
67
  true,
68
68
  ]);
69
69
  const values2 = prices.tomorrow.map((p) => p.value);
70
- expect(
71
- mostSavedStrategy.calculate(values2, 5, 2, 1, 0.001, true, 1)
72
- ).toEqual([
73
- false,
74
- false,
75
- true,
70
+ expect(mostSavedStrategy.calculate(values2, 2, 1, 0.001, true, 1)).toEqual([
76
71
  false,
77
- true,
78
- true,
79
- false,
80
- false,
81
- true,
82
- true,
83
- ]);
84
- expect(
85
- mostSavedStrategy.calculate(values2, 5, 2, 1, 0.001, false, 1)
86
- ).toEqual([
87
- true,
88
72
  false,
89
73
  true,
90
74
  false,
@@ -95,5 +79,8 @@ describe("mostSavedStrategy", () => {
95
79
  true,
96
80
  true,
97
81
  ]);
82
+ expect(mostSavedStrategy.calculate(values2, 2, 1, 0.001, false, 1)).toEqual(
83
+ [true, false, true, false, false, true, false, false, true, true]
84
+ );
98
85
  });
99
86
  });
@@ -5,13 +5,21 @@ const powerSaver = require("../power-saver.js");
5
5
  const { DateTime } = require("luxon");
6
6
 
7
7
  const prices = require("./data/prices");
8
+ const result = require("./data/result");
9
+
8
10
  const plan = {
9
11
  schedule: [
10
12
  { time: "2021-06-20T01:50:00.000+02:00", value: true },
11
- { time: "2021-06-20T01:50:00.070+02:00", value: false },
13
+ { time: "2021-06-20T01:50:00.020+02:00", value: false },
14
+ { time: "2021-06-20T01:50:00.040+02:00", value: true },
15
+ { time: "2021-06-20T01:50:00.050+02:00", value: false },
12
16
  { time: "2021-06-20T01:50:00.080+02:00", value: true },
13
- { time: "2021-06-20T01:50:00.110+02:00", value: false },
17
+ { time: "2021-06-20T01:50:00.100+02:00", value: false },
14
18
  { time: "2021-06-20T01:50:00.120+02:00", value: true },
19
+ { time: "2021-06-20T01:50:00.130+02:00", value: false },
20
+ { time: "2021-06-20T01:50:00.140+02:00", value: true },
21
+ { time: "2021-06-20T01:50:00.150+02:00", value: false },
22
+ { time: "2021-06-20T01:50:00.180+02:00", value: true },
15
23
  ],
16
24
  time: "2021-06-20T01:50:00+02:00",
17
25
  };
@@ -67,32 +75,16 @@ describe("power-saver Node", function () {
67
75
  });
68
76
  });
69
77
  it("should send new schedule on output 3", function (done) {
70
- const flow = [
71
- {
72
- id: "n1",
73
- type: "power-saver",
74
- name: "test name",
75
- minSaving: 0.001,
76
- wires: [["n3"], ["n4"], ["n2"]],
77
- },
78
- { id: "n2", type: "helper" },
79
- { id: "n3", type: "helper" },
80
- { id: "n4", type: "helper" },
81
- ];
78
+ const flow = makeFlow(3, 2);
82
79
  helper.load(powerSaver, flow, function () {
83
80
  const n1 = helper.getNode("n1");
84
81
  const n2 = helper.getNode("n2");
85
82
  const n3 = helper.getNode("n3");
86
83
  const n4 = helper.getNode("n4");
87
84
  n2.on("input", function (msg) {
88
- console.log(JSON.stringify(msg, null, 2));
89
- console.log(JSON.stringify(plan.schedule, null, 2));
90
- expect(msg.payload).toHaveProperty("schedule", plan.schedule);
85
+ expect(msg).toHaveProperty("payload", result);
91
86
  n1.warn.should.not.be.called;
92
- // done();
93
- setTimeout(() => {
94
- done();
95
- }, 500);
87
+ done();
96
88
  });
97
89
  n3.on("input", function (msg) {
98
90
  expect(msg).toHaveProperty("payload", true);
@@ -100,20 +92,127 @@ describe("power-saver Node", function () {
100
92
  n4.on("input", function (msg) {
101
93
  expect(msg).toHaveProperty("payload", false);
102
94
  });
103
- payload = cloneDeep(prices);
104
- payload.time = plan.time;
105
- let entryTime = DateTime.fromISO(payload.time);
106
- payload.today.forEach((e) => {
107
- e.start = entryTime.toISO();
108
- entryTime = entryTime.plus({ milliseconds: 10 });
109
- e.end = entryTime.toISO();
95
+ n1.receive({ payload: makePayload(prices, plan.time) });
96
+ });
97
+ });
98
+
99
+ it("can schedule one day", function (done) {
100
+ const values = [1, 1, 1, 1, 1, 1, 1, 5, 4, 3];
101
+ const schedule = [
102
+ {
103
+ time: "2021-06-20T01:50:00.000+02:00",
104
+ value: true,
105
+ },
106
+ {
107
+ time: "2021-06-20T01:50:00.070+02:00",
108
+ value: false,
109
+ },
110
+ {
111
+ time: "2021-06-20T01:50:00.090+02:00",
112
+ value: true,
113
+ },
114
+ ];
115
+ const flow = makeFlow(4, 2);
116
+ helper.load(powerSaver, flow, function () {
117
+ const n1 = helper.getNode("n1");
118
+ const n2 = helper.getNode("n2");
119
+ n2.on("input", function (msg) {
120
+ expect(msg.payload).toHaveProperty("schedule", schedule);
121
+ n1.warn.should.not.be.called;
122
+ done();
110
123
  });
111
- payload.tomorrow.forEach((e) => {
112
- e.start = entryTime.toISO();
113
- entryTime = entryTime.plus({ milliseconds: 10 });
114
- e.end = entryTime.toISO();
124
+ const mPrices = cloneDeep(prices);
125
+ delete mPrices.tomorrow;
126
+ for (i = 0; i < mPrices.today.length; i++) {
127
+ mPrices.today[i].value = values[i];
128
+ }
129
+ const payload = makePayload(mPrices, plan.time);
130
+ n1.receive({ payload });
131
+ });
132
+ });
133
+
134
+ it("should schedule over midnight", function (done) {
135
+ const values1 = [1, 1, 1, 1, 1, 1, 1, 5, 4, 3];
136
+ const values2 = [2, 1, 5, 5, 5, 5, 5, 5, 5, 5];
137
+ const schedule = [
138
+ {
139
+ time: "2021-06-20T01:50:00.000+02:00",
140
+ value: true,
141
+ },
142
+ {
143
+ time: "2021-06-20T01:50:00.070+02:00",
144
+ value: false,
145
+ },
146
+ {
147
+ time: "2021-06-20T01:50:00.110+02:00",
148
+ value: true,
149
+ },
150
+ ];
151
+ const flow = makeFlow(4, 2);
152
+ helper.load(powerSaver, flow, function () {
153
+ const n1 = helper.getNode("n1");
154
+ const n2 = helper.getNode("n2");
155
+ n2.on("input", function (msg) {
156
+ expect(msg.payload).toHaveProperty("schedule", schedule);
157
+ n1.warn.should.not.be.called;
158
+ done();
115
159
  });
160
+ const mPrices = cloneDeep(prices);
161
+ for (i = 0; i < mPrices.today.length; i++) {
162
+ mPrices.today[i].value = values1[i];
163
+ mPrices.tomorrow[i].value = values2[i];
164
+ }
165
+ const payload = makePayload(mPrices, plan.time);
116
166
  n1.receive({ payload });
117
167
  });
118
168
  });
169
+ it("works for Tibber data", function (done) {
170
+ const tibberData = require("./data/tibber_prices.json");
171
+ const tibberResult = require("./data/tibber_result.json");
172
+ const flow = makeFlow(4, 2);
173
+ helper.load(powerSaver, flow, function () {
174
+ const n1 = helper.getNode("n1");
175
+ const n2 = helper.getNode("n2");
176
+ n2.on("input", function (msg) {
177
+ console.log(JSON.stringify(msg, null, 2));
178
+ expect(msg).toHaveProperty("payload", tibberResult);
179
+ done();
180
+ });
181
+ n1.receive({ ...tibberData });
182
+ });
183
+ });
119
184
  });
185
+
186
+ function makeFlow(maxHoursToSaveInSequence, minHoursOnAfterMaxSequenceSaved) {
187
+ return [
188
+ {
189
+ id: "n1",
190
+ type: "power-saver",
191
+ name: "test name",
192
+ maxHoursToSaveInSequence,
193
+ minHoursOnAfterMaxSequenceSaved,
194
+ minSaving: 0.001,
195
+ wires: [["n3"], ["n4"], ["n2"]],
196
+ },
197
+ { id: "n2", type: "helper" },
198
+ { id: "n3", type: "helper" },
199
+ { id: "n4", type: "helper" },
200
+ ];
201
+ }
202
+
203
+ function makePayload(prices, time) {
204
+ const payload = cloneDeep(prices);
205
+ payload.time = time;
206
+ let entryTime = DateTime.fromISO(payload.time);
207
+ payload.today.forEach((e) => {
208
+ e.start = entryTime.toISO();
209
+ entryTime = entryTime.plus({ milliseconds: 10 });
210
+ e.end = entryTime.toISO();
211
+ });
212
+ payload.tomorrow?.forEach((e) => {
213
+ e.start = entryTime.toISO();
214
+ entryTime = entryTime.plus({ milliseconds: 10 });
215
+ e.end = entryTime.toISO();
216
+ });
217
+ return payload;
218
+ }