@atelieruldetehnologii/node-red-custome-solutions 0.62.22

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 (107) hide show
  1. package/NOTICE +56 -0
  2. package/PROPRIETARY-LICENSE.txt +157 -0
  3. package/README.md +105 -0
  4. package/TERMS-AND-CONDITIONS.md +311 -0
  5. package/advantech-read/advantech-read.html +775 -0
  6. package/advantech-read/advantech-read.js +449 -0
  7. package/advantech-write/advantech-write.html +413 -0
  8. package/advantech-write/advantech-write.js +338 -0
  9. package/bess-control/bess-control.html +569 -0
  10. package/bess-control/bess-control.js +541 -0
  11. package/bess-control/lib/allocation.js +149 -0
  12. package/bess-control/lib/batteries.js +86 -0
  13. package/bess-control/lib/helpers.js +157 -0
  14. package/bess-control/lib/messages.js +131 -0
  15. package/bess-control/lib/runtime.js +156 -0
  16. package/carlo-gavazzi/carlo-gavazzi.html +4327 -0
  17. package/carlo-gavazzi/carlo-gavazzi.js +3081 -0
  18. package/control-export/control-export.html +3644 -0
  19. package/control-export/control-export.js +2192 -0
  20. package/control-reactive/control-reactive.html +3136 -0
  21. package/control-reactive/control-reactive.js +2124 -0
  22. package/fronius-emulator/README.md +258 -0
  23. package/fronius-emulator/fronius-emulator.html +170 -0
  24. package/fronius-emulator/fronius-emulator.js +520 -0
  25. package/fronius-emulator/lib/binary-codec.js +65 -0
  26. package/fronius-emulator/lib/fronius-register-map.js +185 -0
  27. package/fronius-emulator/lib/modbus-parser.js +61 -0
  28. package/fronius-emulator/lib/modbus-tcp-server.js +224 -0
  29. package/fronius-emulator/lib/validation.js +206 -0
  30. package/fronius-emulator/lib/virtual-meter.js +132 -0
  31. package/fronius-read/fronius-read.html +3944 -0
  32. package/fronius-read/fronius-read.js +1466 -0
  33. package/fronius-read/lib/inverter-profiles.js +711 -0
  34. package/fronius-read/lib/sunspec-core.js +303 -0
  35. package/fronius-read/lib/sunspec-model-parsers.js +845 -0
  36. package/fronius-write/fronius-write.html +1789 -0
  37. package/fronius-write/fronius-write.js +2531 -0
  38. package/influxdb/influxdb.html +1077 -0
  39. package/influxdb/influxdb.js +1487 -0
  40. package/janitza/janitza.html +2562 -0
  41. package/janitza/janitza.js +1500 -0
  42. package/janitza/lib/janitza-profiles.js +371 -0
  43. package/lib/a3-test-server.js +199 -0
  44. package/lib/adam-6000-profiles.js +173 -0
  45. package/lib/licensing/constants.js +103 -0
  46. package/lib/licensing/device-id.js +251 -0
  47. package/lib/licensing/errors.js +21 -0
  48. package/lib/licensing/license-client.js +377 -0
  49. package/lib/licensing/license-state.js +50 -0
  50. package/lib/licensing/node-guard.js +150 -0
  51. package/lib/licensing/package-integrity.js +167 -0
  52. package/lib/licensing/package-integrity.json +513 -0
  53. package/lib/licensing/public-key.pem +3 -0
  54. package/lib/licensing/public-key.pem.example +2 -0
  55. package/lib/licensing/public-keys.js +18 -0
  56. package/lib/licensing/storage.js +63 -0
  57. package/lib/licensing/token-verifier.js +84 -0
  58. package/lib/numbers.js +26 -0
  59. package/license/atelier-license.html +88 -0
  60. package/license/atelier-license.js +170 -0
  61. package/modbus-tcp-discover/modbus-tcp-discover.html +190 -0
  62. package/modbus-tcp-discover/modbus-tcp-discover.js +706 -0
  63. package/multi-battery/multi-battery.html +649 -0
  64. package/multi-battery/multi-battery.js +668 -0
  65. package/multi-grid/multi-grid.html +745 -0
  66. package/multi-grid/multi-grid.js +1392 -0
  67. package/multi-inverter/lib/engine-core.js +237 -0
  68. package/multi-inverter/multi-inverter.html +2674 -0
  69. package/multi-inverter/multi-inverter.js +1393 -0
  70. package/package.json +109 -0
  71. package/phoenix-contact/lib/eem-ma370-advanced.js +175 -0
  72. package/phoenix-contact/lib/eem-ma370.js +138 -0
  73. package/phoenix-contact/lib/integrations.js +149 -0
  74. package/phoenix-contact/lib/phoenix-contact-profile.js +35030 -0
  75. package/phoenix-contact/phoenix-contact.html +840 -0
  76. package/phoenix-contact/phoenix-contact.js +679 -0
  77. package/pv-generator/pv-generator.html +284 -0
  78. package/pv-generator/pv-generator.js +387 -0
  79. package/pylontech-read/pylontech-read.html +763 -0
  80. package/pylontech-read/pylontech-read.js +518 -0
  81. package/pylontech-write/pylontech-write.html +405 -0
  82. package/pylontech-write/pylontech-write.js +546 -0
  83. package/scada-aggregator/lib/aggregate.js +72 -0
  84. package/scada-aggregator/lib/groups.js +39 -0
  85. package/scada-aggregator/scada-aggregator.html +108 -0
  86. package/scada-aggregator/scada-aggregator.js +117 -0
  87. package/scada-server/lib/aggregator-map.js +58 -0
  88. package/scada-server/lib/encoding.js +235 -0
  89. package/scada-server/lib/modbus-server.js +492 -0
  90. package/scada-server/lib/object-path.js +18 -0
  91. package/scada-server/lib/register-map.js +288 -0
  92. package/scada-server/scada-server.html +1419 -0
  93. package/scada-server/scada-server.js +704 -0
  94. package/scripts/check-syntax.js +66 -0
  95. package/scripts/package-integrity.js +46 -0
  96. package/scripts/package-release.js +116 -0
  97. package/scripts/run-tests.js +2178 -0
  98. package/scripts/tgz-integrity.js +74 -0
  99. package/sma-read/lib/sunspec-core.js +83 -0
  100. package/sma-read/lib/sunspec-model-parsers.js +853 -0
  101. package/sma-read/sma-read.html +659 -0
  102. package/sma-read/sma-read.js +458 -0
  103. package/sma-write/sma-write.html +105 -0
  104. package/sma-write/sma-write.js +270 -0
  105. package/victron-read/lib/mqtt-state.js +176 -0
  106. package/victron-read/victron-read.html +1074 -0
  107. package/victron-read/victron-read.js +1222 -0
@@ -0,0 +1,413 @@
1
+ <style>
2
+ .advantech-write-editor {
3
+ --pr-border: #d7dde5;
4
+ --pr-muted: #667085;
5
+ --pr-surface: #f8fafc;
6
+ }
7
+
8
+ .advantech-write-editor .aw-section {
9
+ margin: 0 0 18px;
10
+ padding: 14px 16px 16px;
11
+ border: 1px solid var(--pr-border);
12
+ border-radius: 8px;
13
+ background: var(--pr-surface);
14
+ }
15
+
16
+ .advantech-write-editor .aw-title {
17
+ display: flex;
18
+ align-items: center;
19
+ gap: 8px;
20
+ margin: 0 0 4px;
21
+ font-size: 15px;
22
+ font-weight: 600;
23
+ color: #243447;
24
+ }
25
+
26
+ .advantech-write-editor .aw-note {
27
+ margin: 0 0 14px;
28
+ color: var(--pr-muted);
29
+ font-size: 12px;
30
+ line-height: 1.45;
31
+ }
32
+
33
+ .advantech-write-editor .aw-grid {
34
+ display: grid;
35
+ grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
36
+ gap: 12px 16px;
37
+ }
38
+
39
+ .advantech-write-editor .form-row {
40
+ margin-bottom: 12px;
41
+ }
42
+
43
+ .advantech-write-editor .aw-grid .form-row,
44
+ .advantech-write-editor .form-row:last-child {
45
+ margin-bottom: 0;
46
+ }
47
+
48
+ .advantech-write-editor .form-row > label {
49
+ width: 150px;
50
+ font-weight: 600;
51
+ }
52
+
53
+ .advantech-write-editor .form-row > input[type="text"],
54
+ .advantech-write-editor .form-row > select {
55
+ width: calc(100% - 160px);
56
+ }
57
+
58
+ .advantech-write-editor .aw-checkbox input {
59
+ display: inline-block;
60
+ width: auto;
61
+ vertical-align: top;
62
+ }
63
+
64
+ .advantech-write-editor .aw-inline-note {
65
+ margin-left: 8px;
66
+ color: var(--pr-muted);
67
+ line-height: 1.4;
68
+ }
69
+
70
+ .advantech-write-editor .aw-advanced {
71
+ display: none;
72
+ }
73
+
74
+ .advantech-write-editor .aw-secret-action {
75
+ margin-left: auto;
76
+ padding: 0;
77
+ width: 18px;
78
+ height: 18px;
79
+ border: 0;
80
+ background: transparent;
81
+ color: #8a94a6;
82
+ opacity: 0.55;
83
+ cursor: default;
84
+ }
85
+ </style>
86
+
87
+ <script type="text/javascript">
88
+ const ADAM_WRITE_CHANNEL_COUNTS = {
89
+ "6017": { do: 2, ao: 0 },
90
+ "6018": { do: 8, ao: 0 },
91
+ "6022": { do: 2, ao: 2 },
92
+ "6024": { do: 2, ao: 2 },
93
+ "6050": { do: 6, ao: 0 },
94
+ "6051": { do: 2, ao: 0 },
95
+ "6052": { do: 8, ao: 0 },
96
+ "6060": { do: 6, ao: 0 },
97
+ "6066": { do: 6, ao: 0 }
98
+ };
99
+
100
+ function normalizeAdamWriteModel(value) {
101
+ const match = String(value || "").toUpperCase().match(/60\d{2}\+?/);
102
+ return match ? match[0] : "";
103
+ }
104
+
105
+ function selectedWriteCounts() {
106
+ return ADAM_WRITE_CHANNEL_COUNTS[normalizeAdamWriteModel($("#node-input-moduleType").val())] || { do: 0, ao: 0 };
107
+ }
108
+
109
+ function advantechWriteAutoLabel(config) {
110
+ const name = config && String(config.name || "").trim();
111
+ if (name) return name;
112
+
113
+ const mode = config && config.doCommandMode === "multiple" ? "multiple" : "single";
114
+ const channel = Math.max(0, Math.round(Number(config && config.defaultChannel) || 0));
115
+ const module = String(config && config.moduleType ? config.moduleType : "ADAM-6066").replace(/^ADAM-/, "");
116
+ if (mode === "multiple") {
117
+ return "advantech-write " + module + " DO multi";
118
+ }
119
+ return "advantech-write " + module + " DO" + (channel + 1);
120
+ }
121
+
122
+ function advantechWriteSyncNamePlaceholder() {
123
+ $("#node-input-name").attr("placeholder", advantechWriteAutoLabel({
124
+ name: "",
125
+ moduleType: $("#node-input-moduleType").val(),
126
+ doCommandMode: $("#node-input-doCommandMode").val(),
127
+ defaultChannel: $("#node-input-defaultChannel").val()
128
+ }));
129
+ }
130
+
131
+ function advantechWriteSetAutoName() {
132
+ const name = advantechWriteAutoLabel({
133
+ name: "",
134
+ moduleType: $("#node-input-moduleType").val(),
135
+ doCommandMode: $("#node-input-doCommandMode").val(),
136
+ defaultChannel: $("#node-input-defaultChannel").val()
137
+ });
138
+ $("#node-input-name").val(name).attr("placeholder", name);
139
+ }
140
+
141
+ RED.nodes.registerType("advantech-write", {
142
+ category: "Atelierul de Tehnologii",
143
+ color: "#e67700",
144
+ defaults: {
145
+ license: { value: "", type: "atelier-license", required: true },
146
+ name: { value: "" },
147
+ host: { value: "", required: true },
148
+ port: { value: 502, required: true, validate: RED.validators.number() },
149
+ unitId: { value: 1, required: true, validate: RED.validators.number() },
150
+ addressMode: { value: "manual" },
151
+ moduleType: { value: "ADAM-6066" },
152
+ writeType: { value: "do" },
153
+ doCommandMode: { value: "single" },
154
+ doStart: { value: 17, validate: RED.validators.number() },
155
+ aoStart: { value: 40011, validate: RED.validators.number() },
156
+ defaultChannel: { value: 0, validate: RED.validators.number() },
157
+ aoScale: { value: 1, validate: RED.validators.number() },
158
+ aoOffset: { value: 0, validate: RED.validators.number() },
159
+ allowDoMask: { value: false },
160
+ doMaskRegister: { value: 40303, validate: RED.validators.number() },
161
+ verifyWrite: { value: true }
162
+ },
163
+ inputs: 1,
164
+ outputs: 1,
165
+ icon: "font-awesome/fa-microchip",
166
+ label: function () {
167
+ return advantechWriteAutoLabel(this);
168
+ },
169
+ oneditprepare: function () {
170
+ const node = this;
171
+ let advancedUnlocked = false;
172
+ let longPressTimer = null;
173
+ let longPressTriggered = false;
174
+
175
+ function clearLongPressTimer() {
176
+ if (longPressTimer) {
177
+ clearTimeout(longPressTimer);
178
+ longPressTimer = null;
179
+ }
180
+ }
181
+
182
+ function syncAdvancedRows() {
183
+ $(".advantech-write-editor .aw-advanced").toggle(advancedUnlocked);
184
+ }
185
+
186
+ function startLongPress() {
187
+ longPressTriggered = false;
188
+ clearLongPressTimer();
189
+ longPressTimer = setTimeout(function () {
190
+ advancedUnlocked = true;
191
+ longPressTriggered = true;
192
+ syncAdvancedRows();
193
+ }, 5000);
194
+ }
195
+
196
+ function syncDoMode() {
197
+ const multiple = $("#node-input-doCommandMode").val() === "multiple";
198
+ $("#single-do-note").toggle(!multiple);
199
+ $("#multiple-do-note").toggle(multiple);
200
+ advantechWriteSyncNamePlaceholder();
201
+ }
202
+
203
+ function syncSelectedDoOptions() {
204
+ const counts = selectedWriteCounts();
205
+ const select = $("#node-input-defaultChannel");
206
+ const selected = select.val();
207
+ const current = Math.max(0, Math.round(Number(selected !== null && selected !== undefined ? selected : node.defaultChannel) || 0));
208
+ const count = Math.max(0, counts.do || 0);
209
+ select.empty();
210
+ if (count <= 0) {
211
+ select.append($("<option></option>").attr("value", 0).text("No DO available"));
212
+ select.prop("disabled", true);
213
+ } else {
214
+ for (let i = 0; i < count; i += 1) {
215
+ select.append($("<option></option>").attr("value", i).text("DO " + (i + 1)));
216
+ }
217
+ select.prop("disabled", false);
218
+ select.val(String(Math.min(current, count - 1)));
219
+ }
220
+ }
221
+
222
+ function syncWriteUi() {
223
+ syncSelectedDoOptions();
224
+ syncDoMode();
225
+ advantechWriteSyncNamePlaceholder();
226
+ }
227
+
228
+ $("#node-input-moduleType, #node-input-doCommandMode, #node-input-defaultChannel")
229
+ .on("change.advantechWrite input.advantechWrite", syncWriteUi);
230
+ $("#node-input-host")
231
+ .off(".advantechWriteName")
232
+ .on("change.advantechWriteName input.advantechWriteName", function () {
233
+ $("#node-input-name").val(String($(this).val() || "").trim());
234
+ });
235
+ $("#node-advantech-write-secret")
236
+ .off(".advantechWriteExpert")
237
+ .on("mousedown.advantechWriteExpert touchstart.advantechWriteExpert", function () {
238
+ startLongPress();
239
+ })
240
+ .on("mouseup.advantechWriteExpert mouseleave.advantechWriteExpert touchend.advantechWriteExpert touchcancel.advantechWriteExpert", function () {
241
+ clearLongPressTimer();
242
+ })
243
+ .on("click.advantechWriteExpert", function (evt) {
244
+ if (!longPressTriggered) return;
245
+ evt.preventDefault();
246
+ evt.stopImmediatePropagation();
247
+ longPressTriggered = false;
248
+ });
249
+ $("#module-type-note").text("Profilul ales valideaza automat canalele DO si AO disponibile.");
250
+ syncAdvancedRows();
251
+ syncWriteUi();
252
+ },
253
+ oneditsave: function () {
254
+ if (!String($("#node-input-name").val() || "").trim()) {
255
+ $("#node-input-name").val(String($("#node-input-host").val() || "").trim());
256
+ }
257
+ $("#node-input-moduleType, #node-input-doCommandMode, #node-input-defaultChannel").off(".advantechWrite");
258
+ $("#node-input-host").off(".advantechWriteName");
259
+ $("#node-advantech-write-secret").off(".advantechWriteExpert");
260
+ },
261
+ oneditcancel: function () {
262
+ $("#node-input-moduleType, #node-input-doCommandMode, #node-input-defaultChannel").off(".advantechWrite");
263
+ $("#node-input-host").off(".advantechWriteName");
264
+ $("#node-advantech-write-secret").off(".advantechWriteExpert");
265
+ }
266
+ });
267
+ </script>
268
+
269
+ <script type="text/html" data-template-name="advantech-write">
270
+ <div class="form-row"><label for="node-input-license"><i class="fa fa-key"></i> License</label><input type="text" id="node-input-license"></div>
271
+ <div class="advantech-write-editor">
272
+ <div class="aw-section">
273
+ <p class="aw-title"><i class="fa fa-microchip"></i> Advantech ADAM Writer <button type="button" class="aw-secret-action" id="node-advantech-write-secret"><i class="fa fa-circle"></i></button></p>
274
+ <p class="aw-note">Scriere Modbus TCP pentru iesiri digitale si analogice ADAM-6000, cu validare automata a canalelor disponibile.</p>
275
+ <div class="aw-grid">
276
+ <div class="form-row">
277
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
278
+ <input type="text" id="node-input-name" placeholder="advantech-write">
279
+ </div>
280
+ <div class="form-row">
281
+ <label for="node-input-host"><i class="fa fa-plug"></i> Host</label>
282
+ <input type="text" id="node-input-host" placeholder="192.168.1.50">
283
+ </div>
284
+ <div class="form-row">
285
+ <label for="node-input-port"><i class="fa fa-ellipsis-h"></i> Port</label>
286
+ <input type="text" id="node-input-port" placeholder="502">
287
+ </div>
288
+ <div class="form-row">
289
+ <label for="node-input-unitId"><i class="fa fa-hashtag"></i> Unit ID</label>
290
+ <input type="text" id="node-input-unitId" placeholder="1">
291
+ </div>
292
+ </div>
293
+ </div>
294
+
295
+ <div class="aw-section">
296
+ <p class="aw-title"><i class="fa fa-cube"></i> Module Profile</p>
297
+ <p class="aw-note">Alege modelul ADAM instalat. Profilul ales este folosit direct pentru validarea canalelor, fara detectie automata din registrul modulului.</p>
298
+ <div class="aw-grid">
299
+ <div class="form-row" id="row-module-type">
300
+ <label for="node-input-moduleType"><i class="fa fa-cube"></i> Module</label>
301
+ <select id="node-input-moduleType">
302
+ <option value="ADAM-6017">ADAM-6017</option>
303
+ <option value="ADAM-6018">ADAM-6018</option>
304
+ <option value="ADAM-6022">ADAM-6022</option>
305
+ <option value="ADAM-6024">ADAM-6024</option>
306
+ <option value="ADAM-6050">ADAM-6050</option>
307
+ <option value="ADAM-6051">ADAM-6051</option>
308
+ <option value="ADAM-6052">ADAM-6052</option>
309
+ <option value="ADAM-6060">ADAM-6060</option>
310
+ <option value="ADAM-6066">ADAM-6066</option>
311
+ </select>
312
+ <span class="aw-inline-note" id="module-type-note"></span>
313
+ </div>
314
+ <div class="form-row aw-advanced">
315
+ <label for="node-input-addressMode"><i class="fa fa-map-marker"></i> Addresses</label>
316
+ <select id="node-input-addressMode">
317
+ <option value="manual">Manual format (00017 / 40011)</option>
318
+ <option value="zero">Zero-based Modbus offsets</option>
319
+ </select>
320
+ </div>
321
+ <div class="form-row aw-advanced">
322
+ <label for="node-input-writeType"><i class="fa fa-pencil"></i> Write</label>
323
+ <select id="node-input-writeType">
324
+ <option value="do">Digital outputs</option>
325
+ <option value="ao">Analog outputs</option>
326
+ <option value="both">DO and AO from payload</option>
327
+ </select>
328
+ </div>
329
+ </div>
330
+ </div>
331
+
332
+ <div class="aw-section">
333
+ <p class="aw-title"><i class="fa fa-toggle-on"></i> Digital Outputs</p>
334
+ <p class="aw-note">Implicit, DO incepe la <code>00017</code>. Pentru modulele CE/D se poate permite si scrierea registrului agregat <code>40303</code>.</p>
335
+ <div class="aw-grid">
336
+ <div class="form-row">
337
+ <label for="node-input-doCommandMode">DO Mode</label>
338
+ <select id="node-input-doCommandMode">
339
+ <option value="single">Single selected DO</option>
340
+ <option value="multiple">Multiple DO from one message</option>
341
+ </select>
342
+ </div>
343
+ <div class="form-row aw-advanced"><label for="node-input-doStart"><i class="fa fa-toggle-on"></i> DO Start</label><input type="text" id="node-input-doStart" placeholder="17"></div>
344
+ <div class="form-row">
345
+ <label for="node-input-defaultChannel">Selected DO</label>
346
+ <select id="node-input-defaultChannel"></select>
347
+ </div>
348
+ <div class="form-row aw-checkbox aw-advanced"><label for="node-input-allowDoMask">DO Mask</label><input type="checkbox" id="node-input-allowDoMask"></div>
349
+ <div class="form-row aw-advanced"><label for="node-input-doMaskRegister">Mask Reg</label><input type="text" id="node-input-doMaskRegister" placeholder="40303"></div>
350
+ </div>
351
+ <p class="aw-note" id="single-do-note" style="margin-top:12px;">In modul Single, un payload boolean schimba DO-ul selectat. Lista este generata automat dupa modelul ales.</p>
352
+ <p class="aw-note" id="multiple-do-note" style="margin-top:12px;">In modul Multiple, poti trimite un array sau un obiect <code>{ "do": [...] }</code>; fiecare pozitie corespunde unui DO.</p>
353
+ </div>
354
+
355
+ <div class="aw-section aw-advanced">
356
+ <p class="aw-title"><i class="fa fa-sliders"></i> Analog Outputs</p>
357
+ <p class="aw-note">Pentru ADAM-6024, AO incepe la <code>40011</code>. Valorile sunt convertite cu formula raw = (valoare - offset) / scale.</p>
358
+ <div class="aw-grid">
359
+ <div class="form-row"><label for="node-input-aoStart"><i class="fa fa-sliders"></i> AO Start</label><input type="text" id="node-input-aoStart" placeholder="40011"></div>
360
+ <div class="form-row"><label for="node-input-aoScale">AO Scale</label><input type="text" id="node-input-aoScale" placeholder="1"></div>
361
+ <div class="form-row"><label for="node-input-aoOffset">AO Offset</label><input type="text" id="node-input-aoOffset" placeholder="0"></div>
362
+ <div class="form-row aw-checkbox"><label for="node-input-verifyWrite">Verify</label><input type="checkbox" id="node-input-verifyWrite"></div>
363
+ </div>
364
+ </div>
365
+ </div>
366
+ </script>
367
+
368
+ <script type="text/html" data-help-name="advantech-write">
369
+ <p>Nodul <b>advantech-write</b> scrie iesiri pe module Advantech ADAM-6000 prin Modbus TCP.</p>
370
+ <h3>Profil modul</h3>
371
+ <p>Alege modelul real al modulului in campul <b>Module</b>. Nodul foloseste direct profilul ales pentru validarea canalelor DO/AO, fara sa mai citeasca registrul de identificare al modulului.</p>
372
+ <p>Aceasta abordare evita cazul in care un ADAM-6066 raporteaza prin registru codul ADAM-6060. Pentru ADAM-6066, alege explicit <b>ADAM-6066</b>.</p>
373
+
374
+ <h3>Nume automat</h3>
375
+ <p>Nodul isi actualizeaza automat numele dupa model, modul DO si canalul selectat. Exemplu: <code>advantech-write 6066 DO1</code>. Cand schimbi <b>Selected DO</b>, numele se actualizeaza imediat. In modul multi-DO, numele devine de forma <code>advantech-write 6066 DO multi</code>.</p>
376
+
377
+ <h3>Digital outputs</h3>
378
+ <p><b>DO Mode</b> controleaza modul de lucru al intrarii digitale:</p>
379
+ <ul>
380
+ <li><b>Single selected DO</b> - un payload simplu schimba doar canalul din <b>Selected DO</b>.</li>
381
+ <li><b>Multiple DO from one message</b> - un singur mesaj poate schimba mai multe iesiri digitale folosind un array sau obiect.</li>
382
+ </ul>
383
+ <p><b>Selected DO</b> este generat automat dupa modelul ales. De exemplu, ADAM-6066 afiseaza doar DO 1 pana la DO 6, astfel incat sa nu poti selecta un canal inexistent. Intern, canalele raman zero-based: DO 1 din lista inseamna canalul <code>0</code>, DO 2 inseamna canalul <code>1</code> etc.</p>
384
+ <p>Adresa Modbus folosita este <code>DO Start + channel</code>; implicit <code>DO Start</code> este <code>00017</code>.</p>
385
+
386
+ <h3>Input DO single</h3>
387
+ <pre>msg.payload = true</pre>
388
+ <pre>msg.payload = false</pre>
389
+ <pre>msg.payload = { "channel": 2, "value": true }</pre>
390
+ <pre>msg.payload = { "do_channel": 2, "do_value": true }</pre>
391
+
392
+ <h3>Input DO multiplu</h3>
393
+ <pre>msg.payload = [true, false, true]</pre>
394
+ <pre>msg.payload = { "do": [true, false, true, false, true, false] }</pre>
395
+ <p>Array-ul scrie incepand cu DO 0. Exemplul de mai sus seteaza DO0 = true, DO1 = false, DO2 = true etc. Valorile acceptate sunt boolean, <code>0/1</code>, sau texte precum <code>on</code>, <code>off</code>, <code>true</code>, <code>false</code>.</p>
396
+
397
+ <h3>DO Mask</h3>
398
+ <p>Daca activezi <b>DO Mask</b>, poti scrie registrul agregat configurat in <b>Mask Reg</b>, implicit <code>40303</code>, cu un payload de forma:</p>
399
+ <pre>msg.payload = { "do_mask": 21 }</pre>
400
+ <p>Masca este utila cand modulul accepta scrierea tuturor iesirilor printr-un singur registru. Bitul 0 corespunde DO0, bitul 1 corespunde DO1 etc.</p>
401
+
402
+ <h3>Input AO</h3>
403
+ <pre>msg.payload = { "ao_channel": 0, "ao_value": 1200 }</pre>
404
+ <pre>msg.payload = { "ao": [1000, 2000] }</pre>
405
+ <pre>msg.payload = { "ao_channel": 0, "ao_raw": 32768 }</pre>
406
+ <p>Pentru AO, valoarea este convertita cu formula <code>raw = (value - AO Offset) / AO Scale</code>. <code>ao_raw</code> permite scrierea directa a valorii brute pe 16 biti.</p>
407
+
408
+ <h3>Confirmare</h3>
409
+ <p>Daca <b>Verify</b> este activ, nodul citeste inapoi DO/AO dupa scriere si raporteaza eroare daca valoarea confirmata nu corespunde comenzii.</p>
410
+
411
+ <h3>Output</h3>
412
+ <p>La succes, nodul trimite un mesaj cu <code>payload.status = "ok"</code>, modelul detectat, numarul de canale si lista <code>payload.written</code> cu operatiile executate.</p>
413
+ </script>