目的
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>


