node-red-contrib-power-saver 4.1.0 → 4.1.2

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.
@@ -7,6 +7,15 @@ sidebarDepth: 1
7
7
 
8
8
  List the most significant changes.
9
9
 
10
+ ## 4.1.2
11
+
12
+ - Fix so configured values for output are sent, not only true/false.
13
+ - Catch error from Elvia API so NR does not crash.
14
+
15
+ ## 4.1.1
16
+
17
+ - Update dependencies
18
+
10
19
  ## 4.1.0
11
20
 
12
21
  - Fix bug with override function. It did not override longer than until next scheduled change. Now it overrides until set to auto again.
@@ -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
  ![Capacity Flow](../images/example-capacity-flow.png)
105
29
 
106
- The first part of nodes (upper left) is used to read consumption from Tibber and to perform all calculations.
107
- The second part (right) is used to update a set of sensors in HA. You can use those sensor for many
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 third part (bottom left) is used to take actions in order to reduce power consumption,
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. There is one `entity` node for each sensor value.
180
- You may delete the entity nodes for sensor values you don't need.
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
 
@@ -642,7 +567,7 @@ See [Calculated sensor values](#calculated-sensor-values) for description of the
642
567
 
643
568
  ```js
644
569
  const HA_NAME = "homeAssistant"; // Your HA name
645
- const STEPS = [2, 5, 10, 15, 20];
570
+ const STEPS = [10, 15, 20];
646
571
  const MAX_COUNTING = 3; // Number of days to calculate month
647
572
  const BUFFER = 0.5; // Closer to limit increases level
648
573
  const SAFE_ZONE = 2; // Further from limit reduces level
@@ -790,6 +715,8 @@ const payload = {
790
715
  highestCounting,
791
716
  highestCountingWithCurrent,
792
717
  highestToday,
718
+ highestTodayConsumption: highestToday.consumption,
719
+ highestTodayFrom: highestToday.from,
793
720
  currentMonthlyEstimate: Math.round(currentMonthlyEstimate * RESOLUTION) / RESOLUTION,
794
721
  accumulatedConsumptionLastHour: Math.round(accumulatedConsumptionLastHour * RESOLUTION) / RESOLUTION,
795
722
  consumptionLeft: Math.round(consumptionLeft * RESOLUTION) / RESOLUTION,
@@ -815,6 +742,61 @@ return msg;
815
742
 
816
743
  :::
817
744
 
745
+ ### Update sensors
746
+
747
+ This function node maps the values from the previous node to entity_ids that shall be updated in HA.
748
+ Then, for each sensor, it sends output that uses the API node to perform the actual update.
749
+
750
+ You can remove sensors that you do not want.
751
+
752
+ ::: details Code
753
+
754
+ <CodeGroup>
755
+ <CodeGroupItem title="On Message" active>
756
+
757
+ ```js
758
+ const sensors = [
759
+ { id: "sensor.ps_cap_status", value: "status", uom: null },
760
+ { id: "binary_sensor.ps_cap_ok", value: "statusOk", uom: null },
761
+ { id: "binary_sensor.ps_cap_warning", value: "statusWarning", uom: null },
762
+ { id: "binary_sensor.ps_cap_alarm", value: "statusAlarm", uom: null },
763
+ { id: "sensor.ps_cap_alarm_level", value: "alarmLevel", uom: null },
764
+ { id: "sensor.ps_cap_current_step", value: "currentStep", uom: "kW" },
765
+ { id: "sensor.ps_cap_hour_estimate", value: "hourEstimate", uom: "kW" },
766
+ { id: "sensor.ps_cap_current_hour_ranking", value: "currentHourRanking", uom: null },
767
+ { id: "sensor.ps_cap_monthly_estimate", value: "currentMonthlyEstimate", uom: "kW" },
768
+ { id: "sensor.ps_cap_highest_today", value: "highestTodayConsumption", uom: "kW" },
769
+ { id: "sensor.ps_cap_highest_today_time", value: "highestTodayFrom", uom: null },
770
+ { id: "sensor.ps_cap_reduction_required", value: "reductionRequired", uom: "kW" },
771
+ { id: "sensor.ps_cap_reduction_recommended", value: "reductionRecommended", uom: "kW" },
772
+ { id: "sensor.ps_cap_increase_possible", value: "increasePossible", uom: "kW" },
773
+ { id: "sensor.ps_cap_estimate_rest_of_hour", value: "consumptionLeft", uom: "kW" },
774
+ { id: "sensor.ps_cap_consumption_accumulated_hour", value: "accumulatedConsumptionLastHour", uom: "kW" },
775
+ { id: "sensor.ps_cap_time_left", value: "timeLeftSec", uom: "s" },
776
+ { id: "sensor.ps_cap_consumption_now", value: "averageConsumptionNow", uom: "kW" },
777
+ ];
778
+
779
+ sensors.forEach((sensor) => {
780
+ const payload = {
781
+ protocol: "http",
782
+ method: "post",
783
+ path: "/api/states/" + sensor.id,
784
+ data: {
785
+ state: msg.payload[sensor.value],
786
+ attributes: { unit_of_measurement: sensor.uom },
787
+ },
788
+ };
789
+ node.send({ payload });
790
+ });
791
+ ```
792
+
793
+ </CodeGroupItem>
794
+ </CodeGroup>
795
+
796
+ :::
797
+
798
+ ### Set entity
799
+
818
800
  ### Reduction Actions
819
801
 
820
802
  This is where you set up actions to be taken in case reduction is required or recommended.
@@ -827,34 +809,74 @@ In the **On Start** tab of this node, you set up the actions by writing a Javasc
827
809
  the `actions` array.
828
810
  The example shows some actions, but you may set up any number of actions.
829
811
 
830
- Actions are taken by sending a payload to a HA `call service` node (the `Perform action` node).
812
+ There are two types of actions that can be sent:
813
+
814
+ #### Call service actions
815
+
816
+ These actions are taken by sending a payload to a HA `call service` node (the `Perform action` node).
831
817
  The items in the `actions` array contains the payload you need to send to the `call service` node
832
818
  in order to take action, and the payload you need to send to the same `call service` node
833
819
  in order to reset the action.
834
820
 
821
+ #### Override Power Saver actions
822
+
823
+ These actions are taken by sending an override message to one or more strategy nodes.
824
+ Reduction is done by sending override `off`, and reset is done by sending override `auto`.
825
+ To use this type of action, specify the name of the strategy node that shall be overridden
826
+ in the `nameOfStrategyToOverride` attribute of the action.
827
+
828
+ Then send output 2 from the `Reduction Actions` node to the input of the strategy node.
829
+
830
+ You may have multiple actions controlling multiple strategy nodes. They are separated using the `name`
831
+ of the strategy node, so make sure they all have different names.
832
+ Output 2 must be sent to all strategy nodes that shall be controlled.
833
+
834
+ If you send the output to two strategy nodes with the same name, they will both be controlled.
835
+
836
+ You can use this to override the following nodes:
837
+
838
+ - Best Save
839
+ - Lowest Price
840
+ - Schedule Merger
841
+ - Fixed Schedule
842
+
843
+ If you are using the schedule merger node, you do not have to override the strategy nodes preceding the schedule merger,
844
+ only override the schedule merger.
845
+
846
+ #### Entity consumption
847
+
835
848
  An action may be to turn on or off a switch, to perform a climate control or what ever else
836
849
  you can do to control your entities.
837
850
 
838
- In order to know how much power that is saved by turning off an action, each item must have a sensor
839
- to give this information. This way, if a device is not using any power, the action will not be taken.
851
+ 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:
852
+
853
+ - The entity_id of a sensor that gives the consumption in kW (recommended)
854
+ - A number with the consumption in kW
855
+ - A function returning the consumption.
840
856
 
841
- ::: warning Entity consumption
842
- In the current example, there must be a sensor holding the consumption of the entity to
843
- turn off. If this is not possible, the code must be changed in order to work.
857
+ ::: warning Consumption must be kW
858
+ If your sensor gives consumption in W, not the required kW, you should find a way to divide it by 1000.
844
859
  :::
845
860
 
861
+ #### Actions configuration
862
+
846
863
  Each item in the `actions` array contains the following data:
847
864
 
848
- | Variable name | Description |
849
- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
850
- | 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. |
851
- | name | The name of the actions. Can be any thing. |
852
- | id | A unique id of the action. |
853
- | minAlarmLevel | The minimum alarm level that must be present to take this action. |
854
- | reduceWhenRecommended | If `true` the action will be taken when `Reduction Recommended` > 0. If `false` the action will be taken only when `Reduction Required` > 0 |
855
- | minTimeOffSec | The action will not be reset until minimum this number of seconds has passed since the action was taken. |
856
- | payloadToTakeAction | The payload that shall be sent to the `call service` node to take the action (for example turn off a switch). |
857
- | payloadToResetAction | The payload that shall be sent to the `call service` node to reset the action (for example turn a switch back on again). |
865
+ | Variable name | Description |
866
+ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
867
+ | 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. |
868
+ | name | The name of the actions. Can be any thing. |
869
+ | id | A unique id of the action. |
870
+ | minAlarmLevel | The minimum alarm level that must be present to take this action. |
871
+ | reduceWhenRecommended | If `true` the action will be taken when `Reduction Recommended` > 0. If `false` the action will be taken only when `Reduction Required` > 0 |
872
+ | minTimeOffSec | The action will not be reset until minimum this number of seconds has passed since the action was taken. |
873
+ | payloadToTakeAction | The payload that shall be sent to the `call service` node to take the action (for example turn off a switch). |
874
+ | payloadToResetAction | The payload that shall be sent to the `call service` node to reset the action (for example turn a switch back on again). |
875
+ | nameOfStrategyToOverride | The name of the strategy node that shall be overridden by this action. |
876
+
877
+ ::: warning Action type
878
+ Use either `nameOfStrategyToOverride` or `payloadToTakeAction` and `payloadToResetAction`. If you use them both at the same time, both actions are performed.
879
+ :::
858
880
 
859
881
  ::: tip Actions order
860
882
  Actions to reduce consumption are taken in the order they appear in the `actions` array until enough reduction has been done,
@@ -889,20 +911,7 @@ const actions = [
889
911
  minAlarmLevel: 3,
890
912
  reduceWhenRecommended: true,
891
913
  minTimeOffSec: 300,
892
- payloadToTakeAction: {
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
- },
914
+ nameOfStrategyToOverride: "Lowest Price VVB",
906
915
  },
907
916
  {
908
917
  consumption: "sensor.varme_gulv_bad_electric_consumption_w_2",
@@ -911,20 +920,7 @@ const actions = [
911
920
  minAlarmLevel: 3,
912
921
  reduceWhenRecommended: true,
913
922
  minTimeOffSec: 300,
914
- payloadToTakeAction: {
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
- },
923
+ nameOfStrategyToOverride: "Lowest Price Varmekabel",
928
924
  },
929
925
  {
930
926
  consumption: "sensor.varme_gulv_gang_electric_consumption_w",
@@ -1030,7 +1026,17 @@ function takeAction(action, consumption) {
1030
1026
  data: msg.payload,
1031
1027
  action,
1032
1028
  };
1033
- node.send([{ payload: action.payloadToTakeAction }, { payload: info }]);
1029
+
1030
+ // output1 is for actions
1031
+ const output1 = action.payloadToTakeAction ? { payload: action.payloadToTakeAction } : null;
1032
+ // output 2 is for overriding PS strategies
1033
+ const output2 = action.nameOfStrategyToOverride
1034
+ ? { payload: { config: { override: "off" }, name: action.nameOfStrategyToOverride } }
1035
+ : null;
1036
+ // output 3 is for logging
1037
+ const output3 = { payload: info };
1038
+
1039
+ node.send([output1, output2, output3]);
1034
1040
  reductionRequired = Math.max(0, reductionRequired - consumption);
1035
1041
  reductionRecommended = Math.max(0, reductionRecommended - consumption);
1036
1042
  action.actionTaken = true;
@@ -1042,7 +1048,7 @@ function takeAction(action, consumption) {
1042
1048
  function getConsumption(consumption) {
1043
1049
  if (typeof consumption === "string") {
1044
1050
  const sensor = ha.states[consumption];
1045
- return sensor.state;
1051
+ return sensor.state / 1000;
1046
1052
  } else if (typeof consumption === "number") {
1047
1053
  return consumption;
1048
1054
  } else if (typeof consumption === "function") {
@@ -1102,7 +1108,13 @@ function resetAction(action) {
1102
1108
  data: msg.paylaod,
1103
1109
  action,
1104
1110
  };
1105
- node.send([{ payload: action.payloadToResetAction }, { payload: info }]);
1111
+ const output1 = action.payloadToResetAction ? { payload: action.payloadToResetAction } : null;
1112
+ const output2 = action.nameOfStrategyToOverride
1113
+ ? { payload: { config: { override: "auto" }, name: action.nameOfStrategyToOverride } }
1114
+ : null;
1115
+ const output3 = { payload: info };
1116
+
1117
+ node.send([output1, output2, output3]);
1106
1118
  increasePossible -= action.savedConsumption;
1107
1119
  action.actionTaken = false;
1108
1120
  action.savedConsumption = 0;
@@ -1126,7 +1138,7 @@ actions
1126
1138
 
1127
1139
  ### Perform action
1128
1140
 
1129
- This is a `call service` node used to perform the actions (both taking actions and resetting actions).
1141
+ This is a `call service` node used to perform the call service actions (both taking actions and resetting actions).
1130
1142
  There is no setup here except selecting the HA server.
1131
1143
 
1132
1144
  ### Save actions to file
@@ -1138,16 +1150,11 @@ Please make sure the file name configured works for you (for example that the fo
1138
1150
 
1139
1151
  This is supposed to catch any errors in the action-related nodes, and log them to the file.
1140
1152
 
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
1153
  ## The code
1147
1154
 
1148
1155
  Below is the code for the Node-RED flow.
1149
1156
  Copy the code and paste it to Node-RED using Import in the NR menu.
1150
1157
 
1151
1158
  ::: details Flow code
1152
- @[code](./example-grid-tariff-capacity-flow.json)
1159
+ @[code](../../examples/example-grid-tariff-capacity-flow.json)
1153
1160
  :::