node-red-contrib-symi-mesh 1.7.4 → 1.7.5

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 CHANGED
@@ -1462,6 +1462,20 @@ node-red-contrib-symi-mesh/
1462
1462
 
1463
1463
  ## 更新日志
1464
1464
 
1465
+ ### v1.7.5 (2025-12-24)
1466
+ - **API路径兼容性修复**:修复HassOS环境下节点配置界面无法加载设备列表的问题
1467
+ - **根本原因**:HassOS Node-RED使用nginx反向代理,绝对路径`/api`会被拦截,需使用相对路径`api`
1468
+ - **修复范围**:所有节点HTML中的`$.getJSON()`调用统一使用相对路径
1469
+ - **开发规范**:后续开发节点时,所有前端API调用必须使用相对路径,不带前导斜杠
1470
+ - **KNX Bridge双向同步修复**:修复Mesh控制KNX开关不工作的问题
1471
+ - **根本原因**:knxUltimate节点当`setTopicType: "str"`时使用`msg.topic`作为目标地址,而非`msg.destination`
1472
+ - **修复方案**:发送消息同时包含`topic`和`destination`字段,确保兼容所有knxUltimate配置
1473
+ - **消息格式**:`{ topic, destination, payload, dpt, event }`
1474
+ - **防死循环**:不包含`knx`对象,避免触发knxUltimate的循环引用保护机制
1475
+ - **用户体验优化**:
1476
+ - 设备列表加载时显示"加载中..."提示
1477
+ - API调用失败时显示"加载失败,请重试"提示
1478
+
1465
1479
  ### v1.7.4 (2025-12-24)
1466
1480
  - **串口配置完善**:完整的串口参数配置,解决HassOS环境串口锁定问题
1467
1481
  - **完整参数**:波特率、数据位(7/8)、停止位(1/2)、校验位(None/Even/Odd)
@@ -1585,23 +1599,6 @@ node-red-contrib-symi-mesh/
1585
1599
  - 防死循环机制优化
1586
1600
  - 内存优化,防止日志溢出
1587
1601
 
1588
- ### v1.6.9 (2025-12-20)
1589
- - **KNX-HA双向同步**:新增`symi-knx-ha-bridge`节点
1590
- - 直接连接KNX与HA实体,实现双向同步
1591
- - 支持Tab分隔格式导入KNX组地址配置(与KNX桥接节点100%一致)
1592
- - 使用共享HA服务器节点,通过REST API自动加载HA实体列表
1593
- - 支持开关、灯光、窗帘、空调、风扇等设备类型
1594
- - 完整双向同步:KNX↔HA实时状态同步
1595
- - 事件驱动架构,通过HA events-state节点实时接收事件
1596
- - 智能防抖:调光300ms、窗帘500ms,只同步最终值
1597
- - 内置防死循环机制(800ms防抖)
1598
- - 快速输入框:支持输入实体ID或名称搜索,自动提示806+实体
1599
- - 手动刷新按钮,随时重新加载HA实体
1600
- - 宽屏界面:对话框最小1000px宽度
1601
- - 持久化配置保存,内存优化
1602
- - 连接knxUltimate节点,无缝集成
1603
- - 适用于已有KNX系统与HA整合的场景
1604
-
1605
1602
  ## 许可证
1606
1603
 
1607
1604
  MIT License
@@ -1613,7 +1610,7 @@ Copyright (c) 2025 SYMI 亖米
1613
1610
  ## 关于
1614
1611
 
1615
1612
  **作者**: SYMI 亖米
1616
- **版本**: 1.7.4
1613
+ **版本**: 1.7.5
1617
1614
  **协议**: 蓝牙MESH网关(初级版)串口协议V1.0
1618
1615
  **最后更新**: 2025-12-24
1619
1616
  **仓库**: https://github.com/symi-daguo/node-red-contrib-symi-mesh
@@ -80,12 +80,12 @@
80
80
  "notifyreadrequest": false,
81
81
  "notifyresponse": false,
82
82
  "notifywrite": true,
83
- "name": "Universal KNX",
83
+ "name": "Universal KNX Output",
84
84
  "outputtype": "write",
85
85
  "outputRBE": "false",
86
86
  "inputRBE": "false",
87
87
  "passthrough": "no",
88
- "listenallga": true,
88
+ "listenallga": false,
89
89
  "buttonEnabled": false,
90
90
  "x": 620,
91
91
  "y": 120,
@@ -34,7 +34,7 @@
34
34
 
35
35
  function loadHistory() {
36
36
  if (!node.id) return;
37
- $.getJSON('/rs485-debug/history/' + node.id, function(messages) {
37
+ $.getJSON('rs485-debug/history/' + node.id, function(messages) {
38
38
  var container = $('#debug-history');
39
39
 
40
40
  if (messages.length === 0) {
@@ -43,7 +43,7 @@
43
43
  if (callback) callback();
44
44
  return;
45
45
  }
46
- $.getJSON('/symi-rs485-bridge/mesh-devices/' + gatewayId)
46
+ $.getJSON('symi-rs485-bridge/mesh-devices/' + gatewayId)
47
47
  .done(function(devices) {
48
48
  meshDevices = devices || [];
49
49
  console.log('[RS485 Bridge] 加载Mesh设备:', meshDevices.length);
@@ -56,7 +56,7 @@
56
56
  }
57
57
 
58
58
  // 加载协议模板
59
- $.getJSON('/symi-rs485-bridge/protocols', function(data) {
59
+ $.getJSON('symi-rs485-bridge/protocols', function(data) {
60
60
  protocolData = data || { brands: {} };
61
61
  // 延迟加载设备,确保gateway选择框已初始化
62
62
  setTimeout(function() {
@@ -38,7 +38,7 @@
38
38
  $btn.prop('disabled', true);
39
39
  $select.empty().append('<option value="">搜索中...</option>').show();
40
40
 
41
- $.getJSON('/symi-gateway/serial-ports', function(ports) {
41
+ $.getJSON('symi-gateway/serial-ports', function(ports) {
42
42
  $select.empty();
43
43
  if (ports && ports.length > 0) {
44
44
  $select.append('<option value="">-- 选择串口 --</option>');
@@ -60,6 +60,7 @@
60
60
 
61
61
  var loadDevices = function(gatewayId) {
62
62
  if (!gatewayId) {
63
+ console.log('[symi-device] 网关ID为空,跳过加载');
63
64
  return;
64
65
  }
65
66
 
@@ -67,11 +68,16 @@
67
68
  var currentValue = deviceSelect.val();
68
69
 
69
70
  deviceSelect.empty();
70
- deviceSelect.append('<option value="">-- 选择设备 --</option>');
71
+ deviceSelect.append('<option value="">加载中...</option>');
71
72
 
72
- $.getJSON('/symi-gateway/devices/' + gatewayId)
73
+ var apiUrl = 'symi-gateway/devices/' + gatewayId;
74
+ console.log('[symi-device] 加载设备列表, API:', apiUrl);
75
+
76
+ $.getJSON(apiUrl)
73
77
  .done(function(devices) {
74
- console.log('加载设备列表:', devices.length, '个设备');
78
+ console.log('[symi-device] 加载成功:', devices ? devices.length : 0, '个设备');
79
+ deviceSelect.empty();
80
+ deviceSelect.append('<option value="">-- 选择设备 --</option>');
75
81
  if (devices && devices.length > 0) {
76
82
  devices.forEach(function(device) {
77
83
  var label = device.name + ' (' + device.mac + ')';
@@ -99,8 +105,10 @@
99
105
 
100
106
  deviceSelect.trigger('change');
101
107
  })
102
- .fail(function(err) {
103
- console.log('加载设备失败:', err);
108
+ .fail(function(xhr, status, err) {
109
+ console.log('[symi-device] 加载设备失败:', status, err, xhr.responseText);
110
+ deviceSelect.empty();
111
+ deviceSelect.append('<option value="">加载失败,请重试</option>');
104
112
  });
105
113
  };
106
114
 
@@ -37,7 +37,7 @@
37
37
  $btn.prop('disabled', true).text('搜索中...');
38
38
  $select.empty().append('<option value="">搜索中...</option>');
39
39
 
40
- $.getJSON('/symi-gateway/serial-ports', function(ports) {
40
+ $.getJSON('symi-gateway/serial-ports', function(ports) {
41
41
  $select.empty();
42
42
  if (ports && ports.length > 0) {
43
43
  $select.append('<option value="">-- 选择串口 --</option>');
@@ -760,9 +760,12 @@ module.exports = function(RED) {
760
760
  const destAddr = knxMsg.knx.destination;
761
761
  node.lastKnxAddrSent[destAddr] = Date.now();
762
762
 
763
- // knxUltimate官方格式: https://supergiovane.github.io/node-red-contrib-knx-ultimate/wiki/Device
764
- // 必须包含: destination, payload, dpt, event
763
+ // knxUltimate输入格式:topic + destination + payload + dpt + event
764
+ // topic: 当setTopicType=str时,knxUltimate使用msg.topic作为目标地址
765
+ // destination: 官方备用字段
766
+ // 注意:不能包含knx对象,否则会触发knxUltimate的循环引用保护
765
767
  const sendMsg = {
768
+ topic: destAddr,
766
769
  destination: destAddr,
767
770
  payload: knxMsg.payload,
768
771
  dpt: knxMsg.dpt || knxMsg.knx.dpt,
@@ -784,7 +787,7 @@ module.exports = function(RED) {
784
787
  timestamp: new Date().toISOString()
785
788
  };
786
789
 
787
- node.log(`[Mesh->KNX] 发送: destination=${sendMsg.destination}, payload=${sendMsg.payload}, dpt=${sendMsg.dpt}, event=${sendMsg.event}`);
790
+ node.log(`[Mesh->KNX] 发送: topic=${sendMsg.topic}, payload=${sendMsg.payload}, dpt=${sendMsg.dpt}`);
788
791
 
789
792
  // 同时发送到两个输出端口(一次send调用)
790
793
  node.send([sendMsg, debugMsg]);
@@ -59,7 +59,7 @@
59
59
  if (callback) callback();
60
60
  return;
61
61
  }
62
- $.getJSON('/symi-gateway/devices/' + gatewayId, function(devices) {
62
+ $.getJSON('symi-gateway/devices/' + gatewayId, function(devices) {
63
63
  meshDevices = devices || [];
64
64
  if (callback) callback();
65
65
  }).fail(function() {
@@ -76,7 +76,7 @@
76
76
  if (callback) callback();
77
77
  return;
78
78
  }
79
- $.getJSON('/symi-mqtt-brand/devices/' + brandConfigId, function(devices) {
79
+ $.getJSON('symi-mqtt-brand/devices/' + brandConfigId, function(devices) {
80
80
  brandDevices = devices || [];
81
81
  if (callback) callback();
82
82
  }).fail(function() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-symi-mesh",
3
- "version": "1.7.4",
3
+ "version": "1.7.5",
4
4
  "description": "Node-RED节点集合,用于通过TCP/串口连接Symi蓝牙Mesh网关,支持Home Assistant MQTT Discovery自动发现和云端数据同步",
5
5
  "main": "nodes/symi-gateway.js",
6
6
  "scripts": {