Node.js如何在'data'事件中访问SerialPort路径 承诺和异步/等待

问题描述

我正在使用nodejs中的SerialPort库列出可用端口,并将数据发送到每个端口。如果其中任何一个返回“ OK”,我想找出返回它的端口:

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

很明显,在返回数据时,rtuSocket将是一个不同的变量。有没有办法知道哪个端口正在返回.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',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,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更加容易推理。为此,您需要转换代码以返回承诺:

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

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

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

现在,尽管现在无法使用forEachmapfilter或任何数组方法,但for循环更易于理解。如果要使用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();