node-red-contrib-power-saver 3.6.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/.eslintrc.js +15 -0
  2. package/docs/.vuepress/components/DonateButtons.vue +26 -3
  3. package/docs/.vuepress/components/VippsPlakat.vue +20 -0
  4. package/docs/.vuepress/config.js +18 -10
  5. package/docs/.vuepress/public/ads.txt +1 -0
  6. package/docs/README.md +4 -4
  7. package/docs/changelog/README.md +59 -1
  8. package/docs/contribute/README.md +8 -3
  9. package/docs/examples/README.md +2 -0
  10. package/docs/examples/example-grid-tariff-capacity-flow.json +1142 -0
  11. package/docs/examples/example-grid-tariff-capacity-part.md +988 -107
  12. package/docs/faq/README.md +1 -1
  13. package/docs/faq/best-save-viewer.md +1 -1
  14. package/docs/guide/README.md +20 -5
  15. package/docs/images/best-save-config.png +0 -0
  16. package/docs/images/combine-two-lowest-price.png +0 -0
  17. package/docs/images/example-capacity-flow.png +0 -0
  18. package/docs/images/fixed-schedule-config.png +0 -0
  19. package/docs/images/global-context-window.png +0 -0
  20. package/docs/images/lowest-price-config.png +0 -0
  21. package/docs/images/node-ps-schedule-merger.png +0 -0
  22. package/docs/images/node-ps-strategy-fixed-schedule.png +0 -0
  23. package/docs/images/ps-strategy-fixed-schedule-example.png +0 -0
  24. package/docs/images/schedule-merger-config.png +0 -0
  25. package/docs/images/schedule-merger-example-1.png +0 -0
  26. package/docs/images/vipps-plakat.png +0 -0
  27. package/docs/images/vipps-qr.png +0 -0
  28. package/docs/images/vipps-smiling-rgb-orange-pos.png +0 -0
  29. package/docs/nodes/README.md +12 -6
  30. package/docs/nodes/dynamic-commands.md +79 -0
  31. package/docs/nodes/dynamic-config.md +76 -0
  32. package/docs/nodes/ps-elvia-add-tariff.md +4 -0
  33. package/docs/nodes/ps-general-add-tariff.md +10 -0
  34. package/docs/nodes/ps-receive-price.md +2 -1
  35. package/docs/nodes/ps-schedule-merger.md +227 -0
  36. package/docs/nodes/ps-strategy-best-save.md +46 -110
  37. package/docs/nodes/ps-strategy-fixed-schedule.md +101 -0
  38. package/docs/nodes/ps-strategy-heat-capacitor.md +6 -1
  39. package/docs/nodes/ps-strategy-lowest-price.md +51 -112
  40. package/package.json +5 -2
  41. package/src/elvia/elvia-add-tariff.html +1 -2
  42. package/src/elvia/elvia-add-tariff.js +1 -3
  43. package/src/elvia/elvia-api.js +9 -0
  44. package/src/elvia/elvia-tariff.html +1 -1
  45. package/src/general-add-tariff.html +14 -8
  46. package/src/general-add-tariff.js +0 -1
  47. package/src/handle-input.js +94 -106
  48. package/src/handle-output.js +109 -0
  49. package/src/receive-price-functions.js +3 -3
  50. package/src/schedule-merger-functions.js +98 -0
  51. package/src/schedule-merger.html +135 -0
  52. package/src/schedule-merger.js +108 -0
  53. package/src/strategy-best-save.html +38 -1
  54. package/src/strategy-best-save.js +17 -63
  55. package/src/strategy-fixed-schedule.html +339 -0
  56. package/src/strategy-fixed-schedule.js +84 -0
  57. package/src/strategy-functions.js +35 -0
  58. package/src/strategy-lowest-price.html +76 -38
  59. package/src/strategy-lowest-price.js +16 -35
  60. package/src/utils.js +75 -2
  61. package/test/commands-input-best-save.test.js +142 -0
  62. package/test/commands-input-lowest-price.test.js +149 -0
  63. package/test/commands-input-schedule-merger.test.js +128 -0
  64. package/test/data/best-save-overlap-result.json +5 -1
  65. package/test/data/best-save-result.json +4 -0
  66. package/test/data/commands-result-best-save.json +383 -0
  67. package/test/data/commands-result-lowest-price.json +340 -0
  68. package/test/data/fixed-schedule-result.json +353 -0
  69. package/test/data/lowest-price-result-cont-max-fail.json +5 -1
  70. package/test/data/lowest-price-result-cont-max.json +3 -1
  71. package/test/data/lowest-price-result-cont.json +8 -1
  72. package/test/data/lowest-price-result-missing-end.json +8 -3
  73. package/test/data/lowest-price-result-neg-cont.json +27 -0
  74. package/test/data/lowest-price-result-neg-split.json +23 -0
  75. package/test/data/lowest-price-result-split-allday.json +3 -1
  76. package/test/data/lowest-price-result-split-allday10.json +1 -0
  77. package/test/data/lowest-price-result-split-max.json +3 -1
  78. package/test/data/lowest-price-result-split.json +3 -1
  79. package/test/data/merge-schedule-data.js +238 -0
  80. package/test/data/negative-prices.json +197 -0
  81. package/test/data/nordpool-event-prices.json +96 -480
  82. package/test/data/nordpool-zero-prices.json +90 -0
  83. package/test/data/reconfigResult.js +1 -0
  84. package/test/data/result.js +1 -0
  85. package/test/data/tibber-result-end-0-24h.json +12 -2
  86. package/test/data/tibber-result-end-0.json +12 -2
  87. package/test/data/tibber-result.json +1 -0
  88. package/test/receive-price.test.js +22 -0
  89. package/test/schedule-merger-functions.test.js +101 -0
  90. package/test/schedule-merger-test-utils.js +27 -0
  91. package/test/schedule-merger.test.js +130 -0
  92. package/test/send-config-input.test.js +45 -2
  93. package/test/strategy-best-save-test-utils.js +1 -1
  94. package/test/strategy-best-save.test.js +45 -0
  95. package/test/strategy-fixed-schedule.test.js +117 -0
  96. package/test/strategy-heat-capacitor.test.js +1 -1
  97. package/test/strategy-lowest-price-functions.test.js +1 -1
  98. package/test/strategy-lowest-price-test-utils.js +31 -0
  99. package/test/strategy-lowest-price.test.js +55 -45
  100. package/test/test-utils.js +43 -36
  101. package/test/utils.test.js +13 -0
  102. package/docs/images/node-power-saver.png +0 -0
  103. package/docs/nodes/power-saver.md +0 -23
  104. package/src/power-saver.html +0 -116
  105. package/src/power-saver.js +0 -260
  106. package/test/commands-input.test.js +0 -47
  107. package/test/power-saver.test.js +0 -189
@@ -1,3 +1,7 @@
1
+ ---
2
+ next: ./ps-strategy-lowest-price.md
3
+ ---
4
+
1
5
  # ps-strategy-best-save
2
6
 
3
7
  ![ps-strategy-best-save](../images/node-ps-strategy-best-save.png)
@@ -6,7 +10,11 @@ Strategy node to postpone power consumption until the price is lower.
6
10
 
7
11
  ## Description
8
12
 
9
- This strategy turns off the hours where the price difference is largest compared to the next hour that is on. The idea is that the power you are not using when the switch is turned off, will be used immediately when the switch is turned on. This would fit well for turning off a water heater or another thermostat controlled heater.
13
+ This strategy turns off the hours where the price difference is largest compared to the next hour that is on. The idea is that the power you are not using when the switch is turned off, will be used immediately when the switch is turned on (during the first hour). This would fit well for turning off a water heater or another thermostat controlled heater.
14
+
15
+ ::: danger 70°C
16
+ Be aware that the norwegian [FHI](https://www.fhi.no/nettpub/legionellaveilederen/) recommends that the temperature in the water heater is at least 70°C.
17
+ :::
10
18
 
11
19
  The picture at the bottom of the page, under [Integration with MagicMirror](#integration-with-magicmirror), illustrates this by the purple strokes, taking the price from the top of the price curve to the level of the first hour after the save-period.
12
20
 
@@ -14,14 +22,16 @@ The picture at the bottom of the page, under [Integration with MagicMirror](#int
14
22
 
15
23
  ![Best Save Config](../images/best-save-config.png)
16
24
 
17
- | Value | Description |
18
- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
19
- | Max per sequence | Maximum number of hours to turn off in a sequence. |
20
- | Min recover | Minimum hours to turn on immediately after a period when turned off the maximum number of hours that is allowed to be turned off |
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
- | Send when rescheduling | Check this to make sure on or off output is sent immediately after rescheduling |
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. |
25
+ | Value | |
26
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
27
+ | Max per sequence | Maximum number of hours to turn off in a sequence |
28
+ | Min recover | Minimum hours to turn on immediately after a period when turned off the maximum number of hours that is allowed to be turned off |
29
+ | 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? |
30
+ | Output value for on | Set what value to output on output 1 in order to turn on. Default is `boolean true`. You can also select a `number`, for example `1`, or a `string`, for example `on`, or any other value. |
31
+ | Output value for off | Set what value to output on output 2 in order to turn off. Default is `boolean false`. You can also select a `number`, for example `0`, or a `string`, for example `off`, or any other value. |
32
+ | Send when rescheduling | Check this to make sure on or off output is sent immediately after rescheduling. If unchecked, the output is sent only if it has not been sent before, or is different from the current value. |
33
+ | If no schedule, send | What to do if there is no valid schedule any more (turn on or off). This value will be sent also before there is any valid schedule, or after the last hour there is price data for. |
34
+ | Context storage | Select context storage to save data to, if more than one is configured in the Node-RED `settings.js` file. |
25
35
 
26
36
  ::: warning Min recover
27
37
  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.
@@ -29,108 +39,28 @@ NB! The `Min recover` only has effect if the previous save-period is of length `
29
39
 
30
40
  ### Dynamic config
31
41
 
32
- It is possible to change config dynamically by sending a config message to the node. The config messages has a payload with a config object like this example:
42
+ The following config values can be changed dynamically:
33
43
 
34
- ```json
35
- "payload": {
36
- "config": {
37
- "contextStorage": "file",
38
- "maxHoursToSaveInSequence": 4,
39
- "minHoursOnAfterMaxSequenceSaved": 2,
40
- "minSaving": 0.02,
41
- "sendCurrentValueWhenRescheduling": true,
42
- "outputIfNoSchedule": true,
43
- }
44
- }
45
- ```
46
-
47
- All the variables in the config object are optional. You can send only those you want to change.
48
-
49
- The config sent like this will be valid until a new config is sent the same way, or until the flow is restarted. On a restart, the original config set up in the node will be used.
50
-
51
- When a config is sent like this, and without price data, the schedule will be replanned based on the last previously received price data. If no price data has been received, no scheduling is done.
44
+ | Name | Description |
45
+ | ---------------------------------- | -------------------------------------------------------- |
46
+ | `contextStorage` | String |
47
+ | `maxHoursToSaveInSequence` | Number |
48
+ | `minHoursOnAfterMaxSequenceSaved` | Number |
49
+ | `minSaving` | Number |
50
+ | `outputIfNoSchedule` | Legal values: `true`, `false` |
51
+ | `sendCurrentValueWhenRescheduling` | Legal values: `true`, `false` |
52
+ | `outputValueForOn` | See description in [Dynamic Config](./dynamic-config.md) |
53
+ | `outputValueForOff` | See description in [Dynamic Config](./dynamic-config.md) |
54
+ | `outputValueForOntype` | See description in [Dynamic Config](./dynamic-config.md) |
55
+ | `outputValueForOfftype` | See description in [Dynamic Config](./dynamic-config.md) |
56
+ | `override` | Legal values: `"on"`, `"off"`, `"auto"` |
52
57
 
53
- However, you can send config and price data in the same message. Then both will be used.
58
+ See [Dynamic Config](./dynamic-config.md) for details and how to send dynamic config.
54
59
 
55
60
  ### Dynamic commands
56
61
 
57
- You can dynamically send some commands to the node via its input, by using a `commands` object in the payload as described below.
58
-
59
- Commands can be sent together with config and/or price data, but the exact behavior is not defined.
60
-
61
- #### sendSchedule
62
-
63
- You can get the schedule sent to output 3 any time by sending a message like this to the node:
64
-
65
- ```json
66
- "payload": {
67
- "commands": {
68
- "sendSchedule": true,
69
- }
70
- }
71
- ```
72
-
73
- When you do this, the current schedule is actually recalculated based on the last received data, and then sent to output 3 the same way as when it was originally planned.
74
-
75
- #### sendOutput
76
-
77
- You can get the node to send the current output to output 1 or 2 any time by sending a message like this to the node:
78
-
79
- ```json
80
- "payload": {
81
- "commands": {
82
- "sendOutput": true,
83
- }
84
- }
85
- ```
86
-
87
- When you do this, the current schedule is actually recalculated based on the last received data. The current output is sent to output 1 or 2, and the schedule is sent to output 3.
88
-
89
- #### reset
90
-
91
- You can reset data the node has saved in context by sending this message:
92
-
93
- ```json
94
- "payload": {
95
- "commands": {
96
- "reset": true,
97
- }
98
- }
99
- ```
100
-
101
- When you do this, all historical data the node has saved is deleted, including the current schedule, so the result will be
102
- that the node shows status "No price data". When new price data is received, a schedule is calculated without considering any history.
103
-
104
- The nodes config is not deleted, as the node depends on it to work.
105
-
106
- ::: warning
107
- This operation cannot be undone.
108
-
109
- However, it is normally not a big loss, as you can just feed the node with new price data and start from scratch.
110
- :::
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.
62
+ You can send dynamic commands to this node, for example to make it resend output.
63
+ See [Dynamic Commands](./dynamic-commands.md) for details and how to send dynamic commands.
134
64
 
135
65
  ## Input
136
66
 
@@ -151,11 +81,11 @@ There are three outputs. You use only those you need for your purpose.
151
81
 
152
82
  ### Output 1
153
83
 
154
- A payload with the word `true` is sent to output 1 whenever the power / switch shall be turned on.
84
+ A payload with the value set in config, default `true`, is sent to output 1 whenever the power / switch shall be turned on.
155
85
 
156
86
  ### Output 2
157
87
 
158
- A payload with the word `false` is sent to output 2 whenever the power / switch shall be turned off.
88
+ A payload with the value set in config, default `false` is sent to output 2 whenever the power / switch shall be turned off.
159
89
 
160
90
  ### Output 3
161
91
 
@@ -174,7 +104,12 @@ Example of output:
174
104
  {
175
105
  "time": "2021-09-30T01:00:00.000+02:00",
176
106
  "value": true,
177
- "countHours": 2
107
+ "countHours": 23
108
+ },
109
+ {
110
+ "time": "2021-09-31T00:00:00.000+02:00",
111
+ "value": false,
112
+ "countHours": null
178
113
  }
179
114
  ],
180
115
  "hours": [
@@ -195,11 +130,12 @@ Example of output:
195
130
  "onOff": true,
196
131
  "start": "2021-09-30T02:00:00.000+02:00",
197
132
  "saving": null
198
- }
133
+ } // ...
199
134
  ],
200
135
  "source": "Nord Pool",
201
136
  "config": {
202
137
  "contextStorage": "default",
138
+ "hasChanged": false,
203
139
  "maxHoursToSaveInSequence": 3,
204
140
  "minHoursOnAfterMaxSequenceSaved": "1",
205
141
  "minSaving": 0.001,
@@ -0,0 +1,101 @@
1
+ ---
2
+ prev: ./ps-strategy-heat-capacitor
3
+ next: ./ps-receive-price.md
4
+ ---
5
+
6
+ # ps-strategy-fixed-schedule
7
+
8
+ ![ps-strategy-fixed-schedule](../images/node-ps-strategy-fixed-schedule.png)
9
+
10
+ Strategy node to set a fixed schedule.
11
+ This can be used by itself, but it is also perfect to combine with other strategies
12
+ and the [Schedule Merger](./ps-schedule-merger.md) node in order to force periods of the day either on or off.
13
+
14
+ ## Description
15
+
16
+ This strategy can be used to set a period of the day or the week fixed to on or off.
17
+
18
+ The strategy was made together with the [Schedule Merger](./ps-schedule-merger.md) node,
19
+ and can be used together with this in order to mask periods of the day from being
20
+ affected by another schedule, primarily the Fixed Schedule or Lowest Price strategies.
21
+
22
+ Here is an example of how to combine it with the Lowest Price node:
23
+
24
+ ![ps-strategy-fixed-schedule-example](../images/ps-strategy-fixed-schedule-example.png)
25
+
26
+ ## Configuration
27
+
28
+ ![Fixed Schedule Config](../images/fixed-schedule-config.png)
29
+
30
+ | Value | |
31
+ | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
32
+ | Schedule | Decide from what time, and what value to set, for one or more periods during the day. It is working around the clock, so the value that is at the end of one day continues on the beginning of the next day, unless you change it at 00:00. Click `Add period` to get more periods. |
33
+ | Days | Use this if you want the schedule to work only on specific days. For the other days, the value on the `If no schedule, send` setting is sent. |
34
+ | Valid from date | If this is set, the schedule is not valid before this date. |
35
+ | Valid to date | If this is set, the schedule is not valid after this date. |
36
+ | Output value for on | Set what value to output on output 1 in order to turn on. Default is `boolean true`. You can also select a `number`, for example `1`, or a `string`, for example `on`, or any other value. |
37
+ | Output value for off | Set what value to output on output 2 in order to turn off. Default is `boolean false`. You can also select a `number`, for example `0`, or a `string`, for example `off`, or any other value. |
38
+ | Send when rescheduling | Check this to make sure on or off output is sent immediately after rescheduling. If unchecked, the output is sent only if it has not been sent before, or is different from the current value. |
39
+ | If no schedule, send | What to do if there is no valid schedule any more (turn on or off). This value will be sent also before there is any valid schedule, or after the last hour there is price data for. |
40
+ | Context storage | Select context storage to save data to, if more than one is configured in the Node-RED `settings.js` file. |
41
+
42
+ ### Dynamic config
43
+
44
+ The following config values can be changed dynamically:
45
+
46
+ | Name | Description |
47
+ | ---------------------------------- | -------------------------------------------------------- |
48
+ | `contextStorage` | String |
49
+ | `periods` | An array with periods. See below. |
50
+ | `validFrom` | String with date in form `YYYY-MM-DD` |
51
+ | `validTo` | String with date in form `YYYY-MM-DD` |
52
+ | `days` | An array of days. See below. |
53
+ | `outputIfNoSchedule` | Legal values: `true`, `false` |
54
+ | `sendCurrentValueWhenRescheduling` | Legal values: `true`, `false` |
55
+ | `outputValueForOn` | See description in [Dynamic Config](./dynamic-config.md) |
56
+ | `outputValueForOff` | See description in [Dynamic Config](./dynamic-config.md) |
57
+ | `outputValueForOntype` | See description in [Dynamic Config](./dynamic-config.md) |
58
+ | `outputValueForOfftype` | See description in [Dynamic Config](./dynamic-config.md) |
59
+ | `override` | Legal values: `"on"`, `"off"`, `"auto"` |
60
+
61
+ See [Dynamic Config](./dynamic-config.md) for details and how to send dynamic config.
62
+
63
+ ### Dynamic commands
64
+
65
+ You can send dynamic commands to this node, for example to make it resend output.
66
+ See [Dynamic Commands](./dynamic-commands.md) for details and how to send dynamic commands.
67
+
68
+ ## Input
69
+
70
+ The input is the [common strategy input format](./strategy-input.md).
71
+
72
+ The node requires the price-data input in order to know what times to generate schedule for.
73
+ This is especially important when merging the schedule using the Schedule Merger node,
74
+ as all schedules that are merged must be for the exact same period.
75
+
76
+ ## Output
77
+
78
+ There are three outputs. You use only those you need for your purpose.
79
+
80
+ ### Output 1
81
+
82
+ A payload with the value set in config, default `true`, is sent to output 1 whenever the power / switch shall be turned on.
83
+
84
+ ### Output 2
85
+
86
+ A payload with the value set in config, default `false` is sent to output 2 whenever the power / switch shall be turned off.
87
+
88
+ ### Output 3
89
+
90
+ When a valid input is received, and the schedule is recalculated, the resulting schedule, as well as some other information, is sent to output 3. You can use this to see the plan and verify that it meets your expectations. You can also use it to display the schedule in any way you like.
91
+
92
+ The aoutput is similar to the output from the other strategy nodes.
93
+
94
+ ## Usage ideas
95
+
96
+ ### Turn on every morning
97
+
98
+ If you want to make sure that a switch is turned on at least 2 hours every morning from 04:00 to 06:00,
99
+ even if you are using the Lowest Price node to turn it on only the 4 cheapest hours during
100
+ the whole day, you can use this node to make sure it is on this period, and then merge it with the
101
+ Lowest Price schedule using the Schedule Merger node with the `OR` function.
@@ -1,4 +1,9 @@
1
- # ps-strategy-heat-capacitor <Badge type="warning">Experimental</Badge>
1
+ ---
2
+ prev: ./ps-strategy-lowest-price.md
3
+ next: ./ps-strategy-fixed-schedule.md
4
+ ---
5
+
6
+ # ps-strategy-heat-capacitor
2
7
 
3
8
  ![ps-strategy-lowest-price](../images/node-ps-strategy-heat-capacitor.png)
4
9
 
@@ -1,5 +1,6 @@
1
1
  ---
2
- next: ./ps-receive-price.md
2
+ prev: ./ps-strategy-best-save.md
3
+ next: ./ps-strategy-heat-capacitor.md
3
4
  ---
4
5
 
5
6
  # ps-strategy-lowest-price
@@ -16,17 +17,18 @@ The node can work on a specific period from 1 to 24 hours during a 24 hour perio
16
17
 
17
18
  ![Node Configuration](../images/lowest-price-config.png)
18
19
 
19
- | Value | Description |
20
- | ---------------------- | -------------------------------------------------------------------------------- |
21
- | From time | The start time of the selected period. |
22
- | To time | The end time of the selected period. |
23
- | Hours on | The number of hours that shall be turned on. |
24
- | Max price | If set, does not turn on if price is over this limit. See below. |
25
- | Consecutive on-period | Check this if you need the on-period to be consecutive. |
26
- | Send when rescheduling | Check this to make sure on or off output is sent immediately after rescheduling. |
27
- | If no schedule, send | What to do if there is no valid schedule any more (turn on or off). |
28
- | Outside period, send | Select the value to send outside the selected period. |
29
- | Context storage | Select context storage to save data to, if you want other than the default. |
20
+ | Value | Description |
21
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
22
+ | From time | The start time of the selected period. |
23
+ | To time | The end time of the selected period. |
24
+ | Hours on | The number of hours that shall be turned on. |
25
+ | Max price | If set, does not turn on if price is over this limit. See below. |
26
+ | Consecutive on-period | Check this if you need the on-period to be consecutive. |
27
+ | Output value for on | Set what value to output on output 1 in order to turn on. Default is `boolean true`. You can also select a `number`, for example `1`, or a `string`, for example `on`, or any other value. |
28
+ | Output value for off | Set what value to output on output 2 in order to turn off. Default is `boolean false`. You can also select a `number`, for example `0`, or a `string`, for example `off`, or any other value. |
29
+ | Send when rescheduling | Check this to make sure on or off output is sent immediately after rescheduling. If unchecked, the output is sent only if it has not been sent before, or is different from the current value. |
30
+ | If no schedule, send | What to do if there is no valid schedule any more (turn on or off). This value will be sent also before there is any valid schedule, or after the last hour there is price data for. |
31
+ | Context storage | Select context storage to save data to, if more than one is configured in the Node-RED `settings.js` file. |
30
32
 
31
33
  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.
32
34
 
@@ -64,117 +66,50 @@ If you leave `Max price` blank, it has no effect.
64
66
 
65
67
  ### Dynamic config
66
68
 
67
- It is possible to change config dynamically by sending a config message to the node. The config messages has a payload with a config object like this example:
68
-
69
- ```json
70
- "payload": {
71
- "config": {
72
- "contextStorage": "file",
73
- "fromTime": 10,
74
- "toTime": 16,
75
- "hoursOn": 3,
76
- "maxPrice": null,
77
- "doNotSplit": false,
78
- "sendCurrentValueWhenRescheduling": true,
79
- "outputIfNoSchedule": false,
80
- "outputOutsidePeriod": false
81
- }
82
- }
83
- ```
84
-
85
- All the variables in the config object are optional. You can send only those you want to change.
86
-
87
- The config sent like this will be valid until a new config is sent the same way, or until the flow is restarted. On a restart, the original config set up in the node will be used.
88
-
89
- When a config is sent like this, and without price data, the schedule will be replanned based on the last previously received price data. If no price data has been received, no scheduling is done.
90
-
91
- However, you can send config and price data in the same message. Then both will be used .
69
+ The following config values can be changed dynamically:
70
+
71
+ | Name | Description |
72
+ | ---------------------------------- | -------------------------------------------------------- |
73
+ | `contextStorage` | String |
74
+ | `fromTime` | String with number, 2 digits, "00"-"23" |
75
+ | `toTime` | String with number, 2 digits, "00"-"23" |
76
+ | `hoursOn` | Number |
77
+ | `maxPrice` | Number |
78
+ | `outputIfNoSchedule` | Legal values: `true`, `false` |
79
+ | `outputIfNoSchedule` | Legal values: `true`, `false` |
80
+ | `doNotSplit` | Legal values: `true`, `false` |
81
+ | `outputOutsidePeriod` | Legal values: `true`, `false` |
82
+ | `sendCurrentValueWhenRescheduling` | Legal values: `true`, `false` |
83
+ | `outputValueForOn` | See description in [Dynamic Config](./dynamic-config.md) |
84
+ | `outputValueForOff` | See description in [Dynamic Config](./dynamic-config.md) |
85
+ | `outputValueForOntype` | See description in [Dynamic Config](./dynamic-config.md) |
86
+ | `outputValueForOfftype` | See description in [Dynamic Config](./dynamic-config.md) |
87
+ | `override` | Legal values: `"on"`, `"off"`, `"auto"` |
88
+
89
+ See [Dynamic Config](./dynamic-config.md) for details and how to send dynamic config.
92
90
 
93
91
  ### Dynamic commands
94
92
 
95
- You can dynamically send some commands to the node via its input, by using a `commands` object in the payload as described below.
96
-
97
- Commands can be sent together with config and/or price data, but the exact behavior is not defined.
98
-
99
- #### sendSchedule
100
-
101
- You can get the schedule sent to output 3 any time by sending a message like this to the node:
102
-
103
- ```json
104
- "payload": {
105
- "commands": {
106
- "sendSchedule": true,
107
- }
108
- }
109
- ```
110
-
111
- When you do this, the current schedule is actually recalculated based on the last received data, and then sent to output 3 the same way as when it was originally planned.
112
-
113
- #### sendOutput
114
-
115
- You can get the node to send the current output to output 1 or 2 any time by sending a message like this to the node:
116
-
117
- ```json
118
- "payload": {
119
- "commands": {
120
- "sendOutput": true,
121
- }
122
- }
123
- ```
124
-
125
- When you do this, the current schedule is actually recalculated based on the last received data. The current output is sent to output 1 or 2, and the schedule is sent to output 3.
126
-
127
- #### reset
128
-
129
- You can reset data the node has saved in context by sending this message:
130
-
131
- ```json
132
- "payload": {
133
- "commands": {
134
- "reset": true,
135
- }
136
- }
137
- ```
138
-
139
- When you do this, all historical data the node has saved is deleted, including the current schedule, so the result will be
140
- that the node shows status "No price data". When new price data is received, a schedule is calculated without considering any history.
141
-
142
- The nodes config is not deleted, as the node depends on it to work.
143
-
144
- ::: warning
145
- This operation cannot be undone.
93
+ You can send dynamic commands to this node, for example to make it resend output.
94
+ See [Dynamic Commands](./dynamic-commands.md) for details and how to send dynamic commands.
146
95
 
147
- However, it is normally not a big loss, as you can just feed the node with new price data and start from scratch.
148
- :::
149
-
150
- #### replan
96
+ ## Input
151
97
 
152
- By sending this command, you can have the node read the last received prices from the context storage,
153
- and make a plan based on those prices:
98
+ The input is the [common strategy input format](./strategy-input.md)
154
99
 
155
- ```json
156
- "payload": {
157
- "commands": {
158
- "replan": true,
159
- }
160
- }
161
- ```
100
+ ## Output
162
101
 
163
- If the context storage is `file` you can use this to create a new schedule after a restart,
164
- instead of fetching prices again.
102
+ There are three outputs. You use only those you need for your purpose.
165
103
 
166
- ### Config saved in context
104
+ ### Output 1
167
105
 
168
- The nodes config is saved in the nodes context.
169
- If dynamic config is sent as input, this replaces the saved config.
170
- It is the config that is saved in context that is used when calculating.
171
- 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.
106
+ A payload with the value set in config, default `true`, is sent to output 1 whenever the power / switch shall be turned on.
172
107
 
173
- ## Input
108
+ ### Output 2
174
109
 
175
- The input is the [common strategy input format](./strategy-input.md)
110
+ A payload with the value set in config, default `false` is sent to output 2 whenever the power / switch shall be turned off.
176
111
 
177
- ## Output
112
+ ### Output 3
178
113
 
179
114
  When a valid input is received, and the schedule is recalculated, the resulting schedule, as well as some other information, is sent to output 3. You can use this to see the plan and verify that it meets your expectations. You can also use it to display the schedule in any way you like.
180
115
 
@@ -238,6 +173,7 @@ Example of output:
238
173
  "contextStorage": "default",
239
174
  "fromTime": "04",
240
175
  "toTime": "18",
176
+ "hasChanged": false,
241
177
  "hoursOn": "06",
242
178
  "doNotSplit": false,
243
179
  "sendCurrentValueWhenRescheduling": true,
@@ -298,7 +234,10 @@ This is an alternative to fetching new prices and send as input.
298
234
 
299
235
  ### Multiple nodes works together
300
236
 
301
- You can use multiple nodes simultanously, for different periods, if you want more hours on one part of the day than another part, or to make sure there are at least some hours on during each period.
237
+ You can use multiple nodes simultanously, for different periods, for example if you want more hours on one part of the day than another part, or to make sure there are at least some hours on during each period. In this case set up one Lowest Price node for each period and
238
+ combine the output from them into one schedule using the Schedule Merger node:
239
+
240
+ ![Combine two lowest price nodes](../images/combine-two-lowest-price.png)
302
241
 
303
242
  ### Highest price
304
243
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-power-saver",
3
- "version": "3.6.1",
3
+ "version": "4.0.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": {
@@ -21,11 +21,12 @@
21
21
  ],
22
22
  "node-red": {
23
23
  "nodes": {
24
- "power-saver": "src/power-saver.js",
25
24
  "ps-receive-price": "src/receive-price.js",
26
25
  "ps-strategy-best-save": "src/strategy-best-save.js",
27
26
  "ps-strategy-lowest-price": "src/strategy-lowest-price.js",
28
27
  "ps-strategy-heat-capacitor": "src/strategy-heat-capacitor.js",
28
+ "ps-strategy-fixed-schedule": "src/strategy-fixed-schedule.js",
29
+ "ps-schedule-merger": "src/schedule-merger.js",
29
30
  "ps-elvia-config": "src/elvia/elvia-config.js",
30
31
  "ps-elvia-tariff-types": "src/elvia/elvia-tariff-types.js",
31
32
  "ps-elvia-tariff": "src/elvia/elvia-tariff.js",
@@ -50,6 +51,7 @@
50
51
  "@vuepress/plugin-register-components": "^2.0.0-beta.36",
51
52
  "@vuepress/plugin-search": "^2.0.0-beta.38",
52
53
  "@vuepress/utils": "^2.0.0-beta.35",
54
+ "eslint": "^8.25.0",
53
55
  "expect": "^27.5.1",
54
56
  "mocha": "^9.2.0",
55
57
  "node-red": "^2.2.2",
@@ -61,6 +63,7 @@
61
63
  "floating-vue": "^2.0.0-beta.6",
62
64
  "lodash.clonedeep": "^4.5.0",
63
65
  "luxon": "^2.3.1",
66
+ "nano-time": "^1.0.0",
64
67
  "node-fetch": "^2.6.7"
65
68
  }
66
69
  }
@@ -6,7 +6,6 @@
6
6
  name: { value: "Add Elvia Grid Tariff" },
7
7
  elviaConfig: { value: "", type: "ps-elvia-config" },
8
8
  tariffKey: { value: "", required: true },
9
- range: { value: "today", required: true },
10
9
  },
11
10
  inputs: 1,
12
11
  outputs: 1,
@@ -67,7 +66,7 @@
67
66
  </script>
68
67
 
69
68
  <script type="text/markdown" data-help-name="ps-elvia-add-tariff">
70
- # Elvia Add Tariff (deprecated)
69
+ # Elvia Add Tariff
71
70
 
72
71
  A node to get the tariff from Elvia and add it to the price before it is sent to the power saver strategy nodes.
73
72
  Use this node between the receive-price node and any of the strategy nodes.
@@ -8,7 +8,6 @@ module.exports = function (RED) {
8
8
  this.elviaConfig = RED.nodes.getNode(config.elviaConfig);
9
9
  const key = this.elviaConfig.credentials.elviaSubscriptionKey;
10
10
  this.tariffKey = config.tariffKey;
11
- this.range = config.range;
12
11
  const node = this;
13
12
  ping(node, key);
14
13
 
@@ -30,10 +29,9 @@ module.exports = function (RED) {
30
29
 
31
30
  getTariffForPeriod(node, key, node.tariffKey, fromTime, toTime).then((json) => {
32
31
  const tariff = json;
33
- const priceInfo = tariff.gridTariff.tariffPrice.hours;
32
+ const priceInfo = tariff.gridTariff?.tariffPrice?.hours || [];
34
33
  if (priceInfo.length !== prices.length) {
35
34
  node.warn(`Elvia tariff count mismatch. Expected ${prices.length} items, but got ${priceInfo.length}`);
36
- node.status({ fill: "red", shape: "dot", text: "Tariff error" });
37
35
  } else {
38
36
  prices.forEach((p, i) => {
39
37
  p.powerPrice = p.value;
@@ -38,7 +38,14 @@ function get(node, subscriptionKey, url, setResultStatus) {
38
38
  if (setResultStatus && node) {
39
39
  setNodeStatus(node, res.status);
40
40
  }
41
+ if (res.status === 500) {
42
+ console.error("Elvia internal server error (status 500)");
43
+ return;
44
+ }
41
45
  return res.json().then((json) => {
46
+ if (json.statusCode === 401) {
47
+ console.error("Elvia API error: " + json.message);
48
+ }
42
49
  return json;
43
50
  });
44
51
  });
@@ -51,6 +58,8 @@ function setNodeStatus(node, status) {
51
58
  node.status({ fill: "red", shape: "dot", text: "Unauthorized" });
52
59
  } else if (status === 403) {
53
60
  node.status({ fill: "red", shape: "dot", text: "Forbidden" });
61
+ } else if (status === 500) {
62
+ node.status({ fill: "red", shape: "dot", text: "Elvia server error" });
54
63
  }
55
64
  }
56
65