目的
Raspberry PiでEnOceanセンサデータを受信し、ブラウザ(localhost)上でリアルタイムに見れるようにしたい。WebSocketを扱う場合、PythonよりもNode.jsの方が簡単そうだったので実装してみた。
Node.jsのバージョンはv6.9.1。今のところ、MacOS 10.12.1(Sierra)で動作を確認している。
EnOceanの受信にはnode-enoceanを利用。今回使っているのは以下4種類のセンサ。
- ドア開閉 (STM431J or CS-EO429J)
- 人感 (HM92-01WHC)
- 温度 (STM429J or CS-EO429J)
- ロッカースイッチ (ESM210R)
実行例
EnOceanのセンサが動作すると、リアルタイムにdatetimeとstate欄の表示が更新される。ソースコード(サーバ側)
USBドングルのデバイス名(ここでは/dev/tty.usbserial-FTYKW2P5)とセンサIDは要変更。また、EnOceanプロトコルについては以前の記事を参照。
// execute at node.js v6.9.1 // サーバ設定 var fs = require("fs"); var http = require("http"); var socketio = require("socket.io"); var server = http.createServer( function(req, res) { res.writeHead(200, {"Content-Type": "text/html" } ); var output = fs.readFileSync("index.html", "utf-8"); res.end(output); }).listen(3000); var io = socketio.listen(server); // EnOcean設定 require("date-utils"); var enocean = require("node-enocean")(); enocean.listen("/dev/tty.usbserial-FTYKW2P5") // サーバからデータ送信 io.sockets.on("connection", function (socket) { // EnOceanの電文を受信 enocean.on("data", function (data) { console.log("============================"); var dt = new Date(); var datetime = dt.toFormat("YYYY/MM/DD HH24:MI:SS"); console.log(datetime); // 電文からdata部を抽出し、センサIDを取得 console.log("raw : "+data["rawByte"]); // 電文本体 body_length = parseInt(data["rawByte"].slice(4,6),16); // data部のbyte数 body = data["rawByte"].slice(12,12+body_length*2); // data部 sid = body.slice(2,10); // センサID console.log("data : "+body); console.log("sid : "+sid); // センサの種類を識別して状態を取得 // ドア開閉 (STM431J or CS-EO429J) if(sid=="0a007cd0"){ sType = "door"; if(body.slice(10,12)=="08") state = "open"; else if(body.slice(10,12)=="09") state = "close"; // 人感 (HM92-01WHC) } else if(sid=="040150a5"){ sType = "motion"; if(body.slice(14,16)=="ff") state = "on"; else if(body.slice(14,16)=="00") state = "off"; // 温度 (STM429J or CS-EO429J) } else if(sid=="040177db"){ sType = "temp"; val = parseInt(body.slice(14,16),16); state = (255.0-val)/255.0*40.0; // ロッカースイッチ (ESM210R) } else if(sid=="002c865a"){ sType = "SW"; if(body.slice(10,12)=="84") state = "SW1-on"; else if(body.slice(10,12)=="88") state = "SW2-on"; else if(body.slice(10,12)=="04") state = "SW1-off"; else if(body.slice(10,12)=="00") state = "SW2-off"; } else { sType = "unknown"; state = null } console.log("state : "+state); // 送信用JSON作成 sensorStr = '{"datetime":"'+datetime+'","type":"'+sType+'","state":"'+state+'"}'; sensorJson = JSON.parse(sensorStr); // WebSocketでJSONを送信 io.sockets.emit("sendLog", sensorJson); }); });
ソースコード(クライアント側)
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>WebSocket Sample</title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> <script src="/socket.io/socket.io.js"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <table class="table"> <tr> <th>type</th> <th>datetime</th> <th>state</th> </tr> <tr> <td>door</td> <td><div id="door-dt"></div></td> <td><div id="door-state"></div></td> </tr> <tr> <td>motion</td> <td><div id="motion-dt"></div></td> <td><div id="motion-state"></div></td> </tr> <tr> <td>temp</td> <td><div id="temp-dt"></div></td> <td><div id="temp-state"></div></td> </tr> <tr> <td>SW</td> <td><div id="SW-dt"></div></td> <td><div id="SW-state"></div></td> </tr> </table> <script type="text/javascript"> var s = io.connect(); s.on("sendLog", function (data) { sType = data["type"]; if(sType == "door"){ tgtId = "#door"; } else if(sType == "motion"){ tgtId = "#motion"; } else if(sType == "temp"){ tgtId = "#temp"; } else if(sType == "SW"){ tgtId = "#SW"; } $(tgtId+"-dt").html(data["datetime"]); $(tgtId+"-state").html(data["state"]); }); </script> </body> </html>