node-red-contrib-power-saver 1.0.9 → 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,14 +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");
8
9
 
9
10
  const plan = {
10
11
  schedule: [
11
12
  { time: "2021-06-20T01:50:00.000+02:00", value: true },
12
- { 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 },
13
16
  { time: "2021-06-20T01:50:00.080+02:00", value: true },
14
- { time: "2021-06-20T01:50:00.110+02:00", value: false },
17
+ { time: "2021-06-20T01:50:00.100+02:00", value: false },
15
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 },
16
23
  ],
17
24
  time: "2021-06-20T01:50:00+02:00",
18
25
  };
@@ -68,18 +75,16 @@ describe("power-saver Node", function () {
68
75
  });
69
76
  });
70
77
  it("should send new schedule on output 3", function (done) {
71
- const flow = makeFlow();
78
+ const flow = makeFlow(3, 2);
72
79
  helper.load(powerSaver, flow, function () {
73
80
  const n1 = helper.getNode("n1");
74
81
  const n2 = helper.getNode("n2");
75
82
  const n3 = helper.getNode("n3");
76
83
  const n4 = helper.getNode("n4");
77
84
  n2.on("input", function (msg) {
78
- expect(msg.payload).toHaveProperty("schedule", plan.schedule);
85
+ expect(msg).toHaveProperty("payload", result);
79
86
  n1.warn.should.not.be.called;
80
- setTimeout(() => {
81
- done();
82
- }, 500);
87
+ done();
83
88
  });
84
89
  n3.on("input", function (msg) {
85
90
  expect(msg).toHaveProperty("payload", true);
@@ -107,17 +112,14 @@ describe("power-saver Node", function () {
107
112
  value: true,
108
113
  },
109
114
  ];
110
- const flow = makeFlow(12, 4, 2);
115
+ const flow = makeFlow(4, 2);
111
116
  helper.load(powerSaver, flow, function () {
112
117
  const n1 = helper.getNode("n1");
113
118
  const n2 = helper.getNode("n2");
114
119
  n2.on("input", function (msg) {
115
- console.log(JSON.stringify(msg, null, 2));
116
120
  expect(msg.payload).toHaveProperty("schedule", schedule);
117
- // n1.warn.should.not.be.called;
118
- setTimeout(() => {
119
- done();
120
- }, 500);
121
+ n1.warn.should.not.be.called;
122
+ done();
121
123
  });
122
124
  const mPrices = cloneDeep(prices);
123
125
  delete mPrices.tomorrow;
@@ -146,17 +148,14 @@ describe("power-saver Node", function () {
146
148
  value: true,
147
149
  },
148
150
  ];
149
- const flow = makeFlow(12, 4, 2);
151
+ const flow = makeFlow(4, 2);
150
152
  helper.load(powerSaver, flow, function () {
151
153
  const n1 = helper.getNode("n1");
152
154
  const n2 = helper.getNode("n2");
153
155
  n2.on("input", function (msg) {
154
- console.log(JSON.stringify(msg, null, 2));
155
156
  expect(msg.payload).toHaveProperty("schedule", schedule);
156
- // n1.warn.should.not.be.called;
157
- setTimeout(() => {
158
- done();
159
- }, 500);
157
+ n1.warn.should.not.be.called;
158
+ done();
160
159
  });
161
160
  const mPrices = cloneDeep(prices);
162
161
  for (i = 0; i < mPrices.today.length; i++) {
@@ -168,36 +167,28 @@ describe("power-saver Node", function () {
168
167
  });
169
168
  });
170
169
  it("works for Tibber data", function (done) {
171
- const tibberData = require("./data/tibber.json");
172
- const tibberSchedule = require("./data/tibber_schedule.json");
173
- // console.log(JSON.stringify(tibberData, null, 2));
174
- const flow = makeFlow(12, 4, 2);
170
+ const tibberData = require("./data/tibber_prices.json");
171
+ const tibberResult = require("./data/tibber_result.json");
172
+ const flow = makeFlow(4, 2);
175
173
  helper.load(powerSaver, flow, function () {
176
174
  const n1 = helper.getNode("n1");
177
175
  const n2 = helper.getNode("n2");
178
176
  n2.on("input", function (msg) {
179
177
  console.log(JSON.stringify(msg, null, 2));
180
- expect(msg).toHaveProperty("payload", tibberSchedule.payload);
181
- setTimeout(() => {
182
- done();
183
- }, 500);
178
+ expect(msg).toHaveProperty("payload", tibberResult);
179
+ done();
184
180
  });
185
181
  n1.receive({ ...tibberData });
186
182
  });
187
183
  });
188
184
  });
189
185
 
190
- function makeFlow(
191
- maxHoursToSavePerDay,
192
- maxHoursToSaveInSequence,
193
- minHoursOnAfterMaxSequenceSaved
194
- ) {
186
+ function makeFlow(maxHoursToSaveInSequence, minHoursOnAfterMaxSequenceSaved) {
195
187
  return [
196
188
  {
197
189
  id: "n1",
198
190
  type: "power-saver",
199
191
  name: "test name",
200
- maxHoursToSavePerDay,
201
192
  maxHoursToSaveInSequence,
202
193
  minHoursOnAfterMaxSequenceSaved,
203
194
  minSaving: 0.001,
@@ -1,3 +1,4 @@
1
+ const { DateTime } = require("luxon");
1
2
  const expect = require("expect");
2
3
  const {
3
4
  sortedIndex,
@@ -9,6 +10,8 @@ const {
9
10
  makeSchedule,
10
11
  fillArray,
11
12
  convertMsg,
13
+ extractPlanForDate,
14
+ isSameDate,
12
15
  } = require("../utils");
13
16
 
14
17
  describe("utils", () => {
@@ -232,4 +235,108 @@ describe("utils", () => {
232
235
  ...msgStdTodayOnly.payload,
233
236
  });
234
237
  });
238
+
239
+ it("can compare dates", () => {
240
+ const date1 = "2021-06-20T01:50:00.000+02:00";
241
+ expect(isSameDate(date1, "2021-06-20T01:50:00.000+02:00")).toBeTruthy();
242
+ expect(isSameDate(date1, "2021-06-21T01:50:00.000+02:00")).toBeFalsy();
243
+ expect(isSameDate(date1, "2021-06-20")).toBeTruthy();
244
+ expect(isSameDate(date1, "2021-06-21")).toBeFalsy();
245
+ });
246
+
247
+ it("can extract plan for a date", () => {
248
+ const plan = {
249
+ hours: [
250
+ {
251
+ price: 0.3,
252
+ onOff: true,
253
+ start: "2021-06-20T01:50:00.000+02:00",
254
+ saving: 1,
255
+ },
256
+ {
257
+ price: 0.4,
258
+ onOff: false,
259
+ start: "2021-06-20T01:50:00.010+02:00",
260
+ saving: 2,
261
+ },
262
+ {
263
+ price: 0.2,
264
+ onOff: false,
265
+ start: "2021-06-21T01:50:00.180+02:00",
266
+ saving: 3,
267
+ },
268
+ {
269
+ price: 0.85,
270
+ onOff: true,
271
+ start: "2021-06-21T01:50:00.190+02:00",
272
+ saving: null,
273
+ },
274
+ ],
275
+ schedule: [
276
+ {
277
+ time: "2021-06-20T01:50:00.000+02:00",
278
+ value: true,
279
+ },
280
+ {
281
+ time: "2021-06-21T01:50:00.020+02:00",
282
+ value: false,
283
+ },
284
+ {
285
+ time: "2021-06-21T01:50:00.040+02:00",
286
+ value: false,
287
+ },
288
+ ],
289
+ };
290
+ const part1 = {
291
+ hours: [
292
+ {
293
+ price: 0.3,
294
+ onOff: true,
295
+ start: "2021-06-20T01:50:00.000+02:00",
296
+ saving: 1,
297
+ },
298
+ {
299
+ price: 0.4,
300
+ onOff: false,
301
+ start: "2021-06-20T01:50:00.010+02:00",
302
+ saving: 2,
303
+ },
304
+ ],
305
+ schedule: [
306
+ {
307
+ time: "2021-06-20T01:50:00.000+02:00",
308
+ value: true,
309
+ },
310
+ ],
311
+ };
312
+ const part2 = {
313
+ hours: [
314
+ {
315
+ price: 0.2,
316
+ onOff: false,
317
+ start: "2021-06-21T01:50:00.180+02:00",
318
+ saving: 3,
319
+ },
320
+ {
321
+ price: 0.85,
322
+ onOff: true,
323
+ start: "2021-06-21T01:50:00.190+02:00",
324
+ saving: null,
325
+ },
326
+ ],
327
+ schedule: [
328
+ {
329
+ time: "2021-06-21T01:50:00.020+02:00",
330
+ value: false,
331
+ },
332
+ {
333
+ time: "2021-06-21T01:50:00.040+02:00",
334
+ value: false,
335
+ },
336
+ ],
337
+ };
338
+ expect(extractPlanForDate(plan, "2021-06-20T01:50:00.000+02:00")).toEqual(
339
+ part1
340
+ );
341
+ });
235
342
  });