メールを受信すると、raspberrypi3のカメラで撮影し、
メールに添付して指定のメールアドレスに送信するスクリプト。
子供や愛犬の見守りなど目的は同じになるが、
玄関の施錠をしたか?を最寄りの駅で気になった場合に
万が一の為に戻りたくないので作成。
玄関が開き戸だったら、もっといろいろな仕掛けができたのだが・・・。
補足
メール部分は自分でサーバ建てるのが大変なので、
Gmailを利用し、node.jsを使ってメールの送信を常に監視し、
監視中にメールが来るとそれをトリガーにして
カメラで撮影、メールを送信する。
node.jsは『非同期スクリプト』であるため、
fs等を使う場合は、同期させた処理を行う必要がある。
ここで、嵌ってしまった・・・。
カメラの処理に時間がかかり、ファイルが生成される前に
メール送信のためのファイル加工が動作してしまい、
エラーが返って来てしまうので、
別々に動作確認が終わったら、promise 等で同期処理をさせる。
前提
・raspberry-pi3のカメラモジュールを認識済み
・Gmailのアカウント取得、安全性の低いアプリの許可」を有効にしてある。
・nodeが動かせること
◆◆◆成果物◆◆◆
'use strict';
var inbox = require('inbox');
//var nodemailer = require('nodemailer');
//var iconv = require('iconv');
//var conv = new iconv.Iconv("UTF-8", "UTF-8");
const simpleParser = require('mailparser').simpleParser;
var client = inbox.createConnection(false, 'imap.gmail.com', {
secureConnection: true
,auth: {
user:'Gmailアカウント@gmail.com'
,pass:'Gmailパスワード'
}
});
client.on('connect', function() {
console.log('connected');
client.openMailbox('INBOX', function(error) {
if (error) throw error;
});
});
client.connect();
client.on("new", function(message) {
console.log('日時:' + message.date);
console.log('送信者:' + message.from.name + '-' + message.from.address);
console.log('タイトル:' + message.title);
var stream = client.createMessageStream(message.UID);
simpleParser(stream)
.then(mail=> {
console.log('本文(HTMLテキスト):' + mail.textAsHtml);
})
.catch(err=> {
console.log(err);
});
//node.jsはデフォルトで非同期処理を行うため、
//asyncを用いてカメラがsnap.jpgを生成するのを待ち
//Gmailの送信(snap.jpgの添付)、snap.jpgの削除を行っている
//pi-cameraでは上書き保存ができないため、メール送信後に削除しておく。
const async = require('async'); //同期処理のためasync呼び出す
async.series([
function(callback) {
console.log('カメラの処理開始');
//pi-camera の動作ここから
const PiCamera = require('pi-camera');
const myCamera = new PiCamera({
mode: 'photo',
output: `${ __dirname }/snap.jpg`,
width: 640,
height: 480,
nopreview: true,
});
myCamera.snap()
.then((result) => {
// Your picture was captured
})
.catch((error) => {
// Handle your error
});
//pi-camera の動作ここまで
//安全をみて7秒ディレイ
setTimeout(callback, 7000);
}, function(callback) {
console.log('メールの返信開始');
//Gmailで送信ここから
var nodemailer = require('nodemailer')
var fs = require('fs');
// メッセージ内容
var message = {
from : '送信元@gmail.com',
to : '送信先@gmail.com',
subject : 'Reply to request',
text : 'Reply to request,Picture of the Pi-Camera !',
attachments : [{
filename: 'snap.jpg',
content: fs.readFileSync('snap.jpg') //カメラのデータ生成待ち
}]
};
var smtpConfig = {
host: 'smtp.gmail.com',
port: 465,
secure: true, // SSL
auth: {
user : 'Gmailアカウント@gmail.com',
pass : 'Gmailパスワード'
}
};
var transporter = nodemailer.createTransport(smtpConfig);
transporter.sendMail(message, function(err, response) {
console.log(err || response);
});
//ファイル削除
try {
fs.unlinkSync('snap.jpg');
console.log('snap.jpgを削除しました。');
} catch (error) {
throw error;
}
//Gmailで送信ここまで
setTimeout(callback, 1000);
}, function(callback) {
return console.log('処理終了');
}
], function(err, results) {
if (err) {
return console.log('err[' + err + ']');
}
});
}); // client.connect() を閉じる。
コマンド自体はプロンプト状態なので停止はcrtl+Zにて行う。
sshで操作する場合は、forever等で動かさないと、ターミナル閉じた瞬間に
Killされるので注意が必要。
◆◆動作部分解説◆◆
◆メール受信トリガー部分◆
node.jsのパッケージインストール
$ npm install inbox
$ npm install mailparser
まんま、@hideito2000様の掲載内容を使わせていただいた。
//ソース
client.on("new", function(message) {
console.log('日時:' + message.date);
console.log('送信者:' + message.from.name + '-' + message.from.address);
console.log('タイトル:' + message.title);
var stream = client.createMessageStream(message.UID);
simpleParser(stream)
.then(mail=> {
console.log('本文(HTMLテキスト):' + mail.textAsHtml);
})
.catch(err=> {
console.log(err);
});
//この部分にカメラ処理とメール送信を組み込む
});
//ソースここまで
◆pi-cameraのインストール◆
$ npm install pi-camera
作成者のページのサンプルをそのまま使う
//ソース
const PiCamera = require('pi-camera');
const myCamera = new PiCamera({
mode: 'photo',
output: `${ __dirname }/snap.jpg`,
width: 640,
height: 480,
nopreview: true,
});
myCamera.snap()
.then((result) => {
// Your picture was captured
})
.catch((error) => {
// Handle your error
});
//ソースここまで
◆nodemailer でメールを送信させるので、インストール◆ $ npm i -D nodemailer
ソースは皆さまの内容を参照させていただいた。
ありがとうございます。
//ソース
var mailer = require('nodemailer');
mailer.SMTP = {
host: 'smtp.gmail.com',
port: 465,
secure: true, // SSL
auth: {
user : 'Gmailのid@gmail.com,
pass : 'Gmailのパスワード'
}
};
fs.readFile("./snap.jpg", function (err, data) {
mailer.send_mail({
sender: '送信元@gmail.com',
to: '送信先@gmail.com',
subject: 'snapshot-Ent!',
body: 'Snapshot of the Entrance !',
attachments: [{'filename': 'snap.jpg', 'content': picture}]
}), function(err, success) {
if (err) {
// Handle error
}
}
});
//ソースここまで
◆ファイルの削除◆
try {
fs.unlinkSync('snap.jpg');
console.log('snap.jpgを削除しました。');
} catch (error) {
throw error;
}
fsは非同期だが、同じコマンドであれば記載の順に動くようだ。
駄目な場合は、 async の回数を増やせば良い。
◆同期処理◆
async.series([
function(callback) {
console.log('処理開始');
このcallback間にメソッドを記載
setTimeout(callback, 1000);
}, function(callback) { console.log('処理2開始');
setTimeout(callback, 1000);
});
}, function(callback) {
return console.log('処理終了');
}
],
期待した動きができたので、満足。