node-red-contrib-power-saver 3.0.8 → 3.1.1
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/docs/.vuepress/config.js +9 -1
- package/docs/.vuepress/dist/404.html +3 -3
- package/docs/.vuepress/dist/assets/img/add-tariff-flow.eb700d4f.png +0 -0
- package/docs/.vuepress/dist/assets/img/best-save-config.93fa3c21.png +0 -0
- package/docs/.vuepress/dist/assets/img/lowest-price-config.6d66a8c2.png +0 -0
- package/docs/.vuepress/dist/assets/img/next-schedule-entity.4406856a.png +0 -0
- package/docs/.vuepress/dist/assets/img/next-schedule-flow.413ad62b.png +0 -0
- package/docs/.vuepress/dist/assets/img/next-schedule-sensor.eb896bdd.png +0 -0
- package/docs/.vuepress/dist/assets/img/node-ps-general-add-tariff.a3cf6f06.png +0 -0
- package/docs/.vuepress/dist/assets/js/app.8016111b.js +1 -0
- package/docs/.vuepress/dist/assets/js/runtime~app.0da14230.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-0607240a.661e1808.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-08683c60.a6b9cf5b.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-0aca7ba6.b42fad7f.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-0b5e3c8c.34230e16.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-1ad821fa.6e2194d0.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-1e2b191e.50b8fa18.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-30acb564.f2fcd69f.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-4637f9e4.38f66bbb.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-510ed0d4.9f2a81c6.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-5954bcb2.182daf70.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-5db8da3a.f2de6cb9.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-61f728ca.6fdbbb92.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-677dfaed.0013f083.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-7446a652.d05e2648.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-7c87f26e.1127dcf5.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-8daa1a0e.dde202c9.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-b4a42144.9e5f9728.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-e8c55052.8384b053.js +1 -0
- package/docs/.vuepress/dist/assets/js/v-fffb8e28.3406fd88.js +1 -0
- package/docs/.vuepress/dist/changelog/index.html +3 -3
- package/docs/.vuepress/dist/contribute/index.html +3 -3
- package/docs/.vuepress/dist/examples/example-next-schedule-entity.html +25 -0
- package/docs/.vuepress/dist/examples/example-nordpool-current-state.html +176 -156
- package/docs/.vuepress/dist/examples/example-nordpool-events-state.html +4 -4
- package/docs/.vuepress/dist/examples/example-tibber-mqtt.html +4 -4
- package/docs/.vuepress/dist/examples/index.html +3 -3
- package/docs/.vuepress/dist/faq/index.html +15 -0
- package/docs/.vuepress/dist/guide/index.html +4 -4
- package/docs/.vuepress/dist/index.html +3 -3
- package/docs/.vuepress/dist/logo.png +0 -0
- package/docs/.vuepress/dist/nodes/index.html +3 -3
- package/docs/.vuepress/dist/nodes/old-power-saver-doc.html +5 -5
- package/docs/.vuepress/dist/nodes/power-saver.html +3 -3
- package/docs/.vuepress/dist/nodes/ps-elvia-add-tariff.html +3 -3
- package/docs/.vuepress/dist/nodes/ps-general-add-tariff.html +15 -0
- package/docs/.vuepress/dist/nodes/ps-receive-price.html +6 -6
- package/docs/.vuepress/dist/nodes/ps-strategy-best-save.html +4 -4
- package/docs/.vuepress/dist/nodes/ps-strategy-lowest-price.html +4 -4
- package/docs/.vuepress/dist/nodes/strategy-input.html +4 -4
- package/docs/.vuepress/public/logo.png +0 -0
- package/docs/README.md +7 -5
- package/docs/changelog/README.md +22 -5
- package/docs/contribute/README.md +1 -1
- package/docs/examples/README.md +4 -0
- package/docs/examples/example-next-schedule-entity.md +41 -0
- package/docs/examples/example-nordpool-current-state.md +172 -152
- package/docs/faq/README.md +23 -0
- package/docs/guide/README.md +16 -15
- package/docs/images/add-tariff-flow.png +0 -0
- package/docs/images/logo copy.png +0 -0
- package/docs/images/logo.png +0 -0
- package/docs/images/logo.psd +0 -0
- package/docs/images/mysterious-plan.png +0 -0
- package/docs/images/next-schedule-entity.png +0 -0
- package/docs/images/next-schedule-flow.png +0 -0
- package/docs/images/next-schedule-sensor.png +0 -0
- package/docs/images/node-ps-general-add-tariff.png +0 -0
- package/docs/images/node-red-icon-2.svg +30 -0
- package/docs/nodes/README.md +6 -0
- package/docs/nodes/old-power-saver-doc.md +6 -6
- package/docs/nodes/ps-elvia-add-tariff.md +1 -1
- package/docs/nodes/ps-general-add-tariff.md +49 -0
- package/docs/nodes/ps-receive-price.md +9 -5
- package/docs/nodes/ps-strategy-best-save.md +5 -1
- package/docs/nodes/ps-strategy-lowest-price.md +3 -3
- package/docs/nodes/strategy-input.md +1 -1
- package/package.json +3 -2
- package/src/elvia/elvia-add-tariff.js +7 -6
- package/src/general-add-tariff-functions.js +46 -0
- package/src/general-add-tariff.html +186 -0
- package/src/general-add-tariff.js +35 -0
- package/src/handle-input.js +1 -1
- package/src/power-saver.js +1 -1
- package/src/receive-price-functions.js +8 -0
- package/src/strategy-lowest-price.js +6 -6
- package/test/data/nordpool-3-days-prices.json +293 -0
- package/test/data/nordpool-3-days-result.json +444 -0
- package/test/data/nordpool-prices-in-payload.json +287 -0
- package/test/elvia.test.js +16 -2
- package/test/general-add-tariff-functions.test.js +104 -0
- package/test/general-add-tariff.test.js +183 -0
- package/test/receive-price.test.js +22 -0
- package/test/strategy-lowest-price-3days.test.js +88 -0
- package/docs/.vuepress/dist/assets/js/app.8ccc81e3.js +0 -1
- package/docs/.vuepress/dist/assets/js/runtime~app.7653fe7e.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-08683c60.07fe8291.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-0aca7ba6.aec5ba75.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-0b5e3c8c.d008d8bc.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-1ad821fa.85407071.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-30acb564.73b8e29f.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-4637f9e4.22ab9413.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-510ed0d4.e5215a83.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-5954bcb2.be07962c.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-5db8da3a.ac192f35.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-61f728ca.802ab15e.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-677dfaed.9bbbd037.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-7c87f26e.457a1a60.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-8daa1a0e.db8b59c6.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-b4a42144.6e0c5aa0.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-e8c55052.5f85b6cd.js +0 -1
- package/docs/.vuepress/dist/assets/js/v-fffb8e28.e815e852.js +0 -1
package/docs/guide/README.md
CHANGED
|
@@ -6,8 +6,10 @@ sidebar: "auto"
|
|
|
6
6
|
|
|
7
7
|
## Introduction
|
|
8
8
|
|
|
9
|
-
This is a collection of nodes you can use to save money on variable
|
|
10
|
-
|
|
9
|
+
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.
|
|
10
|
+
|
|
11
|
+
The solution can be used to control switches or other entities in a smart home system, and for example turn on when the price is low, and turn off when the price is high.
|
|
12
|
+
There are different ways to calculate what hours to turn on and off, and these are implemented as **strategies nodes**. Each strategy node can be configured to fit different purposes.
|
|
11
13
|
|
|
12
14
|
The strategies need price data to work. These can be received from different sources, for example Tibber, Nord Pool or custom sources.
|
|
13
15
|
|
|
@@ -23,7 +25,7 @@ Example:
|
|
|
23
25
|
|
|
24
26
|

|
|
25
27
|
|
|
26
|
-
Here prices are received from Tibber, converted in the `ps-receive-price` node, then
|
|
28
|
+
Here prices are received from Tibber, converted in the `ps-receive-price` node, then grid tariff for Elvia is added before sent to the `ps-strategy-best-save` node. Output is sent to Home Assistant via two `call-service` nodes, and the schedule is sent to a debug node.
|
|
27
29
|
|
|
28
30
|
::: tip Home Assistant
|
|
29
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.
|
|
@@ -48,7 +50,7 @@ This solution is useless without price data. In the nordics, there are at least
|
|
|
48
50
|
- Tibber
|
|
49
51
|
- Nord Pool
|
|
50
52
|
|
|
51
|
-
The `ps-receive-price` node is designed to handle price input
|
|
53
|
+
The `ps-receive-price` node is designed to handle price input from both these, and convert it to the format required by the strategy nodes.
|
|
52
54
|
|
|
53
55
|
If you are a Tibber customer, use the `tibber-query` node from the [Tibber API](https://flows.nodered.org/node/node-red-contrib-tibber-api) to receive price, with one of the following queries:
|
|
54
56
|
|
|
@@ -75,7 +77,7 @@ If you are a Tibber customer, use the `tibber-query` node from the [Tibber API](
|
|
|
75
77
|
|
|
76
78
|
</CodeGroupItem>
|
|
77
79
|
|
|
78
|
-
<CodeGroupItem title="
|
|
80
|
+
<CodeGroupItem title="Single home" active>
|
|
79
81
|
|
|
80
82
|
```gql{3}
|
|
81
83
|
{
|
|
@@ -120,21 +122,20 @@ If you use Home Assistant (HA), you can install the
|
|
|
120
122
|
that provides a _sensor_ that gives price per hour for today and tomorrow.
|
|
121
123
|
Data can be sent from both the `current state` node or the `events: state` node.
|
|
122
124
|
|
|
123
|
-
[See example with
|
|
125
|
+
[See example with Nord Pool and `current state` node](../examples/example-nordpool-current-state.md)
|
|
124
126
|
|
|
125
|
-
[See example with
|
|
127
|
+
[See example with Nord Pool and `events: state` node](../examples/example-nordpool-events-state.md)
|
|
126
128
|
|
|
127
129
|
### Add grid tariff
|
|
128
130
|
|
|
129
131
|
When also the grid tariff changes per hour, it must be added to the electricity price in order to get the calculations right.
|
|
130
132
|
|
|
131
|
-
After the the `ps-receive-price` node, add a `ps-xxx-add-tariff` node to add grid tariff. What node to choose depends on what grid you get electricity through. The
|
|
132
|
-
|
|
133
|
-
| Grid supplier | Node |
|
|
134
|
-
| ------------- | --------------------- |
|
|
135
|
-
| Elvia | `ps-elvia-add-tariff` |
|
|
133
|
+
After the the `ps-receive-price` node, add a `ps-xxx-add-tariff` node to add grid tariff. What node to choose depends on what grid you get electricity through. The following grids are supported:
|
|
136
134
|
|
|
137
|
-
|
|
135
|
+
| Grid supplier | Node |
|
|
136
|
+
| ------------- | ----------------------- |
|
|
137
|
+
| General (any) | `ps-general-add-tariff` |
|
|
138
|
+
| Elvia | `ps-elvia-add-tariff` |
|
|
138
139
|
|
|
139
140
|
If your grid is not supported, you may code this yourself.
|
|
140
141
|
|
|
@@ -178,14 +179,14 @@ Example using Home Assistant:
|
|
|
178
179
|
There are many ways you can use the output:
|
|
179
180
|
|
|
180
181
|
- Turn on/off a switch
|
|
181
|
-
- Set a
|
|
182
|
+
- Set a thermostat up, down or to specific values
|
|
182
183
|
- Change setting of a dimmer
|
|
183
184
|
- Send a notification
|
|
184
185
|
:::
|
|
185
186
|
|
|
186
187
|
### Display schedule
|
|
187
188
|
|
|
188
|
-
**Output 3** can be used to print or
|
|
189
|
+
**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.
|
|
189
190
|
|
|
190
191
|
For users of Magic Mirror and Tibber, the `ps-best-save` node can send its schedule to the MMM-Tibber module. See more details in the `ps-best-save` node documentation.
|
|
191
192
|
|
|
Binary file
|
|
Binary file
|
package/docs/images/logo.png
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
3
|
+
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="512" width="512" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 511.99999 511.99999">
|
|
4
|
+
<metadata>
|
|
5
|
+
<rdf:RDF>
|
|
6
|
+
<cc:Work rdf:about="">
|
|
7
|
+
<dc:format>image/svg+xml</dc:format>
|
|
8
|
+
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
|
9
|
+
<dc:title/>
|
|
10
|
+
</cc:Work>
|
|
11
|
+
</rdf:RDF>
|
|
12
|
+
</metadata>
|
|
13
|
+
<g transform="translate(0 -540.36)">
|
|
14
|
+
<rect style="color:#000000" height="392" width="512" y="540.36" x=".000013828" fill="#8f0000"/>
|
|
15
|
+
<rect ry="0" height="108.23" width="500.23" stroke="#fff" y="938.25" x="5.886" stroke-width="11.772" fill="#fff"/>
|
|
16
|
+
<g transform="matrix(4 0 0 4 -162 -450.91)">
|
|
17
|
+
<path style="color-rendering:auto;text-decoration-color:#000000;color:#000000;isolation:auto;mix-blend-mode:normal;shape-rendering:auto;solid-color:#000000;block-progression:tb;text-decoration-line:none;image-rendering:auto;white-space:normal;text-indent:0;text-transform:none;text-decoration-style:solid" d="m122.88 305.82c-2.3846 0-4.3789 2.0376-4.3789 4.4222v0.77344c-2.2304 0.10995-4.0388 0.5467-5.3281 1.4316-1.5951 1.0948-2.4675 2.582-3.1816 3.877-0.71415 1.295-1.2996 2.4093-2.1504 3.1894-0.72545 0.66525-1.7997 1.1216-3.4512 1.3301-0.21359-2.192-2.0615-3.9512-4.3052-3.9512h-17.167c-2.3846 0-4.4165 1.965-4.4165 4.3496v4.2422c0 2.3846 2.0319 4.3516 4.4165 4.3516h17.167c2.3846 0 4.3872-1.9669 4.3872-4.3516v-1.6133c9.7257 0.15307 12.467 2.6032 15.594 5.3379 3.0006 2.6241 6.6658 5.3789 15.436 5.4948v0.73633c0 2.3846 2.0695 4.3799 4.4541 4.3799h17.092c2.3846 0 4.4541-1.9952 4.4541-4.3799v-4.2422c0-2.3846-2.0695-4.3779-4.4541-4.3779h-17.092c-2.3846 0-4.4541 1.9933-4.4541 4.3779v0.58594c-8.0984-0.0599-10.486-2.1557-13.498-4.7897-2.5035-2.1893-5.6398-4.5852-11.947-5.5859 1.176-1.1795 1.8834-2.5192 2.5137-3.6621 0.67724-1.228 1.2899-2.2006 2.2695-2.873 0.76303-0.52371 1.9757-0.83922 3.6621-0.93945v0.55078c0 2.3846 1.9943 4.3356 4.3789 4.3356h17.242c2.3846 0 4.3789-1.951 4.3789-4.3356v-4.2422c0-2.3846-1.9943-4.4222-4.3789-4.4222zm0 3h17.242c0.80513 0 1.3789 0.6171 1.3789 1.4222v4.2422c0 0.80514-0.57378 1.3356-1.3789 1.3356h-17.242c-0.80513 0-1.3789-0.53045-1.3789-1.3356v-4.2422c0-0.80513 0.57378-1.4222 1.3789-1.4222zm-39.962 11.016h17.167c0.80513 0 1.4165 0.60112 1.4165 1.4062v4.2422c0 0.80513-0.61138 1.4082-1.4165 1.4082h-17.167c-0.80513 0-1.4165-0.60307-1.4165-1.4082v-4.2422c0-0.80513 0.61137-1.4062 1.4165-1.4062zm57.038 9.984h17.092c0.80513 0 1.4541 0.5728 1.4541 1.3779v4.168c0 0.80513-0.64898 1.4541-1.4541 1.4541h-17.092c-0.80513 0-1.4541-0.64897-1.4541-1.4541v-4.168c0-0.80513 0.64897-1.3779 1.4541-1.3779z" fill="#fff"/>
|
|
18
|
+
</g>
|
|
19
|
+
<g transform="matrix(1.0024 0 0 1.0024 .26914 -2.6855)" fill="#8f0000">
|
|
20
|
+
<path d="m90.51 954.73v8.4388l-7.9801 1.4384v59.934h-13.931l-28.465-46.989-0.49878 0.048v37.111l7.9805 1.4384v8.3908h-28.929v-8.3908l7.4319-1.4384v-50.105l-7.4319-1.4384v-8.4388h7.4319 14.001l28.302 46.989 0.14384-0.048v-37.063l-6.983-1.4384v-8.4388h20.971 7.9586z"/>
|
|
21
|
+
<path d="m94.501 998.12q0-11.603 6.4729-18.987 6.5209-7.4319 17.98-7.4319 11.507 0 17.98 7.3839 6.5209 7.3839 6.5209 19.035v1.0069q0 11.699-6.5209 19.083-6.4729 7.3359-17.884 7.3359-11.555 0-18.076-7.3359-6.4729-7.384-6.4729-19.083v-1.0069zm14.001 1.0069q0 7.0963 2.4933 11.411 2.4933 4.2674 8.0552 4.2674 5.4181 0 7.9114-4.3153 2.5412-4.3153 2.5412-11.364v-1.0069q0-6.9044-2.5412-11.268-2.5412-4.3632-8.0072-4.3632t-7.9593 4.3632-2.4933 11.268v1.0069z"/>
|
|
22
|
+
<path d="m183.77 1018.2c-1.6302 2.3973-3.5641 4.2193-5.8017 5.466-2.2056 1.2466-4.7308 1.8797-7.5757 1.8797-6.393 0-11.364-2.3432-14.912-7.0101-3.5161-4.6669-5.1162-10.836-5.1162-18.508v-1.0069c0-8.1833 1.6161-14.784 5.1642-19.802 3.5481-5.0185 8.5348-7.5278 14.96-7.5278 2.5892 0 4.9226 0.57537 7.0003 1.7261 2.0777 1.1188 4.2289 2.7171 5.7952 4.7948v-18.604l-7.9806-1.4384v-8.4388h7.6513 14.295v64.969l5.9854 1.4384v8.4102h-18.41l-1.0548-6.3484zm-19.44-18.172c0 4.5391 0.62786 8.1191 2.1302 10.74 1.5343 2.5891 4.0276 3.8837 7.4798 3.8837 2.0457 0 3.8198-0.4155 5.3222-1.2466 1.5023-0.8311 3.0626-2.0298 4.0216-3.5961v-22.008c-0.95893-1.6622-2.5192-2.9408-4.0216-3.8358-1.4704-0.927-3.2125-1.3905-5.2263-1.3905-3.4203 0-5.9135 1.5183-7.4798 4.555s-2.2261 7.0003-2.2261 11.891v1.0069z"/>
|
|
23
|
+
<path d="m232.87 1025.5c-7.48 0-13.457-2.3974-17.932-7.1921-4.4751-4.7947-6.7127-10.884-6.7127-18.268v-1.9179c0-7.7033 2.1097-14.048 6.3291-19.035 4.2513-4.9865 9.941-7.4419 17.069-7.41 7.0007 0 12.435 2.0878 16.302 6.3072 3.8678 4.2194 6.4539 9.93 6.188 17.117v7.5004h-31.36l-0.0959 0.4109c0.25573 3.4203 1.3905 6.2332 3.4043 8.4388 2.0457 2.2056 4.8107 3.3084 8.2949 3.3084 3.1006 0 5.6738-0.3037 7.7196-0.911 2.0457-0.6393 4.2833-1.6303 6.7127-2.9728l3.7879 8.6306c-2.1417 1.6941-4.9226 3.1166-8.3429 4.2673-3.3883 1.1507-7.1763 1.7261-11.364 1.7261zm-1.2466-43.057c-2.5892 0-4.635 0.99093-6.1373 2.9728s-2.4293 4.587-2.781 7.8154l0.14385 0.39233h17.299v-1.3992c0-2.9727-0.83677-5.3381-2.2432-7.0962-1.3745-1.7901-3.4682-2.6851-6.2811-2.6851z"/>
|
|
24
|
+
<path d="m291.02 1000.6h-26.934v-10.973h26.934z"/>
|
|
25
|
+
<path d="m330.82 954.73c7.9273 0 14.145 1.822 18.652 5.466 4.5071 3.6121 6.3914 8.6152 6.3914 15.008 0 3.5161-0.57382 6.5684-2.4598 9.1576-1.8859 2.5892-4.6509 4.6829-8.2949 6.2811 4.1235 1.2147 7.0802 3.2445 8.8703 6.0894 1.822 2.8129 2.8819 6.3133 2.8819 10.501v3.5481c0 1.5343 0.15475 2.733 0.76208 3.5961 0.60734 0.8311 1.6142 1.3265 3.0207 1.4863l1.2051 0.2398v8.4387h-6.7191c-4.571 0-7.7835-1.2306-9.6375-3.6919s-2.5972-5.6419-2.5972-9.5416v-3.9796c0-3.3883-1.0948-6.0414-2.9168-7.9593-1.7901-1.9499-4.3313-2.9727-7.6237-3.0686h-11.406v18.412l6.9825 1.4384v8.3908h-28.929v-8.3908l7.9805-1.4384v-50.105l-7.9805-1.4384v-8.4388h7.8932 23.926zm-9.9252 30.782h9.6854c3.8997 0 6.8245-0.8311 8.7744-2.4933s2.9248-4.0596 2.9248-7.1921c0-3.1326-0.97493-5.6259-2.9248-7.4798-1.9179-1.8859-4.7628-2.8289-8.5347-2.8289h-9.8718v19.994z"/>
|
|
26
|
+
<path d="m411.73 993.62h-22.944v19.951h22.163l0.62332-7.9805h10.181v18.942h-54.914v-8.3908l7.9806-1.4384v-50.105l-7.9806-1.4384v-8.4451h7.5735 47.245v18.954h-10.277l-0.62332-7.9806h-21.972v16.959h22.944v10.973z"/>
|
|
27
|
+
<path d="m461.1 954.75c8.5347 0 15.567 2.7087 21.097 8.1747 5.5299 5.4341 8.3382 12.392 8.3382 20.927v11.555c0 8.5667-2.8082 15.593-8.3382 21.027-5.5299 5.4021-12.562 8.1031-21.097 8.1031h-31.416v-8.3908l6.983-1.5117v-50.105l-6.983-1.3652v-8.4145l7.4424-0.0733 23.974 0.0754zm-10.468 10.737v48.283l9.7484 0.026c5.0185 0.013 8.9502-1.6942 11.795-5.0825 2.8449-3.3883 4.3934-7.7938 4.3934-13.26v-11.651c0-5.4021-1.5486-9.8189-4.3934-13.207-2.8449-3.3883-6.7765-5.0824-11.795-5.0824l-9.7484-0.0262z"/>
|
|
28
|
+
</g>
|
|
29
|
+
</g>
|
|
30
|
+
</svg>
|
package/docs/nodes/README.md
CHANGED
|
@@ -34,6 +34,12 @@ Node to convert different types of input data to the format used by the strategy
|
|
|
34
34
|
|
|
35
35
|
## Grid tariff nodes
|
|
36
36
|
|
|
37
|
+
### [ps-general-add-tariff](./ps-general-add-tariff)
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
Node to add a variable grid tariff (or any value) to the prices before sending them to the strategy nodes.
|
|
42
|
+
|
|
37
43
|
### [ps-elvia-add-tariff](./ps-elvia-add-tariff)
|
|
38
44
|
|
|
39
45
|

|
|
@@ -10,7 +10,7 @@ You can use it to control for example a heater, a water heater or any other powe
|
|
|
10
10
|
|
|
11
11
|
The node takes power prices per hour as input, and sends output to turn a switch on or off based on the power price. It also outputs the schedule that is planned, as well as how much you save per kWh for each of the hours that are turned off, assuming that the same power is used as soon as the power is turned on.
|
|
12
12
|
|
|
13
|
-
Power prices may be received from Tibber,
|
|
13
|
+
Power prices may be received from Tibber, Nord Pool or any other source that gives price per hour for today and optionally tomorrow. It is primarily made to be used together with Home Assistant (HA), but there is no dependency to HA, so it can just as well be used by itself.
|
|
14
14
|
|
|
15
15
|
The node can also be used in combination with MagicMirror with the MMM-MQTT and MMM-Tibber modules, in order to get the savings displayed on the MM screen in the MMM-Tibber module.
|
|
16
16
|
|
|
@@ -38,7 +38,7 @@ Make sure that you upgrade now and then to get the latest version. See [changelo
|
|
|
38
38
|
- Nordpool
|
|
39
39
|
- Other sources in a specific JSON format
|
|
40
40
|
|
|
41
|
-
Choose the one that fits you best. Of course, all inputs are JSON, but the Tibber and
|
|
41
|
+
Choose the one that fits you best. Of course, all inputs are JSON, but the Tibber and Nord Pool alternatives are designed to connect directly to those sources with a minimum effort.
|
|
42
42
|
|
|
43
43
|
From version 2.1.0, you can also send a config object as input for dynamically changing the node config.
|
|
44
44
|
|
|
@@ -73,17 +73,17 @@ Send the result from the `tibber-query` node with the query above directly to th
|
|
|
73
73
|
|
|
74
74
|
### Nordpool input
|
|
75
75
|
|
|
76
|
-
This is especially designed to work for Home Assistant (HA), and the [
|
|
76
|
+
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 `power-saver` node. Make sure this is done whenever the node is updated, as well as when the system starts up.
|
|
77
77
|
|
|
78
78
|
Data can be sent from both the `current state` node or the `events: state` node.
|
|
79
79
|
|
|
80
|
-
[See example with
|
|
80
|
+
[See example with Nord Pool and `current state` node](doc/example-nordpool-current-state.md)
|
|
81
81
|
|
|
82
|
-
[See example with
|
|
82
|
+
[See example with Nord Pool and `events: state` node](doc/example-nordpool-events-state.md)
|
|
83
83
|
|
|
84
84
|
### Other input
|
|
85
85
|
|
|
86
|
-
If you cannot use any of the two above (Tibber or
|
|
86
|
+
If you cannot use any of the two above (Tibber or Nord Pool), create the input to the node with the payload containing JSON like this:
|
|
87
87
|
|
|
88
88
|
```json
|
|
89
89
|
{
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# ps-general-add-tariff
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
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.
|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
|
|
9
|
+
This node is useful if there is an addition to the electricity price that varies over the day, as it might be for the grid tariff.
|
|
10
|
+
|
|
11
|
+
If there is one price for example from 22:00 to 06:00 every day, and another price from 06:00 to 22:00, this is the right node to use. It can be used for more than two periods, as long as the time it changes is the same every day.
|
|
12
|
+
|
|
13
|
+
Here is how this node is normally used:
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
::: tip Changes during the year
|
|
18
|
+
If there is one price now, and another price from a specific date, you can use two nodes after each other. Set the `Valid to date` of the node with the current prices to the last date the current prices are valid. Set the `Valid from date` of the node with the upcoming prices to the first date those prices are valid.
|
|
19
|
+
:::
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
### Add and delete periods
|
|
24
|
+
|
|
25
|
+
You can have from 1 to 24 periods during the day, with different values to add for each hour. Click the `Add period` button to add more periods. Click the `X` button to delete a period.
|
|
26
|
+
|
|
27
|
+
### From time and Value
|
|
28
|
+
|
|
29
|
+
For each period, select the time of the day the value is valid from, and enter the value.
|
|
30
|
+
|
|
31
|
+
### Valid from date
|
|
32
|
+
|
|
33
|
+
Fill in the first date the config is valid.
|
|
34
|
+
|
|
35
|
+
If this is empty, the config is valid from the dawn of time.
|
|
36
|
+
|
|
37
|
+
### Valid to date
|
|
38
|
+
|
|
39
|
+
Fill in the last date the config is valid.
|
|
40
|
+
|
|
41
|
+
If this is empty, the config is valid until forever.
|
|
42
|
+
|
|
43
|
+
## Input
|
|
44
|
+
|
|
45
|
+
The input is the [common strategy input format](./strategy-input.md)
|
|
46
|
+
|
|
47
|
+
## Output
|
|
48
|
+
|
|
49
|
+
The output is the [common strategy input format](./strategy-input.md)
|
|
@@ -55,11 +55,11 @@ If you are a Tibber customer, you can use the `tibber-query` node from the [`nod
|
|
|
55
55
|
|
|
56
56
|
Send the result from the `tibber-query` node with the query above directly to the `ps-receive-price` node. Make sure it is refreshed when new prices are ready. Prices for the next day are normally ready at 13:00, but refreshing every hour can be a good idea.
|
|
57
57
|
|
|
58
|
-
[See example with Tibber, a switch and MQTT](
|
|
58
|
+
[See example with Tibber, a switch and MQTT](../examples/example-tibber-mqtt.md)
|
|
59
59
|
|
|
60
60
|
::: danger Warning
|
|
61
61
|
The query above returns an array with all houses you have in your Tibber account.
|
|
62
|
-
It
|
|
62
|
+
It will work only if the house you want is the first house in the array, for example if you have only one house.
|
|
63
63
|
If that is not the case, you must use the query below.
|
|
64
64
|
:::
|
|
65
65
|
|
|
@@ -67,7 +67,7 @@ If that is not the case, you must use the query below.
|
|
|
67
67
|
|
|
68
68
|
If the above query does not give you the house you want as the first in the result array, you can use the following method. In this method you need run one query in order to find the id of the house you want the prices for first, and then use the id in the real query.
|
|
69
69
|
|
|
70
|
-
Go to the [Tibber
|
|
70
|
+
Go to the [Tibber Developer pages](https://developer.tibber.com/), sign in, and go to the [API Explorer](https://developer.tibber.com/explorer). Load your personal token, then run the following query:
|
|
71
71
|
|
|
72
72
|
```gql
|
|
73
73
|
{
|
|
@@ -125,9 +125,13 @@ This is especially designed to work for Home Assistant (HA), and the [Nord Pool
|
|
|
125
125
|
|
|
126
126
|
Data can be sent from both the `current state` node or the `events: state` node.
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
::: tip Output properties
|
|
129
|
+
When using the `current state` node, configure the output properties to set `msg.payload` to `entity`.
|
|
130
|
+
:::
|
|
131
|
+
|
|
132
|
+
[See example with Nord Pool and `current state` node](../examples/example-nordpool-current-state.md)
|
|
129
133
|
|
|
130
|
-
[See example with Nord Pool and `events: state` node](
|
|
134
|
+
[See example with Nord Pool and `events: state` node](../examples/example-nordpool-events-state.md)
|
|
131
135
|
|
|
132
136
|
### Other input
|
|
133
137
|
|
|
@@ -12,7 +12,7 @@ The picture at the bottom of the page, under [Integration with MagicMirror](#int
|
|
|
12
12
|
|
|
13
13
|
## Configuration
|
|
14
14
|
|
|
15
|
-

|
|
15
|
+

|
|
16
16
|
|
|
17
17
|
| Value | Description |
|
|
18
18
|
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -27,6 +27,10 @@ The picture at the bottom of the page, under [Integration with MagicMirror](#int
|
|
|
27
27
|
NB! The `Min recover` only has effect if the previous save-period is of length `Max per sequence`. If the save-period is shorter, the following on-period may be as short as one hour.
|
|
28
28
|
:::
|
|
29
29
|
|
|
30
|
+
::: tip Legionella
|
|
31
|
+
Many people ask if there is a danger that legionella bacteria will grow and become dangerous when the temperature of the water heater is lowered. As long as the water is heated to at least 65 °C every day, or at least every week, the risk of infection is not considered significant, according to the norwegian [FHI](https://www.fhi.no/nettpub/legionellaveilederen/).
|
|
32
|
+
:::
|
|
33
|
+
|
|
30
34
|
### Dynamic config
|
|
31
35
|
|
|
32
36
|
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:
|
|
@@ -10,11 +10,11 @@ Strategy node to turn on power the hours when the price is lowest during a given
|
|
|
10
10
|
|
|
11
11
|
## Description
|
|
12
12
|
|
|
13
|
-
The node can work on a specific period from 1 to 24 hours during a 24 hour period. Inside this period, you can decide how many hours that shall be on. The rest of the period will be off. Outside the
|
|
13
|
+
The node can work on a specific period from 1 to 24 hours during a 24 hour period. Inside this period, you can decide how many hours that shall be on. The rest of the period will be off. Outside the period, you can select that the output shall be either on or off. You can also decide that the hours on shall be consecutive (one continuous period) or spread around in multiple on-periods.
|
|
14
14
|
|
|
15
15
|
## Configuration
|
|
16
16
|
|
|
17
|
-

|
|
17
|
+

|
|
18
18
|
|
|
19
19
|
| Value | Description |
|
|
20
20
|
| ---------------------- | -------------------------------------------------------------------------------- |
|
|
@@ -26,7 +26,7 @@ The node can work on a specific period from 1 to 24 hours during a 24 hour perio
|
|
|
26
26
|
| If No Schedule, Send | What to do if there is no valid schedule any more (turn on or off). |
|
|
27
27
|
| Outside Period, Send | Select the value to send outside the selected period. |
|
|
28
28
|
|
|
29
|
-
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
|
|
29
|
+
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.
|
|
30
30
|
|
|
31
31
|
::: tip Example with Consecutive On-Period
|
|
32
32
|
One example to need a consecutive on-period can be if you want to control the washing machine. Let's say it needs 3 hours, and you want it to run between 22:00 and 06:00. Set `From Time = 22:00`, `To Time = 06:00` and check the `Consecutive On-Period` flag. This will turn on the cheapest 3-hour period from 22:00 to 06:00.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Strategy input format
|
|
2
2
|
|
|
3
|
-
The common input for strategy nodes is a payload with a `priceData` array containing an object for each hour. Each object has a `value`
|
|
3
|
+
The common input for strategy nodes is a payload with a `priceData` array containing an object for each hour. Each object has a `value` which is the price, and a `start` which is the start time for the hour.
|
|
4
4
|
|
|
5
5
|
Example:
|
|
6
6
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-power-saver",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.1",
|
|
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": {
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"ps-elvia-config": "src/elvia/elvia-config.js",
|
|
29
29
|
"ps-elvia-tariff-types": "src/elvia/elvia-tariff-types.js",
|
|
30
30
|
"ps-elvia-tariff": "src/elvia/elvia-tariff.js",
|
|
31
|
-
"ps-elvia-add-tariff": "src/elvia/elvia-add-tariff.js"
|
|
31
|
+
"ps-elvia-add-tariff": "src/elvia/elvia-add-tariff.js",
|
|
32
|
+
"ps-general-add-tariff": "src/general-add-tariff.js"
|
|
32
33
|
}
|
|
33
34
|
},
|
|
34
35
|
"prettier": {
|
|
@@ -6,25 +6,26 @@ module.exports = function (RED) {
|
|
|
6
6
|
function PsElviaAddTariffNode(config) {
|
|
7
7
|
RED.nodes.createNode(this, config);
|
|
8
8
|
this.elviaConfig = RED.nodes.getNode(config.elviaConfig);
|
|
9
|
+
const key = this.elviaConfig.credentials.elviaSubscriptionKey;
|
|
9
10
|
this.tariffKey = config.tariffKey;
|
|
10
11
|
this.range = config.range;
|
|
11
12
|
const node = this;
|
|
12
|
-
|
|
13
|
-
const configList = node.context().global.get("elviaConfigList") || [];
|
|
14
|
-
const key = configList.find((c) => c.id == node.elviaConfig.id)?.elviaSubscriptionKey;
|
|
15
13
|
ping(node, key);
|
|
16
14
|
|
|
17
15
|
node.on("input", function (msg) {
|
|
18
16
|
const prices = msg.payload.priceData;
|
|
17
|
+
if (!prices) {
|
|
18
|
+
node.warn(
|
|
19
|
+
"No price data received on input. Did you use the ps-receive-price node or convert to correct format otherwise?"
|
|
20
|
+
);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
19
23
|
const fromTime = prices[0].start.substr(0, 19);
|
|
20
24
|
const toTime = DateTime.fromISO(prices[prices.length - 1].start)
|
|
21
25
|
.plus({ hours: 1 })
|
|
22
26
|
.toISO()
|
|
23
27
|
.substr(0, 19);
|
|
24
28
|
|
|
25
|
-
const configList = node.context().global.get("elviaConfigList") || [];
|
|
26
|
-
const key = configList.find((c) => c.id == node.elviaConfig.id)?.elviaSubscriptionKey;
|
|
27
|
-
|
|
28
29
|
getTariffForPeriod(node, key, node.tariffKey, fromTime, toTime).then((json) => {
|
|
29
30
|
const tariff = json;
|
|
30
31
|
const priceInfo = tariff.gridTariff.tariffPrice.priceInfo;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const cloneDeep = require("lodash.clonedeep");
|
|
2
|
+
const { DateTime } = require("luxon");
|
|
3
|
+
const { nodes } = require("node-red");
|
|
4
|
+
const { roundPrice } = require("./utils");
|
|
5
|
+
|
|
6
|
+
function buildAllHours(node, periods) {
|
|
7
|
+
const sortedPeriods = cloneDeep(periods);
|
|
8
|
+
sortedPeriods.sort((a, b) => a.start - b.start);
|
|
9
|
+
let res = [];
|
|
10
|
+
let hour = 0;
|
|
11
|
+
let current = sortedPeriods[sortedPeriods.length - 1];
|
|
12
|
+
sortedPeriods.push({ start: 24, value: null });
|
|
13
|
+
sortedPeriods.forEach((period) => {
|
|
14
|
+
const nextHour = parseInt(period.start);
|
|
15
|
+
while (hour < nextHour) {
|
|
16
|
+
let value = 0;
|
|
17
|
+
try {
|
|
18
|
+
value = parseFloat(("" + current.value).replace(",", "."));
|
|
19
|
+
} catch (e) {
|
|
20
|
+
node.warn("Illegal number: " + current.value);
|
|
21
|
+
}
|
|
22
|
+
res[hour] = value;
|
|
23
|
+
hour++;
|
|
24
|
+
}
|
|
25
|
+
current = period;
|
|
26
|
+
});
|
|
27
|
+
return res;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function addTariffToPrices(node, config, prices) {
|
|
31
|
+
const allHours = buildAllHours(node, config.periods);
|
|
32
|
+
const validFrom = DateTime.fromISO(config.validFrom || prices[0].start.substr(0, 10));
|
|
33
|
+
const validTo = DateTime.fromISO(config.validTo || prices[prices.length - 1].start.substr(0, 10));
|
|
34
|
+
prices.forEach((p, i) => {
|
|
35
|
+
const date = DateTime.fromISO(p.start.substr(0, 10));
|
|
36
|
+
const hour = DateTime.fromISO(p.start).hour;
|
|
37
|
+
if (date >= validFrom && date <= validTo) {
|
|
38
|
+
prices[i].value = roundPrice(prices[i].value + allHours[hour]);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
addTariffToPrices,
|
|
45
|
+
buildAllHours,
|
|
46
|
+
};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
const dateRe = /^$|^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$/;
|
|
3
|
+
const priceRe = /^(\d+\.\d*)|(\d+)$/;
|
|
4
|
+
RED.nodes.registerType("ps-general-add-tariff", {
|
|
5
|
+
category: "Power Saver",
|
|
6
|
+
color: "#a6bbcf",
|
|
7
|
+
defaults: {
|
|
8
|
+
name: { value: "Add General Tariff" },
|
|
9
|
+
periods: {
|
|
10
|
+
value: [
|
|
11
|
+
{ start: "22", value: 0.0 },
|
|
12
|
+
{ start: "06", value: 0.0 },
|
|
13
|
+
],
|
|
14
|
+
validate: function () {
|
|
15
|
+
return !this.periods.some((p) => !priceRe.test("" + p.value));
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
validFrom: { value: null, required: false, validate: RED.validators.regex(dateRe) },
|
|
19
|
+
validTo: { value: null, required: false, validate: RED.validators.regex(dateRe) },
|
|
20
|
+
},
|
|
21
|
+
hours: [
|
|
22
|
+
"00",
|
|
23
|
+
"01",
|
|
24
|
+
"02",
|
|
25
|
+
"03",
|
|
26
|
+
"04",
|
|
27
|
+
"05",
|
|
28
|
+
"06",
|
|
29
|
+
"07",
|
|
30
|
+
"08",
|
|
31
|
+
"09",
|
|
32
|
+
"10",
|
|
33
|
+
"11",
|
|
34
|
+
"12",
|
|
35
|
+
"13",
|
|
36
|
+
"14",
|
|
37
|
+
"15",
|
|
38
|
+
"16",
|
|
39
|
+
"17",
|
|
40
|
+
"18",
|
|
41
|
+
"19",
|
|
42
|
+
"20",
|
|
43
|
+
"21",
|
|
44
|
+
"22",
|
|
45
|
+
"23",
|
|
46
|
+
],
|
|
47
|
+
inputs: 1,
|
|
48
|
+
outputs: 1,
|
|
49
|
+
periodCont: 2,
|
|
50
|
+
icon: "font-awesome/fa-plus",
|
|
51
|
+
color: "#FFCC66",
|
|
52
|
+
label: function () {
|
|
53
|
+
return this.name || "Add Tariff";
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
oneditprepare: function () {
|
|
57
|
+
const createElement = function (type, attrs = [], children = []) {
|
|
58
|
+
const el = document.createElement(type);
|
|
59
|
+
attrs.forEach((attr) => {
|
|
60
|
+
el.setAttribute(attr[0], attr[1]);
|
|
61
|
+
});
|
|
62
|
+
children.forEach((child) => {
|
|
63
|
+
el.append(child);
|
|
64
|
+
});
|
|
65
|
+
return el;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const createInputPart = function (name, i, text, inpStyle, value) {
|
|
69
|
+
const id = `node-input-${name}-${i}`;
|
|
70
|
+
const label = createElement(
|
|
71
|
+
"label",
|
|
72
|
+
[
|
|
73
|
+
["for", id],
|
|
74
|
+
["style", "margin-right: 10px;"],
|
|
75
|
+
],
|
|
76
|
+
[]
|
|
77
|
+
);
|
|
78
|
+
label.innerHTML = text;
|
|
79
|
+
const inp = createElement("input", [
|
|
80
|
+
["type", "text"],
|
|
81
|
+
["id", id],
|
|
82
|
+
["style", `width: 80px; ${inpStyle};`],
|
|
83
|
+
]);
|
|
84
|
+
inp.value = value;
|
|
85
|
+
return createElement("span", [["style", "text-align: right;"]], [label, inp]);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const addPeriod = function (periods) {
|
|
89
|
+
const prev = periods[periods.length - 1].start;
|
|
90
|
+
const next = prev === "23" ? "00" : "" + (parseInt(prev) + 1);
|
|
91
|
+
periods.push({ start: next, value: null });
|
|
92
|
+
drawPeriods(periods);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const removePeriod = function (periods, i) {
|
|
96
|
+
periods.splice(i, 1);
|
|
97
|
+
drawPeriods(periods);
|
|
98
|
+
RED.nodes.dirty(true);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const drawPeriods = function (periods) {
|
|
102
|
+
document.getElementById("node-input-period-container").replaceChildren();
|
|
103
|
+
for (let i = 0; i < periods.length; i++) {
|
|
104
|
+
let period = periods[i];
|
|
105
|
+
|
|
106
|
+
const timeEl = createInputPart("fromTime", i, "From time:", "margin-right: 20px;", period.start);
|
|
107
|
+
const valEl = createInputPart("value", i, "Value:", "margin-right: 20px;", period.value);
|
|
108
|
+
|
|
109
|
+
let li;
|
|
110
|
+
if (periods.length > 1) {
|
|
111
|
+
// Delete button
|
|
112
|
+
const delButton = document.createElement("button");
|
|
113
|
+
delButton.setAttribute("style", "width: 24px;");
|
|
114
|
+
delButton.innerText = "X";
|
|
115
|
+
delButton.addEventListener("click", () => {
|
|
116
|
+
removePeriod(periods, i);
|
|
117
|
+
});
|
|
118
|
+
li = createElement("div", [["style", "text-align: left;"]], [timeEl, valEl, delButton]);
|
|
119
|
+
} else {
|
|
120
|
+
li = createElement("div", [["style", "text-align: left;"]], [timeEl, valEl]);
|
|
121
|
+
}
|
|
122
|
+
$("#node-input-period-container").append(li);
|
|
123
|
+
|
|
124
|
+
$("#node-input-fromTime-" + i).typedInput({
|
|
125
|
+
types: [
|
|
126
|
+
{
|
|
127
|
+
value: "fromtime",
|
|
128
|
+
options: hours.map((h) => ({ value: h, label: h + ":00" })),
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
});
|
|
132
|
+
$("#node-input-fromTime-" + i).change(function () {
|
|
133
|
+
periods[i].start = this.value;
|
|
134
|
+
RED.nodes.dirty(true);
|
|
135
|
+
});
|
|
136
|
+
$("#node-input-value-" + i).change(function () {
|
|
137
|
+
periods[i].value = this.value;
|
|
138
|
+
RED.nodes.dirty(true);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
drawPeriods(this.periods);
|
|
144
|
+
$("#add-period-button").on("click", () => {
|
|
145
|
+
addPeriod(this.periods);
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
</script>
|
|
150
|
+
|
|
151
|
+
<script type="text/html" data-template-name="ps-general-add-tariff">
|
|
152
|
+
<div class="form-row">
|
|
153
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
154
|
+
<input type="text" id="node-input-name" placeholder="Name" />
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<div class="form-row node-input-period-container-row">
|
|
158
|
+
<div id="node-input-period-container"></div>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<div class="form-row">
|
|
162
|
+
<button type="button" id="add-period-button" class="red-ui-button">Add period</button>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<h3>Optional:</h3>
|
|
166
|
+
|
|
167
|
+
<div class="form-row">
|
|
168
|
+
<label for="node-input-validFrom"><i class="fa fa-calendar"></i> Valid from date</label>
|
|
169
|
+
<input type="text" id="node-input-validFrom" placeholder="YYYY-MM-DD" />
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
<div class="form-row">
|
|
173
|
+
<label for="node-input-validTo"><i class="fa fa-calendar"></i> Valid to date</label>
|
|
174
|
+
<input type="text" id="node-input-validTo" placeholder="YYYY-MM-DD" />
|
|
175
|
+
</div>
|
|
176
|
+
</script>
|
|
177
|
+
|
|
178
|
+
<script type="text/markdown" data-help-name="ps-general-add-tariff">
|
|
179
|
+
# Add Tariff
|
|
180
|
+
|
|
181
|
+
A node to add a tariff that is fixed for periods of the day/year
|
|
182
|
+
to the price before it is sent to the strategy nodes.
|
|
183
|
+
Use this node between the receive-price node and any of the strategy nodes.
|
|
184
|
+
|
|
185
|
+
Please read more in the [node documentation](https://ottopaulsen.github.io/node-red-contrib-power-saver/nodes/ps-general-add-tariff)
|
|
186
|
+
</script>
|