Nodejs 如何在 'data' 事件上访问 SerialPort 路径

Nodejs how to access SerialPort path on 'data' event

我正在使用 nodejs 中的 SerialPort 库来列出可用端口,并向每个端口发送数据。如果其中任何一个 return “OK”,我想找出 return 是哪个端口:

SerialPort.list().then(ports => {
            ports.forEach(port => {
                    var rtuSocket = new SerialPort(port.path, { baudRate: 9600 }, (err, data) => {
                        rtuSocket.on('data', (err, data) => {
                            console.log(rtuSocket.path)
                            console.log("[RTU][CONNECTED]")
                        })
                        rtuSocket.write("AT")
                    })
            })
        })

很明显,rtuSocket 在时间数据 return 之前将是一个不同的变量。有没有办法知道哪个端口正在 returning .on("data") 中的数据?

您需要某种超时来检测端口是否没有响应。我还强烈建议您检查响应数据并发送比简单的“AT”命令更多的东西,因为许多其他设备响应 AT 命令,例如游戏 PC 的 RGB 控制器和一些配置为调制解调器的 Android 手机。

像下面这样的东西应该可以工作:

function checkPort (path, callback) { // callback(error, path)
    let sock = new SerialPort(path, { baudRate: 9600 }, (err, data) => {
        let timer = setTimeout(() => {
            callback(new Error('Timeout'));
        }, 100); // 100ms should be enough. If not increase it

        sock.on('data', (err, data) => {
            clearTimeout(timer); // clear the timer

            if (err) {
                return callback(err);
            }
            else {
                return callback(null, path);
            }
        })
        sock.write("AT");
    })
}

现在您可以检查哪个端口已连接:

function findConnectedPort (callback) {
    SerialPort.list().then(ports => {

        portCount = ports.length;

        ports.forEach(port => {
            checkPort(port.path, (err, foundPath) => {
                if (err) {
                    // Ignore errors or deal with them how you want
                }
                else {
                    // Great! Got response. Return the path:

                    if (portCount > 0) { // prevent calling callback
                                         // more than once
                       
                        callback(null, foundPath);
                    }
                    portCount = 0;
                }

                portCount--;

                if (portCount <= 0) {
                    // Well, none of the ports responded so we
                    // return an error:

                    callback(new Error('Not found'));
                }
            })
        })
    })
}

现在要找到连接的端口,只需执行以下操作:

findConnectedPort((err,path) => {
    if (err) {
        console.error(err);
    }
    else {
        console.log("RTU CONNECTED at " + path);

        // Do what you need with the port here...
    }
})

承诺和async/await

虽然上面的代码有效。对于像这样需要大量条件逻辑的异步代码,我发现使用 async/await 更容易推理。为此,您需要将代码转换为 return promises:

function checkPort (path) {
    return new Promise((resolve, reject) => {
        let sock = new SerialPort(path, { baudRate: 9600 }, (err, data) => {
            let timer = setTimeout(() => {
                reject(new Error('Timeout'));
            }, 100); // 100ms should be enough. If not increase it

            sock.on('data', (err, data) => {
                clearTimeout(timer); // clear the timer

                if (err) {
                    return reject(err);
                }
                else {
                    return resolve(path);
                }
            })
            sock.write("AT");
        })
    });
}

现在 for 循环更容易理解,尽管现在您不能使用 forEachmapfilter 或任何数组方法。如果要使用 async/await:

,则需要使用 forwhile
async function findConnectedPort () {
    let ports = await SerialPort.list();

    for (let i=0; i<ports.length; i++) {
        let port = ports[i];

        try {
            // return the first successful result:
            return await checkPort(port.path);
        }
        catch (err) {
            // ignore errors or handle them how you like
            // just remember that we use an error to signal
            // a timeout which simply means no device
            // responded
        }
    }

    // we didn't find anything. In this case I prefer to return
    // nothing instead of returning an error:

    return null;
}

现在您可以通过以下操作简单地获取连接的端口:

async function main () {

    let connectedPath = await findConnectedPort();

    if (connectedPath === null) {
        console.log('No devices found!');
    }
    else {
        // Do what you need with the port here...
    }
}

main();