如何将Loxone WebSocket接收的数据转发到另一WebSocket连接
解决方案
问题根因
你现有代码的核心错误是:每次收到Loxone推送的事件时,才给客户端WebSocket服务注册connection事件监听,这会导致两个问题:
- 已经连接成功的客户端永远收不到后续新的事件通知
- 每次事件都新增一个重复的监听,后续新客户端连接时会收到大量重复的历史消息
实现思路
维持全局唯一的客户端连接池,仅在服务启动时绑定一次客户端连接/断开监听:
- 客户端连接成功后加入连接池
- 客户端断开连接后自动从池中移除
- 收到Loxone事件时直接遍历连接池,给所有存活的客户端广播消息
- 全程仅维持1条Loxone服务端连接,符合你的架构设计要求
修改后的完整代码
if (typeof LxCommunicator === 'undefined') { global.LxCommunicator = require('lxcommunicator'); } //=== Node.js only === var fs = require('fs'); var WebSocket = require('ws'); // 请补全实际的私钥、证书文件读取逻辑 var privateKey = fs.readFileSync('./private.key'); //PkeyFile var certificate = fs.readFileSync('./cert.pem'); //CertFile var credentials = { key: privateKey, cert: certificate }; var https = require('https'); var httpsServer = https.createServer(credentials); httpsServer.listen(60088); var WebSocketServer = require('ws').Server; var wss = new WebSocketServer({ server: httpsServer }); // 新增:客户端连接池,存储所有存活的客户端WebSocket实例 const connectedClients = new Set(); // 仅绑定一次客户端连接监听 wss.on('connection', ws => { // 新客户端连接加入池 connectedClients.add(ws); // 监听客户端断开,自动从池移除 ws.on('close', () => { connectedClients.delete(ws); }); // 可选:监听客户端错误,避免进程崩溃 ws.on('error', err => { console.error('客户端连接错误', err); connectedClients.delete(ws); }); }); // Prepare our variables // uuid是设备唯一标识,若getUUID未定义请自行实现 var uuid = getUUID(), // delegateObj 包含所有可用的委托方法 delegateObj = { socketOnDataProgress: function socketOnDataProgress(socket, progress) { //console.log(progress); }, socketOnTokenConfirmed: function socketOnTokenConfirmed(socket, response) { //console.log(response); }, socketOnTokenReceived: function socketOnTokenReceived(socket, result) { //console.log(result); }, socketOnTokenRefresh: function socketOnTokenRefresh(socket, newTkObj) { //console.log(newTkObj); }, socketOnConnectionClosed: function socketOnConnectionClosed(socket, code) { process.exit(-1); }, socketOnEventReceived: function socketOnEventReceived(socket, events, type) { events.forEach(function(event) { if(type === 2 || type ===3){ //2=灯光状态 3=模式状态 var data = {}; data["uuid"] = event.uuid; data["value"] = event.value; data['text'] = event.text; // 修改:遍历所有已连接客户端广播消息 const msg = JSON.stringify(data); connectedClients.forEach(ws => { // 仅给存活的客户端发消息 if (ws.readyState === WebSocket.OPEN) { ws.send(msg); } }); } }); } }, // deviceInfo 是设备专属信息,类似浏览器的userAgent deviceInfo; // Node.js环境没有userAgent,用主机名替代 if (typeof window !== "undefined") { deviceInfo = window.navigator.userAgent; } else { deviceInfo = require('os').hostname(); } // 可选配置 // 如果不设置版本,LxCommunicator.WebSocket会自动拉取版本 // 该版本用于判断Miniserver是否支持加密和Token //LxCommunicator.setConfigVersion("9.3.2.20"); // 获取LxCommunicator.WebSocketConfig构造器,简化后续调用 var WebSocketConfig = LxCommunicator.WebSocketConfig; // 实例化配置对象,后续传给LxCommunicator.WebSocket var config = new WebSocketConfig(WebSocketConfig.protocol.WS, uuid, deviceInfo, WebSocketConfig.permission.APP, false); // 可选:绑定委托对象,即可响应委托回调 config.delegate = delegateObj; // 实例化LxCommunicator.WebSocket,即实际和Loxone服务通信的WebSocket var socket = new LxCommunicator.WebSocket(config); // 只需提供主机、用户名、密码,即可打开和Miniserver的WebSocket连接 socket.open("loxoneserver", "loxoneuser", "loxonepassword").then(function() { socket.send("jdev/sps/enablebinstatusupdate").then(function(respons) { console.log("成功执行'" + respons.LL.control + "',返回码" + respons.LL.Code + ",返回值" + respons.LL.value); }, function(err) { console.error(err); process.exit(-1); }); }, function(e) { console.error(e); });
补充说明
- 若代码中
getUUID方法未定义,可自行实现简单的UUID生成逻辑,或直接用固定的设备唯一标识 - 生产环境建议增加消息堆积、客户端心跳检测逻辑,避免异常连接占用资源
内容的提问来源于stack exchange,提问作者jogoe
相关产品推荐
相关产品推荐

