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.
- package/.eslintrc.js +15 -0
- package/docs/.vuepress/components/DonateButtons.vue +26 -3
- package/docs/.vuepress/components/VippsPlakat.vue +20 -0
- package/docs/.vuepress/config.js +18 -10
- package/docs/.vuepress/public/ads.txt +1 -0
- package/docs/README.md +4 -4
- package/docs/changelog/README.md +59 -1
- package/docs/contribute/README.md +8 -3
- package/docs/examples/README.md +2 -0
- package/docs/examples/example-grid-tariff-capacity-flow.json +1142 -0
- package/docs/examples/example-grid-tariff-capacity-part.md +988 -107
- package/docs/faq/README.md +1 -1
- package/docs/faq/best-save-viewer.md +1 -1
- package/docs/guide/README.md +20 -5
- package/docs/images/best-save-config.png +0 -0
- package/docs/images/combine-two-lowest-price.png +0 -0
- package/docs/images/example-capacity-flow.png +0 -0
- package/docs/images/fixed-schedule-config.png +0 -0
- package/docs/images/global-context-window.png +0 -0
- package/docs/images/lowest-price-config.png +0 -0
- package/docs/images/node-ps-schedule-merger.png +0 -0
- package/docs/images/node-ps-strategy-fixed-schedule.png +0 -0
- package/docs/images/ps-strategy-fixed-schedule-example.png +0 -0
- package/docs/images/schedule-merger-config.png +0 -0
- package/docs/images/schedule-merger-example-1.png +0 -0
- package/docs/images/vipps-plakat.png +0 -0
- package/docs/images/vipps-qr.png +0 -0
- package/docs/images/vipps-smiling-rgb-orange-pos.png +0 -0
- package/docs/nodes/README.md +12 -6
- package/docs/nodes/dynamic-commands.md +79 -0
- package/docs/nodes/dynamic-config.md +76 -0
- package/docs/nodes/ps-elvia-add-tariff.md +4 -0
- package/docs/nodes/ps-general-add-tariff.md +10 -0
- package/docs/nodes/ps-receive-price.md +2 -1
- package/docs/nodes/ps-schedule-merger.md +227 -0
- package/docs/nodes/ps-strategy-best-save.md +46 -110
- package/docs/nodes/ps-strategy-fixed-schedule.md +101 -0
- package/docs/nodes/ps-strategy-heat-capacitor.md +6 -1
- package/docs/nodes/ps-strategy-lowest-price.md +51 -112
- package/package.json +5 -2
- package/src/elvia/elvia-add-tariff.html +1 -2
- package/src/elvia/elvia-add-tariff.js +1 -3
- package/src/elvia/elvia-api.js +9 -0
- package/src/elvia/elvia-tariff.html +1 -1
- package/src/general-add-tariff.html +14 -8
- package/src/general-add-tariff.js +0 -1
- package/src/handle-input.js +94 -106
- package/src/handle-output.js +109 -0
- package/src/receive-price-functions.js +3 -3
- package/src/schedule-merger-functions.js +98 -0
- package/src/schedule-merger.html +135 -0
- package/src/schedule-merger.js +108 -0
- package/src/strategy-best-save.html +38 -1
- package/src/strategy-best-save.js +17 -63
- package/src/strategy-fixed-schedule.html +339 -0
- package/src/strategy-fixed-schedule.js +84 -0
- package/src/strategy-functions.js +35 -0
- package/src/strategy-lowest-price.html +76 -38
- package/src/strategy-lowest-price.js +16 -35
- package/src/utils.js +75 -2
- package/test/commands-input-best-save.test.js +142 -0
- package/test/commands-input-lowest-price.test.js +149 -0
- package/test/commands-input-schedule-merger.test.js +128 -0
- package/test/data/best-save-overlap-result.json +5 -1
- package/test/data/best-save-result.json +4 -0
- package/test/data/commands-result-best-save.json +383 -0
- package/test/data/commands-result-lowest-price.json +340 -0
- package/test/data/fixed-schedule-result.json +353 -0
- package/test/data/lowest-price-result-cont-max-fail.json +5 -1
- package/test/data/lowest-price-result-cont-max.json +3 -1
- package/test/data/lowest-price-result-cont.json +8 -1
- package/test/data/lowest-price-result-missing-end.json +8 -3
- package/test/data/lowest-price-result-neg-cont.json +27 -0
- package/test/data/lowest-price-result-neg-split.json +23 -0
- package/test/data/lowest-price-result-split-allday.json +3 -1
- package/test/data/lowest-price-result-split-allday10.json +1 -0
- package/test/data/lowest-price-result-split-max.json +3 -1
- package/test/data/lowest-price-result-split.json +3 -1
- package/test/data/merge-schedule-data.js +238 -0
- package/test/data/negative-prices.json +197 -0
- package/test/data/nordpool-event-prices.json +96 -480
- package/test/data/nordpool-zero-prices.json +90 -0
- package/test/data/reconfigResult.js +1 -0
- package/test/data/result.js +1 -0
- package/test/data/tibber-result-end-0-24h.json +12 -2
- package/test/data/tibber-result-end-0.json +12 -2
- package/test/data/tibber-result.json +1 -0
- package/test/receive-price.test.js +22 -0
- package/test/schedule-merger-functions.test.js +101 -0
- package/test/schedule-merger-test-utils.js +27 -0
- package/test/schedule-merger.test.js +130 -0
- package/test/send-config-input.test.js +45 -2
- package/test/strategy-best-save-test-utils.js +1 -1
- package/test/strategy-best-save.test.js +45 -0
- package/test/strategy-fixed-schedule.test.js +117 -0
- package/test/strategy-heat-capacitor.test.js +1 -1
- package/test/strategy-lowest-price-functions.test.js +1 -1
- package/test/strategy-lowest-price-test-utils.js +31 -0
- package/test/strategy-lowest-price.test.js +55 -45
- package/test/test-utils.js +43 -36
- package/test/utils.test.js +13 -0
- package/docs/images/node-power-saver.png +0 -0
- package/docs/nodes/power-saver.md +0 -23
- package/src/power-saver.html +0 -116
- package/src/power-saver.js +0 -260
- package/test/commands-input.test.js +0 -47
- 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
|

|
|
@@ -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
|

|
|
16
24
|
|
|
17
|
-
| Value |
|
|
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
|
-
|
|
|
23
|
-
|
|
|
24
|
-
|
|
|
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
|
-
|
|
42
|
+
The following config values can be changed dynamically:
|
|
33
43
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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":
|
|
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
|
+

|
|
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
|
+

|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+

|
|
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
|
-
|
|
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
|

|
|
4
9
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
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
|

|
|
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
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
|
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
|
-
|
|
148
|
-
:::
|
|
149
|
-
|
|
150
|
-
#### replan
|
|
96
|
+
## Input
|
|
151
97
|
|
|
152
|
-
|
|
153
|
-
and make a plan based on those prices:
|
|
98
|
+
The input is the [common strategy input format](./strategy-input.md)
|
|
154
99
|
|
|
155
|
-
|
|
156
|
-
"payload": {
|
|
157
|
-
"commands": {
|
|
158
|
-
"replan": true,
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
```
|
|
100
|
+
## Output
|
|
162
101
|
|
|
163
|
-
|
|
164
|
-
instead of fetching prices again.
|
|
102
|
+
There are three outputs. You use only those you need for your purpose.
|
|
165
103
|
|
|
166
|
-
###
|
|
104
|
+
### Output 1
|
|
167
105
|
|
|
168
|
-
|
|
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
|
-
|
|
108
|
+
### Output 2
|
|
174
109
|
|
|
175
|
-
|
|
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
|
-
|
|
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
|
+

|
|
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
|
+
"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
|
|
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
|
|
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;
|
package/src/elvia/elvia-api.js
CHANGED
|
@@ -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
|
|