smart-nodes 0.1.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 (62) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +127 -0
  4. package/central/central.html +328 -0
  5. package/central/central.js +95 -0
  6. package/compare/compare.html +137 -0
  7. package/compare/compare.js +151 -0
  8. package/delay/delay.html +192 -0
  9. package/delay/delay.js +175 -0
  10. package/examples/central.json +804 -0
  11. package/examples/central.png +0 -0
  12. package/examples/compare.json +916 -0
  13. package/examples/compare.png +0 -0
  14. package/examples/delay.json +198 -0
  15. package/examples/delay.png +0 -0
  16. package/examples/forwarder.json +152 -0
  17. package/examples/forwarder.png +0 -0
  18. package/examples/hysteresis.json +358 -0
  19. package/examples/hysteresis.png +0 -0
  20. package/examples/light-control.json +499 -0
  21. package/examples/light-control.png +0 -0
  22. package/examples/logic.json +562 -0
  23. package/examples/logic.png +0 -0
  24. package/examples/long-press-control.json +113 -0
  25. package/examples/long-press-control.png +0 -0
  26. package/examples/multi-press-control.json +136 -0
  27. package/examples/multi-press-control.png +0 -0
  28. package/examples/scene-control.json +535 -0
  29. package/examples/scene-control.png +0 -0
  30. package/examples/scheduler.json +164 -0
  31. package/examples/scheduler.png +0 -0
  32. package/examples/shutter-complex-control.json +489 -0
  33. package/examples/shutter-complex-control.png +0 -0
  34. package/examples/shutter-control.json +457 -0
  35. package/examples/shutter-control.png +0 -0
  36. package/examples/statistic.json +1112 -0
  37. package/examples/statistic.png +0 -0
  38. package/forwarder/forwarder.html +100 -0
  39. package/forwarder/forwarder.js +95 -0
  40. package/hysteresis/hysteresis.html +152 -0
  41. package/hysteresis/hysteresis.js +146 -0
  42. package/light-control/light-control.html +358 -0
  43. package/light-control/light-control.js +231 -0
  44. package/logic/logic.html +168 -0
  45. package/logic/logic.js +171 -0
  46. package/long-press-control/long-press-control.html +74 -0
  47. package/long-press-control/long-press-control.js +75 -0
  48. package/multi-press-control/multi-press-control.html +135 -0
  49. package/multi-press-control/multi-press-control.js +68 -0
  50. package/package.json +59 -0
  51. package/persistence.js +74 -0
  52. package/scene-control/scene-control.html +575 -0
  53. package/scene-control/scene-control.js +265 -0
  54. package/scheduler/scheduler.html +338 -0
  55. package/scheduler/scheduler.js +209 -0
  56. package/shutter-complex-control/shutter-complex-control.html +330 -0
  57. package/shutter-complex-control/shutter-complex-control.js +399 -0
  58. package/shutter-control/shutter-control.html +283 -0
  59. package/shutter-control/shutter-control.js +208 -0
  60. package/smart_helper.js +156 -0
  61. package/statistic/statistic.html +107 -0
  62. package/statistic/statistic.js +196 -0
@@ -0,0 +1,575 @@
1
+ <script type="text/javascript">
2
+ (function ()
3
+ {
4
+ let treeList;
5
+ let candidateNodesCount = 0;
6
+ let flows = [];
7
+ let flowMap = {};
8
+
9
+ function onEditPrepare(node, targetTypes)
10
+ {
11
+ if (!node.links)
12
+ node.links = [];
13
+
14
+ const activeSubflow = RED.nodes.subflow(node.z);
15
+
16
+ treeList = $("<div>")
17
+ .css({ width: "100%", height: "100%" })
18
+ .appendTo(".node-input-link-row")
19
+ .treeList({ autoSelect: false })
20
+ .on("treelistitemmouseover", function (e, item)
21
+ {
22
+ if (item.node)
23
+ {
24
+ item.node.highlighted = true;
25
+ item.node.dirty = true;
26
+ RED.view.redraw();
27
+ }
28
+ })
29
+ .on("treelistitemmouseout", function (e, item)
30
+ {
31
+ if (item.node)
32
+ {
33
+ item.node.highlighted = false;
34
+ item.node.dirty = true;
35
+ RED.view.redraw();
36
+ }
37
+ });
38
+
39
+ flows = [];
40
+ flowMap = {};
41
+
42
+ if (activeSubflow)
43
+ {
44
+ flowMap[activeSubflow.id] = {
45
+ id: activeSubflow.id,
46
+ class: "red-ui-palette-header",
47
+ label: "Subflow : " + (activeSubflow.name || activeSubflow.id),
48
+ expanded: true,
49
+ children: []
50
+ };
51
+ flows.push(flowMap[activeSubflow.id]);
52
+ }
53
+ else
54
+ {
55
+ RED.nodes.eachWorkspace(function (ws)
56
+ {
57
+ if (!ws.disabled)
58
+ {
59
+ flowMap[ws.id] = {
60
+ id: ws.id,
61
+ class: "red-ui-palette-header",
62
+ label: (ws.label || ws.id) + (node.z === ws.id ? " *" : ""),
63
+ expanded: true,
64
+ children: []
65
+ };
66
+ flows.push(flowMap[ws.id]);
67
+ }
68
+ });
69
+ }
70
+
71
+ setTimeout(function ()
72
+ {
73
+ treeList.treeList("show", node.z);
74
+ }, 100);
75
+ }
76
+
77
+ function initTreeList(node, targetTypes)
78
+ {
79
+ candidateNodesCount = 0;
80
+ for (const key in flowMap)
81
+ {
82
+ flowMap[key].children = [];
83
+ }
84
+
85
+ let candidateNodes = [];
86
+
87
+ targetTypes.forEach(function (targetType)
88
+ {
89
+ candidateNodes = candidateNodes.concat(RED.nodes.filterNodes({ type: targetType }));
90
+ });
91
+
92
+ candidateNodes.forEach(function (n)
93
+ {
94
+ if (flowMap[n.z])
95
+ {
96
+ const isChecked = (node.links.indexOf(n.id) !== -1) || (n.links || []).indexOf(node.id) !== -1;
97
+ if (isChecked)
98
+ {
99
+ flowMap[n.z].children.push({
100
+ id: n.id,
101
+ node: n,
102
+ label: n.name || n.id,
103
+ selected: false,
104
+ checkbox: false,
105
+ radio: false
106
+ });
107
+ candidateNodesCount++;
108
+ }
109
+ }
110
+ });
111
+
112
+ for (const key in flowMap)
113
+ {
114
+ flowMap[key].children.sort((a, b) => a.label.localeCompare(b.label));
115
+ }
116
+
117
+ const flowsFiltered = flows.filter(function (f) { return f.children.length > 0 });
118
+ treeList.treeList("empty");
119
+ treeList.treeList("data", flowsFiltered);
120
+ }
121
+
122
+ function resizeDialog(size)
123
+ {
124
+ size = size || { height: $(".red-ui-tray-content form").height() }
125
+ var rowsScenes = $("#dialog-form > div:not(.node-input-property-scenes-row):visible");
126
+ var rowsOutputs = $("#dialog-form > div:not(.node-input-property-outputs-row):visible");
127
+ var rows = Math.max(rowsScenes, rowsOutputs);
128
+ var height = size.height;
129
+ for (var i = 0; i < rows.length; i++)
130
+ {
131
+ height -= $(rows[i]).outerHeight(true);
132
+ }
133
+ let sceneHeight = height;
134
+ let outputHeight = height;
135
+
136
+ var editorRow = $("#dialog-form > div.node-input-property-scenes-row");
137
+ sceneHeight -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
138
+ sceneHeight += 16;
139
+ $("#node-input-property-scenes").editableList("height", sceneHeight);
140
+
141
+ var editorRow = $("#dialog-form > div.node-input-property-outputs-row");
142
+ outputHeight -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
143
+ outputHeight += 16;
144
+ $("#node-input-property-outputs").editableList("height", outputHeight);
145
+
146
+ // links tree list
147
+ var rows = $("#dialog-form>div:not(#light-control-scenes)");
148
+ var height = $("#dialog-form").height();
149
+ for (var i = 0; i < rows.length; i++)
150
+ {
151
+ height -= $(rows[i]).outerHeight(true);
152
+ }
153
+ var tabRow = $("#dialog-form div.scene-tabs-row");
154
+ height -= (parseInt(tabRow.css("marginTop")) + parseInt(tabRow.css("marginBottom"))) + tabRow.outerHeight(true);
155
+ var editorRow = $("#dialog-form div.node-input-link-row");
156
+ height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
157
+ $(".node-input-link-row").css("height", height + "px");
158
+ }
159
+
160
+ function getScenes(el)
161
+ {
162
+ var result = {
163
+ scenes: []
164
+ }
165
+ el.each(function (i)
166
+ {
167
+ var prop = $(this);
168
+ result.scenes.push({
169
+ name: prop.find(".node-input-prop-name").val(),
170
+ outputs: prop.find(".node-input-prop-outputs").typedInput("value")
171
+ });
172
+ });
173
+ return result;
174
+ }
175
+
176
+ function getOutputs(el)
177
+ {
178
+ var result = {
179
+ output_items: []
180
+ }
181
+ el.each(function (i)
182
+ {
183
+ var prop = $(this);
184
+ result.output_items.push({
185
+ name: prop.find(".node-input-prop-name").val(),
186
+ });
187
+ });
188
+ return result;
189
+ }
190
+
191
+ function initScenesOutputs()
192
+ {
193
+ let outputs = getOutputs($("#node-input-property-outputs").editableList("items"));
194
+
195
+ let options = [];
196
+ for (let i = 0; i < outputs.output_items.length; i++)
197
+ {
198
+ const item = outputs.output_items[i];
199
+ options.push({ value: "" + (i + 1), label: item.name });
200
+ }
201
+
202
+ let inputs = $(".node-input-prop-outputs");
203
+ for (let i = 0; i < inputs.length; i++)
204
+ {
205
+ let value = $(inputs[i]).typedInput("value");
206
+ $(inputs[i]).typedInput("types", [{
207
+ multiple: "true",
208
+ options: options
209
+ }]);
210
+ $(inputs[i]).typedInput("value", value);
211
+ }
212
+ }
213
+
214
+ RED.nodes.registerType("smart_scene-control", {
215
+ category: "Smart Nodes",
216
+ paletteLabel: "Scene control",
217
+ color: "#C882FF",
218
+ defaults: {
219
+ name: { value: "" },
220
+ max_time_on: { value: "0" },
221
+ max_time_on_unit: { value: "s" },
222
+ outputs: { value: 1 },
223
+ output_items: { value: [{ name: "" }] },
224
+ scenes: {
225
+ value: [{ name: "", outputs: "" }],
226
+ },
227
+ links: { value: [], type: "smart_central-control[]" }
228
+ },
229
+ inputs: 1,
230
+ outputs: 1,
231
+ outputLabels: function (index)
232
+ {
233
+ return this.output_items[index].name;
234
+ },
235
+
236
+ icon: "font-awesome/fa-lightbulb-o",
237
+ label: function ()
238
+ {
239
+ return this.name || "Scene control";
240
+ },
241
+ oneditprepare: function ()
242
+ {
243
+ let node = this;
244
+ onEditPrepare(this, ["smart_central-control"]);
245
+ initTreeList(node, ["smart_central-control"]);
246
+
247
+ // Output list
248
+ var outputList = $("#node-input-property-outputs").css("min-height", "120px").css("min-width", "445px");
249
+
250
+ outputList.editableList({
251
+ addItem: function (container, i, opt)
252
+ {
253
+ var prop = opt;
254
+ if (!prop.hasOwnProperty("name"))
255
+ {
256
+ prop = { name: "" };
257
+ }
258
+ container.css({
259
+ overflow: "hidden",
260
+ whiteSpace: "nowrap"
261
+ });
262
+ var row = $("<div/>").appendTo(container);
263
+
264
+ // Output number
265
+ $("<div/>", { style: "display:inline-block; padding:0px 6px;" })
266
+ .text((i + 1) + ":")
267
+ .appendTo(row);
268
+
269
+ // Output name
270
+ var outputName = $("<input/>", { class: "node-input-prop-name", placeholder: "Name", type: "text" })
271
+ .css("width", "80%")
272
+ .appendTo(row);
273
+
274
+ outputName.val(prop.name);
275
+ },
276
+ removable: true,
277
+ });
278
+
279
+ // Default outputs
280
+ if (!this.output_items)
281
+ this.output_items = [{ name: "" }];
282
+
283
+ // Add existing outputs to list
284
+ for (var i = 0; i < this.output_items.length; i++)
285
+ {
286
+ var item = this.output_items[i];
287
+ var newItem = { name: item.name };
288
+ outputList.editableList("addItem", newItem);
289
+ }
290
+
291
+ // Scene list
292
+ var sceneList = $("#node-input-property-scenes").css("min-height", "120px").css("min-width", "445px");
293
+
294
+ sceneList.editableList({
295
+ addItem: function (container, i, opt)
296
+ {
297
+ var prop = opt;
298
+ if (!prop.hasOwnProperty("name"))
299
+ {
300
+ prop = { name: "", outputs: "" };
301
+ }
302
+ container.css({
303
+ overflow: "hidden",
304
+ whiteSpace: "nowrap"
305
+ });
306
+ var row = $("<div/>").appendTo(container);
307
+
308
+ // Scene number
309
+ $("<div/>", { style: "display:inline-block; padding:0px 6px;" })
310
+ .text((i + 1) + ":")
311
+ .appendTo(row);
312
+
313
+ // Scene name
314
+ var sceneName = $("<input/>", { class: "node-input-prop-name", placeholder: "Name", type: "text" })
315
+ .css("width", "30%")
316
+ .appendTo(row);
317
+
318
+ // Arrow
319
+ $("<div/>", { style: "display:inline-block; padding:0px 6px;" })
320
+ .text("=>")
321
+ .appendTo(row);
322
+
323
+ // Output select
324
+ var outputs = $("<input/>", { class: "node-input-prop-outputs", type: "text" })
325
+ .css("width", "calc(70% - 55px)")
326
+ .appendTo(row)
327
+ .typedInput({
328
+ types: [{
329
+ multiple: "true",
330
+ options: [
331
+ ]
332
+ }]
333
+ });
334
+
335
+ // Fill values
336
+ sceneName.val(prop.name);
337
+ outputs.typedInput("value", prop.outputs);
338
+
339
+ initScenesOutputs();
340
+ },
341
+ removable: true,
342
+ });
343
+
344
+ // Default scenes
345
+ if (!this.scenes)
346
+ this.scenes = [{ name: "", outputs: "" }];
347
+
348
+ // Add existing scenes to list
349
+ for (var i = 0; i < this.scenes.length; i++)
350
+ {
351
+ var scene = this.scenes[i];
352
+ var newScene = { name: scene.name, outputs: scene.outputs };
353
+ sceneList.editableList("addItem", newScene);
354
+ }
355
+
356
+ // Init tabs
357
+ var tabs = RED.tabs.create({
358
+ id: "scene-tabs",
359
+ onchange: function (tab)
360
+ {
361
+ if (tab.id == "scene-tab-scenes")
362
+ initScenesOutputs();
363
+
364
+ $("#scene-tabs-content").children().hide();
365
+ $("#" + tab.id).show();
366
+ resizeDialog();
367
+ }
368
+ });
369
+ tabs.addTab({
370
+ id: "scene-tab-outputs",
371
+ iconClass: "fa fa-lightbulb-o",
372
+ label: "Ausgänge"
373
+ });
374
+
375
+ tabs.addTab({
376
+ id: "scene-tab-scenes",
377
+ iconClass: "fa fa-list-ul",
378
+ label: "Szenen"
379
+ });
380
+
381
+ tabs.addTab({
382
+ id: "scene-tab-links",
383
+ iconClass: "fa fa-links",
384
+ label: "Links"
385
+ });
386
+
387
+
388
+ $("#scene-tabs").trigger("change");
389
+
390
+ $("#node-input-max_time_on").spinner({
391
+ min: 0,
392
+ change: function (event, ui)
393
+ {
394
+ var value = parseInt(this.value);
395
+ value = isNaN(value) ? 0 : value;
396
+ value = Math.max(value, parseInt($(this).attr("aria-valuemin")));
397
+ // value = Math.min(value, parseInt($(this).attr("aria-valuemax")));
398
+ if (value !== this.value)
399
+ $(this).spinner("value", value);
400
+ }
401
+ });
402
+
403
+ $("#node-input-max_time_on_unit")
404
+ .css("max-width", "10rem")
405
+ .typedInput({
406
+ types: [
407
+ {
408
+ default: "s",
409
+ options: [
410
+ { value: "ms", label: "Millisekunden" },
411
+ { value: "s", label: "Sekunden" },
412
+ { value: "min", label: "Minuten" },
413
+ { value: "h", label: "Stunden" },
414
+ ],
415
+ },
416
+ ],
417
+ });
418
+ },
419
+ oneditsave: function ()
420
+ {
421
+ // Set scenes
422
+ var items = $("#node-input-property-scenes").editableList("items");
423
+ var result = getScenes(items);
424
+ this.scenes = result.scenes;
425
+
426
+ // Set outputs
427
+ var items = $("#node-input-property-outputs").editableList("items");
428
+ var result = getOutputs(items);
429
+ this.output_items = result.output_items;
430
+ this.outputs = this.output_items.length;
431
+ },
432
+ onadd: function ()
433
+ {
434
+ this.links = [];
435
+ },
436
+ oneditresize: resizeDialog
437
+ });
438
+ })();
439
+ </script>
440
+
441
+ <script type="text/html" data-template-name="smart_scene-control">
442
+ <div class="form-row">
443
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
444
+ <input type="text" id="node-input-name" placeholder="Name" />
445
+ </div>
446
+ <div class="form-row">
447
+ <label for="node-input-max_time_on"><i class="fa fa-clock-o"></i> Zeit Ein</label>
448
+ <input id="node-input-max_time_on" value="0" />
449
+ <input id="node-input-max_time_on_unit" />
450
+ </div>
451
+
452
+ <div id="light-control-scenes">
453
+ <div class="form-row scene-tabs-row">
454
+ <ul style="min-width: 600px; margin-bottom: 20px;" id="scene-tabs"></ul>
455
+ </div>
456
+ <div id="scene-tabs-content">
457
+ <div id="scene-tab-outputs" style="display: none;">
458
+ <ol id="node-input-property-outputs"></ol>
459
+ </div>
460
+ <div id="scene-tab-scenes" style="display: none;">
461
+ <ol id="node-input-property-scenes"></ol>
462
+ </div>
463
+ <div id="scene-tab-links" style="display: none;">
464
+ <span><i class="fa fa-link"></i> Dieser Baustein wird von folgenden Zentralbausteinen gesteuert:</span>
465
+ <div class="form-row node-input-link-row node-input-link-rows"></div>
466
+ </div>
467
+ </div>
468
+ </div>
469
+ </script>
470
+
471
+ <script type="text/html" data-help-name="smart_scene-control">
472
+ <p>
473
+ Diese Node steuert mehrere Ausgänge die anhand einer definierten Szene ein- bzw. ausgeschaltet werden.
474
+ An jeden Ausgang wird immer <code>msg.payload = true</code> oder <code>msg.payload = false</code> gesendet um ihn ein-, bzw. auszuschalten.
475
+ </p>
476
+ <p>
477
+ <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/>
478
+ Diese Node verwendet sowohl den Teil <code>name</code> als auch <code>nummer</code>. Je nach Nachricht müssen evtl. beide Werte gesetzt sein.
479
+ </p>
480
+ <p>
481
+ Folgende topics werden akzeptiert:
482
+ <table>
483
+ <thead>
484
+ <tr>
485
+ <th>Topic</th>
486
+ <th>Beschreibung</th>
487
+ </tr>
488
+ </thead>
489
+ <tbody>
490
+ <tr>
491
+ <td><code>status#2</code></td>
492
+ <td>
493
+ Gibt über <code>msg.payload = true</code> oder <code>msg.payload = false</code> den aktuellen Status des Ausgangs <code>2</code> an.<br/>
494
+ Bei einem Wechsel eines Ausgangs wird die Zeitmessung für die hinterlegte, bzw. mitgesendete Zeit gestartet, sofern vorhanden.
495
+ </td>
496
+ </tr>
497
+ <tr>
498
+ <td><code>on</code></td>
499
+ <td>Schaltet alle Ausgänge ein und startet die Zeitmessung für die hinterlegte, bzw. mitgesendete Zeit gestartet, sofern vorhanden.</td>
500
+ </tr>
501
+ <tr>
502
+ <td><code>off</code></td>
503
+ <td>Schaltet alle Ausgänge aus.</td>
504
+ </tr>
505
+ <tr>
506
+ <td><code>set</code></td>
507
+ <td>
508
+ Schaltet alle Ausgänge bei <code>msg.payload = true</code> ein und bei <code>msg.payload = false</code> aus.<br/>
509
+ Bei einem Wechsel von ausgeschaltet nach eingeschaltet wird die Zeitmessung für die hinterlegte, bzw. mitgesendete Zeit gestartet, sofern vorhanden.
510
+ </td>
511
+ </tr>
512
+ <tr>
513
+ <td><code>set_permanent</code></td>
514
+ <td>
515
+ Schaltet alle Ausgänge bei <code>msg.payload = true</code>dauerhaft ein und bei <code>msg.payload = false</code> aus.<br/>
516
+ Es wird dabei keine Zeitmessung gestartet.
517
+ </td>
518
+ </tr>
519
+ <tr>
520
+ <td><code>scene_x,y,z</code></td>
521
+ <td>
522
+ Schaltet die Ausgänge entsprechend der mitgegebenen Szenennummern (x, y und z) an, bzw. aus.<br/>
523
+ 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/>
524
+ Taucht die Szene nicht in der Liste auf, wird die erste aufgelistete Szene aktiviert.<br/>
525
+ Wenn nur eine Szene angegeben ist, wechselt der Baustein zwischen der angegebenen Szene und aus.<br/>
526
+ Sollte mindestens ein Ausgang eingeschaltet sein, startet die Zeitmessung erneut.
527
+ </td>
528
+ </tr>
529
+ <tr>
530
+ <td><code>toggle</code> (default)</td>
531
+ <td>
532
+ Schaltet alle Ausgänge aus, falls mindestens einer bereits eingeschaltet wahr.<br/>
533
+ Sollten bereits alle Ausgänge ausgeschaltet sein, werden alle eingeschalten.
534
+ </td>
535
+ </tr>
536
+ </tbody>
537
+ </table>
538
+ </p>
539
+ <p>
540
+ Diese Node hat eine einstellbare Maximallaufzeit, bevor alle Ausgänge automatisch wieder ausgeschalten werden.
541
+ Diese Zeitmessung wird wie in der Tabelle oben verwendet.
542
+ Die eingestellte Zeit kann gezielt überschrieben werden.
543
+ Beispiel: <code>msg = { "topic": "on", "time_on": 5000 }</code> oder <code>msg = { "topic": "on", "time_on": "5s" }</code><br/>
544
+ Diese Nachricht schaltet das Licht für 5000 Millisekunden / 5 Sekunden an und anschließend wieder aus.
545
+ Die nächste Nachricht ohne <code>time_on</code> Angabe verwendet wieder die voreingestellte Zeit.
546
+ Ist die Zeit auf 0 eingestellt, wird das Licht <b>nicht</b> automatisch ausgeschalten.<br/>
547
+ Als Einheit für die Zeit können folgende Werte verwendet werden:
548
+ <table>
549
+ <thead>
550
+ <tr>
551
+ <th>Einheit</th>
552
+ <th>Beschreibung</th>
553
+ </tr>
554
+ </thead>
555
+ <tbody>
556
+ <tr>
557
+ <td><code>ms</code> (default)</td>
558
+ <td>Millisekunden</td>
559
+ </tr>
560
+ <tr>
561
+ <td><code>s</code> oder <code>sec</code></td>
562
+ <td>Sekunden</td>
563
+ </tr>
564
+ <tr>
565
+ <td><code>m</code> oder <code>min</code></td>
566
+ <td>Mintun.</td>
567
+ </tr>
568
+ <tr>
569
+ <td><code>h</code></td>
570
+ <td>Stunden</td>
571
+ </tr>
572
+ </tbody>
573
+ </table>
574
+ </p>
575
+ </script>