smart-nodes 0.3.36 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +35 -17
  3. package/central/central.html +27 -24
  4. package/central/central.js +84 -26
  5. package/central/locales/de-DE/central.html +10 -0
  6. package/central/locales/de-DE/central.json +14 -0
  7. package/central/locales/en-US/central.html +10 -0
  8. package/central/locales/en-US/central.json +14 -0
  9. package/compare/compare.html +64 -87
  10. package/compare/compare.js +69 -29
  11. package/compare/locales/de-DE/compare.html +36 -0
  12. package/compare/locales/de-DE/compare.json +35 -0
  13. package/compare/locales/en-US/compare.html +36 -0
  14. package/compare/locales/en-US/compare.json +35 -0
  15. package/counter/counter.html +70 -72
  16. package/counter/counter.js +43 -20
  17. package/counter/locales/de-DE/counter.html +48 -0
  18. package/counter/locales/de-DE/counter.json +21 -0
  19. package/counter/locales/en-US/counter.html +48 -0
  20. package/counter/locales/en-US/counter.json +21 -0
  21. package/delay/delay.html +30 -102
  22. package/delay/delay.js +63 -20
  23. package/delay/locales/de-DE/delay.html +71 -0
  24. package/delay/locales/de-DE/delay.json +19 -0
  25. package/delay/locales/en-US/delay.html +76 -0
  26. package/delay/locales/en-US/delay.json +19 -0
  27. package/forwarder/forwarder.html +11 -42
  28. package/forwarder/forwarder.js +59 -18
  29. package/forwarder/locales/de-DE/forwarder.html +32 -0
  30. package/forwarder/locales/de-DE/forwarder.json +15 -0
  31. package/forwarder/locales/en-US/forwarder.html +32 -0
  32. package/forwarder/locales/en-US/forwarder.json +15 -0
  33. package/heating-curve/heating-curve.html +10 -51
  34. package/heating-curve/heating-curve.js +38 -13
  35. package/heating-curve/locales/de-DE/heating-curve.html +38 -0
  36. package/heating-curve/locales/de-DE/heating-curve.json +12 -0
  37. package/heating-curve/locales/en-US/heating-curve.html +38 -0
  38. package/heating-curve/locales/en-US/heating-curve.json +12 -0
  39. package/hysteresis/hysteresis.html +49 -69
  40. package/hysteresis/hysteresis.js +94 -68
  41. package/hysteresis/locales/de-DE/hysteresis.html +36 -0
  42. package/hysteresis/locales/de-DE/hysteresis.json +27 -0
  43. package/hysteresis/locales/en-US/hysteresis.html +36 -0
  44. package/hysteresis/locales/en-US/hysteresis.json +27 -0
  45. package/light/light.html +250 -0
  46. package/{light-control/light-control.js → light/light.js} +151 -32
  47. package/light/locales/de-DE/light.html +149 -0
  48. package/light/locales/de-DE/light.json +24 -0
  49. package/light/locales/en-US/light.html +148 -0
  50. package/light/locales/en-US/light.json +24 -0
  51. package/logic/locales/de-DE/logic.html +12 -0
  52. package/logic/locales/de-DE/logic.json +26 -0
  53. package/logic/locales/en-US/logic.html +12 -0
  54. package/logic/locales/en-US/logic.json +26 -0
  55. package/logic/logic.html +48 -64
  56. package/logic/logic.js +63 -29
  57. package/long-press/locales/de-DE/long-press.html +5 -0
  58. package/long-press/locales/de-DE/long-press.json +13 -0
  59. package/long-press/locales/en-US/long-press.html +5 -0
  60. package/long-press/locales/en-US/long-press.json +13 -0
  61. package/{long-press-control/long-press-control.html → long-press/long-press.html} +10 -14
  62. package/long-press/long-press.js +163 -0
  63. package/mixing-valve/locales/de-DE/mixing-valve.html +65 -0
  64. package/mixing-valve/locales/de-DE/mixing-valve.json +19 -0
  65. package/mixing-valve/locales/en-US/mixing-valve.html +66 -0
  66. package/mixing-valve/locales/en-US/mixing-valve.json +19 -0
  67. package/mixing-valve/mixing-valve.html +27 -93
  68. package/mixing-valve/mixing-valve.js +87 -61
  69. package/multi-press/locales/de-DE/multi-press.html +5 -0
  70. package/multi-press/locales/de-DE/multi-press.json +12 -0
  71. package/multi-press/locales/en-US/multi-press.html +5 -0
  72. package/multi-press/locales/en-US/multi-press.json +12 -0
  73. package/{multi-press-control/multi-press-control.html → multi-press/multi-press.html} +9 -13
  74. package/{multi-press-control/multi-press-control.js → multi-press/multi-press.js} +53 -5
  75. package/package.json +7 -7
  76. package/persistence.js +1 -0
  77. package/scene/locales/de-DE/scene.html +105 -0
  78. package/scene/locales/de-DE/scene.json +21 -0
  79. package/scene/locales/en-US/scene.html +107 -0
  80. package/scene/locales/en-US/scene.json +20 -0
  81. package/{scene-control/scene-control.html → scene/scene.html} +30 -132
  82. package/{scene-control/scene-control.js → scene/scene.js} +76 -26
  83. package/scheduler/locales/de-DE/scheduler.html +30 -0
  84. package/scheduler/locales/de-DE/scheduler.json +21 -0
  85. package/scheduler/locales/en-US/scheduler.html +30 -0
  86. package/scheduler/locales/en-US/scheduler.json +21 -0
  87. package/scheduler/scheduler.html +34 -64
  88. package/scheduler/scheduler.js +85 -53
  89. package/shutter/locales/de-DE/shutter.html +127 -0
  90. package/shutter/locales/de-DE/shutter.json +11 -0
  91. package/shutter/locales/en-US/shutter.html +133 -0
  92. package/shutter/locales/en-US/shutter.json +11 -0
  93. package/{shutter-control/shutter-control.html → shutter/shutter.html} +7 -133
  94. package/{shutter-control/shutter-control.js → shutter/shutter.js} +116 -56
  95. package/shutter-complex/locales/de-DE/shutter-complex.html +120 -0
  96. package/shutter-complex/locales/de-DE/shutter-complex.json +20 -0
  97. package/shutter-complex/locales/en-US/shutter-complex.html +120 -0
  98. package/shutter-complex/locales/en-US/shutter-complex.json +20 -0
  99. package/{shutter-complex-control/shutter-complex-control.html → shutter-complex/shutter-complex.html} +36 -140
  100. package/shutter-complex/shutter-complex.js +578 -0
  101. package/smart_helper.js +52 -9
  102. package/statistic/locales/de-DE/statistic.html +10 -0
  103. package/statistic/locales/de-DE/statistic.json +29 -0
  104. package/statistic/locales/en-US/statistic.html +10 -0
  105. package/statistic/locales/en-US/statistic.json +29 -0
  106. package/statistic/statistic.html +38 -43
  107. package/statistic/statistic.js +57 -28
  108. package/text-exec/locales/de-DE/text-exec.html +18 -0
  109. package/text-exec/locales/de-DE/text-exec.json +7 -0
  110. package/text-exec/locales/en-US/text-exec.html +18 -0
  111. package/text-exec/locales/en-US/text-exec.json +7 -0
  112. package/text-exec/text-exec.html +9 -25
  113. package/text-exec/text-exec.js +43 -2
  114. package/light-control/light-control.html +0 -363
  115. package/long-press-control/long-press-control.js +0 -76
  116. package/shutter-complex-control/shutter-complex-control.js +0 -442
@@ -7,11 +7,25 @@ module.exports = function (RED)
7
7
  const node = this;
8
8
  RED.nodes.createNode(node, config);
9
9
 
10
+
11
+ // ###################
12
+ // # Class constants #
13
+ // ###################
14
+ const ADJUST_OPEN = 0;
15
+ const ADJUST_CLOSE = 1;
16
+
17
+
18
+ // #######################
19
+ // # Global help objects #
20
+ // #######################
10
21
  const smart_context = require("../persistence.js")(RED);
11
22
  const helper = require("../smart_helper.js");
12
23
 
13
- // persistent values
14
- var node_settings = Object.assign({}, {
24
+
25
+ // #####################
26
+ // # persistent values #
27
+ // #####################
28
+ var node_settings = helper.cloneObject({
15
29
  enabled: config.enabled,
16
30
  setpoint: config.setpoint,
17
31
  off_mode: config.off_mode,
@@ -19,21 +33,46 @@ module.exports = function (RED)
19
33
  last_position: null
20
34
  }, smart_context.get(node.id));
21
35
 
22
- // dynamic config
36
+
37
+ // ##################
38
+ // # Dynamic config #
39
+ // ##################
23
40
  let time_total = config.time_total;
24
41
  let time_sampling = config.time_sampling;
25
42
 
26
- // runtime values
43
+
44
+ // ##################
45
+ // # Runtime values #
46
+ // ##################
47
+
48
+ // Here the setInterval return value is stored which is used to recheck the valve position
27
49
  let sampling_interval = null;
50
+
51
+ // Here the setTimeout return value is stored to stop the calibration time.
28
52
  let calibration_timeout = null;
53
+
54
+ // Here the setTimeout return value is stored to stop the valve adjustment.
29
55
  let changing_timeout = null;
30
- let changing_open = null;
56
+
57
+ // Store the direction of the adjustment
58
+ let adjusting = null;
59
+
60
+ // Stores the current temperature which is used to determine the adjusting direction
31
61
  let current_temperature = null;
32
- let changing_start_time = null;
33
62
 
63
+ // The start time of the adjustment to count the change
64
+ let adjusting_start_time = null;
65
+
66
+
67
+ // ###############
68
+ // # Node events #
69
+ // ###############
34
70
  node.on("input", function (msg)
35
71
  {
36
72
  handleTopic(msg);
73
+
74
+ setStatus();
75
+ smart_context.set(node.id, node_settings);
37
76
  });
38
77
 
39
78
  node.on("close", function ()
@@ -53,14 +92,22 @@ module.exports = function (RED)
53
92
  });
54
93
 
55
94
 
95
+ // #####################
96
+ // # Private functions #
97
+ // #####################
98
+
99
+ // This is the main function which handles all topics that was received.
56
100
  let handleTopic = msg =>
57
101
  {
58
102
  let real_topic = helper.getTopicName(msg.topic);
103
+
104
+ if (real_topic == "set_state")
105
+ real_topic = (!!msg.payload) ? "enable" : "disable";
106
+
59
107
  switch (real_topic)
60
108
  {
61
109
  case "enable":
62
110
  node_settings.enabled = true;
63
- smart_context.set(node.id, node_settings);
64
111
 
65
112
  stopChanging();
66
113
  startSampling();
@@ -68,37 +115,20 @@ module.exports = function (RED)
68
115
 
69
116
  case "disable":
70
117
  node_settings.enabled = false;
71
- smart_context.set(node.id, node_settings);
72
118
 
73
119
  stopSampling();
74
120
  doOffMode();
75
121
  break;
76
122
 
77
- case "set_state":
78
- node_settings.enabled = !!msg.payload; // force boolean
79
- smart_context.set(node.id, node_settings);
80
-
81
- if (node_settings.enabled)
82
- {
83
- startSampling();
84
- }
85
- else
86
- {
87
- stopSampling();
88
- doOffMode();
89
- }
90
- break;
91
-
92
123
  case "setpoint":
93
124
  let new_setpoint = parseFloat(msg.payload);
94
125
  if (isNaN(new_setpoint) && !isFinite(new_setpoint))
95
126
  {
96
- // node.error("Invalid payload: " + msg.payload);
127
+ console.warn("Invalid payload: " + msg.payload);
97
128
  return;
98
129
  }
130
+
99
131
  node_settings.setpoint = new_setpoint;
100
- smart_context.set(node.id, node_settings);
101
- node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": New setpoint " + new_setpoint });
102
132
  break;
103
133
 
104
134
  case "off_mode":
@@ -108,11 +138,14 @@ module.exports = function (RED)
108
138
  case "OPEN":
109
139
  case "CLOSE":
110
140
  node_settings.off_mode = msg.payload;
111
- smart_context.set(node.id, node_settings);
112
141
 
113
142
  if (!node_settings.enabled)
114
143
  doOffMode();
115
144
  break;
145
+
146
+ default:
147
+ console.warn("Invalid off_mode: " + msg.payload);
148
+ return;
116
149
  }
117
150
  break;
118
151
 
@@ -122,12 +155,13 @@ module.exports = function (RED)
122
155
  case "HEATING":
123
156
  case "COOLING":
124
157
  node_settings.valve_mode = msg.payload;
125
- smart_context.set(node.id, node_settings);
126
158
  setStatus();
127
159
  break;
160
+
161
+ default:
162
+ console.warn("Invalid valve_mode: " + msg.payload);
163
+ return;
128
164
  }
129
- node_settings.enabled = true;
130
- smart_context.set(node.id, node_settings);
131
165
 
132
166
  startSampling();
133
167
  break;
@@ -136,11 +170,10 @@ module.exports = function (RED)
136
170
  let new_temp = parseFloat(msg.payload);
137
171
  if (isNaN(new_temp) && !isFinite(new_temp))
138
172
  {
139
- // node.error("Invalid payload: " + msg.payload);
173
+ console.warn("Invalid payload for current_temperature: " + msg.payload);
140
174
  return;
141
175
  }
142
176
  current_temperature = new_temp;
143
- setStatus();
144
177
  break;
145
178
 
146
179
  case "calibrate":
@@ -148,7 +181,7 @@ module.exports = function (RED)
148
181
  break;
149
182
 
150
183
  default:
151
- node.error("Invalid topic: " + real_topic);
184
+ console.warn("Invalid topic: " + real_topic);
152
185
  return;
153
186
  }
154
187
  }
@@ -208,55 +241,50 @@ module.exports = function (RED)
208
241
  }
209
242
 
210
243
  // calculate direction
211
- let do_open = false;
244
+ let adjustAction = ADJUST_CLOSE;
212
245
  if (current_temperature < node_settings.setpoint)
213
246
  {
214
247
  if (node_settings.valve_mode == "HEATING")
215
- do_open = true;
248
+ adjustAction = ADJUST_OPEN;
216
249
  }
217
250
  else
218
251
  {
219
252
  if (node_settings.valve_mode == "COOLING")
220
- do_open = true;
253
+ adjustAction = ADJUST_OPEN;
221
254
  }
222
255
 
223
256
  // start moving
224
- startChanging(do_open, moving_time);
225
-
226
- setStatus();
257
+ startChanging(adjustAction, moving_time);
227
258
  }
228
259
 
229
- let startChanging = (do_open, time_ms) =>
260
+ let startChanging = (adjustAction, time_ms) =>
230
261
  {
231
262
  stopChanging();
232
263
 
233
264
  // Already oppened/closed
234
- if (do_open && node_settings.last_position == 100)
265
+ if (adjustAction == ADJUST_OPEN && node_settings.last_position == 100)
235
266
  return;
236
- if (!do_open && node_settings.last_position == 0)
267
+ if (adjustAction == ADJUST_CLOSE && node_settings.last_position == 0)
237
268
  return;
238
269
 
239
- changing_start_time = Date.now();
240
- if (do_open)
270
+ adjusting_start_time = Date.now();
271
+ if (adjustAction == ADJUST_OPEN)
241
272
  node.send([{ payload: true }, { payload: false }, null]);
242
273
  else
243
274
  node.send([{ payload: false }, { payload: true }, null]);
244
275
 
245
- node.status({
246
- fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": Start " + (do_open ? "opening" : "closing") + " for " + helper.formatMsToStatus(time_ms)
247
- });
248
-
249
- changing_open = do_open;
276
+ adjusting = adjustAction;
250
277
  changing_timeout = setTimeout(() =>
251
278
  {
252
279
  changing_timeout = null;
253
280
  stopChanging();
281
+ setStatus();
254
282
  }, time_ms);
255
-
256
283
  }
257
284
 
258
285
  let stopChanging = () =>
259
286
  {
287
+ // Stop any runnting timeout
260
288
  if (changing_timeout !== null)
261
289
  {
262
290
  clearTimeout(changing_timeout);
@@ -264,15 +292,15 @@ module.exports = function (RED)
264
292
  }
265
293
 
266
294
  // No changing in progress
267
- if (changing_start_time == null)
295
+ if (adjusting_start_time == null)
268
296
  return;
269
297
 
270
298
  // Calculate moved percentage
271
- let time_passed = (Date.now() - changing_start_time) / 1000;
272
- changing_start_time = null;
299
+ let time_passed = (Date.now() - adjusting_start_time) / 1000;
300
+ adjusting_start_time = null;
273
301
 
274
302
  let changed_value = (time_passed / time_total) * 100; // calculate in % value (0-100)
275
- if (changing_open)
303
+ if (adjusting == ADJUST_OPEN)
276
304
  node_settings.last_position += changed_value;
277
305
  else
278
306
  node_settings.last_position -= changed_value;
@@ -280,9 +308,6 @@ module.exports = function (RED)
280
308
  // Only values from 0 to 100 are allowed
281
309
  node_settings.last_position = Math.min(Math.max(node_settings.last_position, 0), 100);
282
310
 
283
- // Save state
284
- smart_context.set(node.id, node_settings);
285
-
286
311
  node.send([{ payload: false }, { payload: false }, { payload: node_settings.last_position.toFixed(1) }]);
287
312
 
288
313
  setStatus();
@@ -302,6 +327,7 @@ module.exports = function (RED)
302
327
 
303
328
  // Calibration finished, start sampling if enabled
304
329
  calibration_timeout = null;
330
+
305
331
  if (node_settings.enabled)
306
332
  startSampling();
307
333
  else
@@ -309,8 +335,6 @@ module.exports = function (RED)
309
335
 
310
336
  setStatus();
311
337
  }, time_total * 1000);
312
-
313
- setStatus();
314
338
  }
315
339
 
316
340
  let doOffMode = () =>
@@ -318,11 +342,11 @@ module.exports = function (RED)
318
342
  switch (node_settings.off_mode)
319
343
  {
320
344
  case "OPEN":
321
- startChanging(true, time_total * 1000);
345
+ startChanging(ADJUST_OPEN, time_total * 1000);
322
346
  break;
323
347
 
324
348
  case "CLOSE":
325
- startChanging(false, time_total * 1000);
349
+ startChanging(ADJUST_CLOSE, time_total * 1000);
326
350
  break;
327
351
 
328
352
  case "NOTHING":
@@ -335,6 +359,8 @@ module.exports = function (RED)
335
359
  {
336
360
  if (calibration_timeout !== null)
337
361
  node.status({ fill: "yellow", shape: "ring", text: helper.getCurrentTimeForStatus() + ": In calibration" });
362
+ else if (changing_timeout != null)
363
+ node.status({ fill: node_settings.enabled ? "green" : "red", shape: "ring", text: helper.getCurrentTimeForStatus() + ": " + (node_settings.valve_mode == "HEATING" ? "🔥" : "❄️") + " " + (adjusting == ADJUST_OPEN ? "Opening" : "Closing") + ", Set: " + node_settings.setpoint?.toFixed(1) + "°C, Cur: " + current_temperature?.toFixed(1) + "°C, Pos: " + node_settings.last_position?.toFixed(1) + "%" });
338
364
  else
339
365
  node.status({ fill: node_settings.enabled ? "green" : "red", shape: "dot", text: helper.getCurrentTimeForStatus() + ": " + (node_settings.valve_mode == "HEATING" ? "🔥" : "❄️") + " Set: " + node_settings.setpoint?.toFixed(1) + "°C, Cur: " + current_temperature?.toFixed(1) + "°C, Pos: " + node_settings.last_position?.toFixed(1) + "%" });
340
366
  }
@@ -0,0 +1,5 @@
1
+ <script type="text/html" data-help-name="smart_multi-press-control">
2
+ <p>Diese Node zählt mit, wie oft eine bestimmte Taste gedrückt wurde. Ein weiterer Tastendruck muss innerhalb der eingestellten Zeit erfolgen.</p>
3
+ <p>Wenn nach der eingestellten Zeit kein weiterer Tastendruck vorgenommen wird, so wird eine Nachricht mit dem eingestellen Inhalt an den entsprechenden Ausgang geschickt.</p>
4
+ <p>Ist die maximale Anzahl an Tastendrücken erreicht, wird sofort eine Nachricht rausgeschickt. Weitere Tastendrücke werden wieder von vorne gezählt und ausgewertet.</p>
5
+ </script>
@@ -0,0 +1,12 @@
1
+ {
2
+ "multi-press": {
3
+ "ui": {
4
+ "name": "Name",
5
+ "count_presses": "Anzahl Tastendrücke",
6
+ "count_presses_placeholder": "Max Anzahl an Tastendrücke",
7
+ "time_interval": "Zeitabstand",
8
+ "time_interval_placeholder": "Max Zeit in ms zwischen Tastendruck",
9
+ "output_messages": "Ausgangsnachrichten"
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,5 @@
1
+ <script type="text/html" data-help-name="smart_multi-press-control">
2
+ <p>This node counts how often a certain key has been pressed. A further key press must be made within the set time.</p>
3
+ <p>If no further key press is made after the set time, a message with the set content is sent to the corresponding output.</p>
4
+ <p>If the maximum number of key presses is reached, a message is sent out immediately. Further key presses are counted and evaluated from the beginning again.</p>
5
+ </script>
@@ -0,0 +1,12 @@
1
+ {
2
+ "multi-press": {
3
+ "ui": {
4
+ "name": "Name",
5
+ "count_presses": "Number of keypresses",
6
+ "count_presses_placeholder": "Max number of keypresses",
7
+ "time_interval": "Time interval",
8
+ "time_interval_placeholder": "Max time in ms between keypresses",
9
+ "output_messages": "Output messages"
10
+ }
11
+ }
12
+ }
@@ -25,6 +25,8 @@
25
25
  },
26
26
  oneditprepare: function ()
27
27
  {
28
+ let node = this;
29
+
28
30
  $("#node-input-outputs").spinner({
29
31
  min: 2,
30
32
  max: 4,
@@ -96,20 +98,20 @@
96
98
 
97
99
  <script type="text/html" data-template-name="smart_multi-press-control">
98
100
  <div class="form-row">
99
- <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
100
- <input type="text" id="node-input-name" placeholder="Name" />
101
+ <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="multi-press.ui.name"></span></label>
102
+ <input type="text" id="node-input-name" data-i18n="[placeholder]multi-press.ui.name" />
101
103
  </div>
102
104
  <div class="form-row">
103
- <label for="node-input-outputs" style="vertical-align: middle"><i class="fa fa-hand-o-up"></i> Anzahl Tastendrücke</label>
104
- <input id="node-input-outputs" placeholder="Max Anzahl an Tastendrücke" />
105
+ <label for="node-input-outputs" style="vertical-align: middle"><i class="fa fa-hand-o-up"></i> <span data-i18n="multi-press.ui.count_presses"></span></label>
106
+ <input id="node-input-outputs" data-i18n="[placeholder]multi-press.ui.count_presses_placeholder" placeholder="" />
105
107
  </div>
106
108
  <div class="form-row">
107
- <label for="node-input-press_delay_ms"><i class="fa fa-clock-o"></i> Zeitabstand</label>
108
- <input id="node-input-press_delay_ms" placeholder="Max Zeit in ms zwischen Tastendruck" />
109
+ <label for="node-input-press_delay_ms"><i class="fa fa-clock-o"></i> <span data-i18n="multi-press.ui.time_interval"></span></label>
110
+ <input id="node-input-press_delay_ms" data-i18n="[placeholder]multi-press.ui.time_interval_placeholder" placeholder="" />
109
111
  <span> ms</span>
110
112
  </div>
111
113
  <hr/>
112
- <h4 style="margin: 0.5rem 0;">Ausgangsnachrichten</h4>
114
+ <h4 style="margin: 0.5rem 0;" data-i18n="multi-press.ui.output_messages"></h4>
113
115
  <div class="form-row">
114
116
  <label for="node-input-out1"><i class="fa fa-hand-o-up"></i> 1x</label>
115
117
  <input type="text" id="node-input-out1" />
@@ -126,10 +128,4 @@
126
128
  <label for="node-input-out4"><i class="fa fa-hand-o-up"></i> 4x</label>
127
129
  <input type="text" id="node-input-out4" />
128
130
  </div>
129
- </script>
130
-
131
- <script type="text/html" data-help-name="smart_multi-press-control">
132
- <p>Diese Node zählt mit, wie oft eine bestimmte Taste gedrückt wurde. Ein weiterer Tastendruck muss innerhalb der eingestellten Zeit erfolgen.</p>
133
- <p>Wenn nach der eingestellten Zeit kein weiterer Tastendruck vorgenommen wird, so wird eine Nachricht mit dem eingestellen Inhalt an den entsprechenden Ausgang geschickt.</p>
134
- <p>Ist die maximale Anzahl an Tastendrücken erreicht, wird sofort eine Nachricht rausgeschickt. Weitere Tastendrücke werden wieder von vorne gezählt und ausgewertet.</p>
135
131
  </script>
@@ -7,9 +7,27 @@ module.exports = function (RED)
7
7
  const node = this;
8
8
  RED.nodes.createNode(node, config);
9
9
 
10
+
11
+ // ###################
12
+ // # Class constants #
13
+ // ###################
14
+
15
+
16
+ // #######################
17
+ // # Global help objects #
18
+ // #######################
19
+ const smart_context = require("../persistence.js")(RED);
10
20
  const helper = require("../smart_helper.js");
11
21
 
12
- // dynamic config
22
+
23
+ // #####################
24
+ // # persistent values #
25
+ // #####################
26
+
27
+
28
+ // ##################
29
+ // # Dynamic config #
30
+ // ##################
13
31
  let press_delay_ms = parseInt(config.press_delay_ms || 200, 10);
14
32
  let outs = [
15
33
  helper.evaluateNodeProperty(RED, config.out1, "json"),
@@ -18,12 +36,21 @@ module.exports = function (RED)
18
36
  helper.evaluateNodeProperty(RED, config.out4, "json")
19
37
  ];
20
38
 
21
- // runtime values
39
+
40
+ // ##################
41
+ // # Runtime values #
42
+ // ##################
43
+
44
+ // Count the number of current presses
22
45
  let count = 0;
46
+
47
+ // Here the setTimeout return value is stored to detect end of multipress.
23
48
  let timeout = null;
24
49
 
25
- node.status({});
26
50
 
51
+ // ###############
52
+ // # Node events #
53
+ // ###############
27
54
  node.on("input", function (msg)
28
55
  {
29
56
  if (msg.payload)
@@ -39,6 +66,13 @@ module.exports = function (RED)
39
66
  }
40
67
  });
41
68
 
69
+
70
+ // #####################
71
+ // # Private functions #
72
+ // #####################
73
+ /**
74
+ * This function start/restarts the timer and increase the counter by one.
75
+ */
42
76
  let startTimeout = () =>
43
77
  {
44
78
  count++;
@@ -49,18 +83,32 @@ module.exports = function (RED)
49
83
  timeout = null;
50
84
  }
51
85
 
86
+ // If maximum presses are detected, send result immediately
87
+ // Otherwise start timeout
52
88
  if (count == config.outputs)
53
89
  sendResult();
54
90
  else
55
- timeout = setTimeout(sendResult, press_delay_ms);
91
+ timeout = setTimeout(() =>
92
+ {
93
+ timeout = null;
94
+ sendResult();
95
+ }, press_delay_ms);
56
96
  }
57
97
 
98
+ /**
99
+ * This function is called if the number of presses should be send to the output.
100
+ */
58
101
  let sendResult = () =>
59
102
  {
60
103
  node.status({ fill: "green", shape: "dot", text: helper.getCurrentTimeForStatus() + ": Last was press " + count + " time" + (count == 1 ? "" : "s") });
104
+
105
+ // Prepare data
61
106
  let data = Array.from({ length: config.outputs }).fill(null);
62
- data[count - 1] = outs[count - 1];
107
+ // Send a copy of the defined json
108
+ data[count - 1] = helper.cloneObject(outs[count - 1]);
63
109
  node.send(data);
110
+
111
+ // Reset values
64
112
  count = 0;
65
113
  timeout = null;
66
114
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-nodes",
3
- "version": "0.3.36",
3
+ "version": "0.4.0",
4
4
  "description": "Smart Nodes",
5
5
  "keywords": [
6
6
  "node-red",
@@ -34,12 +34,12 @@
34
34
  "node-red": {
35
35
  "version": ">=1.0.0",
36
36
  "nodes": {
37
- "light-control": "light-control/light-control.js",
38
- "scene-control": "scene-control/scene-control.js",
39
- "shutter-control": "shutter-control/shutter-control.js",
40
- "shutter-complex-control": "shutter-complex-control/shutter-complex-control.js",
41
- "long-press-control": "long-press-control/long-press-control.js",
42
- "multi-press-control": "multi-press-control/multi-press-control.js",
37
+ "light": "light/light.js",
38
+ "scene": "scene/scene.js",
39
+ "shutter": "shutter/shutter.js",
40
+ "shutter-complex": "shutter-complex/shutter-complex.js",
41
+ "long-press": "long-press/long-press.js",
42
+ "multi-press": "multi-press/multi-press.js",
43
43
  "logic": "logic/logic.js",
44
44
  "forwarder": "forwarder/forwarder.js",
45
45
  "compare": "compare/compare.js",
package/persistence.js CHANGED
@@ -66,6 +66,7 @@ module.exports = function (_RED)
66
66
 
67
67
  function del(id)
68
68
  {
69
+ hasChanges = true;
69
70
  delete globalData["id" + id];
70
71
  }
71
72
 
@@ -0,0 +1,105 @@
1
+ <script type="text/html" data-help-name="smart_scene-control">
2
+ <p>
3
+ Diese Node steuert mehrere Ausgänge die anhand einer definierten Szene ein- bzw. ausgeschaltet werden.
4
+ An jeden Ausgang wird immer <code>msg.payload = true</code> oder <code>msg.payload = false</code> gesendet um ihn ein-, bzw. auszuschalten.
5
+ </p>
6
+ <p>
7
+ <b>Hinweis:</b> Smart Nodes verwenden Topics im Format <code>name#nummer</code>, damit können verschiedene Smart Nodes mit dem gleichen Topic angesteuert werden.<br/>
8
+ Diese Node verwendet sowohl den Teil <code>name</code> als auch <code>nummer</code>. Je nach Nachricht müssen evtl. beide Werte gesetzt sein.
9
+ </p>
10
+ <p>
11
+ Folgende topics werden akzeptiert:
12
+ <table>
13
+ <thead>
14
+ <tr>
15
+ <th>Topic</th>
16
+ <th>Beschreibung</th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <tr>
21
+ <td><code>status#2</code></td>
22
+ <td>
23
+ Gibt über <code>msg.payload = true</code> oder <code>msg.payload = false</code> den aktuellen Status des Ausgangs <code>2</code> an.<br/>
24
+ Bei einem Wechsel eines Ausgangs wird die Zeitmessung für die hinterlegte, bzw. mitgesendete Zeit gestartet, sofern vorhanden.
25
+ </td>
26
+ </tr>
27
+ <tr>
28
+ <td><code>on</code></td>
29
+ <td>Schaltet alle Ausgänge ein und startet die Zeitmessung für die hinterlegte, bzw. mitgesendete Zeit gestartet, sofern vorhanden.</td>
30
+ </tr>
31
+ <tr>
32
+ <td><code>off</code></td>
33
+ <td>Schaltet alle Ausgänge aus.</td>
34
+ </tr>
35
+ <tr>
36
+ <td><code>set</code></td>
37
+ <td>
38
+ Schaltet alle Ausgänge bei <code>msg.payload = true</code> ein und bei <code>msg.payload = false</code> aus.<br/>
39
+ Bei einem Wechsel von ausgeschaltet nach eingeschaltet wird die Zeitmessung für die hinterlegte, bzw. mitgesendete Zeit gestartet, sofern vorhanden.
40
+ </td>
41
+ </tr>
42
+ <tr>
43
+ <td><code>set_permanent</code></td>
44
+ <td>
45
+ Schaltet alle Ausgänge bei <code>msg.payload = true</code>dauerhaft ein und bei <code>msg.payload = false</code> aus.<br/>
46
+ Es wird dabei keine Zeitmessung gestartet.
47
+ </td>
48
+ </tr>
49
+ <tr>
50
+ <td><code>scene_x,y,z</code></td>
51
+ <td>
52
+ Schaltet die Ausgänge entsprechend der mitgegebenen Szenennummern (x, y und z) an, bzw. aus.<br/>
53
+ Beim Eintreffen der Nachricht wird geschaut welche Szene aktuell aktiv ist. Taucht die Nummer in der Liste auf, wird die nächste angegebene Szene aktiviert.<br/>
54
+ Taucht die Szene nicht in der Liste auf, wird die erste aufgelistete Szene aktiviert.<br/>
55
+ Wenn nur eine Szene angegeben ist, wechselt der Baustein zwischen der angegebenen Szene und aus.<br/>
56
+ Sollte mindestens ein Ausgang eingeschaltet sein, startet die Zeitmessung erneut.
57
+ </td>
58
+ </tr>
59
+ <tr>
60
+ <td><code>toggle</code> (default)</td>
61
+ <td>
62
+ Schaltet alle Ausgänge aus, falls mindestens einer bereits eingeschaltet wahr.<br/>
63
+ Sollten bereits alle Ausgänge ausgeschaltet sein, werden alle eingeschalten.
64
+ </td>
65
+ </tr>
66
+ </tbody>
67
+ </table>
68
+ </p>
69
+ <p>
70
+ Diese Node hat eine einstellbare Maximallaufzeit, bevor alle Ausgänge automatisch wieder ausgeschalten werden.
71
+ Diese Zeitmessung wird wie in der Tabelle oben verwendet.
72
+ Die eingestellte Zeit kann gezielt überschrieben werden.
73
+ Beispiel: <code>msg = { "topic": "on", "time_on": 5000 }</code> oder <code>msg = { "topic": "on", "time_on": "5s" }</code><br/>
74
+ Diese Nachricht schaltet das Licht für 5000 Millisekunden / 5 Sekunden an und anschließend wieder aus.
75
+ Die nächste Nachricht ohne <code>time_on</code> Angabe verwendet wieder die voreingestellte Zeit.
76
+ Ist die Zeit auf 0 eingestellt, wird das Licht <b>nicht</b> automatisch ausgeschalten.<br/>
77
+ Als Einheit für die Zeit können folgende Werte verwendet werden:
78
+ <table>
79
+ <thead>
80
+ <tr>
81
+ <th>Einheit</th>
82
+ <th>Beschreibung</th>
83
+ </tr>
84
+ </thead>
85
+ <tbody>
86
+ <tr>
87
+ <td><code>ms</code> (default)</td>
88
+ <td>Millisekunden</td>
89
+ </tr>
90
+ <tr>
91
+ <td><code>s</code> oder <code>sec</code></td>
92
+ <td>Sekunden</td>
93
+ </tr>
94
+ <tr>
95
+ <td><code>m</code> oder <code>min</code></td>
96
+ <td>Mintun.</td>
97
+ </tr>
98
+ <tr>
99
+ <td><code>h</code></td>
100
+ <td>Stunden</td>
101
+ </tr>
102
+ </tbody>
103
+ </table>
104
+ </p>
105
+ </script>