node-red-contrib-power-saver 4.1.1 → 4.1.3
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/components/AdsenseAdd.vue +6 -0
- package/docs/changelog/README.md +9 -0
- package/docs/contribute/README.md +1 -1
- package/docs/examples/example-grid-tariff-capacity-part.md +162 -138
- package/docs/guide/README.md +5 -1
- package/docs/images/example-capacity-flow.png +0 -0
- package/examples/example-grid-tariff-capacity-flow.json +244 -0
- package/package.json +1 -1
- package/src/elvia/elvia-api.js +26 -18
- package/src/handle-output.js +3 -3
- package/src/schedule-merger-functions.js +2 -2
- package/src/schedule-merger.js +1 -1
- package/src/strategy-functions.js +1 -1
- package/test/strategy-best-save.test.js +60 -2
- package/test/strategy-lowest-price-3days.test.js +31 -0
- package/docs/examples/example-grid-tariff-capacity-flow.json +0 -1142
package/docs/changelog/README.md
CHANGED
|
@@ -7,6 +7,15 @@ sidebarDepth: 1
|
|
|
7
7
|
|
|
8
8
|
List the most significant changes.
|
|
9
9
|
|
|
10
|
+
## 4.1.3
|
|
11
|
+
|
|
12
|
+
- Fix bug that saved some data in wrong context storage.
|
|
13
|
+
|
|
14
|
+
## 4.1.2
|
|
15
|
+
|
|
16
|
+
- Fix so configured values for output are sent, not only true/false.
|
|
17
|
+
- Catch error from Elvia API so NR does not crash.
|
|
18
|
+
|
|
10
19
|
## 4.1.1
|
|
11
20
|
|
|
12
21
|
- Update dependencies
|
|
@@ -49,7 +49,7 @@ Main developer: [Otto Paulsen](https://github.com/ottopaulsen)
|
|
|
49
49
|
|
|
50
50
|
Heat Capacitor developer: [Arne Klaveness](https://github.com/TomTorger)
|
|
51
51
|
|
|
52
|
-
Example contributors: [Stefan](https://github.com/oakhill87/node-red-contrib-power-saver)
|
|
52
|
+
Example contributors: [Stefan](https://github.com/oakhill87/node-red-contrib-power-saver), [Kim Storøy](https://www.facebook.com/kim.storoy)
|
|
53
53
|
|
|
54
54
|
###
|
|
55
55
|
|
|
@@ -1,81 +1,5 @@
|
|
|
1
1
|
# Capacity part of grid tariff
|
|
2
2
|
|
|
3
|
-
::: danger Bug-fix 12. September 2022
|
|
4
|
-
|
|
5
|
-
::: details A bug was found 12. sep 2022. Here is how to fix:
|
|
6
|
-
|
|
7
|
-
### 1. Node "Find highest per day":
|
|
8
|
-
|
|
9
|
-
Replace this line:
|
|
10
|
-
|
|
11
|
-
```js
|
|
12
|
-
const highestToday = days.get(new Date().getDate());
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
With this code:
|
|
16
|
-
|
|
17
|
-
```js
|
|
18
|
-
const highestToday = days.get(new Date().getDate()) ?? {
|
|
19
|
-
consumption: 0,
|
|
20
|
-
from: null,
|
|
21
|
-
};
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
This will set the `highestToday` to 0 during the first hour.
|
|
25
|
-
|
|
26
|
-
### 2. Node "Calculate values":
|
|
27
|
-
|
|
28
|
-
Above this line:
|
|
29
|
-
|
|
30
|
-
```js
|
|
31
|
-
function calculateLevel(hourEstimate, ...
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Insert this code:
|
|
35
|
-
|
|
36
|
-
```js
|
|
37
|
-
function isNull(value) {
|
|
38
|
-
return value === null || value === undefined;
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Further down the code you can find these 3 lines with 4 lines between:
|
|
43
|
-
|
|
44
|
-
```js
|
|
45
|
-
if (!highestPerDay) {
|
|
46
|
-
if (!highestToday) {
|
|
47
|
-
if (!hourEstimate) {
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Change these to:
|
|
51
|
-
|
|
52
|
-
```js
|
|
53
|
-
if (isNull(highestPerDay)) {
|
|
54
|
-
if (isNull(highestToday)) {
|
|
55
|
-
if (isNull(hourEstimate)) {
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Then these will not fail the first hour.
|
|
59
|
-
|
|
60
|
-
### 3. Node "Build query for consumption":
|
|
61
|
-
|
|
62
|
-
Find this line:
|
|
63
|
-
|
|
64
|
-
```js
|
|
65
|
-
const hour = time.getMinutes(); // NB Change to getMinutes()
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Change it to:
|
|
69
|
-
|
|
70
|
-
```js
|
|
71
|
-
const hour = time.getHours();
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
The bug fixed on no. 3 does so data for hours are read every minute,
|
|
75
|
-
instead of every hour. This is not necessary.
|
|
76
|
-
However, it does not lead to any error.
|
|
77
|
-
:::
|
|
78
|
-
|
|
79
3
|
## Introduction
|
|
80
4
|
|
|
81
5
|
I Norway, there has been introduced a monthly fee for grid capacity.
|
|
@@ -103,10 +27,10 @@ and you may not want to use them all, so it is a good idea to read through it al
|
|
|
103
27
|
|
|
104
28
|

|
|
105
29
|
|
|
106
|
-
The first part of nodes (upper
|
|
107
|
-
The
|
|
30
|
+
The first part of nodes (upper part) is used to read consumption from Tibber, and to perform all calculations.
|
|
31
|
+
The upper right two nodes are used to update a set of sensors in HA. You can use those sensor for many
|
|
108
32
|
purposes related to the grid capacity.
|
|
109
|
-
The
|
|
33
|
+
The bottom part is used to take actions in order to reduce power consumption,
|
|
110
34
|
or to reset actions when the consumption is lowered.
|
|
111
35
|
|
|
112
36
|
You may use the whole example, or only part of it, so you should read through the whole documentation before you start,
|
|
@@ -145,6 +69,7 @@ If you have the same information from other sources, you may be able to adapt th
|
|
|
145
69
|
- Automatically take actions to reduce consumption if it is recommended or required.
|
|
146
70
|
- Automatically reset actions if the consumption is sufficiently reduced.
|
|
147
71
|
- Log actions taken to a file
|
|
72
|
+
- Actions may also be done by directly and automatically overriding strategy nodes.
|
|
148
73
|
|
|
149
74
|
## Algorithm
|
|
150
75
|
|
|
@@ -176,8 +101,8 @@ See description for each of them for details.
|
|
|
176
101
|
## Calculated sensor values
|
|
177
102
|
|
|
178
103
|
The `Calculate values` node creates a payload with values that are used to create
|
|
179
|
-
sensors in Home Assistant.
|
|
180
|
-
|
|
104
|
+
sensors in Home Assistant. The `Update sensors` node maps these values to entity ids,
|
|
105
|
+
and the `Set entity` node uses the HA API to update sensors.
|
|
181
106
|
|
|
182
107
|
Here is a description of each of those sensor values.
|
|
183
108
|
|
|
@@ -526,7 +451,10 @@ context.set("buffer", buffer);
|
|
|
526
451
|
|
|
527
452
|
// Calculate buffer
|
|
528
453
|
const periodMs = buffer[buffer.length - 1].timeMs - buffer[0].timeMs;
|
|
529
|
-
|
|
454
|
+
let consumptionInPeriod = buffer[buffer.length - 1].accumulatedConsumption - buffer[0].accumulatedConsumption;
|
|
455
|
+
if (consumptionInPeriod < 0) {
|
|
456
|
+
consumptionInPeriod = 0;
|
|
457
|
+
}
|
|
530
458
|
if (periodMs === 0) {
|
|
531
459
|
return; // First item in buffer
|
|
532
460
|
}
|
|
@@ -642,7 +570,7 @@ See [Calculated sensor values](#calculated-sensor-values) for description of the
|
|
|
642
570
|
|
|
643
571
|
```js
|
|
644
572
|
const HA_NAME = "homeAssistant"; // Your HA name
|
|
645
|
-
const STEPS = [
|
|
573
|
+
const STEPS = [10, 15, 20];
|
|
646
574
|
const MAX_COUNTING = 3; // Number of days to calculate month
|
|
647
575
|
const BUFFER = 0.5; // Closer to limit increases level
|
|
648
576
|
const SAFE_ZONE = 2; // Further from limit reduces level
|
|
@@ -790,6 +718,8 @@ const payload = {
|
|
|
790
718
|
highestCounting,
|
|
791
719
|
highestCountingWithCurrent,
|
|
792
720
|
highestToday,
|
|
721
|
+
highestTodayConsumption: highestToday.consumption,
|
|
722
|
+
highestTodayFrom: highestToday.from,
|
|
793
723
|
currentMonthlyEstimate: Math.round(currentMonthlyEstimate * RESOLUTION) / RESOLUTION,
|
|
794
724
|
accumulatedConsumptionLastHour: Math.round(accumulatedConsumptionLastHour * RESOLUTION) / RESOLUTION,
|
|
795
725
|
consumptionLeft: Math.round(consumptionLeft * RESOLUTION) / RESOLUTION,
|
|
@@ -815,6 +745,61 @@ return msg;
|
|
|
815
745
|
|
|
816
746
|
:::
|
|
817
747
|
|
|
748
|
+
### Update sensors
|
|
749
|
+
|
|
750
|
+
This function node maps the values from the previous node to entity_ids that shall be updated in HA.
|
|
751
|
+
Then, for each sensor, it sends output that uses the API node to perform the actual update.
|
|
752
|
+
|
|
753
|
+
You can remove sensors that you do not want.
|
|
754
|
+
|
|
755
|
+
::: details Code
|
|
756
|
+
|
|
757
|
+
<CodeGroup>
|
|
758
|
+
<CodeGroupItem title="On Message" active>
|
|
759
|
+
|
|
760
|
+
```js
|
|
761
|
+
const sensors = [
|
|
762
|
+
{ id: "sensor.ps_cap_status", value: "status", uom: null },
|
|
763
|
+
{ id: "binary_sensor.ps_cap_ok", value: "statusOk", uom: null },
|
|
764
|
+
{ id: "binary_sensor.ps_cap_warning", value: "statusWarning", uom: null },
|
|
765
|
+
{ id: "binary_sensor.ps_cap_alarm", value: "statusAlarm", uom: null },
|
|
766
|
+
{ id: "sensor.ps_cap_alarm_level", value: "alarmLevel", uom: null },
|
|
767
|
+
{ id: "sensor.ps_cap_current_step", value: "currentStep", uom: "kW" },
|
|
768
|
+
{ id: "sensor.ps_cap_hour_estimate", value: "hourEstimate", uom: "kW" },
|
|
769
|
+
{ id: "sensor.ps_cap_current_hour_ranking", value: "currentHourRanking", uom: null },
|
|
770
|
+
{ id: "sensor.ps_cap_monthly_estimate", value: "currentMonthlyEstimate", uom: "kW" },
|
|
771
|
+
{ id: "sensor.ps_cap_highest_today", value: "highestTodayConsumption", uom: "kW" },
|
|
772
|
+
{ id: "sensor.ps_cap_highest_today_time", value: "highestTodayFrom", uom: null },
|
|
773
|
+
{ id: "sensor.ps_cap_reduction_required", value: "reductionRequired", uom: "kW" },
|
|
774
|
+
{ id: "sensor.ps_cap_reduction_recommended", value: "reductionRecommended", uom: "kW" },
|
|
775
|
+
{ id: "sensor.ps_cap_increase_possible", value: "increasePossible", uom: "kW" },
|
|
776
|
+
{ id: "sensor.ps_cap_estimate_rest_of_hour", value: "consumptionLeft", uom: "kW" },
|
|
777
|
+
{ id: "sensor.ps_cap_consumption_accumulated_hour", value: "accumulatedConsumptionLastHour", uom: "kW" },
|
|
778
|
+
{ id: "sensor.ps_cap_time_left", value: "timeLeftSec", uom: "s" },
|
|
779
|
+
{ id: "sensor.ps_cap_consumption_now", value: "averageConsumptionNow", uom: "kW" },
|
|
780
|
+
];
|
|
781
|
+
|
|
782
|
+
sensors.forEach((sensor) => {
|
|
783
|
+
const payload = {
|
|
784
|
+
protocol: "http",
|
|
785
|
+
method: "post",
|
|
786
|
+
path: "/api/states/" + sensor.id,
|
|
787
|
+
data: {
|
|
788
|
+
state: msg.payload[sensor.value],
|
|
789
|
+
attributes: { unit_of_measurement: sensor.uom },
|
|
790
|
+
},
|
|
791
|
+
};
|
|
792
|
+
node.send({ payload });
|
|
793
|
+
});
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
</CodeGroupItem>
|
|
797
|
+
</CodeGroup>
|
|
798
|
+
|
|
799
|
+
:::
|
|
800
|
+
|
|
801
|
+
### Set entity
|
|
802
|
+
|
|
818
803
|
### Reduction Actions
|
|
819
804
|
|
|
820
805
|
This is where you set up actions to be taken in case reduction is required or recommended.
|
|
@@ -827,34 +812,74 @@ In the **On Start** tab of this node, you set up the actions by writing a Javasc
|
|
|
827
812
|
the `actions` array.
|
|
828
813
|
The example shows some actions, but you may set up any number of actions.
|
|
829
814
|
|
|
830
|
-
|
|
815
|
+
There are two types of actions that can be sent:
|
|
816
|
+
|
|
817
|
+
#### Call service actions
|
|
818
|
+
|
|
819
|
+
These actions are taken by sending a payload to a HA `call service` node (the `Perform action` node).
|
|
831
820
|
The items in the `actions` array contains the payload you need to send to the `call service` node
|
|
832
821
|
in order to take action, and the payload you need to send to the same `call service` node
|
|
833
822
|
in order to reset the action.
|
|
834
823
|
|
|
824
|
+
#### Override Power Saver actions
|
|
825
|
+
|
|
826
|
+
These actions are taken by sending an override message to one or more strategy nodes.
|
|
827
|
+
Reduction is done by sending override `off`, and reset is done by sending override `auto`.
|
|
828
|
+
To use this type of action, specify the name of the strategy node that shall be overridden
|
|
829
|
+
in the `nameOfStrategyToOverride` attribute of the action.
|
|
830
|
+
|
|
831
|
+
Then send output 2 from the `Reduction Actions` node to the input of the strategy node.
|
|
832
|
+
|
|
833
|
+
You may have multiple actions controlling multiple strategy nodes. They are separated using the `name`
|
|
834
|
+
of the strategy node, so make sure they all have different names.
|
|
835
|
+
Output 2 must be sent to all strategy nodes that shall be controlled.
|
|
836
|
+
|
|
837
|
+
If you send the output to two strategy nodes with the same name, they will both be controlled.
|
|
838
|
+
|
|
839
|
+
You can use this to override the following nodes:
|
|
840
|
+
|
|
841
|
+
- Best Save
|
|
842
|
+
- Lowest Price
|
|
843
|
+
- Schedule Merger
|
|
844
|
+
- Fixed Schedule
|
|
845
|
+
|
|
846
|
+
If you are using the schedule merger node, you do not have to override the strategy nodes preceding the schedule merger,
|
|
847
|
+
only override the schedule merger.
|
|
848
|
+
|
|
849
|
+
#### Entity consumption
|
|
850
|
+
|
|
835
851
|
An action may be to turn on or off a switch, to perform a climate control or what ever else
|
|
836
852
|
you can do to control your entities.
|
|
837
853
|
|
|
838
|
-
In order to know how much power that is saved by turning off an action, each
|
|
839
|
-
to give this information. This way, if a device is not using any power, the action will not be taken.
|
|
854
|
+
In order to know how much power that is saved by turning off an action, you should specify this for each action, using the `consumption` attribute. This can be used in 3 different ways:
|
|
840
855
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
856
|
+
- The entity_id of a sensor that gives the consumption in kW (recommended)
|
|
857
|
+
- A number with the consumption in kW
|
|
858
|
+
- A function returning the consumption.
|
|
859
|
+
|
|
860
|
+
::: warning Consumption must be kW
|
|
861
|
+
If your sensor gives consumption in W, not the required kW, you should find a way to divide it by 1000.
|
|
844
862
|
:::
|
|
845
863
|
|
|
864
|
+
#### Actions configuration
|
|
865
|
+
|
|
846
866
|
Each item in the `actions` array contains the following data:
|
|
847
867
|
|
|
848
|
-
| Variable name
|
|
849
|
-
|
|
|
850
|
-
| consumption
|
|
851
|
-
| name
|
|
852
|
-
| id
|
|
853
|
-
| minAlarmLevel
|
|
854
|
-
| reduceWhenRecommended
|
|
855
|
-
| minTimeOffSec
|
|
856
|
-
| payloadToTakeAction
|
|
857
|
-
| payloadToResetAction
|
|
868
|
+
| Variable name | Description |
|
|
869
|
+
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
870
|
+
| consumption | The consumption that will be reduced by taking the action, given as either a) (Recommended) The entity_id of a sensor that gives the consumption, or b) A number with the consumption in kWh, or c) a function returning the consumption. |
|
|
871
|
+
| name | The name of the actions. Can be any thing. |
|
|
872
|
+
| id | A unique id of the action. |
|
|
873
|
+
| minAlarmLevel | The minimum alarm level that must be present to take this action. |
|
|
874
|
+
| reduceWhenRecommended | If `true` the action will be taken when `Reduction Recommended` > 0. If `false` the action will be taken only when `Reduction Required` > 0 |
|
|
875
|
+
| minTimeOffSec | The action will not be reset until minimum this number of seconds has passed since the action was taken. |
|
|
876
|
+
| payloadToTakeAction | The payload that shall be sent to the `call service` node to take the action (for example turn off a switch). |
|
|
877
|
+
| payloadToResetAction | The payload that shall be sent to the `call service` node to reset the action (for example turn a switch back on again). |
|
|
878
|
+
| nameOfStrategyToOverride | The name of the strategy node that shall be overridden by this action. |
|
|
879
|
+
|
|
880
|
+
::: warning Action type
|
|
881
|
+
Use either `nameOfStrategyToOverride` or `payloadToTakeAction` and `payloadToResetAction`. If you use them both at the same time, both actions are performed.
|
|
882
|
+
:::
|
|
858
883
|
|
|
859
884
|
::: tip Actions order
|
|
860
885
|
Actions to reduce consumption are taken in the order they appear in the `actions` array until enough reduction has been done,
|
|
@@ -873,6 +898,8 @@ If you don't want the actions, or you want to control actions another way,
|
|
|
873
898
|
you can omit the action-related nodes and only use the nodes creating the sensors.
|
|
874
899
|
:::
|
|
875
900
|
|
|
901
|
+
The `MIN_MINUTES_INTO_HOUR_TO_TAKE_ACTION` constant in the `On Message` code sets a period (of default 5 minutes) in the beginning of the hour when no reduction action is taken. This is to avoid that a high consumption at the end of the previous hour causes reduction actions to be taken as soon as the hour changes.
|
|
902
|
+
|
|
876
903
|
::: details Code
|
|
877
904
|
|
|
878
905
|
<CodeGroup>
|
|
@@ -889,20 +916,7 @@ const actions = [
|
|
|
889
916
|
minAlarmLevel: 3,
|
|
890
917
|
reduceWhenRecommended: true,
|
|
891
918
|
minTimeOffSec: 300,
|
|
892
|
-
|
|
893
|
-
domain: "switch",
|
|
894
|
-
service: "turn_off",
|
|
895
|
-
target: {
|
|
896
|
-
entity_id: ["switch.varmtvannsbereder"],
|
|
897
|
-
},
|
|
898
|
-
},
|
|
899
|
-
payloadToResetAction: {
|
|
900
|
-
domain: "switch",
|
|
901
|
-
service: "turn_on",
|
|
902
|
-
target: {
|
|
903
|
-
entity_id: ["switch.varmtvannsbereder"],
|
|
904
|
-
},
|
|
905
|
-
},
|
|
919
|
+
nameOfStrategyToOverride: "Lowest Price VVB",
|
|
906
920
|
},
|
|
907
921
|
{
|
|
908
922
|
consumption: "sensor.varme_gulv_bad_electric_consumption_w_2",
|
|
@@ -911,20 +925,7 @@ const actions = [
|
|
|
911
925
|
minAlarmLevel: 3,
|
|
912
926
|
reduceWhenRecommended: true,
|
|
913
927
|
minTimeOffSec: 300,
|
|
914
|
-
|
|
915
|
-
domain: "climate",
|
|
916
|
-
service: "turn_off",
|
|
917
|
-
target: {
|
|
918
|
-
entity_id: ["climate.varme_gulv_bad_2"],
|
|
919
|
-
},
|
|
920
|
-
},
|
|
921
|
-
payloadToResetAction: {
|
|
922
|
-
domain: "climate",
|
|
923
|
-
service: "turn_on",
|
|
924
|
-
target: {
|
|
925
|
-
entity_id: ["climate.varme_gulv_bad_2"],
|
|
926
|
-
},
|
|
927
|
-
},
|
|
928
|
+
nameOfStrategyToOverride: "Lowest Price Varmekabel",
|
|
928
929
|
},
|
|
929
930
|
{
|
|
930
931
|
consumption: "sensor.varme_gulv_gang_electric_consumption_w",
|
|
@@ -1012,6 +1013,7 @@ flow.set("actions", actions);
|
|
|
1012
1013
|
|
|
1013
1014
|
```js
|
|
1014
1015
|
const MIN_CONSUMPTION_TO_CARE = 0.05; // Do not reduce unless at least 50W
|
|
1016
|
+
const MIN_MINUTES_INTO_HOUR_TO_TAKE_ACTION = 5;
|
|
1015
1017
|
|
|
1016
1018
|
const actions = flow.get("actions");
|
|
1017
1019
|
const ha = global.get("homeassistant").homeAssistant;
|
|
@@ -1019,10 +1021,21 @@ const ha = global.get("homeassistant").homeAssistant;
|
|
|
1019
1021
|
let reductionRequired = msg.payload.reductionRequired;
|
|
1020
1022
|
let reductionRecommended = msg.payload.reductionRecommended;
|
|
1021
1023
|
|
|
1024
|
+
node.status({});
|
|
1025
|
+
|
|
1022
1026
|
if (reductionRecommended <= 0) {
|
|
1023
1027
|
return null;
|
|
1024
1028
|
}
|
|
1025
1029
|
|
|
1030
|
+
if (3600 - msg.payload.timeLeftSec < MIN_MINUTES_INTO_HOUR_TO_TAKE_ACTION * 60) {
|
|
1031
|
+
node.status({
|
|
1032
|
+
fill: "yellow",
|
|
1033
|
+
shape: "ring",
|
|
1034
|
+
text: "No action during first " + MIN_MINUTES_INTO_HOUR_TO_TAKE_ACTION + " minutes",
|
|
1035
|
+
});
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1026
1039
|
function takeAction(action, consumption) {
|
|
1027
1040
|
const info = {
|
|
1028
1041
|
time: new Date().toISOString(),
|
|
@@ -1030,7 +1043,17 @@ function takeAction(action, consumption) {
|
|
|
1030
1043
|
data: msg.payload,
|
|
1031
1044
|
action,
|
|
1032
1045
|
};
|
|
1033
|
-
|
|
1046
|
+
|
|
1047
|
+
// output1 is for actions
|
|
1048
|
+
const output1 = action.payloadToTakeAction ? { payload: action.payloadToTakeAction } : null;
|
|
1049
|
+
// output 2 is for overriding PS strategies
|
|
1050
|
+
const output2 = action.nameOfStrategyToOverride
|
|
1051
|
+
? { payload: { config: { override: "off" }, name: action.nameOfStrategyToOverride } }
|
|
1052
|
+
: null;
|
|
1053
|
+
// output 3 is for logging
|
|
1054
|
+
const output3 = { payload: info };
|
|
1055
|
+
|
|
1056
|
+
node.send([output1, output2, output3]);
|
|
1034
1057
|
reductionRequired = Math.max(0, reductionRequired - consumption);
|
|
1035
1058
|
reductionRecommended = Math.max(0, reductionRecommended - consumption);
|
|
1036
1059
|
action.actionTaken = true;
|
|
@@ -1042,7 +1065,7 @@ function takeAction(action, consumption) {
|
|
|
1042
1065
|
function getConsumption(consumption) {
|
|
1043
1066
|
if (typeof consumption === "string") {
|
|
1044
1067
|
const sensor = ha.states[consumption];
|
|
1045
|
-
return sensor.state;
|
|
1068
|
+
return sensor.state / 1000;
|
|
1046
1069
|
} else if (typeof consumption === "number") {
|
|
1047
1070
|
return consumption;
|
|
1048
1071
|
} else if (typeof consumption === "function") {
|
|
@@ -1099,10 +1122,16 @@ function resetAction(action) {
|
|
|
1099
1122
|
const info = {
|
|
1100
1123
|
time: new Date().toISOString(),
|
|
1101
1124
|
name: "Reset action",
|
|
1102
|
-
data: msg.
|
|
1125
|
+
data: msg.payload,
|
|
1103
1126
|
action,
|
|
1104
1127
|
};
|
|
1105
|
-
|
|
1128
|
+
const output1 = action.payloadToResetAction ? { payload: action.payloadToResetAction } : null;
|
|
1129
|
+
const output2 = action.nameOfStrategyToOverride
|
|
1130
|
+
? { payload: { config: { override: "auto" }, name: action.nameOfStrategyToOverride } }
|
|
1131
|
+
: null;
|
|
1132
|
+
const output3 = { payload: info };
|
|
1133
|
+
|
|
1134
|
+
node.send([output1, output2, output3]);
|
|
1106
1135
|
increasePossible -= action.savedConsumption;
|
|
1107
1136
|
action.actionTaken = false;
|
|
1108
1137
|
action.savedConsumption = 0;
|
|
@@ -1126,7 +1155,7 @@ actions
|
|
|
1126
1155
|
|
|
1127
1156
|
### Perform action
|
|
1128
1157
|
|
|
1129
|
-
This is a `call service` node used to perform the actions (both taking actions and resetting actions).
|
|
1158
|
+
This is a `call service` node used to perform the call service actions (both taking actions and resetting actions).
|
|
1130
1159
|
There is no setup here except selecting the HA server.
|
|
1131
1160
|
|
|
1132
1161
|
### Save actions to file
|
|
@@ -1138,16 +1167,11 @@ Please make sure the file name configured works for you (for example that the fo
|
|
|
1138
1167
|
|
|
1139
1168
|
This is supposed to catch any errors in the action-related nodes, and log them to the file.
|
|
1140
1169
|
|
|
1141
|
-
### Entity nodes
|
|
1142
|
-
|
|
1143
|
-
There is a large number of `entity` nodes, one for each sensor value that is created with values from the `Calculate values` node.
|
|
1144
|
-
See [Calculated sensor values](#calculated-sensor-values) for description of each sensor value.
|
|
1145
|
-
|
|
1146
1170
|
## The code
|
|
1147
1171
|
|
|
1148
1172
|
Below is the code for the Node-RED flow.
|
|
1149
1173
|
Copy the code and paste it to Node-RED using Import in the NR menu.
|
|
1150
1174
|
|
|
1151
1175
|
::: details Flow code
|
|
1152
|
-
@[code](
|
|
1176
|
+
@[code](../../examples/example-grid-tariff-capacity-flow.json)
|
|
1153
1177
|
:::
|
package/docs/guide/README.md
CHANGED
|
@@ -239,4 +239,8 @@ You may directly replace the `Power Saver` node by two of the new nodes (`ps-rec
|
|
|
239
239
|
|
|
240
240
|
See more details in the [documentation for the `ps-strategy-best-save`](../nodes/ps-strategy-best-save.md) node.
|
|
241
241
|
|
|
242
|
-
|
|
242
|
+
## Disclaimer
|
|
243
|
+
|
|
244
|
+
This software is offered for free as open source. You use it totally on your own risk. The developers take no responsibility of any consequences caused by use or misuse of this software.
|
|
245
|
+
|
|
246
|
+
It is not recommended to reduce the temperature of the water heater or similar over longer periods, due to the risk of legionella. Please read the recommendations of [FHI](https://www.fhi.no/sv/smittsomme-sykdommer/legionella/) about this. You do this at your own risk.
|
|
Binary file
|