2015年2月11日水曜日

Beaglebone black(bonescript)からメールを送る

サランラップ+お湯で柔らかくなるプラスチックによる雑な仕事w

まず、SMTPサーバを入れてその設定、次にBoneScriptを書く。

SMTPサーバの入れ方はこちら。とても参考になりました、ありがとうございます。
記事との相違点はMacではなくBeagleboneなので「brew/aptitudeの替わりに apt-get を使う」ことと、設定ファイルの中身です。蛇足ですが、fromとuserは同じでOKです。設定したら記事にあるように、テストしてみてください。

で、BoneScriptで書いてみます。Node.jsから直接SMTPを呼び出せるmailなどのモジュールも試してみたのですが、エラーの山を解決することができなかったので、child processとして呼び出す方式にしました。

var b = require('bonescript');
var exec = require('child_process').exec, child;
var fs = require('fs');
var filename = '/root/test.msg';
function sendMessage(to, subject, message) {
// create message file
var msg = 'To: ' + to + '\n' + 'Subject: ' + subject + '\n' + message + '\n';
fs.writeFileSync(filename, msg);
// send it
child = exec('msmtp -t < ' + filename, function(error, stdout, stderr) {
if (stdout != null) console.log('stdout:' + stdout);
if (error != null) {
if (stderr != null) console.log('stderr:' + stderr);
console.log(error);
}
});
}
sendMessage('mail@example.com', 'this is subject', 'たれぱんだはとてつもなくかわいい');
view raw gistfile1.js hosted with ❤ by GitHub



メール系のテストをするとこうなるよねw

さて。

この度、玄関にもPIRセンサーを取り付けました。恐ろしいことに15mのワイヤ(余ってた6芯の電話線)による有線接続ですw センサーをほどよくナナメに固定するのは結構難しいのですが、玩具として売られているお湯で柔らかくなるプラスチックを使いました。80度のお湯に3分ほどつけておくと練り消しゴム状態になり、好きな形に成型してから冷します。プラスチックというよりもスーパーゴムのような素材なので、パッキングがわりに使ったり、断線しやすいiPhoneコネクタの補強、壊れた自転車用パーツの補修などに使えると思います。これでまた3Dプリンタの購入が遠ざかってしまいました(笑)。

これだけ入って1080円

なお、お湯を保温性のあるカップにいれて作業場所まで持っていくのがコツです。PIRセンサーを覆うように形を作っておき、反対側を冷たいドアに押し付けると丁度いい角度に調整することができます。私は面倒くさいので養生テープで止めちゃいましたが、プラスチックの中に磁石埋め込めばそのまま固定できると思います。電子工作において、「ナナメ固定」は結構鬼門ですが、これはホントに便利です。安いし。

養生テーブが泣かせます
先日の「自室での人間の動きを記録するアプリ」をちょっと改造して、来客を検知したらメールを送るようにしてみました。

これで留守番中に間違ってドアチェーンをかけてしまって外出中のヨメを締め出してしまっても大丈夫だ(ごめん)。

うちは宅配便ぐらいしか来ない&廊下の端で他の住民が通らないから通知ごとに送るようにしていますが、人通りの多いところでは一度送ったら数分間は検出しても送らない、などの工夫が必要かもしれないですね。
// Read PIR, Write csv, Push to ShowSensor
//
// 2015-02-11 : add function : send email when out door sensor detect a visitor
//
var b = require('bonescript');
var fs = require('fs');
var http = require('http');
var exec = require('child_process').exec, child; // for mail
var mailfile = '/root/sendmail.msg'; // for mail
var useLED = true;
var LED = 'USR3';
var pirInRoom = 'P8_19';
var pirOutDoor = 'P8_18';
b.pinMode(pirInRoom, b.INPUT);
b.pinMode(pirOutDoor, b.INPUT);
setInterval(readStatus, 100); // Checks the Sensor Every 0.1 Seconds
var limitCurrentHour = 12;
var limitPrevHour = limitCurrentHour -1;
var filename = null;
var isStart = false;
var countInRoom = 0;
var countOutDoow = 0;
var prevMinute = 99;
var prevHour = 99;
function readStatus() {
var outDoor = b.digitalRead(pirOutDoor);
var inRoom = b.digitalRead(pirInRoom);
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);
// filename = '/root/' + formatDate(tempTokei, "YYYY-MM-DD") + '.txt';
// console.log("filename=" + filename);
}
if (prevHour == limitCurrentHour-1 && hour == limitCurrentHour) {
filename = getStrFilename(tokei);
// filename = '/root/' + formatDate(tokei, "YYYY-MM-DD") + '.txt';
// console.log("filename=" + filename);
}
var sDate = formatDate(tokei, "YYYY-MM-DD hh:mm");
var sInRoom = Math.round(countInRoom /10);
var sOutDoor = Math.round(countOutDoor/10);
var s = sDate + "," + sInRoom + "," + sOutDoor;
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: sInRoom,
outdoor: sOutDoor,
email: "mail@example.com"
});
console.log(body);
try {
pushData(body);
if (sOutDoor > 10) {
sendMessage('mail@example.com', '来客?', 'カウント=' + sOutDoor);
}
} catch(e) {
console.log(body);
}
prevMinute = min;
}
prevHour = hour;
countInRoom = countOutDoor = 0;
}
if (inRoom == 0) { // detected
countInRoom ++;
}
if (outDoor == 1) {
countOutDoor ++;
}
if (useLED) b.digitalWrite(LED, outDoor);
}
function pushData(inBody) {
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(inBody)
}
});
request.on('response', function (response) {
response.on('data', function (chunk) {
});
response.on('error', function (chunk) {
console.log('BODY: ' + chunk);
});
});
request.write(inBody);
request.end();
}
function getStrFilename(x) {
var str = '/root/' + formatDate(x, "YYYY-MM-DD") + '.txt';
console.log("filename=" + str);
return str;
}
function sendMessage(to, subject, message) {
// create message file
var msg = 'To: ' + to + '\n' + 'Subject: ' + subject + '\n' + message + '\n';
fs.writeFileSync(mailfile, msg);
// send it
child = exec('msmtp -t < ' + mailfile, function(error, stdout, stderr) {
if (stdout != null) console.log('stdout:' + stdout);
if (error != null) {
if (stderr != null) console.log('stderr:' + stderr);
console.log(error);
}
});
}
// http://qiita.com/osakanafish/items/c64fe8a34e7221e811d0
/**
* 日付をフォーマットする
* @param {Date} date 日付
* @param {String} [format] フォーマット
* @return {String} フォーマット済み日付
*/
var formatDate = function (date, format) {
if (!format) format = 'YYYY-MM-DD hh:mm:ss.SSS';
format = format.replace(/YYYY/g, date.getFullYear());
format = format.replace(/MM/g, ('0' + (date.getMonth() + 1)).slice(-2));
format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2));
format = format.replace(/hh/g, ('0' + date.getHours()).slice(-2));
format = format.replace(/mm/g, ('0' + date.getMinutes()).slice(-2));
format = format.replace(/ss/g, ('0' + date.getSeconds()).slice(-2));
if (format.match(/S/g)) {
var milliSeconds = ('00' + date.getMilliseconds()).slice(-3);
var length = format.match(/S/g).length;
for (var i = 0; i < length; i++) format = format.replace(/S/, milliSeconds.substring(i, i + 1));
}
return format;
};
view raw gistfile1.js hosted with ❤ by GitHub


0 件のコメント:

コメントを投稿

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