2015年1月12日月曜日

Play!アプリとBoneScriptの通信 - 3.BoneScript

「BBBとは?」みたいな余計な説明がなくて中身が濃い。

というわけで、Play!アプリとBoneScriptの通信、完結編です。

  1. 構成
  2. Playアプリ
  3. BoneScript

■BoneScript■

以前、BoneScriptで7セグメントLEDを駆動したら、毎秒170桁しかダイナミック点灯させることができずにちらつきました。その際には各セグメントのon/offもループしていたのでおよそ毎秒7x170回はループしていた、ということになります。ダイナミック点灯は無理でも毎秒10回程度のサンプリングなら余裕ですね。8bit時代のBASICマイコンで空のFOR〜NEXTループを回すと250回ぐらいだったかなぁ(遠い目)。

ということで、以下ソースです。
// Read PIR, Write csv, Push to ShowSensor
var b = require('bonescript');
var fs = require('fs');
var http = require('http');
var useLED = false;
var LED = 'USR3';
b.pinMode('P8_19', b.INPUT);
setInterval(checkPIR, 100); // Checks the Sensor Every 0.1 Seconds
var limitCurrentHour = 12;
var limitPrevHour = limitCurrentHour -1;
var filename = null;
var isStart = false;
var countDetected = 0;
var prevMinute = 99;
var prevHour = 99;
function checkPIR(){
b.digitalRead('P8_19', printStatus);
}
function printStatus(x) {
var tokei = new Date();
var sec = tokei.getSeconds();
var min = tokei.getMinutes();
var hour = tokei.getHours();
var day = tokei.getHours();
if (min != prevMinute) {
if (prevHour == 99) prevHour = hour;
if (prevMinute == 99) {
if (sec == 0) {
prevMinute = min;
}
} else {
if (filename == null) {
var tempTokei = tokei;
if (hour <= limitPrevHour) {
tempTokei.setTime(tokei.getTime() - 24*3600*1000);
}
filename = getStrFilename(tempTokei);
}
if (prevHour == limitCurrentHour-1 && hour == limitCurrentHour) {
filename = getStrFilename(tokei);
}
var sDate = formatDate(tokei, "YYYY-MM-DD hh:mm");
var sCount = Math.round(countDetected/10);
var s = sDate + "," + sCount;
console.log(s);
fs.appendFile(filename, s + "\n", function(err) {
if (err) console.log(err);
});
// http://stackoverflow.com/questions/4505809/how-to-post-to-a-request-using-node-js
var body = JSON.stringify({
date: sDate,
count: sCount,
email: "mail@foo.com"
});
console.log(body);
var request = new http.ClientRequest({
hostname: "192.168.0.70",
// hostname: "infinite-reaches-8771.herokuapp.com",
port: 80,
path: "/receive",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body)
}
});
request.on('response', function (response) {
response.on('data', function (chunk) {
});
response.on('error', function (chunk) {
console.log('BODY: ' + chunk);
});
});
request.write(body);
request.end();
prevMinute = min;
}
prevHour = hour;
countDetected = 0;
}
if (x.value == 1) { // detected
countDetected ++;
}
if (useLED) b.digitalWrite(LED, x.value);
}
function getStrFilename(x) {
var str = '/root/' + formatDate(x, "YYYY-MM-DD") + '.txt';
console.log("filename=" + str);
return str;
}


特に目新しいことはしていません(できません)。line 11で100m秒ごとのインターバルを設定してchechPIRを呼び出し、digitalReadのコールバックとしてprintStatusを呼び出しています。

printStatusでは100m秒ごとにサンプリングして入力がHIGHならcountDetectedをインクリメントし、「1分間のうち何秒間、PIRセンサがHIGHを返してくるか(なおPIRセンサは負論理で動きを検出するとLOWになるのですが、トランジスタでレベル変換した時に正論理に変わってます)」を求めています。結果はCSVとしてファイルに書き出し(line no 56 - 62)、JsonとしてWeb APIに送っています(line no 64 - 94)。

その処理自体は簡単なのですが、起動直後の中途半端な「分」を無視したり(prevMinute==99)、「睡眠記録」として作ったので昼の12時でファイル名が切り替わるようにしたりで(line no 44 - 54)、ちょっと面倒になっています。

なお、日付書式の変換には下記で公開されている「formatDate」を使わせていただきました。ありがとうございます。上記ソースを試す場合には末尾にformatDateをコピペしてください。
Qiita : 日付フォーマットなど 日付系処理

■今後の予定■

現状ではセンサーを追加したらDBの定義からやり直さなければいけないですが…それはなんぼ何でもIoTっぽくないので、定義を抽象化するなりシリアライズして「思いついたらすぐセンサーを追加してグラフ化」という路線を目指してみましょうか。

そういえばXivery申し込んだんだけど、返事が来ない…まぁXiveryを使っていたら、Play!でグラフ化するなんてことをやろうとは思わなかったでしょうから、むしろ感謝すべきかなw

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。