@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.
- package/NOTICE +56 -0
- package/PROPRIETARY-LICENSE.txt +157 -0
- package/README.md +105 -0
- package/TERMS-AND-CONDITIONS.md +311 -0
- package/advantech-read/advantech-read.html +775 -0
- package/advantech-read/advantech-read.js +449 -0
- package/advantech-write/advantech-write.html +413 -0
- package/advantech-write/advantech-write.js +338 -0
- package/bess-control/bess-control.html +569 -0
- package/bess-control/bess-control.js +541 -0
- package/bess-control/lib/allocation.js +149 -0
- package/bess-control/lib/batteries.js +86 -0
- package/bess-control/lib/helpers.js +157 -0
- package/bess-control/lib/messages.js +131 -0
- package/bess-control/lib/runtime.js +156 -0
- package/carlo-gavazzi/carlo-gavazzi.html +4327 -0
- package/carlo-gavazzi/carlo-gavazzi.js +3081 -0
- package/control-export/control-export.html +3644 -0
- package/control-export/control-export.js +2192 -0
- package/control-reactive/control-reactive.html +3136 -0
- package/control-reactive/control-reactive.js +2124 -0
- package/fronius-emulator/README.md +258 -0
- package/fronius-emulator/fronius-emulator.html +170 -0
- package/fronius-emulator/fronius-emulator.js +520 -0
- package/fronius-emulator/lib/binary-codec.js +65 -0
- package/fronius-emulator/lib/fronius-register-map.js +185 -0
- package/fronius-emulator/lib/modbus-parser.js +61 -0
- package/fronius-emulator/lib/modbus-tcp-server.js +224 -0
- package/fronius-emulator/lib/validation.js +206 -0
- package/fronius-emulator/lib/virtual-meter.js +132 -0
- package/fronius-read/fronius-read.html +3944 -0
- package/fronius-read/fronius-read.js +1466 -0
- package/fronius-read/lib/inverter-profiles.js +711 -0
- package/fronius-read/lib/sunspec-core.js +303 -0
- package/fronius-read/lib/sunspec-model-parsers.js +845 -0
- package/fronius-write/fronius-write.html +1789 -0
- package/fronius-write/fronius-write.js +2531 -0
- package/influxdb/influxdb.html +1077 -0
- package/influxdb/influxdb.js +1487 -0
- package/janitza/janitza.html +2562 -0
- package/janitza/janitza.js +1500 -0
- package/janitza/lib/janitza-profiles.js +371 -0
- package/lib/a3-test-server.js +199 -0
- package/lib/adam-6000-profiles.js +173 -0
- package/lib/licensing/constants.js +103 -0
- package/lib/licensing/device-id.js +251 -0
- package/lib/licensing/errors.js +21 -0
- package/lib/licensing/license-client.js +377 -0
- package/lib/licensing/license-state.js +50 -0
- package/lib/licensing/node-guard.js +150 -0
- package/lib/licensing/package-integrity.js +167 -0
- package/lib/licensing/package-integrity.json +513 -0
- package/lib/licensing/public-key.pem +3 -0
- package/lib/licensing/public-key.pem.example +2 -0
- package/lib/licensing/public-keys.js +18 -0
- package/lib/licensing/storage.js +63 -0
- package/lib/licensing/token-verifier.js +84 -0
- package/lib/numbers.js +26 -0
- package/license/atelier-license.html +88 -0
- package/license/atelier-license.js +170 -0
- package/modbus-tcp-discover/modbus-tcp-discover.html +190 -0
- package/modbus-tcp-discover/modbus-tcp-discover.js +706 -0
- package/multi-battery/multi-battery.html +649 -0
- package/multi-battery/multi-battery.js +668 -0
- package/multi-grid/multi-grid.html +745 -0
- package/multi-grid/multi-grid.js +1392 -0
- package/multi-inverter/lib/engine-core.js +237 -0
- package/multi-inverter/multi-inverter.html +2674 -0
- package/multi-inverter/multi-inverter.js +1393 -0
- package/package.json +109 -0
- package/phoenix-contact/lib/eem-ma370-advanced.js +175 -0
- package/phoenix-contact/lib/eem-ma370.js +138 -0
- package/phoenix-contact/lib/integrations.js +149 -0
- package/phoenix-contact/lib/phoenix-contact-profile.js +35030 -0
- package/phoenix-contact/phoenix-contact.html +840 -0
- package/phoenix-contact/phoenix-contact.js +679 -0
- package/pv-generator/pv-generator.html +284 -0
- package/pv-generator/pv-generator.js +387 -0
- package/pylontech-read/pylontech-read.html +763 -0
- package/pylontech-read/pylontech-read.js +518 -0
- package/pylontech-write/pylontech-write.html +405 -0
- package/pylontech-write/pylontech-write.js +546 -0
- package/scada-aggregator/lib/aggregate.js +72 -0
- package/scada-aggregator/lib/groups.js +39 -0
- package/scada-aggregator/scada-aggregator.html +108 -0
- package/scada-aggregator/scada-aggregator.js +117 -0
- package/scada-server/lib/aggregator-map.js +58 -0
- package/scada-server/lib/encoding.js +235 -0
- package/scada-server/lib/modbus-server.js +492 -0
- package/scada-server/lib/object-path.js +18 -0
- package/scada-server/lib/register-map.js +288 -0
- package/scada-server/scada-server.html +1419 -0
- package/scada-server/scada-server.js +704 -0
- package/scripts/check-syntax.js +66 -0
- package/scripts/package-integrity.js +46 -0
- package/scripts/package-release.js +116 -0
- package/scripts/run-tests.js +2178 -0
- package/scripts/tgz-integrity.js +74 -0
- package/sma-read/lib/sunspec-core.js +83 -0
- package/sma-read/lib/sunspec-model-parsers.js +853 -0
- package/sma-read/sma-read.html +659 -0
- package/sma-read/sma-read.js +458 -0
- package/sma-write/sma-write.html +105 -0
- package/sma-write/sma-write.js +270 -0
- package/victron-read/lib/mqtt-state.js +176 -0
- package/victron-read/victron-read.html +1074 -0
- package/victron-read/victron-read.js +1222 -0
|
@@ -0,0 +1,3944 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
(function () {
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
|
|
9
|
+
PAYLOAD_OPTION_GROUPS,
|
|
10
|
+
|
|
11
|
+
INVERTER_PROFILES,
|
|
12
|
+
|
|
13
|
+
buildMpptOptions,
|
|
14
|
+
|
|
15
|
+
buildAcOptions,
|
|
16
|
+
|
|
17
|
+
resolveProfile
|
|
18
|
+
|
|
19
|
+
} = (function () {
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
const AC_OPTIONS_COMMON = [
|
|
23
|
+
|
|
24
|
+
{ value: "summary.ac.power_w", label: "Putere AC (W)" },
|
|
25
|
+
|
|
26
|
+
{ value: "summary.ac.frequency_hz", label: "Frecventa (Hz)" },
|
|
27
|
+
|
|
28
|
+
{ value: "summary.ac.apparent_power_va", label: "Putere aparenta (VA)" },
|
|
29
|
+
|
|
30
|
+
{ value: "summary.ac.reactive_power_var", label: "Putere reactiva (var)" }
|
|
31
|
+
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const AC_OPTIONS_SINGLE_PHASE = [
|
|
36
|
+
|
|
37
|
+
{ value: "summary.ac.current_total_a", label: "Curent total (A)" },
|
|
38
|
+
|
|
39
|
+
{ value: "summary.ac.current_l1_a", label: "Curent L1 (A)" },
|
|
40
|
+
|
|
41
|
+
{ value: "summary.ac.voltage_l1_v", label: "Tensiune L1 (V)" }
|
|
42
|
+
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
const AC_OPTIONS_THREE_PHASE = [
|
|
47
|
+
|
|
48
|
+
{ value: "summary.ac.current_total_a", label: "Curent total (A)" },
|
|
49
|
+
|
|
50
|
+
{ value: "summary.ac.current_l1_a", label: "Curent L1 (A)" },
|
|
51
|
+
|
|
52
|
+
{ value: "summary.ac.current_l2_a", label: "Curent L2 (A)" },
|
|
53
|
+
|
|
54
|
+
{ value: "summary.ac.current_l3_a", label: "Curent L3 (A)" },
|
|
55
|
+
|
|
56
|
+
{ value: "summary.ac.voltage_ll_ab_v", label: "Tensiune AB (V)" },
|
|
57
|
+
|
|
58
|
+
{ value: "summary.ac.voltage_ll_bc_v", label: "Tensiune BC (V)" },
|
|
59
|
+
|
|
60
|
+
{ value: "summary.ac.voltage_ll_ca_v", label: "Tensiune CA (V)" },
|
|
61
|
+
|
|
62
|
+
{ value: "summary.ac.voltage_l1_v", label: "Tensiune L1 (V)" },
|
|
63
|
+
|
|
64
|
+
{ value: "summary.ac.voltage_l2_v", label: "Tensiune L2 (V)" },
|
|
65
|
+
|
|
66
|
+
{ value: "summary.ac.voltage_l3_v", label: "Tensiune L3 (V)" }
|
|
67
|
+
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
const PAYLOAD_OPTION_GROUPS = {
|
|
72
|
+
|
|
73
|
+
meter: [
|
|
74
|
+
|
|
75
|
+
{ value: "summary.meter.model_id", label: "Model ID" },
|
|
76
|
+
|
|
77
|
+
{ value: "summary.meter.meter_model", label: "Model" },
|
|
78
|
+
|
|
79
|
+
{ value: "summary.meter.power_w", label: "Putere activa (W)" },
|
|
80
|
+
|
|
81
|
+
{ value: "summary.meter.power_l1_w", label: "Putere L1 (W)" },
|
|
82
|
+
|
|
83
|
+
{ value: "summary.meter.power_l2_w", label: "Putere L2 (W)" },
|
|
84
|
+
|
|
85
|
+
{ value: "summary.meter.power_l3_w", label: "Putere L3 (W)" },
|
|
86
|
+
|
|
87
|
+
{ value: "summary.meter.current_total_a", label: "Curent total (A)" },
|
|
88
|
+
|
|
89
|
+
{ value: "summary.meter.current_l1_a", label: "Curent L1 (A)" },
|
|
90
|
+
|
|
91
|
+
{ value: "summary.meter.current_l2_a", label: "Curent L2 (A)" },
|
|
92
|
+
|
|
93
|
+
{ value: "summary.meter.current_l3_a", label: "Curent L3 (A)" },
|
|
94
|
+
|
|
95
|
+
{ value: "summary.meter.voltage_ln_avg_v", label: "Tensiune L-N medie (V)" },
|
|
96
|
+
|
|
97
|
+
{ value: "summary.meter.voltage_l1_v", label: "Tensiune L1 (V)" },
|
|
98
|
+
|
|
99
|
+
{ value: "summary.meter.voltage_l2_v", label: "Tensiune L2 (V)" },
|
|
100
|
+
|
|
101
|
+
{ value: "summary.meter.voltage_l3_v", label: "Tensiune L3 (V)" },
|
|
102
|
+
|
|
103
|
+
{ value: "summary.meter.voltage_ll_avg_v", label: "Tensiune L-L medie (V)" },
|
|
104
|
+
|
|
105
|
+
{ value: "summary.meter.voltage_ll_ab_v", label: "Tensiune L1-L2 (V)" },
|
|
106
|
+
|
|
107
|
+
{ value: "summary.meter.voltage_ll_bc_v", label: "Tensiune L2-L3 (V)" },
|
|
108
|
+
|
|
109
|
+
{ value: "summary.meter.voltage_ll_ca_v", label: "Tensiune L3-L1 (V)" },
|
|
110
|
+
|
|
111
|
+
{ value: "summary.meter.frequency_hz", label: "Frecventa (Hz)" },
|
|
112
|
+
|
|
113
|
+
{ value: "summary.meter.apparent_power_va", label: "Putere aparenta (VA)" },
|
|
114
|
+
|
|
115
|
+
{ value: "summary.meter.apparent_power_l1_va", label: "Putere aparenta L1 (VA)" },
|
|
116
|
+
|
|
117
|
+
{ value: "summary.meter.apparent_power_l2_va", label: "Putere aparenta L2 (VA)" },
|
|
118
|
+
|
|
119
|
+
{ value: "summary.meter.apparent_power_l3_va", label: "Putere aparenta L3 (VA)" },
|
|
120
|
+
|
|
121
|
+
{ value: "summary.meter.reactive_power_var", label: "Putere reactiva (var)" },
|
|
122
|
+
|
|
123
|
+
{ value: "summary.meter.reactive_power_l1_var", label: "Putere reactiva L1 (var)" },
|
|
124
|
+
|
|
125
|
+
{ value: "summary.meter.reactive_power_l2_var", label: "Putere reactiva L2 (var)" },
|
|
126
|
+
|
|
127
|
+
{ value: "summary.meter.reactive_power_l3_var", label: "Putere reactiva L3 (var)" },
|
|
128
|
+
|
|
129
|
+
{ value: "summary.meter.power_factor", label: "Factor putere" },
|
|
130
|
+
|
|
131
|
+
{ value: "summary.meter.power_factor_l1", label: "Factor putere L1" },
|
|
132
|
+
|
|
133
|
+
{ value: "summary.meter.power_factor_l2", label: "Factor putere L2" },
|
|
134
|
+
|
|
135
|
+
{ value: "summary.meter.power_factor_l3", label: "Factor putere L3" },
|
|
136
|
+
|
|
137
|
+
{ value: "summary.meter.energy_import_wh", label: "Energie import (Wh)" },
|
|
138
|
+
|
|
139
|
+
{ value: "summary.meter.energy_import_l1_wh", label: "Energie import L1 (Wh)" },
|
|
140
|
+
|
|
141
|
+
{ value: "summary.meter.energy_import_l2_wh", label: "Energie import L2 (Wh)" },
|
|
142
|
+
|
|
143
|
+
{ value: "summary.meter.energy_import_l3_wh", label: "Energie import L3 (Wh)" },
|
|
144
|
+
|
|
145
|
+
{ value: "summary.meter.energy_export_wh", label: "Energie export (Wh)" },
|
|
146
|
+
|
|
147
|
+
{ value: "summary.meter.energy_export_l1_wh", label: "Energie export L1 (Wh)" },
|
|
148
|
+
|
|
149
|
+
{ value: "summary.meter.energy_export_l2_wh", label: "Energie export L2 (Wh)" },
|
|
150
|
+
|
|
151
|
+
{ value: "summary.meter.energy_export_l3_wh", label: "Energie export L3 (Wh)" },
|
|
152
|
+
|
|
153
|
+
{ value: "summary.meter.apparent_energy_import_vah", label: "Energie aparenta import (VAh)" },
|
|
154
|
+
|
|
155
|
+
{ value: "summary.meter.apparent_energy_export_vah", label: "Energie aparenta export (VAh)" },
|
|
156
|
+
|
|
157
|
+
{ value: "summary.meter.reactive_energy_import_q1_varh", label: "Energie reactiva import Q1 (varh)" },
|
|
158
|
+
|
|
159
|
+
{ value: "summary.meter.reactive_energy_import_q2_varh", label: "Energie reactiva import Q2 (varh)" },
|
|
160
|
+
|
|
161
|
+
{ value: "summary.meter.reactive_energy_export_q3_varh", label: "Energie reactiva export Q3 (varh)" },
|
|
162
|
+
|
|
163
|
+
{ value: "summary.meter.reactive_energy_export_q4_varh", label: "Energie reactiva export Q4 (varh)" },
|
|
164
|
+
|
|
165
|
+
{ value: "summary.meter.event_flags", label: "Event flags" }
|
|
166
|
+
|
|
167
|
+
],
|
|
168
|
+
|
|
169
|
+
dcGeneral: [
|
|
170
|
+
|
|
171
|
+
{ value: "summary.dc.dc_total_power_w", label: "Putere DC totala (W)" },
|
|
172
|
+
|
|
173
|
+
{ value: "summary.dc.module_count", label: "Numar module/stringuri DC (brut)" },
|
|
174
|
+
|
|
175
|
+
{ value: "summary.dc.global_event", label: "Eveniment DC global" }
|
|
176
|
+
|
|
177
|
+
],
|
|
178
|
+
|
|
179
|
+
device: [
|
|
180
|
+
|
|
181
|
+
{ value: "summary.common.manufacturer", label: "Producator" },
|
|
182
|
+
|
|
183
|
+
{ value: "summary.common.model", label: "Model" },
|
|
184
|
+
|
|
185
|
+
{ value: "summary.common.options", label: "Optiuni" },
|
|
186
|
+
|
|
187
|
+
{ value: "summary.common.version", label: "Versiune" },
|
|
188
|
+
|
|
189
|
+
{ value: "summary.common.serial", label: "Serie" },
|
|
190
|
+
|
|
191
|
+
{ value: "summary.common.device_address", label: "Adresa device" }
|
|
192
|
+
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
const INVERTER_PROFILES = {
|
|
199
|
+
|
|
200
|
+
auto: {
|
|
201
|
+
|
|
202
|
+
key: "auto",
|
|
203
|
+
|
|
204
|
+
label: "Auto Detect",
|
|
205
|
+
|
|
206
|
+
fallbackMpptCount: 4,
|
|
207
|
+
|
|
208
|
+
fallbackPhaseMode: "unknown",
|
|
209
|
+
|
|
210
|
+
includeAC: true,
|
|
211
|
+
|
|
212
|
+
includeDCGeneral: true,
|
|
213
|
+
|
|
214
|
+
includeDevice: true
|
|
215
|
+
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
fronius_verto: {
|
|
219
|
+
|
|
220
|
+
key: "fronius_verto",
|
|
221
|
+
|
|
222
|
+
label: "Fronius Verto",
|
|
223
|
+
|
|
224
|
+
fallbackMpptCount: 4,
|
|
225
|
+
|
|
226
|
+
fallbackPhaseMode: "three_phase",
|
|
227
|
+
|
|
228
|
+
includeAC: true,
|
|
229
|
+
|
|
230
|
+
includeDCGeneral: true,
|
|
231
|
+
|
|
232
|
+
includeDevice: true
|
|
233
|
+
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
fronius_symo: {
|
|
237
|
+
|
|
238
|
+
key: "fronius_symo",
|
|
239
|
+
|
|
240
|
+
label: "Fronius Symo",
|
|
241
|
+
|
|
242
|
+
fallbackMpptCount: 2,
|
|
243
|
+
|
|
244
|
+
fallbackPhaseMode: "three_phase",
|
|
245
|
+
|
|
246
|
+
includeAC: true,
|
|
247
|
+
|
|
248
|
+
includeDCGeneral: true,
|
|
249
|
+
|
|
250
|
+
includeDevice: true
|
|
251
|
+
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
fronius_primo: {
|
|
255
|
+
|
|
256
|
+
key: "fronius_primo",
|
|
257
|
+
|
|
258
|
+
label: "Fronius Primo",
|
|
259
|
+
|
|
260
|
+
fallbackMpptCount: 2,
|
|
261
|
+
|
|
262
|
+
fallbackPhaseMode: "single_phase",
|
|
263
|
+
|
|
264
|
+
includeAC: true,
|
|
265
|
+
|
|
266
|
+
includeDCGeneral: true,
|
|
267
|
+
|
|
268
|
+
includeDevice: true
|
|
269
|
+
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
fronius_eco: {
|
|
273
|
+
|
|
274
|
+
key: "fronius_eco",
|
|
275
|
+
|
|
276
|
+
label: "Fronius Eco",
|
|
277
|
+
|
|
278
|
+
fallbackMpptCount: 1,
|
|
279
|
+
|
|
280
|
+
fallbackPhaseMode: "three_phase",
|
|
281
|
+
|
|
282
|
+
includeAC: true,
|
|
283
|
+
|
|
284
|
+
includeDCGeneral: true,
|
|
285
|
+
|
|
286
|
+
includeDevice: true
|
|
287
|
+
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
fronius_tauro: {
|
|
291
|
+
|
|
292
|
+
key: "fronius_tauro",
|
|
293
|
+
|
|
294
|
+
label: "Fronius Tauro",
|
|
295
|
+
|
|
296
|
+
fallbackMpptCount: 3,
|
|
297
|
+
|
|
298
|
+
fallbackPhaseMode: "three_phase",
|
|
299
|
+
|
|
300
|
+
includeAC: true,
|
|
301
|
+
|
|
302
|
+
includeDCGeneral: true,
|
|
303
|
+
|
|
304
|
+
includeDevice: true
|
|
305
|
+
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
fronius_tauro_eco: {
|
|
309
|
+
|
|
310
|
+
key: "fronius_tauro_eco",
|
|
311
|
+
|
|
312
|
+
label: "Fronius Tauro Eco",
|
|
313
|
+
|
|
314
|
+
fallbackMpptCount: 1,
|
|
315
|
+
|
|
316
|
+
fallbackPhaseMode: "three_phase",
|
|
317
|
+
|
|
318
|
+
includeAC: true,
|
|
319
|
+
|
|
320
|
+
includeDCGeneral: true,
|
|
321
|
+
|
|
322
|
+
includeDevice: true
|
|
323
|
+
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
function buildMpptOptions(mpptIndex) {
|
|
330
|
+
|
|
331
|
+
return [
|
|
332
|
+
|
|
333
|
+
{ value: "summary.dc.mppts." + mpptIndex + ".dc_voltage_v", label: "Tensiune (V)" },
|
|
334
|
+
|
|
335
|
+
{ value: "summary.dc.mppts." + mpptIndex + ".dc_current_a", label: "Curent (A)" },
|
|
336
|
+
|
|
337
|
+
{ value: "summary.dc.mppts." + mpptIndex + ".dc_power_w", label: "Putere (W)" },
|
|
338
|
+
|
|
339
|
+
{ value: "summary.dc.mppts." + mpptIndex + ".dc_energy_wh", label: "Energie (Wh)" }
|
|
340
|
+
|
|
341
|
+
];
|
|
342
|
+
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
function buildAcOptions(phaseMode) {
|
|
347
|
+
|
|
348
|
+
const common = AC_OPTIONS_COMMON.slice();
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
if (phaseMode === "single_phase") {
|
|
352
|
+
|
|
353
|
+
return common.concat(AC_OPTIONS_SINGLE_PHASE);
|
|
354
|
+
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
if (phaseMode === "three_phase") {
|
|
359
|
+
|
|
360
|
+
return common.concat(AC_OPTIONS_THREE_PHASE);
|
|
361
|
+
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
const merged = [];
|
|
366
|
+
|
|
367
|
+
const seen = new Set();
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
common
|
|
371
|
+
|
|
372
|
+
.concat(AC_OPTIONS_SINGLE_PHASE)
|
|
373
|
+
|
|
374
|
+
.concat(AC_OPTIONS_THREE_PHASE)
|
|
375
|
+
|
|
376
|
+
.forEach(function (item) {
|
|
377
|
+
|
|
378
|
+
if (!seen.has(item.value)) {
|
|
379
|
+
|
|
380
|
+
seen.add(item.value);
|
|
381
|
+
|
|
382
|
+
merged.push(item);
|
|
383
|
+
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
return merged;
|
|
390
|
+
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
function resolveProfile(profileKey, detectedMpptCount, detectedPhaseMode) {
|
|
395
|
+
|
|
396
|
+
const profile = INVERTER_PROFILES[profileKey] || INVERTER_PROFILES.auto;
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
const resolvedMpptCount =
|
|
400
|
+
|
|
401
|
+
Number.isFinite(detectedMpptCount) && detectedMpptCount > 0
|
|
402
|
+
|
|
403
|
+
? detectedMpptCount
|
|
404
|
+
|
|
405
|
+
: profile.fallbackMpptCount;
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
const resolvedPhaseMode =
|
|
409
|
+
|
|
410
|
+
detectedPhaseMode && detectedPhaseMode !== "unknown"
|
|
411
|
+
|
|
412
|
+
? detectedPhaseMode
|
|
413
|
+
|
|
414
|
+
: profile.fallbackPhaseMode;
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
return Object.assign({}, profile, {
|
|
418
|
+
|
|
419
|
+
resolvedMpptCount: resolvedMpptCount,
|
|
420
|
+
|
|
421
|
+
resolvedPhaseMode: resolvedPhaseMode
|
|
422
|
+
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
|
|
430
|
+
PAYLOAD_OPTION_GROUPS: PAYLOAD_OPTION_GROUPS,
|
|
431
|
+
|
|
432
|
+
INVERTER_PROFILES: INVERTER_PROFILES,
|
|
433
|
+
|
|
434
|
+
buildMpptOptions: buildMpptOptions,
|
|
435
|
+
|
|
436
|
+
buildAcOptions: buildAcOptions,
|
|
437
|
+
|
|
438
|
+
resolveProfile: resolveProfile
|
|
439
|
+
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
})();
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
let detectedMpptCount = null;
|
|
447
|
+
|
|
448
|
+
let detectedProfileKey = "auto";
|
|
449
|
+
|
|
450
|
+
let detectedPhaseMode = "unknown";
|
|
451
|
+
|
|
452
|
+
let detectedDeviceType = "unknown";
|
|
453
|
+
|
|
454
|
+
let probeRequestId = 0;
|
|
455
|
+
|
|
456
|
+
let lastProbeKey = null;
|
|
457
|
+
|
|
458
|
+
let probeInFlight = false;
|
|
459
|
+
|
|
460
|
+
let lastGoodProbeInfo = null;
|
|
461
|
+
|
|
462
|
+
let payloadSelectionState = ["full"];
|
|
463
|
+
|
|
464
|
+
let payloadModeState = "full";
|
|
465
|
+
|
|
466
|
+
let multiInverterCustomPayloadEnabledState = false;
|
|
467
|
+
|
|
468
|
+
let influxCustomPayloadEnabledState = false;
|
|
469
|
+
|
|
470
|
+
let influxCustomPayloadWasSavedState = false;
|
|
471
|
+
|
|
472
|
+
let multiAdvancedUnlockedState = false;
|
|
473
|
+
|
|
474
|
+
let multiLongPressTimer = null;
|
|
475
|
+
|
|
476
|
+
let multiLongPressTriggered = false;
|
|
477
|
+
|
|
478
|
+
let multiLongPressStartSelector = null;
|
|
479
|
+
|
|
480
|
+
let suppressAdvancedResetOnce = false;
|
|
481
|
+
|
|
482
|
+
const MULTI_EXPERT_LONG_PRESS_MS = 5000;
|
|
483
|
+
const DEFAULT_INFLUX_PAYLOAD_FIELDS = [
|
|
484
|
+
"summary.ac.power_w",
|
|
485
|
+
"summary.ac.frequency_hz",
|
|
486
|
+
"summary.ac.apparent_power_va",
|
|
487
|
+
"summary.ac.reactive_power_var",
|
|
488
|
+
"summary.dc.dc_total_power_w",
|
|
489
|
+
"summary.ac.voltage_l1_v",
|
|
490
|
+
"summary.ac.voltage_l2_v",
|
|
491
|
+
"summary.ac.voltage_l3_v"
|
|
492
|
+
];
|
|
493
|
+
const DEFAULT_MULTI_GRID_PAYLOAD_FIELDS = [
|
|
494
|
+
"summary.meter.power_w",
|
|
495
|
+
"summary.meter.power_l1_w",
|
|
496
|
+
"summary.meter.power_l2_w",
|
|
497
|
+
"summary.meter.power_l3_w"
|
|
498
|
+
];
|
|
499
|
+
const DEFAULT_METER_INFLUX_PAYLOAD_FIELDS = [
|
|
500
|
+
"summary.meter.power_w",
|
|
501
|
+
"summary.meter.power_l1_w",
|
|
502
|
+
"summary.meter.power_l2_w",
|
|
503
|
+
"summary.meter.power_l3_w",
|
|
504
|
+
"summary.meter.current_total_a",
|
|
505
|
+
"summary.meter.current_l1_a",
|
|
506
|
+
"summary.meter.current_l2_a",
|
|
507
|
+
"summary.meter.current_l3_a",
|
|
508
|
+
"summary.meter.voltage_ln_avg_v",
|
|
509
|
+
"summary.meter.voltage_l1_v",
|
|
510
|
+
"summary.meter.voltage_l2_v",
|
|
511
|
+
"summary.meter.voltage_l3_v",
|
|
512
|
+
"summary.meter.voltage_ll_avg_v",
|
|
513
|
+
"summary.meter.voltage_ll_ab_v",
|
|
514
|
+
"summary.meter.voltage_ll_bc_v",
|
|
515
|
+
"summary.meter.voltage_ll_ca_v",
|
|
516
|
+
"summary.meter.frequency_hz",
|
|
517
|
+
"summary.meter.apparent_power_va",
|
|
518
|
+
"summary.meter.apparent_power_l1_va",
|
|
519
|
+
"summary.meter.apparent_power_l2_va",
|
|
520
|
+
"summary.meter.apparent_power_l3_va",
|
|
521
|
+
"summary.meter.reactive_power_var",
|
|
522
|
+
"summary.meter.reactive_power_l1_var",
|
|
523
|
+
"summary.meter.reactive_power_l2_var",
|
|
524
|
+
"summary.meter.reactive_power_l3_var",
|
|
525
|
+
"summary.meter.power_factor"
|
|
526
|
+
];
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
function normalizeSelectedValues(value) {
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
if (Array.isArray(value)) {
|
|
533
|
+
|
|
534
|
+
const filtered = value
|
|
535
|
+
|
|
536
|
+
.map(function (v) { return String(v || "").trim(); })
|
|
537
|
+
|
|
538
|
+
.filter(Boolean);
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
return filtered.length ? filtered : ["full"];
|
|
542
|
+
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
if (typeof value === "string") {
|
|
547
|
+
|
|
548
|
+
const trimmed = value.trim();
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
if (!trimmed) {
|
|
552
|
+
|
|
553
|
+
return ["full"];
|
|
554
|
+
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
if (trimmed[0] === "[") {
|
|
559
|
+
|
|
560
|
+
try {
|
|
561
|
+
|
|
562
|
+
const parsed = JSON.parse(trimmed);
|
|
563
|
+
|
|
564
|
+
if (Array.isArray(parsed)) {
|
|
565
|
+
|
|
566
|
+
return normalizeSelectedValues(parsed);
|
|
567
|
+
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
} catch (e) {
|
|
571
|
+
|
|
572
|
+
// ignore
|
|
573
|
+
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
return [trimmed];
|
|
580
|
+
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
return ["full"];
|
|
585
|
+
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
function dedupeSelectedValues(values) {
|
|
590
|
+
|
|
591
|
+
return Array.from(new Set(normalizeSelectedValues(values)));
|
|
592
|
+
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
function normalizePayloadMode(mode) {
|
|
597
|
+
|
|
598
|
+
return mode === "selected" ? "selected" : "full";
|
|
599
|
+
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
function inferPayloadModeFromSelection(values) {
|
|
604
|
+
|
|
605
|
+
const normalized = dedupeSelectedValues(values);
|
|
606
|
+
|
|
607
|
+
return normalized.includes("full") ? "full" : "selected";
|
|
608
|
+
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
function sanitizeSelectedValues(values, previousValues, allowEmpty) {
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
const normalized = dedupeSelectedValues(values);
|
|
616
|
+
|
|
617
|
+
const previous = dedupeSelectedValues(previousValues || []);
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
if (normalized.includes("full") && normalized.length > 1) {
|
|
621
|
+
|
|
622
|
+
if (!previous.includes("full")) {
|
|
623
|
+
|
|
624
|
+
return normalized.filter(function (v) {
|
|
625
|
+
|
|
626
|
+
return v !== "full";
|
|
627
|
+
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
return ["full"];
|
|
633
|
+
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
return normalized.length ? normalized : (allowEmpty ? [] : ["full"]);
|
|
638
|
+
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
function applyExclusiveSelectionRule(selected, changedValue, checked) {
|
|
643
|
+
|
|
644
|
+
const unique = Array.from(new Set((selected || []).filter(Boolean)));
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
if (changedValue === "full") {
|
|
648
|
+
|
|
649
|
+
if (checked) {
|
|
650
|
+
|
|
651
|
+
return ["full"];
|
|
652
|
+
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
return unique.length ? unique.filter(function (v) { return v !== "full"; }) : ["full"];
|
|
656
|
+
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
if (checked) {
|
|
661
|
+
|
|
662
|
+
return unique.filter(function (v) {
|
|
663
|
+
|
|
664
|
+
return v !== "full";
|
|
665
|
+
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
const withoutEmpty = unique.filter(Boolean);
|
|
672
|
+
|
|
673
|
+
return withoutEmpty.length ? withoutEmpty : ["full"];
|
|
674
|
+
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
function getPayloadLabel(path) {
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
const labels = {
|
|
682
|
+
|
|
683
|
+
"full": "Toate valorile",
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
"summary.ac.power_w": "Putere AC (W)",
|
|
687
|
+
|
|
688
|
+
"summary.ac.frequency_hz": "Frecventa (Hz)",
|
|
689
|
+
|
|
690
|
+
"summary.ac.apparent_power_va": "Putere aparenta (VA)",
|
|
691
|
+
|
|
692
|
+
"summary.ac.reactive_power_var": "Putere reactiva (var)",
|
|
693
|
+
|
|
694
|
+
"summary.ac.current_total_a": "Curent total (A)",
|
|
695
|
+
|
|
696
|
+
"summary.ac.current_l1_a": "Curent L1 (A)",
|
|
697
|
+
|
|
698
|
+
"summary.ac.current_l2_a": "Curent L2 (A)",
|
|
699
|
+
|
|
700
|
+
"summary.ac.current_l3_a": "Curent L3 (A)",
|
|
701
|
+
|
|
702
|
+
"summary.ac.voltage_ll_ab_v": "Tensiune AB (V)",
|
|
703
|
+
|
|
704
|
+
"summary.ac.voltage_ll_bc_v": "Tensiune BC (V)",
|
|
705
|
+
|
|
706
|
+
"summary.ac.voltage_ll_ca_v": "Tensiune CA (V)",
|
|
707
|
+
|
|
708
|
+
"summary.ac.voltage_l1_v": "Tensiune L1 (V)",
|
|
709
|
+
|
|
710
|
+
"summary.ac.voltage_l2_v": "Tensiune L2 (V)",
|
|
711
|
+
|
|
712
|
+
"summary.ac.voltage_l3_v": "Tensiune L3 (V)",
|
|
713
|
+
|
|
714
|
+
"summary.meter.model_id": "Model ID",
|
|
715
|
+
|
|
716
|
+
"summary.meter.meter_model": "Model",
|
|
717
|
+
|
|
718
|
+
"summary.meter.power_w": "Putere activa (W)",
|
|
719
|
+
|
|
720
|
+
"summary.meter.power_l1_w": "Putere L1 (W)",
|
|
721
|
+
|
|
722
|
+
"summary.meter.power_l2_w": "Putere L2 (W)",
|
|
723
|
+
|
|
724
|
+
"summary.meter.power_l3_w": "Putere L3 (W)",
|
|
725
|
+
|
|
726
|
+
"summary.meter.current_total_a": "Curent total (A)",
|
|
727
|
+
|
|
728
|
+
"summary.meter.current_l1_a": "Curent L1 (A)",
|
|
729
|
+
|
|
730
|
+
"summary.meter.current_l2_a": "Curent L2 (A)",
|
|
731
|
+
|
|
732
|
+
"summary.meter.current_l3_a": "Curent L3 (A)",
|
|
733
|
+
|
|
734
|
+
"summary.meter.voltage_ln_avg_v": "Tensiune L-N medie (V)",
|
|
735
|
+
|
|
736
|
+
"summary.meter.voltage_l1_v": "Tensiune L1 (V)",
|
|
737
|
+
|
|
738
|
+
"summary.meter.voltage_l2_v": "Tensiune L2 (V)",
|
|
739
|
+
|
|
740
|
+
"summary.meter.voltage_l3_v": "Tensiune L3 (V)",
|
|
741
|
+
|
|
742
|
+
"summary.meter.voltage_ll_avg_v": "Tensiune L-L medie (V)",
|
|
743
|
+
|
|
744
|
+
"summary.meter.voltage_ll_ab_v": "Tensiune L1-L2 (V)",
|
|
745
|
+
|
|
746
|
+
"summary.meter.voltage_ll_bc_v": "Tensiune L2-L3 (V)",
|
|
747
|
+
|
|
748
|
+
"summary.meter.voltage_ll_ca_v": "Tensiune L3-L1 (V)",
|
|
749
|
+
|
|
750
|
+
"summary.meter.frequency_hz": "Frecventa (Hz)",
|
|
751
|
+
|
|
752
|
+
"summary.meter.apparent_power_va": "Putere aparenta (VA)",
|
|
753
|
+
|
|
754
|
+
"summary.meter.apparent_power_l1_va": "Putere aparenta L1 (VA)",
|
|
755
|
+
|
|
756
|
+
"summary.meter.apparent_power_l2_va": "Putere aparenta L2 (VA)",
|
|
757
|
+
|
|
758
|
+
"summary.meter.apparent_power_l3_va": "Putere aparenta L3 (VA)",
|
|
759
|
+
|
|
760
|
+
"summary.meter.reactive_power_var": "Putere reactiva (var)",
|
|
761
|
+
|
|
762
|
+
"summary.meter.reactive_power_l1_var": "Putere reactiva L1 (var)",
|
|
763
|
+
|
|
764
|
+
"summary.meter.reactive_power_l2_var": "Putere reactiva L2 (var)",
|
|
765
|
+
|
|
766
|
+
"summary.meter.reactive_power_l3_var": "Putere reactiva L3 (var)",
|
|
767
|
+
|
|
768
|
+
"summary.meter.power_factor": "Factor putere",
|
|
769
|
+
|
|
770
|
+
"summary.meter.power_factor_l1": "Factor putere L1",
|
|
771
|
+
|
|
772
|
+
"summary.meter.power_factor_l2": "Factor putere L2",
|
|
773
|
+
|
|
774
|
+
"summary.meter.power_factor_l3": "Factor putere L3",
|
|
775
|
+
|
|
776
|
+
"summary.meter.energy_import_wh": "Energie import (Wh)",
|
|
777
|
+
|
|
778
|
+
"summary.meter.energy_import_l1_wh": "Energie import L1 (Wh)",
|
|
779
|
+
|
|
780
|
+
"summary.meter.energy_import_l2_wh": "Energie import L2 (Wh)",
|
|
781
|
+
|
|
782
|
+
"summary.meter.energy_import_l3_wh": "Energie import L3 (Wh)",
|
|
783
|
+
|
|
784
|
+
"summary.meter.energy_export_wh": "Energie export (Wh)",
|
|
785
|
+
|
|
786
|
+
"summary.meter.energy_export_l1_wh": "Energie export L1 (Wh)",
|
|
787
|
+
|
|
788
|
+
"summary.meter.energy_export_l2_wh": "Energie export L2 (Wh)",
|
|
789
|
+
|
|
790
|
+
"summary.meter.energy_export_l3_wh": "Energie export L3 (Wh)",
|
|
791
|
+
|
|
792
|
+
"summary.meter.apparent_energy_import_vah": "Energie aparenta import (VAh)",
|
|
793
|
+
|
|
794
|
+
"summary.meter.apparent_energy_export_vah": "Energie aparenta export (VAh)",
|
|
795
|
+
|
|
796
|
+
"summary.meter.reactive_energy_import_q1_varh": "Energie reactiva import Q1 (varh)",
|
|
797
|
+
|
|
798
|
+
"summary.meter.reactive_energy_import_q2_varh": "Energie reactiva import Q2 (varh)",
|
|
799
|
+
|
|
800
|
+
"summary.meter.reactive_energy_export_q3_varh": "Energie reactiva export Q3 (varh)",
|
|
801
|
+
|
|
802
|
+
"summary.meter.reactive_energy_export_q4_varh": "Energie reactiva export Q4 (varh)",
|
|
803
|
+
|
|
804
|
+
"summary.meter.event_flags": "Event flags",
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
"summary.dc.dc_total_power_w": "Putere DC totala (W)",
|
|
808
|
+
|
|
809
|
+
"summary.dc.module_count": "Numar module/stringuri DC (brut)",
|
|
810
|
+
|
|
811
|
+
"summary.dc.global_event": "Eveniment DC global",
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
"summary.common.manufacturer": "Producator",
|
|
815
|
+
|
|
816
|
+
"summary.common.model": "Model",
|
|
817
|
+
|
|
818
|
+
"summary.common.options": "Optiuni",
|
|
819
|
+
|
|
820
|
+
"summary.common.version": "Versiune",
|
|
821
|
+
|
|
822
|
+
"summary.common.serial": "Serie",
|
|
823
|
+
|
|
824
|
+
"summary.common.device_address": "Adresa device"
|
|
825
|
+
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
const mpptMatch = path.match(/^summary\.dc\.mppts\.(\d+)\.(dc_voltage_v|dc_current_a|dc_power_w|dc_energy_wh)$/);
|
|
830
|
+
|
|
831
|
+
if (mpptMatch) {
|
|
832
|
+
|
|
833
|
+
const mpptIndex = Number(mpptMatch[1]) + 1;
|
|
834
|
+
|
|
835
|
+
const key = mpptMatch[2];
|
|
836
|
+
|
|
837
|
+
const suffixMap = {
|
|
838
|
+
|
|
839
|
+
dc_voltage_v: "Tensiune (V)",
|
|
840
|
+
|
|
841
|
+
dc_current_a: "Curent (A)",
|
|
842
|
+
|
|
843
|
+
dc_power_w: "Putere (W)",
|
|
844
|
+
|
|
845
|
+
dc_energy_wh: "Energie (Wh)"
|
|
846
|
+
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
return "MPPT" + mpptIndex + " " + suffixMap[key];
|
|
850
|
+
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
return labels[path] || path;
|
|
855
|
+
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
function hasValidDetection(profileKey, phaseMode, mpptCount) {
|
|
860
|
+
|
|
861
|
+
return (
|
|
862
|
+
|
|
863
|
+
profileKey &&
|
|
864
|
+
|
|
865
|
+
profileKey !== "auto" &&
|
|
866
|
+
|
|
867
|
+
phaseMode &&
|
|
868
|
+
|
|
869
|
+
phaseMode !== "unknown" &&
|
|
870
|
+
|
|
871
|
+
Number.isFinite(mpptCount) &&
|
|
872
|
+
|
|
873
|
+
mpptCount > 0
|
|
874
|
+
|
|
875
|
+
);
|
|
876
|
+
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
function computeOutputsCount(selectedValues, isMulti, isDebug) {
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
const base = isMulti
|
|
884
|
+
|
|
885
|
+
? 1
|
|
886
|
+
|
|
887
|
+
: (function () {
|
|
888
|
+
|
|
889
|
+
const normalized = dedupeSelectedValues(selectedValues);
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
if (normalized.includes("full")) {
|
|
893
|
+
|
|
894
|
+
return 1;
|
|
895
|
+
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
return Math.max(1, normalized.length);
|
|
900
|
+
|
|
901
|
+
})();
|
|
902
|
+
|
|
903
|
+
|
|
904
|
+
return base + (isDebug ? 1 : 0);
|
|
905
|
+
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
function isCompactIntegrationEnabled() {
|
|
910
|
+
|
|
911
|
+
return $("#node-input-multiInverter").is(":checked") ||
|
|
912
|
+
$("#node-input-controlExport").is(":checked") ||
|
|
913
|
+
$("#node-input-multiGrid").is(":checked");
|
|
914
|
+
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
function isInfluxIntegrationEnabled() {
|
|
918
|
+
|
|
919
|
+
return $("#node-input-influxDb").is(":checked");
|
|
920
|
+
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function isScadaIntegrationEnabled() {
|
|
924
|
+
|
|
925
|
+
return $("#node-input-scadaAggregator").is(":checked");
|
|
926
|
+
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
function isSmartMeterDetected() {
|
|
930
|
+
|
|
931
|
+
return detectedDeviceType === "smart_meter";
|
|
932
|
+
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
function syncDetectedDeviceLabels() {
|
|
936
|
+
|
|
937
|
+
const isMeter = isSmartMeterDetected();
|
|
938
|
+
|
|
939
|
+
$("label[for='node-input-inverterId']").html(
|
|
940
|
+
'<i class="fa fa-id-badge"></i> ' + (isMeter ? "Meter ID" : "Inverter ID")
|
|
941
|
+
);
|
|
942
|
+
|
|
943
|
+
$("#node-input-inverterId").attr("placeholder", isMeter ? "meter1" : "inv1");
|
|
944
|
+
$("#node-input-influxMeasurement").attr(
|
|
945
|
+
"placeholder",
|
|
946
|
+
isMeter ? "Fronius Smart Meter" : "Fronius Inverter 1"
|
|
947
|
+
);
|
|
948
|
+
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function enforceSmartMeterIntegrationAvailability() {
|
|
952
|
+
|
|
953
|
+
const blocked = isSmartMeterDetected();
|
|
954
|
+
const $multi = $("#node-input-multiInverter");
|
|
955
|
+
const $control = $("#node-input-controlExport");
|
|
956
|
+
const $multiGrid = $("#node-input-multiGrid");
|
|
957
|
+
const title = blocked
|
|
958
|
+
? "Inactiv pentru Fronius Smart Meter IP. Foloseste payload normal, Multi-grid sau InfluxDB."
|
|
959
|
+
: "";
|
|
960
|
+
|
|
961
|
+
if (blocked) {
|
|
962
|
+
$multi.prop("checked", false);
|
|
963
|
+
$control.prop("checked", false);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
$multi.prop("disabled", blocked).attr("title", title);
|
|
967
|
+
$control.prop("disabled", blocked).attr("title", title);
|
|
968
|
+
$multiGrid
|
|
969
|
+
.prop("disabled", !blocked)
|
|
970
|
+
.attr("title", blocked ? "" : "Disponibil doar pentru Fronius Smart Meter IP.");
|
|
971
|
+
|
|
972
|
+
if (detectedDeviceType === "inverter") {
|
|
973
|
+
$multiGrid.prop("checked", false);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
$("#node-fronius-read-smart-meter-integration-note").toggle(blocked);
|
|
977
|
+
syncDetectedDeviceLabels();
|
|
978
|
+
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
function getDefaultCompactField() {
|
|
982
|
+
|
|
983
|
+
return "summary.ac.power_w";
|
|
984
|
+
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
function isSingleOutputIntegrationEnabled() {
|
|
988
|
+
|
|
989
|
+
return isCompactIntegrationEnabled() || isInfluxIntegrationEnabled() || isScadaIntegrationEnabled();
|
|
990
|
+
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
|
|
994
|
+
function updateOutputsPreview(selectedValues) {
|
|
995
|
+
|
|
996
|
+
const isFullMode = normalizePayloadMode($("#node-input-payloadMode").val()) === "full";
|
|
997
|
+
|
|
998
|
+
const values = isFullMode ? ["full"] : selectedValues;
|
|
999
|
+
|
|
1000
|
+
const outputs = computeOutputsCount(
|
|
1001
|
+
|
|
1002
|
+
values,
|
|
1003
|
+
|
|
1004
|
+
isSingleOutputIntegrationEnabled(),
|
|
1005
|
+
|
|
1006
|
+
$("#node-input-debugMode").is(":checked")
|
|
1007
|
+
|
|
1008
|
+
);
|
|
1009
|
+
|
|
1010
|
+
|
|
1011
|
+
$("#node-fronius-read-outputs-info").text(String(outputs));
|
|
1012
|
+
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
function updatePayloadSummary(values) {
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
const normalized = sanitizeSelectedValues(values, []);
|
|
1020
|
+
|
|
1021
|
+
|
|
1022
|
+
let text = "Toate valorile";
|
|
1023
|
+
|
|
1024
|
+
|
|
1025
|
+
if (!normalized.includes("full")) {
|
|
1026
|
+
|
|
1027
|
+
if (normalized.length === 1) {
|
|
1028
|
+
|
|
1029
|
+
text = getPayloadLabel(normalized[0]);
|
|
1030
|
+
|
|
1031
|
+
} else {
|
|
1032
|
+
|
|
1033
|
+
text = normalized.length + " valori selectate";
|
|
1034
|
+
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
$("#node-fronius-read-payload-summary").text(text);
|
|
1041
|
+
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
function persistPayloadSelection(values, allowEmpty) {
|
|
1046
|
+
|
|
1047
|
+
payloadSelectionState = sanitizeSelectedValues(values, payloadSelectionState, !!allowEmpty);
|
|
1048
|
+
|
|
1049
|
+
$("#node-input-payloadFields").val(JSON.stringify(payloadSelectionState));
|
|
1050
|
+
|
|
1051
|
+
updatePayloadSummary(payloadSelectionState);
|
|
1052
|
+
|
|
1053
|
+
updateOutputsPreview(payloadSelectionState);
|
|
1054
|
+
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
function getNonFullSelections(values) {
|
|
1059
|
+
|
|
1060
|
+
return dedupeSelectedValues(values).filter(function (value) {
|
|
1061
|
+
|
|
1062
|
+
return value !== "full";
|
|
1063
|
+
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
function pickFirstSelectableField() {
|
|
1070
|
+
|
|
1071
|
+
const $first = $("#node-fronius-read-field-list-container .pr-field-checkbox").first();
|
|
1072
|
+
|
|
1073
|
+
return $first.length ? String($first.attr("data-value") || "").trim() : "";
|
|
1074
|
+
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
function getAllSelectableFields() {
|
|
1078
|
+
|
|
1079
|
+
const values = [];
|
|
1080
|
+
|
|
1081
|
+
$("#node-fronius-read-field-list-container .pr-field-checkbox").each(function () {
|
|
1082
|
+
const value = String($(this).attr("data-value") || "").trim();
|
|
1083
|
+
if (value) {
|
|
1084
|
+
values.push(value);
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
return dedupeSelectedValues(values).filter(function (value) {
|
|
1089
|
+
return value !== "full";
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
function getDefaultInfluxFields() {
|
|
1095
|
+
|
|
1096
|
+
const selectable = getAllSelectableFields();
|
|
1097
|
+
|
|
1098
|
+
if (!selectable.length) {
|
|
1099
|
+
return detectedDeviceType === "smart_meter"
|
|
1100
|
+
? DEFAULT_METER_INFLUX_PAYLOAD_FIELDS.slice()
|
|
1101
|
+
: DEFAULT_INFLUX_PAYLOAD_FIELDS.slice();
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
const selectableSet = new Set(selectable);
|
|
1105
|
+
const defaultCandidates = detectedDeviceType === "smart_meter"
|
|
1106
|
+
? DEFAULT_METER_INFLUX_PAYLOAD_FIELDS
|
|
1107
|
+
: DEFAULT_INFLUX_PAYLOAD_FIELDS;
|
|
1108
|
+
const defaults = defaultCandidates.filter(function (field) {
|
|
1109
|
+
return selectableSet.has(field);
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
if (defaults.length) {
|
|
1113
|
+
return defaults;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
return [selectable[0]];
|
|
1117
|
+
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
function applyFieldCheckboxSelection(values) {
|
|
1121
|
+
|
|
1122
|
+
const selectedSet = new Set(dedupeSelectedValues(values));
|
|
1123
|
+
|
|
1124
|
+
$("#node-fronius-read-field-list-container .pr-field-checkbox").each(function () {
|
|
1125
|
+
const value = String($(this).attr("data-value") || "").trim();
|
|
1126
|
+
$(this).prop("checked", !!value && selectedSet.has(value));
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
function syncPayloadModeUi() {
|
|
1133
|
+
|
|
1134
|
+
const mode = normalizePayloadMode($("#node-input-payloadMode").val());
|
|
1135
|
+
|
|
1136
|
+
payloadModeState = mode;
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
const isSelectedMode = mode === "selected";
|
|
1140
|
+
|
|
1141
|
+
const compactMode = isCompactIntegrationEnabled();
|
|
1142
|
+
const influxMode = isInfluxIntegrationEnabled();
|
|
1143
|
+
const integrationMode = compactMode || influxMode;
|
|
1144
|
+
const customSelectionEnabled = compactMode
|
|
1145
|
+
? multiInverterCustomPayloadEnabledState
|
|
1146
|
+
: influxMode
|
|
1147
|
+
? influxCustomPayloadEnabledState
|
|
1148
|
+
: true;
|
|
1149
|
+
|
|
1150
|
+
const canShowSelectionList = isSelectedMode && (!integrationMode || (multiAdvancedUnlockedState && customSelectionEnabled));
|
|
1151
|
+
const showDefaultButton = canShowSelectionList && isInfluxIntegrationEnabled() && !!multiAdvancedUnlockedState;
|
|
1152
|
+
|
|
1153
|
+
$("#row-fronius-read-field-list").toggle(canShowSelectionList);
|
|
1154
|
+
$("#node-fronius-read-default-values").toggle(showDefaultButton);
|
|
1155
|
+
|
|
1156
|
+
|
|
1157
|
+
if (!isSelectedMode) {
|
|
1158
|
+
|
|
1159
|
+
persistPayloadSelection(["full"]);
|
|
1160
|
+
|
|
1161
|
+
return;
|
|
1162
|
+
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
const selectedNonFull = getNonFullSelections(payloadSelectionState);
|
|
1167
|
+
|
|
1168
|
+
if (selectedNonFull.length > 0) {
|
|
1169
|
+
|
|
1170
|
+
persistPayloadSelection(selectedNonFull);
|
|
1171
|
+
|
|
1172
|
+
return;
|
|
1173
|
+
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
|
|
1177
|
+
const firstSelectable = pickFirstSelectableField();
|
|
1178
|
+
|
|
1179
|
+
if (firstSelectable) {
|
|
1180
|
+
|
|
1181
|
+
persistPayloadSelection([firstSelectable]);
|
|
1182
|
+
|
|
1183
|
+
return;
|
|
1184
|
+
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
|
|
1188
|
+
persistPayloadSelection(["full"]);
|
|
1189
|
+
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
|
|
1193
|
+
function setPayloadFieldSelectionEnabled(enabled) {
|
|
1194
|
+
|
|
1195
|
+
$("#node-fronius-read-field-list-container .pr-field-checkbox").prop("disabled", !enabled);
|
|
1196
|
+
|
|
1197
|
+
$("#node-fronius-read-select-all, #node-fronius-read-clear-all")
|
|
1198
|
+
|
|
1199
|
+
.toggleClass("disabled", !enabled)
|
|
1200
|
+
|
|
1201
|
+
.attr("aria-disabled", enabled ? "false" : "true");
|
|
1202
|
+
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
|
|
1206
|
+
function getPersistedPayloadSelection(nodeContext) {
|
|
1207
|
+
|
|
1208
|
+
const fromConfig = nodeContext && nodeContext.payloadFields !== undefined
|
|
1209
|
+
|
|
1210
|
+
? nodeContext.payloadFields
|
|
1211
|
+
|
|
1212
|
+
: (nodeContext && nodeContext.payloadField ? [nodeContext.payloadField] : ["full"]);
|
|
1213
|
+
|
|
1214
|
+
|
|
1215
|
+
return sanitizeSelectedValues(fromConfig, []);
|
|
1216
|
+
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
function renderPayloadDropdown(profileKey, selectedValues, phaseMode, mpptCount, deviceType) {
|
|
1221
|
+
|
|
1222
|
+
|
|
1223
|
+
const $container = $("#node-fronius-read-field-list-container");
|
|
1224
|
+
|
|
1225
|
+
const normalized = sanitizeSelectedValues(selectedValues, payloadSelectionState);
|
|
1226
|
+
|
|
1227
|
+
|
|
1228
|
+
$container.empty();
|
|
1229
|
+
|
|
1230
|
+
|
|
1231
|
+
function renderGroup(groupLabel, items) {
|
|
1232
|
+
|
|
1233
|
+
const $group = $('<div class="pr-field-group"></div>');
|
|
1234
|
+
|
|
1235
|
+
const $title = $('<p class="pr-field-group-title"></p>').text(groupLabel);
|
|
1236
|
+
|
|
1237
|
+
const $grid = $('<div class="pr-field-group-grid"></div>');
|
|
1238
|
+
|
|
1239
|
+
|
|
1240
|
+
items.forEach(function (item) {
|
|
1241
|
+
|
|
1242
|
+
const checkboxId = "fronius-field-" + item.value.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
1243
|
+
|
|
1244
|
+
const $checkbox = $('<input type="checkbox" class="pr-field-checkbox">')
|
|
1245
|
+
|
|
1246
|
+
.attr("id", checkboxId)
|
|
1247
|
+
|
|
1248
|
+
.attr("data-value", item.value)
|
|
1249
|
+
|
|
1250
|
+
.prop("checked", normalized.includes(item.value));
|
|
1251
|
+
|
|
1252
|
+
|
|
1253
|
+
const $label = $('<label class="pr-field-item"></label>')
|
|
1254
|
+
|
|
1255
|
+
.attr("for", checkboxId)
|
|
1256
|
+
|
|
1257
|
+
.append($checkbox)
|
|
1258
|
+
|
|
1259
|
+
.append($('<span></span>').text(item.label));
|
|
1260
|
+
|
|
1261
|
+
|
|
1262
|
+
$grid.append($label);
|
|
1263
|
+
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
|
|
1267
|
+
$group.append($title).append($grid);
|
|
1268
|
+
|
|
1269
|
+
$container.append($group);
|
|
1270
|
+
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
|
|
1274
|
+
if (deviceType === "smart_meter") {
|
|
1275
|
+
|
|
1276
|
+
renderGroup("Smart Meter", PAYLOAD_OPTION_GROUPS.meter);
|
|
1277
|
+
|
|
1278
|
+
renderGroup("Device", PAYLOAD_OPTION_GROUPS.device);
|
|
1279
|
+
|
|
1280
|
+
updatePayloadSummary(normalized);
|
|
1281
|
+
|
|
1282
|
+
persistPayloadSelection(normalized);
|
|
1283
|
+
|
|
1284
|
+
$container.find(".pr-field-checkbox").off(".froniusPayloadCheck").on("change.froniusPayloadCheck", function () {
|
|
1285
|
+
const selected = [];
|
|
1286
|
+
$container.find(".pr-field-checkbox:checked").each(function () {
|
|
1287
|
+
selected.push(String($(this).attr("data-value") || ""));
|
|
1288
|
+
});
|
|
1289
|
+
const sanitized = sanitizeSelectedValues(selected, payloadSelectionState);
|
|
1290
|
+
persistPayloadSelection(sanitized);
|
|
1291
|
+
$("#node-input-payloadMode").val(inferPayloadModeFromSelection(sanitized));
|
|
1292
|
+
syncPayloadModeUi();
|
|
1293
|
+
});
|
|
1294
|
+
|
|
1295
|
+
return;
|
|
1296
|
+
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
if (!hasValidDetection(profileKey, phaseMode, mpptCount)) {
|
|
1300
|
+
|
|
1301
|
+
updatePayloadSummary(normalized);
|
|
1302
|
+
|
|
1303
|
+
persistPayloadSelection(normalized);
|
|
1304
|
+
|
|
1305
|
+
$container.append($('<div class="fronius-multiselect-empty"></div>').text("Detectare in curs. Campurile apar dupa identificarea dispozitivului SunSpec."));
|
|
1306
|
+
|
|
1307
|
+
return;
|
|
1308
|
+
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
|
|
1312
|
+
const resolved = resolveProfile(profileKey, mpptCount, phaseMode);
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
if (resolved.includeAC) {
|
|
1316
|
+
|
|
1317
|
+
renderGroup("AC", buildAcOptions(resolved.resolvedPhaseMode));
|
|
1318
|
+
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
|
|
1322
|
+
if (resolved.includeDCGeneral) {
|
|
1323
|
+
|
|
1324
|
+
renderGroup("DC General", PAYLOAD_OPTION_GROUPS.dcGeneral);
|
|
1325
|
+
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
|
|
1329
|
+
for (let i = 0; i < resolved.resolvedMpptCount; i++) {
|
|
1330
|
+
|
|
1331
|
+
renderGroup("MPPT" + (i + 1), buildMpptOptions(i));
|
|
1332
|
+
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
|
|
1336
|
+
if (resolved.includeDevice) {
|
|
1337
|
+
|
|
1338
|
+
renderGroup("Device", PAYLOAD_OPTION_GROUPS.device);
|
|
1339
|
+
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
|
|
1343
|
+
updatePayloadSummary(normalized);
|
|
1344
|
+
|
|
1345
|
+
persistPayloadSelection(normalized);
|
|
1346
|
+
|
|
1347
|
+
|
|
1348
|
+
$container.find(".pr-field-checkbox").off(".froniusPayloadCheck").on("change.froniusPayloadCheck", function () {
|
|
1349
|
+
|
|
1350
|
+
const selected = [];
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
$container.find(".pr-field-checkbox:checked").each(function () {
|
|
1354
|
+
|
|
1355
|
+
selected.push($(this).attr("data-value"));
|
|
1356
|
+
|
|
1357
|
+
});
|
|
1358
|
+
|
|
1359
|
+
|
|
1360
|
+
const sanitized = sanitizeSelectedValues(selected, payloadSelectionState);
|
|
1361
|
+
|
|
1362
|
+
|
|
1363
|
+
$container.find(".pr-field-checkbox").each(function () {
|
|
1364
|
+
|
|
1365
|
+
const value = $(this).attr("data-value");
|
|
1366
|
+
|
|
1367
|
+
$(this).prop("checked", sanitized.includes(value));
|
|
1368
|
+
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
|
|
1372
|
+
persistPayloadSelection(sanitized);
|
|
1373
|
+
|
|
1374
|
+
$("#node-input-payloadMode").val(inferPayloadModeFromSelection(sanitized));
|
|
1375
|
+
|
|
1376
|
+
syncPayloadModeUi();
|
|
1377
|
+
|
|
1378
|
+
});
|
|
1379
|
+
|
|
1380
|
+
|
|
1381
|
+
const compactMode = isCompactIntegrationEnabled();
|
|
1382
|
+
const influxMode = isInfluxIntegrationEnabled();
|
|
1383
|
+
const integrationMode = compactMode || influxMode;
|
|
1384
|
+
const customSelectionEnabled = compactMode
|
|
1385
|
+
? multiInverterCustomPayloadEnabledState
|
|
1386
|
+
: influxMode
|
|
1387
|
+
? influxCustomPayloadEnabledState
|
|
1388
|
+
: true;
|
|
1389
|
+
|
|
1390
|
+
setPayloadFieldSelectionEnabled(!integrationMode || (customSelectionEnabled && multiAdvancedUnlockedState));
|
|
1391
|
+
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
|
|
1395
|
+
function buildPayloadSelect(profileKey, selectedValues, phaseMode, mpptCount, deviceType) {
|
|
1396
|
+
|
|
1397
|
+
renderPayloadDropdown(profileKey, selectedValues, phaseMode, mpptCount, deviceType || detectedDeviceType);
|
|
1398
|
+
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
|
|
1402
|
+
function setProbeInfo(message, color) {
|
|
1403
|
+
|
|
1404
|
+
const $el = $("#node-fronius-read-probe-info");
|
|
1405
|
+
|
|
1406
|
+
$el.text(message);
|
|
1407
|
+
|
|
1408
|
+
$el.css("color", color || "");
|
|
1409
|
+
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
|
|
1413
|
+
function getProbeKey() {
|
|
1414
|
+
|
|
1415
|
+
const host = ($("#node-input-host").val() || "").trim();
|
|
1416
|
+
|
|
1417
|
+
const port = ($("#node-input-port").val() || "").trim();
|
|
1418
|
+
|
|
1419
|
+
const unitId = ($("#node-input-unitId").val() || "").trim();
|
|
1420
|
+
|
|
1421
|
+
return [host, port, unitId].join("|");
|
|
1422
|
+
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
|
|
1426
|
+
function buildProbeMessage(data) {
|
|
1427
|
+
|
|
1428
|
+
|
|
1429
|
+
if (data.device_type === "smart_meter") {
|
|
1430
|
+
|
|
1431
|
+
const meterLabel = data.meter_model || data.model || "";
|
|
1432
|
+
|
|
1433
|
+
return "Detectat: Fronius SmartMeter IP" + (meterLabel ? " (" + meterLabel + ")" : "");
|
|
1434
|
+
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
const labelText =
|
|
1438
|
+
|
|
1439
|
+
data.model ||
|
|
1440
|
+
|
|
1441
|
+
data.inverter_profile_label ||
|
|
1442
|
+
|
|
1443
|
+
"Auto Detect";
|
|
1444
|
+
|
|
1445
|
+
|
|
1446
|
+
const mpptText = Number.isFinite(data.mppt_count) && data.mppt_count > 0
|
|
1447
|
+
|
|
1448
|
+
? ", " + data.mppt_count + " MPPT"
|
|
1449
|
+
|
|
1450
|
+
: "";
|
|
1451
|
+
|
|
1452
|
+
|
|
1453
|
+
const phaseText =
|
|
1454
|
+
|
|
1455
|
+
data.phase_mode === "single_phase"
|
|
1456
|
+
|
|
1457
|
+
? ", monofazic"
|
|
1458
|
+
|
|
1459
|
+
: data.phase_mode === "three_phase"
|
|
1460
|
+
|
|
1461
|
+
? ", trifazic"
|
|
1462
|
+
|
|
1463
|
+
: "";
|
|
1464
|
+
|
|
1465
|
+
|
|
1466
|
+
return "Detectat: " + labelText + mpptText + phaseText;
|
|
1467
|
+
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
|
|
1471
|
+
function applyProbeData(data, selectedPayloads, probeKey) {
|
|
1472
|
+
|
|
1473
|
+
|
|
1474
|
+
detectedMpptCount = Number.isFinite(data.mppt_count) ? data.mppt_count : null;
|
|
1475
|
+
|
|
1476
|
+
detectedProfileKey = data.inverter_profile || "auto";
|
|
1477
|
+
|
|
1478
|
+
detectedPhaseMode = data.phase_mode || "unknown";
|
|
1479
|
+
|
|
1480
|
+
detectedDeviceType = data.device_type || "unknown";
|
|
1481
|
+
|
|
1482
|
+
enforceSmartMeterIntegrationAvailability();
|
|
1483
|
+
|
|
1484
|
+
lastProbeKey = probeKey;
|
|
1485
|
+
|
|
1486
|
+
|
|
1487
|
+
buildPayloadSelect(
|
|
1488
|
+
|
|
1489
|
+
detectedProfileKey,
|
|
1490
|
+
|
|
1491
|
+
selectedPayloads,
|
|
1492
|
+
|
|
1493
|
+
detectedPhaseMode,
|
|
1494
|
+
|
|
1495
|
+
detectedMpptCount,
|
|
1496
|
+
|
|
1497
|
+
detectedDeviceType
|
|
1498
|
+
|
|
1499
|
+
);
|
|
1500
|
+
|
|
1501
|
+
|
|
1502
|
+
if (detectedDeviceType === "smart_meter" || hasValidDetection(detectedProfileKey, detectedPhaseMode, detectedMpptCount)) {
|
|
1503
|
+
|
|
1504
|
+
const message = buildProbeMessage(data);
|
|
1505
|
+
|
|
1506
|
+
lastGoodProbeInfo = {
|
|
1507
|
+
|
|
1508
|
+
message: message,
|
|
1509
|
+
|
|
1510
|
+
color: "green"
|
|
1511
|
+
|
|
1512
|
+
};
|
|
1513
|
+
|
|
1514
|
+
setProbeInfo(message, "green");
|
|
1515
|
+
|
|
1516
|
+
} else {
|
|
1517
|
+
|
|
1518
|
+
setProbeInfo("Detectarea nu este inca disponibila. Payload ramane pe valoarea salvata sau pe 'Toate valorile'.", "#999");
|
|
1519
|
+
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
|
|
1525
|
+
function readCachedState(nodeId, callback) {
|
|
1526
|
+
|
|
1527
|
+
|
|
1528
|
+
if (!nodeId) {
|
|
1529
|
+
|
|
1530
|
+
callback(null);
|
|
1531
|
+
|
|
1532
|
+
return;
|
|
1533
|
+
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
|
|
1537
|
+
$.getJSON("fronius-read/state/" + encodeURIComponent(nodeId))
|
|
1538
|
+
|
|
1539
|
+
.done(function (data) {
|
|
1540
|
+
|
|
1541
|
+
|
|
1542
|
+
if (data && data.ok && data.state && data.state.status === "ok") {
|
|
1543
|
+
|
|
1544
|
+
callback(data.state);
|
|
1545
|
+
|
|
1546
|
+
return;
|
|
1547
|
+
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
|
|
1551
|
+
callback(null);
|
|
1552
|
+
|
|
1553
|
+
|
|
1554
|
+
})
|
|
1555
|
+
|
|
1556
|
+
.fail(function () {
|
|
1557
|
+
|
|
1558
|
+
callback(null);
|
|
1559
|
+
|
|
1560
|
+
});
|
|
1561
|
+
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
|
|
1565
|
+
function runLiveProbe(force, selectedPayloadsOverride) {
|
|
1566
|
+
|
|
1567
|
+
|
|
1568
|
+
const host = ($("#node-input-host").val() || "").trim();
|
|
1569
|
+
|
|
1570
|
+
const port = ($("#node-input-port").val() || "").trim();
|
|
1571
|
+
|
|
1572
|
+
const unitId = ($("#node-input-unitId").val() || "").trim();
|
|
1573
|
+
|
|
1574
|
+
const selectedPayloads = dedupeSelectedValues(
|
|
1575
|
+
|
|
1576
|
+
selectedPayloadsOverride || payloadSelectionState || ["full"]
|
|
1577
|
+
|
|
1578
|
+
);
|
|
1579
|
+
|
|
1580
|
+
const probeKey = getProbeKey();
|
|
1581
|
+
|
|
1582
|
+
|
|
1583
|
+
if (!host || !port || !unitId) {
|
|
1584
|
+
|
|
1585
|
+
detectedMpptCount = null;
|
|
1586
|
+
|
|
1587
|
+
detectedProfileKey = "auto";
|
|
1588
|
+
|
|
1589
|
+
detectedPhaseMode = "unknown";
|
|
1590
|
+
|
|
1591
|
+
lastProbeKey = null;
|
|
1592
|
+
|
|
1593
|
+
buildPayloadSelect(detectedProfileKey, selectedPayloads, detectedPhaseMode, detectedMpptCount, detectedDeviceType);
|
|
1594
|
+
|
|
1595
|
+
setProbeInfo("Completeaza IP / Port / Unit ID pentru detectare automata SunSpec.", "#999");
|
|
1596
|
+
|
|
1597
|
+
return;
|
|
1598
|
+
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
|
|
1602
|
+
if (!force && probeKey === lastProbeKey) {
|
|
1603
|
+
|
|
1604
|
+
if (lastGoodProbeInfo) {
|
|
1605
|
+
|
|
1606
|
+
setProbeInfo(lastGoodProbeInfo.message, lastGoodProbeInfo.color);
|
|
1607
|
+
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
return;
|
|
1611
|
+
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
|
|
1615
|
+
if (probeInFlight) {
|
|
1616
|
+
|
|
1617
|
+
return;
|
|
1618
|
+
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
|
|
1622
|
+
probeInFlight = true;
|
|
1623
|
+
|
|
1624
|
+
const requestId = ++probeRequestId;
|
|
1625
|
+
|
|
1626
|
+
|
|
1627
|
+
if (lastGoodProbeInfo) {
|
|
1628
|
+
|
|
1629
|
+
setProbeInfo(lastGoodProbeInfo.message, lastGoodProbeInfo.color);
|
|
1630
|
+
|
|
1631
|
+
} else {
|
|
1632
|
+
|
|
1633
|
+
setProbeInfo("Detectare Fronius in curs...", "#999");
|
|
1634
|
+
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
|
|
1638
|
+
$.getJSON("fronius-read/probe", {
|
|
1639
|
+
|
|
1640
|
+
host: host,
|
|
1641
|
+
|
|
1642
|
+
port: port,
|
|
1643
|
+
|
|
1644
|
+
unitId: unitId
|
|
1645
|
+
|
|
1646
|
+
})
|
|
1647
|
+
|
|
1648
|
+
.done(function (data) {
|
|
1649
|
+
|
|
1650
|
+
|
|
1651
|
+
if (requestId !== probeRequestId) {
|
|
1652
|
+
|
|
1653
|
+
return;
|
|
1654
|
+
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
|
|
1658
|
+
if (data && data.ok) {
|
|
1659
|
+
|
|
1660
|
+
applyProbeData(data, selectedPayloads, probeKey);
|
|
1661
|
+
|
|
1662
|
+
enforceMultiInverterPayload();
|
|
1663
|
+
|
|
1664
|
+
} else if (lastGoodProbeInfo) {
|
|
1665
|
+
|
|
1666
|
+
setProbeInfo(lastGoodProbeInfo.message, lastGoodProbeInfo.color);
|
|
1667
|
+
|
|
1668
|
+
} else {
|
|
1669
|
+
|
|
1670
|
+
detectedMpptCount = null;
|
|
1671
|
+
|
|
1672
|
+
detectedProfileKey = "auto";
|
|
1673
|
+
|
|
1674
|
+
detectedPhaseMode = "unknown";
|
|
1675
|
+
detectedDeviceType = "unknown";
|
|
1676
|
+
enforceSmartMeterIntegrationAvailability();
|
|
1677
|
+
|
|
1678
|
+
buildPayloadSelect("auto", selectedPayloads, "unknown", null);
|
|
1679
|
+
|
|
1680
|
+
setProbeInfo("Detectarea automata a esuat. Payload ramane pe valoarea salvata sau pe 'Toate valorile'.", "#c77d00");
|
|
1681
|
+
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
|
|
1685
|
+
})
|
|
1686
|
+
|
|
1687
|
+
.fail(function () {
|
|
1688
|
+
|
|
1689
|
+
|
|
1690
|
+
if (requestId !== probeRequestId) {
|
|
1691
|
+
|
|
1692
|
+
return;
|
|
1693
|
+
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
|
|
1697
|
+
if (lastGoodProbeInfo) {
|
|
1698
|
+
|
|
1699
|
+
setProbeInfo(lastGoodProbeInfo.message, lastGoodProbeInfo.color);
|
|
1700
|
+
|
|
1701
|
+
} else {
|
|
1702
|
+
|
|
1703
|
+
detectedMpptCount = null;
|
|
1704
|
+
|
|
1705
|
+
detectedProfileKey = "auto";
|
|
1706
|
+
|
|
1707
|
+
detectedPhaseMode = "unknown";
|
|
1708
|
+
detectedDeviceType = "unknown";
|
|
1709
|
+
enforceSmartMeterIntegrationAvailability();
|
|
1710
|
+
|
|
1711
|
+
buildPayloadSelect("auto", selectedPayloads, "unknown", null);
|
|
1712
|
+
|
|
1713
|
+
setProbeInfo("Detectarea automata a esuat. Payload ramane pe valoarea salvata sau pe 'Toate valorile'.", "#c77d00");
|
|
1714
|
+
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
|
|
1718
|
+
})
|
|
1719
|
+
|
|
1720
|
+
.always(function () {
|
|
1721
|
+
|
|
1722
|
+
if (requestId === probeRequestId) {
|
|
1723
|
+
|
|
1724
|
+
probeInFlight = false;
|
|
1725
|
+
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
});
|
|
1729
|
+
|
|
1730
|
+
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
|
|
1734
|
+
function enforceMultiInverterPayload() {
|
|
1735
|
+
|
|
1736
|
+
|
|
1737
|
+
const isMulti = $("#node-input-multiInverter").is(":checked");
|
|
1738
|
+
|
|
1739
|
+
const isControlExport = $("#node-input-controlExport").is(":checked");
|
|
1740
|
+
const isMultiGrid = $("#node-input-multiGrid").is(":checked");
|
|
1741
|
+
const isInflux = $("#node-input-influxDb").is(":checked");
|
|
1742
|
+
|
|
1743
|
+
const isCompact = isMulti || isControlExport || isMultiGrid;
|
|
1744
|
+
|
|
1745
|
+
const $note = $("#node-fronius-read-multi-note");
|
|
1746
|
+
|
|
1747
|
+
const $mode = $("#node-input-payloadMode");
|
|
1748
|
+
|
|
1749
|
+
const useCustomSelection = isCompact && multiInverterCustomPayloadEnabledState;
|
|
1750
|
+
|
|
1751
|
+
|
|
1752
|
+
if (isInflux) {
|
|
1753
|
+
|
|
1754
|
+
const defaultInfluxFields = getDefaultInfluxFields();
|
|
1755
|
+
let effectiveInfluxFields;
|
|
1756
|
+
if (influxCustomPayloadEnabledState) {
|
|
1757
|
+
const selected = getNonFullSelections(payloadSelectionState);
|
|
1758
|
+
if (selected.length > 0) {
|
|
1759
|
+
effectiveInfluxFields = selected;
|
|
1760
|
+
} else {
|
|
1761
|
+
effectiveInfluxFields = defaultInfluxFields;
|
|
1762
|
+
}
|
|
1763
|
+
persistPayloadSelection(effectiveInfluxFields);
|
|
1764
|
+
setPayloadFieldSelectionEnabled(!!multiAdvancedUnlockedState);
|
|
1765
|
+
$note.find(".fronius-meta-info").text("In modul InfluxDB poti selecta ce valori sunt trimise din Selected payload.");
|
|
1766
|
+
} else {
|
|
1767
|
+
effectiveInfluxFields = defaultInfluxFields;
|
|
1768
|
+
persistPayloadSelection(effectiveInfluxFields);
|
|
1769
|
+
setPayloadFieldSelectionEnabled(false);
|
|
1770
|
+
$note.find(".fronius-meta-info").text("In modul InfluxDB se trimit implicit valorile presetate.");
|
|
1771
|
+
}
|
|
1772
|
+
applyFieldCheckboxSelection(effectiveInfluxFields);
|
|
1773
|
+
|
|
1774
|
+
$mode.val("selected");
|
|
1775
|
+
$mode.prop("disabled", true);
|
|
1776
|
+
$note.show();
|
|
1777
|
+
|
|
1778
|
+
} else if (isCompact && !useCustomSelection) {
|
|
1779
|
+
|
|
1780
|
+
const defaultCompactFields = isMultiGrid
|
|
1781
|
+
? DEFAULT_MULTI_GRID_PAYLOAD_FIELDS.slice()
|
|
1782
|
+
: [getDefaultCompactField()];
|
|
1783
|
+
const defaultCompactField = defaultCompactFields[0];
|
|
1784
|
+
|
|
1785
|
+
persistPayloadSelection(defaultCompactFields);
|
|
1786
|
+
applyFieldCheckboxSelection(defaultCompactFields);
|
|
1787
|
+
|
|
1788
|
+
$mode.val("selected");
|
|
1789
|
+
|
|
1790
|
+
$mode.prop("disabled", true);
|
|
1791
|
+
|
|
1792
|
+
setPayloadFieldSelectionEnabled(false);
|
|
1793
|
+
|
|
1794
|
+
$note.show();
|
|
1795
|
+
|
|
1796
|
+
$note.find(".fronius-meta-info").text(
|
|
1797
|
+
|
|
1798
|
+
isMultiGrid
|
|
1799
|
+
? "In modul Multi-grid se folosesc automat puterile totala si pe faze."
|
|
1800
|
+
: isControlExport && !isMulti
|
|
1801
|
+
|
|
1802
|
+
? (defaultCompactField === "summary.meter.power_w"
|
|
1803
|
+
? "In modul control-export se foloseste automat Putere activa (W)."
|
|
1804
|
+
: "In modul control-export se foloseste automat Putere AC (W).")
|
|
1805
|
+
|
|
1806
|
+
: "In modul multi-inverter se foloseste automat Putere AC (W)."
|
|
1807
|
+
|
|
1808
|
+
);
|
|
1809
|
+
|
|
1810
|
+
} else if (isCompact && useCustomSelection) {
|
|
1811
|
+
|
|
1812
|
+
const selected = getNonFullSelections(payloadSelectionState);
|
|
1813
|
+
|
|
1814
|
+
if (selected.length > 0) {
|
|
1815
|
+
|
|
1816
|
+
persistPayloadSelection(selected);
|
|
1817
|
+
|
|
1818
|
+
} else {
|
|
1819
|
+
|
|
1820
|
+
const fallbackFields = isMultiGrid
|
|
1821
|
+
? DEFAULT_MULTI_GRID_PAYLOAD_FIELDS.slice()
|
|
1822
|
+
: [getDefaultCompactField()];
|
|
1823
|
+
persistPayloadSelection(fallbackFields);
|
|
1824
|
+
applyFieldCheckboxSelection(fallbackFields);
|
|
1825
|
+
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
$mode.val("selected");
|
|
1829
|
+
|
|
1830
|
+
$mode.prop("disabled", true);
|
|
1831
|
+
|
|
1832
|
+
setPayloadFieldSelectionEnabled(!!multiAdvancedUnlockedState);
|
|
1833
|
+
|
|
1834
|
+
$note.show();
|
|
1835
|
+
|
|
1836
|
+
$note.find(".fronius-meta-info").text(
|
|
1837
|
+
|
|
1838
|
+
"Selectia custom este activa pentru integrarea compacta."
|
|
1839
|
+
|
|
1840
|
+
);
|
|
1841
|
+
|
|
1842
|
+
} else {
|
|
1843
|
+
|
|
1844
|
+
$mode.prop("disabled", false);
|
|
1845
|
+
|
|
1846
|
+
setPayloadFieldSelectionEnabled(true);
|
|
1847
|
+
|
|
1848
|
+
$note.hide();
|
|
1849
|
+
|
|
1850
|
+
persistPayloadSelection(payloadSelectionState);
|
|
1851
|
+
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
|
|
1857
|
+
function syncMultiInverterExpertUi() {
|
|
1858
|
+
|
|
1859
|
+
// no visible expert controls in UI
|
|
1860
|
+
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
|
|
1864
|
+
function clearMultiLongPressTimer() {
|
|
1865
|
+
|
|
1866
|
+
if (multiLongPressTimer) {
|
|
1867
|
+
|
|
1868
|
+
clearTimeout(multiLongPressTimer);
|
|
1869
|
+
|
|
1870
|
+
multiLongPressTimer = null;
|
|
1871
|
+
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
|
|
1877
|
+
function unlockAdvancedSelection(selector) {
|
|
1878
|
+
|
|
1879
|
+
multiAdvancedUnlockedState = true;
|
|
1880
|
+
|
|
1881
|
+
if (selector === "#node-input-influxDb") {
|
|
1882
|
+
influxCustomPayloadEnabledState = true;
|
|
1883
|
+
} else {
|
|
1884
|
+
multiInverterCustomPayloadEnabledState = true;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
enforceMultiInverterPayload();
|
|
1888
|
+
|
|
1889
|
+
syncPayloadModeUi();
|
|
1890
|
+
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
|
|
1894
|
+
function setupMultiInverterLongPress() {
|
|
1895
|
+
|
|
1896
|
+
const $multi = $("#node-input-multiInverter");
|
|
1897
|
+
|
|
1898
|
+
const $controlExport = $("#node-input-controlExport");
|
|
1899
|
+
const $multiGrid = $("#node-input-multiGrid");
|
|
1900
|
+
const $influx = $("#node-input-influxDb");
|
|
1901
|
+
|
|
1902
|
+
|
|
1903
|
+
function startLongPress(selector) {
|
|
1904
|
+
|
|
1905
|
+
if (!selector) {
|
|
1906
|
+
|
|
1907
|
+
return;
|
|
1908
|
+
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
multiLongPressTriggered = false;
|
|
1912
|
+
|
|
1913
|
+
multiLongPressStartSelector = selector;
|
|
1914
|
+
|
|
1915
|
+
clearMultiLongPressTimer();
|
|
1916
|
+
|
|
1917
|
+
multiLongPressTimer = setTimeout(function () {
|
|
1918
|
+
|
|
1919
|
+
const $target = $(multiLongPressStartSelector);
|
|
1920
|
+
|
|
1921
|
+
if ($target.length && $target.is(":checked")) {
|
|
1922
|
+
|
|
1923
|
+
multiLongPressTriggered = true;
|
|
1924
|
+
|
|
1925
|
+
unlockAdvancedSelection(multiLongPressStartSelector);
|
|
1926
|
+
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
}, MULTI_EXPERT_LONG_PRESS_MS);
|
|
1930
|
+
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
|
|
1934
|
+
function stopLongPress() {
|
|
1935
|
+
|
|
1936
|
+
clearMultiLongPressTimer();
|
|
1937
|
+
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
|
|
1941
|
+
$multi
|
|
1942
|
+
|
|
1943
|
+
.off(".froniusMultiLongPress")
|
|
1944
|
+
|
|
1945
|
+
.on("mousedown.froniusMultiLongPress touchstart.froniusMultiLongPress", function () {
|
|
1946
|
+
|
|
1947
|
+
startLongPress("#node-input-multiInverter");
|
|
1948
|
+
|
|
1949
|
+
})
|
|
1950
|
+
|
|
1951
|
+
.on("mouseup.froniusMultiLongPress mouseleave.froniusMultiLongPress touchend.froniusMultiLongPress touchcancel.froniusMultiLongPress", function () {
|
|
1952
|
+
|
|
1953
|
+
stopLongPress();
|
|
1954
|
+
|
|
1955
|
+
})
|
|
1956
|
+
|
|
1957
|
+
.on("click.froniusMultiLongPress", function (evt) {
|
|
1958
|
+
|
|
1959
|
+
if (!multiLongPressTriggered) {
|
|
1960
|
+
|
|
1961
|
+
return;
|
|
1962
|
+
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
evt.preventDefault();
|
|
1966
|
+
|
|
1967
|
+
evt.stopImmediatePropagation();
|
|
1968
|
+
|
|
1969
|
+
suppressAdvancedResetOnce = true;
|
|
1970
|
+
|
|
1971
|
+
$multi.prop("checked", true).trigger("change");
|
|
1972
|
+
|
|
1973
|
+
multiLongPressTriggered = false;
|
|
1974
|
+
|
|
1975
|
+
});
|
|
1976
|
+
|
|
1977
|
+
|
|
1978
|
+
$controlExport
|
|
1979
|
+
|
|
1980
|
+
.off(".froniusControlLongPress")
|
|
1981
|
+
|
|
1982
|
+
.on("mousedown.froniusControlLongPress touchstart.froniusControlLongPress", function () {
|
|
1983
|
+
|
|
1984
|
+
startLongPress("#node-input-controlExport");
|
|
1985
|
+
|
|
1986
|
+
})
|
|
1987
|
+
|
|
1988
|
+
.on("mouseup.froniusControlLongPress mouseleave.froniusControlLongPress touchend.froniusControlLongPress touchcancel.froniusControlLongPress", function () {
|
|
1989
|
+
|
|
1990
|
+
stopLongPress();
|
|
1991
|
+
|
|
1992
|
+
})
|
|
1993
|
+
|
|
1994
|
+
.on("click.froniusControlLongPress", function (evt) {
|
|
1995
|
+
|
|
1996
|
+
if (!multiLongPressTriggered) {
|
|
1997
|
+
|
|
1998
|
+
return;
|
|
1999
|
+
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
evt.preventDefault();
|
|
2003
|
+
|
|
2004
|
+
evt.stopImmediatePropagation();
|
|
2005
|
+
|
|
2006
|
+
suppressAdvancedResetOnce = true;
|
|
2007
|
+
|
|
2008
|
+
$controlExport.prop("checked", true).trigger("change");
|
|
2009
|
+
|
|
2010
|
+
multiLongPressTriggered = false;
|
|
2011
|
+
|
|
2012
|
+
});
|
|
2013
|
+
|
|
2014
|
+
$influx
|
|
2015
|
+
.off(".froniusInfluxLongPress")
|
|
2016
|
+
.on("mousedown.froniusInfluxLongPress touchstart.froniusInfluxLongPress", function () {
|
|
2017
|
+
startLongPress("#node-input-influxDb");
|
|
2018
|
+
})
|
|
2019
|
+
.on("mouseup.froniusInfluxLongPress mouseleave.froniusInfluxLongPress touchend.froniusInfluxLongPress touchcancel.froniusInfluxLongPress", function () {
|
|
2020
|
+
stopLongPress();
|
|
2021
|
+
})
|
|
2022
|
+
.on("click.froniusInfluxLongPress", function (evt) {
|
|
2023
|
+
if (!multiLongPressTriggered) {
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
2026
|
+
evt.preventDefault();
|
|
2027
|
+
evt.stopImmediatePropagation();
|
|
2028
|
+
suppressAdvancedResetOnce = true;
|
|
2029
|
+
$influx.prop("checked", true).trigger("change");
|
|
2030
|
+
multiLongPressTriggered = false;
|
|
2031
|
+
});
|
|
2032
|
+
|
|
2033
|
+
$multiGrid
|
|
2034
|
+
.off(".froniusMultiGridLongPress")
|
|
2035
|
+
.on("mousedown.froniusMultiGridLongPress touchstart.froniusMultiGridLongPress", function () {
|
|
2036
|
+
startLongPress("#node-input-multiGrid");
|
|
2037
|
+
})
|
|
2038
|
+
.on("mouseup.froniusMultiGridLongPress mouseleave.froniusMultiGridLongPress touchend.froniusMultiGridLongPress touchcancel.froniusMultiGridLongPress", function () {
|
|
2039
|
+
stopLongPress();
|
|
2040
|
+
})
|
|
2041
|
+
.on("click.froniusMultiGridLongPress", function (evt) {
|
|
2042
|
+
if (!multiLongPressTriggered) {
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
evt.preventDefault();
|
|
2046
|
+
evt.stopImmediatePropagation();
|
|
2047
|
+
suppressAdvancedResetOnce = true;
|
|
2048
|
+
$multiGrid.prop("checked", true).trigger("change");
|
|
2049
|
+
multiLongPressTriggered = false;
|
|
2050
|
+
});
|
|
2051
|
+
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
|
|
2055
|
+
function enforceIntegrationExclusivity(changed) {
|
|
2056
|
+
|
|
2057
|
+
const $multi = $("#node-input-multiInverter");
|
|
2058
|
+
|
|
2059
|
+
const $control = $("#node-input-controlExport");
|
|
2060
|
+
|
|
2061
|
+
const $influx = $("#node-input-influxDb");
|
|
2062
|
+
const $multiGrid = $("#node-input-multiGrid");
|
|
2063
|
+
const $scada = $("#node-input-scadaAggregator");
|
|
2064
|
+
|
|
2065
|
+
if (changed === "scada" && $scada.is(":checked")) {
|
|
2066
|
+
$multi.prop("checked", false);
|
|
2067
|
+
$control.prop("checked", false);
|
|
2068
|
+
$multiGrid.prop("checked", false);
|
|
2069
|
+
$influx.prop("checked", false);
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
if (changed !== "scada" && ($multi.is(":checked") || $control.is(":checked") || $multiGrid.is(":checked") || $influx.is(":checked"))) {
|
|
2073
|
+
$scada.prop("checked", false);
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
|
|
2077
|
+
if (changed === "multi" && $multi.is(":checked")) {
|
|
2078
|
+
|
|
2079
|
+
$control.prop("checked", false);
|
|
2080
|
+
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
if (changed === "control" && $control.is(":checked")) {
|
|
2084
|
+
|
|
2085
|
+
$multi.prop("checked", false);
|
|
2086
|
+
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
if (changed === "influx" && $influx.is(":checked")) {
|
|
2090
|
+
// Pastreaza integrarea principala activa.
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
if ((changed === "multi" || changed === "control") && ($multi.is(":checked") || $control.is(":checked"))) {
|
|
2094
|
+
$multiGrid.prop("checked", false);
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
if (changed === "multiGrid" && $multiGrid.is(":checked")) {
|
|
2098
|
+
$multi.prop("checked", false);
|
|
2099
|
+
$control.prop("checked", false);
|
|
2100
|
+
// Pastreaza InfluxDB ca integrare secundara.
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
|
|
2106
|
+
function toggleMultiInverterFields() {
|
|
2107
|
+
|
|
2108
|
+
|
|
2109
|
+
if (isSingleOutputIntegrationEnabled()) {
|
|
2110
|
+
|
|
2111
|
+
$("#row-inverter-id").show();
|
|
2112
|
+
|
|
2113
|
+
} else {
|
|
2114
|
+
|
|
2115
|
+
$("#row-inverter-id").hide();
|
|
2116
|
+
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
|
|
2120
|
+
syncMultiInverterExpertUi();
|
|
2121
|
+
|
|
2122
|
+
$("#row-influx-measurement,#row-influx-node").toggle(isInfluxIntegrationEnabled());
|
|
2123
|
+
|
|
2124
|
+
enforceMultiInverterPayload();
|
|
2125
|
+
|
|
2126
|
+
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
|
|
2130
|
+
RED.nodes.registerType("fronius-read", {
|
|
2131
|
+
|
|
2132
|
+
|
|
2133
|
+
category: "Atelierul de Tehnologii",
|
|
2134
|
+
|
|
2135
|
+
|
|
2136
|
+
color: "#f59f00",
|
|
2137
|
+
|
|
2138
|
+
|
|
2139
|
+
defaults: {
|
|
2140
|
+
license: { value: "", type: "atelier-license", required: true },
|
|
2141
|
+
|
|
2142
|
+
name: { value: "" },
|
|
2143
|
+
|
|
2144
|
+
host: { value: "", required: true },
|
|
2145
|
+
|
|
2146
|
+
port: { value: 502, required: true, validate: RED.validators.number() },
|
|
2147
|
+
|
|
2148
|
+
unitId: { value: 1, required: true, validate: RED.validators.number() },
|
|
2149
|
+
|
|
2150
|
+
pollInterval: {
|
|
2151
|
+
value: 5000,
|
|
2152
|
+
required: true,
|
|
2153
|
+
validate: function (value) {
|
|
2154
|
+
const text = String(value || "").trim().toLowerCase();
|
|
2155
|
+
if (text === "off") return true;
|
|
2156
|
+
const n = Number(text);
|
|
2157
|
+
return Number.isFinite(n) && n >= 0;
|
|
2158
|
+
}
|
|
2159
|
+
},
|
|
2160
|
+
|
|
2161
|
+
inverterType: { value: "auto" },
|
|
2162
|
+
|
|
2163
|
+
payloadMode: { value: "full" },
|
|
2164
|
+
|
|
2165
|
+
payloadField: { value: "full" },
|
|
2166
|
+
|
|
2167
|
+
payloadFields: { value: ["full"] },
|
|
2168
|
+
|
|
2169
|
+
debugMode: { value: false },
|
|
2170
|
+
|
|
2171
|
+
multiInverter: { value: false },
|
|
2172
|
+
|
|
2173
|
+
controlExport: { value: false },
|
|
2174
|
+
|
|
2175
|
+
multiGrid: { value: false },
|
|
2176
|
+
|
|
2177
|
+
scadaAggregator: { value: false },
|
|
2178
|
+
|
|
2179
|
+
influxDb: { value: false },
|
|
2180
|
+
|
|
2181
|
+
influxMeasurement: {
|
|
2182
|
+
value: "",
|
|
2183
|
+
validate: function (v) {
|
|
2184
|
+
const influxChecked = $("#node-input-influxDb").length
|
|
2185
|
+
? $("#node-input-influxDb").is(":checked")
|
|
2186
|
+
: !!this.influxDb;
|
|
2187
|
+
|
|
2188
|
+
return !influxChecked || !!String(v || "").trim();
|
|
2189
|
+
}
|
|
2190
|
+
},
|
|
2191
|
+
influxNode: { value: "" },
|
|
2192
|
+
|
|
2193
|
+
multiInverterExpertMode: { value: false },
|
|
2194
|
+
|
|
2195
|
+
multiInverterUseSelectedFields: { value: false },
|
|
2196
|
+
|
|
2197
|
+
multiGridUseSelectedFields: { value: false },
|
|
2198
|
+
|
|
2199
|
+
inverterId: {
|
|
2200
|
+
|
|
2201
|
+
value: "",
|
|
2202
|
+
|
|
2203
|
+
validate: function (v) {
|
|
2204
|
+
|
|
2205
|
+
const isMulti = $("#node-input-multiInverter").is(":checked") ||
|
|
2206
|
+
$("#node-input-controlExport").is(":checked") ||
|
|
2207
|
+
$("#node-input-multiGrid").is(":checked") ||
|
|
2208
|
+
$("#node-input-scadaAggregator").is(":checked") ||
|
|
2209
|
+
$("#node-input-influxDb").is(":checked");
|
|
2210
|
+
|
|
2211
|
+
|
|
2212
|
+
if (!isMulti) {
|
|
2213
|
+
|
|
2214
|
+
return true;
|
|
2215
|
+
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
|
|
2219
|
+
return !!String(v || "").trim();
|
|
2220
|
+
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
},
|
|
2226
|
+
|
|
2227
|
+
|
|
2228
|
+
inputs: 0,
|
|
2229
|
+
|
|
2230
|
+
|
|
2231
|
+
outputs: 1,
|
|
2232
|
+
|
|
2233
|
+
|
|
2234
|
+
icon: "font-awesome/fa-sun-o",
|
|
2235
|
+
|
|
2236
|
+
|
|
2237
|
+
label: function () {
|
|
2238
|
+
|
|
2239
|
+
const baseLabel = this.name || this.host || "fronius-read";
|
|
2240
|
+
|
|
2241
|
+
|
|
2242
|
+
if ((this.multiInverter || this.controlExport || this.multiGrid || this.scadaAggregator || this.influxDb) && this.inverterId) {
|
|
2243
|
+
|
|
2244
|
+
const suffix = " [" + this.inverterId + "]";
|
|
2245
|
+
|
|
2246
|
+
if (baseLabel.indexOf(suffix) !== -1) {
|
|
2247
|
+
|
|
2248
|
+
return baseLabel;
|
|
2249
|
+
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
return baseLabel + suffix;
|
|
2253
|
+
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
|
|
2257
|
+
return baseLabel;
|
|
2258
|
+
|
|
2259
|
+
},
|
|
2260
|
+
|
|
2261
|
+
|
|
2262
|
+
oneditprepare: function () {
|
|
2263
|
+
|
|
2264
|
+
|
|
2265
|
+
const node = this;
|
|
2266
|
+
const influxSelect = $("#node-input-influxNode").empty().append($("<option></option>").val("").text("Selecteaza adt-influxdb"));
|
|
2267
|
+
RED.nodes.eachNode(function (candidate) {
|
|
2268
|
+
if (candidate.type === "adt-influxdb") influxSelect.append($("<option></option>").val(candidate.id).text(candidate.name || "adt-influxdb"));
|
|
2269
|
+
});
|
|
2270
|
+
influxSelect.val(node.influxNode || "");
|
|
2271
|
+
function syncInputs() {
|
|
2272
|
+
const text = String($("#node-input-pollInterval").val() || "").trim().toLowerCase();
|
|
2273
|
+
node.inputs = text === "off" || text === "0" ? 1 : 0;
|
|
2274
|
+
}
|
|
2275
|
+
$("#node-input-pollInterval").off(".froniusReadPoll").on("keyup.froniusReadPoll change.froniusReadPoll", syncInputs);
|
|
2276
|
+
syncInputs();
|
|
2277
|
+
|
|
2278
|
+
const influxEnabledOnLoad = !!this.influxDb;
|
|
2279
|
+
const compactIntegrationOnLoad = !!(this.multiInverter || this.controlExport || this.multiGrid);
|
|
2280
|
+
const scadaEnabledOnLoad = !!this.scadaAggregator;
|
|
2281
|
+
const compactEnabledOnLoad = !!(compactIntegrationOnLoad || influxEnabledOnLoad || scadaEnabledOnLoad);
|
|
2282
|
+
|
|
2283
|
+
let currentPayloadFields;
|
|
2284
|
+
|
|
2285
|
+
if (influxEnabledOnLoad && !compactIntegrationOnLoad) {
|
|
2286
|
+
const selectedInflux = getNonFullSelections(getPersistedPayloadSelection(this));
|
|
2287
|
+
currentPayloadFields = selectedInflux.length ? selectedInflux : DEFAULT_INFLUX_PAYLOAD_FIELDS.slice();
|
|
2288
|
+
} else if (this.multiGrid) {
|
|
2289
|
+
const selectedMultiGrid = getNonFullSelections(getPersistedPayloadSelection(this));
|
|
2290
|
+
currentPayloadFields = this.multiGridUseSelectedFields && selectedMultiGrid.length
|
|
2291
|
+
? selectedMultiGrid
|
|
2292
|
+
: DEFAULT_MULTI_GRID_PAYLOAD_FIELDS.slice();
|
|
2293
|
+
} else if (compactEnabledOnLoad) {
|
|
2294
|
+
currentPayloadFields = (
|
|
2295
|
+
(this.multiInverterUseSelectedFields || this.multiInverterExpertMode)
|
|
2296
|
+
? (function () {
|
|
2297
|
+
|
|
2298
|
+
const selected = getNonFullSelections(getPersistedPayloadSelection(this));
|
|
2299
|
+
|
|
2300
|
+
return selected.length ? selected : ["summary.ac.power_w"];
|
|
2301
|
+
|
|
2302
|
+
}).call(this)
|
|
2303
|
+
|
|
2304
|
+
: ["summary.ac.power_w"]
|
|
2305
|
+
);
|
|
2306
|
+
} else {
|
|
2307
|
+
currentPayloadFields = getPersistedPayloadSelection(this);
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
|
|
2311
|
+
payloadSelectionState = currentPayloadFields.slice();
|
|
2312
|
+
|
|
2313
|
+
payloadModeState = normalizePayloadMode(this.payloadMode || inferPayloadModeFromSelection(currentPayloadFields));
|
|
2314
|
+
|
|
2315
|
+
multiInverterCustomPayloadEnabledState = !!(
|
|
2316
|
+
compactIntegrationOnLoad &&
|
|
2317
|
+
(this.multiInverterUseSelectedFields || this.multiGridUseSelectedFields || this.multiInverterExpertMode)
|
|
2318
|
+
);
|
|
2319
|
+
|
|
2320
|
+
influxCustomPayloadWasSavedState = !!(influxEnabledOnLoad && this.multiInverterUseSelectedFields);
|
|
2321
|
+
influxCustomPayloadEnabledState = influxCustomPayloadWasSavedState;
|
|
2322
|
+
|
|
2323
|
+
// Advanced edit unlock is session-only: after each Done/Deploy editor starts locked.
|
|
2324
|
+
|
|
2325
|
+
multiAdvancedUnlockedState = false;
|
|
2326
|
+
|
|
2327
|
+
$("#node-input-payloadFields").val(JSON.stringify(payloadSelectionState));
|
|
2328
|
+
|
|
2329
|
+
$("#node-input-payloadMode").val(payloadModeState);
|
|
2330
|
+
|
|
2331
|
+
|
|
2332
|
+
this.outputs = computeOutputsCount(
|
|
2333
|
+
|
|
2334
|
+
payloadSelectionState,
|
|
2335
|
+
|
|
2336
|
+
compactEnabledOnLoad || !!this.influxDb,
|
|
2337
|
+
|
|
2338
|
+
!!this.debugMode
|
|
2339
|
+
|
|
2340
|
+
);
|
|
2341
|
+
|
|
2342
|
+
|
|
2343
|
+
const nodeId = this.id;
|
|
2344
|
+
|
|
2345
|
+
const probeKey = getProbeKey();
|
|
2346
|
+
|
|
2347
|
+
const savedAutoName = this.host && this.inverterId
|
|
2348
|
+
? this.host + " [" + this.inverterId + "]"
|
|
2349
|
+
: "";
|
|
2350
|
+
let autoNameEnabled = !this.name || this.name === this.host || this.name === savedAutoName || this.name === "fronius-read";
|
|
2351
|
+
|
|
2352
|
+
function buildAutoName() {
|
|
2353
|
+
|
|
2354
|
+
const host = ($("#node-input-host").val() || "").trim();
|
|
2355
|
+
|
|
2356
|
+
const inverterId = String($("#node-input-inverterId").val() || "").trim();
|
|
2357
|
+
|
|
2358
|
+
if (!isSingleOutputIntegrationEnabled() || !inverterId) {
|
|
2359
|
+
|
|
2360
|
+
return host;
|
|
2361
|
+
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
return host ? (host + " [" + inverterId + "]") : inverterId;
|
|
2365
|
+
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
|
|
2369
|
+
lastGoodProbeInfo = null;
|
|
2370
|
+
detectedDeviceType = "unknown";
|
|
2371
|
+
enforceSmartMeterIntegrationAvailability();
|
|
2372
|
+
|
|
2373
|
+
buildPayloadSelect("auto", currentPayloadFields, "unknown", null);
|
|
2374
|
+
|
|
2375
|
+
setProbeInfo("Detectarea nu este inca disponibila. Payload ramane pe valoarea salvata sau pe 'Toate valorile'.", "#999");
|
|
2376
|
+
|
|
2377
|
+
|
|
2378
|
+
if (!$("#node-input-name").val().trim()) {
|
|
2379
|
+
|
|
2380
|
+
const autoName = buildAutoName();
|
|
2381
|
+
|
|
2382
|
+
if (autoName) {
|
|
2383
|
+
|
|
2384
|
+
$("#node-input-name").val(autoName);
|
|
2385
|
+
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
|
|
2391
|
+
$("#node-input-host")
|
|
2392
|
+
|
|
2393
|
+
.off(".froniusAutoName")
|
|
2394
|
+
|
|
2395
|
+
.on("input.froniusAutoName change.froniusAutoName", function () {
|
|
2396
|
+
|
|
2397
|
+
autoNameEnabled = true;
|
|
2398
|
+
$("#node-input-name").val(buildAutoName());
|
|
2399
|
+
|
|
2400
|
+
});
|
|
2401
|
+
|
|
2402
|
+
|
|
2403
|
+
$("#node-input-inverterId")
|
|
2404
|
+
|
|
2405
|
+
.off(".froniusAutoName")
|
|
2406
|
+
|
|
2407
|
+
.on("input.froniusAutoName change.froniusAutoName", function () {
|
|
2408
|
+
|
|
2409
|
+
if (autoNameEnabled) {
|
|
2410
|
+
$("#node-input-name").val(buildAutoName());
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
});
|
|
2414
|
+
|
|
2415
|
+
$("#node-input-name")
|
|
2416
|
+
.off(".froniusAutoName")
|
|
2417
|
+
.on("input.froniusAutoName", function () {
|
|
2418
|
+
const value = String($(this).val() || "").trim();
|
|
2419
|
+
autoNameEnabled = !value || value === buildAutoName();
|
|
2420
|
+
});
|
|
2421
|
+
|
|
2422
|
+
|
|
2423
|
+
$("#node-input-payloadMode")
|
|
2424
|
+
|
|
2425
|
+
.off(".froniusPayloadMode")
|
|
2426
|
+
|
|
2427
|
+
.on("change.froniusPayloadMode", function () {
|
|
2428
|
+
|
|
2429
|
+
syncPayloadModeUi();
|
|
2430
|
+
|
|
2431
|
+
});
|
|
2432
|
+
|
|
2433
|
+
|
|
2434
|
+
$("#node-fronius-read-select-all")
|
|
2435
|
+
|
|
2436
|
+
.off(".froniusToolbar")
|
|
2437
|
+
|
|
2438
|
+
.on("click.froniusToolbar", function (evt) {
|
|
2439
|
+
|
|
2440
|
+
evt.preventDefault();
|
|
2441
|
+
|
|
2442
|
+
if ($("#node-fronius-read-select-all").hasClass("disabled")) {
|
|
2443
|
+
|
|
2444
|
+
return;
|
|
2445
|
+
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
const selected = [];
|
|
2449
|
+
|
|
2450
|
+
$("#node-fronius-read-field-list-container .pr-field-checkbox").each(function () {
|
|
2451
|
+
|
|
2452
|
+
const value = String($(this).attr("data-value") || "").trim();
|
|
2453
|
+
|
|
2454
|
+
if (value) {
|
|
2455
|
+
|
|
2456
|
+
$(this).prop("checked", true);
|
|
2457
|
+
|
|
2458
|
+
selected.push(value);
|
|
2459
|
+
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
});
|
|
2463
|
+
|
|
2464
|
+
if (selected.length > 0) {
|
|
2465
|
+
|
|
2466
|
+
persistPayloadSelection(selected);
|
|
2467
|
+
applyFieldCheckboxSelection(selected);
|
|
2468
|
+
|
|
2469
|
+
}
|
|
2470
|
+
|
|
2471
|
+
$("#node-input-payloadMode").val("selected");
|
|
2472
|
+
|
|
2473
|
+
syncPayloadModeUi();
|
|
2474
|
+
|
|
2475
|
+
});
|
|
2476
|
+
|
|
2477
|
+
|
|
2478
|
+
$("#node-fronius-read-clear-all")
|
|
2479
|
+
|
|
2480
|
+
.off(".froniusToolbar")
|
|
2481
|
+
|
|
2482
|
+
.on("click.froniusToolbar", function (evt) {
|
|
2483
|
+
|
|
2484
|
+
evt.preventDefault();
|
|
2485
|
+
|
|
2486
|
+
if ($("#node-fronius-read-clear-all").hasClass("disabled")) {
|
|
2487
|
+
|
|
2488
|
+
return;
|
|
2489
|
+
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
if (isInfluxIntegrationEnabled() && multiAdvancedUnlockedState) {
|
|
2493
|
+
$("#node-fronius-read-field-list-container .pr-field-checkbox").prop("checked", false);
|
|
2494
|
+
persistPayloadSelection([], true);
|
|
2495
|
+
$("#node-input-payloadMode").val("selected");
|
|
2496
|
+
return;
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
const firstSelectable = pickFirstSelectableField();
|
|
2500
|
+
|
|
2501
|
+
if (firstSelectable) {
|
|
2502
|
+
|
|
2503
|
+
persistPayloadSelection([firstSelectable]);
|
|
2504
|
+
|
|
2505
|
+
$("#node-input-payloadMode").val("selected");
|
|
2506
|
+
|
|
2507
|
+
} else {
|
|
2508
|
+
|
|
2509
|
+
persistPayloadSelection(["full"]);
|
|
2510
|
+
|
|
2511
|
+
$("#node-input-payloadMode").val("full");
|
|
2512
|
+
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
syncPayloadModeUi();
|
|
2516
|
+
|
|
2517
|
+
});
|
|
2518
|
+
|
|
2519
|
+
$("#node-fronius-read-default-values")
|
|
2520
|
+
|
|
2521
|
+
.off(".froniusToolbar")
|
|
2522
|
+
|
|
2523
|
+
.on("click.froniusToolbar", function (evt) {
|
|
2524
|
+
|
|
2525
|
+
evt.preventDefault();
|
|
2526
|
+
|
|
2527
|
+
if (!isInfluxIntegrationEnabled()) {
|
|
2528
|
+
return;
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
persistPayloadSelection(getDefaultInfluxFields());
|
|
2532
|
+
applyFieldCheckboxSelection(getDefaultInfluxFields());
|
|
2533
|
+
$("#node-input-payloadMode").val("selected");
|
|
2534
|
+
syncPayloadModeUi();
|
|
2535
|
+
|
|
2536
|
+
});
|
|
2537
|
+
|
|
2538
|
+
|
|
2539
|
+
$("#node-input-host, #node-input-port, #node-input-unitId")
|
|
2540
|
+
|
|
2541
|
+
.off(".froniusProbe")
|
|
2542
|
+
|
|
2543
|
+
.on("change.froniusProbe", function () {
|
|
2544
|
+
|
|
2545
|
+
currentPayloadFields = payloadSelectionState.slice();
|
|
2546
|
+
|
|
2547
|
+
lastProbeKey = null;
|
|
2548
|
+
detectedDeviceType = "unknown";
|
|
2549
|
+
enforceSmartMeterIntegrationAvailability();
|
|
2550
|
+
|
|
2551
|
+
buildPayloadSelect("auto", currentPayloadFields, "unknown", null);
|
|
2552
|
+
|
|
2553
|
+
runLiveProbe(true, currentPayloadFields);
|
|
2554
|
+
|
|
2555
|
+
});
|
|
2556
|
+
|
|
2557
|
+
|
|
2558
|
+
$("#node-input-multiInverter")
|
|
2559
|
+
|
|
2560
|
+
.off(".froniusMulti")
|
|
2561
|
+
|
|
2562
|
+
.on("change.froniusMulti", () => {
|
|
2563
|
+
|
|
2564
|
+
enforceIntegrationExclusivity("multi");
|
|
2565
|
+
|
|
2566
|
+
if (!suppressAdvancedResetOnce) {
|
|
2567
|
+
|
|
2568
|
+
multiAdvancedUnlockedState = false;
|
|
2569
|
+
influxCustomPayloadEnabledState = false;
|
|
2570
|
+
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2573
|
+
suppressAdvancedResetOnce = false;
|
|
2574
|
+
|
|
2575
|
+
toggleMultiInverterFields();
|
|
2576
|
+
|
|
2577
|
+
this.outputs = computeOutputsCount(
|
|
2578
|
+
|
|
2579
|
+
payloadSelectionState,
|
|
2580
|
+
|
|
2581
|
+
isSingleOutputIntegrationEnabled(),
|
|
2582
|
+
|
|
2583
|
+
$("#node-input-debugMode").is(":checked")
|
|
2584
|
+
|
|
2585
|
+
);
|
|
2586
|
+
|
|
2587
|
+
$("#node-input-inverterId").trigger("change");
|
|
2588
|
+
|
|
2589
|
+
});
|
|
2590
|
+
|
|
2591
|
+
|
|
2592
|
+
$("#node-input-controlExport")
|
|
2593
|
+
|
|
2594
|
+
.off(".froniusControlExport")
|
|
2595
|
+
|
|
2596
|
+
.on("change.froniusControlExport", () => {
|
|
2597
|
+
|
|
2598
|
+
enforceIntegrationExclusivity("control");
|
|
2599
|
+
|
|
2600
|
+
if (!suppressAdvancedResetOnce) {
|
|
2601
|
+
|
|
2602
|
+
multiAdvancedUnlockedState = false;
|
|
2603
|
+
influxCustomPayloadEnabledState = false;
|
|
2604
|
+
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2607
|
+
suppressAdvancedResetOnce = false;
|
|
2608
|
+
|
|
2609
|
+
toggleMultiInverterFields();
|
|
2610
|
+
|
|
2611
|
+
this.outputs = computeOutputsCount(
|
|
2612
|
+
|
|
2613
|
+
payloadSelectionState,
|
|
2614
|
+
|
|
2615
|
+
isSingleOutputIntegrationEnabled(),
|
|
2616
|
+
|
|
2617
|
+
$("#node-input-debugMode").is(":checked")
|
|
2618
|
+
|
|
2619
|
+
);
|
|
2620
|
+
|
|
2621
|
+
$("#node-input-inverterId").trigger("change");
|
|
2622
|
+
|
|
2623
|
+
});
|
|
2624
|
+
|
|
2625
|
+
$("#node-input-multiGrid")
|
|
2626
|
+
.off(".froniusMultiGrid")
|
|
2627
|
+
.on("change.froniusMultiGrid", () => {
|
|
2628
|
+
|
|
2629
|
+
enforceIntegrationExclusivity("multiGrid");
|
|
2630
|
+
|
|
2631
|
+
if (!suppressAdvancedResetOnce) {
|
|
2632
|
+
multiAdvancedUnlockedState = false;
|
|
2633
|
+
multiInverterCustomPayloadEnabledState = false;
|
|
2634
|
+
influxCustomPayloadEnabledState = false;
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
suppressAdvancedResetOnce = false;
|
|
2638
|
+
toggleMultiInverterFields();
|
|
2639
|
+
|
|
2640
|
+
this.outputs = computeOutputsCount(
|
|
2641
|
+
payloadSelectionState,
|
|
2642
|
+
isSingleOutputIntegrationEnabled(),
|
|
2643
|
+
$("#node-input-debugMode").is(":checked")
|
|
2644
|
+
);
|
|
2645
|
+
|
|
2646
|
+
$("#node-input-inverterId").trigger("change");
|
|
2647
|
+
});
|
|
2648
|
+
|
|
2649
|
+
$("#node-input-scadaAggregator")
|
|
2650
|
+
.off(".froniusScada")
|
|
2651
|
+
.on("change.froniusScada", () => {
|
|
2652
|
+
enforceIntegrationExclusivity("scada");
|
|
2653
|
+
toggleMultiInverterFields();
|
|
2654
|
+
this.outputs = computeOutputsCount(
|
|
2655
|
+
payloadSelectionState,
|
|
2656
|
+
isSingleOutputIntegrationEnabled(),
|
|
2657
|
+
$("#node-input-debugMode").is(":checked")
|
|
2658
|
+
);
|
|
2659
|
+
$("#node-input-inverterId").trigger("change");
|
|
2660
|
+
});
|
|
2661
|
+
|
|
2662
|
+
$("#node-input-influxDb")
|
|
2663
|
+
.off(".froniusInflux")
|
|
2664
|
+
.on("change.froniusInflux", () => {
|
|
2665
|
+
|
|
2666
|
+
enforceIntegrationExclusivity("influx");
|
|
2667
|
+
if (!suppressAdvancedResetOnce) {
|
|
2668
|
+
multiAdvancedUnlockedState = false;
|
|
2669
|
+
influxCustomPayloadEnabledState = false;
|
|
2670
|
+
}
|
|
2671
|
+
suppressAdvancedResetOnce = false;
|
|
2672
|
+
toggleMultiInverterFields();
|
|
2673
|
+
|
|
2674
|
+
this.outputs = computeOutputsCount(
|
|
2675
|
+
payloadSelectionState,
|
|
2676
|
+
isSingleOutputIntegrationEnabled(),
|
|
2677
|
+
$("#node-input-debugMode").is(":checked")
|
|
2678
|
+
);
|
|
2679
|
+
|
|
2680
|
+
$("#node-input-inverterId").trigger("change");
|
|
2681
|
+
});
|
|
2682
|
+
|
|
2683
|
+
|
|
2684
|
+
if ($("#node-input-multiInverter").is(":checked") && $("#node-input-controlExport").is(":checked")) {
|
|
2685
|
+
|
|
2686
|
+
enforceIntegrationExclusivity("multi");
|
|
2687
|
+
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
if ($("#node-input-influxDb").is(":checked")) {
|
|
2691
|
+
enforceIntegrationExclusivity("influx");
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
if ($("#node-input-multiGrid").is(":checked")) {
|
|
2695
|
+
enforceIntegrationExclusivity("multiGrid");
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
|
|
2699
|
+
$("#node-input-debugMode")
|
|
2700
|
+
|
|
2701
|
+
.off(".froniusDebug")
|
|
2702
|
+
|
|
2703
|
+
.on("change.froniusDebug", () => {
|
|
2704
|
+
|
|
2705
|
+
updateOutputsPreview(payloadSelectionState);
|
|
2706
|
+
|
|
2707
|
+
this.outputs = computeOutputsCount(
|
|
2708
|
+
|
|
2709
|
+
payloadSelectionState,
|
|
2710
|
+
|
|
2711
|
+
isSingleOutputIntegrationEnabled(),
|
|
2712
|
+
|
|
2713
|
+
$("#node-input-debugMode").is(":checked")
|
|
2714
|
+
|
|
2715
|
+
);
|
|
2716
|
+
|
|
2717
|
+
});
|
|
2718
|
+
|
|
2719
|
+
|
|
2720
|
+
toggleMultiInverterFields();
|
|
2721
|
+
|
|
2722
|
+
setupMultiInverterLongPress();
|
|
2723
|
+
|
|
2724
|
+
syncPayloadModeUi();
|
|
2725
|
+
|
|
2726
|
+
|
|
2727
|
+
readCachedState(nodeId, function (state) {
|
|
2728
|
+
|
|
2729
|
+
|
|
2730
|
+
if (state) {
|
|
2731
|
+
|
|
2732
|
+
applyProbeData({
|
|
2733
|
+
|
|
2734
|
+
inverter_profile: state.inverter_profile,
|
|
2735
|
+
|
|
2736
|
+
inverter_profile_label: state.inverter_profile_label,
|
|
2737
|
+
|
|
2738
|
+
model: state.summary && state.summary.common ? state.summary.common.model : null,
|
|
2739
|
+
|
|
2740
|
+
device_type: state.device_type,
|
|
2741
|
+
|
|
2742
|
+
meter_model: state.summary && state.summary.meter ? state.summary.meter.meter_model : null,
|
|
2743
|
+
|
|
2744
|
+
phase_mode: state.phase_mode,
|
|
2745
|
+
|
|
2746
|
+
mppt_count: state.mppt_count
|
|
2747
|
+
|
|
2748
|
+
}, currentPayloadFields, probeKey);
|
|
2749
|
+
|
|
2750
|
+
enforceMultiInverterPayload();
|
|
2751
|
+
|
|
2752
|
+
syncPayloadModeUi();
|
|
2753
|
+
|
|
2754
|
+
} else {
|
|
2755
|
+
|
|
2756
|
+
runLiveProbe(true, currentPayloadFields);
|
|
2757
|
+
|
|
2758
|
+
syncPayloadModeUi();
|
|
2759
|
+
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
|
|
2763
|
+
});
|
|
2764
|
+
|
|
2765
|
+
|
|
2766
|
+
},
|
|
2767
|
+
|
|
2768
|
+
|
|
2769
|
+
oneditsave: function () {
|
|
2770
|
+
|
|
2771
|
+
|
|
2772
|
+
this.inverterType = "auto";
|
|
2773
|
+
this.influxDb = $("#node-input-influxDb").is(":checked");
|
|
2774
|
+
this.multiGrid = $("#node-input-multiGrid").is(":checked");
|
|
2775
|
+
this.scadaAggregator = $("#node-input-scadaAggregator").is(":checked");
|
|
2776
|
+
if (this.scadaAggregator) {
|
|
2777
|
+
$("#node-input-multiInverter,#node-input-controlExport,#node-input-multiGrid,#node-input-influxDb").prop("checked", false);
|
|
2778
|
+
this.multiInverter = false;
|
|
2779
|
+
this.controlExport = false;
|
|
2780
|
+
this.multiGrid = false;
|
|
2781
|
+
this.influxDb = false;
|
|
2782
|
+
this.payloadMode = "full";
|
|
2783
|
+
this.payloadFields = ["full"];
|
|
2784
|
+
this.payloadField = "full";
|
|
2785
|
+
this.outputs = computeOutputsCount(["full"], true, $("#node-input-debugMode").is(":checked"));
|
|
2786
|
+
}
|
|
2787
|
+
if (isSmartMeterDetected()) {
|
|
2788
|
+
$("#node-input-multiInverter").prop("checked", false);
|
|
2789
|
+
$("#node-input-controlExport").prop("checked", false);
|
|
2790
|
+
} else {
|
|
2791
|
+
$("#node-input-multiGrid").prop("checked", false);
|
|
2792
|
+
this.multiGrid = false;
|
|
2793
|
+
}
|
|
2794
|
+
this.influxMeasurement = String($("#node-input-influxMeasurement").val() || "").trim();
|
|
2795
|
+
const pollText = String($("#node-input-pollInterval").val() || "").trim().toLowerCase();
|
|
2796
|
+
this.inputs = pollText === "off" || pollText === "0" ? 1 : 0;
|
|
2797
|
+
|
|
2798
|
+
|
|
2799
|
+
if (!$("#node-input-name").val().trim()) {
|
|
2800
|
+
|
|
2801
|
+
const host = ($("#node-input-host").val() || "").trim();
|
|
2802
|
+
|
|
2803
|
+
const inverterId = String($("#node-input-inverterId").val() || "").trim();
|
|
2804
|
+
|
|
2805
|
+
if (isSingleOutputIntegrationEnabled() && inverterId) {
|
|
2806
|
+
|
|
2807
|
+
$("#node-input-name").val(host ? (host + " [" + inverterId + "]") : inverterId);
|
|
2808
|
+
|
|
2809
|
+
} else {
|
|
2810
|
+
|
|
2811
|
+
$("#node-input-name").val(host);
|
|
2812
|
+
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
|
|
2818
|
+
if (!this.scadaAggregator && (isCompactIntegrationEnabled() || this.influxDb)) {
|
|
2819
|
+
|
|
2820
|
+
const selected = getNonFullSelections(payloadSelectionState);
|
|
2821
|
+
const compactIntegrationActive = isCompactIntegrationEnabled();
|
|
2822
|
+
const useCompactCustomSelection = !!multiInverterCustomPayloadEnabledState;
|
|
2823
|
+
const useInfluxCustomSelection = !!(influxCustomPayloadEnabledState || influxCustomPayloadWasSavedState);
|
|
2824
|
+
|
|
2825
|
+
this.multiInverterExpertMode = false;
|
|
2826
|
+
|
|
2827
|
+
this.payloadMode = "selected";
|
|
2828
|
+
this.multiInverterUseSelectedFields = compactIntegrationActive ? useCompactCustomSelection : useInfluxCustomSelection;
|
|
2829
|
+
this.multiGridUseSelectedFields = this.multiGrid && useCompactCustomSelection;
|
|
2830
|
+
|
|
2831
|
+
if (this.influxDb && !compactIntegrationActive) {
|
|
2832
|
+
const defaultInfluxFields = getDefaultInfluxFields();
|
|
2833
|
+
const effectiveInflux = useInfluxCustomSelection
|
|
2834
|
+
? (selected.length ? selected : defaultInfluxFields)
|
|
2835
|
+
: defaultInfluxFields;
|
|
2836
|
+
|
|
2837
|
+
this.payloadFields = effectiveInflux.slice();
|
|
2838
|
+
this.payloadField = effectiveInflux[0];
|
|
2839
|
+
} else {
|
|
2840
|
+
const defaultCompactFields = this.multiGrid
|
|
2841
|
+
? DEFAULT_MULTI_GRID_PAYLOAD_FIELDS.slice()
|
|
2842
|
+
: [getDefaultCompactField()];
|
|
2843
|
+
const effectiveCompact = selected.length ? selected : defaultCompactFields;
|
|
2844
|
+
if (useCompactCustomSelection) {
|
|
2845
|
+
this.payloadFields = effectiveCompact.slice();
|
|
2846
|
+
this.payloadField = effectiveCompact[0];
|
|
2847
|
+
} else {
|
|
2848
|
+
this.payloadFields = defaultCompactFields.slice();
|
|
2849
|
+
this.payloadField = defaultCompactFields[0];
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
}
|
|
2853
|
+
|
|
2854
|
+
|
|
2855
|
+
this.outputs = computeOutputsCount(
|
|
2856
|
+
|
|
2857
|
+
this.payloadFields,
|
|
2858
|
+
|
|
2859
|
+
true,
|
|
2860
|
+
|
|
2861
|
+
$("#node-input-debugMode").is(":checked")
|
|
2862
|
+
|
|
2863
|
+
);
|
|
2864
|
+
|
|
2865
|
+
} else if (!this.scadaAggregator) {
|
|
2866
|
+
|
|
2867
|
+
this.multiInverterExpertMode = false;
|
|
2868
|
+
|
|
2869
|
+
this.multiInverterUseSelectedFields = false;
|
|
2870
|
+
this.multiGridUseSelectedFields = false;
|
|
2871
|
+
|
|
2872
|
+
const mode = normalizePayloadMode($("#node-input-payloadMode").val());
|
|
2873
|
+
|
|
2874
|
+
this.payloadMode = mode;
|
|
2875
|
+
|
|
2876
|
+
|
|
2877
|
+
if (mode === "full") {
|
|
2878
|
+
|
|
2879
|
+
this.payloadFields = ["full"];
|
|
2880
|
+
|
|
2881
|
+
this.payloadField = "full";
|
|
2882
|
+
|
|
2883
|
+
this.outputs = computeOutputsCount(["full"], this.influxDb, $("#node-input-debugMode").is(":checked"));
|
|
2884
|
+
|
|
2885
|
+
} else {
|
|
2886
|
+
|
|
2887
|
+
const selected = sanitizeSelectedValues(
|
|
2888
|
+
|
|
2889
|
+
payloadSelectionState,
|
|
2890
|
+
|
|
2891
|
+
this.payloadFields || this.payloadField || "full"
|
|
2892
|
+
|
|
2893
|
+
);
|
|
2894
|
+
|
|
2895
|
+
const nonFull = getNonFullSelections(selected);
|
|
2896
|
+
|
|
2897
|
+
|
|
2898
|
+
if (nonFull.length > 0) {
|
|
2899
|
+
|
|
2900
|
+
this.payloadFields = nonFull.slice();
|
|
2901
|
+
|
|
2902
|
+
this.payloadField = nonFull[0];
|
|
2903
|
+
|
|
2904
|
+
this.outputs = computeOutputsCount(nonFull, this.influxDb, $("#node-input-debugMode").is(":checked"));
|
|
2905
|
+
|
|
2906
|
+
} else {
|
|
2907
|
+
|
|
2908
|
+
this.payloadFields = ["full"];
|
|
2909
|
+
|
|
2910
|
+
this.payloadField = "full";
|
|
2911
|
+
|
|
2912
|
+
this.outputs = computeOutputsCount(["full"], this.influxDb, $("#node-input-debugMode").is(":checked"));
|
|
2913
|
+
|
|
2914
|
+
this.payloadMode = "full";
|
|
2915
|
+
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
|
|
2923
|
+
$("#node-input-payloadFields").val(JSON.stringify(this.payloadFields));
|
|
2924
|
+
|
|
2925
|
+
|
|
2926
|
+
$("#node-input-host, #node-input-port, #node-input-unitId").off(".froniusProbe");
|
|
2927
|
+
|
|
2928
|
+
$("#node-input-multiInverter").off(".froniusMulti");
|
|
2929
|
+
|
|
2930
|
+
$("#node-input-host").off(".froniusAutoName");
|
|
2931
|
+
|
|
2932
|
+
$("#node-input-inverterId").off(".froniusAutoName");
|
|
2933
|
+
$("#node-input-name").off(".froniusAutoName");
|
|
2934
|
+
|
|
2935
|
+
$("#node-input-payloadMode").off(".froniusPayloadMode");
|
|
2936
|
+
|
|
2937
|
+
$("#node-fronius-read-select-all").off(".froniusToolbar");
|
|
2938
|
+
|
|
2939
|
+
$("#node-fronius-read-clear-all").off(".froniusToolbar");
|
|
2940
|
+
$("#node-fronius-read-default-values").off(".froniusToolbar");
|
|
2941
|
+
|
|
2942
|
+
$("#node-input-debugMode").off(".froniusDebug");
|
|
2943
|
+
|
|
2944
|
+
$("#node-input-multiInverter").off(".froniusMultiLongPress");
|
|
2945
|
+
|
|
2946
|
+
$("#node-input-controlExport").off(".froniusControlLongPress");
|
|
2947
|
+
|
|
2948
|
+
$("#node-input-controlExport").off(".froniusControlExport");
|
|
2949
|
+
$("#node-input-multiGrid").off(".froniusMultiGrid");
|
|
2950
|
+
$("#node-input-scadaAggregator").off(".froniusScada");
|
|
2951
|
+
$("#node-input-multiGrid").off(".froniusMultiGridLongPress");
|
|
2952
|
+
$("#node-input-influxDb").off(".froniusInflux");
|
|
2953
|
+
$("#node-input-influxDb").off(".froniusInfluxLongPress");
|
|
2954
|
+
|
|
2955
|
+
clearMultiLongPressTimer();
|
|
2956
|
+
|
|
2957
|
+
|
|
2958
|
+
},
|
|
2959
|
+
|
|
2960
|
+
|
|
2961
|
+
oneditcancel: function () {
|
|
2962
|
+
|
|
2963
|
+
|
|
2964
|
+
$("#node-input-host, #node-input-port, #node-input-unitId").off(".froniusProbe");
|
|
2965
|
+
|
|
2966
|
+
$("#node-input-multiInverter").off(".froniusMulti");
|
|
2967
|
+
|
|
2968
|
+
$("#node-input-host").off(".froniusAutoName");
|
|
2969
|
+
|
|
2970
|
+
$("#node-input-inverterId").off(".froniusAutoName");
|
|
2971
|
+
$("#node-input-name").off(".froniusAutoName");
|
|
2972
|
+
|
|
2973
|
+
$("#node-input-payloadMode").off(".froniusPayloadMode");
|
|
2974
|
+
|
|
2975
|
+
$("#node-fronius-read-select-all").off(".froniusToolbar");
|
|
2976
|
+
|
|
2977
|
+
$("#node-fronius-read-clear-all").off(".froniusToolbar");
|
|
2978
|
+
$("#node-fronius-read-default-values").off(".froniusToolbar");
|
|
2979
|
+
|
|
2980
|
+
$("#node-input-debugMode").off(".froniusDebug");
|
|
2981
|
+
|
|
2982
|
+
$("#node-input-multiInverter").off(".froniusMultiLongPress");
|
|
2983
|
+
|
|
2984
|
+
$("#node-input-controlExport").off(".froniusControlLongPress");
|
|
2985
|
+
|
|
2986
|
+
$("#node-input-controlExport").off(".froniusControlExport");
|
|
2987
|
+
$("#node-input-multiGrid").off(".froniusMultiGrid");
|
|
2988
|
+
$("#node-input-multiGrid").off(".froniusMultiGridLongPress");
|
|
2989
|
+
$("#node-input-influxDb").off(".froniusInflux");
|
|
2990
|
+
$("#node-input-influxDb").off(".froniusInfluxLongPress");
|
|
2991
|
+
|
|
2992
|
+
clearMultiLongPressTimer();
|
|
2993
|
+
|
|
2994
|
+
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
|
|
2998
|
+
});
|
|
2999
|
+
|
|
3000
|
+
|
|
3001
|
+
})();
|
|
3002
|
+
|
|
3003
|
+
|
|
3004
|
+
</script>
|
|
3005
|
+
|
|
3006
|
+
|
|
3007
|
+
|
|
3008
|
+
<script type="text/html" data-template-name="fronius-read">
|
|
3009
|
+
<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>
|
|
3010
|
+
|
|
3011
|
+
<div class="fronius-read-editor">
|
|
3012
|
+
|
|
3013
|
+
<div class="pr-section">
|
|
3014
|
+
|
|
3015
|
+
<div class="pr-section-title"><i class="fa fa-plug"></i> Connection</div>
|
|
3016
|
+
|
|
3017
|
+
<p class="pr-section-note">Configuratia de citire SunSpec (Modbus TCP) pentru invertor Fronius sau Fronius Smart Meter IP.</p>
|
|
3018
|
+
|
|
3019
|
+
|
|
3020
|
+
<div class="pr-grid pr-grid-2">
|
|
3021
|
+
|
|
3022
|
+
<div class="form-row">
|
|
3023
|
+
|
|
3024
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
3025
|
+
|
|
3026
|
+
<input type="text" id="node-input-name" placeholder="192.168.0.101">
|
|
3027
|
+
|
|
3028
|
+
</div>
|
|
3029
|
+
|
|
3030
|
+
|
|
3031
|
+
<div class="form-row">
|
|
3032
|
+
|
|
3033
|
+
<label for="node-input-host"><i class="fa fa-globe"></i> IP</label>
|
|
3034
|
+
|
|
3035
|
+
<input type="text" id="node-input-host" placeholder="192.168.0.xxx">
|
|
3036
|
+
|
|
3037
|
+
</div>
|
|
3038
|
+
|
|
3039
|
+
|
|
3040
|
+
<div class="form-row">
|
|
3041
|
+
|
|
3042
|
+
<label for="node-input-port"><i class="fa fa-plug"></i> Port</label>
|
|
3043
|
+
|
|
3044
|
+
<input type="text" id="node-input-port" placeholder="502">
|
|
3045
|
+
|
|
3046
|
+
</div>
|
|
3047
|
+
|
|
3048
|
+
|
|
3049
|
+
<div class="form-row">
|
|
3050
|
+
|
|
3051
|
+
<label for="node-input-unitId"><i class="fa fa-hashtag"></i> Unit ID</label>
|
|
3052
|
+
|
|
3053
|
+
<input type="text" id="node-input-unitId" placeholder="1">
|
|
3054
|
+
|
|
3055
|
+
</div>
|
|
3056
|
+
|
|
3057
|
+
|
|
3058
|
+
<div class="form-row">
|
|
3059
|
+
|
|
3060
|
+
<label for="node-input-pollInterval"><i class="fa fa-clock-o"></i> Poll</label>
|
|
3061
|
+
|
|
3062
|
+
<input type="text" id="node-input-pollInterval" placeholder="5000 sau off">
|
|
3063
|
+
|
|
3064
|
+
</div>
|
|
3065
|
+
|
|
3066
|
+
|
|
3067
|
+
<div class="form-row" id="row-inverter-id">
|
|
3068
|
+
|
|
3069
|
+
<label for="node-input-inverterId"><i class="fa fa-id-badge"></i> Inverter ID</label>
|
|
3070
|
+
|
|
3071
|
+
<input type="text" id="node-input-inverterId" placeholder="inv1">
|
|
3072
|
+
|
|
3073
|
+
</div>
|
|
3074
|
+
|
|
3075
|
+
|
|
3076
|
+
<div class="form-row pr-span-2 fronius-probe-row">
|
|
3077
|
+
|
|
3078
|
+
<label><i class="fa fa-search"></i> Detectare</label>
|
|
3079
|
+
|
|
3080
|
+
<div id="node-fronius-read-probe-info" class="fronius-probe-info">-</div>
|
|
3081
|
+
|
|
3082
|
+
</div>
|
|
3083
|
+
|
|
3084
|
+
</div>
|
|
3085
|
+
|
|
3086
|
+
</div>
|
|
3087
|
+
|
|
3088
|
+
|
|
3089
|
+
<div class="pr-section">
|
|
3090
|
+
|
|
3091
|
+
<div class="pr-section-title"><i class="fa fa-filter"></i> Payload</div>
|
|
3092
|
+
|
|
3093
|
+
<p class="pr-section-note">Alege payload complet sau selecteaza campurile care trebuie emise pe iesiri.</p>
|
|
3094
|
+
|
|
3095
|
+
|
|
3096
|
+
<input type="hidden" id="node-input-inverterType">
|
|
3097
|
+
|
|
3098
|
+
<input type="hidden" id="node-input-payloadFields">
|
|
3099
|
+
|
|
3100
|
+
|
|
3101
|
+
<div class="form-row">
|
|
3102
|
+
|
|
3103
|
+
<label for="node-input-payloadMode"><i class="fa fa-list"></i> Payload mode</label>
|
|
3104
|
+
|
|
3105
|
+
<select id="node-input-payloadMode">
|
|
3106
|
+
|
|
3107
|
+
<option value="full">Full payload</option>
|
|
3108
|
+
|
|
3109
|
+
<option value="selected">Selected payload</option>
|
|
3110
|
+
|
|
3111
|
+
</select>
|
|
3112
|
+
|
|
3113
|
+
</div>
|
|
3114
|
+
|
|
3115
|
+
|
|
3116
|
+
<div class="form-row pr-checkbox-row">
|
|
3117
|
+
|
|
3118
|
+
<label for="node-input-multiInverter"><i class="fa fa-sitemap"></i> Multi-inverter</label>
|
|
3119
|
+
|
|
3120
|
+
<input type="checkbox" id="node-input-multiInverter">
|
|
3121
|
+
|
|
3122
|
+
<span class="pr-inline-note">Fixeaza automat payload-ul pe Putere AC (W) pentru integrare in <code>multi-inverter</code>.</span>
|
|
3123
|
+
|
|
3124
|
+
</div>
|
|
3125
|
+
|
|
3126
|
+
|
|
3127
|
+
<div class="form-row pr-checkbox-row">
|
|
3128
|
+
|
|
3129
|
+
<label for="node-input-controlExport"><i class="fa fa-exchange"></i> Control-export</label>
|
|
3130
|
+
|
|
3131
|
+
<input type="checkbox" id="node-input-controlExport">
|
|
3132
|
+
|
|
3133
|
+
<span class="pr-inline-note">Fixeaza automat payload-ul pe Putere AC (W) pentru integrare directa in <code>control-export</code>.</span>
|
|
3134
|
+
|
|
3135
|
+
</div>
|
|
3136
|
+
|
|
3137
|
+
<div class="form-row fronius-meta-row" id="node-fronius-read-smart-meter-integration-note" style="display:none;">
|
|
3138
|
+
|
|
3139
|
+
<label></label>
|
|
3140
|
+
|
|
3141
|
+
<div class="fronius-meta-info">Smart Meter detectat: functiile Multi-inverter si Control-export sunt inactive; Multi-grid este disponibil.</div>
|
|
3142
|
+
|
|
3143
|
+
</div>
|
|
3144
|
+
|
|
3145
|
+
<div class="form-row pr-checkbox-row">
|
|
3146
|
+
|
|
3147
|
+
<label for="node-input-multiGrid"><i class="fa fa-sitemap"></i> Multi-grid</label>
|
|
3148
|
+
|
|
3149
|
+
<input type="checkbox" id="node-input-multiGrid" disabled>
|
|
3150
|
+
|
|
3151
|
+
<span class="pr-inline-note">Trimite un payload compact cu puterile Smart Meter-ului pentru nodul <code>multi-grid</code>.</span>
|
|
3152
|
+
|
|
3153
|
+
</div>
|
|
3154
|
+
|
|
3155
|
+
<div class="form-row pr-checkbox-row">
|
|
3156
|
+
|
|
3157
|
+
<label for="node-input-scadaAggregator"><i class="fa fa-object-group"></i> SCADA aggregator</label>
|
|
3158
|
+
|
|
3159
|
+
<input type="checkbox" id="node-input-scadaAggregator">
|
|
3160
|
+
|
|
3161
|
+
<span class="pr-inline-note">Emite P, Q, U și f normalizate, cu <code>msg.scadaSource</code> și <code>msg.scadaGroup</code>, direct pentru <code>scada-aggregator</code>.</span>
|
|
3162
|
+
|
|
3163
|
+
</div>
|
|
3164
|
+
|
|
3165
|
+
<div class="form-row pr-checkbox-row">
|
|
3166
|
+
|
|
3167
|
+
<label for="node-input-influxDb"><i class="fa fa-database"></i> InfluxDB</label>
|
|
3168
|
+
|
|
3169
|
+
<input type="checkbox" id="node-input-influxDb">
|
|
3170
|
+
|
|
3171
|
+
<span class="pr-inline-note">Grupeaza valorile in <code>msg.influx</code> pentru nodul <code>adt-influxdb</code>.</span>
|
|
3172
|
+
|
|
3173
|
+
</div>
|
|
3174
|
+
|
|
3175
|
+
<div class="form-row" id="row-influx-measurement" style="display:none;">
|
|
3176
|
+
|
|
3177
|
+
<label for="node-input-influxMeasurement"><i class="fa fa-line-chart"></i> Measurement</label>
|
|
3178
|
+
|
|
3179
|
+
<input type="text" id="node-input-influxMeasurement" placeholder="Fronius Inverter 1">
|
|
3180
|
+
|
|
3181
|
+
</div>
|
|
3182
|
+
<div class="form-row" id="row-influx-node" style="display:none;">
|
|
3183
|
+
<label for="node-input-influxNode"><i class="fa fa-plug"></i> Nod InfluxDB</label>
|
|
3184
|
+
<select id="node-input-influxNode"></select>
|
|
3185
|
+
</div>
|
|
3186
|
+
|
|
3187
|
+
|
|
3188
|
+
<div class="form-row pr-checkbox-row">
|
|
3189
|
+
|
|
3190
|
+
<label for="node-input-debugMode"><i class="fa fa-bug"></i> Debug mode</label>
|
|
3191
|
+
|
|
3192
|
+
<input type="checkbox" id="node-input-debugMode">
|
|
3193
|
+
|
|
3194
|
+
<span class="pr-inline-note">Adauga o iesire suplimentara care livreaza mesajul raw citit la fiecare poll.</span>
|
|
3195
|
+
|
|
3196
|
+
</div>
|
|
3197
|
+
|
|
3198
|
+
|
|
3199
|
+
<div class="form-row fronius-meta-row" id="node-fronius-read-multi-note" style="display:none;">
|
|
3200
|
+
|
|
3201
|
+
<label></label>
|
|
3202
|
+
|
|
3203
|
+
<div class="fronius-meta-info">In modul multi-inverter se foloseste automat Putere AC (W).</div>
|
|
3204
|
+
|
|
3205
|
+
</div>
|
|
3206
|
+
|
|
3207
|
+
|
|
3208
|
+
<div id="row-fronius-read-field-list" style="display:none;">
|
|
3209
|
+
|
|
3210
|
+
<div class="pr-toolbar">
|
|
3211
|
+
|
|
3212
|
+
<a href="#" class="button" id="node-fronius-read-select-all"><i class="fa fa-check-square-o"></i> Select all</a>
|
|
3213
|
+
|
|
3214
|
+
<a href="#" class="button" id="node-fronius-read-clear-all"><i class="fa fa-square-o"></i> Clear all</a>
|
|
3215
|
+
|
|
3216
|
+
<a href="#" class="button" id="node-fronius-read-default-values" style="display:none;"><i class="fa fa-undo"></i> Default values</a>
|
|
3217
|
+
|
|
3218
|
+
</div>
|
|
3219
|
+
|
|
3220
|
+
|
|
3221
|
+
<div id="node-fronius-read-field-list-container" class="pr-field-list"></div>
|
|
3222
|
+
|
|
3223
|
+
<div id="node-fronius-read-payload-summary" style="display:none;"></div>
|
|
3224
|
+
|
|
3225
|
+
</div>
|
|
3226
|
+
|
|
3227
|
+
|
|
3228
|
+
<div class="form-row fronius-meta-row">
|
|
3229
|
+
|
|
3230
|
+
<label></label>
|
|
3231
|
+
|
|
3232
|
+
<div class="fronius-meta-info">Iesiri active: <span id="node-fronius-read-outputs-info">1</span></div>
|
|
3233
|
+
|
|
3234
|
+
</div>
|
|
3235
|
+
|
|
3236
|
+
</div>
|
|
3237
|
+
|
|
3238
|
+
</div>
|
|
3239
|
+
|
|
3240
|
+
|
|
3241
|
+
</script>
|
|
3242
|
+
|
|
3243
|
+
|
|
3244
|
+
<script type="text/html" data-help-name="fronius-read">
|
|
3245
|
+
|
|
3246
|
+
|
|
3247
|
+
<p>
|
|
3248
|
+
|
|
3249
|
+
Nodul <b>fronius-read</b> citeste date dintr-un invertor Fronius sau Fronius Smart Meter IP folosind protocolul <b>SunSpec (Modbus TCP)</b>.
|
|
3250
|
+
|
|
3251
|
+
Este gandit pentru citire periodica, selectie clara de payload si integrare directa cu nodurile de control din pachet.
|
|
3252
|
+
|
|
3253
|
+
</p>
|
|
3254
|
+
|
|
3255
|
+
|
|
3256
|
+
<h3>Cerinte</h3>
|
|
3257
|
+
|
|
3258
|
+
<ul>
|
|
3259
|
+
|
|
3260
|
+
<li>Invertorul trebuie sa fie accesibil in retea prin IP.</li>
|
|
3261
|
+
|
|
3262
|
+
<li>Modbus TCP / SunSpec trebuie sa fie activ pe invertor.</li>
|
|
3263
|
+
|
|
3264
|
+
<li>Portul folosit este, de obicei, <code>502</code>.</li>
|
|
3265
|
+
|
|
3266
|
+
</ul>
|
|
3267
|
+
|
|
3268
|
+
|
|
3269
|
+
<h3>Conexiune</h3>
|
|
3270
|
+
|
|
3271
|
+
<ul>
|
|
3272
|
+
|
|
3273
|
+
<li><b>Name</b> - numele afisat in flow. Daca este gol, nodul foloseste automat IP-ul.</li>
|
|
3274
|
+
|
|
3275
|
+
<li><b>IP</b> - adresa invertorului Fronius, de exemplu <code>192.168.0.101</code>.</li>
|
|
3276
|
+
|
|
3277
|
+
<li><b>Port</b> - portul Modbus TCP; valoarea uzuala este <code>502</code>.</li>
|
|
3278
|
+
|
|
3279
|
+
<li><b>Unit ID</b> - adresa Modbus a invertorului; in cele mai multe instalatii este <code>1</code>.</li>
|
|
3280
|
+
|
|
3281
|
+
<li><b>Poll</b> - intervalul de citire in milisecunde. Valoarea <code>off</code> sau <code>0</code> opreste poll-ul si activeaza intrarea pentru trigger manual.</li>
|
|
3282
|
+
|
|
3283
|
+
</ul>
|
|
3284
|
+
|
|
3285
|
+
|
|
3286
|
+
<h3>Detectare automata</h3>
|
|
3287
|
+
|
|
3288
|
+
<p>
|
|
3289
|
+
|
|
3290
|
+
La deschiderea editorului si in timpul rularii, nodul incearca sa identifice dispozitivul prin SunSpec. Pentru smart meter, valorile sunt expuse in <code>summary.meter.*</code>.
|
|
3291
|
+
|
|
3292
|
+
Detectarea este folosita ca sa afiseze doar campurile relevante pentru echipamentul gasit.
|
|
3293
|
+
|
|
3294
|
+
</p>
|
|
3295
|
+
|
|
3296
|
+
<ul>
|
|
3297
|
+
|
|
3298
|
+
<li><b>Model invertor</b> - de exemplu Fronius Verto, Symo, Primo, Eco sau Tauro.</li>
|
|
3299
|
+
|
|
3300
|
+
<li><b>Numar MPPT</b> - cate trackere DC sunt disponibile pentru selectie.</li>
|
|
3301
|
+
|
|
3302
|
+
<li><b>Tip faza</b> - monofazic sau trifazic, pentru afisarea tensiunilor si curentilor corecti.</li>
|
|
3303
|
+
|
|
3304
|
+
</ul>
|
|
3305
|
+
|
|
3306
|
+
|
|
3307
|
+
<p>
|
|
3308
|
+
|
|
3309
|
+
Daca detectarea nu este inca disponibila, nodul pastreaza selectia salvata sau foloseste payload complet.
|
|
3310
|
+
|
|
3311
|
+
</p>
|
|
3312
|
+
|
|
3313
|
+
|
|
3314
|
+
<h3>Payload</h3>
|
|
3315
|
+
|
|
3316
|
+
<ul>
|
|
3317
|
+
|
|
3318
|
+
<li><b>Full payload</b> - trimite obiectul complet cu status, detectare, sumar SunSpec si modele raw atunci cand sunt citite.</li>
|
|
3319
|
+
|
|
3320
|
+
<li><b>Selected payload</b> - permite alegerea unuia sau mai multor campuri. Pentru mai multe campuri, nodul creeaza cate o iesire principala pentru fiecare valoare selectata.</li>
|
|
3321
|
+
|
|
3322
|
+
<li><b>Select all</b> - selecteaza toate campurile disponibile dupa detectare.</li>
|
|
3323
|
+
|
|
3324
|
+
<li><b>Clear all</b> - deselecteaza campurile selectate; daca nu exista campuri disponibile, revine la payload complet.</li>
|
|
3325
|
+
|
|
3326
|
+
</ul>
|
|
3327
|
+
|
|
3328
|
+
|
|
3329
|
+
<h3>Campuri disponibile</h3>
|
|
3330
|
+
|
|
3331
|
+
<ul>
|
|
3332
|
+
|
|
3333
|
+
<li><b>AC</b> - putere activa, frecventa, putere aparenta, putere reactiva, curenti si tensiuni pe faze.</li>
|
|
3334
|
+
|
|
3335
|
+
<li><b>DC General</b> - putere DC totala, numar brut de module/stringuri si eveniment DC global.</li>
|
|
3336
|
+
|
|
3337
|
+
<li><b>MPPT</b> - tensiune, curent, putere si energie pentru fiecare MPPT detectat.</li>
|
|
3338
|
+
|
|
3339
|
+
<li><b>Device</b> - producator, model, optiuni, versiune, serie si adresa device.</li>
|
|
3340
|
+
|
|
3341
|
+
</ul>
|
|
3342
|
+
|
|
3343
|
+
|
|
3344
|
+
<h3>Iesiri</h3>
|
|
3345
|
+
|
|
3346
|
+
<ul>
|
|
3347
|
+
|
|
3348
|
+
<li>In <b>Full payload</b>, nodul are o iesire principala cu tot obiectul citit.</li>
|
|
3349
|
+
|
|
3350
|
+
<li>In <b>Selected payload</b> cu un singur camp, nodul are o iesire principala cu valoarea selectata.</li>
|
|
3351
|
+
|
|
3352
|
+
<li>In <b>Selected payload</b> cu mai multe campuri, fiecare camp primeste propria iesire, in ordinea selectiei.</li>
|
|
3353
|
+
|
|
3354
|
+
<li>Daca <b>Debug mode</b> este activ, se adauga o iesire suplimentara la final, cu mesajul raw.</li>
|
|
3355
|
+
|
|
3356
|
+
</ul>
|
|
3357
|
+
|
|
3358
|
+
|
|
3359
|
+
<h3>Structura mesajului</h3>
|
|
3360
|
+
|
|
3361
|
+
<ul>
|
|
3362
|
+
|
|
3363
|
+
<li><code>msg.topic</code> contine numele campului selectat sau <code>full</code>.</li>
|
|
3364
|
+
|
|
3365
|
+
<li><code>msg.payload</code> contine valoarea efectiva sau obiectul complet, in functie de modul de payload.</li>
|
|
3366
|
+
|
|
3367
|
+
<li><code>msg.payload_field</code> contine calea interna a campului, de exemplu <code>summary.ac.power_w</code>.</li>
|
|
3368
|
+
|
|
3369
|
+
<li><code>msg.payload_fields</code> contine lista campurilor folosite de nod.</li>
|
|
3370
|
+
|
|
3371
|
+
<li><code>msg.inverter_profile</code>, <code>msg.phase_mode</code> si <code>msg.mppt_count</code> descriu detectarea curenta.</li>
|
|
3372
|
+
|
|
3373
|
+
</ul>
|
|
3374
|
+
|
|
3375
|
+
|
|
3376
|
+
<h3>Multi-inverter</h3>
|
|
3377
|
+
|
|
3378
|
+
<p>
|
|
3379
|
+
|
|
3380
|
+
Cand optiunea <b>Multi-inverter</b> este activata, nodul pregateste automat mesajul pentru nodul <code>multi-inverter</code>.
|
|
3381
|
+
|
|
3382
|
+
Acest mod se foloseste atunci cand ai doua sau mai multe invertoare si vrei ca limita de productie sa fie impartita intre ele in functie de puterea curenta.
|
|
3383
|
+
|
|
3384
|
+
</p>
|
|
3385
|
+
|
|
3386
|
+
<ul>
|
|
3387
|
+
|
|
3388
|
+
<li>Payload-ul este fixat automat pe <b>Putere AC (W)</b>.</li>
|
|
3389
|
+
|
|
3390
|
+
<li>Nodul ramane cu o singura iesire principala, ca telemetrie compacta pentru un singur invertor.</li>
|
|
3391
|
+
|
|
3392
|
+
<li><b>Inverter ID</b> devine obligatoriu si trebuie sa fie identic cu ID-ul configurat in lista de invertoare din <code>multi-inverter</code>.</li>
|
|
3393
|
+
|
|
3394
|
+
<li><code>msg.topic</code> si <code>msg.inverter_id</code> primesc valoarea din <b>Inverter ID</b>.</li>
|
|
3395
|
+
|
|
3396
|
+
<li><code>msg.payload.power_w</code> contine puterea activa AC in W.</li>
|
|
3397
|
+
|
|
3398
|
+
<li><code>msg.payload_field</code> este <code>summary.ac.power_w</code>, iar <code>msg.payload_fields</code> confirma lista campurilor trimise.</li>
|
|
3399
|
+
|
|
3400
|
+
<li>Mesajul mai include informatii de detectare, cum ar fi <code>msg.inverter_profile</code>, <code>msg.phase_mode</code> si <code>msg.mppt_count</code>.</li>
|
|
3401
|
+
|
|
3402
|
+
</ul>
|
|
3403
|
+
|
|
3404
|
+
<p>
|
|
3405
|
+
|
|
3406
|
+
Pentru fiecare invertor fizic se foloseste cate un nod <code>fronius-read</code>, fiecare cu propriul IP si propriul <b>Inverter ID</b>.
|
|
3407
|
+
|
|
3408
|
+
Toate iesirile acestor noduri pot intra in acelasi <code>multi-inverter</code>.
|
|
3409
|
+
|
|
3410
|
+
Daca ID-ul din mesaj nu exista in configuratia <code>multi-inverter</code>, sau daca <code>msg.topic</code> si <code>msg.inverter_id</code> difera,
|
|
3411
|
+
|
|
3412
|
+
<code>multi-inverter</code> trateaza mesajul ca invalid pentru protectie.
|
|
3413
|
+
|
|
3414
|
+
</p>
|
|
3415
|
+
|
|
3416
|
+
<p>
|
|
3417
|
+
|
|
3418
|
+
Flux recomandat:
|
|
3419
|
+
|
|
3420
|
+
</p>
|
|
3421
|
+
|
|
3422
|
+
<pre>
|
|
3423
|
+
|
|
3424
|
+
fronius-read inv1 -> multi-inverter -> fronius-write inv1 / inv2 / ...
|
|
3425
|
+
|
|
3426
|
+
fronius-read inv2 -> multi-inverter -> fronius-write inv1 / inv2 / ...
|
|
3427
|
+
|
|
3428
|
+
fronius-read inv3 -> multi-inverter -> fronius-write inv1 / inv2 / ...
|
|
3429
|
+
|
|
3430
|
+
</pre>
|
|
3431
|
+
|
|
3432
|
+
<h3>Multi-grid pentru Smart Meter</h3>
|
|
3433
|
+
|
|
3434
|
+
<p>
|
|
3435
|
+
Cand este detectat un <b>Fronius Smart Meter IP</b>, optiunea <b>Multi-grid</b> devine disponibila.
|
|
3436
|
+
Nodul trimite un mesaj compact compatibil direct cu nodul <code>multi-grid</code>.
|
|
3437
|
+
</p>
|
|
3438
|
+
|
|
3439
|
+
<ul>
|
|
3440
|
+
<li>Implicit sunt trimise <code>power_w</code>, <code>power_l1_w</code>, <code>power_l2_w</code> si <code>power_l3_w</code>.</li>
|
|
3441
|
+
<li><b>Meter ID</b> este transmis in <code>msg.topic</code> si <code>msg.meter_id</code>.</li>
|
|
3442
|
+
<li>Multi-grid este indisponibil pentru invertoare si este exclusiv cu Multi-inverter, Control-export si InfluxDB.</li>
|
|
3443
|
+
</ul>
|
|
3444
|
+
|
|
3445
|
+
|
|
3446
|
+
<h3>Control-export</h3>
|
|
3447
|
+
|
|
3448
|
+
<p>
|
|
3449
|
+
|
|
3450
|
+
Cand optiunea <b>Control-export</b> este activata, nodul trimite acelasi format compact bazat pe <b>Putere AC (W)</b>,
|
|
3451
|
+
|
|
3452
|
+
potrivit pentru scenariile in care <code>control-export</code> trebuie sa cunoasca productia PV curenta a invertorului.
|
|
3453
|
+
|
|
3454
|
+
</p>
|
|
3455
|
+
|
|
3456
|
+
<ul>
|
|
3457
|
+
|
|
3458
|
+
<li><b>Multi-inverter</b>, <b>Control-export</b> si <b>InfluxDB</b> sunt exclusive; activarea uneia dezactiveaza celelalte.</li>
|
|
3459
|
+
|
|
3460
|
+
<li><b>Inverter ID</b> ramane obligatoriu si este trimis in <code>msg.topic</code> si <code>msg.inverter_id</code>.</li>
|
|
3461
|
+
|
|
3462
|
+
<li><code>msg.payload.power_w</code> reprezinta productia AC curenta a invertorului.</li>
|
|
3463
|
+
|
|
3464
|
+
<li>Mesajul nu este o limita de export; este telemetrie PV. Limita este calculata ulterior de <code>control-export</code>.</li>
|
|
3465
|
+
|
|
3466
|
+
<li>In <code>control-export</code>, aceasta telemetrie este utila impreuna cu optiunea de plafonare dupa productia PV disponibila.</li>
|
|
3467
|
+
|
|
3468
|
+
<li>Pentru un singur invertor, <b>Inverter ID</b> trebuie sa corespunda sursei PV pe care o asteapta <code>control-export</code>.</li>
|
|
3469
|
+
|
|
3470
|
+
</ul>
|
|
3471
|
+
|
|
3472
|
+
<p>
|
|
3473
|
+
|
|
3474
|
+
Intrarea principala a nodului <code>control-export</code> ramane masurarea din retea, de exemplu contorul de la punctul de cuplare.
|
|
3475
|
+
|
|
3476
|
+
Mesajul din <code>fronius-read</code> completeaza controlul cu productia PV curenta, astfel incat limita calculata sa nu ceara mai mult decat poate produce invertorul.
|
|
3477
|
+
|
|
3478
|
+
</p>
|
|
3479
|
+
|
|
3480
|
+
<p>
|
|
3481
|
+
|
|
3482
|
+
Flux recomandat pentru control direct:
|
|
3483
|
+
|
|
3484
|
+
</p>
|
|
3485
|
+
|
|
3486
|
+
<pre>
|
|
3487
|
+
|
|
3488
|
+
contor retea -> control-export -> fronius-write
|
|
3489
|
+
|
|
3490
|
+
fronius-read cu Control-export activ -> control-export
|
|
3491
|
+
|
|
3492
|
+
</pre>
|
|
3493
|
+
|
|
3494
|
+
|
|
3495
|
+
<h3>InfluxDB</h3>
|
|
3496
|
+
|
|
3497
|
+
<p>
|
|
3498
|
+
|
|
3499
|
+
Cand optiunea <b>InfluxDB</b> este activa, nodul emite un singur mesaj agregat pe ciclu de citire, cu
|
|
3500
|
+
<code>msg.influx.measurement</code>, <code>msg.influx.tags</code>, <code>msg.influx.fields</code> si
|
|
3501
|
+
<code>msg.influx.timestamp</code>, compatibil direct cu nodul <code>adt-influxdb</code>.
|
|
3502
|
+
|
|
3503
|
+
</p>
|
|
3504
|
+
|
|
3505
|
+
<ul>
|
|
3506
|
+
|
|
3507
|
+
<li><b>Inverter ID</b> devine obligatoriu si este folosit in tag-ul <code>inverter_id</code>.</li>
|
|
3508
|
+
|
|
3509
|
+
<li>Protectia anti-duplicare blocheaza combinatiile duplicate <code>measurement + inverter_id</code>.</li>
|
|
3510
|
+
|
|
3511
|
+
<li>Implicit, Influx foloseste setul presetat: <code>summary.ac.power_w</code>, <code>summary.dc.dc_total_power_w</code>, <code>summary.ac.voltage_l1_v</code>, <code>summary.ac.voltage_l2_v</code>, <code>summary.ac.voltage_l3_v</code>.</li>
|
|
3512
|
+
|
|
3513
|
+
<li>Valorile trimise in <code>msg.influx.fields</code> sunt cele selectate in <b>Selected payload</b>.</li>
|
|
3514
|
+
|
|
3515
|
+
</ul>
|
|
3516
|
+
|
|
3517
|
+
<h3>SCADA aggregator</h3>
|
|
3518
|
+
|
|
3519
|
+
<p>Cu <b>SCADA aggregator</b> activ, nodul emite un singur mesaj normalizat pentru fiecare citire. Pentru un invertor, mesajul are <code>msg.scadaGroup = "pv_inverter"</code>; pentru un Fronius Smart Meter, <code>msg.scadaGroup = "grid_meter"</code>. ID-ul stabil este preluat din <b>Inverter ID</b> / <b>Meter ID</b> și este transmis în <code>msg.scadaSource</code>; acesta trebuie să fie unic în întregul <code>scada-aggregator</code>.</p>
|
|
3520
|
+
|
|
3521
|
+
<pre>
|
|
3522
|
+
msg.scadaSource: "inv_01"
|
|
3523
|
+
msg.scadaGroup: "pv_inverter"
|
|
3524
|
+
msg.payload: { p, q, f, u_l1n, u_l2n, u_l3n, u_ln_avg, u_l12, u_l23, u_l31, u_ll_avg }
|
|
3525
|
+
</pre>
|
|
3526
|
+
|
|
3527
|
+
<p><code>p</code> este în W, <code>q</code> în VAr, <code>f</code> în Hz, iar tensiunile sunt în V. Acest mod este exclusiv față de Multi-inverter, Control-export, Multi-grid și InfluxDB.</p>
|
|
3528
|
+
|
|
3529
|
+
|
|
3530
|
+
<h3>Debug mode</h3>
|
|
3531
|
+
|
|
3532
|
+
<p>
|
|
3533
|
+
|
|
3534
|
+
<b>Debug mode</b> adauga ultima iesire a nodului. Aceasta emite <code>msg.topic = "fronius/raw"</code> si include modelele SunSpec brute,
|
|
3535
|
+
|
|
3536
|
+
sumarul citit, profilul detectat si lista campurilor folosite. Iesirea este utila pentru diagnostic si validarea maparii SunSpec.
|
|
3537
|
+
|
|
3538
|
+
</p>
|
|
3539
|
+
|
|
3540
|
+
|
|
3541
|
+
<h3>Erori</h3>
|
|
3542
|
+
|
|
3543
|
+
<p>
|
|
3544
|
+
|
|
3545
|
+
Daca citirea esueaza, nodul seteaza status rosu si trimite un mesaj cu <code>msg.topic = "fronius/error"</code>.
|
|
3546
|
+
|
|
3547
|
+
Payload-ul contine IP-ul, Unit ID-ul, mesajul de eroare si timestamp-ul.
|
|
3548
|
+
|
|
3549
|
+
</p>
|
|
3550
|
+
|
|
3551
|
+
|
|
3552
|
+
<h3>Exemplu multi-inverter</h3>
|
|
3553
|
+
|
|
3554
|
+
<pre>
|
|
3555
|
+
|
|
3556
|
+
msg.topic: "inv1"
|
|
3557
|
+
|
|
3558
|
+
msg.payload: {
|
|
3559
|
+
|
|
3560
|
+
power_w: 1040
|
|
3561
|
+
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3564
|
+
msg.inverter_id: "inv1"
|
|
3565
|
+
|
|
3566
|
+
</pre>
|
|
3567
|
+
|
|
3568
|
+
<h3>Referinta completa parametri</h3>
|
|
3569
|
+
|
|
3570
|
+
<ul>
|
|
3571
|
+
|
|
3572
|
+
<li><code>host</code>, <code>port</code>, <code>unitId</code>: conexiunea Modbus TCP catre Fronius.</li>
|
|
3573
|
+
|
|
3574
|
+
<li><code>pollInterval</code>: intervalul de citire periodica in milisecunde; <code>off</code> sau <code>0</code> activeaza citirea doar la trigger pe intrare.</li>
|
|
3575
|
+
|
|
3576
|
+
<li><code>inverterType</code>: profilul detectat sau selectat pentru maparea SunSpec.</li>
|
|
3577
|
+
|
|
3578
|
+
<li><code>payloadMode</code>: <code>full</code> sau <code>selected</code>.</li>
|
|
3579
|
+
|
|
3580
|
+
<li><code>payloadField</code>: campul unic folosit de configuratii vechi.</li>
|
|
3581
|
+
|
|
3582
|
+
<li><code>payloadFields</code>: lista campurilor selectate in modul curent.</li>
|
|
3583
|
+
|
|
3584
|
+
<li><code>debugMode</code>: adauga iesire raw pentru diagnostic.</li>
|
|
3585
|
+
|
|
3586
|
+
<li><code>multiInverter</code>: pregateste telemetrie compacta pentru <code>multi-inverter</code>.</li>
|
|
3587
|
+
|
|
3588
|
+
<li><code>controlExport</code>: trimite productie PV compacta pentru <code>control-export</code>.</li>
|
|
3589
|
+
|
|
3590
|
+
<li><code>multiGrid</code>: trimite format compact de meter catre <code>multi-grid</code>, cand dispozitivul detectat este Smart Meter.</li>
|
|
3591
|
+
|
|
3592
|
+
<li><code>scadaAggregator</code>: emite telemetrie P/Q/U/f normalizată pentru <code>scada-aggregator</code>.</li>
|
|
3593
|
+
|
|
3594
|
+
<li><code>influxDb</code>: emite <code>msg.influx</code> pentru <code>adt-influxdb</code>.</li>
|
|
3595
|
+
|
|
3596
|
+
<li><code>influxMeasurement</code>: measurement-ul folosit in InfluxDB.</li>
|
|
3597
|
+
|
|
3598
|
+
<li><code>multiInverterUseSelectedFields</code>: foloseste lista selectata pentru presetul multi-inverter.</li>
|
|
3599
|
+
|
|
3600
|
+
<li><code>multiGridUseSelectedFields</code>: permite selectie custom pentru presetul multi-grid.</li>
|
|
3601
|
+
|
|
3602
|
+
<li><code>inverterId</code>: ID stabil emis in <code>msg.topic</code>, <code>msg.inverter_id</code> si tag-uri Influx.</li>
|
|
3603
|
+
|
|
3604
|
+
</ul>
|
|
3605
|
+
|
|
3606
|
+
|
|
3607
|
+
</script>
|
|
3608
|
+
|
|
3609
|
+
|
|
3610
|
+
<style>
|
|
3611
|
+
|
|
3612
|
+
.fronius-read-editor {
|
|
3613
|
+
|
|
3614
|
+
--pr-border: #d7dde5;
|
|
3615
|
+
|
|
3616
|
+
--pr-muted: #667085;
|
|
3617
|
+
|
|
3618
|
+
--pr-surface: #f8fafc;
|
|
3619
|
+
|
|
3620
|
+
}
|
|
3621
|
+
|
|
3622
|
+
|
|
3623
|
+
.fronius-read-editor .pr-section {
|
|
3624
|
+
|
|
3625
|
+
margin: 0 0 18px;
|
|
3626
|
+
|
|
3627
|
+
padding: 14px 16px 16px;
|
|
3628
|
+
|
|
3629
|
+
border: 1px solid var(--pr-border);
|
|
3630
|
+
|
|
3631
|
+
border-radius: 10px;
|
|
3632
|
+
|
|
3633
|
+
background: var(--pr-surface);
|
|
3634
|
+
|
|
3635
|
+
}
|
|
3636
|
+
|
|
3637
|
+
|
|
3638
|
+
.fronius-read-editor .pr-section-title {
|
|
3639
|
+
|
|
3640
|
+
display: flex;
|
|
3641
|
+
|
|
3642
|
+
align-items: center;
|
|
3643
|
+
|
|
3644
|
+
gap: 8px;
|
|
3645
|
+
|
|
3646
|
+
margin: 0 0 4px;
|
|
3647
|
+
|
|
3648
|
+
font-size: 15px;
|
|
3649
|
+
|
|
3650
|
+
font-weight: 600;
|
|
3651
|
+
|
|
3652
|
+
color: #243447;
|
|
3653
|
+
|
|
3654
|
+
}
|
|
3655
|
+
|
|
3656
|
+
|
|
3657
|
+
.fronius-read-editor .pr-section-note {
|
|
3658
|
+
|
|
3659
|
+
margin: 0 0 14px;
|
|
3660
|
+
|
|
3661
|
+
color: var(--pr-muted);
|
|
3662
|
+
|
|
3663
|
+
font-size: 12px;
|
|
3664
|
+
|
|
3665
|
+
line-height: 1.45;
|
|
3666
|
+
|
|
3667
|
+
}
|
|
3668
|
+
|
|
3669
|
+
|
|
3670
|
+
.fronius-read-editor .pr-grid {
|
|
3671
|
+
|
|
3672
|
+
display: grid;
|
|
3673
|
+
|
|
3674
|
+
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
3675
|
+
|
|
3676
|
+
gap: 12px 16px;
|
|
3677
|
+
|
|
3678
|
+
}
|
|
3679
|
+
|
|
3680
|
+
|
|
3681
|
+
.fronius-read-editor .pr-grid-2 {
|
|
3682
|
+
|
|
3683
|
+
grid-template-columns: repeat(2, minmax(320px, 1fr));
|
|
3684
|
+
|
|
3685
|
+
}
|
|
3686
|
+
|
|
3687
|
+
|
|
3688
|
+
.fronius-read-editor .pr-span-2 {
|
|
3689
|
+
|
|
3690
|
+
grid-column: 1 / -1;
|
|
3691
|
+
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
|
|
3695
|
+
.fronius-read-editor .form-row {
|
|
3696
|
+
|
|
3697
|
+
margin-bottom: 12px;
|
|
3698
|
+
|
|
3699
|
+
}
|
|
3700
|
+
|
|
3701
|
+
|
|
3702
|
+
.fronius-read-editor .pr-grid .form-row,
|
|
3703
|
+
|
|
3704
|
+
.fronius-read-editor .form-row:last-child {
|
|
3705
|
+
|
|
3706
|
+
margin-bottom: 0;
|
|
3707
|
+
|
|
3708
|
+
}
|
|
3709
|
+
|
|
3710
|
+
|
|
3711
|
+
.fronius-read-editor .form-row > label {
|
|
3712
|
+
|
|
3713
|
+
width: 150px;
|
|
3714
|
+
|
|
3715
|
+
font-weight: 600;
|
|
3716
|
+
|
|
3717
|
+
}
|
|
3718
|
+
|
|
3719
|
+
|
|
3720
|
+
.fronius-read-editor .form-row > input[type="text"],
|
|
3721
|
+
|
|
3722
|
+
.fronius-read-editor .form-row > input[type="number"],
|
|
3723
|
+
|
|
3724
|
+
.fronius-read-editor .form-row > select {
|
|
3725
|
+
|
|
3726
|
+
width: calc(100% - 160px);
|
|
3727
|
+
|
|
3728
|
+
}
|
|
3729
|
+
|
|
3730
|
+
|
|
3731
|
+
.fronius-read-editor .pr-grid-2 .form-row > label {
|
|
3732
|
+
|
|
3733
|
+
width: 130px;
|
|
3734
|
+
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3737
|
+
|
|
3738
|
+
.fronius-read-editor .pr-grid-2 .form-row > input[type="text"],
|
|
3739
|
+
|
|
3740
|
+
.fronius-read-editor .pr-grid-2 .form-row > input[type="number"],
|
|
3741
|
+
|
|
3742
|
+
.fronius-read-editor .pr-grid-2 .form-row > select {
|
|
3743
|
+
|
|
3744
|
+
width: calc(100% - 140px);
|
|
3745
|
+
|
|
3746
|
+
}
|
|
3747
|
+
|
|
3748
|
+
|
|
3749
|
+
.fronius-read-editor .pr-inline-control {
|
|
3750
|
+
|
|
3751
|
+
width: calc(100% - 160px);
|
|
3752
|
+
|
|
3753
|
+
display: inline-block;
|
|
3754
|
+
|
|
3755
|
+
position: relative;
|
|
3756
|
+
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
|
|
3760
|
+
.fronius-read-editor .pr-toolbar {
|
|
3761
|
+
|
|
3762
|
+
display: flex;
|
|
3763
|
+
|
|
3764
|
+
flex-wrap: wrap;
|
|
3765
|
+
|
|
3766
|
+
gap: 8px;
|
|
3767
|
+
|
|
3768
|
+
margin-bottom: 10px;
|
|
3769
|
+
|
|
3770
|
+
}
|
|
3771
|
+
|
|
3772
|
+
|
|
3773
|
+
.fronius-read-editor .pr-field-list {
|
|
3774
|
+
|
|
3775
|
+
max-height: 320px;
|
|
3776
|
+
|
|
3777
|
+
overflow: auto;
|
|
3778
|
+
|
|
3779
|
+
padding: 12px;
|
|
3780
|
+
|
|
3781
|
+
border: 1px solid var(--pr-border);
|
|
3782
|
+
|
|
3783
|
+
border-radius: 10px;
|
|
3784
|
+
|
|
3785
|
+
background: #fff;
|
|
3786
|
+
|
|
3787
|
+
}
|
|
3788
|
+
|
|
3789
|
+
|
|
3790
|
+
.fronius-read-editor .pr-field-group {
|
|
3791
|
+
|
|
3792
|
+
margin-bottom: 14px;
|
|
3793
|
+
|
|
3794
|
+
}
|
|
3795
|
+
|
|
3796
|
+
|
|
3797
|
+
.fronius-read-editor .pr-field-group:last-child {
|
|
3798
|
+
|
|
3799
|
+
margin-bottom: 0;
|
|
3800
|
+
|
|
3801
|
+
}
|
|
3802
|
+
|
|
3803
|
+
|
|
3804
|
+
.fronius-read-editor .pr-field-group-title {
|
|
3805
|
+
|
|
3806
|
+
margin: 0 0 8px;
|
|
3807
|
+
|
|
3808
|
+
font-size: 12px;
|
|
3809
|
+
|
|
3810
|
+
font-weight: 700;
|
|
3811
|
+
|
|
3812
|
+
text-transform: uppercase;
|
|
3813
|
+
|
|
3814
|
+
letter-spacing: 0.03em;
|
|
3815
|
+
|
|
3816
|
+
color: #344054;
|
|
3817
|
+
|
|
3818
|
+
}
|
|
3819
|
+
|
|
3820
|
+
|
|
3821
|
+
.fronius-read-editor .pr-field-group-grid {
|
|
3822
|
+
|
|
3823
|
+
display: grid;
|
|
3824
|
+
|
|
3825
|
+
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
|
|
3826
|
+
|
|
3827
|
+
gap: 8px 16px;
|
|
3828
|
+
|
|
3829
|
+
}
|
|
3830
|
+
|
|
3831
|
+
|
|
3832
|
+
.fronius-read-editor .pr-field-item {
|
|
3833
|
+
|
|
3834
|
+
display: flex;
|
|
3835
|
+
|
|
3836
|
+
align-items: center;
|
|
3837
|
+
|
|
3838
|
+
gap: 8px;
|
|
3839
|
+
|
|
3840
|
+
margin: 0;
|
|
3841
|
+
|
|
3842
|
+
line-height: 1.35;
|
|
3843
|
+
|
|
3844
|
+
font-weight: 400;
|
|
3845
|
+
|
|
3846
|
+
cursor: pointer;
|
|
3847
|
+
|
|
3848
|
+
}
|
|
3849
|
+
|
|
3850
|
+
|
|
3851
|
+
.fronius-read-editor .pr-field-item > input[type="checkbox"] {
|
|
3852
|
+
|
|
3853
|
+
width: auto;
|
|
3854
|
+
|
|
3855
|
+
margin: 0;
|
|
3856
|
+
|
|
3857
|
+
flex: 0 0 auto;
|
|
3858
|
+
|
|
3859
|
+
}
|
|
3860
|
+
|
|
3861
|
+
|
|
3862
|
+
.fronius-read-editor .button.disabled {
|
|
3863
|
+
|
|
3864
|
+
pointer-events: none;
|
|
3865
|
+
|
|
3866
|
+
opacity: 0.5;
|
|
3867
|
+
|
|
3868
|
+
}
|
|
3869
|
+
|
|
3870
|
+
|
|
3871
|
+
.fronius-read-editor .pr-checkbox-row > input[type="checkbox"] {
|
|
3872
|
+
|
|
3873
|
+
display: inline-block;
|
|
3874
|
+
|
|
3875
|
+
width: auto;
|
|
3876
|
+
|
|
3877
|
+
vertical-align: top;
|
|
3878
|
+
|
|
3879
|
+
}
|
|
3880
|
+
|
|
3881
|
+
|
|
3882
|
+
.fronius-read-editor .pr-inline-note {
|
|
3883
|
+
|
|
3884
|
+
margin-left: 8px;
|
|
3885
|
+
|
|
3886
|
+
color: var(--pr-muted);
|
|
3887
|
+
|
|
3888
|
+
line-height: 1.4;
|
|
3889
|
+
|
|
3890
|
+
}
|
|
3891
|
+
|
|
3892
|
+
|
|
3893
|
+
.fronius-probe-row {
|
|
3894
|
+
|
|
3895
|
+
margin-top: 4px;
|
|
3896
|
+
|
|
3897
|
+
}
|
|
3898
|
+
|
|
3899
|
+
|
|
3900
|
+
.fronius-probe-info,
|
|
3901
|
+
|
|
3902
|
+
.fronius-meta-info {
|
|
3903
|
+
|
|
3904
|
+
color: var(--pr-muted);
|
|
3905
|
+
|
|
3906
|
+
line-height: 1.45;
|
|
3907
|
+
|
|
3908
|
+
padding-top: 2px;
|
|
3909
|
+
|
|
3910
|
+
}
|
|
3911
|
+
|
|
3912
|
+
|
|
3913
|
+
.fronius-meta-row {
|
|
3914
|
+
|
|
3915
|
+
margin-top: 0;
|
|
3916
|
+
|
|
3917
|
+
margin-bottom: 8px;
|
|
3918
|
+
|
|
3919
|
+
}
|
|
3920
|
+
|
|
3921
|
+
|
|
3922
|
+
.fronius-multiselect-empty {
|
|
3923
|
+
|
|
3924
|
+
padding: 8px 12px;
|
|
3925
|
+
|
|
3926
|
+
color: #999;
|
|
3927
|
+
|
|
3928
|
+
font-style: italic;
|
|
3929
|
+
|
|
3930
|
+
}
|
|
3931
|
+
|
|
3932
|
+
|
|
3933
|
+
@media (max-width: 1100px) {
|
|
3934
|
+
|
|
3935
|
+
.fronius-read-editor .pr-grid-2 {
|
|
3936
|
+
|
|
3937
|
+
grid-template-columns: 1fr;
|
|
3938
|
+
|
|
3939
|
+
}
|
|
3940
|
+
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
</style>
|
|
3944
|
+
|