smart-nodes 0.4.13 → 0.4.15-beta

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 CHANGED
@@ -136,3 +136,18 @@
136
136
  ## Version 0.4.13:
137
137
 
138
138
  - Fixed text exec node again.
139
+
140
+ ## Version 0.4.14:
141
+
142
+ - Removed log outputs.
143
+
144
+ ## Version 0.5.0:
145
+
146
+ - Added new option to define node output format.
147
+
148
+ - Simple: Compatible with knx_ultimate nodes.
149
+ - HomeAssistant: Outputs messages that can directly be sent to home assistant entities via action nodes.
150
+
151
+ **Important Action node settings:**
152
+
153
+ - Disable option `Block input overrides`, so the smart nodes can control the actions and the sended data.
package/light/light.html CHANGED
@@ -139,6 +139,7 @@
139
139
  defaults: {
140
140
  name: { value: "" },
141
141
  exec_text_names: { value: "" },
142
+ data_type: { value: "SIMPLE" }, // SIMPLE || HOMEASSISTANT
142
143
  max_time_on: { value: "0" },
143
144
  max_time_on_unit: { value: "s" },
144
145
  alarm_action: { value: 'NOTHING' }, // NOTHING | ON | OFF
@@ -159,6 +160,19 @@
159
160
  onEditPrepare(this, ["smart_central-control"]);
160
161
  initTreeList(node, ["smart_central-control"]);
161
162
 
163
+ $("#node-input-data_type")
164
+ .css("max-width", "70%")
165
+ .typedInput({
166
+ types: [{
167
+ value: "data_type",
168
+ default: "SIMPLE",
169
+ options: [
170
+ { value: "SIMPLE", label: node._("light.ui.simple") },
171
+ { value: "HOMEASSISTANT", label: node._("light.ui.home_assistant") }
172
+ ],
173
+ }],
174
+ });
175
+
162
176
  $("#node-input-max_time_on")
163
177
  .css("max-width", "4rem")
164
178
  .spinner({
@@ -237,6 +251,10 @@
237
251
  <input id="node-input-exec_text_names" type="text" />
238
252
  <div style="max-width: 450px;" data-i18n="light.ui.controlled_by_words"></div>
239
253
  </div>
254
+ <div class="form-row">
255
+ <label for="node-input-data_type"><i class="fa fa-file-code-o"></i> <span data-i18n="light.ui.data_type"></span></label>
256
+ <input id="node-input-data_type"/>
257
+ </div>
240
258
  <div class="form-row">
241
259
  <label for="node-input-max_time_on"><i class="fa fa-clock-o"></i> <span data-i18n="light.ui.max_time_on"></span></label>
242
260
  <input id="node-input-max_time_on" value="0" />
package/light/light.js CHANGED
@@ -45,6 +45,7 @@ module.exports = function (RED)
45
45
  let max_time_on = helper.getTimeInMs(config.max_time_on, config.max_time_on_unit);
46
46
  let alarm_action = config.alarm_action || "NOTHING";
47
47
  let alarm_off_action = config.alarm_off_action || "NOTHING";
48
+ let data_type = config.data_type || "SIMPLE";
48
49
 
49
50
  // ##################
50
51
  // # Runtime values #
@@ -230,7 +231,7 @@ module.exports = function (RED)
230
231
  if (!node_settings.alarm_active)
231
232
  {
232
233
  isBlinking = true;
233
- node.send({ payload: !node_settings.last_value });
234
+ sendState(!node_settings.last_value)
234
235
  setStatus();
235
236
  setTimeout(
236
237
  () =>
@@ -238,7 +239,7 @@ module.exports = function (RED)
238
239
  isBlinking = false;
239
240
  if (!node_settings.alarm_active)
240
241
  {
241
- node.send({ payload: node_settings.last_value });
242
+ sendState(node_settings.last_value)
242
243
  setStatus();
243
244
  }
244
245
  },
@@ -283,7 +284,7 @@ module.exports = function (RED)
283
284
  }
284
285
 
285
286
  if (node_settings.alarm_active || helper.getTopicName(msg.topic) != "status")
286
- node.send({ payload: node_settings.last_value });
287
+ sendState(node_settings.last_value)
287
288
 
288
289
  // Output is on, now
289
290
  if (node_settings.last_value && doRestartTimer)
@@ -326,7 +327,7 @@ module.exports = function (RED)
326
327
  {
327
328
  timeout = null;
328
329
  node_settings.last_value = false;
329
- node.send({ payload: false });
330
+ sendTurnOff();
330
331
  notifyCentral(false);
331
332
 
332
333
  setStatus();
@@ -372,6 +373,67 @@ module.exports = function (RED)
372
373
  }
373
374
  }
374
375
 
376
+ /**
377
+ * Turns the output to the given state and returns the sent message
378
+ * @param {bool} state The new state of the output
379
+ * @returns The sent message
380
+ */
381
+ let sendState = state =>
382
+ {
383
+ if (state)
384
+ return sendTurnOn();
385
+
386
+ return sendTurnOff();
387
+ }
388
+
389
+ /**
390
+ * Turns the output on and returns the sent message
391
+ * @returns The sent message
392
+ */
393
+ let sendTurnOn = () =>
394
+ {
395
+ let data = null;
396
+ switch (data_type)
397
+ {
398
+ case "SIMPLE":
399
+ data = { payload: true };
400
+ break;
401
+
402
+ case "HOMEASSISTANT":
403
+ data = { payload: { action: "homeassistant.turn_on" } };
404
+ break;
405
+
406
+ default:
407
+ return null;
408
+ }
409
+ node.send(data);
410
+ return data;
411
+ }
412
+
413
+ /**
414
+ * Turns the output off and returns the sent message
415
+ * @returns The sent message
416
+ */
417
+ let sendTurnOff = () =>
418
+ {
419
+ let data = null;
420
+ switch (data_type)
421
+ {
422
+ case "SIMPLE":
423
+ data = { payload: false };
424
+ break;
425
+
426
+ case "HOMEASSISTANT":
427
+ data = { payload: { action: "homeassistant.turn_off" } };
428
+ break;
429
+
430
+ default:
431
+ return null;
432
+ }
433
+ node.send(data);
434
+ return data;
435
+ }
436
+
375
437
  /**
376
438
  * Notify all connected central nodes
377
439
  * @param {boolean} state The state if the light is on
@@ -4,6 +4,11 @@
4
4
  "name": "Name",
5
5
  "text": "Text",
6
6
  "controlled_by_words": "Diese Node kann über die eingegebenen Wörter gesteuert werden. Mehrere Wörter werden durch ein Komma getrennt.",
7
+
8
+ "data_type": "Datentyp",
9
+ "simple": "Einfaches Format",
10
+ "home_assistant": "HA Action Format",
11
+
7
12
  "max_time_on": "Max Zeit Ein",
8
13
  "alarm_on": "Alarm Ein",
9
14
  "alarm_off": "Alarm Aus",
@@ -4,6 +4,11 @@
4
4
  "name": "Name",
5
5
  "text": "Text",
6
6
  "controlled_by_words": "This node can be controlled using the words entered. Multiple words are separated by a comma.",
7
+
8
+ "data_type": "Data type",
9
+ "simple": "Simple format",
10
+ "home_assistant": "HA Action format",
11
+
7
12
  "max_time_on": "Max time on",
8
13
  "alarm_on": "Alarm on",
9
14
  "alarm_off": "Alarm off",
@@ -1,12 +1,12 @@
1
- <script type="text/html" data-help-name="smart_logic">
2
- <p>Dieser Knoten bietet verschiedene Logikoperationen, wie AND, OR und XOR an.</p>
3
- <p>Alle Eingänge, sowie der Ausgang lassen sich gezielt invertieren, womit weitere komplexe Logiken abgebildet werden können.</p>
4
- <p>Um beispielsweise eine NOT Logik zu erstellen, wird die Anzahl der Eingänge auf 1 gesetzt, die Logik auf AND oder OR und der Ausgang invertiert.</p>
5
- <p>
6
- <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/>
7
- Diese Node verwendet nur den Teil <code>nummer</code>. <code>name</code> und <code>#</code> sind dabei optional.
8
- </p>
9
- <p>
10
- <strong>Hinweis:</strong> <code>msg.payload</code> wird automatisch auf das Logik-Ergebnis gesetzt, sofern es nicht bereits in der Konfiguration gesetzt wurde.
11
- </p>
1
+ <script type="text/html" data-help-name="smart_logic">
2
+ <p>Dieser Knoten bietet verschiedene Logikoperationen, wie AND, OR und XOR an.</p>
3
+ <p>Alle Eingänge, sowie der Ausgang lassen sich gezielt invertieren, womit weitere komplexe Logiken abgebildet werden können.</p>
4
+ <p>Um beispielsweise eine NOT Logik zu erstellen, wird die Anzahl der Eingänge auf 1 gesetzt, die Logik auf AND oder OR und der Ausgang invertiert.</p>
5
+ <p>
6
+ <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/>
7
+ Diese Node verwendet nur den Teil <code>nummer</code>. <code>name</code> und <code>#</code> sind dabei optional.
8
+ </p>
9
+ <p>
10
+ <strong>Hinweis:</strong> <code>msg.payload</code> wird automatisch auf das Logik-Ergebnis gesetzt, sofern es nicht bereits in der Konfiguration gesetzt wurde.
11
+ </p>
12
12
  </script>
@@ -1,27 +1,27 @@
1
- {
2
- "logic": {
3
- "ui": {
4
- "name": "Name",
5
- "logic": "Logik",
6
- "inputs": "Eingänge",
7
- "invert": "Invertieren",
8
- "output": "Ausgang",
9
- "output_messages": "Ausgangsnachrichten",
10
- "true": "Wahr",
11
- "false": "Falsch",
12
- "send": "Senden",
13
- "outputs": "Ausgänge",
14
- "note": "Hinweis:",
15
- "note_text": "<code>msg.payload</code> wird automatisch auf das Logik-Ergebnis gesetzt,<br/>sofern es nicht bereits hier in der Konfiguration gesetzt wurde.",
16
- "system_start": "Systemstart",
17
- "save_state": "Zustand speichern",
18
- "send_after_start": "Letze Nachricht 10 Sekunden nach dem Start senden",
19
-
20
- "send_nothing": "Nichts senden",
21
- "send_only_change": "Nur bei Änderung",
22
- "always": "Immer",
23
- "common_output": "Gemeinsamer Ausgang",
24
- "separate_output": "Separate Ausgänge"
25
- }
26
- }
27
- }
1
+ {
2
+ "logic": {
3
+ "ui": {
4
+ "name": "Name",
5
+ "logic": "Logik",
6
+ "inputs": "Eingänge",
7
+ "invert": "Invertieren",
8
+ "output": "Ausgang",
9
+ "output_messages": "Ausgangsnachrichten",
10
+ "true": "Wahr",
11
+ "false": "Falsch",
12
+ "send": "Senden",
13
+ "outputs": "Ausgänge",
14
+ "note": "Hinweis:",
15
+ "note_text": "<code>msg.payload</code> wird automatisch auf das Logik-Ergebnis gesetzt,<br/>sofern es nicht bereits hier in der Konfiguration gesetzt wurde.",
16
+ "system_start": "Systemstart",
17
+ "save_state": "Zustand speichern",
18
+ "send_after_start": "Letze Nachricht 10 Sekunden nach dem Start senden",
19
+
20
+ "send_nothing": "Nichts senden",
21
+ "send_only_change": "Nur bei Änderung",
22
+ "always": "Immer",
23
+ "common_output": "Gemeinsamer Ausgang",
24
+ "separate_output": "Separate Ausgänge"
25
+ }
26
+ }
27
+ }
@@ -1,12 +1,12 @@
1
- <script type="text/html" data-help-name="smart_logic">
2
- <p>This node offers various logic operations, such as AND, OR and XOR.</p>
3
- <p>All inputs and the output can be specifically inverted, which can be used to map further complex logic.</p>
4
- <p>For example, to create a NOT logic, the number of inputs is set to 1, the logic to AND or OR and the output is inverted.</p>
5
- <p>
6
- <b>Note:</b> Smart Nodes use topics in the format <code>name#number</code>, so that different Smart Nodes can be controlled with the same topic.<br />
7
- This node only uses the <code>number</code> part. <code>name</code> and <code>#</code> are optional.
8
- </p>
9
- <p>
10
- <strong>Note:</strong> <code>msg.payload</code> is automatically set to the logic result if it has not already been set in the configuration.
11
- </p>
1
+ <script type="text/html" data-help-name="smart_logic">
2
+ <p>This node offers various logic operations, such as AND, OR and XOR.</p>
3
+ <p>All inputs and the output can be specifically inverted, which can be used to map further complex logic.</p>
4
+ <p>For example, to create a NOT logic, the number of inputs is set to 1, the logic to AND or OR and the output is inverted.</p>
5
+ <p>
6
+ <b>Note:</b> Smart Nodes use topics in the format <code>name#number</code>, so that different Smart Nodes can be controlled with the same topic.<br />
7
+ This node only uses the <code>number</code> part. <code>name</code> and <code>#</code> are optional.
8
+ </p>
9
+ <p>
10
+ <strong>Note:</strong> <code>msg.payload</code> is automatically set to the logic result if it has not already been set in the configuration.
11
+ </p>
12
12
  </script>
@@ -1,27 +1,27 @@
1
- {
2
- "logic": {
3
- "ui": {
4
- "name": "Name",
5
- "logic": "Logic",
6
- "inputs": "Inputs",
7
- "invert": "Invert",
8
- "output": "Output",
9
- "output_messages": "Output messages",
10
- "true": "True",
11
- "false": "False",
12
- "send": "Send",
13
- "outputs": "Outputs",
14
- "note": "Note:",
15
- "note_text": "<code>msg.payload</code> is automatically set to the logic result<br/>if it has not already been set here in the configuration.",
16
- "system_start": "System start",
17
- "save_state": "Save state",
18
- "send_after_start": "Send last message 10 seconds after start",
19
-
20
- "send_nothing": "Send nothing",
21
- "send_only_change": "Only on change",
22
- "always": "Always",
23
- "common_output": "Common output",
24
- "separate_output": "Separate outputs"
25
- }
26
- }
27
- }
1
+ {
2
+ "logic": {
3
+ "ui": {
4
+ "name": "Name",
5
+ "logic": "Logic",
6
+ "inputs": "Inputs",
7
+ "invert": "Invert",
8
+ "output": "Output",
9
+ "output_messages": "Output messages",
10
+ "true": "True",
11
+ "false": "False",
12
+ "send": "Send",
13
+ "outputs": "Outputs",
14
+ "note": "Note:",
15
+ "note_text": "<code>msg.payload</code> is automatically set to the logic result<br/>if it has not already been set here in the configuration.",
16
+ "system_start": "System start",
17
+ "save_state": "Save state",
18
+ "send_after_start": "Send last message 10 seconds after start",
19
+
20
+ "send_nothing": "Send nothing",
21
+ "send_only_change": "Only on change",
22
+ "always": "Always",
23
+ "common_output": "Common output",
24
+ "separate_output": "Separate outputs"
25
+ }
26
+ }
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-nodes",
3
- "version": "0.4.13",
3
+ "version": "0.4.15-beta",
4
4
  "description": "Smart Nodes",
5
5
  "keywords": [
6
6
  "node-red",
@@ -4,6 +4,11 @@
4
4
  "name": "Name",
5
5
  "text": "Text",
6
6
  "controlled_by_words": "Diese Node kann über die eingegebenen Wörter gesteuert werden. Mehrere Wörter werden durch ein Komma getrennt.",
7
+
8
+ "data_type": "Datentyp",
9
+ "simple": "Einfaches Format",
10
+ "home_assistant": "HA Action Format",
11
+
7
12
  "time_on": "Zeit Ein",
8
13
  "controlled_by_central": "Dieser Baustein wird von folgenden Zentralbausteinen gesteuert:",
9
14
 
@@ -4,6 +4,11 @@
4
4
  "name": "Name",
5
5
  "text": "Text",
6
6
  "controlled_by_words": "This node can be controlled using the words entered. Multiple words are separated by a comma.",
7
+
8
+ "data_type": "Data type",
9
+ "simple": "Simple format",
10
+ "home_assistant": "HA Action format",
11
+
7
12
  "time_on": "Time On",
8
13
  "controlled_by_central": "This block is controlled by the following central blocks:",
9
14
 
package/scene/scene.html CHANGED
@@ -144,7 +144,7 @@
144
144
  $("#node-input-property-outputs").editableList("height", outputHeight);
145
145
 
146
146
  // links tree list
147
- var rows = $("#dialog-form>div:not(#light-control-scenes)");
147
+ var rows = $("#dialog-form>div:not(#smart-control-scenes)");
148
148
  var height = $("#dialog-form").height();
149
149
  for (var i = 0; i < rows.length; i++)
150
150
  {
@@ -219,6 +219,7 @@
219
219
  defaults: {
220
220
  name: { value: "" },
221
221
  exec_text_names: { value: "" },
222
+ data_type: { value: "SIMPLE" }, // SIMPLE || HOMEASSISTANT
222
223
  max_time_on: { value: "0" },
223
224
  max_time_on_unit: { value: "s" },
224
225
  outputs: { value: 1 },
@@ -247,6 +248,19 @@
247
248
  onEditPrepare(this, ["smart_central-control"]);
248
249
  initTreeList(node, ["smart_central-control"]);
249
250
 
251
+ $("#node-input-data_type")
252
+ .css("max-width", "70%")
253
+ .typedInput({
254
+ types: [{
255
+ value: "data_type",
256
+ default: "SIMPLE",
257
+ options: [
258
+ { value: "SIMPLE", label: node._("scene.ui.simple") },
259
+ { value: "HOMEASSISTANT", label: node._("scene.ui.home_assistant") }
260
+ ],
261
+ }],
262
+ });
263
+
250
264
  // Output list
251
265
  var outputList = $("#node-input-property-outputs").css("min-height", "120px").css("min-width", "445px");
252
266
 
@@ -455,13 +469,17 @@
455
469
  <input id="node-input-exec_text_names" type="text" />
456
470
  <div style="max-width: 450px;" data-i18n="scene.ui.controlled_by_words"></div>
457
471
  </div>
472
+ <div class="form-row">
473
+ <label for="node-input-data_type"><i class="fa fa-file-code-o"></i> <span data-i18n="scene.ui.data_type"></span></label>
474
+ <input id="node-input-data_type"/>
475
+ </div>
458
476
  <div class="form-row">
459
477
  <label for="node-input-max_time_on"><i class="fa fa-clock-o"></i> <span data-i18n="scene.ui.time_on"></span></label>
460
478
  <input id="node-input-max_time_on" value="0" />
461
479
  <input id="node-input-max_time_on_unit" />
462
480
  </div>
463
481
 
464
- <div id="light-control-scenes">
482
+ <div id="smart-control-scenes">
465
483
  <div class="form-row scene-tabs-row">
466
484
  <ul style="min-width: 600px; margin-bottom: 20px;" id="scene-tabs"></ul>
467
485
  </div>
package/scene/scene.js CHANGED
@@ -41,6 +41,8 @@ module.exports = function (RED)
41
41
  // # Dynamic config #
42
42
  // ##################
43
43
  let max_time_on = helper.getTimeInMs(config.max_time_on, config.max_time_on_unit);
44
+ let data_type = config.data_type || "SIMPLE";
45
+
44
46
 
45
47
  // ##################
46
48
  // # Runtime values #
@@ -203,7 +205,7 @@ module.exports = function (RED)
203
205
 
204
206
  stopAutoOff();
205
207
 
206
- node.send(node_settings.last_values.map(val => { return { payload: val }; }));
208
+ sendStates(node_settings.last_values);
207
209
  notifyCentral();
208
210
  }
209
211
 
@@ -272,7 +274,7 @@ module.exports = function (RED)
272
274
  {
273
275
  timeout = null;
274
276
  node_settings.last_values = new Array(config.outputs).fill(false);
275
- node.send(node_settings.last_values.map(val => { return { payload: val }; }));
277
+ sendStates(node_settings.last_values);
276
278
  notifyCentral();
277
279
 
278
280
  setStatus();
@@ -305,6 +307,31 @@ module.exports = function (RED)
305
307
  }
306
308
  }
307
309
 
310
+ /**
311
+ * Turns the outputs to the given states and returns the sent messages
312
+ * @param {bool[]} states The new states of the outputs
313
+ * @returns The sent messages
314
+ */
315
+ let sendStates = states =>
316
+ {
317
+ let data = null;
318
+ switch (data_type)
319
+ {
320
+ case "SIMPLE":
321
+ data = states.map(val => { return { payload: val }; });
322
+ break;
323
+
324
+ case "HOMEASSISTANT":
325
+ data = states.map(val => { return { payload: { action: val ? "homeassistant.turn_on" : "homeassistant.turn_off" } }; });
326
+ break;
327
+
328
+ default:
329
+ return null;
330
+ }
331
+ node.send(data);
332
+ return data;
333
+ }
334
+
308
335
  let notifyCentral = () =>
309
336
  {
310
337
  if (!config.links)
@@ -4,6 +4,11 @@
4
4
  "name": "Name",
5
5
  "text": "Text",
6
6
  "controlled_by_words": "Diese Node kann über die eingegebenen Wörter gesteuert werden. Mehrere Wörter werden durch ein Komma getrennt.",
7
+
8
+ "data_type": "Datentyp",
9
+ "simple": "Einfaches Format",
10
+ "home_assistant": "HA Action Format",
11
+
7
12
  "time_short": "Zeit kurz",
8
13
  "controlled_by_central": "Dieser Baustein wird von folgenden Zentralbausteinen gesteuert:"
9
14
  }
@@ -4,6 +4,11 @@
4
4
  "name": "Name",
5
5
  "text": "Text",
6
6
  "controlled_by_words": "This node can be controlled using the words entered. Multiple words are separated by a comma.",
7
+
8
+ "data_type": "Data type",
9
+ "simple": "Simple format",
10
+ "home_assistant": "HA Action format",
11
+
7
12
  "time_short": "Time short",
8
13
  "controlled_by_central": "This module is controlled by the following central modules:"
9
14
  }
@@ -139,12 +139,20 @@
139
139
  defaults: {
140
140
  name: { value: "" },
141
141
  exec_text_names: { value: "" },
142
+ data_type: { value: "SIMPLE" }, // SIMPLE || HOMEASSISTANT
143
+ outputs: { value: 3 },
142
144
  short_time_on_ms: { value: 200 },
143
145
  links: { value: [], type: "smart_central-control[]" }
144
146
  },
145
147
  inputs: 1,
146
148
  outputs: 3,
147
- outputLabels: ["Up/Down", "Stop", "Position"],
149
+ outputLabels: function (index)
150
+ {
151
+ if (this.data_type == "SIMPLE")
152
+ return ["Up/Down", "Stop", "Position"][index];
153
+
154
+ return "HA Shutter";
155
+ },
148
156
  icon: "font-awesome/fa-align-justify",
149
157
  label: function ()
150
158
  {
@@ -157,6 +165,22 @@
157
165
  onEditPrepare(this, ["smart_central-control"]);
158
166
  initTreeList(node, ["smart_central-control"]);
159
167
 
168
+ $("#node-input-data_type")
169
+ .css("max-width", "70%")
170
+ .typedInput({
171
+ types: [{
172
+ value: "data_type",
173
+ default: "SIMPLE",
174
+ options: [
175
+ { value: "SIMPLE", label: node._("shutter.ui.simple") },
176
+ { value: "HOMEASSISTANT", label: node._("shutter.ui.home_assistant") }
177
+ ],
178
+ }],
179
+ }).on("change", function (event, type, value)
180
+ {
181
+ node.outputs = value == "SIMPLE" ? 3 : 1;
182
+ });
183
+
160
184
  $("#node-input-short_time_on_ms")
161
185
  .css("max-width", "4rem")
162
186
  .spinner({
@@ -191,6 +215,10 @@
191
215
  <input id="node-input-exec_text_names" type="text" />
192
216
  <div style="max-width: 450px;" data-i18n="shutter.ui.controlled_by_words"></div>
193
217
  </div>
218
+ <div class="form-row">
219
+ <label for="node-input-data_type"><i class="fa fa-file-code-o"></i> <span data-i18n="shutter.ui.data_type"></span></label>
220
+ <input id="node-input-data_type"/>
221
+ </div>
194
222
  <div class="form-row">
195
223
  <label for="node-input-short_time_on_ms"><i class="fa fa-clock-o"></i> <span data-i18n="shutter.ui.time_short"></span></label>
196
224
  <input id="node-input-short_time_on_ms" placeholder="200" /> ms
@@ -41,6 +41,7 @@ module.exports = function (RED)
41
41
  // # Dynamic config #
42
42
  // ##################
43
43
  let short_time_on_ms = parseInt(config.short_time_on_ms || 200, 10);
44
+ let data_type = config.data_type || "SIMPLE";
44
45
 
45
46
 
46
47
  // ##################
@@ -179,17 +180,17 @@ module.exports = function (RED)
179
180
 
180
181
  if (resultUpDown != null)
181
182
  {
182
- node.send([{ payload: resultUpDown }, null, null]);
183
+ sendDirection(resultUpDown);
183
184
  notifyCentral(true);
184
185
  }
185
186
  else if (resultStop != null)
186
187
  {
187
- node.send([null, { payload: resultStop }, null]);
188
+ sendStop();
188
189
  notifyCentral(false);
189
190
  }
190
191
  else if (resultPosition != null)
191
192
  {
192
- node.send([null, null, { payload: resultPosition }]);
193
+ sendPosition(cover.set_cover_position);
193
194
  }
194
195
  };
195
196
 
@@ -218,7 +219,7 @@ module.exports = function (RED)
218
219
  is_running = false;
219
220
  timeout = null;
220
221
 
221
- node.send([null, { payload: true }, null]);
222
+ sendStop();
222
223
  notifyCentral(false);
223
224
 
224
225
  smart_context.set(node.id, node_settings);
@@ -238,7 +239,6 @@ module.exports = function (RED)
238
239
  timeout = null;
239
240
  }
240
241
  };
241
-
242
242
  /**
243
243
  * Set the current node status
244
244
  */
@@ -262,6 +262,118 @@ module.exports = function (RED)
262
262
  node.status({ fill, shape, text: helper.getCurrentTimeForStatus() + ": " + texts.join(", ") });
263
263
  }
264
264
 
265
+ /**
266
+ * Turns the shutter to the given direction and returns the sent message
267
+ * @param {bool} down True if down, else up
268
+ * @returns The sent message
269
+ */
270
+ let sendDirection = down =>
271
+ {
272
+ if (down)
273
+ return sendTurnDown();
274
+
275
+ return sendTurnUp();
276
+ }
277
+
278
+ /**
279
+ * Turns the shutter up and returns the sent message
280
+ * @returns The sent message
281
+ */
282
+ let sendTurnUp = () =>
283
+ {
284
+ let data = null;
285
+ switch (data_type)
286
+ {
287
+ case "SIMPLE":
288
+ data = [{ payload: false }, null, null];
289
+ break;
290
+
291
+ case "HOMEASSISTANT":
292
+ data = { payload: { action: "cover.open_cover" } };
293
+ break;
294
+
295
+ default:
296
+ return null;
297
+ }
298
+ node.send(data);
299
+ return data;
300
+ }
301
+
302
+ /**
303
+ * Turns the shutter down and returns the sent message
304
+ * @returns The sent message
305
+ */
306
+ let sendTurnDown = () =>
307
+ {
308
+ let data = null;
309
+ switch (data_type)
310
+ {
311
+ case "SIMPLE":
312
+ data = [{ payload: true }, null, null];
313
+ break;
314
+
315
+ case "HOMEASSISTANT":
316
+ data = { payload: { action: "cover.close_cover" } };
317
+ break;
318
+
319
+ default:
320
+ return null;
321
+ }
322
+ node.send(data);
323
+ return data;
324
+ }
325
+
326
+ /**
327
+ * Stops the shutter and returns the sent message
328
+ * @returns The sent message
329
+ */
330
+ let sendStop = () =>
331
+ {
332
+ let data = null;
333
+ switch (data_type)
334
+ {
335
+ case "SIMPLE":
336
+ data = [null, { payload: true }, null];
337
+ break;
338
+
339
+ case "HOMEASSISTANT":
340
+ data = { payload: { action: "cover.stop_cover" } };
341
+ break;
342
+
343
+ default:
344
+ return null;
345
+ }
346
+ node.send(data);
347
+ return data;
348
+ }
349
+
350
+ /**
351
+ * Turns the shutter to the given position and returns the sent message
352
+ * @returns The sent message
353
+ */
354
+ let sendPosition = position =>
355
+ {
356
+ let data = null;
357
+ switch (data_type)
358
+ {
359
+ case "SIMPLE":
360
+ data = [null, null, { payload: position }];
361
+ break;
362
+
363
+ case "HOMEASSISTANT":
364
+ // In Simple, 0% is open
365
+ // In HomeAssistant 100% is open
366
+ data = { payload: { action: "cover.set_cover_position", data: { position: 100 - position } } };
367
+ break;
368
+
369
+ default:
370
+ return null;
371
+ }
372
+ node.send(data);
373
+ return data;
374
+ }
375
+
376
+
265
377
  /**
266
378
  * Notify all connected central nodes
267
379
  * @param {boolean} state The state if the shutter is running
@@ -4,6 +4,11 @@
4
4
  "name": "Name",
5
5
  "text": "Text",
6
6
  "controlled_by_words": "Diese Node kann über die eingegebenen Wörter gesteuert werden. Mehrere Wörter werden durch ein Komma getrennt.",
7
+
8
+ "data_type": "Datentyp",
9
+ "simple": "Einfaches Format",
10
+ "home_assistant": "HA Action Format",
11
+
7
12
  "time_up": "Zeit auf",
8
13
  "time_down": "Zeit ab",
9
14
  "pause_change": "Pause Wechsel",
@@ -4,6 +4,11 @@
4
4
  "name": "Name",
5
5
  "text": "Text",
6
6
  "controlled_by_words": "This node can be controlled using the words entered. Multiple words are separated by a comma.",
7
+
8
+ "data_type": "Data type",
9
+ "simple": "Simple format",
10
+ "home_assistant": "HA Action format",
11
+
7
12
  "time_up": "Time up",
8
13
  "time_down": "Time down",
9
14
  "pause_change": "Pause change",
@@ -139,6 +139,8 @@
139
139
  defaults: {
140
140
  name: { value: "" },
141
141
  exec_text_names: { value: "" },
142
+ data_type: { value: "SIMPLE" }, // SIMPLE || HOMEASSISTANT
143
+ outputs: { value: 3 },
142
144
  max_time: { value: 60 },
143
145
  max_time_up: { value: 60 },
144
146
  max_time_down: { value: 60 },
@@ -149,7 +151,13 @@
149
151
  },
150
152
  inputs: 1,
151
153
  outputs: 3,
152
- outputLabels: ["Up", "Down", "Status Position"],
154
+ outputLabels: function (index)
155
+ {
156
+ if (this.data_type == "SIMPLE")
157
+ return ["Up", "Down", "Status Position"][index];
158
+
159
+ return ["HA Shutter", "HA State Position"][index];
160
+ },
153
161
  icon: "font-awesome/fa-align-justify",
154
162
  label: function ()
155
163
  {
@@ -162,6 +170,22 @@
162
170
  onEditPrepare(this, ["smart_central-control"]);
163
171
  initTreeList(node, ["smart_central-control"]);
164
172
 
173
+ $("#node-input-data_type")
174
+ .css("max-width", "70%")
175
+ .typedInput({
176
+ types: [{
177
+ value: "data_type",
178
+ default: "SIMPLE",
179
+ options: [
180
+ { value: "SIMPLE", label: node._("shutter.ui.simple") },
181
+ { value: "HOMEASSISTANT", label: node._("shutter.ui.home_assistant") }
182
+ ],
183
+ }],
184
+ }).on("change", function (event, type, value)
185
+ {
186
+ node.outputs = value == "SIMPLE" ? 3 : 2;
187
+ });
188
+
165
189
  $("#node-input-max_time_up")
166
190
  .css("max-width", "4rem")
167
191
  .spinner({
@@ -265,6 +289,10 @@
265
289
  <input id="node-input-exec_text_names" type="text" />
266
290
  <div style="max-width: 450px;" data-i18n="shutter.ui.controlled_by_words"></div>
267
291
  </div>
292
+ <div class="form-row">
293
+ <label for="node-input-data_type"><i class="fa fa-file-code-o"></i> <span data-i18n="shutter.ui.data_type"></span></label>
294
+ <input id="node-input-data_type"/>
295
+ </div>
268
296
  <div class="form-row">
269
297
  <label for="node-input-max_time_up"><i class="fa fa-clock-o"></i> <span data-i18n="shutter.ui.time_up"></span></label>
270
298
  <input id="node-input-max_time_up" placeholder="Komplette Fahrt auf" /> s
@@ -61,6 +61,7 @@ module.exports = function (RED)
61
61
  let revert_time_ms = parseInt(config.revert_time_ms || 100, 10);
62
62
  let alarm_action = config.alarm_action || "NOTHING";
63
63
  let alarm_off_action = config.alarm_off_action || "NOTHING";
64
+ let data_type = config.data_type || "SIMPLE";
64
65
 
65
66
 
66
67
  // ##################
@@ -484,7 +485,10 @@ module.exports = function (RED)
484
485
  else if (down)
485
486
  node_settings.last_direction_up = false;
486
487
 
487
- node.send([{ payload: up }, { payload: down }, { payload: node_settings.last_position }]);
488
+ if (up || down)
489
+ sendDirection(down);
490
+ else
491
+ sendStop()
488
492
 
489
493
  // Inform central nodes that shutter is running/stopped
490
494
  notifyCentral(up || down);
@@ -541,6 +545,117 @@ module.exports = function (RED)
541
545
  node.status({ fill, shape, text: helper.getCurrentTimeForStatus() + ": " + texts.join(", ") });
542
546
  }
543
547
 
548
+ /**
549
+ * Turns the shutter to the given direction and returns the sent message
550
+ * @param {bool} down True if down, else up
551
+ * @returns The sent message
552
+ */
553
+ let sendDirection = down =>
554
+ {
555
+ if (down)
556
+ return sendTurnDown();
557
+
558
+ return sendTurnUp();
559
+ }
560
+
561
+ /**
562
+ * Turns the shutter up and returns the sent message
563
+ * @returns The sent message
564
+ */
565
+ let sendTurnUp = () =>
566
+ {
567
+ let data = null;
568
+ switch (data_type)
569
+ {
570
+ case "SIMPLE":
571
+ data = [{ payload: true }, { payload: false }, { payload: node_settings.last_position }];
572
+ break;
573
+
574
+ case "HOMEASSISTANT":
575
+ data = [{ payload: { action: "cover.open_cover" } }, { payload: { action: "number.set_value", data: { "value": parseInt(node_settings.last_position * 2.55, 10) } } }];
576
+ break;
577
+
578
+ default:
579
+ return null;
580
+ }
581
+ node.send(data);
582
+ return data;
583
+ }
584
+
585
+ /**
586
+ * Turns the shutter down and returns the sent message
587
+ * @returns The sent message
588
+ */
589
+ let sendTurnDown = () =>
590
+ {
591
+ let data = null;
592
+ switch (data_type)
593
+ {
594
+ case "SIMPLE":
595
+ data = [{ payload: false }, { payload: true }, { payload: node_settings.last_position }];
596
+ break;
597
+
598
+ case "HOMEASSISTANT":
599
+ data = [{ payload: { action: "cover.close_cover" } }, { payload: { action: "number.set_value", data: { "value": parseInt(node_settings.last_position * 2.55, 10) } } }];
600
+ break;
601
+
602
+ default:
603
+ return null;
604
+ }
605
+ node.send(data);
606
+ return data;
607
+ }
608
+
609
+ /**
610
+ * Stops the shutter and returns the sent message
611
+ * @returns The sent message
612
+ */
613
+ let sendStop = () =>
614
+ {
615
+ let data = null;
616
+ switch (data_type)
617
+ {
618
+ case "SIMPLE":
619
+ data = [null, { payload: true }, null];
620
+ break;
621
+
622
+ case "HOMEASSISTANT":
623
+ data = [{ payload: { action: "cover.stop_cover" } }, { payload: { action: "number.set_value", data: { "value": parseInt(node_settings.last_position * 2.55, 10) } } }];
624
+ break;
625
+
626
+ default:
627
+ return null;
628
+ }
629
+ node.send(data);
630
+ return data;
631
+ }
632
+
633
+ /**
634
+ * Sets the current position state of the shutter to the given value and returns the sent message
635
+ * @param {int} position The current position in percent
636
+ * @returns The sent message
637
+ */
638
+ let sendPositionState = position =>
639
+ {
640
+ let data = null;
641
+ switch (data_type)
642
+ {
643
+ case "SIMPLE":
644
+ data = [null, null, { payload: position }];
645
+ break;
646
+
647
+ case "HOMEASSISTANT":
648
+ data = [null, { payload: { action: "number.set_value", data: { "value": parseInt(node_settings.last_position * 2.55, 10) } } }];
649
+ break;
650
+
651
+ default:
652
+ return null;
653
+ }
654
+ node.send(data);
655
+ return data;
656
+ }
657
+
658
+
544
659
  /**
545
660
  * Notify all connected central nodes
546
661
  * @param {boolean} state The state if the shutter is running
@@ -265,7 +265,7 @@ module.exports = function (RED)
265
265
  {
266
266
  for (const link of config.links)
267
267
  {
268
- node.log("Check node = " + link);
268
+ // node.log("Check node = " + link);
269
269
  let linkedNode = RED.nodes.getNode(link);
270
270
 
271
271
  if (linkedNode == null || linkedNode.exec_text_names == null || linkedNode.exec_text_names.length == 0)
@@ -280,7 +280,7 @@ module.exports = function (RED)
280
280
  case "smart_scene-control":
281
281
  case "smart_shutter-control":
282
282
  case "smart_shutter-complex-control":
283
- node.log("Add room: " + name);
283
+ // node.log("Add room: " + name);
284
284
  if (!lookup.has(name))
285
285
  lookup.set(name, []);
286
286
 
@@ -289,7 +289,7 @@ module.exports = function (RED)
289
289
 
290
290
  if (!rooms.includes(name))
291
291
  {
292
- node.log("Add room to room list: " + name);
292
+ // node.log("Add room to room list: " + name);
293
293
  rooms.push(name);
294
294
  }
295
295
  break;