smart-nodes 0.3.26 → 0.3.28

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/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ ## Version 0.3.28:
4
+
5
+ - Added this changlog file.
6
+ - Separate values for shutter_complex node for up and down times.
7
+ (Open each node and save it, to use the new times. This should be done before the version 0.4.0 is released.)
8
+ - For the following nodes you can choose to have one or two outputs (Could be a **breaking change**, please check your nodes).
9
+ - Logic
10
+ - Compare
11
+ - Hysteresis
12
+ - You can now separately declare the messages that should be sent by the following nodes (Could be a **breaking change**, please check your nodes).
13
+ - Logic
14
+ - Compare
15
+ - Hysteresis
16
+
17
+ - You can choose for the following nodes if they should send the result all the time or only if the result changed.
18
+ - Logic
19
+ - Compare
20
+ - Hysteresis
@@ -15,6 +15,8 @@
15
15
  out_false_type: { value: 'json' },
16
16
  out_true: { value: '{"topic": ""}' },
17
17
  out_true_type: { value: 'json' },
18
+ send_only_change: { value: true },
19
+ outputs: { value: 1 },
18
20
  save_state: { value: true },
19
21
  resend_on_start: { value: true }
20
22
  },
@@ -25,6 +27,10 @@
25
27
  {
26
28
  return this.name || this.comparator || "Compare";
27
29
  },
30
+ outputLabels: function (index)
31
+ {
32
+ return this.outputs == 1 ? "" : ["Wahr", "Falsch"][index];
33
+ },
28
34
  oneditprepare: function ()
29
35
  {
30
36
  $("#node-input-comparator").typedInput({
@@ -65,6 +71,8 @@
65
71
  typeField: "#node-input-value2_type"
66
72
  });
67
73
 
74
+
75
+
68
76
  $("#node-input-out_true").typedInput({
69
77
  type: "json",
70
78
  types: ["json", {
@@ -87,6 +95,30 @@
87
95
  typeField: "#node-input-out_false_type"
88
96
  });
89
97
 
98
+ $("#node-input-send_only_change").typedInput({
99
+ type: "bool",
100
+ types: [{
101
+ value: "1",
102
+ options: [
103
+ { value: "true", label: "Nur bei Änderung" },
104
+ { value: "false", label: "Immer" },
105
+ ]
106
+ }]
107
+ });
108
+
109
+ $("#node-input-outputs").typedInput({
110
+ type: "num",
111
+ types: [{
112
+ value: "1",
113
+ options: [
114
+ { value: "1", label: "Gemeinsamer Ausgang" },
115
+ { value: "2", label: "Separate Ausgänge" },
116
+ ]
117
+ }]
118
+ });
119
+
120
+
121
+
90
122
  $("#node-input-save_state").on("change", ev =>
91
123
  {
92
124
  if (ev.target.checked)
@@ -109,7 +141,8 @@
109
141
  <input id="node-input-comparator" />
110
142
  </div>
111
143
  <div class="form-row">
112
- <div>Defaultwerte werden hier gesetzt und können durch die einkommenden Nachrichten überschrieben werden.</div>
144
+ <div>Defaultwerte werden hier gesetzt und können durch</div>
145
+ <div>die einkommenden Nachrichten überschrieben werden.</div>
113
146
  </div>
114
147
  <div class="form-row">
115
148
  <label for="node-input-value1"><i class="fa fa-hashtag"></i> Wert 1</label>
@@ -134,13 +167,19 @@
134
167
  <input type="hidden" id="node-input-out_false_type">
135
168
  </div>
136
169
  <div class="form-row">
137
- <span><strong>Hinweis:</strong></span>
170
+ <label for="node-input-send_only_change"><i class="fa fa-repeat"></i> Senden</label>
171
+ <input id="node-input-send_only_change" />
138
172
  </div>
139
173
  <div class="form-row">
140
- <span>
141
- <code>msg.payload</code> wird automatisch auf das Logik-Ergebnis gesetzt.<br/>
142
- <code>msg.comperator</code> wird automatisch auf den Logik-Operator gesetzt.
143
- </span>
174
+ <label for="node-input-outputs"><i class="fa fa-hashtag"></i> Ausgänge</label>
175
+ <input id="node-input-outputs" />
176
+ </div>
177
+ <div class="form-row">
178
+ <div><strong>Hinweis:</strong></div>
179
+ <div><code>msg.payload</code> wird automatisch auf das Vergleichs-Ergebnis gesetzt,</div>
180
+ <div>sofern es nicht bereits hier in der Konfiguration gesetzt wurde.</div>
181
+ <div><code>msg.comperator</code> wird automatisch auf den Vergleichs-Operator gesetzt,</div>
182
+ <div>sofern es nicht bereits hier in der Konfiguration gesetzt wurde.</div>
144
183
  </div>
145
184
  <hr/>
146
185
  <h4 style="margin: 0.5rem 0;">Systemstart</h4>
@@ -182,4 +221,11 @@
182
221
  </table>
183
222
  </p>
184
223
  <p>Texte werden anhand ihres Ascii-Codes verglichen.<code>"c" &lt; "b"</code> ergibt <code>false</code><code>"C" &lt; "b"</code> ergibt <code>true</code>.</p>
224
+ <p>
225
+ <strong>Hinweis:</strong><br/>
226
+ <code>msg.payload</code> wird automatisch auf das Vergleichs-Ergebnis gesetzt,
227
+ sofern es nicht bereits in der Konfiguration gesetzt wurde.<br/>
228
+ <code>msg.comperator</code> wird automatisch auf den Vergleichs-Operator gesetzt,
229
+ sofern es nicht bereits in der Konfiguration gesetzt wurde.
230
+ </p>
185
231
  </script>
@@ -10,11 +10,13 @@ module.exports = function (RED)
10
10
  const smart_context = require("../persistence.js")(RED);
11
11
  const helper = require("../smart_helper.js");
12
12
 
13
+ // persistant values
13
14
  var node_settings = {
14
15
  values: [
15
16
  helper.evaluateNodeProperty(RED, config.value1, config.value1_type),
16
17
  helper.evaluateNodeProperty(RED, config.value2, config.value2_type)
17
18
  ],
19
+ last_result: null,
18
20
  last_message: null,
19
21
  };
20
22
 
@@ -33,6 +35,8 @@ module.exports = function (RED)
33
35
  let comparator = config.comparator;
34
36
  let out_true = helper.evaluateNodeProperty(RED, config.out_true, config.out_true_type);
35
37
  let out_false = helper.evaluateNodeProperty(RED, config.out_false, config.out_false_type);
38
+ let send_only_change = helper.evaluateNodeProperty(RED, config.send_only_change, "bool");
39
+ let outputs = helper.evaluateNodeProperty(RED, config.outputs, "num");
36
40
 
37
41
  // runtime values
38
42
 
@@ -50,7 +54,7 @@ module.exports = function (RED)
50
54
  let num = parseFloat(msg.payload);
51
55
  if (Number.isNaN(num))
52
56
  {
53
- node.error("Payload has to be numeric");
57
+ // node.error("Payload has to be numeric");
54
58
  return;
55
59
  }
56
60
 
@@ -58,28 +62,52 @@ module.exports = function (RED)
58
62
  node_settings.values[input - 1] = num;
59
63
 
60
64
  let result = getResult();
65
+ let out_msg = null;
66
+
61
67
  setStatus(result);
62
68
 
63
69
  if (result != null)
64
70
  {
65
- let msg = result ? out_true : out_false;
71
+ // Get custom output message
72
+ if (result)
73
+ {
74
+ if (out_true !== null)
75
+ out_msg = Object.assign({}, out_true);
76
+ }
77
+ else
78
+ {
79
+ if (out_false !== null)
80
+ out_msg = Object.assign({}, out_false);
81
+ }
66
82
 
67
- if (msg != null)
83
+ if (out_msg !== null)
68
84
  {
69
- msg = Object.assign(
70
- {},
71
- msg,
72
- { payload: result, comparator: comparator }
73
- );
85
+ // Overwrite automatic values, if not already defined
86
+ if (typeof out_msg.payload === "undefined")
87
+ out_msg.payload = result;
88
+
89
+ if (typeof out_msg.comparator === "undefined")
90
+ out_msg.comparator = comparator;
91
+
92
+ // Separate outputs if needed
93
+ if (outputs == 2)
94
+ {
95
+ if (result)
96
+ out_msg = [out_msg, null];
97
+ else
98
+ out_msg = [null, out_msg];
99
+ }
100
+
101
+ // Send only if needed
102
+ if (send_only_change == false || node_settings.last_result != result)
103
+ node.send(out_msg);
74
104
  }
75
105
 
76
- node_settings.last_message = msg;
106
+ node_settings.last_result = result;
107
+ node_settings.last_message = out_msg;
77
108
 
78
109
  if (config.save_state)
79
110
  smart_context.set(node.id, node_settings);
80
-
81
- if (msg != null)
82
- node.send(msg);
83
111
  }
84
112
  });
85
113
 
@@ -2,25 +2,38 @@
2
2
  RED.nodes.registerType("smart_counter", {
3
3
  category: "Smart Nodes",
4
4
  paletteLabel: "Counter",
5
- color: "#6EE2D9",
5
+ color: "#E2D96E",
6
6
  defaults: {
7
7
  name: { value: "" },
8
8
  start: { value: 0 },
9
9
  step: { value: 1 },
10
10
  min: { value: 0 },
11
11
  max: { value: 10 },
12
+ out_message: { value: '{"topic": ""}' },
13
+ out_message_type: { value: 'json' },
12
14
  save_state: { value: true },
13
15
  resend_on_start: { value: true }
14
16
  },
15
17
  inputs: 1,
16
18
  outputs: 1,
17
- icon: "smart_counter.png",
19
+ icon: "counter.png",
18
20
  label: function ()
19
21
  {
20
22
  return this.name || "Counter";
21
23
  },
22
24
  oneditprepare: function ()
23
25
  {
26
+ $("#node-input-out_message").typedInput({
27
+ type: "json",
28
+ types: ["json", {
29
+ value: "null",
30
+ label: "Standard",
31
+ icon: "fa fa-times",
32
+ hasValue: false,
33
+ }],
34
+ typeField: "#node-input-out_message_type"
35
+ });
36
+
24
37
  $("#node-input-save_state").on("change", ev =>
25
38
  {
26
39
  if (ev.target.checked)
@@ -55,6 +68,21 @@
55
68
  <input type="number" id="node-input-max" placeholder="Max">
56
69
  </div>
57
70
  <hr/>
71
+ <h4 style="margin: 0.5rem 0;">Ausgangsnachricht</h4>
72
+ <div class="form-row">
73
+ <label for="node-input-out_message"><i class="fa fa-check-circle"></i> Nachricht</label>
74
+ <input type="text" id="node-input-out_message"/>
75
+ <input type="hidden" id="node-input-out_message_type">
76
+ </div>
77
+ <div class="form-row">
78
+ <span><strong>Hinweis:</strong></span>
79
+ </div>
80
+ <div class="form-row">
81
+ <span>
82
+ <code>msg.payload</code> wird immer automatisch auf den Ergebnis-Wert gesetzt.
83
+ </span>
84
+ </div>
85
+ <hr/>
58
86
  <h4 style="margin: 0.5rem 0;">Systemstart</h4>
59
87
  <div class="form-row">
60
88
  <input type="checkbox" id="node-input-save_state" style="width: 20px;" />
@@ -86,6 +114,18 @@
86
114
  </tr>
87
115
  </thead>
88
116
  <tbody>
117
+ <tr>
118
+ <td><code>set_min</code></td>
119
+ <td>Überschreibt den eingestellten Min-Wert mit <code>msg.payload</code>.</td>
120
+ </tr>
121
+ <tr>
122
+ <td><code>set_max</code></td>
123
+ <td>Überschreibt den eingestellten Max-Wert mit <code>msg.payload</code>.</td>
124
+ </tr>
125
+ <tr>
126
+ <td><code>set_step</code></td>
127
+ <td>Überschreibt die eingestellte Schrittweite mit <code>msg.payload</code>.</td>
128
+ </tr>
89
129
  <tr>
90
130
  <td><code>up</code></td>
91
131
  <td>Erhöht den Wert um <code>msg.payload</code> oder falls nicht gesetzt (oder <code>null</code>) um die konfigurierte Schrittweite. Der neue Wert ist dabei immer innerhalb der Min- und Max-Werte.</td>
@@ -31,6 +31,7 @@ module.exports = function (RED)
31
31
  let step = config.step;
32
32
  let min = config.min;
33
33
  let max = config.max;
34
+ let out_message = helper.evaluateNodeProperty(RED, config.out_message, config.out_message_type);
34
35
 
35
36
  // runtime values
36
37
 
@@ -47,6 +48,18 @@ module.exports = function (RED)
47
48
  let temp_value;
48
49
  switch (real_topic)
49
50
  {
51
+ case "set_min":
52
+ min = parseFloat(msg.payload);
53
+ break;
54
+
55
+ case "set_max":
56
+ max = parseFloat(msg.payload);
57
+ break;
58
+
59
+ case "set_step":
60
+ step = parseFloat(msg.payload);
61
+ break;
62
+
50
63
  case "up":
51
64
  temp_value = parseFloat(msg.payload);
52
65
  if (isNaN(temp_value) && !isFinite(temp_value))
@@ -86,7 +99,12 @@ module.exports = function (RED)
86
99
  if (node_settings.value == node_settings.last_message?.payload)
87
100
  return;
88
101
 
89
- node_settings.last_message = { payload: node_settings.value };
102
+ // if out_message is set, use this instead of the default message
103
+ if (out_message)
104
+ node_settings.last_message = Object.assign({}, out_message, { payload: node_settings.value });
105
+ else
106
+ node_settings.last_message = { payload: node_settings.value };
107
+
90
108
  smart_context.set(node.id, node_settings);
91
109
 
92
110
  node.send(node_settings.last_message);
@@ -102,7 +120,7 @@ module.exports = function (RED)
102
120
  if (node_settings.value == null)
103
121
  node.status({});
104
122
  else
105
- node.status({ fill: "yellow", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Value = " + node_settings.value });
123
+ node.status({ fill: "yellow", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Min = " + min + " | Max = " + max + " | Value = " + node_settings.value });
106
124
  }
107
125
 
108
126
  if (config.save_state && config.resend_on_start && node_settings.last_message != null)
package/delay/delay.js CHANGED
@@ -94,7 +94,7 @@ module.exports = function (RED)
94
94
  }
95
95
  });
96
96
 
97
- let send = (msg) =>
97
+ let send = msg =>
98
98
  {
99
99
  let delay_ms = 0;
100
100
 
@@ -139,7 +139,7 @@ module.exports = function (RED)
139
139
  // No delay if 0 or smaller
140
140
  if (delay_ms <= 0)
141
141
  {
142
- node.status({ fill: "yellow", shape: "dot", text: helper.getCurrentTimeForStatus() + ": " + "Sended msg.topic = '" + +msg.topic + "' msg.payload = '" + msg.payload + "'" });
142
+ node.status({ fill: "yellow", shape: "dot", text: helper.getCurrentTimeForStatus() + ": " + "Sended " + getMessageStatusText(msg) });
143
143
  node_settings.last_message = msg
144
144
 
145
145
  if (config.save_state)
@@ -150,11 +150,11 @@ module.exports = function (RED)
150
150
  }
151
151
 
152
152
  // start new timeout
153
- node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": " + "Forward msg.topic = '" + msg.topic + "' msg.payload = '" + msg.payload + "' in " + helper.formatMsToStatus(delay_ms, "at") });
153
+ node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": " + "Forward " + getMessageStatusText(msg) + " in " + helper.formatMsToStatus(delay_ms, "at") });
154
154
  timeout = setTimeout(() =>
155
155
  {
156
156
  timeout = null;
157
- node.status({ fill: "yellow", shape: "dot", text: helper.getCurrentTimeForStatus() + ": " + "Sended msg.topic = '" + msg.topic + "' msg.payload = '" + msg.payload + "'" });
157
+ node.status({ fill: "yellow", shape: "dot", text: helper.getCurrentTimeForStatus() + ": " + "Sended " + getMessageStatusText(msg) });
158
158
  node_settings.last_message = msg
159
159
 
160
160
  if (config.save_state)
@@ -164,11 +164,25 @@ module.exports = function (RED)
164
164
  }, delay_ms);
165
165
  }
166
166
 
167
+ let getMessageStatusText = msg =>
168
+ {
169
+ let text = "";
170
+ if (msg.topic != null)
171
+ text += " topic = '" + msg.topic + "'";
172
+ if (msg.payload != null)
173
+ text += " payload = '" + msg.payload + "'";
174
+
175
+ if (text == "")
176
+ return "a message";
177
+
178
+ return text.trim();
179
+ }
180
+
167
181
  if (config.save_state && config.resend_on_start && node_settings.last_message != null)
168
182
  {
169
183
  setTimeout(() =>
170
184
  {
171
- node.status({ fill: "yellow", shape: "dot", text: helper.getCurrentTimeForStatus() + ": " + "Sended msg.topic = '" + node_settings.last_message.topic + "' msg.payload = '" + node_settings.last_message.payload + "'" });
185
+ node.status({ fill: "yellow", shape: "dot", text: helper.getCurrentTimeForStatus() + ": " + "Sended " + getMessageStatusText(node_settings.last_message) });
172
186
  node.send(node_settings.last_message);
173
187
  }, 10000);
174
188
  }
@@ -223,7 +223,6 @@
223
223
  let first = true;
224
224
 
225
225
  let labels = [];
226
- debugger;
227
226
 
228
227
  for (let out = 20; out >= -20; out -= 1)
229
228
  {
@@ -46,7 +46,7 @@ module.exports = function (RED)
46
46
  let new_setpoint = parseFloat(msg.payload);
47
47
  if (isNaN(new_setpoint) && !isFinite(new_setpoint))
48
48
  {
49
- node.error("Invalid payload: " + msg.payload);
49
+ // node.error("Invalid payload: " + msg.payload);
50
50
  return;
51
51
  }
52
52
 
@@ -58,7 +58,7 @@ module.exports = function (RED)
58
58
  let new_temp = parseFloat(msg.payload);
59
59
  if (isNaN(new_temp) && !isFinite(new_temp))
60
60
  {
61
- node.error("Invalid payload: " + msg.payload);
61
+ // node.error("Invalid payload: " + msg.payload);
62
62
  return;
63
63
  }
64
64
 
@@ -70,7 +70,7 @@ module.exports = function (RED)
70
70
  let new_flow_min = parseFloat(msg.payload);
71
71
  if (isNaN(new_flow_min) && !isFinite(new_flow_min))
72
72
  {
73
- node.error("Invalid payload: " + msg.payload);
73
+ // node.error("Invalid payload: " + msg.payload);
74
74
  return;
75
75
  }
76
76
 
@@ -82,7 +82,7 @@ module.exports = function (RED)
82
82
  let new_flow_max = parseFloat(msg.payload);
83
83
  if (isNaN(new_flow_max) && !isFinite(new_flow_max))
84
84
  {
85
- node.error("Invalid payload: " + msg.payload);
85
+ // node.error("Invalid payload: " + msg.payload);
86
86
  return;
87
87
  }
88
88
 
@@ -11,17 +11,22 @@
11
11
  out_higher_type: { value: 'json' },
12
12
  out_lower: { value: '{"topic": ""}' },
13
13
  out_lower_type: { value: 'json' },
14
+ send_only_change: { value: true },
15
+ outputs: { value: 1 },
14
16
  save_state: { value: true },
15
17
  resend_on_start: { value: true }
16
18
  },
17
19
  inputs: 1,
18
20
  outputs: 2,
19
- outputLabels: ["Über", "Unter"],
20
21
  icon: "font-awesome/fa-arrows-v",
21
22
  label: function ()
22
23
  {
23
24
  return this.name || this.comparator || "Hysteresis";
24
25
  },
26
+ outputLabels: function (index)
27
+ {
28
+ return this.outputs == 1 ? "" : ["Höher", "Niedriger"][index];
29
+ },
25
30
  oneditprepare: function ()
26
31
  {
27
32
  $("#node-input-setpoint").typedInput({
@@ -34,28 +39,66 @@
34
39
  types: ["num"]
35
40
  });
36
41
 
42
+
43
+
37
44
  $("#node-input-out_higher").typedInput({
38
45
  type: "json",
39
- types: ["json", {
40
- value: "null",
41
- label: "Originalnachricht",
42
- icon: "fa fa-times",
43
- hasValue: false,
44
- }],
46
+ types: ["json",
47
+ {
48
+ value: "null",
49
+ label: "Nichts senden",
50
+ icon: "fa fa-times",
51
+ hasValue: false,
52
+ }, {
53
+ value: "original",
54
+ label: "Originalnachricht",
55
+ icon: "fa fa-arrow-right",
56
+ hasValue: false,
57
+ }],
45
58
  typeField: "#node-input-out_higher_type"
46
59
  });
47
60
 
48
61
  $("#node-input-out_lower").typedInput({
49
62
  type: "json",
50
- types: ["json", {
51
- value: "null",
52
- label: "Originalnachricht",
53
- icon: "fa fa-times",
54
- hasValue: false,
55
- }],
63
+ types: ["json",
64
+ {
65
+ value: "null",
66
+ label: "Nichts senden",
67
+ icon: "fa fa-times",
68
+ hasValue: false,
69
+ }, {
70
+ value: "original",
71
+ label: "Originalnachricht",
72
+ icon: "fa fa-arrow-right",
73
+ hasValue: false,
74
+ }],
56
75
  typeField: "#node-input-out_lower_type"
57
76
  });
58
77
 
78
+ $("#node-input-send_only_change").typedInput({
79
+ type: "bool",
80
+ types: [{
81
+ value: "1",
82
+ options: [
83
+ { value: "true", label: "Nur bei Änderung" },
84
+ { value: "false", label: "Immer" },
85
+ ]
86
+ }]
87
+ });
88
+
89
+ $("#node-input-outputs").typedInput({
90
+ type: "num",
91
+ types: [{
92
+ value: "1",
93
+ options: [
94
+ { value: "1", label: "Gemeinsamer Ausgang" },
95
+ { value: "2", label: "Separate Ausgänge" },
96
+ ]
97
+ }]
98
+ });
99
+
100
+
101
+
59
102
  $("#node-input-save_state").on("change", ev =>
60
103
  {
61
104
  if (ev.target.checked)
@@ -98,6 +141,20 @@
98
141
  <input type="text" id="node-input-out_lower" />
99
142
  <input type="hidden" id="node-input-out_lower_type">
100
143
  </div>
144
+ <div class="form-row">
145
+ <label for="node-input-send_only_change"><i class="fa fa-repeat"></i> Senden</label>
146
+ <input id="node-input-send_only_change" />
147
+ </div>
148
+ <div class="form-row">
149
+ <label for="node-input-outputs"><i class="fa fa-hashtag"></i> Ausgänge</label>
150
+ <input id="node-input-outputs" />
151
+ </div>
152
+ <div class="form-row">
153
+ <div><strong>Hinweis:</strong></div>
154
+ <div><code>msg.payload</code> wird automatisch auf das Hystere-Ergebnis gesetzt,</div>
155
+ <div>sofern es nicht bereits hier in der Konfiguration gesetzt wurde.</div>
156
+ <div><code>true</code>, wenn höher, <code>false</code> wenn niedriger.</div>
157
+ </div>
101
158
  <hr/>
102
159
  <h4 style="margin: 0.5rem 0;">Systemstart</h4>
103
160
  <div class="form-row">
@@ -139,10 +196,6 @@
139
196
  <td><code>hysteresis</code></td>
140
197
  <td>Überschreibt die Hysterese mit <code>msg.payload</code>.</td>
141
198
  </tr>
142
- <tr>
143
- <td><code>resend</code></td>
144
- <td>Sendet den aktuellen Zustand erneut.</td>
145
- </tr>
146
199
  </tbody>
147
200
  </table>
148
201
  </p>