node-red-contrib-symi-mesh 1.8.6 → 1.8.7
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 +10 -0
- package/lib/tcp-client.js +1 -1
- package/nodes/rs485-debug.js +3 -2
- package/nodes/symi-485-config.js +13 -2
- package/nodes/symi-cloud-sync.js +1 -1
- package/nodes/symi-device.js +4 -4
- package/nodes/symi-gateway.js +12 -1
- package/nodes/symi-ha-sync.js +2 -2
- package/nodes/symi-mqtt.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -558,6 +558,8 @@ npm install node-red-contrib-home-assistant-websocket
|
|
|
558
558
|
|
|
559
559
|
| 节点 | 用途 |
|
|
560
560
|
|-----|------|
|
|
561
|
+
| **Symi RS485 Sync** | RS485多机批量同步 |
|
|
562
|
+
| **RS485调试** | 原始485字节流抓取显示 |
|
|
561
563
|
| **Symi Gateway** | 网关连接(TCP/串口) |
|
|
562
564
|
| **Symi MQTT** | MQTT桥接,设备发布到HA |
|
|
563
565
|
| **Symi Device** | Flow中单设备控制/监听 |
|
|
@@ -702,6 +704,14 @@ node-red-contrib-symi-mesh/
|
|
|
702
704
|
|
|
703
705
|
## 更新日志
|
|
704
706
|
|
|
707
|
+
### v1.8.7 (2026-01-08)
|
|
708
|
+
|
|
709
|
+
**生产环境日志优化与稳定性增强**:
|
|
710
|
+
- **错误日志节流 (Throttling)**:在网关连接和 RS485 配置中引入 60 秒节流机制,同类网络错误(如 `ECONNREFUSED`)每分钟仅记录一次,彻底解决离线时的日志刷屏问题。
|
|
711
|
+
- **日志级别降级**:将所有节点的 `node.error` 和 `node.warn` 统一降级为 `node.log` (Info 级别),保持 Node-RED 控制台整洁,仅在调试模式下显示详细信息。
|
|
712
|
+
- **TCP 客户端优化**:在 `tcp-client` 库级别拦截常见的网络波动报错,提升系统在高频重连场景下的静默稳定性。
|
|
713
|
+
- **全量节点适配**:完成 MQTT、HA同步、云端同步、RS485、KNX 等所有功能节点的日志规范化清理。
|
|
714
|
+
|
|
705
715
|
### v1.8.6 (2026-01-07)
|
|
706
716
|
|
|
707
717
|
**核心修复与同步增强**:
|
package/lib/tcp-client.js
CHANGED
|
@@ -111,7 +111,7 @@ class TCPClient extends EventEmitter {
|
|
|
111
111
|
// 只在首次连接或重要错误时记录,避免大量重复日志
|
|
112
112
|
// ECONNRESET通常是网络波动,不记录错误
|
|
113
113
|
else if (!this.connected && error.code !== 'ECONNREFUSED' && error.code !== 'ECONNRESET') {
|
|
114
|
-
this.logger.
|
|
114
|
+
this.logger.log('TCP client error: ' + error.message);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
// 确保错误不会导致uncaught exception
|
package/nodes/rs485-debug.js
CHANGED
|
@@ -145,12 +145,13 @@ module.exports = function(RED) {
|
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
node.rs485Config.on('disconnected', function() {
|
|
148
|
-
node.
|
|
148
|
+
node.log('RS485连接已断开');
|
|
149
149
|
updateStatus();
|
|
150
150
|
});
|
|
151
151
|
|
|
152
152
|
node.rs485Config.on('error', function(err) {
|
|
153
|
-
|
|
153
|
+
// 降级为 log,避免控制台报错
|
|
154
|
+
node.log('RS485错误: ' + err.message);
|
|
154
155
|
node.status({ fill: 'red', shape: 'ring', text: '错误: ' + err.message });
|
|
155
156
|
});
|
|
156
157
|
|
package/nodes/symi-485-config.js
CHANGED
|
@@ -66,6 +66,17 @@ module.exports = function(RED) {
|
|
|
66
66
|
node.receiveBuffer = Buffer.alloc(0);
|
|
67
67
|
node.users = [];
|
|
68
68
|
|
|
69
|
+
// 限流错误日志
|
|
70
|
+
node._lastErrorLog = 0;
|
|
71
|
+
node._ERROR_LOG_INTERVAL = 60000;
|
|
72
|
+
node.logErrorThrottled = function(msg) {
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
if (now - node._lastErrorLog > node._ERROR_LOG_INTERVAL) {
|
|
75
|
+
node._lastErrorLog = now;
|
|
76
|
+
node.log(msg);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
69
80
|
// 注册使用者
|
|
70
81
|
node.register = function(userNode) {
|
|
71
82
|
if (!node.users.includes(userNode)) {
|
|
@@ -122,7 +133,7 @@ module.exports = function(RED) {
|
|
|
122
133
|
});
|
|
123
134
|
|
|
124
135
|
node.client.on('error', (err) => {
|
|
125
|
-
node.
|
|
136
|
+
node.logErrorThrottled(`RS485串口错误: ${err.message}`);
|
|
126
137
|
node.emit('error', err);
|
|
127
138
|
});
|
|
128
139
|
|
|
@@ -170,7 +181,7 @@ module.exports = function(RED) {
|
|
|
170
181
|
if (err.name === 'AggregateError' || err.errors) {
|
|
171
182
|
node.debug(`RS485 TCP连接失败: 无法连接到 ${node.host}:${node.port}`);
|
|
172
183
|
} else {
|
|
173
|
-
node.
|
|
184
|
+
node.logErrorThrottled(`RS485 TCP错误: ${err.message}`);
|
|
174
185
|
}
|
|
175
186
|
node.emit('error', err);
|
|
176
187
|
});
|
package/nodes/symi-cloud-sync.js
CHANGED
package/nodes/symi-device.js
CHANGED
|
@@ -99,21 +99,21 @@ module.exports = function(RED) {
|
|
|
99
99
|
node.on('input', async function(msg) {
|
|
100
100
|
try {
|
|
101
101
|
if (!node.gateway.connected) {
|
|
102
|
-
node.
|
|
102
|
+
node.log('网关未连接');
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
if (!node.device) {
|
|
107
107
|
updateDevice();
|
|
108
108
|
if (!node.device) {
|
|
109
|
-
node.
|
|
109
|
+
node.log('设备未找到');
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
const command = node.parseInputCommand(msg);
|
|
115
115
|
if (!command) {
|
|
116
|
-
node.
|
|
116
|
+
node.log('无效的命令格式');
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -122,7 +122,7 @@ module.exports = function(RED) {
|
|
|
122
122
|
node.status({ fill: 'green', shape: 'dot', text: '命令已发送' });
|
|
123
123
|
|
|
124
124
|
} catch (error) {
|
|
125
|
-
node.
|
|
125
|
+
node.log(`控制失败: ${error.message}`);
|
|
126
126
|
node.status({ fill: 'red', shape: 'dot', text: '控制失败' });
|
|
127
127
|
}
|
|
128
128
|
});
|
package/nodes/symi-gateway.js
CHANGED
|
@@ -70,6 +70,17 @@ module.exports = function(RED) {
|
|
|
70
70
|
this.sceneExecutionInProgress = false; // 场景执行中标志
|
|
71
71
|
this.sceneExecutionTimer = null; // 场景执行超时定时器
|
|
72
72
|
|
|
73
|
+
// 限流错误日志
|
|
74
|
+
this._lastErrorLog = 0;
|
|
75
|
+
this._ERROR_LOG_INTERVAL = 60000;
|
|
76
|
+
this.logErrorThrottled = function(msg) {
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
if (now - this._lastErrorLog > this._ERROR_LOG_INTERVAL) {
|
|
79
|
+
this._lastErrorLog = now;
|
|
80
|
+
this.log(msg);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
73
84
|
this.log(`Initializing Symi Gateway: ${this.connectionType === 'tcp' ? `${this.host}:${this.port}` : this.serialPort}`);
|
|
74
85
|
|
|
75
86
|
// 三合一设备检测已在 queryAllDeviceStates 中实现,无需额外事件监听
|
|
@@ -128,7 +139,7 @@ module.exports = function(RED) {
|
|
|
128
139
|
|
|
129
140
|
} catch (error) {
|
|
130
141
|
// 初始连接失败,但自动重连会继续尝试
|
|
131
|
-
this.
|
|
142
|
+
this.logErrorThrottled(`Initial connection failed: ${error.message}, will retry automatically`);
|
|
132
143
|
}
|
|
133
144
|
|
|
134
145
|
// 节点关闭时清理资源
|
package/nodes/symi-ha-sync.js
CHANGED
|
@@ -117,7 +117,7 @@ module.exports = function(RED) {
|
|
|
117
117
|
}
|
|
118
118
|
} catch (e) {
|
|
119
119
|
node.mappings = [];
|
|
120
|
-
node.
|
|
120
|
+
node.log('映射配置解析失败: ' + e.message);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
node.commandQueue = [];
|
|
@@ -162,7 +162,7 @@ module.exports = function(RED) {
|
|
|
162
162
|
|
|
163
163
|
if (configError) {
|
|
164
164
|
node.status({ fill: 'red', shape: 'ring', text: configError });
|
|
165
|
-
node.
|
|
165
|
+
node.log(`[HA同步] ${configError}`);
|
|
166
166
|
// 不要return,继续注册input监听器
|
|
167
167
|
} else {
|
|
168
168
|
// 初始状态:只有Mesh→HA方向,等待HA输入连接
|
package/nodes/symi-mqtt.js
CHANGED
|
@@ -1145,12 +1145,12 @@ module.exports = function(RED) {
|
|
|
1145
1145
|
node.publishCommandFeedback(device, command, payload, topic);
|
|
1146
1146
|
|
|
1147
1147
|
} catch(err) {
|
|
1148
|
-
node.
|
|
1148
|
+
node.log(`[MQTT发送] 失败: ${err.message}`);
|
|
1149
1149
|
}
|
|
1150
1150
|
}
|
|
1151
1151
|
})();
|
|
1152
1152
|
} else {
|
|
1153
|
-
node.
|
|
1153
|
+
node.log(`[MQTT解析] 无法解析命令 - topic: ${topic}, payload: ${payload}`);
|
|
1154
1154
|
}
|
|
1155
1155
|
};
|
|
1156
1156
|
|