node-red-contrib-symi-mesh 1.6.8 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +297 -48
- package/nodes/symi-485-bridge.html +206 -32
- package/nodes/symi-485-bridge.js +162 -48
- package/nodes/symi-knx-bridge.js +1 -1
- package/nodes/symi-knx-ha-bridge.html +370 -0
- package/nodes/symi-knx-ha-bridge.js +524 -0
- package/package.json +3 -2
|
@@ -160,9 +160,11 @@
|
|
|
160
160
|
|
|
161
161
|
mappings.forEach(function(m, idx) {
|
|
162
162
|
var row = $('<div class="mapping-row" data-idx="' + idx + '" style="flex-wrap:wrap;"></div>');
|
|
163
|
-
//
|
|
163
|
+
// 地址输入框:杜亚2字节地址,自定义模式隐藏,其他显示
|
|
164
164
|
var addrHtml = '';
|
|
165
|
-
if (m.brand === '
|
|
165
|
+
if (m.brand === 'custom') {
|
|
166
|
+
addrHtml = '<div class="addr-col" style="width:60px;visibility:hidden;"></div>';
|
|
167
|
+
} else if (m.brand === 'duya') {
|
|
166
168
|
addrHtml = '<div class="addr-col duya-addr" style="display:flex;gap:2px;">' +
|
|
167
169
|
'<input type="number" class="addr-high" value="' + (m.addrHigh || 1) + '" min="0" max="255" style="width:40px;" title="地址高字节" placeholder="高">' +
|
|
168
170
|
'<input type="number" class="addr-low" value="' + (m.addrLow || 1) + '" min="0" max="255" style="width:40px;" title="地址低字节" placeholder="低">' +
|
|
@@ -279,33 +281,88 @@
|
|
|
279
281
|
renderMappings();
|
|
280
282
|
});
|
|
281
283
|
|
|
282
|
-
// 自定义码输入事件
|
|
283
|
-
container.find('.custom-
|
|
284
|
+
// 自定义码输入事件 - 开关
|
|
285
|
+
container.find('.custom-send-on').off('change').on('change', function() {
|
|
284
286
|
var idx = $(this).closest('.mapping-row').data('idx');
|
|
285
287
|
mappings[idx].customCodes = mappings[idx].customCodes || {};
|
|
286
|
-
mappings[idx].customCodes.
|
|
288
|
+
mappings[idx].customCodes.sendOn = $(this).val();
|
|
287
289
|
});
|
|
288
|
-
container.find('.custom-
|
|
290
|
+
container.find('.custom-send-off').off('change').on('change', function() {
|
|
289
291
|
var idx = $(this).closest('.mapping-row').data('idx');
|
|
290
292
|
mappings[idx].customCodes = mappings[idx].customCodes || {};
|
|
291
|
-
mappings[idx].customCodes.
|
|
293
|
+
mappings[idx].customCodes.sendOff = $(this).val();
|
|
292
294
|
});
|
|
293
|
-
container.find('.custom-
|
|
295
|
+
container.find('.custom-recv-on').off('change').on('change', function() {
|
|
294
296
|
var idx = $(this).closest('.mapping-row').data('idx');
|
|
295
297
|
mappings[idx].customCodes = mappings[idx].customCodes || {};
|
|
296
|
-
mappings[idx].customCodes.
|
|
298
|
+
mappings[idx].customCodes.recvOn = $(this).val();
|
|
297
299
|
});
|
|
298
|
-
container.find('.custom-
|
|
300
|
+
container.find('.custom-recv-off').off('change').on('change', function() {
|
|
299
301
|
var idx = $(this).closest('.mapping-row').data('idx');
|
|
300
302
|
mappings[idx].customCodes = mappings[idx].customCodes || {};
|
|
301
|
-
mappings[idx].customCodes.
|
|
303
|
+
mappings[idx].customCodes.recvOff = $(this).val();
|
|
302
304
|
});
|
|
303
|
-
|
|
305
|
+
// 窗帘码
|
|
306
|
+
container.find('.custom-send-open, .custom-send-close, .custom-send-stop, .custom-recv-open, .custom-recv-close, .custom-recv-stop').off('change').on('change', function() {
|
|
304
307
|
var idx = $(this).closest('.mapping-row').data('idx');
|
|
305
308
|
mappings[idx].customCodes = mappings[idx].customCodes || {};
|
|
306
|
-
mappings[idx].customCodes.
|
|
309
|
+
if ($(this).hasClass('custom-send-open')) mappings[idx].customCodes.sendOpen = $(this).val();
|
|
310
|
+
if ($(this).hasClass('custom-send-close')) mappings[idx].customCodes.sendClose = $(this).val();
|
|
311
|
+
if ($(this).hasClass('custom-send-stop')) mappings[idx].customCodes.sendStop = $(this).val();
|
|
312
|
+
if ($(this).hasClass('custom-recv-open')) mappings[idx].customCodes.recvOpen = $(this).val();
|
|
313
|
+
if ($(this).hasClass('custom-recv-close')) mappings[idx].customCodes.recvClose = $(this).val();
|
|
314
|
+
if ($(this).hasClass('custom-recv-stop')) mappings[idx].customCodes.recvStop = $(this).val();
|
|
307
315
|
});
|
|
308
|
-
|
|
316
|
+
// 空调码
|
|
317
|
+
container.find('[class^="custom-ac-"], [class^="custom-fan-"], [class^="custom-mode-"], [class^="custom-temp-"]').off('change').on('change', function() {
|
|
318
|
+
var idx = $(this).closest('.mapping-row').data('idx');
|
|
319
|
+
mappings[idx].customCodes = mappings[idx].customCodes || {};
|
|
320
|
+
var cls = $(this).attr('class').split(' ')[0];
|
|
321
|
+
|
|
322
|
+
// 处理空调开关、风速、模式
|
|
323
|
+
if (cls.includes('ac-send-on')) mappings[idx].customCodes.acSendOn = $(this).val();
|
|
324
|
+
else if (cls.includes('ac-send-off')) mappings[idx].customCodes.acSendOff = $(this).val();
|
|
325
|
+
else if (cls.includes('ac-recv-on')) mappings[idx].customCodes.acRecvOn = $(this).val();
|
|
326
|
+
else if (cls.includes('ac-recv-off')) mappings[idx].customCodes.acRecvOff = $(this).val();
|
|
327
|
+
else if (cls.includes('fan-send-high')) mappings[idx].customCodes.fanSendHigh = $(this).val();
|
|
328
|
+
else if (cls.includes('fan-send-mid')) mappings[idx].customCodes.fanSendMid = $(this).val();
|
|
329
|
+
else if (cls.includes('fan-send-low')) mappings[idx].customCodes.fanSendLow = $(this).val();
|
|
330
|
+
else if (cls.includes('fan-recv-high')) mappings[idx].customCodes.fanRecvHigh = $(this).val();
|
|
331
|
+
else if (cls.includes('fan-recv-mid')) mappings[idx].customCodes.fanRecvMid = $(this).val();
|
|
332
|
+
else if (cls.includes('fan-recv-low')) mappings[idx].customCodes.fanRecvLow = $(this).val();
|
|
333
|
+
else if (cls.includes('mode-send-cool')) mappings[idx].customCodes.modeSendCool = $(this).val();
|
|
334
|
+
else if (cls.includes('mode-send-heat')) mappings[idx].customCodes.modeSendHeat = $(this).val();
|
|
335
|
+
else if (cls.includes('mode-send-dry')) mappings[idx].customCodes.modeSendDry = $(this).val();
|
|
336
|
+
else if (cls.includes('mode-send-fan')) mappings[idx].customCodes.modeSendFan = $(this).val();
|
|
337
|
+
else if (cls.includes('mode-recv-cool')) mappings[idx].customCodes.modeRecvCool = $(this).val();
|
|
338
|
+
else if (cls.includes('mode-recv-heat')) mappings[idx].customCodes.modeRecvHeat = $(this).val();
|
|
339
|
+
else if (cls.includes('mode-recv-dry')) mappings[idx].customCodes.modeRecvDry = $(this).val();
|
|
340
|
+
else if (cls.includes('mode-recv-fan')) mappings[idx].customCodes.modeRecvFan = $(this).val();
|
|
341
|
+
|
|
342
|
+
// 处理 16-30 度独立温度码
|
|
343
|
+
else if (cls.startsWith('custom-temp-')) {
|
|
344
|
+
// 提取 key, 如 tempSendCool16
|
|
345
|
+
var parts = cls.split('-'); // ["custom", "temp", "send", "cool", "16"]
|
|
346
|
+
if (parts.length === 5) {
|
|
347
|
+
var type = parts[2]; // send/recv
|
|
348
|
+
var mode = parts[3]; // cool/heat
|
|
349
|
+
var temp = parts[4]; // 16-30
|
|
350
|
+
var key = 'temp' + type.charAt(0).toUpperCase() + type.slice(1) +
|
|
351
|
+
mode.charAt(0).toUpperCase() + mode.slice(1) + temp;
|
|
352
|
+
mappings[idx].customCodes[key] = $(this).val();
|
|
353
|
+
} else {
|
|
354
|
+
// 兼容旧的占位符模式
|
|
355
|
+
if (cls.includes('temp-send-cool')) mappings[idx].customCodes.tempSendCool = $(this).val();
|
|
356
|
+
else if (cls.includes('temp-recv-cool')) mappings[idx].customCodes.tempRecvCool = $(this).val();
|
|
357
|
+
else if (cls.includes('temp-send-heat')) mappings[idx].customCodes.tempSendHeat = $(this).val();
|
|
358
|
+
else if (cls.includes('temp-recv-heat')) mappings[idx].customCodes.tempRecvHeat = $(this).val();
|
|
359
|
+
else if (cls.includes('temp-send')) mappings[idx].customCodes.tempSend = $(this).val();
|
|
360
|
+
else if (cls.includes('temp-recv')) mappings[idx].customCodes.tempRecv = $(this).val();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
// 场景码
|
|
365
|
+
container.find('.custom-trigger').off('change').on('change', function() {
|
|
309
366
|
var idx = $(this).closest('.mapping-row').data('idx');
|
|
310
367
|
mappings[idx].customCodes = mappings[idx].customCodes || {};
|
|
311
368
|
mappings[idx].customCodes.trigger = $(this).val();
|
|
@@ -322,15 +379,79 @@
|
|
|
322
379
|
html += '<div style="font-size:11px;color:#f57c00;margin-bottom:6px;"><i class="fa fa-code"></i> 自定义RS485码(十六进制,如: 55 01 01 03 01 B9 00)</div>';
|
|
323
380
|
|
|
324
381
|
if (deviceId === 'custom_switch') {
|
|
325
|
-
html += '<div style="display:
|
|
326
|
-
html += '<label style="font-size:11px;"
|
|
327
|
-
html += '<label style="font-size:11px;"
|
|
382
|
+
html += '<div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;">';
|
|
383
|
+
html += '<label style="font-size:11px;">发开码: <input type="text" class="custom-code-send-on" value="' + (codes.sendOn || '') + '" placeholder="01 20 10 14 00 01 00 7F..." maxlength="72" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:10px;font-family:monospace;"></label>';
|
|
384
|
+
html += '<label style="font-size:11px;">发关码: <input type="text" class="custom-code-send-off" value="' + (codes.sendOff || '') + '" placeholder="01 20 10 14 00 01 00 FF..." maxlength="72" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:10px;font-family:monospace;"></label>';
|
|
385
|
+
html += '<label style="font-size:11px;">收开码: <input type="text" class="custom-code-recv-on" value="' + (codes.recvOn || '') + '" placeholder="01 20..." maxlength="72" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:10px;font-family:monospace;"></label>';
|
|
386
|
+
html += '<label style="font-size:11px;">收关码: <input type="text" class="custom-code-recv-off" value="' + (codes.recvOff || '') + '" placeholder="01 20..." maxlength="72" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:10px;font-family:monospace;"></label>';
|
|
328
387
|
html += '</div>';
|
|
388
|
+
html += '<div style="font-size:10px;color:#666;margin-top:4px;">提示:收开码=收关码时,收到后翻转开关状态</div>';
|
|
329
389
|
} else if (deviceId === 'custom_curtain') {
|
|
330
|
-
html += '<div style="display:
|
|
331
|
-
html += '<label style="font-size:11px;"
|
|
332
|
-
html += '<label style="font-size:11px;"
|
|
333
|
-
html += '<label style="font-size:11px;"
|
|
390
|
+
html += '<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;">';
|
|
391
|
+
html += '<label style="font-size:11px;">发开码: <input type="text" class="custom-code-send-open" value="' + (codes.sendOpen || '') + '" placeholder="55 02 02 03 01..." maxlength="72" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:10px;font-family:monospace;"></label>';
|
|
392
|
+
html += '<label style="font-size:11px;">发关码: <input type="text" class="custom-code-send-close" value="' + (codes.sendClose || '') + '" placeholder="55 02 02 03 02..." maxlength="72" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:10px;font-family:monospace;"></label>';
|
|
393
|
+
html += '<label style="font-size:11px;">发停码: <input type="text" class="custom-code-send-stop" value="' + (codes.sendStop || '') + '" placeholder="55 02 02 03 03..." maxlength="72" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:10px;font-family:monospace;"></label>';
|
|
394
|
+
html += '<label style="font-size:11px;">收开码: <input type="text" class="custom-code-recv-open" value="' + (codes.recvOpen || '') + '" placeholder="01 20..." maxlength="72" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:10px;font-family:monospace;"></label>';
|
|
395
|
+
html += '<label style="font-size:11px;">收关码: <input type="text" class="custom-code-recv-close" value="' + (codes.recvClose || '') + '" placeholder="01 20..." maxlength="72" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:10px;font-family:monospace;"></label>';
|
|
396
|
+
html += '<label style="font-size:11px;">收停码: <input type="text" class="custom-code-recv-stop" value="' + (codes.recvStop || '') + '" placeholder="01 20..." maxlength="72" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:10px;font-family:monospace;"></label>';
|
|
397
|
+
html += '</div>';
|
|
398
|
+
} else if (deviceId === 'custom_climate') {
|
|
399
|
+
html += '<div style="font-size:10px;color:#f57c00;margin-bottom:4px;">开关控制</div>';
|
|
400
|
+
html += '<div style="display:grid;grid-template-columns:1fr 1fr;gap:4px;margin-bottom:6px;">';
|
|
401
|
+
html += '<label style="font-size:10px;">发开码: <input type="text" class="custom-ac-send-on" value="' + (codes.acSendOn || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
402
|
+
html += '<label style="font-size:10px;">发关码: <input type="text" class="custom-ac-send-off" value="' + (codes.acSendOff || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
403
|
+
html += '<label style="font-size:10px;">收开码: <input type="text" class="custom-ac-recv-on" value="' + (codes.acRecvOn || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
404
|
+
html += '<label style="font-size:10px;">收关码: <input type="text" class="custom-ac-recv-off" value="' + (codes.acRecvOff || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
405
|
+
html += '</div>';
|
|
406
|
+
|
|
407
|
+
html += '<div style="font-size:10px;color:#f57c00;margin-bottom:4px;">风速控制</div>';
|
|
408
|
+
html += '<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:4px;margin-bottom:6px;">';
|
|
409
|
+
html += '<label style="font-size:10px;">发高风: <input type="text" class="custom-fan-send-high" value="' + (codes.fanSendHigh || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
410
|
+
html += '<label style="font-size:10px;">发中风: <input type="text" class="custom-fan-send-mid" value="' + (codes.fanSendMid || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
411
|
+
html += '<label style="font-size:10px;">发低风: <input type="text" class="custom-fan-send-low" value="' + (codes.fanSendLow || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
412
|
+
html += '<label style="font-size:10px;">收高风: <input type="text" class="custom-fan-recv-high" value="' + (codes.fanRecvHigh || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
413
|
+
html += '<label style="font-size:10px;">收中风: <input type="text" class="custom-fan-recv-mid" value="' + (codes.fanRecvMid || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
414
|
+
html += '<label style="font-size:10px;">收低风: <input type="text" class="custom-fan-recv-low" value="' + (codes.fanRecvLow || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
415
|
+
html += '</div>';
|
|
416
|
+
|
|
417
|
+
html += '<div style="font-size:10px;color:#f57c00;margin-bottom:4px;">模式控制</div>';
|
|
418
|
+
html += '<div style="display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:4px;margin-bottom:6px;">';
|
|
419
|
+
html += '<label style="font-size:10px;">发制冷: <input type="text" class="custom-mode-send-cool" value="' + (codes.modeSendCool || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
420
|
+
html += '<label style="font-size:10px;">发制热: <input type="text" class="custom-mode-send-heat" value="' + (codes.modeSendHeat || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
421
|
+
html += '<label style="font-size:10px;">发除湿: <input type="text" class="custom-mode-send-dry" value="' + (codes.modeSendDry || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
422
|
+
html += '<label style="font-size:10px;">发送风: <input type="text" class="custom-mode-send-fan" value="' + (codes.modeSendFan || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
423
|
+
html += '<label style="font-size:10px;">收制冷: <input type="text" class="custom-mode-recv-cool" value="' + (codes.modeRecvCool || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
424
|
+
html += '<label style="font-size:10px;">收制热: <input type="text" class="custom-mode-recv-heat" value="' + (codes.modeRecvHeat || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
425
|
+
html += '<label style="font-size:10px;">收除湿: <input type="text" class="custom-mode-recv-dry" value="' + (codes.modeRecvDry || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
426
|
+
html += '<label style="font-size:10px;">收送风: <input type="text" class="custom-mode-recv-fan" value="' + (codes.modeRecvFan || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
427
|
+
html += '</div>';
|
|
428
|
+
|
|
429
|
+
html += '<div style="font-size:10px;color:#f57c00;margin-bottom:4px;margin-top:4px;">制冷温度发码 (16-30度)</div>';
|
|
430
|
+
html += '<div style="display:grid;grid-template-columns:repeat(5, 1fr);gap:4px;margin-bottom:6px;">';
|
|
431
|
+
for (var t=16; t<=30; t++) {
|
|
432
|
+
html += '<label style="font-size:9px;">' + t + '°C: <input type="text" class="custom-temp-send-cool-' + t + '" value="' + (codes['tempSendCool'+t] || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
433
|
+
}
|
|
434
|
+
html += '</div>';
|
|
435
|
+
|
|
436
|
+
html += '<div style="font-size:10px;color:#f57c00;margin-bottom:4px;">制冷温度收码 (16-30度)</div>';
|
|
437
|
+
html += '<div style="display:grid;grid-template-columns:repeat(5, 1fr);gap:4px;margin-bottom:6px;">';
|
|
438
|
+
for (var t=16; t<=30; t++) {
|
|
439
|
+
html += '<label style="font-size:9px;">' + t + '°C: <input type="text" class="custom-temp-recv-cool-' + t + '" value="' + (codes['tempRecvCool'+t] || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
440
|
+
}
|
|
441
|
+
html += '</div>';
|
|
442
|
+
|
|
443
|
+
html += '<div style="font-size:10px;color:#f57c00;margin-bottom:4px;">制热温度发码 (16-30度)</div>';
|
|
444
|
+
html += '<div style="display:grid;grid-template-columns:repeat(5, 1fr);gap:4px;margin-bottom:6px;">';
|
|
445
|
+
for (var t=16; t<=30; t++) {
|
|
446
|
+
html += '<label style="font-size:9px;">' + t + '°C: <input type="text" class="custom-temp-send-heat-' + t + '" value="' + (codes['tempSendHeat'+t] || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
447
|
+
}
|
|
448
|
+
html += '</div>';
|
|
449
|
+
|
|
450
|
+
html += '<div style="font-size:10px;color:#f57c00;margin-bottom:4px;">制热温度收码 (16-30度)</div>';
|
|
451
|
+
html += '<div style="display:grid;grid-template-columns:repeat(5, 1fr);gap:4px;margin-bottom:6px;">';
|
|
452
|
+
for (var t=16; t<=30; t++) {
|
|
453
|
+
html += '<label style="font-size:9px;">' + t + '°C: <input type="text" class="custom-temp-recv-heat-' + t + '" value="' + (codes['tempRecvHeat'+t] || '') + '" placeholder="" maxlength="128" style="width:100%;padding:2px 4px;border:1px solid #ffb74d;border-radius:2px;font-size:9px;font-family:monospace;"></label>';
|
|
454
|
+
}
|
|
334
455
|
html += '</div>';
|
|
335
456
|
} else if (deviceId === 'custom_scene') {
|
|
336
457
|
html += '<div style="display:flex;gap:8px;">';
|
|
@@ -374,18 +495,71 @@
|
|
|
374
495
|
}
|
|
375
496
|
// 保存自定义码
|
|
376
497
|
if (m.brand === 'custom') {
|
|
498
|
+
var row = $(this);
|
|
377
499
|
m.customCodes = {};
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
var
|
|
381
|
-
var
|
|
382
|
-
var
|
|
383
|
-
var
|
|
384
|
-
|
|
385
|
-
if (
|
|
386
|
-
if (
|
|
387
|
-
if (
|
|
388
|
-
if (
|
|
500
|
+
|
|
501
|
+
// 通用/开关
|
|
502
|
+
var sendOn = row.find('.custom-code-send-on').val() || row.find('.custom-ac-send-on').val() || row.find('.custom-send-on').val();
|
|
503
|
+
var sendOff = row.find('.custom-code-send-off').val() || row.find('.custom-ac-send-off').val() || row.find('.custom-send-off').val();
|
|
504
|
+
var recvOn = row.find('.custom-code-recv-on').val() || row.find('.custom-ac-recv-on').val() || row.find('.custom-recv-on').val();
|
|
505
|
+
var recvOff = row.find('.custom-code-recv-off').val() || row.find('.custom-ac-recv-off').val() || row.find('.custom-recv-off').val();
|
|
506
|
+
|
|
507
|
+
if (sendOn) m.customCodes.sendOn = sendOn;
|
|
508
|
+
if (sendOff) m.customCodes.sendOff = sendOff;
|
|
509
|
+
if (recvOn) m.customCodes.recvOn = recvOn;
|
|
510
|
+
if (recvOff) m.customCodes.recvOff = recvOff;
|
|
511
|
+
|
|
512
|
+
// 兼容旧字段名 (空调开关)
|
|
513
|
+
if (sendOn) m.customCodes.acSendOn = sendOn;
|
|
514
|
+
if (sendOff) m.customCodes.acSendOff = sendOff;
|
|
515
|
+
if (recvOn) m.customCodes.acRecvOn = recvOn;
|
|
516
|
+
if (recvOff) m.customCodes.acRecvOff = recvOff;
|
|
517
|
+
|
|
518
|
+
// 窗帘
|
|
519
|
+
var sendOpen = row.find('.custom-code-send-open').val() || row.find('.custom-send-open').val();
|
|
520
|
+
var sendClose = row.find('.custom-code-send-close').val() || row.find('.custom-send-close').val();
|
|
521
|
+
var sendStop = row.find('.custom-code-send-stop').val() || row.find('.custom-send-stop').val();
|
|
522
|
+
var recvOpen = row.find('.custom-code-recv-open').val() || row.find('.custom-recv-open').val();
|
|
523
|
+
var recvClose = row.find('.custom-code-recv-close').val() || row.find('.custom-recv-close').val();
|
|
524
|
+
var recvStop = row.find('.custom-code-recv-stop').val() || row.find('.custom-recv-stop').val();
|
|
525
|
+
|
|
526
|
+
if (sendOpen) m.customCodes.sendOpen = sendOpen;
|
|
527
|
+
if (sendClose) m.customCodes.sendClose = sendClose;
|
|
528
|
+
if (sendStop) m.customCodes.sendStop = sendStop;
|
|
529
|
+
if (recvOpen) m.customCodes.recvOpen = recvOpen;
|
|
530
|
+
if (recvClose) m.customCodes.recvClose = recvClose;
|
|
531
|
+
if (recvStop) m.customCodes.recvStop = recvStop;
|
|
532
|
+
|
|
533
|
+
// 动态提取所有空调相关的自定义码 (ac-, fan-, mode-, temp-)
|
|
534
|
+
row.find('[class^="custom-ac-"], [class^="custom-fan-"], [class^="custom-mode-"], [class^="custom-temp-"]').each(function() {
|
|
535
|
+
var cls = $(this).attr('class').split(' ')[0];
|
|
536
|
+
var val = $(this).val();
|
|
537
|
+
if (!val) return;
|
|
538
|
+
|
|
539
|
+
if (cls.startsWith('custom-temp-')) {
|
|
540
|
+
var parts = cls.split('-');
|
|
541
|
+
if (parts.length === 5) {
|
|
542
|
+
// 独立温度码: custom-temp-send-cool-16
|
|
543
|
+
var type = parts[2];
|
|
544
|
+
var mode = parts[3];
|
|
545
|
+
var temp = parts[4];
|
|
546
|
+
var key = 'temp' + type.charAt(0).toUpperCase() + type.slice(1) +
|
|
547
|
+
mode.charAt(0).toUpperCase() + mode.slice(1) + temp;
|
|
548
|
+
m.customCodes[key] = val;
|
|
549
|
+
} else {
|
|
550
|
+
// 模板码: custom-temp-send-cool
|
|
551
|
+
var key = cls.replace('custom-', '').replace(/-([a-z])/g, function(g) { return g[1].toUpperCase(); });
|
|
552
|
+
m.customCodes[key] = val;
|
|
553
|
+
}
|
|
554
|
+
} else {
|
|
555
|
+
// 其他码: custom-ac-send-on -> acSendOn
|
|
556
|
+
var key = cls.replace('custom-', '').replace(/-([a-z])/g, function(g) { return g[1].toUpperCase(); });
|
|
557
|
+
m.customCodes[key] = val;
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
// 场景
|
|
562
|
+
var trigger = row.find('.custom-code-trigger').val() || row.find('.custom-trigger').val();
|
|
389
563
|
if (trigger) m.customCodes.trigger = trigger;
|
|
390
564
|
}
|
|
391
565
|
mappings.push(m);
|
package/nodes/symi-485-bridge.js
CHANGED
|
@@ -309,7 +309,11 @@ module.exports = function(RED) {
|
|
|
309
309
|
name: '自定义窗帘',
|
|
310
310
|
type: 'cover',
|
|
311
311
|
customMode: true,
|
|
312
|
-
|
|
312
|
+
},
|
|
313
|
+
'custom_climate': {
|
|
314
|
+
name: '自定义空调',
|
|
315
|
+
type: 'climate',
|
|
316
|
+
customMode: true,
|
|
313
317
|
},
|
|
314
318
|
'custom_scene': {
|
|
315
319
|
name: '自定义场景',
|
|
@@ -526,7 +530,7 @@ module.exports = function(RED) {
|
|
|
526
530
|
setTimeout(() => {
|
|
527
531
|
node.initializing = false;
|
|
528
532
|
node.log('[RS485 Bridge] 初始化完成,开始同步');
|
|
529
|
-
},
|
|
533
|
+
}, 10000); // 10秒初始化延迟
|
|
530
534
|
|
|
531
535
|
// Mesh设备状态变化处理(事件驱动)
|
|
532
536
|
const handleMeshStateChange = (eventData) => {
|
|
@@ -708,13 +712,12 @@ module.exports = function(RED) {
|
|
|
708
712
|
}).catch(err => {
|
|
709
713
|
node.error(`[Mesh->杜亚] 位置同步失败: ${err.message}`);
|
|
710
714
|
});
|
|
711
|
-
}, 100);
|
|
715
|
+
}, 100);
|
|
712
716
|
}
|
|
713
717
|
continue;
|
|
714
718
|
}
|
|
715
719
|
|
|
716
720
|
// 【自定义窗帘】处理Mesh面板控制同步到485(逻辑同杜亚)
|
|
717
|
-
// 必须检查isUserControl,只有NODE_ACK(subOpcode=0x05)才是用户控制
|
|
718
721
|
if (mapping.brand === 'custom' && mapping.device === 'custom_curtain' && mapping.customCodes) {
|
|
719
722
|
const now = Date.now();
|
|
720
723
|
const curtainKey = `custom_curtain_${mac}`;
|
|
@@ -1169,8 +1172,8 @@ module.exports = function(RED) {
|
|
|
1169
1172
|
// 开关类型
|
|
1170
1173
|
if (mapping.device === 'custom_switch') {
|
|
1171
1174
|
for (const [key, value] of Object.entries(state)) {
|
|
1172
|
-
if (key === 'switch' || key === 'acSwitch') {
|
|
1173
|
-
const hexCode = value ? codes.
|
|
1175
|
+
if (key === 'switch' || key === 'acSwitch' || key.startsWith('switch_')) {
|
|
1176
|
+
const hexCode = value ? codes.sendOn : codes.sendOff;
|
|
1174
1177
|
if (hexCode) {
|
|
1175
1178
|
await node.sendCustomCode(hexCode);
|
|
1176
1179
|
node.log(`[Mesh->自定义] 开关: ${value ? '开' : '关'}, 发送: ${hexCode}`);
|
|
@@ -1190,41 +1193,29 @@ module.exports = function(RED) {
|
|
|
1190
1193
|
// 1. 优先检查动作命令
|
|
1191
1194
|
if (state.curtainAction !== undefined || state.action !== undefined) {
|
|
1192
1195
|
const action = state.curtainAction || state.action;
|
|
1193
|
-
if (action === 1 || action === 'open') {
|
|
1194
|
-
hexCode = codes.
|
|
1196
|
+
if (action === 1 || action === 'open' || action === 'opening') {
|
|
1197
|
+
hexCode = codes.sendOpen;
|
|
1195
1198
|
actionName = '打开';
|
|
1196
|
-
} else if (action === 2 || action === 'close') {
|
|
1197
|
-
hexCode = codes.
|
|
1199
|
+
} else if (action === 2 || action === 'close' || action === 'closing') {
|
|
1200
|
+
hexCode = codes.sendClose;
|
|
1198
1201
|
actionName = '关闭';
|
|
1199
|
-
} else if (action === 3 || action === 'stop') {
|
|
1200
|
-
hexCode = codes.
|
|
1202
|
+
} else if (action === 3 || action === 'stop' || action === 'stopped') {
|
|
1203
|
+
hexCode = codes.sendStop;
|
|
1201
1204
|
actionName = '停止';
|
|
1202
1205
|
}
|
|
1203
1206
|
}
|
|
1204
|
-
// 2. 其次检查运行状态
|
|
1205
1207
|
else if (state.curtainStatus !== undefined) {
|
|
1206
1208
|
if (state.curtainStatus === 1) {
|
|
1207
|
-
hexCode = codes.
|
|
1208
|
-
actionName = '打开
|
|
1209
|
+
hexCode = codes.sendOpen;
|
|
1210
|
+
actionName = '打开';
|
|
1209
1211
|
} else if (state.curtainStatus === 2) {
|
|
1210
|
-
hexCode = codes.
|
|
1211
|
-
actionName = '关闭
|
|
1212
|
-
} else if (state.curtainStatus === 0 && codes.
|
|
1213
|
-
|
|
1214
|
-
hexCode = codes.stop;
|
|
1212
|
+
hexCode = codes.sendClose;
|
|
1213
|
+
actionName = '关闭';
|
|
1214
|
+
} else if (state.curtainStatus === 0 && codes.sendStop) {
|
|
1215
|
+
hexCode = codes.sendStop;
|
|
1215
1216
|
actionName = '停止';
|
|
1216
1217
|
}
|
|
1217
1218
|
}
|
|
1218
|
-
// 3. 最后检查位置(仅在极端位置时)
|
|
1219
|
-
else if (state.curtainPosition !== undefined) {
|
|
1220
|
-
if (state.curtainPosition >= 95) {
|
|
1221
|
-
hexCode = codes.open;
|
|
1222
|
-
actionName = '打开(位置>=95)';
|
|
1223
|
-
} else if (state.curtainPosition <= 5) {
|
|
1224
|
-
hexCode = codes.close;
|
|
1225
|
-
actionName = '关闭(位置<=5)';
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
1219
|
|
|
1229
1220
|
if (hexCode) {
|
|
1230
1221
|
// 防抖:500ms内不重复发送相同命令
|
|
@@ -1240,6 +1231,51 @@ module.exports = function(RED) {
|
|
|
1240
1231
|
}
|
|
1241
1232
|
}
|
|
1242
1233
|
}
|
|
1234
|
+
// 空调类型
|
|
1235
|
+
else if (mapping.device === 'custom_climate') {
|
|
1236
|
+
for (const [key, value] of Object.entries(state)) {
|
|
1237
|
+
let hexCode = null;
|
|
1238
|
+
if (key === 'acSwitch' || key === 'climateSwitch') {
|
|
1239
|
+
hexCode = value ? codes.acSendOn : codes.acSendOff;
|
|
1240
|
+
}
|
|
1241
|
+
else if (key === 'acFanSpeed' || key === 'fanSpeed') {
|
|
1242
|
+
if (value === 1) hexCode = codes.fanSendHigh;
|
|
1243
|
+
else if (value === 2) hexCode = codes.fanSendMid;
|
|
1244
|
+
else if (value === 3) hexCode = codes.fanSendLow;
|
|
1245
|
+
}
|
|
1246
|
+
else if (key === 'acMode' || key === 'climateMode') {
|
|
1247
|
+
if (value === 1) hexCode = codes.modeSendCool;
|
|
1248
|
+
else if (value === 2) hexCode = codes.modeSendHeat;
|
|
1249
|
+
else if (value === 4) hexCode = codes.modeSendDry;
|
|
1250
|
+
else if (value === 3) hexCode = codes.modeSendFan;
|
|
1251
|
+
}
|
|
1252
|
+
else if (key === 'targetTemp' || key === 'acTargetTemp') {
|
|
1253
|
+
const temp = Math.round(value);
|
|
1254
|
+
const mode = state.acMode || state.climateMode || 1; // 1=Cool, 2=Heat, 3=Fan, 4=Dry
|
|
1255
|
+
|
|
1256
|
+
// 1. 优先尝试特定温度码,如 tempSendCool16
|
|
1257
|
+
const modeSuffix = (mode === 2) ? 'Heat' : 'Cool';
|
|
1258
|
+
const type = 'Send';
|
|
1259
|
+
const specificKey = 'temp' + type + modeSuffix + temp;
|
|
1260
|
+
hexCode = codes[specificKey];
|
|
1261
|
+
|
|
1262
|
+
// 2. 如果没有特定温度码,尝试模板
|
|
1263
|
+
if (!hexCode) {
|
|
1264
|
+
let template = (mode === 2) ? codes.tempSendHeat : codes.tempSendCool;
|
|
1265
|
+
if (!template) template = codes.tempSend; // 回退到通用模板
|
|
1266
|
+
|
|
1267
|
+
if (template && template.includes('{TEMP}')) {
|
|
1268
|
+
hexCode = template.replace('{TEMP}', temp.toString(16).toUpperCase().padStart(2, '0'));
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
if (hexCode) {
|
|
1274
|
+
await node.sendCustomCode(hexCode);
|
|
1275
|
+
node.log(`[Mesh->自定义] 空调 ${key}=${value}, 发送: ${hexCode}`);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1243
1279
|
// 场景类型
|
|
1244
1280
|
else if (mapping.device === 'custom_scene') {
|
|
1245
1281
|
if (state.trigger && codes.trigger) {
|
|
@@ -1795,32 +1831,110 @@ module.exports = function(RED) {
|
|
|
1795
1831
|
|
|
1796
1832
|
node.debug(`[自定义码检测] 检查映射: device=${mapping.device}, meshMac=${mapping.meshMac}, codes=${JSON.stringify(codes)}`);
|
|
1797
1833
|
|
|
1798
|
-
// 开关类型:匹配
|
|
1834
|
+
// 开关类型:匹配recvOn/recvOff
|
|
1799
1835
|
if (mapping.device === 'custom_switch') {
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1836
|
+
const recvOn = (codes.recvOn || '').replace(/\s/g, '').toUpperCase();
|
|
1837
|
+
const recvOff = (codes.recvOff || '').replace(/\s/g, '').toUpperCase();
|
|
1838
|
+
|
|
1839
|
+
// 翻转模式:收开码=收关码
|
|
1840
|
+
if (recvOn && recvOff && recvOn === recvOff && hexStr.includes(recvOn)) {
|
|
1841
|
+
const device = node.gateway.deviceManager.getDeviceByMac(mapping.meshMac);
|
|
1842
|
+
const currentState = device?.state?.switch || false;
|
|
1843
|
+
matchedAction = { switch: !currentState };
|
|
1844
|
+
node.log(`[自定义开关] 翻转: ${currentState} -> ${!currentState}`);
|
|
1845
|
+
} else {
|
|
1846
|
+
if (recvOn && hexStr.includes(recvOn)) {
|
|
1847
|
+
matchedAction = { switch: true };
|
|
1848
|
+
} else if (recvOff && hexStr.includes(recvOff)) {
|
|
1849
|
+
matchedAction = { switch: false };
|
|
1850
|
+
}
|
|
1804
1851
|
}
|
|
1805
1852
|
}
|
|
1806
|
-
// 窗帘类型:匹配
|
|
1853
|
+
// 窗帘类型:匹配recvOpen/recvClose/recvStop
|
|
1807
1854
|
else if (mapping.device === 'custom_curtain') {
|
|
1808
|
-
const
|
|
1809
|
-
const
|
|
1810
|
-
const
|
|
1811
|
-
node.debug(`[自定义窗帘匹配] 帧hex=${hexStr}, open=${openCode}, close=${closeCode}, stop=${stopCode}`);
|
|
1855
|
+
const recvOpen = (codes.recvOpen || '').replace(/\s/g, '').toUpperCase();
|
|
1856
|
+
const recvClose = (codes.recvClose || '').replace(/\s/g, '').toUpperCase();
|
|
1857
|
+
const recvStop = (codes.recvStop || '').replace(/\s/g, '').toUpperCase();
|
|
1812
1858
|
|
|
1813
|
-
if (
|
|
1859
|
+
if (recvOpen && hexStr.includes(recvOpen)) {
|
|
1814
1860
|
matchedAction = { action: 'open' };
|
|
1815
|
-
node.log(`[
|
|
1816
|
-
} else if (
|
|
1861
|
+
node.log(`[自定义窗帘] 收开码`);
|
|
1862
|
+
} else if (recvClose && hexStr.includes(recvClose)) {
|
|
1817
1863
|
matchedAction = { action: 'close' };
|
|
1818
|
-
node.log(`[
|
|
1819
|
-
} else if (
|
|
1864
|
+
node.log(`[自定义窗帘] 收关码`);
|
|
1865
|
+
} else if (recvStop && hexStr.includes(recvStop)) {
|
|
1820
1866
|
matchedAction = { action: 'stop' };
|
|
1821
|
-
node.log(`[
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1867
|
+
node.log(`[自定义窗帘] 收停码`);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
// 空调类型:匹配收码
|
|
1871
|
+
else if (mapping.device === 'custom_climate') {
|
|
1872
|
+
if (codes.acRecvOn && hexStr.includes(codes.acRecvOn.replace(/\s/g, '').toUpperCase())) {
|
|
1873
|
+
matchedAction = { acSwitch: true };
|
|
1874
|
+
} else if (codes.acRecvOff && hexStr.includes(codes.acRecvOff.replace(/\s/g, '').toUpperCase())) {
|
|
1875
|
+
matchedAction = { acSwitch: false };
|
|
1876
|
+
}
|
|
1877
|
+
else if (codes.fanRecvHigh && hexStr.includes(codes.fanRecvHigh.replace(/\s/g, '').toUpperCase())) {
|
|
1878
|
+
matchedAction = { acFanSpeed: 1 };
|
|
1879
|
+
} else if (codes.fanRecvMid && hexStr.includes(codes.fanRecvMid.replace(/\s/g, '').toUpperCase())) {
|
|
1880
|
+
matchedAction = { acFanSpeed: 2 };
|
|
1881
|
+
} else if (codes.fanRecvLow && hexStr.includes(codes.fanRecvLow.replace(/\s/g, '').toUpperCase())) {
|
|
1882
|
+
matchedAction = { acFanSpeed: 3 };
|
|
1883
|
+
}
|
|
1884
|
+
else if (codes.modeRecvCool && hexStr.includes(codes.modeRecvCool.replace(/\s/g, '').toUpperCase())) {
|
|
1885
|
+
for (const m of modes) {
|
|
1886
|
+
for (let t = 16; t <= 30; t++) {
|
|
1887
|
+
const key = `tempRecv${m.suffix}${t}`;
|
|
1888
|
+
const code = (codes[key] || '').replace(/\s/g, '').toUpperCase();
|
|
1889
|
+
if (code && hexStr.includes(code)) {
|
|
1890
|
+
matchedAction = { acTargetTemp: t, acMode: m.val };
|
|
1891
|
+
foundTemp = true;
|
|
1892
|
+
break;
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
if (foundTemp) break;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
// 2. 如果没匹配到独立码,匹配模板
|
|
1899
|
+
if (!foundTemp) {
|
|
1900
|
+
const tempTemplates = [
|
|
1901
|
+
{ template: codes.tempRecvCool, mode: 1 },
|
|
1902
|
+
{ template: codes.tempRecvHeat, mode: 2 },
|
|
1903
|
+
{ template: codes.tempRecv, mode: 0 } // 通用
|
|
1904
|
+
];
|
|
1905
|
+
|
|
1906
|
+
for (const item of tempTemplates) {
|
|
1907
|
+
if (item.template && item.template.includes('{TEMP}')) {
|
|
1908
|
+
const template = item.template.replace(/\s/g, '').toUpperCase();
|
|
1909
|
+
const parts = template.split('{TEMP}');
|
|
1910
|
+
if (parts.length === 2) {
|
|
1911
|
+
const prefix = parts[0];
|
|
1912
|
+
const suffix = parts[1];
|
|
1913
|
+
if (hexStr.includes(prefix)) {
|
|
1914
|
+
// 尝试从 hexStr 中提取温度
|
|
1915
|
+
// 简单起见,如果包含前缀且后面有2位十六进制+后缀
|
|
1916
|
+
const startIdx = hexStr.indexOf(prefix) + prefix.length;
|
|
1917
|
+
const tempHex = hexStr.substring(startIdx, startIdx + 2);
|
|
1918
|
+
const remaining = hexStr.substring(startIdx + 2);
|
|
1919
|
+
|
|
1920
|
+
if (tempHex.length === 2 && (!suffix || remaining.includes(suffix))) {
|
|
1921
|
+
const temp = parseInt(tempHex, 16);
|
|
1922
|
+
if (temp >= 16 && temp <= 30) {
|
|
1923
|
+
matchedAction = { acTargetTemp: temp };
|
|
1924
|
+
if (item.mode > 0) matchedAction.acMode = item.mode;
|
|
1925
|
+
foundTemp = true;
|
|
1926
|
+
break;
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
if (matchedAction) {
|
|
1937
|
+
node.log(`[自定义空调] 匹配: ${JSON.stringify(matchedAction)}`);
|
|
1824
1938
|
}
|
|
1825
1939
|
}
|
|
1826
1940
|
// 场景类型:匹配trigger
|
package/nodes/symi-knx-bridge.js
CHANGED
|
@@ -160,7 +160,7 @@ module.exports = function(RED) {
|
|
|
160
160
|
node.initTimer = setTimeout(() => {
|
|
161
161
|
node.initializing = false;
|
|
162
162
|
node.log('[KNX Bridge] 初始化完成,开始同步');
|
|
163
|
-
},
|
|
163
|
+
}, 10000); // 10秒初始化延迟
|
|
164
164
|
|
|
165
165
|
if (node.mappings.length === 0) {
|
|
166
166
|
node.status({ fill: 'grey', shape: 'ring', text: '请添加实体映射' });
|