node-red-contrib-power-saver 3.4.3 → 3.5.2

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 (132) 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 -58
  7. package/docs/.vuepress/navbar.js +43 -0
  8. package/docs/changelog/README.md +18 -0
  9. package/docs/examples/example-cascade-temperature-control.md +0 -13
  10. package/docs/examples/example-heat-capacitor.md +9 -20
  11. package/docs/examples/example-nordpool-current-state.md +0 -13
  12. package/docs/examples/example-nordpool-events-state.md +0 -13
  13. package/docs/examples/example-tibber-mqtt.md +0 -13
  14. package/docs/faq/best-save-viewer.md +1 -0
  15. package/docs/guide/README.md +20 -12
  16. package/docs/images/best-save-config.png +0 -0
  17. package/docs/images/lowest-price-config.png +0 -0
  18. package/docs/nodes/ps-strategy-best-save.md +67 -11
  19. package/docs/nodes/ps-strategy-lowest-price.md +69 -0
  20. package/package.json +9 -10
  21. package/src/elvia/elvia-add-tariff.html +1 -1
  22. package/src/handle-input.js +30 -10
  23. package/src/receive-price-functions.js +2 -0
  24. package/src/strategy-best-save.html +14 -0
  25. package/src/strategy-best-save.js +6 -2
  26. package/src/strategy-lowest-price.html +15 -2
  27. package/src/strategy-lowest-price.js +3 -1
  28. package/src/utils.js +3 -3
  29. package/test/data/lowest-price-result-cont.json +1 -0
  30. package/test/data/lowest-price-result-missing-end.json +1 -0
  31. package/test/data/lowest-price-result-split-allday.json +1 -0
  32. package/test/data/lowest-price-result-split-allday10.json +1 -0
  33. package/test/data/lowest-price-result-split.json +1 -0
  34. package/test/data/tibber-result-end-0-24h.json +1 -0
  35. package/test/data/tibber-result-end-0.json +1 -0
  36. package/.github/workflows/firebase-hosting-pull-request.yml +0 -17
  37. package/docs/.vuepress/dist/.nojekyll +0 -0
  38. package/docs/.vuepress/dist/404.html +0 -33
  39. package/docs/.vuepress/dist/Ukraine-heart-shape-flag.png +0 -0
  40. package/docs/.vuepress/dist/assets/css/835.styles.c5afb22b.css +0 -1
  41. package/docs/.vuepress/dist/assets/css/896.styles.21a80cb6.css +0 -1
  42. package/docs/.vuepress/dist/assets/css/styles.1c48cbd0.css +0 -10
  43. package/docs/.vuepress/dist/assets/img/add-tariff-flow.eb700d4f.png +0 -0
  44. package/docs/.vuepress/dist/assets/img/back-to-top.8b37f773.svg +0 -1
  45. package/docs/.vuepress/dist/assets/img/best-save-config.79a2f39a.png +0 -0
  46. package/docs/.vuepress/dist/assets/img/copy-payload-best-save.b9192985.png +0 -0
  47. package/docs/.vuepress/dist/assets/img/elvia-config-no-config.b4bb972c.png +0 -0
  48. package/docs/.vuepress/dist/assets/img/elvia-config-no-tariff.3f89aba8.png +0 -0
  49. package/docs/.vuepress/dist/assets/img/elvia-config-select-tariff.0f73fd56.png +0 -0
  50. package/docs/.vuepress/dist/assets/img/elvia-config-subscription-key.8be8ab8a.png +0 -0
  51. package/docs/.vuepress/dist/assets/img/elvia-flow.bae2a4d5.png +0 -0
  52. package/docs/.vuepress/dist/assets/img/example-flow-1.3ff3e23f.png +0 -0
  53. package/docs/.vuepress/dist/assets/img/example-flow-2.b653b58d.png +0 -0
  54. package/docs/.vuepress/dist/assets/img/heat-capacitor-temperatureVsPrice.6e74905b.png +0 -0
  55. package/docs/.vuepress/dist/assets/img/lowest-price-config.6d66a8c2.png +0 -0
  56. package/docs/.vuepress/dist/assets/img/migrate-best-save.f73420f6.png +0 -0
  57. package/docs/.vuepress/dist/assets/img/migrate-power-saver.aae13f9d.png +0 -0
  58. package/docs/.vuepress/dist/assets/img/next-schedule-entity.4406856a.png +0 -0
  59. package/docs/.vuepress/dist/assets/img/next-schedule-flow.413ad62b.png +0 -0
  60. package/docs/.vuepress/dist/assets/img/next-schedule-sensor.eb896bdd.png +0 -0
  61. package/docs/.vuepress/dist/assets/img/node-power-saver.51ff2e5d.png +0 -0
  62. package/docs/.vuepress/dist/assets/img/node-ps-elvia-add-tariff.94ea2b09.png +0 -0
  63. package/docs/.vuepress/dist/assets/img/node-ps-general-add-tariff.a3cf6f06.png +0 -0
  64. package/docs/.vuepress/dist/assets/img/node-ps-receive-price.76eaa418.png +0 -0
  65. package/docs/.vuepress/dist/assets/img/node-ps-strategy-best-save.392292d5.png +0 -0
  66. package/docs/.vuepress/dist/assets/img/node-ps-strategy-heat-capacitor-cascade-control.2e75ed9e.png +0 -0
  67. package/docs/.vuepress/dist/assets/img/node-ps-strategy-heat-capacitor-simple-flow-example.29d9bf59.png +0 -0
  68. package/docs/.vuepress/dist/assets/img/node-ps-strategy-lowest-price.3a4ad347.png +0 -0
  69. package/docs/.vuepress/dist/assets/img/oven-setpoint-calculation.5bda0eec.png +0 -0
  70. package/docs/.vuepress/dist/assets/img/overshoot-time.b3b5d70e.png +0 -0
  71. package/docs/.vuepress/dist/assets/img/power-saver-nordpool-current-state.bf14afde.png +0 -0
  72. package/docs/.vuepress/dist/assets/img/power-saver-nordpool-events-state.8c392507.png +0 -0
  73. package/docs/.vuepress/dist/assets/img/power-saver-tibber-mqtt.16891dd2.png +0 -0
  74. package/docs/.vuepress/dist/assets/js/229.5c5378fa.js +0 -1
  75. package/docs/.vuepress/dist/assets/js/331.872104cd.js +0 -1
  76. package/docs/.vuepress/dist/assets/js/405.f4edd94d.js +0 -2
  77. package/docs/.vuepress/dist/assets/js/405.f4edd94d.js.LICENSE.txt +0 -8
  78. package/docs/.vuepress/dist/assets/js/490.1e639e05.js +0 -1
  79. package/docs/.vuepress/dist/assets/js/491.bd938119.js +0 -1
  80. package/docs/.vuepress/dist/assets/js/555.d8963d84.js +0 -1
  81. package/docs/.vuepress/dist/assets/js/811.5f659592.js +0 -1
  82. package/docs/.vuepress/dist/assets/js/app.6c6c1409.js +0 -1
  83. package/docs/.vuepress/dist/assets/js/runtime~app.f6ac32d7.js +0 -1
  84. package/docs/.vuepress/dist/assets/js/v-0607240a.0193a377.js +0 -1
  85. package/docs/.vuepress/dist/assets/js/v-08683c60.52e94cb6.js +0 -1
  86. package/docs/.vuepress/dist/assets/js/v-0aca7ba6.cac5d4b9.js +0 -1
  87. package/docs/.vuepress/dist/assets/js/v-0b5e3c8c.18561f6e.js +0 -1
  88. package/docs/.vuepress/dist/assets/js/v-1ad821fa.6697a349.js +0 -1
  89. package/docs/.vuepress/dist/assets/js/v-1b3a0ab8.c6c4e19b.js +0 -1
  90. package/docs/.vuepress/dist/assets/js/v-1e2b191e.07b8ab21.js +0 -1
  91. package/docs/.vuepress/dist/assets/js/v-29504124.00be7399.js +0 -1
  92. package/docs/.vuepress/dist/assets/js/v-30acb564.28af12af.js +0 -1
  93. package/docs/.vuepress/dist/assets/js/v-3706649a.c76d575b.js +0 -1
  94. package/docs/.vuepress/dist/assets/js/v-4637f9e4.d334c29a.js +0 -1
  95. package/docs/.vuepress/dist/assets/js/v-4c28314d.8cbb0f9d.js +0 -1
  96. package/docs/.vuepress/dist/assets/js/v-510ed0d4.c04bc2e4.js +0 -1
  97. package/docs/.vuepress/dist/assets/js/v-5954bcb2.dff3fc67.js +0 -1
  98. package/docs/.vuepress/dist/assets/js/v-5db8da3a.e5e6d7a6.js +0 -1
  99. package/docs/.vuepress/dist/assets/js/v-61f728ca.81968036.js +0 -1
  100. package/docs/.vuepress/dist/assets/js/v-677dfaed.c159b0f4.js +0 -1
  101. package/docs/.vuepress/dist/assets/js/v-7446a652.8fc2c591.js +0 -1
  102. package/docs/.vuepress/dist/assets/js/v-7c87f26e.8ed52391.js +0 -1
  103. package/docs/.vuepress/dist/assets/js/v-84304104.f3f07ed3.js +0 -1
  104. package/docs/.vuepress/dist/assets/js/v-8daa1a0e.ed84ca09.js +0 -1
  105. package/docs/.vuepress/dist/assets/js/v-b4a42144.9a2a0c9f.js +0 -1
  106. package/docs/.vuepress/dist/assets/js/v-e8c55052.b7d52fc6.js +0 -1
  107. package/docs/.vuepress/dist/assets/js/v-fffb8e28.d09ab959.js +0 -1
  108. package/docs/.vuepress/dist/changelog/index.html +0 -33
  109. package/docs/.vuepress/dist/contribute/index.html +0 -33
  110. package/docs/.vuepress/dist/euro.png +0 -0
  111. package/docs/.vuepress/dist/examples/example-cascade-temperature-control.html +0 -304
  112. package/docs/.vuepress/dist/examples/example-heat-capacitor.html +0 -247
  113. package/docs/.vuepress/dist/examples/example-next-schedule-entity.html +0 -43
  114. package/docs/.vuepress/dist/examples/example-nordpool-current-state.html +0 -206
  115. package/docs/.vuepress/dist/examples/example-nordpool-events-state.html +0 -191
  116. package/docs/.vuepress/dist/examples/example-tibber-mqtt.html +0 -199
  117. package/docs/.vuepress/dist/examples/index.html +0 -33
  118. package/docs/.vuepress/dist/faq/best-save-viewer.html +0 -33
  119. package/docs/.vuepress/dist/faq/index.html +0 -33
  120. package/docs/.vuepress/dist/guide/index.html +0 -70
  121. package/docs/.vuepress/dist/index.html +0 -33
  122. package/docs/.vuepress/dist/logo.png +0 -0
  123. package/docs/.vuepress/dist/nodes/index.html +0 -33
  124. package/docs/.vuepress/dist/nodes/old-power-saver-doc.html +0 -115
  125. package/docs/.vuepress/dist/nodes/power-saver.html +0 -33
  126. package/docs/.vuepress/dist/nodes/ps-elvia-add-tariff.html +0 -33
  127. package/docs/.vuepress/dist/nodes/ps-general-add-tariff.html +0 -33
  128. package/docs/.vuepress/dist/nodes/ps-receive-price.html +0 -98
  129. package/docs/.vuepress/dist/nodes/ps-strategy-best-save.html +0 -104
  130. package/docs/.vuepress/dist/nodes/ps-strategy-heat-capacitor.html +0 -260
  131. package/docs/.vuepress/dist/nodes/ps-strategy-lowest-price.html +0 -124
  132. package/docs/.vuepress/dist/nodes/strategy-input.html +0 -58
@@ -1,16 +1,16 @@
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 merge
5
- 'on':
1
+ name: "Publish docs to firebase on merge"
2
+ on:
6
3
  push:
7
4
  branches:
8
- - gh-pages
5
+ - "main"
6
+ paths:
7
+ - "docs/**"
9
8
  jobs:
10
9
  build_and_deploy:
11
10
  runs-on: ubuntu-latest
12
11
  steps:
13
12
  - uses: actions/checkout@v2
13
+ - run: npm ci
14
14
  - run: 'npm run docs:build'
15
15
  - uses: FirebaseExtended/action-hosting-deploy@v0
16
16
  with:
@@ -0,0 +1,23 @@
1
+
2
+ name: Publish to npmjs
3
+ on:
4
+ release:
5
+ types: [created]
6
+ jobs:
7
+ build:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v3
11
+ # Setup .npmrc file to publish to npm
12
+ - uses: actions/setup-node@v3
13
+ with:
14
+ node-version: '16.x'
15
+ registry-url: 'https://registry.npmjs.org'
16
+ - uses: szenius/set-timezone@v1.0
17
+ with:
18
+ timezoneLinux: "Europe/Oslo"
19
+ - run: npm ci
20
+ - run: 'npm run test'
21
+ - run: npm publish
22
+ env:
23
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,13 @@
1
+ name: Run tests on pull request
2
+ on: pull_request
3
+ jobs:
4
+ build_and_test:
5
+ if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}'
6
+ runs-on: ubuntu-latest
7
+ steps:
8
+ - uses: actions/checkout@v2
9
+ - uses: szenius/set-timezone@v1.0
10
+ with:
11
+ timezoneLinux: "Europe/Oslo"
12
+ - run: npm ci
13
+ - run: 'npm run test'
@@ -6,8 +6,15 @@
6
6
  <p>Max in sequence: {{ payload.config.maxHoursToSaveInSequence }}</p>
7
7
  <p>Min on after max: {{ payload.config.minHoursOnAfterMaxSequenceSaved }}</p>
8
8
  <p>Minimum saving: {{ payload.config.minSaving }}</p>
9
- <p>Send when rescheduling: {{ payload.config.sendCurrentValueWhenRescheduling ? "Yes" : "No" }}</p>
10
- <p>If no schedule, output: {{ payload.config.outputIfNoSchedule ? "On" : "Off" }}</p>
9
+ <p>
10
+ Send when rescheduling:
11
+ {{ payload.config.sendCurrentValueWhenRescheduling ? "Yes" : "No" }}
12
+ </p>
13
+ <p>
14
+ If no schedule, output:
15
+ {{ payload.config.outputIfNoSchedule ? "On" : "Off" }}
16
+ </p>
17
+ <p>Context is saved to: {{ payload.config.contextStorage }}</p>
11
18
  <h3>Meta data:</h3>
12
19
  <p>Node version: {{ payload.version }}</p>
13
20
  <p>Data timestamp: {{ payload.time }}</p>
@@ -78,7 +85,9 @@
78
85
  </tr>
79
86
  <tr v-for="(hour, i) in payload.hours" :key="hour.start">
80
87
  <td>{{ DateTime.fromISO(hour.start).day }}</td>
81
- <td>{{ DateTime.fromISO(hour.start).toLocaleString(DateTime.TIME_SIMPLE) }}</td>
88
+ <td>
89
+ {{ DateTime.fromISO(hour.start).toLocaleString(DateTime.TIME_SIMPLE) }}
90
+ </td>
82
91
  <td :class="priceClasses(i)">{{ hour.price }}</td>
83
92
  <td>{{ hour.onOff ? "On" : "Off" }}</td>
84
93
  <td>{{ hour.saving ?? "" }}</td>
@@ -106,9 +115,7 @@
106
115
 
107
116
  <script setup>
108
117
  import { computed, reactive, ref, watch } from "vue";
109
-
110
- const { roundPrice } = import("../../../src/utils");
111
- const { DateTime } = import("luxon");
118
+ import { DateTime } from "luxon";
112
119
 
113
120
  const message = ref("");
114
121
  const showNegative = ref(false);
@@ -116,7 +123,9 @@ const showNegative = ref(false);
116
123
  const show = ref("avg");
117
124
  const showSum = computed(() => show.value === "sum");
118
125
 
119
- console.log("This is the setup script");
126
+ function roundPrice(value) {
127
+ return Math.round(value * 10000) / 10000;
128
+ }
120
129
 
121
130
  const dataString = ref("");
122
131
  watch(dataString, (value) => {
@@ -147,6 +156,8 @@ const totalPerSequence = reactive([]);
147
156
  const averagePerSequence = reactive([]);
148
157
 
149
158
  function calculatePotentialSavings() {
159
+ console.log("calculatePotentialSavings");
160
+ console.log({ roundPrice });
150
161
  const hours = payload.hours;
151
162
 
152
163
  // Savings per hour
@@ -14,7 +14,6 @@
14
14
  title="PayPal - The safer, easier way to pay online!"
15
15
  alt="Donate with PayPal button"
16
16
  />
17
- <img alt="" border="0" src="https://www.paypal.com/en_NO/i/scr/pixel.gif" width="1" height="1" />
18
17
  </form>
19
18
  </div>
20
19
  <div class="right">
@@ -1,5 +1,5 @@
1
1
  const { path } = require("@vuepress/utils");
2
- const vue = require("@vitejs/plugin-vue");
2
+ const navbar = require("./navbar");
3
3
 
4
4
  module.exports = {
5
5
  lang: "en-US",
@@ -9,36 +9,7 @@ module.exports = {
9
9
  themeConfig: {
10
10
  contributors: false,
11
11
  logo: "/Ukraine-heart-shape-flag.png",
12
- navbar: [
13
- {
14
- text: "Guide",
15
- link: "/guide/",
16
- },
17
- {
18
- text: "Nodes",
19
- link: "/nodes/",
20
- },
21
- {
22
- text: "Examples",
23
- link: "/examples/",
24
- },
25
- {
26
- text: "FAQ",
27
- link: "/faq/",
28
- },
29
- {
30
- text: "Contribute",
31
- link: "/contribute/",
32
- },
33
- {
34
- text: "Changes",
35
- link: "/changelog/",
36
- },
37
- {
38
- text: "GitHub",
39
- link: "https://github.com/ottopaulsen/node-red-contrib-power-saver",
40
- },
41
- ],
12
+ navbar,
42
13
  sidebar: {
43
14
  "/guide/": [{ text: "Guide", children: ["/guide/README.md"] }],
44
15
  "/nodes/": [
@@ -51,7 +22,10 @@ module.exports = {
51
22
  children: [
52
23
  "/nodes/ps-strategy-best-save.md",
53
24
  "/nodes/ps-strategy-lowest-price.md",
54
- { text: "ps-strategy-heat-capacitor", link: "/nodes/ps-strategy-heat-capacitor.md" },
25
+ {
26
+ text: "ps-strategy-heat-capacitor",
27
+ link: "/nodes/ps-strategy-heat-capacitor.md",
28
+ },
55
29
  ],
56
30
  },
57
31
  { text: "Utility nodes", children: ["/nodes/ps-receive-price.md"] },
@@ -83,37 +57,14 @@ module.exports = {
83
57
  "/changelog/": [{ text: "Changelog", children: ["/changelog/README.md"] }],
84
58
  },
85
59
  },
86
- head: [
87
- ["link", { rel: "shortcut icon", type: "image/x-icon", href: "euro.png" }],
88
- [
89
- "script",
90
- {
91
- async: true,
92
- src: "https://www.googletagmanager.com/gtag/js?id=G-Z2QNNCDQZG",
93
- },
94
- ],
95
- [
96
- "script",
97
- {
98
- src: "window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-Z2QNNCDQZG');",
99
- },
100
- ],
101
- ],
60
+ head: [["link", { rel: "shortcut icon", type: "image/x-icon", href: "euro.png" }]],
102
61
  plugins: [
103
62
  [
104
63
  "@vuepress/register-components",
105
64
  {
106
- components: {
107
- BestSaveVerificator: path.resolve(__dirname, "./components/BestSaveVerificator.vue"),
108
- DonateButtons: path.resolve(__dirname, "./components/DonateButtons.vue"),
109
- },
65
+ componentsDir: path.resolve(__dirname, "./components"),
110
66
  },
111
67
  ],
68
+ ["@vuepress/plugin-search"],
112
69
  ],
113
- bundler: "@vuepress/bundler-webpack",
114
- bundlerConfig: {
115
- viteOptions: {
116
- plugins: [vue()],
117
- },
118
- },
119
70
  };
@@ -0,0 +1,43 @@
1
+ module.exports = [
2
+ {
3
+ text: "Guide",
4
+ link: "/guide/",
5
+ },
6
+ {
7
+ text: "Nodes",
8
+ link: "/nodes/",
9
+ },
10
+ {
11
+ text: "Examples",
12
+ link: "/examples/",
13
+ },
14
+ {
15
+ text: "FAQ",
16
+ link: "/faq/",
17
+ },
18
+ {
19
+ text: "Contribute",
20
+ link: "/contribute/",
21
+ },
22
+ {
23
+ text: "Changes",
24
+ link: "/changelog/",
25
+ },
26
+ {
27
+ text: "Links",
28
+ children: [
29
+ {
30
+ text: "GitHub",
31
+ link: "https://github.com/ottopaulsen/node-red-contrib-power-saver",
32
+ },
33
+ {
34
+ text: "npm registry",
35
+ link: "https://www.npmjs.com/package/node-red-contrib-power-saver",
36
+ },
37
+ {
38
+ text: "Node-RED Library",
39
+ link: "https://flows.nodered.org/node/node-red-contrib-power-saver",
40
+ },
41
+ ],
42
+ },
43
+ ];
@@ -6,6 +6,24 @@ sidebar: "auto"
6
6
 
7
7
  List the most significant changes, starting in version 1.0.9.
8
8
 
9
+ ## 3.5.2
10
+
11
+ - Re-introduce the search bar, after Vuepress upgrade.
12
+
13
+ ## 3.5.1
14
+
15
+ - Update github actions to deploy automatically to the npm library.
16
+
17
+ ## 3.5.0
18
+
19
+ - Select what context storage to store data in the node configuration.
20
+ - New dynamic command: `replan`, that can be sent after a restart in order to create a schedule based on the last received prices, provided `file` is used as context storage (alternatively another permanent storage).
21
+ - Some improvements to node status.
22
+
23
+ ## 3.4.4
24
+
25
+ - Fix bug in Best Save Viewer in the documentation (under FAQ)
26
+
9
27
  ## 3.4.3
10
28
 
11
29
  - Fix Elvia config so it can be used independently on any node.
@@ -326,19 +326,6 @@ A cascade temperature controller is a controller which utilizes the input/setpoi
326
326
  "x": 290,
327
327
  "y": 160,
328
328
  "wires": [["6f77dd60c21180e1"]]
329
- },
330
- {
331
- "id": "e2dd69fb.8f70a8",
332
- "type": "server",
333
- "name": "Home Assistant",
334
- "version": 2,
335
- "addon": true,
336
- "rejectUnauthorizedCerts": true,
337
- "ha_boolean": "y|yes|true|on|home|open",
338
- "connectionDelay": false,
339
- "cacheJson": true,
340
- "heartbeat": true,
341
- "heartbeatInterval": "30"
342
329
  }
343
330
  ]
344
331
  ```
@@ -1,4 +1,4 @@
1
- # Simple heat capacitor strategy flow
1
+ # Simple heat capacitor strategy flow
2
2
 
3
3
  ## Description
4
4
 
@@ -27,13 +27,15 @@ It is a good application for cabins/heated storage spaces, as the entity never a
27
27
  > Import the flow into Node-RED
28
28
 
29
29
  > Configure the heat-capacitor node:
30
- - Insert an approximate time it takes to increase the temperature by 1 Centigrade (could be 90 minutes)
31
- - Insert an approximate time it takes to decrease 1 Centigrade
32
- - Insert minimum savings for a heating/cooling cycle (should not be zero, as a cycle might have a cost)
30
+
31
+ - Insert an approximate time it takes to increase the temperature by 1 Centigrade (could be 90 minutes)
32
+ - Insert an approximate time it takes to decrease 1 Centigrade
33
+ - Insert minimum savings for a heating/cooling cycle (should not be zero, as a cycle might have a cost)
33
34
 
34
35
  > Configure the climate service to target the correct climate entity (this has to be edited in two places)
35
- - Change `Entity Id` in the properties menu
36
- - Change the `entity_id` value in the `Data` property
36
+
37
+ - Change `Entity Id` in the properties menu
38
+ - Change the `entity_id` value in the `Data` property
37
39
 
38
40
  > (optional) If the `input_number` entity was named something else than `setpoint`, change the `entity_id` of the `Setpoint` node accordingly.
39
41
 
@@ -49,7 +51,6 @@ It is a good application for cabins/heated storage spaces, as the entity never a
49
51
 
50
52
  ---
51
53
 
52
-
53
54
  ::: details [Flow code]
54
55
 
55
56
  ```json:no-line-numbers
@@ -252,20 +253,8 @@ It is a good application for cabins/heated storage spaces, as the entity never a
252
253
  "feedUrl": "wss://api.tibber.com/v1-beta/gql/subscriptions",
253
254
  "queryUrl": "https://api.tibber.com/v1-beta/gql",
254
255
  "name": "Tibber"
255
- },
256
- {
257
- "id": "e2dd69fb.8f70a8",
258
- "type": "server",
259
- "name": "Home Assistant",
260
- "version": 2,
261
- "addon": false,
262
- "rejectUnauthorizedCerts": true,
263
- "ha_boolean": "y|yes|true|on|home|open",
264
- "connectionDelay": false,
265
- "cacheJson": true,
266
- "heartbeat": false,
267
- "heartbeatInterval": 30
268
256
  }
269
257
  ]
270
258
  ```
259
+
271
260
  :::
@@ -167,19 +167,6 @@ In this example, data is read from the Nord Pool sensor in HA via the `current s
167
167
  "e2578f6a.210a8"
168
168
  ]
169
169
  ]
170
- },
171
- {
172
- "id": "ec4a12a1.b2be9",
173
- "type": "server",
174
- "name": "Home Assistant",
175
- "version": 2,
176
- "addon": true,
177
- "rejectUnauthorizedCerts": true,
178
- "ha_boolean": "y|yes|true|on|home|open",
179
- "connectionDelay": true,
180
- "cacheJson": true,
181
- "heartbeat": false,
182
- "heartbeatInterval": 30
183
170
  }
184
171
  ]
185
172
  ```
@@ -152,19 +152,6 @@ In this example, data is read from the Nord Pool sensor in HA via the `events: s
152
152
  "x": 490,
153
153
  "y": 620,
154
154
  "wires": [["32f17ab2.927cf6"], ["2a3cd7db.0891f8"], ["ed7202ff.b5725"]]
155
- },
156
- {
157
- "id": "ec4a12a1.b2be9",
158
- "type": "server",
159
- "name": "Home Assistant",
160
- "version": 2,
161
- "addon": true,
162
- "rejectUnauthorizedCerts": true,
163
- "ha_boolean": "y|yes|true|on|home|open",
164
- "connectionDelay": true,
165
- "cacheJson": true,
166
- "heartbeat": false,
167
- "heartbeatInterval": 30
168
155
  }
169
156
  ]
170
157
  ```
@@ -160,19 +160,6 @@ In this example, data is read from Tibber and used to turn on/off a switch, sche
160
160
  "feedUrl": "wss://api.tibber.com/v1-beta/gql/subscriptions",
161
161
  "queryUrl": "https://api.tibber.com/v1-beta/gql",
162
162
  "name": "Tibber API"
163
- },
164
- {
165
- "id": "ec4a12a1.b2be9",
166
- "type": "server",
167
- "name": "Home Assistant",
168
- "version": 2,
169
- "addon": true,
170
- "rejectUnauthorizedCerts": true,
171
- "ha_boolean": "y|yes|true|on|home|open",
172
- "connectionDelay": true,
173
- "cacheJson": true,
174
- "heartbeat": false,
175
- "heartbeatInterval": 30
176
163
  }
177
164
  ]
178
165
  ```
@@ -58,4 +58,5 @@ If the number is black, it could be used, but only if all other criteria are sat
58
58
  The tool is not using the same code as the node, so in case there is a bg in the node (or in the tool) the numbers may not match.
59
59
 
60
60
  <hr/>
61
+
61
62
  <DonateButtons/>
@@ -61,14 +61,17 @@ If you are a Tibber customer, use the `tibber-query` node from the [Tibber API](
61
61
  {
62
62
  viewer {
63
63
  homes {
64
- id
65
- address {
66
- address1
67
- address2
68
- address3
69
- postalCode
70
- city
71
- country
64
+ currentSubscription {
65
+ priceInfo {
66
+ today {
67
+ total
68
+ startsAt
69
+ }
70
+ tomorrow {
71
+ total
72
+ startsAt
73
+ }
74
+ }
72
75
  }
73
76
  }
74
77
  }
@@ -147,10 +150,11 @@ If the grid tariff is the same the whole day, you can skip this step i the flow.
147
150
 
148
151
  This is the step where the value is produced. Based on the prices received, the optimal schedule for you is calculated automatically, based on your configuration. You can choose between the following strategies:
149
152
 
150
- | Strategy | Node | Description |
151
- | ------------ | --------------------------- | --------------------------------------------------------------- |
152
- | Best save | `ps-strategy-best-save` | Postpone power consumption when there is most to save. |
153
- | Lowest price | `ps--strategy-lowest-price` | Turn on power when the prices are the lowest in a given period. |
153
+ | Strategy | Node | Description |
154
+ | -------------- | ---------------------------- | ---------------------------------------------------------------------------- |
155
+ | Best Save | `ps-strategy-best-save` | Postpone power consumption when there is most to save. |
156
+ | Lowest Price | `ps-strategy-lowest-price` | Turn on power when the prices are the lowest in a given period. |
157
+ | Heat Capacitor | `ps-strategy-heat-capacitor` | Move consumption from expensive to cheap periods utilizing climate entities. |
154
158
 
155
159
  These nodes must be configured for your purpose. See configuration description and other details in the documentation for each node.
156
160
 
@@ -161,12 +165,16 @@ strategy node you choose.
161
165
  Choose the best save strategy if you can postpone power consumption, and expect the consumption to occur during the first hour after power is turned on again.
162
166
 
163
167
  Choose the lowest price strategy if you need the power to be on for x hours, but it is not important when that is. Note that you can select to have all hours on in one consecutive period, or spread around on the cheapest hours.
168
+
169
+ Choose the heat capacitor strategy for controlling for example room heating, where you can turn the heat a little down when electricity is expensive, and a little up when it is cheap, using trading principles (only that you know up front when the prices will change).
164
170
  :::
165
171
 
166
172
  ### Use schedule signals
167
173
 
168
174
  Use the outputs to control switches, thermostats or other entities to control your power consumers.
169
175
 
176
+ The following os valid for the Best Save and Lowest Price strategies:
177
+
170
178
  **Output 1** is used to turn on. A payload with value `true` is sent every time turning on is scheduled.
171
179
 
172
180
  **Output 2** is used to turn off. A payload with value `false` is sent every time turning off is scheduled.
Binary file
Binary file
@@ -21,6 +21,7 @@ The picture at the bottom of the page, under [Integration with MagicMirror](#int
21
21
  | Min saving | Minimum amount to save per kWh in order to bother turning it off. It is recommended to have some amount here, e.g. 2 cents / 2 øre. No point in saving 0.001, is it? |
22
22
  | Send when rescheduling | Check this to make sure on or off output is sent immediately after rescheduling |
23
23
  | If no schedule, send | What to do if there is no valid schedule any more (turn on or off). |
24
+ | Context storage | Select context storage to save data to, if more than one is configured in the Node-RED `settings.js` file. |
24
25
 
25
26
  ::: warning Min recover
26
27
  NB! The `Min recover` only has effect if the previous save-period is of length `Max per sequence`. If the save-period is shorter, the following on-period may be as short as one hour.
@@ -33,6 +34,7 @@ It is possible to change config dynamically by sending a config message to the n
33
34
  ```json
34
35
  "payload": {
35
36
  "config": {
37
+ "contextStorage": "file",
36
38
  "maxHoursToSaveInSequence": 4,
37
39
  "minHoursOnAfterMaxSequenceSaved": 2,
38
40
  "minSaving": 0.02,
@@ -107,13 +109,41 @@ This operation cannot be undone.
107
109
  However, it is normally not a big loss, as you can just feed the node with new price data and start from scratch.
108
110
  :::
109
111
 
112
+ #### replan
113
+
114
+ By sending this command, you can have the node read the last received prices from the context storage,
115
+ and make a plan based on those prices:
116
+
117
+ ```json
118
+ "payload": {
119
+ "commands": {
120
+ "replan": true,
121
+ }
122
+ }
123
+ ```
124
+
125
+ If the context storage is `file` you can use this to create a new schedule after a restart,
126
+ instead of fetching prices again.
127
+
128
+ ### Config saved in context
129
+
130
+ The nodes config is saved in the nodes context.
131
+ If dynamic config is sent as input, this replaces the saved config.
132
+ It is the config that is saved in context that is used when calculating.
133
+ 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.
134
+
110
135
  ## Input
111
136
 
112
137
  The input is the [common strategy input format](./strategy-input.md).
113
138
 
114
139
  In addition to the prices sent as input,
115
140
  the node is using the schedule for the day before it receives data for,
116
- so that it can calculate the schedule in the beginning of the day according to the configured rules. This requires of course that the node was run the day before.
141
+ so that it can calculate the schedule in the beginning of the day according to the configured rules.
142
+ This requires of course that the node was run the day before.
143
+
144
+ When a payload with `priceData` is received, this is saved to the nodes context as `lastPriceData`.
145
+ The source is saved as `lastSource`. If config- or command-messages are received without price data,
146
+ the data saved in context is used for replanning.
117
147
 
118
148
  ## Output
119
149
 
@@ -167,6 +197,7 @@ Example of output:
167
197
  ],
168
198
  "source": "Nord Pool",
169
199
  "config": {
200
+ "contextStorage": "default",
170
201
  "maxHoursToSaveInSequence": 3,
171
202
  "minHoursOnAfterMaxSequenceSaved": "1",
172
203
  "minSaving": 0.001,
@@ -180,9 +211,9 @@ Example of output:
180
211
 
181
212
  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.
182
213
 
183
- ### Data saved in context
214
+ ### Output saved in context
184
215
 
185
- The node saves some data in the nodes context, so that it can be used on restarts and also taken into consideration when calculating the schedule over midnight.
216
+ The `schedule` and the `hours` arrays from Output 3 are both saved to the nodes context in an object with key `lastPlan`. This may be used in the plan for the next day, for example if an off-period at the end of one day continues into the next day. In that case, the `saving` values for the last hours in the day have to be recalculated, since the next hour on is changed when the new day is calculated.
186
217
 
187
218
  You can see the saved data if you select the node in Node-RED, and view "Context data", and refresh the Node context.
188
219
 
@@ -204,23 +235,48 @@ I say "in most cases", because there is a chance that a group of two or more seq
204
235
 
205
236
  Normally data is received for one or two whole days, and all this data is used to do the calculation. In addition, if the node has run before, so there is historical data, the last period on or off before the period data is received for, is considered in the calculation, so that the rules in the configuration are followed also between days.
206
237
 
207
- ## Restarts
238
+ ## Restarts and saved context
208
239
 
209
- The node saves data in the nodes context, so if Node-RED is configured to save context between restarts, the node will replan with the last received data when it restarts.
240
+ The config, last received prices and the last calculated schedule are saved to the nodes context.
241
+ This may be saved to memory, to file or to another destination based on how your Node-RED is configured.
242
+ If multiple context storages are defined, you can select which one to use in the nodes config.
243
+ If there is only one context storage defined, this is normally `memory`. In that case, data is not saved over restarts.
244
+ It is common to have two different context storages defined, `memory` and `file`, but there may be more.
245
+ It is also common to have a `default` context storage defined, and often this points to either `memory` or `file`.
246
+ However, the configuration can be different from this.
210
247
 
211
- ::: warning
212
- In Home Assistant, Node-RED is by default configured to save context between restarts. However, if you run Node-RED another way, this may not be the case by default. If context is only stored in memory, it is lost between restarts, and even between re-deployments. This can be changed in the `settings.js` file for Node-RED like this:
248
+ You can find this configuration in the `settings.js` file for Node-RED, usually in the node-red config folder.
249
+ In Home Assistant, this is normally `/config/node-red/settings.js`.
250
+
251
+ Here is an example of a configuration for the context storage:
213
252
 
214
253
  ```js
215
254
  contextStorage: {
216
- default: {
217
- module: "localfilesystem"
218
- }
255
+ file: { module: "localfilesystem"},
256
+ default: { module: "memory" }
219
257
  }
220
258
  ```
221
259
 
260
+ By default, this node saves context to the `default` context storage. In the example above, this is memory.
261
+ Then it is not preserved over a restart.
222
262
  Please read the [Node-RED documentation](https://nodered.org/docs/user-guide/context) for more details about this.
223
- :::
263
+
264
+ The data that is saved is the config, the last used prices and the last calculated schedule.
265
+
266
+ When Node-RED restarts, the config is reset to what is defined in the node config, so by default,
267
+ nothing is read from the context storage after a restart. However, if you send a `replan` command to the
268
+ nodes input, a plan is recalculated, using the last received prices. One way to do this is to use an `inject` node,
269
+ and set `msg.payload` to the following JSON value:
270
+
271
+ ```json
272
+ {
273
+ "commands": {
274
+ "replan": true
275
+ }
276
+ }
277
+ ```
278
+
279
+ This is an alternative to fetching new prices and send as input.
224
280
 
225
281
  ## Integration with MagicMirror
226
282