【追記】Node.jsでsocket.ioを使ってserialportの受信データをブラウザモニタリング


これは色々応用できそうなので最小構成を記事にしようかと

今回シリアルデータのソースはArduinoの赤外線リモコンの受信値をそのままUSBシリアルに流したものを利用したが
基本的にArduinoのなんらかのセンサーで受信した情報をSerial.println()で送ればなんにでも応用はできるんじゃないかと

前準備はこんな感じ

mkdir serial_monitor
cd serial_monitor
npm init -y
npm install ejs serialport socket.io

その他にプロジェクトディレクトリにindex.jsとindex.ejsを作成し以下の様な内容

index.js
const app = require('http').createServer(requestHandler);
const io = require('socket.io')(app);
const fs = require('fs');
const ejs = require('ejs');
const ip = "127.0.0.1";

const page = fs.readFileSync(__dirname + '/index.ejs', 'utf-8');

function requestHandler(req,res){
    var output = null;
    console.log(req.url);
    switch(req.url)
    {
        case '/':
            res.writeHead(200,{'Content-Type': 'text/html'});
            output = ejs.render(page,{ip:ip});
            break;
    }
    if(output !== null)
    {
        res.write(output);
    }
    res.end();
}

const serialport = require('serialport');
const portName = 'COM3';// /dev/ttyACM0, /dev/ttyUSB0などOSによって適宜選択
const sp = new serialport(portName,{
    baudRate: 9600,
    dataBits: 8,
    parity: 'none',
    stopBits: 1,
    flowControl: false,
});

const Readline = serialport.parsers.Readline;
const parser = new Readline();
sp.pipe(parser);

io.on('connection', (socket)=>{
    parser.on('data', (data)=>{
        console.log(data);
        socket.emit('status', { message: data });
    });
});

app.listen(3000);
console.log('Ready!');
index.ejs
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <title>TEST</title>
</head>
<body>
    <div id="message">message waiting...</div>
    <script type="text/javascript">
    </script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
    var socket = io('http://<%=ip%>:3000');
    socket.on('status', (data)=>{
        document.getElementById('message').innerText = data.message.trim();
    });
    </script>
</body>
</html>
node index.js

で実行しブラウザで開くと初期画面が表示され

↓シリアル信号を受信すると


のようにブラウザ画面にリアルタイムに受信情報が反映される

【追記】

上記のコードを使用した場合ブラウザのリロードで際限なくparser.on('data',…)のイベントが積み重なってしまうため
(イベント発生毎にconsole.logを吐かせてたら酷い事になってた)
それに対しての修正案
disconnect字に適宜切断する事が必要だと分かったので受信系と通知系を分離するのが望ましいかと…

index.js
+var message=null;
// メイン受付用(双方向通信など送信、書き込み系処理はすべてこちらで行う)
+parser.on('data',masterReciever);
+function masterReciever(data){
+        console.log(data);
+        message=data;
+}
io.on('connection', (socket)=>{
-    parser.on('data', (data)=>{
-        console.log(data);
-        socket.emit('status', { message: data });
-    });
// Socket通信の為のシリアルレシーバー(状態の通知のみで書き込みなどは行わないこと)
+    parser.on('data',slaveReciever);
//   切断時Removeの為関数化
+    function slaveReciever(data){
+        console.log(data);
+        socket.emit('status', { message: message});
+    }
// ブラウザ切断時は必ずparser.on('data',…)イベントを解除する
+    socket.on('disconnect',()=>{
+        parser.removeListener('data',slaveReciever);
+    });
});