node-red-contrib-power-saver 3.4.2 → 3.5.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.
Files changed (134) hide show
  1. package/.github/workflows/{firebase-hosting-merge.yml → publish-doc-on-merge.yml} +6 -6
  2. package/.github/workflows/publish-to-npm.yml +23 -0
  3. package/.github/workflows/test-on-pull-request.yaml +13 -0
  4. package/docs/.vuepress/components/BestSaveVerificator.vue +18 -7
  5. package/docs/.vuepress/components/DonateButtons.vue +0 -1
  6. package/docs/.vuepress/config.js +9 -53
  7. package/docs/.vuepress/navbar.js +43 -0
  8. package/docs/.vuepress/public/Ukraine-heart-shape-flag.png +0 -0
  9. package/docs/changelog/README.md +14 -0
  10. package/docs/examples/example-cascade-temperature-control.md +0 -13
  11. package/docs/examples/example-heat-capacitor.md +9 -20
  12. package/docs/examples/example-nordpool-current-state.md +0 -13
  13. package/docs/examples/example-nordpool-events-state.md +0 -13
  14. package/docs/examples/example-tibber-mqtt.md +0 -13
  15. package/docs/faq/best-save-viewer.md +1 -0
  16. package/docs/guide/README.md +20 -12
  17. package/docs/images/best-save-config.png +0 -0
  18. package/docs/images/lowest-price-config.png +0 -0
  19. package/docs/nodes/ps-strategy-best-save.md +67 -11
  20. package/docs/nodes/ps-strategy-lowest-price.md +69 -0
  21. package/package.json +9 -11
  22. package/src/elvia/elvia-add-tariff.html +8 -2
  23. package/src/elvia/elvia-config.js +7 -0
  24. package/src/elvia/elvia-tariff-types.js +0 -6
  25. package/src/handle-input.js +30 -10
  26. package/src/receive-price-functions.js +2 -0
  27. package/src/strategy-best-save.html +14 -0
  28. package/src/strategy-best-save.js +6 -2
  29. package/src/strategy-lowest-price.html +15 -2
  30. package/src/strategy-lowest-price.js +3 -1
  31. package/src/utils.js +3 -3
  32. package/test/data/lowest-price-result-cont.json +1 -0
  33. package/test/data/lowest-price-result-missing-end.json +1 -0
  34. package/test/data/lowest-price-result-split-allday.json +1 -0
  35. package/test/data/lowest-price-result-split-allday10.json +1 -0
  36. package/test/data/lowest-price-result-split.json +1 -0
  37. package/test/data/tibber-result-end-0-24h.json +1 -0
  38. package/test/data/tibber-result-end-0.json +1 -0
  39. package/.firebase/hosting.ZG9jcy8udnVlcHJlc3MvZGlzdA.cache +0 -94
  40. package/.github/workflows/firebase-hosting-pull-request.yml +0 -17
  41. package/docs/.vuepress/dist/404.html +0 -33
  42. package/docs/.vuepress/dist/assets/css/835.styles.c5afb22b.css +0 -1
  43. package/docs/.vuepress/dist/assets/css/896.styles.21a80cb6.css +0 -1
  44. package/docs/.vuepress/dist/assets/css/styles.1c48cbd0.css +0 -10
  45. package/docs/.vuepress/dist/assets/img/add-tariff-flow.eb700d4f.png +0 -0
  46. package/docs/.vuepress/dist/assets/img/back-to-top.8b37f773.svg +0 -1
  47. package/docs/.vuepress/dist/assets/img/best-save-config.79a2f39a.png +0 -0
  48. package/docs/.vuepress/dist/assets/img/copy-payload-best-save.b9192985.png +0 -0
  49. package/docs/.vuepress/dist/assets/img/elvia-config-no-config.b4bb972c.png +0 -0
  50. package/docs/.vuepress/dist/assets/img/elvia-config-no-tariff.3f89aba8.png +0 -0
  51. package/docs/.vuepress/dist/assets/img/elvia-config-select-tariff.0f73fd56.png +0 -0
  52. package/docs/.vuepress/dist/assets/img/elvia-config-subscription-key.8be8ab8a.png +0 -0
  53. package/docs/.vuepress/dist/assets/img/elvia-flow.bae2a4d5.png +0 -0
  54. package/docs/.vuepress/dist/assets/img/example-flow-1.3ff3e23f.png +0 -0
  55. package/docs/.vuepress/dist/assets/img/example-flow-2.b653b58d.png +0 -0
  56. package/docs/.vuepress/dist/assets/img/heat-capacitor-temperatureVsPrice.6e74905b.png +0 -0
  57. package/docs/.vuepress/dist/assets/img/lowest-price-config.6d66a8c2.png +0 -0
  58. package/docs/.vuepress/dist/assets/img/migrate-best-save.f73420f6.png +0 -0
  59. package/docs/.vuepress/dist/assets/img/migrate-power-saver.aae13f9d.png +0 -0
  60. package/docs/.vuepress/dist/assets/img/next-schedule-entity.4406856a.png +0 -0
  61. package/docs/.vuepress/dist/assets/img/next-schedule-flow.413ad62b.png +0 -0
  62. package/docs/.vuepress/dist/assets/img/next-schedule-sensor.eb896bdd.png +0 -0
  63. package/docs/.vuepress/dist/assets/img/node-power-saver.51ff2e5d.png +0 -0
  64. package/docs/.vuepress/dist/assets/img/node-ps-elvia-add-tariff.94ea2b09.png +0 -0
  65. package/docs/.vuepress/dist/assets/img/node-ps-general-add-tariff.a3cf6f06.png +0 -0
  66. package/docs/.vuepress/dist/assets/img/node-ps-receive-price.76eaa418.png +0 -0
  67. package/docs/.vuepress/dist/assets/img/node-ps-strategy-best-save.392292d5.png +0 -0
  68. package/docs/.vuepress/dist/assets/img/node-ps-strategy-heat-capacitor-cascade-control.2e75ed9e.png +0 -0
  69. package/docs/.vuepress/dist/assets/img/node-ps-strategy-heat-capacitor-simple-flow-example.29d9bf59.png +0 -0
  70. package/docs/.vuepress/dist/assets/img/node-ps-strategy-lowest-price.3a4ad347.png +0 -0
  71. package/docs/.vuepress/dist/assets/img/oven-setpoint-calculation.5bda0eec.png +0 -0
  72. package/docs/.vuepress/dist/assets/img/overshoot-time.b3b5d70e.png +0 -0
  73. package/docs/.vuepress/dist/assets/img/power-saver-nordpool-current-state.bf14afde.png +0 -0
  74. package/docs/.vuepress/dist/assets/img/power-saver-nordpool-events-state.8c392507.png +0 -0
  75. package/docs/.vuepress/dist/assets/img/power-saver-tibber-mqtt.16891dd2.png +0 -0
  76. package/docs/.vuepress/dist/assets/js/229.5c5378fa.js +0 -1
  77. package/docs/.vuepress/dist/assets/js/331.872104cd.js +0 -1
  78. package/docs/.vuepress/dist/assets/js/405.f4edd94d.js +0 -2
  79. package/docs/.vuepress/dist/assets/js/405.f4edd94d.js.LICENSE.txt +0 -8
  80. package/docs/.vuepress/dist/assets/js/490.1e639e05.js +0 -1
  81. package/docs/.vuepress/dist/assets/js/491.bd938119.js +0 -1
  82. package/docs/.vuepress/dist/assets/js/555.d8963d84.js +0 -1
  83. package/docs/.vuepress/dist/assets/js/811.5f659592.js +0 -1
  84. package/docs/.vuepress/dist/assets/js/app.dfdee6f9.js +0 -1
  85. package/docs/.vuepress/dist/assets/js/runtime~app.f6ac32d7.js +0 -1
  86. package/docs/.vuepress/dist/assets/js/v-0607240a.0193a377.js +0 -1
  87. package/docs/.vuepress/dist/assets/js/v-08683c60.52e94cb6.js +0 -1
  88. package/docs/.vuepress/dist/assets/js/v-0aca7ba6.cac5d4b9.js +0 -1
  89. package/docs/.vuepress/dist/assets/js/v-0b5e3c8c.18561f6e.js +0 -1
  90. package/docs/.vuepress/dist/assets/js/v-1ad821fa.6697a349.js +0 -1
  91. package/docs/.vuepress/dist/assets/js/v-1b3a0ab8.c6c4e19b.js +0 -1
  92. package/docs/.vuepress/dist/assets/js/v-1e2b191e.07b8ab21.js +0 -1
  93. package/docs/.vuepress/dist/assets/js/v-29504124.00be7399.js +0 -1
  94. package/docs/.vuepress/dist/assets/js/v-30acb564.28af12af.js +0 -1
  95. package/docs/.vuepress/dist/assets/js/v-3706649a.c76d575b.js +0 -1
  96. package/docs/.vuepress/dist/assets/js/v-4637f9e4.d334c29a.js +0 -1
  97. package/docs/.vuepress/dist/assets/js/v-4c28314d.8cbb0f9d.js +0 -1
  98. package/docs/.vuepress/dist/assets/js/v-510ed0d4.c04bc2e4.js +0 -1
  99. package/docs/.vuepress/dist/assets/js/v-5954bcb2.dff3fc67.js +0 -1
  100. package/docs/.vuepress/dist/assets/js/v-5db8da3a.e5e6d7a6.js +0 -1
  101. package/docs/.vuepress/dist/assets/js/v-61f728ca.81968036.js +0 -1
  102. package/docs/.vuepress/dist/assets/js/v-677dfaed.c159b0f4.js +0 -1
  103. package/docs/.vuepress/dist/assets/js/v-7446a652.8fc2c591.js +0 -1
  104. package/docs/.vuepress/dist/assets/js/v-7c87f26e.8ed52391.js +0 -1
  105. package/docs/.vuepress/dist/assets/js/v-84304104.f3f07ed3.js +0 -1
  106. package/docs/.vuepress/dist/assets/js/v-8daa1a0e.ed84ca09.js +0 -1
  107. package/docs/.vuepress/dist/assets/js/v-b4a42144.9a2a0c9f.js +0 -1
  108. package/docs/.vuepress/dist/assets/js/v-e8c55052.b7d52fc6.js +0 -1
  109. package/docs/.vuepress/dist/assets/js/v-fffb8e28.d09ab959.js +0 -1
  110. package/docs/.vuepress/dist/changelog/index.html +0 -33
  111. package/docs/.vuepress/dist/contribute/index.html +0 -33
  112. package/docs/.vuepress/dist/euro.png +0 -0
  113. package/docs/.vuepress/dist/examples/example-cascade-temperature-control.html +0 -304
  114. package/docs/.vuepress/dist/examples/example-heat-capacitor.html +0 -247
  115. package/docs/.vuepress/dist/examples/example-next-schedule-entity.html +0 -43
  116. package/docs/.vuepress/dist/examples/example-nordpool-current-state.html +0 -206
  117. package/docs/.vuepress/dist/examples/example-nordpool-events-state.html +0 -191
  118. package/docs/.vuepress/dist/examples/example-tibber-mqtt.html +0 -199
  119. package/docs/.vuepress/dist/examples/index.html +0 -33
  120. package/docs/.vuepress/dist/faq/best-save-viewer.html +0 -33
  121. package/docs/.vuepress/dist/faq/index.html +0 -33
  122. package/docs/.vuepress/dist/guide/index.html +0 -70
  123. package/docs/.vuepress/dist/index.html +0 -33
  124. package/docs/.vuepress/dist/logo.png +0 -0
  125. package/docs/.vuepress/dist/nodes/index.html +0 -33
  126. package/docs/.vuepress/dist/nodes/old-power-saver-doc.html +0 -115
  127. package/docs/.vuepress/dist/nodes/power-saver.html +0 -33
  128. package/docs/.vuepress/dist/nodes/ps-elvia-add-tariff.html +0 -33
  129. package/docs/.vuepress/dist/nodes/ps-general-add-tariff.html +0 -33
  130. package/docs/.vuepress/dist/nodes/ps-receive-price.html +0 -98
  131. package/docs/.vuepress/dist/nodes/ps-strategy-best-save.html +0 -104
  132. package/docs/.vuepress/dist/nodes/ps-strategy-heat-capacitor.html +0 -260
  133. package/docs/.vuepress/dist/nodes/ps-strategy-lowest-price.html +0 -124
  134. package/docs/.vuepress/dist/nodes/strategy-input.html +0 -58
@@ -25,6 +25,7 @@ The node can work on a specific period from 1 to 24 hours during a 24 hour perio
25
25
  | Send When Rescheduling | Check this to make sure on or off output is sent immediately after rescheduling. |
26
26
  | If No Schedule, Send | What to do if there is no valid schedule any more (turn on or off). |
27
27
  | Outside Period, Send | Select the value to send outside the selected period. |
28
+ | Context storage | Select context storage to save data to, if you want other than the default. |
28
29
 
29
30
  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.
30
31
 
@@ -55,6 +56,7 @@ It is possible to change config dynamically by sending a config message to the n
55
56
  ```json
56
57
  "payload": {
57
58
  "config": {
59
+ "contextStorage": "file",
58
60
  "fromTime" : 10,
59
61
  "toTime" : 16,
60
62
  "hoursOn" : 3,
@@ -131,6 +133,29 @@ This operation cannot be undone.
131
133
  However, it is normally not a big loss, as you can just feed the node with new price data and start from scratch.
132
134
  :::
133
135
 
136
+ #### replan
137
+
138
+ By sending this command, you can have the node read the last received prices from the context storage,
139
+ and make a plan based on those prices:
140
+
141
+ ```json
142
+ "payload": {
143
+ "commands": {
144
+ "replan": true,
145
+ }
146
+ }
147
+ ```
148
+
149
+ If the context storage is `file` you can use this to create a new schedule after a restart,
150
+ instead of fetching prices again.
151
+
152
+ ### Config saved in context
153
+
154
+ The nodes config is saved in the nodes context.
155
+ If dynamic config is sent as input, this replaces the saved config.
156
+ It is the config that is saved in context that is used when calculating.
157
+ When Node-RED starts or the flow is redeployed, the config defined in the node replaces the saved config and will be used when planning.
158
+
134
159
  ## Input
135
160
 
136
161
  The input is the [common strategy input format](./strategy-input.md)
@@ -196,6 +221,7 @@ Example of output:
196
221
  ],
197
222
  "source": "Tibber",
198
223
  "config": {
224
+ "contextStorage": "default",
199
225
  "fromTime": "04",
200
226
  "toTime": "18",
201
227
  "hoursOn": "06",
@@ -211,6 +237,49 @@ Example of output:
211
237
 
212
238
  The `schedule` array shows every time the switch is turned on or off. The `hours` array shows values per hour containing the price (received as input), whether that hour is on or off, the start time of the hour and the amount per kWh that is saved on hours that are turned off, compared to the next hour that is on.
213
239
 
240
+ ## Restarts and saved context
241
+
242
+ The config, last received prices and the last calculated schedule are saved to the nodes context.
243
+ This may be saved to memory, to file or to another destination based on how your Node-RED is configured.
244
+ If multiple context storages are defined, you can select which one to use in the nodes config.
245
+ If there is only one context storage defined, this is normally `memory`. In that case, data is not saved over restarts.
246
+ It is common to have two different context storages defined, `memory` and `file`, but there may be more.
247
+ It is also common to have a `default` context storage defined, and often this points to either `memory` or `file`.
248
+ However, the configuration can be different from this.
249
+
250
+ You can find this configuration in the `settings.js` file for Node-RED, usually in the node-red config folder.
251
+ In Home Assistant, this is normally `/config/node-red/settings.js`.
252
+
253
+ Here is an example of a configuration for the context storage:
254
+
255
+ ```js
256
+ contextStorage: {
257
+ file: { module: "localfilesystem"},
258
+ default: { module: "memory" }
259
+ }
260
+ ```
261
+
262
+ By default, this node saves context to the `default` context storage. In the example above, this is memory.
263
+ Then it is not preserved over a restart.
264
+ Please read the [Node-RED documentation](https://nodered.org/docs/user-guide/context) for more details about this.
265
+
266
+ The data that is saved is the config, the last used prices and the last calculated schedule.
267
+
268
+ When Node-RED restarts, the config is reset to what is defined in the node config, so by default,
269
+ nothing is read from the context storage after a restart. However, if you send a `replan` command to the
270
+ nodes input, a plan is recalculated, using the last received prices. One way to do this is to use an `inject` node,
271
+ and set `msg.payload` to the following JSON value:
272
+
273
+ ```json
274
+ {
275
+ "commands": {
276
+ "replan": true
277
+ }
278
+ }
279
+ ```
280
+
281
+ This is an alternative to fetching new prices and send as input.
282
+
214
283
  ## Tips & tricks
215
284
 
216
285
  ### Multiple nodes works together
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-power-saver",
3
- "version": "3.4.2",
3
+ "version": "3.5.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": {
@@ -45,22 +45,20 @@
45
45
  "url": "https://github.com/ottopaulsen/node-red-contrib-power-saver.git"
46
46
  },
47
47
  "devDependencies": {
48
- "@vuepress/bundler-webpack": "^2.0.0-alpha.1",
49
- "@vuepress/plugin-register-components": "^2.0.0-beta.33",
50
- "@vuepress/utils": "^2.0.0-beta.27",
48
+ "@vuepress/bundler-vite": "^2.0.0-beta.36",
49
+ "@vuepress/plugin-register-components": "^2.0.0-beta.36",
50
+ "@vuepress/utils": "^2.0.0-beta.35",
51
+ "sass-loader": "^12.6.0",
52
+ "vuepress": "^2.0.0-beta.36",
51
53
  "expect": "^27.5.1",
52
54
  "mocha": "^9.2.0",
53
- "node-red": "^2.2.0",
54
- "node-red-node-test-helper": "^0.2.7",
55
- "patch-vue-directive-ssr": "^0.0.1",
56
- "vuepress": "^2.0.0-beta.35",
57
- "vuepress-webpack": "^2.0.0-beta.35"
55
+ "node-red": "^2.2.2",
56
+ "node-red-node-test-helper": "^0.2.7"
58
57
  },
59
58
  "dependencies": {
60
- "@vitejs/plugin-vue": "^2.2.0",
61
59
  "floating-vue": "^2.0.0-beta.6",
62
60
  "lodash.clonedeep": "^4.5.0",
63
- "luxon": "^2.3.0",
61
+ "luxon": "^2.3.1",
64
62
  "node-fetch": "^2.6.7"
65
63
  }
66
64
  }
@@ -18,13 +18,15 @@
18
18
  oneditprepare: function () {
19
19
  const readTariffTypes = function () {
20
20
  const configId = $("#node-input-elviaConfig").val();
21
- if (!configId) {
21
+ if (configId === "_ADD_") {
22
+ $("#keyMessage").hide();
22
23
  return;
23
24
  }
24
25
  $.getJSON("elvia-tariff-types?configId=" + configId, function (data) {
25
26
  if (!data.tariffTypes) {
26
27
  return;
27
28
  }
29
+ $("#keyMessage").hide();
28
30
  $("#node-input-tariffKey").typedInput({
29
31
  types: [
30
32
  {
@@ -38,6 +40,7 @@
38
40
  });
39
41
  };
40
42
  $("#node-input-elviaConfig").on("change", function () {
43
+ $("#keyMessage").show();
41
44
  readTariffTypes();
42
45
  });
43
46
  readTariffTypes();
@@ -58,10 +61,13 @@
58
61
  <label for="node-input-tariffKey"><i class="fa fa-tag"></i> Tariff key</label>
59
62
  <input type="text" id="node-input-tariffKey" placeholder="Tariff" style="width: 300px" />
60
63
  </div>
64
+ <div id="keyMessage" class="form-row">
65
+ <p>When Subscription key is set in the Elvia config,<br />you must deploy once to get the list of tariff keys.</p>
66
+ </div>
61
67
  </script>
62
68
 
63
69
  <script type="text/markdown" data-help-name="ps-elvia-add-tariff">
64
- # Elvia Add Tariff
70
+ # Elvia Add Tariff (deprecated)
65
71
 
66
72
  A node to get the tariff from Elvia and add it to the price before it is sent to the power saver strategy nodes.
67
73
  Use this node between the receive-price node and any of the strategy nodes.
@@ -10,6 +10,13 @@ module.exports = function (RED) {
10
10
  const configList = this.context().global.get("elviaConfigList") || [];
11
11
  configList.push(config);
12
12
  this.context().global.set("elviaConfigList", configList);
13
+
14
+ const key = this.credentials.elviaSubscriptionKey;
15
+ RED.httpAdmin.get("/elvia-tariff-types", RED.auth.needsPermission("ps-elvia-config.read"), function (req, res) {
16
+ getTariffTypes(null, key).then((json) => {
17
+ res.json(json);
18
+ });
19
+ });
13
20
  }
14
21
  RED.nodes.registerType("ps-elvia-config", ElviaConfigNode, {
15
22
  credentials: {
@@ -13,12 +13,6 @@ module.exports = function (RED) {
13
13
  node.send([{ payload: json }]);
14
14
  });
15
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
- });
22
16
  }
23
17
 
24
18
  RED.nodes.registerType("ps-elvia-tariff-types", PsElviaTariffTypesNode);
@@ -8,13 +8,29 @@ function handleStrategyInput(node, msg, doPlanning) {
8
8
  if (!validateInput(node, msg)) {
9
9
  return;
10
10
  }
11
+ if (msg.payload.commands && !anyLegalCommands(msg.payload.commands)) {
12
+ const message = "Illegal command";
13
+ node.warn(message);
14
+ node.status({ fill: "yellow", shape: "dot", text: message });
15
+ return;
16
+ }
11
17
  if (msg.payload.commands && msg.payload.commands.reset) {
12
18
  node.warn("Resetting node context by command");
13
19
  // Reset all saved data
14
- node.context().set(["lastPlan", "lastPriceData", "lastSource"], [undefined, undefined, undefined]);
20
+ node
21
+ .context()
22
+ .set(["lastPlan", "lastPriceData", "lastSource"], [undefined, undefined, undefined], node.contextStorage);
15
23
  deleteSavedScheduleBefore(node, DateTime.now().plus({ days: 2 }), 100);
16
24
  }
17
- const { priceData, source } = getPriceData(node, msg);
25
+ let { priceData, source } = getPriceData(node, msg);
26
+ if (!priceData) {
27
+ // Use last saved price data
28
+ priceData = node.context().get("lastPriceData");
29
+ source = node.context().get("lastSource");
30
+ const message = "Using saved prices";
31
+ node.warn(message);
32
+ node.status({ fill: "green", shape: "ring", text: message });
33
+ }
18
34
  if (!priceData) {
19
35
  const message = "No price data";
20
36
  node.warn(message);
@@ -38,7 +54,7 @@ function handleStrategyInput(node, msg, doPlanning) {
38
54
  const plan = doPlanning(node, effectiveConfig, priceData, planFromTime, dateDayBefore, dateToday);
39
55
 
40
56
  // Save schedule
41
- node.context().set("lastPlan", plan);
57
+ node.context().set("lastPlan", plan, node.contextStorage);
42
58
  dates.forEach((d) => saveDayData(node, d, extractPlanForDate(plan, d)));
43
59
 
44
60
  const sentOnCommand = !!msg.payload.commands?.sendSchedule;
@@ -84,14 +100,14 @@ function getPriceData(node, msg) {
84
100
  const isCommandMsg = !!msg?.payload?.commands;
85
101
  const isPriceMsg = !!msg?.payload?.priceData;
86
102
  if ((isConfigMsg || isCommandMsg) && !isPriceMsg) {
87
- const priceData = node.context().get("lastPriceData");
88
- const source = node.context().get("lastSource");
103
+ const priceData = node.context().get("lastPriceData", node.contextStorage);
104
+ const source = node.context().get("lastSource", node.contextStorage);
89
105
  return { priceData, source };
90
106
  }
91
107
  const priceData = msg.payload.priceData;
92
108
  const source = msg.payload.source;
93
- node.context().set("lastPriceData", priceData);
94
- node.context().set("lastSource", source);
109
+ node.context().set("lastPriceData", priceData, node.contextStorage);
110
+ node.context().set("lastSource", source, node.contextStorage);
95
111
  return { priceData, source };
96
112
  }
97
113
 
@@ -129,14 +145,14 @@ function deleteSavedScheduleBefore(node, day, checkDays = 0) {
129
145
  let count = 0;
130
146
  do {
131
147
  date = date.plus({ days: -1 });
132
- data = node.context().get(date.toISODate());
133
- node.context().set(date.toISODate(), undefined);
148
+ data = node.context().get(date.toISODate(), node.contextStorage);
149
+ node.context().set(date.toISODate(), undefined, node.contextStorage);
134
150
  count++;
135
151
  } while (data !== undefined || count <= checkDays);
136
152
  }
137
153
 
138
154
  function saveDayData(node, date, plan) {
139
- node.context().set(date, plan);
155
+ node.context().set(date, plan, node.contextStorage);
140
156
  }
141
157
 
142
158
  function sendSwitch(node, onOff) {
@@ -181,6 +197,10 @@ function validateInput(node, msg) {
181
197
  return true;
182
198
  }
183
199
 
200
+ function anyLegalCommands(commands) {
201
+ return ["reset", "replan", "sendOutput", "sendSchedule"].some((v) => commands.hasOwnProperty(v));
202
+ }
203
+
184
204
  module.exports = {
185
205
  handleStrategyInput,
186
206
  validateInput,
@@ -14,6 +14,8 @@ function getPriceData(node, msg) {
14
14
  priceData = [...input.today, ...input.tomorrow];
15
15
  const source = input.source;
16
16
  node.context().set("lastPriceData", priceData);
17
+ const statusMsg = priceData.length + " hours from " + source;
18
+ node.status({ fill: "green", shape: "ring", text: statusMsg });
17
19
  return { priceData, source };
18
20
  }
19
21
 
@@ -26,6 +26,7 @@
26
26
  align: "left",
27
27
  },
28
28
  outputIfNoSchedule: { value: "true", required: true, align: "left" },
29
+ contextStorage: { value: "default", required: false, align: "left" },
29
30
  },
30
31
  inputs: 1,
31
32
  outputs: 3,
@@ -47,6 +48,14 @@
47
48
  },
48
49
  ],
49
50
  });
51
+ $("#node-input-contextStorage").typedInput({
52
+ types: [
53
+ {
54
+ value: "storages",
55
+ options: RED.settings.context.stores.map((s) => ({ value: s, label: s })),
56
+ },
57
+ ],
58
+ });
50
59
  },
51
60
  });
52
61
  </script>
@@ -86,6 +95,11 @@
86
95
  <input type="text" id="node-input-outputIfNoSchedule" style="width: 80px">
87
96
  </label>
88
97
  </div>
98
+ <h3>Context storage</h3>
99
+ <div class="form-row">
100
+ <label for="node-input-contextStorage"><i class="fa fa-archive"></i> Context storage</label>
101
+ <input type="text" id="node-input-contextStorage" style="width: 160px">
102
+ </div>
89
103
  </script>
90
104
 
91
105
  <script type="text/markdown" data-help-name="ps-strategy-best-save">
@@ -9,14 +9,18 @@ module.exports = function (RED) {
9
9
  RED.nodes.createNode(this, config);
10
10
  const node = this;
11
11
 
12
+ node.status({});
13
+
12
14
  const originalConfig = {
13
15
  maxHoursToSaveInSequence: config.maxHoursToSaveInSequence,
14
16
  minHoursOnAfterMaxSequenceSaved: config.minHoursOnAfterMaxSequenceSaved,
15
17
  minSaving: parseFloat(config.minSaving),
16
18
  sendCurrentValueWhenRescheduling: config.sendCurrentValueWhenRescheduling,
17
19
  outputIfNoSchedule: config.outputIfNoSchedule === "true",
20
+ contextStorage: config.contextStorage || "default",
18
21
  };
19
- node.context().set("config", originalConfig);
22
+ node.context().set("config", originalConfig, originalConfig.contextStorage);
23
+ node.contextStorage = originalConfig.contextStorage;
20
24
 
21
25
  node.on("close", function () {
22
26
  clearTimeout(node.schedulingTimeout);
@@ -55,7 +59,7 @@ function doPlanning(node, _, priceData, _, dateDayBefore, _) {
55
59
  const values = priceData.map((d) => d.value);
56
60
  const startTimes = priceData.map((d) => d.start);
57
61
  const onOffBefore = dataJustBefore.hours.map((h) => h.onOff);
58
- const lastPlanHours = node.context().get("lastPlan")?.hours ?? [];
62
+ const lastPlanHours = node.context().get("lastPlan", node.contextStorage)?.hours ?? [];
59
63
  const plan = makePlan(node, values, startTimes, onOffBefore);
60
64
  const includeFromLastPlanHours = lastPlanHours.filter(
61
65
  (h) => h.start < plan.hours[0].start && h.start >= priceData[0].start
@@ -55,6 +55,7 @@
55
55
  },
56
56
  outputIfNoSchedule: { value: "true", required: true, align: "left" },
57
57
  outputOutsidePeriod: { value: "false", required: true, align: "left" },
58
+ contextStorage: { value: "default", required: false, align: "left" },
58
59
  },
59
60
  inputs: 1,
60
61
  outputs: 3,
@@ -115,6 +116,14 @@
115
116
  },
116
117
  ],
117
118
  });
119
+ $("#node-input-contextStorage").typedInput({
120
+ types: [
121
+ {
122
+ value: "storages",
123
+ options: RED.settings.context.stores.map((s) => ({ value: s, label: s })),
124
+ },
125
+ ],
126
+ });
118
127
  },
119
128
  });
120
129
  </script>
@@ -125,11 +134,11 @@
125
134
  <input type="text" id="node-input-name" placeholder="Name" style="width: 240px">
126
135
  </div>
127
136
  <div class="form-row">
128
- <label for="node-input-fromTime"><i class="fa fa-arrows-h"></i> From time</label>
137
+ <label for="node-input-fromTime"><i class="fa fa-clock-o"></i> From time</label>
129
138
  <input type="text" id="node-input-fromTime" style="width: 80px">
130
139
  </div>
131
140
  <div class="form-row">
132
- <label for="node-input-toTime"><i class="fa fa-arrows-h"></i> To time</label>
141
+ <label for="node-input-toTime"><i class="fa fa-clock-o"></i> To time</label>
133
142
  <input type="text" id="node-input-toTime" style="width: 80px">
134
143
  </div>
135
144
  <div class="form-row">
@@ -159,6 +168,10 @@
159
168
  <input type="text" id="node-input-outputOutsidePeriod" style="width: 80px">
160
169
  </label>
161
170
  </div>
171
+ <div class="form-row">
172
+ <label for="node-input-contextStorage"><i class="fa fa-archive"></i> Context storage</label>
173
+ <input type="text" id="node-input-contextStorage" style="width: 160px">
174
+ </div>
162
175
  </script>
163
176
 
164
177
  <script type="text/markdown" data-help-name="ps-strategy-lowest-price">
@@ -7,6 +7,7 @@ module.exports = function (RED) {
7
7
  function StrategyLowestPriceNode(config) {
8
8
  RED.nodes.createNode(this, config);
9
9
  const node = this;
10
+ node.status({});
10
11
 
11
12
  const originalConfig = {
12
13
  fromTime: config.fromTime,
@@ -16,8 +17,9 @@ module.exports = function (RED) {
16
17
  sendCurrentValueWhenRescheduling: booleanConfig(config.sendCurrentValueWhenRescheduling),
17
18
  outputIfNoSchedule: booleanConfig(config.outputIfNoSchedule),
18
19
  outputOutsidePeriod: booleanConfig(config.outputOutsidePeriod),
20
+ contextStorage: config.contextStorage || "default",
19
21
  };
20
- node.context().set("config", originalConfig);
22
+ node.context().set("config", originalConfig, node.contextStorage);
21
23
 
22
24
  node.on("close", function () {
23
25
  clearTimeout(node.schedulingTimeout);
package/src/utils.js CHANGED
@@ -57,14 +57,14 @@ function getDiff(large, small) {
57
57
  }
58
58
 
59
59
  function getEffectiveConfig(node, msg) {
60
- const res = node.context().get("config");
60
+ const res = node.context().get("config", node.contextStorage);
61
61
  const isConfigMsg = !!msg?.payload?.config;
62
62
  if (isConfigMsg) {
63
63
  const inputConfig = msg.payload.config;
64
64
  Object.keys(inputConfig).forEach((key) => {
65
65
  res[key] = inputConfig[key];
66
66
  });
67
- node.context().set("config", res);
67
+ node.context().set("config", res, node.contextStorage);
68
68
  }
69
69
  return res;
70
70
  }
@@ -73,7 +73,7 @@ function loadDayData(node, date) {
73
73
  // Load saved schedule for the date (YYYY-MM-DD)
74
74
  // Return null if not found
75
75
  const key = date.toISODate();
76
- const saved = node.context().get(key);
76
+ const saved = node.context().get(key, node.contextStorage);
77
77
  const res = saved ?? {
78
78
  schedule: [],
79
79
  hours: [],
@@ -7,6 +7,7 @@
7
7
  { "time": "2021-10-12T16:00:00.000+02:00", "value": false }
8
8
  ],
9
9
  "config": {
10
+ "contextStorage": "default",
10
11
  "doNotSplit": true,
11
12
  "fromTime": "10",
12
13
  "hoursOn": 4,
@@ -306,6 +306,7 @@
306
306
  ],
307
307
  "source": "Nordpool",
308
308
  "config": {
309
+ "contextStorage": "default",
309
310
  "fromTime": "22",
310
311
  "toTime": "08",
311
312
  "hoursOn": 3,
@@ -10,6 +10,7 @@
10
10
  { "time": "2021-10-12T15:00:00.000+02:00", "value": false }
11
11
  ],
12
12
  "config": {
13
+ "contextStorage": "default",
13
14
  "doNotSplit": false,
14
15
  "fromTime": "00",
15
16
  "hoursOn": 8,
@@ -9,6 +9,7 @@
9
9
  { "time": "2021-10-12T10:00:00.000+02:00", "value": true }
10
10
  ],
11
11
  "config": {
12
+ "contextStorage": "default",
12
13
  "doNotSplit": false,
13
14
  "fromTime": "10",
14
15
  "hoursOn": 10,
@@ -9,6 +9,7 @@
9
9
  { "time": "2021-10-12T20:00:00.000+02:00", "value": false }
10
10
  ],
11
11
  "config": {
12
+ "contextStorage": "default",
12
13
  "doNotSplit": false,
13
14
  "fromTime": "10",
14
15
  "hoursOn": 6,
@@ -309,6 +309,7 @@
309
309
  ],
310
310
  "source": "Tibber",
311
311
  "config": {
312
+ "contextStorage": "default",
312
313
  "fromTime": "16",
313
314
  "toTime": "00",
314
315
  "hoursOn": 3,
@@ -157,6 +157,7 @@
157
157
  ],
158
158
  "source": "Tibber",
159
159
  "config": {
160
+ "contextStorage": "default",
160
161
  "fromTime": "16",
161
162
  "toTime": "00",
162
163
  "hoursOn": 3,
@@ -1,94 +0,0 @@
1
- 404.html,1645811434412,addf965cf1261688558a31883296f39b2f4f4deef29686ea625d7dbc60b24aab
2
- euro.png,1645811429838,e6a1d246a05e447333de6e1099b1c3a5ae8ad050b2389e51ff53289e4dc1b8e4
3
- index.html,1645811433976,06fa65afbcca0c52835a4f44f0e194f510d10896bc967048ad113d27c16e32c7
4
- assets/img/back-to-top.8b37f773.svg,1645811429403,c6af5f9d1f495b4bb193a957cf5cbddd69b3df8346fb0ad8421ff29e872e660b
5
- assets/css/835.styles.c5afb22b.css,1645811429836,54c8fc773468d5ab5cacbd55f0535bf1cacbd57cb0ab43cde2a6bc4ea405b80e
6
- assets/css/styles.1c48cbd0.css,1645811429835,d38c8f7fb1e27516179de03c640af9e818968bc17ae1de343bbad594c8f070e7
7
- assets/img/next-schedule-flow.413ad62b.png,1645811429478,dc39e108b2e1c231df8172b375f73bbdce6dba5e7b19b16524c81a15a1ce1036
8
- assets/img/next-schedule-sensor.eb896bdd.png,1645811429478,3017cdc42afaeeccd07240a18729b59264175c8ef7f17d4bf89ecc12dcfd1723
9
- assets/img/node-power-saver.51ff2e5d.png,1645811429572,bc03e13706d001771796195e67e237873c2f2b3fd014e7f8003d80e3c5e09ea9
10
- assets/img/node-ps-strategy-best-save.392292d5.png,1645811429572,d9e48500b4df8cdcb2696faeaea1c5e9f462299a07b0231c1a2e4e8d4d88f7bb
11
- assets/img/node-ps-elvia-add-tariff.94ea2b09.png,1645811429572,82f83794ebee8920524f2c8fb0123014cf8ef0182600c34ca2c170b2adefd970
12
- assets/img/node-ps-strategy-heat-capacitor-simple-flow-example.29d9bf59.png,1645811429404,31d4e2481f50bf3d26b77e1f53899bb10ee214a8c9675114738a4f8fa2c361d2
13
- assets/img/node-ps-receive-price.76eaa418.png,1645811429572,9d8f62d2b5bee458952cd895a143a2c757ba5ae6cd7e13afd3103b7872619571
14
- assets/img/node-ps-general-add-tariff.a3cf6f06.png,1645811429572,0e6ef51de245944acad043cbf6b4c1a9f3762cb0d59c721afd67b8a9fa93dc90
15
- assets/js/229.5c5378fa.js,1645811429830,a649744039e357eab133a3e44074efc5665b3a4383c379fb0cc55f1df088fec2
16
- assets/img/node-ps-strategy-lowest-price.3a4ad347.png,1645811429573,dd4e368f5c81e87f64770a5d80b4c026d92fc89a72589f2d8b163e6a251c3662
17
- assets/js/331.872104cd.js,1645811429830,ac8099e339f2179b45098df3f3501bf9c9cbecc49d93e89c17fa1b607db590a9
18
- assets/js/491.bd938119.js,1645811429830,539cd56bfe8011f139c577cd90fc6673eb8e50822b8d9a807525f7a334249cbe
19
- assets/js/555.d8963d84.js,1645811429830,a354ff7311608a93d08a80fe8e7aff411f4686e294327513d4452d17ee3a0245
20
- assets/js/app.dfdee6f9.js,1645811429403,ccaf87278783d889e683b34df5ddf58f79140e6c8af3f199c5faf86ae7bbabe9
21
- assets/js/v-0607240a.0193a377.js,1645811429404,e9df5a61d68a4d048016061b2e91795ab26b42e07076b5a8fbba6a96691316a5
22
- assets/js/runtime~app.f6ac32d7.js,1645811429403,3c96eeef778202b135996b788cc7ec43a5b81d3771351c9240d68b7bb80019e9
23
- assets/js/811.5f659592.js,1645811429830,4f6777db824062a896831c035032022dcd45d93f634d5afb37e610442f146eef
24
- assets/css/896.styles.21a80cb6.css,1645811429836,bf775e319685fb2df3ca08ddfecb2a6c0670886b5e9829fa0df3b7723b1d9610
25
- logo.png,1645811429838,b0d240bb816f26ca3207f1c99f0db945e48b75928ce80b4b3500035a2627583c
26
- assets/img/elvia-config-no-config.b4bb972c.png,1645811429765,b6d893cf4f56713f3004aff49f28339645ec68e885ec30503740ff071050b643
27
- assets/img/elvia-config-no-tariff.3f89aba8.png,1645811429765,00eee1c51ab3b19e3db8b139071d7596f61601b4295edcc69ad503bcea026d2f
28
- assets/img/elvia-config-subscription-key.8be8ab8a.png,1645811429766,1e8f457772d4941c9f4a245e84e0cd89f8d0387b11464a3eab3533ed50780e9b
29
- assets/img/next-schedule-entity.4406856a.png,1645811429404,d6f36c55bef22fdb27e7a793144016b9b5688fdb7c0f358f446bec4871cb59f1
30
- assets/js/405.f4edd94d.js.LICENSE.txt,1645811429852,adc4d946db037aab89d8d540dc5ba92ec41212a9777b284c2189f3e90729031c
31
- assets/img/node-ps-strategy-heat-capacitor-cascade-control.2e75ed9e.png,1645811429404,277fec95ceb1f4a608c512a361778e21da49cfa48f630f43ced60abf7b586c00
32
- assets/js/v-08683c60.52e94cb6.js,1645811429765,8fd25e78ba78bf62dd075a073b9086ea02abcc6dc868432651192b73d76ef356
33
- assets/img/oven-setpoint-calculation.5bda0eec.png,1645811429404,d59c196f156dbb561106368065b08b9fa16b0555e0683d3d9c6ef2a123b6b787
34
- assets/img/add-tariff-flow.eb700d4f.png,1645811429766,a27790951f13dec75da0da079edeb58378aaa6f74c1d708a0c1b5aea846ae808
35
- assets/img/lowest-price-config.6d66a8c2.png,1645811429817,2e8328c5ccb07158c1c2edb5a5a1b4746f7a773b3a380d88fff2f9da279ffed2
36
- assets/img/heat-capacitor-temperatureVsPrice.6e74905b.png,1645811429404,4ec0ee90f5f8c110e17a07f1c6572c1d6ef31a318e3cc58125680aae6ac39a30
37
- assets/js/490.1e639e05.js,1645811429830,006ac095ab16f790b2c0dd877e05da95dfe6781a5fe3b97f0aa20ba1cec548a4
38
- assets/img/overshoot-time.b3b5d70e.png,1645811429404,c855af9a434f7d56928446dba5466f7fbf62958acf6f53d1230db16d0c40712f
39
- assets/img/best-save-config.79a2f39a.png,1645811429817,0e854e0ad8521268786a86789707053d08f60f7810bf9bbb1c6cbfc9485c657d
40
- assets/img/power-saver-nordpool-events-state.8c392507.png,1645811429479,d8cb79a6ded596050e5ba9a81c21d2277a76ac6c43f388d664aae9559f420780
41
- assets/img/elvia-flow.bae2a4d5.png,1645811429766,a3bbae90b0a528c8975ed92cad0d3cf354aaf6b2df8a8ec8c2f92d55d21e97df
42
- assets/img/elvia-config-select-tariff.0f73fd56.png,1645811429766,db2bce470db8a714b87e3d07b915d225395b49ae2bc99a271f37844d3356e22f
43
- assets/img/migrate-power-saver.aae13f9d.png,1645811429765,0f2c1fd39fcea757d41d48b07d2d02832c14d289ee63ed7175d5fddc8f62bcf6
44
- assets/img/example-flow-2.b653b58d.png,1645811429572,44970df39fb4d1a30778770f91211ef95f13cf14a2137324b955aadff47ab17e
45
- assets/img/power-saver-nordpool-current-state.bf14afde.png,1645811429478,51824f9b48565e1f6f1f1ab8472bce7a2f5045f4bb9312989a10819c1502945c
46
- assets/js/v-0aca7ba6.cac5d4b9.js,1645811429404,fd917a61330af443c75121fe1b5e75c4ceaa301b41aa1d3f9b732433d6a51f08
47
- assets/js/v-1ad821fa.6697a349.js,1645811429648,5e234e0b6d24a8d5916ad639ba74e8eeed633189cecd2d94378d5a2ad1a44afe
48
- assets/js/v-0b5e3c8c.18561f6e.js,1645811429766,0524b7021c8108c02443e57036de24a8a5813b411680cb8e87bc58b61f51ad9a
49
- assets/js/v-1e2b191e.07b8ab21.js,1645811429766,f5a6522cd598f7cb571516449564ae6a9b7b462631c8418a010a28b4a2c3f629
50
- assets/js/v-1b3a0ab8.c6c4e19b.js,1645811429404,529c684f973444575730eeec02703784e32c2904cf74674211a5c163b2fe1e10
51
- assets/js/v-29504124.00be7399.js,1645811429479,c0373166d28da75d579079f694caa8698c63db39ab793bd653aa2b5266c93546
52
- assets/js/v-3706649a.c76d575b.js,1645811429830,c1af291965ecc14041d9aa38724848f00d33561d315b43b2bf6e48d200b0e2ff
53
- assets/js/v-30acb564.28af12af.js,1645811429478,969bd26194d7167ee1d2cd806bc661b57de72b78c20556ef627a182b5b06a6b7
54
- assets/img/migrate-best-save.f73420f6.png,1645811429572,7dbcde0717bc45d78d3d1e77282f9750aba2a49f3364604a7e29911fbfc490eb
55
- assets/js/v-510ed0d4.c04bc2e4.js,1645811429403,01aa6cacf6019a9a13c26aab563249af4af8d624cf20637509d124e0432da722
56
- assets/js/v-5954bcb2.dff3fc67.js,1645811429830,5adc728d7d199c2c278d9849b9d854eccd6153f9fbbc0215038b1ca39ca4ba74
57
- assets/js/v-4637f9e4.d334c29a.js,1645811429817,66b8a40eefc05a5fdf776b56cdc57ef82764007fc3e56274109ab268e26f2ae2
58
- assets/js/v-677dfaed.c159b0f4.js,1645811429766,986de6433a55b6b829ab497b789b3990bec8be3d1eeb65a1ec07015729204fd9
59
- assets/js/v-5db8da3a.e5e6d7a6.js,1645811429479,2584b0b9bb3cdd4567c6d4f9d98caa717f832f12b9060f44b248038dd9280429
60
- assets/js/v-7c87f26e.8ed52391.js,1645811429479,0fba319bf35d8c3c07bf9b0c31a75a6b304af1e732ef08aab71a759af099c3d0
61
- assets/js/v-61f728ca.81968036.js,1645811429478,79e92e6e9b476275dd1472045777f9326be5f3c97850fe3a9be6bddc808da23e
62
- assets/js/v-8daa1a0e.ed84ca09.js,1645811429403,84a5a30cb2e59ada56691b1df6fe69be6d786cec8b75e14801825519af70dcb1
63
- assets/js/v-7446a652.8fc2c591.js,1645811429479,d1615da751dd371cb5bed434cbef5b6fbff6d7a8cf6d4c00c6dff6409a85d8b8
64
- assets/js/v-b4a42144.9a2a0c9f.js,1645811429573,d3142bccc90c0404147ea31a45103ced4b2eda0117492868a433cd9b408493c0
65
- assets/js/v-84304104.f3f07ed3.js,1645811429404,7439928b4c8e094cb03a4c2a58c72391981867578fd39665604d91d76c8699ef
66
- assets/js/v-e8c55052.b7d52fc6.js,1645811429572,fc09eb3b7463332fc69dd5ab437216f91948ae8f91f6c62b0f47e3f3d82da9cc
67
- assets/js/v-fffb8e28.d09ab959.js,1645811429568,979fe0e5f53f986da5ef18761193d3a0be919dcc5378c5df4fd68ee6883f126a
68
- changelog/index.html,1645811434019,f94505f81d65a9359ad42b61d6a8967430655f72af37b1fea126f08f249ad968
69
- contribute/index.html,1645811434125,369de0bd83f5df6d05ffef6063228093570480c1ba7b375658235cc1c4c530dd
70
- examples/example-next-schedule-entity.html,1645811434083,5a0924250f7a0558e6faf85a37226e6dc999d882b0e141b2227a90618cdbfb65
71
- assets/img/copy-payload-best-save.b9192985.png,1645811429480,7b12f6464e3fc8a83222e1e55d0ecdc81c9fdf5356eadd173c98313a45f44f75
72
- examples/example-heat-capacitor.html,1645811434072,8fd6265569df05dd7ec38a2a20a011e0f2afd6e9b2adb6a219901a0f62a7d0c8
73
- examples/example-nordpool-current-state.html,1645811434092,271c108f7953fff08d601564d028721e49f9164ba8414b2d19c7a91ef383e1d0
74
- examples/example-nordpool-events-state.html,1645811434102,a4735ce22fa2a7300366027b1aeb9e9fc670ff92bbc0bd7181b93927e6395360
75
- examples/example-tibber-mqtt.html,1645811434115,195ccc9339fd616fe3e0f279cf45e40477686b3358ccde46df4fd6fc7356167f
76
- examples/index.html,1645811434044,e220d9feb2d2bb3cf8efcb2875cd5b51d47c7a26487ce99faf3c9bcf375e3166
77
- faq/best-save-viewer.html,1645811434172,fb7bbed04ccbfeb1e22ba05e3e2fbdcfc3d68532fb6823ccbcfe2d1ce9027c7a
78
- assets/img/power-saver-tibber-mqtt.16891dd2.png,1645811429479,24f2cad039c83c9031aa7f9d3decadc107b7cc257676e0e466078b2089632fcf
79
- assets/img/example-flow-1.3ff3e23f.png,1645811429572,9602bdee071fd442bc5c466600970ad5b639a8e15c09206c8f824840979b6122
80
- assets/js/405.f4edd94d.js,1645811429836,b1ab4766249e1c371d6fad1120f70a29eddafedbec8fcd4ced179e1e3e1ea3bb
81
- guide/index.html,1645811434203,344d07b979e6f673cb2c58ceb468fe90be6709d341080278b046da2ee7040f9d
82
- faq/index.html,1645811434142,5048881bfe07b5c4e4a5bc42d7d789c15885ef323384eedba512d4acda810dfc
83
- examples/example-cascade-temperature-control.html,1645811434059,006d0d0c6c62c571fe425e6b0345ba6d5df26680cbb12375847c20a67d51c7ef
84
- nodes/index.html,1645811434238,7fef763cdef1ac91215dd691b71f95bbd2baaacdba99d245dd54db71c241873b
85
- nodes/old-power-saver-doc.html,1645811434257,277ff09f7750f9a5089d6d3a034f6b9532271b9458ef5f83c17e9ffe00450b29
86
- nodes/power-saver.html,1645811434272,00e7695c6d5ac103b48037e07164b9e74064b4dc64dfef916ffd23eecdb68dde
87
- nodes/ps-elvia-add-tariff.html,1645811434283,d43458926d9a30fdb9d6e5bbf8cf4034a4832a987c66e7b4c3b5a09ea94f1a20
88
- nodes/ps-receive-price.html,1645811434318,41fbfd1b9daba9c39a32f19f7ca22c273231332629bf56b6e924a70449867951
89
- assets/js/v-4c28314d.8cbb0f9d.js,1645811429817,b24bc2e669f9e2a79198b8a7680c65d63f2e3db962e8b6719ea13a38ec5975e1
90
- nodes/ps-general-add-tariff.html,1645811434304,d83d9995fe8154bc04d618a6239510754cbf862920c2f8edbb29280bb2668635
91
- nodes/ps-strategy-lowest-price.html,1645811434400,d3064b70fa5d28d14e282a893544f586c63dd88b606c89f0391d004f81d06b52
92
- nodes/ps-strategy-best-save.html,1645811434338,d9fa9da54318ed33671177b04f4416a23e329e1d3306ea68a71cc9647999d54c
93
- nodes/strategy-input.html,1645811434408,a62cb80a8a2ddf419b8a778f25e77ce8c982337de0405341f561848aac76def1
94
- nodes/ps-strategy-heat-capacitor.html,1645811434379,e92a1e16315898e798bd84cd54ef9221bb39cfcb6c35c37f25ad3d1c379f47d9
@@ -1,17 +0,0 @@
1
- # This file was auto-generated by the Firebase CLI
2
- # https://github.com/firebase/firebase-tools
3
-
4
- name: Deploy to Firebase Hosting on PR
5
- 'on': pull_request
6
- jobs:
7
- build_and_preview:
8
- if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}'
9
- runs-on: ubuntu-latest
10
- steps:
11
- - uses: actions/checkout@v2
12
- - run: 'npm run docs:build'
13
- - uses: FirebaseExtended/action-hosting-deploy@v0
14
- with:
15
- repoToken: '${{ secrets.GITHUB_TOKEN }}'
16
- firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_POWERSAVER_C98D0 }}'
17
- projectId: powersaver-c98d0