node-red-contrib-power-saver 4.0.0 → 4.1.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.
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <div>
3
+ <ins
4
+ v-if="øverst"
5
+ class="adsbygoogle"
6
+ style="display: inline-block; width: 740px; height: 90px"
7
+ data-ad-client="ca-pub-9857859182772006"
8
+ data-ad-slot="7524453641"
9
+ ></ins>
10
+ <ins
11
+ v-if="type === 'nederst'"
12
+ class="adsbygoogle"
13
+ style="display: block"
14
+ data-ad-client="ca-pub-9857859182772006"
15
+ data-ad-slot="3584713798"
16
+ data-ad-format="auto"
17
+ data-full-width-responsive="true"
18
+ ></ins>
19
+ <ins
20
+ v-if="type === 'artikkel'"
21
+ class="adsbygoogle"
22
+ style="display: block; text-align: center"
23
+ data-ad-layout="in-article"
24
+ data-ad-format="fluid"
25
+ data-ad-client="ca-pub-9857859182772006"
26
+ data-ad-slot="3152349396"
27
+ ></ins>
28
+ </div>
29
+ </template>
30
+
31
+ <script setup>
32
+ import { onMounted } from "vue";
33
+
34
+ const props = defineProps({
35
+ type: { type: String, required: false, default: "artikkel" },
36
+ });
37
+ onMounted(() => {
38
+ (adsbygoogle = window.adsbygoogle || []).push({});
39
+ });
40
+ </script>
package/docs/README.md CHANGED
@@ -32,6 +32,8 @@ footer: Created by Otto Paulsen and contributors
32
32
  footerHtml: true
33
33
  ---
34
34
 
35
+ <AdsenseAdd type="artikkel"/>
36
+
35
37
  This is a collection of nodes for the popular [Node-RED](https://nodered.org/) that you can use to save money on variable electricity prices. Node-RED is a widely used low-code programming tool that can be used together with many smart home solutions to create automations.
36
38
 
37
39
  <DonateButtons/>
@@ -7,6 +7,12 @@ sidebarDepth: 1
7
7
 
8
8
  List the most significant changes.
9
9
 
10
+ ## 4.1.0
11
+
12
+ - Fix bug with override function. It did not override longer than until next scheduled change. Now it overrides until set to auto again.
13
+ - Show override on node status.
14
+ - Fix name filter on schedule merger node.
15
+
10
16
  ## 4.0.0
11
17
 
12
18
  This is a major rewrite of some of the central code, in order to lay ground for further development and maintenance.
@@ -50,3 +50,7 @@ Main developer: [Otto Paulsen](https://github.com/ottopaulsen)
50
50
  Heat Capacitor developer: [Arne Klaveness](https://github.com/TomTorger)
51
51
 
52
52
  Example contributors: [Stefan](https://github.com/oakhill87/node-red-contrib-power-saver)
53
+
54
+ ###
55
+
56
+ <AdsenseAdd type="nederst"/>
@@ -1,3 +1,5 @@
1
+ <AdsenseAdd type="øverst"/>
2
+
1
3
  # Examples
2
4
 
3
5
  [Nord Pool and `current state` node in HA](./example-nordpool-current-state)
@@ -17,3 +19,7 @@
17
19
  ## User provided examples
18
20
 
19
21
  [Output schedule to a sensor entity](./example-next-schedule-entity.md) (by Stefan)
22
+
23
+ ###
24
+
25
+ <AdsenseAdd type="nederst"/>
@@ -48,3 +48,7 @@ Another alternative is to reduce the minimum saving from 0.05 to 0.001. Then the
48
48
  ## Can we get Legionella bacteria when turning off the water heater?
49
49
 
50
50
  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 to avoid growth of legionella. At this temperature, legionalla bacteria die quickly.
51
+
52
+ ###
53
+
54
+ <AdsenseAdd type="nederst"/>
@@ -15,6 +15,10 @@ Then paste it here and see the result below:
15
15
 
16
16
  <BestSaveVerificator/>
17
17
 
18
+ ###
19
+
20
+ <AdsenseAdd type="artikkel"/>
21
+
18
22
  ## Explanation
19
23
 
20
24
  ### Config
@@ -53,6 +57,10 @@ If the average per hour is less than what you have configured as `Minimum saving
53
57
 
54
58
  If the number is black, it could be used, but only if all other criteria are satisfied, and only if it saves more than any other combination.
55
59
 
60
+ ###
61
+
62
+ <AdsenseAdd type="artikkel"/>
63
+
56
64
  ## Something seems wrong
57
65
 
58
66
  The tool is not using the same code as the node, so in case there is a bug in the node (or in the tool) the numbers may not match.
@@ -31,6 +31,10 @@ Here prices are received from Tibber, converted in the `ps-receive-price` node,
31
31
  The node collection fits very well with Home Assistant (HA), as Node-RED is frequently used for automations, and there also is an integration with Nord Pool, but there is no direct dependency to HA, so all nodes can be used also without HA.
32
32
  :::
33
33
 
34
+ ###
35
+
36
+ <AdsenseAdd type="artikkel"/>
37
+
34
38
  ## Getting started
35
39
 
36
40
  ### Installation
@@ -129,6 +133,10 @@ Data can be sent from both the `current state` node or the `events: state` node.
129
133
 
130
134
  [See example with Nord Pool and `events: state` node](../examples/example-nordpool-events-state.md)
131
135
 
136
+ ###
137
+
138
+ <AdsenseAdd type="artikkel"/>
139
+
132
140
  ### Add grid tariff
133
141
 
134
142
  When also the grid tariff changes per hour, it must be added to the electricity price in order to get the calculations right.
@@ -192,6 +200,10 @@ There are many ways you can use the output:
192
200
  - Send a notification
193
201
  :::
194
202
 
203
+ ###
204
+
205
+ <AdsenseAdd type="artikkel"/>
206
+
195
207
  ### Display schedule
196
208
 
197
209
  **Output 3** can be used to print or display the calculated schedule. If you just want to see it, send it to a debug node. You can also use it to display the result as graphs in HA.
@@ -214,6 +226,10 @@ Se the [Schedule Merger](../nodes/ps-schedule-merger.md) node for more details.
214
226
 
215
227
  There are more details and more information in the documentation for each [node](/nodes/) and in the [examples](/examples/).
216
228
 
229
+ ###
230
+
231
+ <AdsenseAdd type="artikkel"/>
232
+
217
233
  ## Migration from v2
218
234
 
219
235
  The `Power Saver` node from v2 has been removed and must be replaced.
@@ -1,7 +1,13 @@
1
+ <AdsenseAdd type="øverst"/>
2
+
1
3
  # Nodes
2
4
 
3
5
  Here is an overview of the nodes, and links to detailed descriptions for eah of them.
4
6
 
7
+ ###
8
+
9
+ <AdsenseAdd type="artikkel"/>
10
+
5
11
  ## Strategy nodes
6
12
 
7
13
  These are the nodes used to calculate and control saving.
@@ -30,6 +36,10 @@ A strategy for moving consumption from expensive to cheap periods utilizing clim
30
36
 
31
37
  A strategy for setting a fixed daily or weekly schedule.
32
38
 
39
+ ###
40
+
41
+ <AdsenseAdd type="artikkel"/>
42
+
33
43
  ## Utility nodes
34
44
 
35
45
  ### [ps-receive-price](./ps-receive-price)
@@ -69,3 +79,7 @@ Use this to get a list of the tariff types available in the Elvia API.
69
79
  ### ps-elvia-tariff
70
80
 
71
81
  Use this to get the Elvia grid tariff for a selected tariff type.
82
+
83
+ ###
84
+
85
+ <AdsenseAdd type="nederst"/>
@@ -1,3 +1,7 @@
1
+ ###
2
+
3
+ <AdsenseAdd type="øverst"/>
4
+
1
5
  # Dynamic commands
2
6
 
3
7
  You can dynamically send some commands to the node via its input, by using a `commands` object in the payload as described below.
@@ -39,6 +43,10 @@ You can get the node to send the current output to output 1 or 2 any time by sen
39
43
 
40
44
  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.
41
45
 
46
+ ###
47
+
48
+ <AdsenseAdd type="artikkel"/>
49
+
42
50
  ### reset
43
51
 
44
52
  You can reset data the node has saved in context by sending this message:
@@ -77,3 +85,7 @@ and make a plan based on those prices:
77
85
 
78
86
  If the context storage is `file` you can use this to create a new schedule after a restart,
79
87
  instead of fetching prices again.
88
+
89
+ ###
90
+
91
+ <AdsenseAdd type="nederst"/>
@@ -31,6 +31,10 @@ to be able to override a specific strategy node.
31
31
  The `name` is the exact same value as you set as name in the nodes config.
32
32
  :::
33
33
 
34
+ ###
35
+
36
+ <AdsenseAdd type="artikkel"/>
37
+
34
38
  ## Output values
35
39
 
36
40
  Valid values for `outputValueForOntype` and `outputValueForOfftype` are `bool`, `num` and `str` and must correspond
@@ -74,3 +78,7 @@ The nodes config is saved in the nodes context.
74
78
  If dynamic config is sent as input, this replaces the saved config.
75
79
  It is the config that is saved in context that is used when calculating.
76
80
  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.
81
+
82
+ ###
83
+
84
+ <AdsenseAdd type="nederst"/>
@@ -229,3 +229,7 @@ See [CHANGELOG.md](CHANGELOG.md)
229
229
  ## Contribute
230
230
 
231
231
  Contributions are welcome. Please start by creating a Github Issue with suggested changes, and state what you would like to do.
232
+
233
+ ###
234
+
235
+ <AdsenseAdd type="nederst"/>
@@ -12,6 +12,10 @@ Node to add grid tariff from Elvia.
12
12
  You need an Elvia API subscription key to use this node. See [configuration](#elvia-configuration).
13
13
  :::
14
14
 
15
+ ###
16
+
17
+ <AdsenseAdd type="artikkel"/>
18
+
15
19
  ## Description
16
20
 
17
21
  When grid tariff changes from hour to hour, this should normally also be considered when finding the most favorable hours to use power. This node retrieves prices from Elvia, so if you are an elvia customer, you can put this node between the `ps-receive-price` node and the strategy nodes. When configured, it will add Elvia tariff to the power prices before doing the calculation:
@@ -47,6 +51,10 @@ Now you should be able to select the right tariff:
47
51
 
48
52
  The next time you use this node, you can select the same config as you created the first time, and then you can also select tariff immediately.
49
53
 
54
+ ###
55
+
56
+ <AdsenseAdd type="artikkel"/>
57
+
50
58
  ## Input
51
59
 
52
60
  The input is the [common strategy input format](./strategy-input.md)
@@ -54,3 +62,7 @@ The input is the [common strategy input format](./strategy-input.md)
54
62
  ## Output
55
63
 
56
64
  The output is the [common strategy input format](./strategy-input.md)
65
+
66
+ ###
67
+
68
+ <AdsenseAdd type="nederst"/>
@@ -9,6 +9,10 @@ next: ./ps-elvia-add-tariff.md
9
9
 
10
10
  Node to add a value, for example a variable grid tariff, to the price before it is used to calculate savings in the strategy nodes.
11
11
 
12
+ ###
13
+
14
+ <AdsenseAdd type="artikkel"/>
15
+
12
16
  ## Description
13
17
 
14
18
  This node is useful if there is an addition to the electricity price that varies over the day or the week, as it might be for the grid tariff.
@@ -64,6 +68,10 @@ Fill in the last date the config is valid.
64
68
 
65
69
  If this is empty, the config is valid until forever.
66
70
 
71
+ ###
72
+
73
+ <AdsenseAdd type="artikkel"/>
74
+
67
75
  ## Input
68
76
 
69
77
  The input is the [common strategy input format](./strategy-input.md)
@@ -73,3 +81,7 @@ The input is the [common strategy input format](./strategy-input.md)
73
81
  The output is the [common strategy input format](./strategy-input.md)
74
82
 
75
83
  If there is a config property in the input payload, it is passed on to the output payload.
84
+
85
+ ###
86
+
87
+ <AdsenseAdd type="nederst"/>
@@ -27,6 +27,10 @@ That is why this is now a separate node.
27
27
 
28
28
  There is no configuration except from node name.
29
29
 
30
+ ###
31
+
32
+ <AdsenseAdd type="artikkel"/>
33
+
30
34
  ## Input
31
35
 
32
36
  ### Tibber input
@@ -120,6 +124,10 @@ Then use the id in the following query, replacing the id with the one you found
120
124
 
121
125
  This is the query you shall put in the `tibber-query` node.
122
126
 
127
+ ###
128
+
129
+ <AdsenseAdd type="artikkel"/>
130
+
123
131
  ### Nord Pool input
124
132
 
125
133
  This is especially designed to work for Home Assistant (HA), and the [Nord Pool custom component](https://github.com/custom-components/nordpool). The Nord Pool component provides a _sensor_ that gives price per hour for today and tomorrow (after 13:00). Send the output from this sensor directly to the `ps-receive-price` node. Make sure this is done whenever the node is updated, as well as when the system starts up.
@@ -156,3 +164,7 @@ If you cannot use any of the two above (Tibber or Nord Pool), create the input t
156
164
  ## Output
157
165
 
158
166
  The output is the [common strategy input format](./strategy-input.md), so it can be sent directly to the strategy nodes, or via any `ps-xxx-add-tariff` node.
167
+
168
+ ###
169
+
170
+ <AdsenseAdd type="nederst"/>
@@ -55,6 +55,10 @@ the schedule from for example the Lowest Price node, using the Schedule Merger n
55
55
  | 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. |
56
56
  | 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. |
57
57
 
58
+ ###
59
+
60
+ <AdsenseAdd type="artikkel"/>
61
+
58
62
  ### Dynamic config
59
63
 
60
64
  The following config values can be changed dynamically:
@@ -37,6 +37,10 @@ The picture at the bottom of the page, under [Integration with MagicMirror](#int
37
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.
38
38
  :::
39
39
 
40
+ ###
41
+
42
+ <AdsenseAdd type="artikkel"/>
43
+
40
44
  ### Dynamic config
41
45
 
42
46
  The following config values can be changed dynamically:
@@ -91,6 +95,10 @@ A payload with the value set in config, default `false` is sent to output 2 when
91
95
 
92
96
  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.
93
97
 
98
+ ###
99
+
100
+ <AdsenseAdd type="artikkel"/>
101
+
94
102
  Example of output:
95
103
 
96
104
  ```json
@@ -155,6 +163,10 @@ The `schedule` and the `hours` arrays from Output 3 are both saved to the nodes
155
163
 
156
164
  You can see the saved data if you select the node in Node-RED, and view "Context data", and refresh the Node context.
157
165
 
166
+ ###
167
+
168
+ <AdsenseAdd type="artikkel"/>
169
+
158
170
  ## Algorithm
159
171
 
160
172
  The calculation that decides what hours to turn off works as follows:
@@ -216,6 +228,10 @@ and set `msg.payload` to the following JSON value:
216
228
 
217
229
  This is an alternative to fetching new prices and send as input.
218
230
 
231
+ ###
232
+
233
+ <AdsenseAdd type="artikkel"/>
234
+
219
235
  ## Integration with MagicMirror
220
236
 
221
237
  Are you using [MagicMirror](https://magicmirror.builders/)? Are you also using [Tibber](https://tibber.com/)? If so, there is a module for MM called [MMM-Tibber](https://github.com/ottopaulsen/MMM-Tibber), that easily can be used to show savings from this node.
@@ -229,3 +245,7 @@ Read more about this in the [MMM-Tibber documentation](https://github.com/ottopa
229
245
  ## Viewer
230
246
 
231
247
  If you like to analyze the data output by the node, take a look at the [Best Save Viewer](../faq/best-save-viewer.md).
248
+
249
+ ###
250
+
251
+ <AdsenseAdd type="nederst"/>
@@ -39,6 +39,10 @@ Here is an example of how to combine it with the Lowest Price node:
39
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
40
  | Context storage | Select context storage to save data to, if more than one is configured in the Node-RED `settings.js` file. |
41
41
 
42
+ ###
43
+
44
+ <AdsenseAdd type="artikkel"/>
45
+
42
46
  ### Dynamic config
43
47
 
44
48
  The following config values can be changed dynamically:
@@ -91,6 +95,10 @@ When a valid input is received, and the schedule is recalculated, the resulting
91
95
 
92
96
  The aoutput is similar to the output from the other strategy nodes.
93
97
 
98
+ ###
99
+
100
+ <AdsenseAdd type="artikkel"/>
101
+
94
102
  ## Usage ideas
95
103
 
96
104
  ### Turn on every morning
@@ -99,3 +107,7 @@ If you want to make sure that a switch is turned on at least 2 hours every morni
99
107
  even if you are using the Lowest Price node to turn it on only the 4 cheapest hours during
100
108
  the whole day, you can use this node to make sure it is on this period, and then merge it with the
101
109
  Lowest Price schedule using the Schedule Merger node with the `OR` function.
110
+
111
+ ###
112
+
113
+ <AdsenseAdd type="nederst"/>
@@ -37,6 +37,10 @@ It is a good application for cabins/heated storage spaces, as the entity never a
37
37
 
38
38
  The node consumes price information and outputs $\Delta T$ on its first output and the planned schedule and benefit calculations on the second output. The $\Delta T$ is used to adjust the set-point of a climate entity.
39
39
 
40
+ ###
41
+
42
+ <AdsenseAdd type="artikkel"/>
43
+
40
44
  ### The impact of **Time +1C**
41
45
 
42
46
  This time is used to optimize the timing of when to turn up the heat. An increase in temperature from 22 to 23C will cause an increased electricity consumption for quite some time after the change has occurred. For heat-pumps, the air is heated first, then walls, furniture etc., creating a high electricity demand in the first hour or so before the demand slowly reduces down to normal levels. The algorithm uses this time to estimate a period of increased consumption and places this at an optimum point in time.
@@ -349,3 +353,7 @@ Full example:
349
353
  ]
350
354
  }
351
355
  ```
356
+
357
+ ###
358
+
359
+ <AdsenseAdd type="nederst"/>
@@ -64,6 +64,10 @@ If `Consecutive on period` is on (checked), hours will be turned on only if the
64
64
  If you leave `Max price` blank, it has no effect.
65
65
  :::
66
66
 
67
+ ###
68
+
69
+ <AdsenseAdd type="artikkel"/>
70
+
67
71
  ### Dynamic config
68
72
 
69
73
  The following config values can be changed dynamically:
@@ -113,6 +117,10 @@ A payload with the value set in config, default `false` is sent to output 2 when
113
117
 
114
118
  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.
115
119
 
120
+ ###
121
+
122
+ <AdsenseAdd type="artikkel"/>
123
+
116
124
  Example of output:
117
125
 
118
126
  ```json
@@ -246,3 +254,7 @@ If you want to find the `x` hours with the highest prices, do as follows:
246
254
  1. Calculate `y` as the total number of hours in the period. For example, if the period is from `08:00` to `20:00`, then `y = 12`.
247
255
  2. Configure `Hours On = y - x`, so if `x = 4`, then `Hours On = 12 - 4 = 8`.
248
256
  3. Use **Output 2** to get a signal when you have the hours with the highest prices. Just remember that the value sent to output 2 is `false`, not `true` as it is on output 1.
257
+
258
+ ###
259
+
260
+ <AdsenseAdd type="nederst"/>
@@ -37,3 +37,7 @@ This format is used for:
37
37
  - Output of the `ps-receive-price` node
38
38
  - Input and output of the `ps-xxx-add-tariff` nodes
39
39
  - Input for the strategy nodes (`ps-strategy-xxx-xxx`)
40
+
41
+ ###
42
+
43
+ <AdsenseAdd type="nederst"/>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-power-saver",
3
- "version": "4.0.0",
3
+ "version": "4.1.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": {
@@ -86,6 +86,9 @@ function makePlanFromPriceData(node, msg, config, doPlanning, calcSavings) {
86
86
  function getCommands(msg) {
87
87
  const legalCommands = ["reset", "replan", "sendOutput", "sendSchedule"];
88
88
  const commands = { legal: true };
89
+ if (msg.payload?.config?.override === "auto") {
90
+ commands.runSchedule = true;
91
+ }
89
92
  if (!msg?.payload?.commands) {
90
93
  return commands;
91
94
  }
@@ -13,6 +13,9 @@ function handleOutput(node, config, plan, outputCommands, planFromTime) {
13
13
 
14
14
  */
15
15
 
16
+ // Clear status
17
+ node.status({});
18
+
16
19
  // Prepare output
17
20
  let output3 = {
18
21
  payload: {
@@ -44,10 +47,15 @@ function handleOutput(node, config, plan, outputCommands, planFromTime) {
44
47
  }
45
48
 
46
49
  // Run schedule
50
+ clearTimeout(node.schedulingTimeout);
47
51
  if (outputCommands.runSchedule) {
48
- clearTimeout(node.schedulingTimeout);
49
52
  node.schedulingTimeout = runSchedule(node, plan.schedule, planFromTime, true);
50
53
  }
54
+
55
+ // Set status if override
56
+ if (config.override !== "auto") {
57
+ node.status({ fill: "yellow", shape: "dot", text: "Override " + config.override });
58
+ }
51
59
  }
52
60
 
53
61
  function sendSwitch(node, onOff) {
@@ -45,6 +45,10 @@ module.exports = function (RED) {
45
45
  });
46
46
 
47
47
  node.on("input", function (msg) {
48
+ if (msg.payload?.name && msg.payload.name !== node.name) {
49
+ // If payload.name is set, and does not match this nodes name, discard message
50
+ return;
51
+ }
48
52
  if (msg.payload.hours) {
49
53
  // Delete config from strategy nodes so it does not merge
50
54
  // with config for this node.
@@ -100,7 +104,7 @@ module.exports = function (RED) {
100
104
 
101
105
  handleOutput(node, config, plan, outputCommands, planFromTime);
102
106
  },
103
- commands.replan ? 0 : node.schedulingDelay
107
+ commands.replan || msg.payload.config ? 0 : node.schedulingDelay
104
108
  );
105
109
  });
106
110
  }
@@ -26,7 +26,7 @@ function strategyOnInput(node, msg, doPlanning, calcSavings) {
26
26
  node.sendCurrentValueWhenRescheduling
27
27
  ),
28
28
  sendSchedule: strategyShallSendSchedule(msg, commands),
29
- runSchedule: commands.replan !== false,
29
+ runSchedule: commands.replan !== false && config.override === "auto",
30
30
  };
31
31
  handleOutput(node, config, plan, outputCommands, planFromTime);
32
32
  }
@@ -115,6 +115,7 @@ describe("send config as input", () => {
115
115
  });
116
116
  it("can override", function (done) {
117
117
  const flow = makeFlow(3, 2, false);
118
+ const time = prices.priceData[0].start;
118
119
  helper.load(bestSave, flow, function () {
119
120
  const n1 = helper.getNode("n1");
120
121
  const n2 = helper.getNode("n2");
@@ -131,6 +132,7 @@ describe("send config as input", () => {
131
132
  console.log("countOn = " + countOn + ", countOff = " + countOff);
132
133
  expect(countOn).toEqual(2);
133
134
  expect(countOff).toEqual(2);
135
+ n1.status.should.be.calledWithExactly({ fill: "yellow", shape: "dot", text: "Override on" });
134
136
  done();
135
137
  }, 900);
136
138
  }
@@ -139,20 +141,19 @@ describe("send config as input", () => {
139
141
  countOn++;
140
142
  expect(msg).toHaveProperty("payload", true);
141
143
  if (countOn === 2) {
142
- n1.receive({ payload: { config: { override: "on" } } });
144
+ n1.receive({ payload: { config: { override: "on" }, time } });
143
145
  }
144
146
  });
145
147
  n4.on("input", function (msg) {
146
148
  countOff++;
147
149
  expect(msg).toHaveProperty("payload", false);
148
150
  if (countOff === 1) {
149
- n1.receive({ payload: { config: { override: "on" }, name: "wrong name" } });
151
+ n1.receive({ payload: { config: { override: "on" }, name: "wrong name" }, time });
150
152
  }
151
153
  if (countOff === 2) {
152
- n1.receive({ payload: { config: { override: "on" } } });
154
+ n1.receive({ payload: { config: { override: "on" }, time } });
153
155
  }
154
156
  });
155
- const time = prices.priceData[0].start;
156
157
  n1.receive({ payload: makePayload(prices, time) });
157
158
  });
158
159
  });
@@ -96,6 +96,7 @@ describe("ps-strategy-best-save node", function () {
96
96
  n1.receive({ payload: makePayload(prices, plan.time) });
97
97
  });
98
98
  });
99
+
99
100
  it("should not send output when rescheduling", function (done) {
100
101
  const flow = makeFlow(3, 2, false);
101
102
  helper.load(bestSave, flow, function () {
@@ -140,6 +141,51 @@ describe("ps-strategy-best-save node", function () {
140
141
  n1.receive({ payload });
141
142
  });
142
143
  });
144
+
145
+ it("should handle override", function (done) {
146
+ const flow = makeFlow(3, 2);
147
+ const expected = cloneDeep(result);
148
+ expected.version = version;
149
+ expected.time = plan.time;
150
+ expected.source = "Tibber";
151
+ expected.current = false;
152
+ let timeoutSet = false;
153
+ helper.load(bestSave, flow, function () {
154
+ const n1 = helper.getNode("n1");
155
+ const n2 = helper.getNode("n2");
156
+ const n3 = helper.getNode("n3");
157
+ const n4 = helper.getNode("n4");
158
+ let countOn = 0;
159
+ let countOff = 0;
160
+ n2.on("input", function (msg) {
161
+ expect(equalPlan(expected, msg.payload)).toBeTruthy();
162
+ n1.warn.should.not.be.called;
163
+ if (!timeoutSet) {
164
+ timeoutSet = true;
165
+ setTimeout(() => {
166
+ console.log("countOn = " + countOn + ", countOff = " + countOff);
167
+ expect(countOn).toEqual(2);
168
+ expect(countOff).toEqual(2);
169
+ done();
170
+ }, 900);
171
+ }
172
+ });
173
+ n3.on("input", function (msg) {
174
+ console.log("on");
175
+ countOn++;
176
+ expect(msg).toHaveProperty("payload", true);
177
+ });
178
+ n4.on("input", function (msg) {
179
+ console.log("off");
180
+ countOff++;
181
+ expect(msg).toHaveProperty("payload", false);
182
+ if (countOff === 2) {
183
+ n1.receive({ payload: { config: { override: "on" }, time: plan.time } });
184
+ }
185
+ });
186
+ n1.receive({ payload: makePayload(prices, plan.time) });
187
+ });
188
+ });
143
189
  });
144
190
 
145
191
  function makePayload(prices, time) {