node-red-contrib-power-saver 3.2.3 → 3.4.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 (137) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +1 -1
  3. package/docs/.vuepress/clientAppEnhance.js +5 -0
  4. package/docs/.vuepress/components/BestSaveVerificator.vue +306 -0
  5. package/docs/.vuepress/components/DonateButtons.vue +87 -0
  6. package/docs/.vuepress/config.js +36 -7
  7. package/docs/.vuepress/dist/404.html +5 -5
  8. package/docs/.vuepress/dist/assets/css/563.styles.99f4a8aa.css +1 -0
  9. package/docs/.vuepress/dist/assets/css/835.styles.c5afb22b.css +1 -0
  10. package/docs/.vuepress/dist/assets/css/{styles.e835bef6.css → styles.031dcf27.css} +2 -1
  11. package/docs/.vuepress/dist/assets/img/best-save-config.79a2f39a.png +0 -0
  12. package/docs/.vuepress/dist/assets/img/copy-payload-best-save.b9192985.png +0 -0
  13. package/docs/.vuepress/dist/assets/img/heat-capacitor-temperatureVsPrice.6e74905b.png +0 -0
  14. package/docs/.vuepress/dist/assets/img/node-ps-strategy-heat-capacitor-cascade-control.2e75ed9e.png +0 -0
  15. package/docs/.vuepress/dist/assets/img/node-ps-strategy-heat-capacitor-simple-flow-example.29d9bf59.png +0 -0
  16. package/docs/.vuepress/dist/assets/img/oven-setpoint-calculation.5bda0eec.png +0 -0
  17. package/docs/.vuepress/dist/assets/img/overshoot-time.b3b5d70e.png +0 -0
  18. package/docs/.vuepress/dist/assets/js/262.cf2c57d2.js +1 -0
  19. package/docs/.vuepress/dist/assets/js/{293.5e967839.js → 293.08ea5200.js} +0 -0
  20. package/docs/.vuepress/dist/assets/js/331.15ee3c51.js +1 -0
  21. package/docs/.vuepress/dist/assets/js/{491.c183eba3.js → 491.17a98f38.js} +0 -0
  22. package/docs/.vuepress/dist/assets/js/619.8ba1b1f6.js +2 -0
  23. package/docs/.vuepress/dist/assets/js/{812.79dad458.js.LICENSE.txt → 619.8ba1b1f6.js.LICENSE.txt} +0 -0
  24. package/docs/.vuepress/dist/assets/js/811.6a3392d5.js +1 -0
  25. package/docs/.vuepress/dist/assets/js/app.e881e9b6.js +1 -0
  26. package/docs/.vuepress/dist/assets/js/runtime~app.8bebaa00.js +1 -0
  27. package/docs/.vuepress/dist/assets/js/{v-0607240a.661e1808.js → v-0607240a.a57c2199.js} +0 -0
  28. package/docs/.vuepress/dist/assets/js/{v-08683c60.a6b9cf5b.js → v-08683c60.ccafdcab.js} +0 -0
  29. package/docs/.vuepress/dist/assets/js/v-0aca7ba6.4f3573a3.js +1 -0
  30. package/docs/.vuepress/dist/assets/js/v-0b5e3c8c.76407435.js +1 -0
  31. package/docs/.vuepress/dist/assets/js/{v-1ad821fa.6e2194d0.js → v-1ad821fa.5978386f.js} +0 -0
  32. package/docs/.vuepress/dist/assets/js/v-1b3a0ab8.def099e9.js +1 -0
  33. package/docs/.vuepress/dist/assets/js/{v-1e2b191e.98cc227b.js → v-1e2b191e.88dc5555.js} +0 -0
  34. package/docs/.vuepress/dist/assets/js/v-29504124.4aca27d5.js +1 -0
  35. package/docs/.vuepress/dist/assets/js/{v-30acb564.f2fcd69f.js → v-30acb564.529a3c16.js} +0 -0
  36. package/docs/.vuepress/dist/assets/js/v-4637f9e4.5cc542f6.js +1 -0
  37. package/docs/.vuepress/dist/assets/js/v-4c28314d.48fc6e75.js +1 -0
  38. package/docs/.vuepress/dist/assets/js/v-510ed0d4.b58000bf.js +1 -0
  39. package/docs/.vuepress/dist/assets/js/{v-5954bcb2.182daf70.js → v-5954bcb2.937005d0.js} +0 -0
  40. package/docs/.vuepress/dist/assets/js/{v-5db8da3a.f2de6cb9.js → v-5db8da3a.3de3588d.js} +1 -1
  41. package/docs/.vuepress/dist/assets/js/{v-61f728ca.6fdbbb92.js → v-61f728ca.21d432fe.js} +1 -1
  42. package/docs/.vuepress/dist/assets/js/v-677dfaed.1ad4c776.js +1 -0
  43. package/docs/.vuepress/dist/assets/js/v-7446a652.74b21d0b.js +1 -0
  44. package/docs/.vuepress/dist/assets/js/v-7c87f26e.5e3553b0.js +1 -0
  45. package/docs/.vuepress/dist/assets/js/v-84304104.f66996c5.js +1 -0
  46. package/docs/.vuepress/dist/assets/js/{v-8daa1a0e.dde202c9.js → v-8daa1a0e.c06c5c76.js} +1 -1
  47. package/docs/.vuepress/dist/assets/js/{v-b4a42144.9e5f9728.js → v-b4a42144.733e4e7c.js} +0 -0
  48. package/docs/.vuepress/dist/assets/js/v-e8c55052.9664f731.js +1 -0
  49. package/docs/.vuepress/dist/assets/js/v-fffb8e28.525be02a.js +1 -0
  50. package/docs/.vuepress/dist/changelog/index.html +5 -5
  51. package/docs/.vuepress/dist/contribute/index.html +5 -5
  52. package/docs/.vuepress/dist/examples/example-cascade-temperature-control.html +286 -0
  53. package/docs/.vuepress/dist/examples/example-heat-capacitor.html +229 -0
  54. package/docs/.vuepress/dist/examples/example-next-schedule-entity.html +6 -6
  55. package/docs/.vuepress/dist/examples/example-nordpool-current-state.html +6 -7
  56. package/docs/.vuepress/dist/examples/example-nordpool-events-state.html +6 -6
  57. package/docs/.vuepress/dist/examples/example-tibber-mqtt.html +6 -7
  58. package/docs/.vuepress/dist/examples/index.html +5 -5
  59. package/docs/.vuepress/dist/faq/best-save-viewer.html +15 -0
  60. package/docs/.vuepress/dist/faq/index.html +5 -5
  61. package/docs/.vuepress/dist/guide/index.html +6 -6
  62. package/docs/.vuepress/dist/index.html +5 -5
  63. package/docs/.vuepress/dist/nodes/index.html +5 -5
  64. package/docs/.vuepress/dist/nodes/old-power-saver-doc.html +7 -7
  65. package/docs/.vuepress/dist/nodes/power-saver.html +5 -5
  66. package/docs/.vuepress/dist/nodes/ps-elvia-add-tariff.html +5 -5
  67. package/docs/.vuepress/dist/nodes/ps-general-add-tariff.html +5 -5
  68. package/docs/.vuepress/dist/nodes/ps-receive-price.html +8 -8
  69. package/docs/.vuepress/dist/nodes/ps-strategy-best-save.html +27 -8
  70. package/docs/.vuepress/dist/nodes/ps-strategy-heat-capacitor.html +242 -0
  71. package/docs/.vuepress/dist/nodes/ps-strategy-lowest-price.html +22 -7
  72. package/docs/.vuepress/dist/nodes/strategy-input.html +5 -5
  73. package/docs/README.md +4 -1
  74. package/docs/changelog/README.md +22 -0
  75. package/docs/contribute/README.md +11 -3
  76. package/docs/examples/README.md +8 -2
  77. package/docs/examples/example-cascade-temperature-control.md +345 -0
  78. package/docs/examples/example-heat-capacitor.md +271 -0
  79. package/docs/examples/example-nordpool-current-state.md +0 -1
  80. package/docs/examples/example-tibber-mqtt.md +0 -1
  81. package/docs/faq/README.md +28 -1
  82. package/docs/faq/best-save-viewer.md +61 -0
  83. package/docs/images/best-save-config.png +0 -0
  84. package/docs/images/copy-payload-best-save.png +0 -0
  85. package/docs/images/heat-capacitor-temperatureVsPrice.png +0 -0
  86. package/docs/images/node-ps-strategy-heat-capacitor-cascade-control.png +0 -0
  87. package/docs/images/node-ps-strategy-heat-capacitor-simple-flow-example.png +0 -0
  88. package/docs/images/node-ps-strategy-heat-capacitor.png +0 -0
  89. package/docs/images/oven-setpoint-calculation.png +0 -0
  90. package/docs/images/overshoot-time.png +0 -0
  91. package/docs/images/temperature-manipulation-config.png +0 -0
  92. package/docs/nodes/README.md +7 -1
  93. package/docs/nodes/ps-strategy-best-save.md +95 -8
  94. package/docs/nodes/ps-strategy-heat-capacitor.md +346 -0
  95. package/docs/nodes/ps-strategy-lowest-price.md +57 -0
  96. package/package.json +8 -3
  97. package/src/handle-input.js +32 -10
  98. package/src/strategy-best-save.html +0 -21
  99. package/src/strategy-best-save.js +8 -11
  100. package/src/strategy-heat-capacitor-functions.js +246 -0
  101. package/src/strategy-heat-capacitor.html +85 -0
  102. package/src/strategy-heat-capacitor.js +125 -0
  103. package/test/commands-input.test.js +47 -0
  104. package/test/data/best-save-result.json +1 -2
  105. package/test/data/converted-prices.json +1 -1
  106. package/test/data/current-undefined-prices.json +197 -0
  107. package/test/data/current-undefined-result.json +208 -0
  108. package/test/data/lowest-price-result-missing-end.json +2 -1
  109. package/test/data/multiple-trades.json +53 -0
  110. package/test/data/reconfigResult.js +56 -294
  111. package/test/data/reconfigResult_old2.js +75 -0
  112. package/test/data/tibber-decreasing-24h.json +101 -0
  113. package/test/data/tibber-decreasing2-24h.json +101 -0
  114. package/test/data/tibber-result-end-0-24h.json +1 -0
  115. package/test/data/tibber-result-end-0.json +1 -0
  116. package/test/send-config-input.test.js +3 -37
  117. package/test/strategy-best-save-test-utils.js +2 -1
  118. package/test/strategy-best-save.test.js +14 -8
  119. package/test/strategy-heat-capacitor-node.test.js +183 -0
  120. package/test/strategy-heat-capacitor.test.js +105 -0
  121. package/test/test-utils.js +1 -7
  122. package/test/utils.test.js +0 -33
  123. package/docs/.vuepress/dist/assets/img/best-save-config.93fa3c21.png +0 -0
  124. package/docs/.vuepress/dist/assets/js/812.79dad458.js +0 -2
  125. package/docs/.vuepress/dist/assets/js/app.49ad6d54.js +0 -1
  126. package/docs/.vuepress/dist/assets/js/runtime~app.547d0f4e.js +0 -1
  127. package/docs/.vuepress/dist/assets/js/v-0aca7ba6.b42fad7f.js +0 -1
  128. package/docs/.vuepress/dist/assets/js/v-0b5e3c8c.3b37457f.js +0 -1
  129. package/docs/.vuepress/dist/assets/js/v-4637f9e4.b320f5e8.js +0 -1
  130. package/docs/.vuepress/dist/assets/js/v-510ed0d4.3c7e0056.js +0 -1
  131. package/docs/.vuepress/dist/assets/js/v-677dfaed.0013f083.js +0 -1
  132. package/docs/.vuepress/dist/assets/js/v-7446a652.d05e2648.js +0 -1
  133. package/docs/.vuepress/dist/assets/js/v-7c87f26e.1127dcf5.js +0 -1
  134. package/docs/.vuepress/dist/assets/js/v-e8c55052.8384b053.js +0 -1
  135. package/docs/.vuepress/dist/assets/js/v-fffb8e28.3406fd88.js +0 -1
  136. package/test/data/adjustedResult.js +0 -302
  137. package/test/data/adjustedResult_old.js +0 -154
@@ -0,0 +1,345 @@
1
+ # Cascade temperature control
2
+
3
+ ## Description
4
+
5
+ The controller changes the setpoint of climate entities to regulate the temperature of room with increased responsiveness, accuracy, and stability.
6
+
7
+ ### An example
8
+
9
+ A room has a temperature sensor and en electric heater. Given a setpoint temperature, the controller can make the sensor match the given value by adjusting the temperature settings of the electric heater. This type of control usually reacts faster and is more accurate then the alternative of simply changing the temperature settings of the heater. The flow requires that node-red, home assistant, and the connection to the climate entity are stable.
10
+
11
+ ![cascade_flow](../images/node-ps-strategy-heat-capacitor-cascade-control.png)
12
+
13
+ ![cascade_example](https://deltamotion.com/support/webhelp/rmctools/Controller_Features/Control_Modes/Advanced_Control/CascadeLoop.png)
14
+
15
+ The example utilizes a PID controller to provide a number between 0 and 1 to indicate a load on the heater
16
+
17
+ A cascade temperature controller is a controller which utilizes the input/setpoints of other controllers/climate entities to regulate to its own setpoint
18
+
19
+ ---
20
+
21
+ ## Requirements
22
+
23
+ > Home assistant integrated with Node-RED
24
+
25
+ > The PID node installed - https://flows.nodered.org/node/node-red-contrib-pid
26
+
27
+ > A climate entity
28
+
29
+ ## Instructions
30
+
31
+ > Create an `input_number` entity in Home Assistant and name it "cascade_setpoint"
32
+
33
+ > Create an `input_boolean` entity in Home Assistant and name it `cascade_enabled`
34
+
35
+ - When set to false, this will disengage the controller
36
+
37
+ > Import the flow into Node-RED
38
+
39
+ > Enter the correct sensor tempertaure entity in the `Temp sensor` node
40
+
41
+ > Change the climate entity name in three places
42
+
43
+ - Current climate settings - node
44
+ - Set Temperature node - two places
45
+ - `Entity ID`
46
+ - `Data`
47
+
48
+ > (optional) Change the oven setpoint range - see figure below.
49
+
50
+ - This regulates what values the controller sends to the oven. As a default, the value sent is oven_setpoint = setpoint +- 5 degrees. That is, for a setoint of 10C, the controller will be sending setpoints between 5 and 15 C to the oven. This is further limited to whole numbers, a minimum value of 5, and a maximum value of 30.
51
+
52
+ > (reccomended) Tune the PID controller - Detailed instructions can be found here: http://blog.clanlaw.org.uk/pid-loop-tuning.html
53
+
54
+ - Measure the system and find the overshoot time
55
+ - Set the proportional band to **zero** and place the setpoint a bit above the current measured value (se figure).
56
+ - Wait for the system to overshoot the target temperature and measure the time it takes for the system to return to the setpoint.
57
+ - Set the proportional band. This is the value indicates how much the measured temperature is allowed to deviate from the setpoint before max load is applied.
58
+ - Spesify the integral time. A good value is two times the overshoot time.
59
+ - Insert the derivative time. A good value here is half of the overshoot time.
60
+
61
+ ![oven_setoint](../images/oven-setpoint-calculation.png)
62
+ ![overshoot_time](../images/overshoot-time.png)
63
+
64
+ ---
65
+
66
+ ## Flow
67
+
68
+ ---
69
+
70
+ ::: details Flow code
71
+
72
+ ```json:no-line-numbers
73
+ [
74
+ {
75
+ "id": "29fde6c61057362b",
76
+ "type": "tab",
77
+ "label": "PID Controller - cascade",
78
+ "disabled": false,
79
+ "info": "",
80
+ "env": []
81
+ },
82
+ {
83
+ "id": "61ae0bee1a382102",
84
+ "type": "server-state-changed",
85
+ "z": "29fde6c61057362b",
86
+ "name": "Setpoint",
87
+ "server": "e2dd69fb.8f70a8",
88
+ "version": 3,
89
+ "exposeToHomeAssistant": false,
90
+ "haConfig": [
91
+ { "property": "name", "value": "" },
92
+ { "property": "icon", "value": "" }
93
+ ],
94
+ "entityidfilter": "input_number.cascade_setpoint",
95
+ "entityidfiltertype": "exact",
96
+ "outputinitially": true,
97
+ "state_type": "num",
98
+ "haltifstate": "",
99
+ "halt_if_type": "str",
100
+ "halt_if_compare": "is",
101
+ "outputs": 1,
102
+ "output_only_on_state_change": false,
103
+ "for": 0,
104
+ "forType": "num",
105
+ "forUnits": "minutes",
106
+ "ignorePrevStateNull": false,
107
+ "ignorePrevStateUnknown": false,
108
+ "ignorePrevStateUnavailable": false,
109
+ "ignoreCurrentStateUnknown": true,
110
+ "ignoreCurrentStateUnavailable": true,
111
+ "outputProperties": [
112
+ { "property": "payload", "propertyType": "msg", "value": "", "valueType": "entityState" },
113
+ { "property": "data", "propertyType": "msg", "value": "", "valueType": "eventData" },
114
+ { "property": "topic", "propertyType": "msg", "value": "", "valueType": "triggerId" }
115
+ ],
116
+ "x": 120,
117
+ "y": 100,
118
+ "wires": [["f8958d382348c254"]]
119
+ },
120
+ {
121
+ "id": "ef1c6050d6de41c7",
122
+ "type": "server-state-changed",
123
+ "z": "29fde6c61057362b",
124
+ "name": "Temp. sensor",
125
+ "server": "e2dd69fb.8f70a8",
126
+ "version": 3,
127
+ "exposeToHomeAssistant": false,
128
+ "haConfig": [
129
+ { "property": "name", "value": "" },
130
+ { "property": "icon", "value": "" }
131
+ ],
132
+ "entityidfilter": "sensor.kjokken_temp",
133
+ "entityidfiltertype": "exact",
134
+ "outputinitially": true,
135
+ "state_type": "num",
136
+ "haltifstate": "",
137
+ "halt_if_type": "str",
138
+ "halt_if_compare": "is",
139
+ "outputs": 1,
140
+ "output_only_on_state_change": false,
141
+ "for": 0,
142
+ "forType": "num",
143
+ "forUnits": "seconds",
144
+ "ignorePrevStateNull": false,
145
+ "ignorePrevStateUnknown": false,
146
+ "ignorePrevStateUnavailable": false,
147
+ "ignoreCurrentStateUnknown": true,
148
+ "ignoreCurrentStateUnavailable": true,
149
+ "outputProperties": [
150
+ { "property": "payload", "propertyType": "msg", "value": "", "valueType": "entityState" },
151
+ { "property": "data", "propertyType": "msg", "value": "", "valueType": "eventData" },
152
+ { "property": "topic", "propertyType": "msg", "value": "", "valueType": "triggerId" }
153
+ ],
154
+ "x": 130,
155
+ "y": 160,
156
+ "wires": [["ee1904546f36bdcb"]]
157
+ },
158
+ {
159
+ "id": "f8958d382348c254",
160
+ "type": "function",
161
+ "z": "29fde6c61057362b",
162
+ "name": "Specify topic",
163
+ "func": "msg.topic = \"setpoint\"\nflow.set('setpoint',msg.payload)\nreturn msg",
164
+ "outputs": 1,
165
+ "noerr": 0,
166
+ "initialize": "",
167
+ "finalize": "",
168
+ "libs": [],
169
+ "x": 270,
170
+ "y": 100,
171
+ "wires": [["6f77dd60c21180e1"]]
172
+ },
173
+ {
174
+ "id": "6f77dd60c21180e1",
175
+ "type": "PID",
176
+ "z": "29fde6c61057362b",
177
+ "name": "",
178
+ "setpoint": "7",
179
+ "pb": "0.6",
180
+ "ti": "3600",
181
+ "td": "900",
182
+ "integral_default": 0.5,
183
+ "smooth_factor": "2",
184
+ "max_interval": "600",
185
+ "enable": 1,
186
+ "disabled_op": 0,
187
+ "x": 430,
188
+ "y": 140,
189
+ "wires": [["ea6adedb7e2fc14e"]]
190
+ },
191
+ {
192
+ "id": "ea6adedb7e2fc14e",
193
+ "type": "function",
194
+ "z": "29fde6c61057362b",
195
+ "name": "Calc oven setpoint",
196
+ "func": "msg.load = msg.payload\n//Max adjustment is +-5 degrees\ntemp = flow.get('setpoint')+ 5 * 2 * (msg.load-0.5)\n//Some ovens have max and min temperature settings\nif(temp<5) {temp=5.0;}\nif(temp>30) {temp=30.0;}\n//Many ovens cannot deal with decimals.\ntemp = Math.round(temp)\nmsg.heater_setpoint=temp\nreturn msg",
197
+ "outputs": 1,
198
+ "noerr": 0,
199
+ "initialize": "",
200
+ "finalize": "",
201
+ "libs": [],
202
+ "x": 590,
203
+ "y": 140,
204
+ "wires": [["45925567a1177d5b"]]
205
+ },
206
+ {
207
+ "id": "5fa07ec0c1842823",
208
+ "type": "api-current-state",
209
+ "z": "29fde6c61057362b",
210
+ "name": "Current climate settings",
211
+ "server": "e2dd69fb.8f70a8",
212
+ "version": 3,
213
+ "outputs": 1,
214
+ "halt_if": "",
215
+ "halt_if_type": "str",
216
+ "halt_if_compare": "is",
217
+ "entity_id": "climate.my_climate",
218
+ "state_type": "str",
219
+ "blockInputOverrides": false,
220
+ "outputProperties": [
221
+ { "property": "payload", "propertyType": "msg", "value": "", "valueType": "entityState" },
222
+ { "property": "data", "propertyType": "msg", "value": "", "valueType": "entity" }
223
+ ],
224
+ "for": 0,
225
+ "forType": "num",
226
+ "forUnits": "minutes",
227
+ "x": 950,
228
+ "y": 140,
229
+ "wires": [["ba7e48582e04c14c", "0a7c09c92a01178e"]]
230
+ },
231
+ {
232
+ "id": "ba7e48582e04c14c",
233
+ "type": "switch",
234
+ "z": "29fde6c61057362b",
235
+ "name": "Not same?",
236
+ "property": "data.attributes.temperature",
237
+ "propertyType": "msg",
238
+ "rules": [{ "t": "neq", "v": "heater_setpoint", "vt": "msg" }],
239
+ "checkall": "true",
240
+ "repair": false,
241
+ "outputs": 1,
242
+ "x": 1150,
243
+ "y": 140,
244
+ "wires": [["1114bb7e63d16e98", "0a7c09c92a01178e"]]
245
+ },
246
+ {
247
+ "id": "1114bb7e63d16e98",
248
+ "type": "api-call-service",
249
+ "z": "29fde6c61057362b",
250
+ "name": "Sett temperatur",
251
+ "server": "e2dd69fb.8f70a8",
252
+ "version": 3,
253
+ "debugenabled": false,
254
+ "service_domain": "climate",
255
+ "service": "set_temperature",
256
+ "entityId": "climate.my_climate",
257
+ "data": "{\"entity_id\":\"climate.my_climate\",\"temperature\":\"{{heater_setpoint}}\"}",
258
+ "dataType": "json",
259
+ "mergecontext": "",
260
+ "mustacheAltTags": false,
261
+ "outputProperties": [],
262
+ "queue": "none",
263
+ "x": 1320,
264
+ "y": 140,
265
+ "wires": [[]]
266
+ },
267
+ {
268
+ "id": "45925567a1177d5b",
269
+ "type": "api-current-state",
270
+ "z": "29fde6c61057362b",
271
+ "name": "Enabled?",
272
+ "server": "e2dd69fb.8f70a8",
273
+ "version": 3,
274
+ "outputs": 2,
275
+ "halt_if": "true",
276
+ "halt_if_type": "bool",
277
+ "halt_if_compare": "is",
278
+ "entity_id": "input_boolean.cascade_enabled",
279
+ "state_type": "habool",
280
+ "blockInputOverrides": false,
281
+ "outputProperties": [
282
+ { "property": "enabled", "propertyType": "msg", "value": "", "valueType": "entityState" },
283
+ { "property": "data", "propertyType": "msg", "value": "", "valueType": "entity" }
284
+ ],
285
+ "for": 0,
286
+ "forType": "num",
287
+ "forUnits": "minutes",
288
+ "x": 760,
289
+ "y": 140,
290
+ "wires": [["5fa07ec0c1842823"], []]
291
+ },
292
+ {
293
+ "id": "0a7c09c92a01178e",
294
+ "type": "debug",
295
+ "z": "29fde6c61057362b",
296
+ "name": "",
297
+ "active": false,
298
+ "tosidebar": true,
299
+ "console": false,
300
+ "tostatus": false,
301
+ "complete": "true",
302
+ "targetType": "full",
303
+ "statusVal": "",
304
+ "statusType": "auto",
305
+ "x": 1330,
306
+ "y": 240,
307
+ "wires": []
308
+ },
309
+ {
310
+ "id": "ee1904546f36bdcb",
311
+ "type": "delay",
312
+ "z": "29fde6c61057362b",
313
+ "name": "",
314
+ "pauseType": "delay",
315
+ "timeout": "100",
316
+ "timeoutUnits": "milliseconds",
317
+ "rate": "1",
318
+ "nbRateUnits": "1",
319
+ "rateUnits": "second",
320
+ "randomFirst": "1",
321
+ "randomLast": "5",
322
+ "randomUnits": "seconds",
323
+ "drop": false,
324
+ "allowrate": false,
325
+ "outputs": 1,
326
+ "x": 290,
327
+ "y": 160,
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
+ }
343
+ ]
344
+ ```
345
+ :::
@@ -0,0 +1,271 @@
1
+ # Simple heat capacitor strategy flow
2
+
3
+ ## Description
4
+
5
+ The heat capacitor strategy utilizes a large body of mass, like your house or cabin, to procure heat at a time where electricity is cheap, and divest at a time where electricity is expensive.
6
+
7
+ This is achieved by increasing the temperature setpoint of one or several climate entities at times when electricity is cheap, and reducing it when electricity is expensive.
8
+
9
+ It is a good application for cabins/heated storage spaces, as the entity never actually shuts off the climate entities and should therefore be rather safe to apply (still at you own risk :-)). It can also be used for you house, jacuzzi, and/or pool.
10
+
11
+ ![Temperature profile vs. cost](../images/heat-capacitor-temperatureVsPrice.png)
12
+
13
+ ---
14
+
15
+ ## Requirements
16
+
17
+ > Home assistant integrated with Node-RED
18
+
19
+ > Tibber node installed and correctly configured
20
+
21
+ > A climate entity
22
+
23
+ ## Instructions
24
+
25
+ > Create an `input_number` entity in Home Assistant named `setpoint`
26
+
27
+ > Import the flow into Node-RED
28
+
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)
33
+
34
+ > 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
37
+
38
+ > (optional) If the `input_number` entity was named something else than `setpoint`, change the `entity_id` of the `Setpoint` node accordingly.
39
+
40
+ ### Advanced set-up
41
+
42
+ > Replace the `Set temperature` node with a [Cascade controller](./example-cascade-temperature-control.md) to improve the heaters accuracy and response time.
43
+
44
+ ---
45
+
46
+ ## Flow
47
+
48
+ ![Simple example with Tibber](../images/node-ps-strategy-heat-capacitor-simple-flow-example.png)
49
+
50
+ ---
51
+
52
+
53
+ ::: details [Flow code]
54
+
55
+ ```json:no-line-numbers
56
+ [
57
+ {
58
+ "id": "135c4e7649611314",
59
+ "type": "tab",
60
+ "label": "PowerSaver",
61
+ "disabled": false,
62
+ "info": "",
63
+ "env": []
64
+ },
65
+ {
66
+ "id": "cf5908a52e0aee5e",
67
+ "type": "ps-receive-price",
68
+ "z": "135c4e7649611314",
69
+ "name": "Price Receiver",
70
+ "x": 400,
71
+ "y": 320,
72
+ "wires": [
73
+ [
74
+ "b7b85590b7d28ba6"
75
+ ]
76
+ ]
77
+ },
78
+ {
79
+ "id": "b08bc12bf8734c5a",
80
+ "type": "tibber-query",
81
+ "z": "135c4e7649611314",
82
+ "name": "",
83
+ "active": true,
84
+ "apiEndpointRef": "9ea07b03b88cb526",
85
+ "x": 230,
86
+ "y": 320,
87
+ "wires": [
88
+ [
89
+ "cf5908a52e0aee5e"
90
+ ]
91
+ ]
92
+ },
93
+ {
94
+ "id": "d0d4dd31efe67e85",
95
+ "type": "inject",
96
+ "z": "135c4e7649611314",
97
+ "name": "",
98
+ "props": [
99
+ {
100
+ "p": "payload"
101
+ },
102
+ {
103
+ "p": "topic",
104
+ "vt": "str"
105
+ }
106
+ ],
107
+ "repeat": "60",
108
+ "crontab": "",
109
+ "once": true,
110
+ "onceDelay": "1",
111
+ "topic": "",
112
+ "payload": "{ viewer { homes { currentSubscription { priceInfo { today { total startsAt } tomorrow { total startsAt } } } } } }",
113
+ "payloadType": "str",
114
+ "x": 90,
115
+ "y": 320,
116
+ "wires": [
117
+ [
118
+ "b08bc12bf8734c5a"
119
+ ]
120
+ ]
121
+ },
122
+ {
123
+ "id": "4831f393a0066565",
124
+ "type": "api-call-service",
125
+ "z": "135c4e7649611314",
126
+ "name": "Set temperature",
127
+ "server": "e2dd69fb.8f70a8",
128
+ "version": 3,
129
+ "debugenabled": false,
130
+ "service_domain": "climate",
131
+ "service": "set_temperature",
132
+ "entityId": "climate.my_climate",
133
+ "data": "{\"entity_id\":\"climate.my_climate\",\"temperature\":\"{{adj_setpoint}}\"}",
134
+ "dataType": "json",
135
+ "mergecontext": "",
136
+ "mustacheAltTags": false,
137
+ "outputProperties": [],
138
+ "queue": "none",
139
+ "x": 980,
140
+ "y": 320,
141
+ "wires": [
142
+ []
143
+ ]
144
+ },
145
+ {
146
+ "id": "027f4267d969e1b8",
147
+ "type": "server-state-changed",
148
+ "z": "135c4e7649611314",
149
+ "name": "Setpoint",
150
+ "server": "e2dd69fb.8f70a8",
151
+ "version": 3,
152
+ "exposeToHomeAssistant": false,
153
+ "haConfig": [
154
+ {
155
+ "property": "name",
156
+ "value": ""
157
+ },
158
+ {
159
+ "property": "icon",
160
+ "value": ""
161
+ }
162
+ ],
163
+ "entityidfilter": "input_number.setpoint",
164
+ "entityidfiltertype": "exact",
165
+ "outputinitially": true,
166
+ "state_type": "num",
167
+ "haltifstate": "",
168
+ "halt_if_type": "str",
169
+ "halt_if_compare": "is",
170
+ "outputs": 1,
171
+ "output_only_on_state_change": false,
172
+ "for": 0,
173
+ "forType": "num",
174
+ "forUnits": "minutes",
175
+ "ignorePrevStateNull": false,
176
+ "ignorePrevStateUnknown": false,
177
+ "ignorePrevStateUnavailable": false,
178
+ "ignoreCurrentStateUnknown": true,
179
+ "ignoreCurrentStateUnavailable": true,
180
+ "outputProperties": [
181
+ {
182
+ "property": "payload.config.setpoint",
183
+ "propertyType": "msg",
184
+ "value": "",
185
+ "valueType": "entityState"
186
+ },
187
+ {
188
+ "property": "data",
189
+ "propertyType": "msg",
190
+ "value": "",
191
+ "valueType": "eventData"
192
+ },
193
+ {
194
+ "property": "topic",
195
+ "propertyType": "msg",
196
+ "value": "",
197
+ "valueType": "triggerId"
198
+ }
199
+ ],
200
+ "x": 420,
201
+ "y": 360,
202
+ "wires": [
203
+ [
204
+ "b7b85590b7d28ba6"
205
+ ]
206
+ ]
207
+ },
208
+ {
209
+ "id": "b7b85590b7d28ba6",
210
+ "type": "ps-strategy-heat-capacitor",
211
+ "z": "135c4e7649611314",
212
+ "name": "Heat capacitor",
213
+ "timeHeat1C": "70",
214
+ "timeCool1C": 50,
215
+ "maxTempAdjustment": "1",
216
+ "boostTempHeat": "2",
217
+ "boostTempCool": "2",
218
+ "minSavings": 0.08,
219
+ "setpoint": 23,
220
+ "x": 600,
221
+ "y": 320,
222
+ "wires": [
223
+ [
224
+ "2b7cbdef3203a482"
225
+ ],
226
+ [],
227
+ []
228
+ ]
229
+ },
230
+ {
231
+ "id": "2b7cbdef3203a482",
232
+ "type": "function",
233
+ "z": "135c4e7649611314",
234
+ "name": "Adjust setpoint",
235
+ "func": "//In case the climate entity can only handle integers\n//Calculate rounded setpoint for the climate entity and return the msg\nmsg.adj_setpoint=Math.round(msg.payload);\nreturn msg\n",
236
+ "outputs": 1,
237
+ "noerr": 0,
238
+ "initialize": "",
239
+ "finalize": "",
240
+ "libs": [],
241
+ "x": 800,
242
+ "y": 320,
243
+ "wires": [
244
+ [
245
+ "4831f393a0066565"
246
+ ]
247
+ ]
248
+ },
249
+ {
250
+ "id": "9ea07b03b88cb526",
251
+ "type": "tibber-api-endpoint",
252
+ "feedUrl": "wss://api.tibber.com/v1-beta/gql/subscriptions",
253
+ "queryUrl": "https://api.tibber.com/v1-beta/gql",
254
+ "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
+ }
269
+ ]
270
+ ```
271
+ :::
@@ -154,7 +154,6 @@ In this example, data is read from the Nord Pool sensor in HA via the `current s
154
154
  "minSaving": "0.03",
155
155
  "sendCurrentValueWhenRescheduling": true,
156
156
  "outputIfNoSchedule": "true",
157
- "scheduleOnlyFromCurrentTime": "false",
158
157
  "x": 630,
159
158
  "y": 380,
160
159
  "wires": [
@@ -120,7 +120,6 @@ In this example, data is read from Tibber and used to turn on/off a switch, sche
120
120
  "minSaving": "0.05",
121
121
  "sendCurrentValueWhenRescheduling": true,
122
122
  "outputIfNoSchedule": "true",
123
- "scheduleOnlyFromCurrentTime": "false",
124
123
  "x": 490,
125
124
  "y": 160,
126
125
  "wires": [["467a5fe.d0bbba", "5e485ff7.db156"], ["9c978d1c.ee76", "467a5fe.d0bbba"], ["42d8b632.402e38"]]
@@ -1,5 +1,28 @@
1
+ ---
2
+ sidebar:
3
+ - /faq/README.md
4
+ - /faq/best-save-viewer.md
5
+ ---
6
+
1
7
  # FAQ
2
8
 
9
+ ## How can I contribute?
10
+
11
+ You can donate:
12
+
13
+ <DonateButtons/>
14
+
15
+ or take a look at the [contribute page](../contribute/README.md)
16
+
17
+ ## Why is the best save schedule like this?
18
+
19
+ There may be many reasons for the best save node planning like it does. Here are some considerations:
20
+
21
+ - It is turning off only if it can save the `Min saving` amount in average per kWh per hour for the hours turned off, compared to the next hour that is on.
22
+ - It will not turn off more than `Max per sequence` hours, so it may have to stay on through the most expensive hours, if there are more than the configured number of hours until the price is low enough.
23
+
24
+ In order to understand how the node works, try out the [Best Save Viewer](./best-save-viewer.md)
25
+
3
26
  ## Why does the Best Save node not turn off the most expensive hours?
4
27
 
5
28
  Here is an example:
@@ -12,7 +35,7 @@ Why does it not save the most expensive period?
12
35
 
13
36
  If you move the saving-period 4-5 hours earlier, the most expensive hours would have been saved. Why is this not better?
14
37
 
15
- Remember that the power that is not used during the saving-period, will be used immediately after. At least, that is the idea, and the normal behaviour if the power consumer is a water heater or another heater controlled by a thermostat. So, then the power would be used one of the blue hours in stead of the green cheaper hour.
38
+ Remember that the power that is not used during the saving-period, will be used immediately after. At least, that is the idea, and the normal behavior if the power consumer is a water heater or another heater controlled by a thermostat. So, then the power would be used one of the blue hours in stead of the green cheaper hour.
16
39
 
17
40
  Also remember that when saving, you do not save the full price. You only save what is the difference between the price during the saved hours and the price the hour immediately after.
18
41
 
@@ -21,3 +44,7 @@ So the best saving is found where this difference is the largest, and that is no
21
44
  Of course, if you expand the saving period from 5 to 10 hours you would save even more, but that would be a different case, and you can do that if it is ok for you to turn off for that long time.
22
45
 
23
46
  Another alternative is to reduce the minimum saving from 0.05 to 0.001. Then the 3 first red hours would be turned off, but the last red would have to be on, in order to get one hour on until the next 5-hour period off. This would however not save you for much money, since the hour that is on is almost as expensive as the hours you would turn off.
47
+
48
+ ## Can we get Legionella bacteria when turning off the water heater?
49
+
50
+ Many people ask if there is a danger that legionella bacteria will grow and become dangerous when the temperature of the water heater is lowered. As long as the water is heated to at least 65 °C every day, or at least every week, the risk of infection is not considered significant, according to the norwegian [FHI](https://www.fhi.no/nettpub/legionellaveilederen/).