node-red-contrib-power-saver 3.0.8 → 3.1.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.
Files changed (112) hide show
  1. package/docs/.vuepress/config.js +9 -1
  2. package/docs/.vuepress/dist/404.html +3 -3
  3. package/docs/.vuepress/dist/assets/img/add-tariff-flow.eb700d4f.png +0 -0
  4. package/docs/.vuepress/dist/assets/img/best-save-config.93fa3c21.png +0 -0
  5. package/docs/.vuepress/dist/assets/img/lowest-price-config.6d66a8c2.png +0 -0
  6. package/docs/.vuepress/dist/assets/img/next-schedule-entity.4406856a.png +0 -0
  7. package/docs/.vuepress/dist/assets/img/next-schedule-flow.413ad62b.png +0 -0
  8. package/docs/.vuepress/dist/assets/img/next-schedule-sensor.eb896bdd.png +0 -0
  9. package/docs/.vuepress/dist/assets/img/node-ps-general-add-tariff.a3cf6f06.png +0 -0
  10. package/docs/.vuepress/dist/assets/js/app.8016111b.js +1 -0
  11. package/docs/.vuepress/dist/assets/js/runtime~app.0da14230.js +1 -0
  12. package/docs/.vuepress/dist/assets/js/v-0607240a.661e1808.js +1 -0
  13. package/docs/.vuepress/dist/assets/js/v-08683c60.a6b9cf5b.js +1 -0
  14. package/docs/.vuepress/dist/assets/js/v-0aca7ba6.b42fad7f.js +1 -0
  15. package/docs/.vuepress/dist/assets/js/v-0b5e3c8c.34230e16.js +1 -0
  16. package/docs/.vuepress/dist/assets/js/v-1ad821fa.6e2194d0.js +1 -0
  17. package/docs/.vuepress/dist/assets/js/v-1e2b191e.50b8fa18.js +1 -0
  18. package/docs/.vuepress/dist/assets/js/v-30acb564.f2fcd69f.js +1 -0
  19. package/docs/.vuepress/dist/assets/js/v-4637f9e4.38f66bbb.js +1 -0
  20. package/docs/.vuepress/dist/assets/js/v-510ed0d4.9f2a81c6.js +1 -0
  21. package/docs/.vuepress/dist/assets/js/v-5954bcb2.182daf70.js +1 -0
  22. package/docs/.vuepress/dist/assets/js/v-5db8da3a.f2de6cb9.js +1 -0
  23. package/docs/.vuepress/dist/assets/js/v-61f728ca.6fdbbb92.js +1 -0
  24. package/docs/.vuepress/dist/assets/js/v-677dfaed.0013f083.js +1 -0
  25. package/docs/.vuepress/dist/assets/js/v-7446a652.d05e2648.js +1 -0
  26. package/docs/.vuepress/dist/assets/js/v-7c87f26e.1127dcf5.js +1 -0
  27. package/docs/.vuepress/dist/assets/js/v-8daa1a0e.dde202c9.js +1 -0
  28. package/docs/.vuepress/dist/assets/js/v-b4a42144.9e5f9728.js +1 -0
  29. package/docs/.vuepress/dist/assets/js/v-e8c55052.8384b053.js +1 -0
  30. package/docs/.vuepress/dist/assets/js/v-fffb8e28.3406fd88.js +1 -0
  31. package/docs/.vuepress/dist/changelog/index.html +3 -3
  32. package/docs/.vuepress/dist/contribute/index.html +3 -3
  33. package/docs/.vuepress/dist/examples/example-next-schedule-entity.html +25 -0
  34. package/docs/.vuepress/dist/examples/example-nordpool-current-state.html +176 -156
  35. package/docs/.vuepress/dist/examples/example-nordpool-events-state.html +4 -4
  36. package/docs/.vuepress/dist/examples/example-tibber-mqtt.html +4 -4
  37. package/docs/.vuepress/dist/examples/index.html +3 -3
  38. package/docs/.vuepress/dist/faq/index.html +15 -0
  39. package/docs/.vuepress/dist/guide/index.html +4 -4
  40. package/docs/.vuepress/dist/index.html +3 -3
  41. package/docs/.vuepress/dist/logo.png +0 -0
  42. package/docs/.vuepress/dist/nodes/index.html +3 -3
  43. package/docs/.vuepress/dist/nodes/old-power-saver-doc.html +5 -5
  44. package/docs/.vuepress/dist/nodes/power-saver.html +3 -3
  45. package/docs/.vuepress/dist/nodes/ps-elvia-add-tariff.html +3 -3
  46. package/docs/.vuepress/dist/nodes/ps-general-add-tariff.html +15 -0
  47. package/docs/.vuepress/dist/nodes/ps-receive-price.html +6 -6
  48. package/docs/.vuepress/dist/nodes/ps-strategy-best-save.html +4 -4
  49. package/docs/.vuepress/dist/nodes/ps-strategy-lowest-price.html +4 -4
  50. package/docs/.vuepress/dist/nodes/strategy-input.html +4 -4
  51. package/docs/.vuepress/public/logo.png +0 -0
  52. package/docs/README.md +7 -5
  53. package/docs/changelog/README.md +22 -5
  54. package/docs/contribute/README.md +1 -1
  55. package/docs/examples/README.md +4 -0
  56. package/docs/examples/example-next-schedule-entity.md +41 -0
  57. package/docs/examples/example-nordpool-current-state.md +172 -152
  58. package/docs/faq/README.md +23 -0
  59. package/docs/guide/README.md +16 -15
  60. package/docs/images/add-tariff-flow.png +0 -0
  61. package/docs/images/logo copy.png +0 -0
  62. package/docs/images/logo.png +0 -0
  63. package/docs/images/logo.psd +0 -0
  64. package/docs/images/mysterious-plan.png +0 -0
  65. package/docs/images/next-schedule-entity.png +0 -0
  66. package/docs/images/next-schedule-flow.png +0 -0
  67. package/docs/images/next-schedule-sensor.png +0 -0
  68. package/docs/images/node-ps-general-add-tariff.png +0 -0
  69. package/docs/images/node-red-icon-2.svg +30 -0
  70. package/docs/nodes/README.md +6 -0
  71. package/docs/nodes/old-power-saver-doc.md +6 -6
  72. package/docs/nodes/ps-elvia-add-tariff.md +1 -1
  73. package/docs/nodes/ps-general-add-tariff.md +49 -0
  74. package/docs/nodes/ps-receive-price.md +9 -5
  75. package/docs/nodes/ps-strategy-best-save.md +5 -1
  76. package/docs/nodes/ps-strategy-lowest-price.md +3 -3
  77. package/docs/nodes/strategy-input.md +1 -1
  78. package/package.json +3 -2
  79. package/src/elvia/elvia-add-tariff.js +7 -6
  80. package/src/general-add-tariff-functions.js +46 -0
  81. package/src/general-add-tariff.html +186 -0
  82. package/src/general-add-tariff.js +35 -0
  83. package/src/handle-input.js +1 -1
  84. package/src/power-saver.js +1 -1
  85. package/src/receive-price-functions.js +8 -0
  86. package/src/strategy-lowest-price.js +6 -6
  87. package/test/data/nordpool-3-days-prices.json +293 -0
  88. package/test/data/nordpool-3-days-result.json +444 -0
  89. package/test/data/nordpool-prices-in-payload.json +287 -0
  90. package/test/elvia.test.js +16 -2
  91. package/test/general-add-tariff-functions.test.js +104 -0
  92. package/test/general-add-tariff.test.js +183 -0
  93. package/test/receive-price.test.js +22 -0
  94. package/test/strategy-lowest-price-3days.test.js +88 -0
  95. package/docs/.vuepress/dist/assets/js/app.8ccc81e3.js +0 -1
  96. package/docs/.vuepress/dist/assets/js/runtime~app.7653fe7e.js +0 -1
  97. package/docs/.vuepress/dist/assets/js/v-08683c60.07fe8291.js +0 -1
  98. package/docs/.vuepress/dist/assets/js/v-0aca7ba6.aec5ba75.js +0 -1
  99. package/docs/.vuepress/dist/assets/js/v-0b5e3c8c.d008d8bc.js +0 -1
  100. package/docs/.vuepress/dist/assets/js/v-1ad821fa.85407071.js +0 -1
  101. package/docs/.vuepress/dist/assets/js/v-30acb564.73b8e29f.js +0 -1
  102. package/docs/.vuepress/dist/assets/js/v-4637f9e4.22ab9413.js +0 -1
  103. package/docs/.vuepress/dist/assets/js/v-510ed0d4.e5215a83.js +0 -1
  104. package/docs/.vuepress/dist/assets/js/v-5954bcb2.be07962c.js +0 -1
  105. package/docs/.vuepress/dist/assets/js/v-5db8da3a.ac192f35.js +0 -1
  106. package/docs/.vuepress/dist/assets/js/v-61f728ca.802ab15e.js +0 -1
  107. package/docs/.vuepress/dist/assets/js/v-677dfaed.9bbbd037.js +0 -1
  108. package/docs/.vuepress/dist/assets/js/v-7c87f26e.457a1a60.js +0 -1
  109. package/docs/.vuepress/dist/assets/js/v-8daa1a0e.db8b59c6.js +0 -1
  110. package/docs/.vuepress/dist/assets/js/v-b4a42144.6e0c5aa0.js +0 -1
  111. package/docs/.vuepress/dist/assets/js/v-e8c55052.5f85b6cd.js +0 -1
  112. package/docs/.vuepress/dist/assets/js/v-fffb8e28.e815e852.js +0 -1
@@ -0,0 +1,35 @@
1
+ const cloneDeep = require("lodash.clonedeep");
2
+ const { DateTime } = require("luxon");
3
+ const { addTariffToPrices, buildAllHours } = require("./general-add-tariff-functions");
4
+ const { roundPrice } = require("./utils");
5
+ const { extractPlanForDate, getEffectiveConfig, validationFailure } = require("./utils");
6
+
7
+ module.exports = function (RED) {
8
+ function PsGeneralAddTariffNode(config) {
9
+ RED.nodes.createNode(this, config);
10
+ this.range = config.range;
11
+ const node = this;
12
+
13
+ const originalConfig = {
14
+ periods: config.periods,
15
+ validFrom: config.validFrom,
16
+ validTo: config.validTo,
17
+ };
18
+ node.context().set("config", originalConfig);
19
+
20
+ node.on("input", function (originalMessage) {
21
+ const msg = cloneDeep(originalMessage);
22
+ const effectiveConfig = getEffectiveConfig(node, msg);
23
+ const prices = msg.payload.priceData;
24
+ if (!prices || prices.length === 0) {
25
+ return;
26
+ }
27
+
28
+ addTariffToPrices(node, effectiveConfig, prices);
29
+
30
+ node.send(msg);
31
+ });
32
+ }
33
+
34
+ RED.nodes.registerType("ps-general-add-tariff", PsGeneralAddTariffNode);
35
+ };
@@ -104,7 +104,7 @@ function deleteSavedScheduleBefore(node, day) {
104
104
  let date = day;
105
105
  do {
106
106
  date = date.plus({ days: -1 });
107
- data = node.context().get(date.toISO());
107
+ data = node.context().set(date.toISO(), undefined);
108
108
  } while (data);
109
109
  }
110
110
 
@@ -156,7 +156,7 @@ function deleteSavedScheduleBefore(node, day) {
156
156
  let date = day;
157
157
  do {
158
158
  date = date.plus({ days: -1 });
159
- data = node.context().get(date.toISO());
159
+ data = node.context().set(date.toISO(), undefined);
160
160
  } while (data);
161
161
  }
162
162
 
@@ -72,6 +72,14 @@ function convertMsg(msg) {
72
72
  value: v.value,
73
73
  start: v.start,
74
74
  }));
75
+ } else if (msg.payload?.attributes && msg.payload.attributes["raw_" + day]) {
76
+ result.source = "Nordpool";
77
+ result[day] = msg.payload.attributes["raw_" + day]
78
+ .filter((v) => v.value)
79
+ .map((v) => ({
80
+ value: v.value,
81
+ start: v.start,
82
+ }));
75
83
  } else {
76
84
  result.source = "Other";
77
85
  result[day] = msg.payload[day] || [];
@@ -43,8 +43,8 @@ function doPlanning(node, _, priceData, _, dateDayBefore, _) {
43
43
  const endIndexes = [];
44
44
  let currentStatus = from < (to === 0 && to !== from ? 24 : to) ? "Outside" : "StartMissing";
45
45
  let hour;
46
- priceData.forEach((pd, i) => {
47
- hour = DateTime.fromISO(pd.start).hour;
46
+ startTimes.forEach((st, i) => {
47
+ hour = DateTime.fromISO(st).hour;
48
48
  if (hour === to && to === from && currentStatus === "Inside") {
49
49
  endIndexes.push(i - 1);
50
50
  }
@@ -63,13 +63,13 @@ function doPlanning(node, _, priceData, _, dateDayBefore, _) {
63
63
  let i = periodStatus.length - 1;
64
64
  do {
65
65
  periodStatus[i] = "EndMissing";
66
- hour = DateTime.fromISO(priceData[i].start).hour;
66
+ hour = DateTime.fromISO(startTimes[i]).hour;
67
67
  i--;
68
68
  } while (periodStatus[i] === "Inside" && hour !== from);
69
69
  startIndexes.splice(startIndexes.length - 1, 1);
70
70
  }
71
71
  if (hour === (to === 0 ? 23 : to - 1)) {
72
- endIndexes.push(priceData.length - 1);
72
+ endIndexes.push(startTimes.length - 1);
73
73
  }
74
74
 
75
75
  const onOff = [];
@@ -78,9 +78,9 @@ function doPlanning(node, _, priceData, _, dateDayBefore, _) {
78
78
  const lastStartMissing = periodStatus.lastIndexOf((s) => s === "StartMissing");
79
79
  if (lastStartMissing >= 0 && dataDayBefore?.hours?.length > 0) {
80
80
  const lastBefore = DateTime.fromISO(dataDayBefore.hours[dataDayBefore.hours.length - 1].start);
81
- if (lastBefore >= DateTime.fromISO(priceData[lastStartMissing].start)) {
81
+ if (lastBefore >= DateTime.fromISO(startTimes[lastStartMissing])) {
82
82
  for (let i = 0; i <= lastStartMissing; i++) {
83
- onOff[i] = dataDayBefore.hours.find((h) => h.start === priceData[i].start);
83
+ onOff[i] = dataDayBefore.hours.find((h) => h.start === startTimes[i]);
84
84
  periodStatus[i] = "Backfilled";
85
85
  }
86
86
  }
@@ -0,0 +1,293 @@
1
+ {
2
+ "priceData": [
3
+ {
4
+ "value": 1.563,
5
+ "start": "2022-01-03T00:00:00+01:00"
6
+ },
7
+ {
8
+ "value": 1.543,
9
+ "start": "2022-01-03T01:00:00+01:00"
10
+ },
11
+ {
12
+ "value": 1.535,
13
+ "start": "2022-01-03T02:00:00+01:00"
14
+ },
15
+ {
16
+ "value": 1.52,
17
+ "start": "2022-01-03T03:00:00+01:00"
18
+ },
19
+ {
20
+ "value": 1.528,
21
+ "start": "2022-01-03T04:00:00+01:00"
22
+ },
23
+ {
24
+ "value": 1.545,
25
+ "start": "2022-01-03T05:00:00+01:00"
26
+ },
27
+ {
28
+ "value": 1.509,
29
+ "start": "2022-01-03T06:00:00+01:00"
30
+ },
31
+ {
32
+ "value": 1.513,
33
+ "start": "2022-01-03T07:00:00+01:00"
34
+ },
35
+ {
36
+ "value": 1.583,
37
+ "start": "2022-01-03T08:00:00+01:00"
38
+ },
39
+ {
40
+ "value": 1.658,
41
+ "start": "2022-01-03T09:00:00+01:00"
42
+ },
43
+ {
44
+ "value": 1.538,
45
+ "start": "2022-01-03T10:00:00+01:00"
46
+ },
47
+ {
48
+ "value": 1.54,
49
+ "start": "2022-01-03T11:00:00+01:00"
50
+ },
51
+ {
52
+ "value": 1.55,
53
+ "start": "2022-01-03T12:00:00+01:00"
54
+ },
55
+ {
56
+ "value": 1.584,
57
+ "start": "2022-01-03T13:00:00+01:00"
58
+ },
59
+ {
60
+ "value": 1.673,
61
+ "start": "2022-01-03T14:00:00+01:00"
62
+ },
63
+ {
64
+ "value": 1.722,
65
+ "start": "2022-01-03T15:00:00+01:00"
66
+ },
67
+ {
68
+ "value": 1.719,
69
+ "start": "2022-01-03T16:00:00+01:00"
70
+ },
71
+ {
72
+ "value": 1.798,
73
+ "start": "2022-01-03T17:00:00+01:00"
74
+ },
75
+ {
76
+ "value": 1.815,
77
+ "start": "2022-01-03T18:00:00+01:00"
78
+ },
79
+ {
80
+ "value": 1.786,
81
+ "start": "2022-01-03T19:00:00+01:00"
82
+ },
83
+ {
84
+ "value": 1.779,
85
+ "start": "2022-01-03T20:00:00+01:00"
86
+ },
87
+ {
88
+ "value": 1.746,
89
+ "start": "2022-01-03T21:00:00+01:00"
90
+ },
91
+ {
92
+ "value": 1.636,
93
+ "start": "2022-01-03T22:00:00+01:00"
94
+ },
95
+ {
96
+ "value": 1.421,
97
+ "start": "2022-01-03T23:00:00+01:00"
98
+ },
99
+ {
100
+ "value": 1.648,
101
+ "start": "2022-01-04T00:00:00+01:00"
102
+ },
103
+ {
104
+ "value": 1.65,
105
+ "start": "2022-01-04T01:00:00+01:00"
106
+ },
107
+ {
108
+ "value": 1.608,
109
+ "start": "2022-01-04T02:00:00+01:00"
110
+ },
111
+ {
112
+ "value": 1.445,
113
+ "start": "2022-01-04T03:00:00+01:00"
114
+ },
115
+ {
116
+ "value": 1.418,
117
+ "start": "2022-01-04T04:00:00+01:00"
118
+ },
119
+ {
120
+ "value": 1.664,
121
+ "start": "2022-01-04T05:00:00+01:00"
122
+ },
123
+ {
124
+ "value": 1.794,
125
+ "start": "2022-01-04T06:00:00+01:00"
126
+ },
127
+ {
128
+ "value": 1.938,
129
+ "start": "2022-01-04T07:00:00+01:00"
130
+ },
131
+ {
132
+ "value": 2.1,
133
+ "start": "2022-01-04T08:00:00+01:00"
134
+ },
135
+ {
136
+ "value": 2.085,
137
+ "start": "2022-01-04T09:00:00+01:00"
138
+ },
139
+ {
140
+ "value": 2.093,
141
+ "start": "2022-01-04T10:00:00+01:00"
142
+ },
143
+ {
144
+ "value": 2.059,
145
+ "start": "2022-01-04T11:00:00+01:00"
146
+ },
147
+ {
148
+ "value": 2.001,
149
+ "start": "2022-01-04T12:00:00+01:00"
150
+ },
151
+ {
152
+ "value": 1.948,
153
+ "start": "2022-01-04T13:00:00+01:00"
154
+ },
155
+ {
156
+ "value": 1.941,
157
+ "start": "2022-01-04T14:00:00+01:00"
158
+ },
159
+ {
160
+ "value": 1.982,
161
+ "start": "2022-01-04T15:00:00+01:00"
162
+ },
163
+ {
164
+ "value": 2.018,
165
+ "start": "2022-01-04T16:00:00+01:00"
166
+ },
167
+ {
168
+ "value": 2.099,
169
+ "start": "2022-01-04T17:00:00+01:00"
170
+ },
171
+ {
172
+ "value": 2.057,
173
+ "start": "2022-01-04T18:00:00+01:00"
174
+ },
175
+ {
176
+ "value": 1.925,
177
+ "start": "2022-01-04T19:00:00+01:00"
178
+ },
179
+ {
180
+ "value": 1.837,
181
+ "start": "2022-01-04T20:00:00+01:00"
182
+ },
183
+ {
184
+ "value": 1.771,
185
+ "start": "2022-01-04T21:00:00+01:00"
186
+ },
187
+ {
188
+ "value": 1.717,
189
+ "start": "2022-01-04T22:00:00+01:00"
190
+ },
191
+ {
192
+ "value": 1.429,
193
+ "start": "2022-01-04T23:00:00+01:00"
194
+ },
195
+ {
196
+ "value": 1.666,
197
+ "start": "2022-01-05T00:00:00+01:00"
198
+ },
199
+ {
200
+ "value": 1.544,
201
+ "start": "2022-01-05T01:00:00+01:00"
202
+ },
203
+ {
204
+ "value": 1.397,
205
+ "start": "2022-01-05T02:00:00+01:00"
206
+ },
207
+ {
208
+ "value": 1.294,
209
+ "start": "2022-01-05T03:00:00+01:00"
210
+ },
211
+ {
212
+ "value": 1.325,
213
+ "start": "2022-01-05T04:00:00+01:00"
214
+ },
215
+ {
216
+ "value": 1.523,
217
+ "start": "2022-01-05T05:00:00+01:00"
218
+ },
219
+ {
220
+ "value": 1.731,
221
+ "start": "2022-01-05T06:00:00+01:00"
222
+ },
223
+ {
224
+ "value": 1.737,
225
+ "start": "2022-01-05T07:00:00+01:00"
226
+ },
227
+ {
228
+ "value": 1.737,
229
+ "start": "2022-01-05T08:00:00+01:00"
230
+ },
231
+ {
232
+ "value": 1.742,
233
+ "start": "2022-01-05T09:00:00+01:00"
234
+ },
235
+ {
236
+ "value": 1.741,
237
+ "start": "2022-01-05T10:00:00+01:00"
238
+ },
239
+ {
240
+ "value": 1.728,
241
+ "start": "2022-01-05T11:00:00+01:00"
242
+ },
243
+ {
244
+ "value": 1.714,
245
+ "start": "2022-01-05T12:00:00+01:00"
246
+ },
247
+ {
248
+ "value": 1.713,
249
+ "start": "2022-01-05T13:00:00+01:00"
250
+ },
251
+ {
252
+ "value": 1.71,
253
+ "start": "2022-01-05T14:00:00+01:00"
254
+ },
255
+ {
256
+ "value": 1.715,
257
+ "start": "2022-01-05T15:00:00+01:00"
258
+ },
259
+ {
260
+ "value": 1.773,
261
+ "start": "2022-01-05T16:00:00+01:00"
262
+ },
263
+ {
264
+ "value": 1.853,
265
+ "start": "2022-01-05T17:00:00+01:00"
266
+ },
267
+ {
268
+ "value": 1.799,
269
+ "start": "2022-01-05T18:00:00+01:00"
270
+ },
271
+ {
272
+ "value": 1.753,
273
+ "start": "2022-01-05T19:00:00+01:00"
274
+ },
275
+ {
276
+ "value": 1.723,
277
+ "start": "2022-01-05T20:00:00+01:00"
278
+ },
279
+ {
280
+ "value": 1.74,
281
+ "start": "2022-01-05T21:00:00+01:00"
282
+ },
283
+ {
284
+ "value": 1.714,
285
+ "start": "2022-01-05T22:00:00+01:00"
286
+ },
287
+ {
288
+ "value": 1.696,
289
+ "start": "2022-01-05T23:00:00+01:00"
290
+ }
291
+ ],
292
+ "source": "Nordpool"
293
+ }