node-red-contrib-symi-mesh 1.7.7 → 1.7.8
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 +90 -73
- package/nodes/symi-485-bridge.html +69 -13
- package/nodes/symi-ha-sync.html +451 -0
- package/nodes/symi-ha-sync.js +787 -0
- package/nodes/symi-mqtt-brand.js +243 -59
- package/nodes/symi-mqtt-sync.html +151 -42
- package/nodes/symi-mqtt-sync.js +45 -18
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -368,7 +368,7 @@ npm install node-red-contrib-home-assistant-websocket
|
|
|
368
368
|
**适合使用KNX-HA桥接的场景**:
|
|
369
369
|
- HA中已有KNX集成,希望与其他系统整合
|
|
370
370
|
- 需要KNX设备与HA中的Zigbee、WiFi等设备联动
|
|
371
|
-
-
|
|
371
|
+
- 可以在HA中统一管理所有设备
|
|
372
372
|
- 需要利用HA的自动化和场景功能
|
|
373
373
|
- 已安装node-red-contrib-home-assistant-websocket,共享HA配置
|
|
374
374
|
|
|
@@ -383,6 +383,46 @@ npm install node-red-contrib-home-assistant-websocket
|
|
|
383
383
|
- 配置灵活,易于调整
|
|
384
384
|
|
|
385
385
|
|
|
386
|
+
### HA双向同步
|
|
387
|
+
|
|
388
|
+
Symi HA同步节点 (`symi-ha-sync`) 用于实现Symi蓝牙Mesh设备与Home Assistant实体的直接双向同步。
|
|
389
|
+
|
|
390
|
+
#### 功能特性
|
|
391
|
+
|
|
392
|
+
1. **配置复用**:
|
|
393
|
+
- 复用`symi-mqtt`配置节点获取Symi设备信息
|
|
394
|
+
- 复用`server`配置节点连接Home Assistant
|
|
395
|
+
2. **双向同步**:
|
|
396
|
+
- **Symi -> HA**:Mesh设备状态变化 -> 更新HA实体状态
|
|
397
|
+
- **HA -> Symi**:HA实体状态变化 -> 控制Mesh设备
|
|
398
|
+
3. **防死循环**:
|
|
399
|
+
- 内置800ms冷却机制
|
|
400
|
+
- 区分Symi触发和HA触发,避免信号震荡
|
|
401
|
+
4. **便捷配置**:
|
|
402
|
+
- 自动加载所有Symi设备和HA实体
|
|
403
|
+
- 支持按键通道选择(1-4键)
|
|
404
|
+
- 支持实体ID搜索和下拉选择
|
|
405
|
+
|
|
406
|
+
#### 配置步骤
|
|
407
|
+
|
|
408
|
+
1. **添加节点**:从左侧拖入`Symi HA Sync`节点
|
|
409
|
+
2. **选择MQTT配置**:选择已有的`symi-mqtt`配置节点(共享Symi网关连接)
|
|
410
|
+
3. **选择HA服务器**:选择已有的`server`配置节点(共享HA连接)
|
|
411
|
+
4. **添加映射**:
|
|
412
|
+
- 点击"添加"按钮
|
|
413
|
+
- **Symi设备**:下拉选择Mesh设备(显示名称和MAC)
|
|
414
|
+
- **按键**:选择控制通道(按键1-4)
|
|
415
|
+
- **HA实体**:输入或选择要同步的HA实体ID(如`switch.living_room_light`)
|
|
416
|
+
5. **部署**:点击部署,立即生效
|
|
417
|
+
|
|
418
|
+
#### 注意事项
|
|
419
|
+
|
|
420
|
+
- **MQTT配置**:必须选择`symi-mqtt`配置节点,用于获取设备列表和接收Mesh事件
|
|
421
|
+
- **HA连接**:必须确保HA服务器节点连接正常
|
|
422
|
+
- **实体类型**:建议同步相同类型的实体(如开关对开关,调光灯对灯光)
|
|
423
|
+
- **多通道设备**:对于多键开关,请分别为每个按键添加一条映射
|
|
424
|
+
|
|
425
|
+
|
|
386
426
|
## 协议说明
|
|
387
427
|
|
|
388
428
|
### 核心协议格式
|
|
@@ -1291,6 +1331,7 @@ A: 每个房间部署一个云端同步节点,配置对应的酒店ID和房间
|
|
|
1291
1331
|
| **Symi RS485 Bridge** | RS485设备双向同步 | [RS485/Modbus双向同步](#rs485modbus双向同步) |
|
|
1292
1332
|
| **Symi KNX Bridge** | KNX系统双向同步 | [KNX双向同步](#knx双向同步) |
|
|
1293
1333
|
| **Symi KNX-HA Bridge** | KNX与HA实体双向同步 | [KNX-HA双向同步](#knx-ha双向同步) |
|
|
1334
|
+
| **Symi HA Sync** | HA实体双向同步 | [HA双向同步](#ha双向同步) |
|
|
1294
1335
|
| **Symi MQTT Sync** | 第三方MQTT品牌设备同步 | v1.7.3新增 |
|
|
1295
1336
|
| **Symi MQTT Brand** | 品牌MQTT配置节点 | v1.7.3新增 |
|
|
1296
1337
|
| **RS485 Debug** | RS485总线数据抓包调试 | [RS485调试节点](#rs485调试节点) |
|
|
@@ -1462,65 +1503,53 @@ node-red-contrib-symi-mesh/
|
|
|
1462
1503
|
|
|
1463
1504
|
## 更新日志
|
|
1464
1505
|
|
|
1465
|
-
### v1.7.
|
|
1466
|
-
-
|
|
1467
|
-
-
|
|
1468
|
-
-
|
|
1469
|
-
-
|
|
1470
|
-
-
|
|
1471
|
-
-
|
|
1472
|
-
|
|
1473
|
-
-
|
|
1474
|
-
-
|
|
1475
|
-
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
-
|
|
1481
|
-
-
|
|
1482
|
-
-
|
|
1483
|
-
-
|
|
1484
|
-
-
|
|
1485
|
-
-
|
|
1486
|
-
|
|
1487
|
-
-
|
|
1488
|
-
|
|
1489
|
-
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
-
|
|
1498
|
-
|
|
1499
|
-
-
|
|
1500
|
-
-
|
|
1501
|
-
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
-
|
|
1511
|
-
-
|
|
1512
|
-
- **输入输出端口**:支持连接debug节点调试同步数据
|
|
1513
|
-
- **错误日志限流**:网络故障时每60秒最多记录一次错误
|
|
1514
|
-
- **断线自动重连**:5秒重连间隔
|
|
1515
|
-
- **串口支持优化**:
|
|
1516
|
-
- 所有串口节点支持手动输入+搜索选择
|
|
1517
|
-
- 兼容serialport v9/v10+,兼容HassOS环境
|
|
1518
|
-
- 串口错误日志限流,避免长时间故障时日志爆炸
|
|
1519
|
-
- **稳定性优化**:
|
|
1520
|
-
- 错误日志频率限制,长时间网络故障不影响系统性能
|
|
1521
|
-
- 静默处理非关键错误,生产级稳定性
|
|
1522
|
-
- 内存安全,无调试日志,断电断网恢复后正常工作
|
|
1523
|
-
- 缓存队列处理,符合MQTT协议要求
|
|
1506
|
+
### v1.7.8 (2026-01-05)
|
|
1507
|
+
- **配置持久化增强**:所有同步节点的设备列表和映射配置持久保存
|
|
1508
|
+
- **MQTT同步节点**:Mesh设备和品牌设备列表持久化,断线后仍可显示已配置的映射
|
|
1509
|
+
- **HA同步节点**:Symi设备和HA实体列表持久化,断线后仍可显示已配置的映射
|
|
1510
|
+
- **RS485桥接节点**:Mesh设备列表持久化,断线后仍可显示已配置的映射
|
|
1511
|
+
- **离线设备显示**:[离线]标记缓存中但当前不在线的设备,[未找到]标记不在缓存中的设备
|
|
1512
|
+
- **刷新按钮**:各节点添加独立刷新按钮,可手动刷新设备列表
|
|
1513
|
+
- **MQTT品牌同步增强**:完整对接HYQW(花语前湾)MQTT协议
|
|
1514
|
+
- **完整设备类型支持**:灯具(8)、空调(12)、窗帘(14)、地暖(16)、新风(36)
|
|
1515
|
+
- **功能码映射**:完整的fn/fv到Mesh属性双向转换
|
|
1516
|
+
- 灯具:开关(fn=1)、亮度(fn=2, 0-100)
|
|
1517
|
+
- 空调:开关(fn=1)、温度(fn=2, 18-29°C)、模式(fn=3)、风速(fn=4)
|
|
1518
|
+
- 窗帘:动作(fn=1, 开/关/停)、位置(fn=2, 0-100%)
|
|
1519
|
+
- 地暖:开关(fn=1)、温度(fn=2, 5-35°C)
|
|
1520
|
+
- 新风:开关(fn=1)、风速(fn=3)
|
|
1521
|
+
- **可扩展架构**:BRAND_PROTOCOLS对象支持添加新品牌协议
|
|
1522
|
+
- **双向状态同步**:HYQW↔Mesh实时同步,2秒防抖防死循环
|
|
1523
|
+
- **自动设备发现**:自动发现品牌MQTT设备,限制200个
|
|
1524
|
+
- **错误日志限流**:每60秒最多记录一次错误,避免日志爆炸
|
|
1525
|
+
- **自动重连**:5秒重连间隔,断线自动恢复
|
|
1526
|
+
- **资源清理**:完善的定时器和事件监听器清理机制
|
|
1527
|
+
- **HA同步节点完整重构**:实现所有实体类型的完美双向同步
|
|
1528
|
+
- **完整实体类型支持**:
|
|
1529
|
+
- switch/input_boolean:开关状态 (on/off)
|
|
1530
|
+
- light:开关 + 亮度 (0-255 ↔ 0-100)
|
|
1531
|
+
- cover:开/关/停 + 位置 (0-100%)
|
|
1532
|
+
- climate:开关 + 温度 + 模式(cool/heat/fan_only/dry) + 风速(high/medium/low/auto)
|
|
1533
|
+
- fan:开关 + 风速
|
|
1534
|
+
- **Mesh属性完整映射**:
|
|
1535
|
+
- 0x02 开关状态(单路/多路)
|
|
1536
|
+
- 0x03 亮度 (0-100)
|
|
1537
|
+
- 0x05 窗帘运行状态
|
|
1538
|
+
- 0x06 窗帘位置 (0-100)
|
|
1539
|
+
- 0x1B 目标温度 (16-30°C)
|
|
1540
|
+
- 0x1C 风速 (1=高/2=中/3=低/4=自动)
|
|
1541
|
+
- 0x1D 空调模式 (1=制冷/2=制热/3=送风/4=除湿)
|
|
1542
|
+
- **智能按键选择**:只有多路开关才显示按键选择,温控器/窗帘/调光灯显示"-"
|
|
1543
|
+
- **设备类型标签**:自动识别并显示设备类型([温控器]、[窗帘]、[调光灯]、[N路开关])
|
|
1544
|
+
- **智能防抖机制**:窗帘和调光灯使用500ms防抖,只同步最终位置/亮度
|
|
1545
|
+
- **防死循环增强**:2秒冷却时间 + 双向时间戳检查
|
|
1546
|
+
- **配置持久化**:设备列表和映射配置持久保存
|
|
1547
|
+
- **内存泄漏防护**:定时清理过期时间戳和防抖定时器
|
|
1548
|
+
- **代码质量优化**:
|
|
1549
|
+
- 同步时间戳Map自动清理60秒以上的条目
|
|
1550
|
+
- 设备发现数量限制,防止内存溢出
|
|
1551
|
+
- 完善的节点关闭清理逻辑
|
|
1552
|
+
- 防死循环机制增强:双向时间戳检查
|
|
1524
1553
|
|
|
1525
1554
|
### v1.7.7 (2026-01-05)
|
|
1526
1555
|
- **RS485桥接节点逻辑优化**:
|
|
@@ -1596,18 +1625,6 @@ node-red-contrib-symi-mesh/
|
|
|
1596
1625
|
- 队列限制100条,防止内存溢出
|
|
1597
1626
|
- **调试日志**:添加详细调试日志,方便排查问题
|
|
1598
1627
|
|
|
1599
|
-
### v1.7.0 (2025-12-21)
|
|
1600
|
-
- **自定义协议增强**:RS485桥接节点自定义协议功能全面升级
|
|
1601
|
-
- 自定义开关:添加发开、发关、收开、收关4组码
|
|
1602
|
-
- 翻转模式:收开码=收关码时,收到后自动翻转开关状态
|
|
1603
|
-
- 自定义窗帘:添加发开、发关、发停、收开、收关、收停6组码
|
|
1604
|
-
- 自定义空调:新增完整收发码支持(开关、风速、模式、温度)
|
|
1605
|
-
- 支持最多24字节(72个十六进制字符)数据录入
|
|
1606
|
-
- 自定义模式自动隐藏地址字段
|
|
1607
|
-
- 配置持久化保存,重启后保持
|
|
1608
|
-
- 防死循环机制优化
|
|
1609
|
-
- 内存优化,防止日志溢出
|
|
1610
|
-
|
|
1611
1628
|
## 许可证
|
|
1612
1629
|
|
|
1613
1630
|
MIT License
|
|
@@ -1619,7 +1636,7 @@ Copyright (c) 2025 SYMI 亖米
|
|
|
1619
1636
|
## 关于
|
|
1620
1637
|
|
|
1621
1638
|
**作者**: SYMI 亖米
|
|
1622
|
-
**版本**: 1.7.
|
|
1639
|
+
**版本**: 1.7.8
|
|
1623
1640
|
**协议**: 蓝牙MESH网关(初级版)串口协议V1.0
|
|
1624
1641
|
**最后更新**: 2026-01-05
|
|
1625
1642
|
**仓库**: https://github.com/symi-daguo/node-red-contrib-symi-mesh
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
name: { value: '' },
|
|
7
7
|
gateway: { value: '', type: 'symi-gateway', required: true },
|
|
8
8
|
rs485Config: { value: '', type: 'symi-485-config', required: true },
|
|
9
|
-
mappings: { value: '[]' }
|
|
9
|
+
mappings: { value: '[]' },
|
|
10
|
+
// 持久化缓存:保存设备列表,断线后仍可显示
|
|
11
|
+
cachedMeshDevices: { value: '[]' }
|
|
10
12
|
},
|
|
11
13
|
inputs: 1,
|
|
12
14
|
outputs: 1,
|
|
@@ -26,6 +28,7 @@
|
|
|
26
28
|
var meshDevices = [];
|
|
27
29
|
var protocolData = {};
|
|
28
30
|
var mappings = [];
|
|
31
|
+
var cachedMeshDevices = [];
|
|
29
32
|
|
|
30
33
|
// 设置编辑面板更宽
|
|
31
34
|
var panel = $('#dialog-form').parent();
|
|
@@ -34,23 +37,58 @@
|
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
try { mappings = JSON.parse(node.mappings || '[]'); } catch(e) { mappings = []; }
|
|
40
|
+
try { cachedMeshDevices = JSON.parse(node.cachedMeshDevices || '[]'); } catch(e) { cachedMeshDevices = []; }
|
|
41
|
+
|
|
42
|
+
// 合并设备列表:在线设备 + 缓存设备(去重)
|
|
43
|
+
function mergeDevices(onlineDevices, cachedDevices) {
|
|
44
|
+
var merged = [];
|
|
45
|
+
var keys = new Set();
|
|
46
|
+
|
|
47
|
+
// 先添加在线设备
|
|
48
|
+
(onlineDevices || []).forEach(function(d) {
|
|
49
|
+
var key = (d.mac || '').toLowerCase().replace(/:/g, '');
|
|
50
|
+
if (key && !keys.has(key)) {
|
|
51
|
+
keys.add(key);
|
|
52
|
+
d._online = true;
|
|
53
|
+
merged.push(d);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// 再添加缓存中不在线的设备
|
|
58
|
+
(cachedDevices || []).forEach(function(d) {
|
|
59
|
+
var key = (d.mac || '').toLowerCase().replace(/:/g, '');
|
|
60
|
+
if (key && !keys.has(key)) {
|
|
61
|
+
keys.add(key);
|
|
62
|
+
d._online = false;
|
|
63
|
+
merged.push(d);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return merged;
|
|
68
|
+
}
|
|
37
69
|
|
|
38
70
|
// 加载Mesh设备 - 等待gateway选择框初始化完成
|
|
39
71
|
function loadMeshDevices(callback) {
|
|
40
72
|
var gatewayId = $('#node-input-gateway').val();
|
|
41
73
|
if (!gatewayId) {
|
|
42
|
-
meshDevices = [];
|
|
74
|
+
meshDevices = mergeDevices([], cachedMeshDevices);
|
|
43
75
|
if (callback) callback();
|
|
44
76
|
return;
|
|
45
77
|
}
|
|
46
78
|
$.getJSON('symi-rs485-bridge/mesh-devices/' + gatewayId)
|
|
47
79
|
.done(function(devices) {
|
|
48
|
-
meshDevices = devices || [];
|
|
80
|
+
meshDevices = mergeDevices(devices || [], cachedMeshDevices);
|
|
81
|
+
// 更新缓存
|
|
82
|
+
if (devices && devices.length > 0) {
|
|
83
|
+
cachedMeshDevices = devices.map(function(d) {
|
|
84
|
+
return { mac: d.mac, name: d.name, channels: d.channels };
|
|
85
|
+
});
|
|
86
|
+
}
|
|
49
87
|
console.log('[RS485 Bridge] 加载Mesh设备:', meshDevices.length);
|
|
50
88
|
if (callback) callback();
|
|
51
89
|
})
|
|
52
90
|
.fail(function() {
|
|
53
|
-
meshDevices = [];
|
|
91
|
+
meshDevices = mergeDevices([], cachedMeshDevices);
|
|
54
92
|
if (callback) callback();
|
|
55
93
|
});
|
|
56
94
|
}
|
|
@@ -81,25 +119,34 @@
|
|
|
81
119
|
return device.channels || 1;
|
|
82
120
|
}
|
|
83
121
|
|
|
84
|
-
// 构建Mesh
|
|
85
|
-
function getMeshOptions(selectedMac) {
|
|
122
|
+
// 构建Mesh设备选项(不包含按键,按键单独选择)- 支持离线显示
|
|
123
|
+
function getMeshOptions(selectedMac, savedName) {
|
|
86
124
|
var html = '<option value="">-- 选择 --</option>';
|
|
87
125
|
var selMacNorm = (selectedMac || '').toLowerCase().replace(/:/g, '');
|
|
126
|
+
var found = false;
|
|
88
127
|
meshDevices.forEach(function(d) {
|
|
89
128
|
var devMacNorm = (d.mac || '').toLowerCase().replace(/:/g, '');
|
|
90
129
|
var selected = (devMacNorm === selMacNorm && selMacNorm !== '') ? ' selected' : '';
|
|
91
|
-
|
|
130
|
+
if (selected) found = true;
|
|
131
|
+
var statusIcon = d._online === false ? ' [离线]' : '';
|
|
132
|
+
var style = d._online === false ? ' style="color:#999;"' : '';
|
|
133
|
+
html += '<option value="' + d.mac + '" data-channels="' + (d.channels || 1) + '" data-name="' + (d.name || '') + '"' + selected + style + '>' + (d.name || d.mac) + statusIcon + '</option>';
|
|
92
134
|
});
|
|
135
|
+
// 如果已选择的设备不在列表中,添加它
|
|
136
|
+
if (selMacNorm && !found) {
|
|
137
|
+
var displayName = savedName || selectedMac;
|
|
138
|
+
html += '<option value="' + selectedMac + '" selected style="color:#c00;">' + displayName + ' [未找到]</option>';
|
|
139
|
+
}
|
|
93
140
|
return html;
|
|
94
141
|
}
|
|
95
142
|
|
|
96
|
-
// 构建Mesh
|
|
97
|
-
function getMeshChannelOptions(mac, selectedChannel) {
|
|
143
|
+
// 构建Mesh按键选项(仅当开关设备时显示)- 支持保存的通道数
|
|
144
|
+
function getMeshChannelOptions(mac, selectedChannel, savedChannels) {
|
|
98
145
|
var macNorm = (mac || '').toLowerCase().replace(/:/g, '');
|
|
99
146
|
var device = meshDevices.find(function(d) {
|
|
100
147
|
return (d.mac || '').toLowerCase().replace(/:/g, '') === macNorm;
|
|
101
148
|
});
|
|
102
|
-
var channels = device ? (device.channels || 1) :
|
|
149
|
+
var channels = device ? (device.channels || 1) : (savedChannels || 1);
|
|
103
150
|
if (channels <= 1) return '';
|
|
104
151
|
var html = '<select class="mesh-channel">';
|
|
105
152
|
for (var i = 1; i <= channels; i++) {
|
|
@@ -207,8 +254,8 @@
|
|
|
207
254
|
row.html(
|
|
208
255
|
'<div class="mapping-main">' +
|
|
209
256
|
'<div class="mesh-col">' +
|
|
210
|
-
' <select class="mesh-select">' + getMeshOptions(m.meshMac) + '</select>' +
|
|
211
|
-
' <span class="mesh-ch-wrap">' + getMeshChannelOptions(m.meshMac, m.meshChannel || 1) + '</span>' +
|
|
257
|
+
' <select class="mesh-select">' + getMeshOptions(m.meshMac, m.meshName) + '</select>' +
|
|
258
|
+
' <span class="mesh-ch-wrap">' + getMeshChannelOptions(m.meshMac, m.meshChannel || 1, m.meshChannels) + '</span>' +
|
|
212
259
|
'</div>' +
|
|
213
260
|
'<div class="arrow-col"><i class="fa fa-arrows-h"></i></div>' +
|
|
214
261
|
'<div class="brand-col">' +
|
|
@@ -279,10 +326,13 @@
|
|
|
279
326
|
var row = $(this).closest('.mapping-row');
|
|
280
327
|
var idx = row.data('idx');
|
|
281
328
|
var mac = $(this).val();
|
|
329
|
+
var opt = $(this).find('option:selected');
|
|
282
330
|
mappings[idx].meshMac = mac || '';
|
|
331
|
+
mappings[idx].meshName = opt.data('name') || opt.text().replace(' [离线]', '').replace(' [未找到]', '');
|
|
332
|
+
mappings[idx].meshChannels = parseInt(opt.data('channels')) || 1;
|
|
283
333
|
mappings[idx].meshChannel = 1;
|
|
284
334
|
// 更新Mesh按键选择器
|
|
285
|
-
row.find('.mesh-ch-wrap').html(getMeshChannelOptions(mac, 1));
|
|
335
|
+
row.find('.mesh-ch-wrap').html(getMeshChannelOptions(mac, 1, mappings[idx].meshChannels));
|
|
286
336
|
bindEvents(); // 重新绑定新元素事件
|
|
287
337
|
});
|
|
288
338
|
|
|
@@ -658,6 +708,8 @@
|
|
|
658
708
|
|
|
659
709
|
var m = {
|
|
660
710
|
meshMac: $(this).find('.mesh-select').val() || '',
|
|
711
|
+
meshName: $(this).find('.mesh-select option:selected').data('name') || $(this).find('.mesh-select option:selected').text().replace(' [离线]', '').replace(' [未找到]', ''),
|
|
712
|
+
meshChannels: parseInt($(this).find('.mesh-select option:selected').data('channels')) || 1,
|
|
661
713
|
meshChannel: parseInt($(this).find('.mesh-channel').val()) || 1,
|
|
662
714
|
brand: $(this).find('.brand-select').val() || '',
|
|
663
715
|
device: $(this).find('.device-select').val() || '',
|
|
@@ -766,6 +818,8 @@
|
|
|
766
818
|
mappings.push(m);
|
|
767
819
|
});
|
|
768
820
|
this.mappings = JSON.stringify(mappings);
|
|
821
|
+
// 保存缓存的设备列表
|
|
822
|
+
this.cachedMeshDevices = JSON.stringify(cachedMeshDevices);
|
|
769
823
|
}
|
|
770
824
|
});
|
|
771
825
|
</script>
|
|
@@ -833,6 +887,8 @@
|
|
|
833
887
|
<div class="form-tips" style="margin-top: 10px;">
|
|
834
888
|
<p><b>提示:</b>开关设备需要分别选择Mesh和RS485的按键,可自由配置对应关系(如Mesh第3路 ↔ RS485第1路)</p>
|
|
835
889
|
</div>
|
|
890
|
+
|
|
891
|
+
<input type="hidden" id="node-input-cachedMeshDevices">
|
|
836
892
|
</script>
|
|
837
893
|
|
|
838
894
|
<script type="text/html" data-help-name="symi-rs485-bridge">
|