はじめに
LINEBotでRaspberryPiで写真を撮って送るという、カメラ装置です。
ハッカソンで作成したねこしぇるじゅ-自慢の猫をとにかく拡散!- | ProtoPediaの一部をupdateしたものです。
2020/05/12追記
完成版追記しました
概要
LINEBotからRaspberryPiを動かして写真を撮り、Gyazoに送って写真をLINEに送るものです。
LINEBotでRaspberryPiを動かしています。
RaspberryPi node.js ngrok Gyazo API という感じです。
できたもの
ねこIoTLTでも発表した、にゃんこのぞき見LINEBot!#IoTLT #protoout pic.twitter.com/0FXWXu2uB8
— 3yaka (@3yaka4) May 7, 2020
使い方
RaspberryPiを猫がよくいる場所に置きます。
猫が見たいので LINEBotに「ねこ」と入れます。
(「ねこ」以外のワードには「何が見たいの?」と返してきます。)
写真を撮るのに時間がかかるので、「写真撮ってくるから待っててねー」、とつなぎのワードが入ります。
10秒ほどすると写真が送られてきます。
環境
MacBook Pro macOS Mojave
Visual Studio Code 1.44.0
RaspberryPi 3B
Release: 10
Codename: buster
Node.js v12.16.3
npm v6.14.4
Pi camera
洗濯バサミ
Raspberry Piの準備
こちらを参考にnode.jsとnpmの最新版を入れましょう。
Raspberry PiにNode.jsとnpmの最新版をインストールする - Qiita
そのほかで必要なnpmはこちら
//Gyazo API
$ npm i gyazo-api
// LINEbot SDK
$ npm i @line/bot-sdk express
//ngrok
$ wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-arm.zip
//ngrokのzipを解凍する
$ unzip ngrok-stable-linux-arm.zip
コード(promise失敗)
'use strict';
const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;
const Gyazo = require('gyazo-api');
const gyazoclient = new Gyazo('Your access token');
const config = {
channelSecret: '***',
channelAccessToken: '***'
};
const app = express();
app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用
app.post('/webhook', line.middleware(config), (req, res) => {
console.log(req.body.events);
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result));
});
const client = new line.Client(config);
async function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
let mes = event.message.text;
if (event.message.text.match("ねこ")) {
await client.replyMessage(event.replyToken, {
type: "text",
text: '写真を撮ってくるからちょっと待っててね'
});
await nyanpi();
return nyancoPic(event.source.userId);
}
else {
return client.replyMessage(event.replyToken, {
type: "text", text: '何が見たいのかな?'
});
}
}
//picameraで写真を撮って送る
const nyanpi = async (userId) => {
const PiCamera = require('pi-camera');
const myCamera = new PiCamera({
mode: 'photo',
output: `${__dirname}/nyan.jpg`,
width: 640,
height: 480,
nopreview: true,
});
await myCamera.snap()
.then((result) => {
console.log("ok");
gyazoclient.upload('./nyan.jpg', {
title: "my picture",
desc: "upload from nodejs"
})
.then((res) => {
console.log("送った");
})
.catch((err) => {
console.error(err);
console.log("送レナカッタ");
});
})
.catch((error) => {
// Handle your error
});
}
//Gyazoの最新の写真のURLをとってくる
const nyancoPic = async (userId) => {
let gyazoimgUrl = '';
await gyazoclient.list()
.then(function (response) {
console.log(response.data[0]);
gyazoimgUrl = `${response.data[0].url}`;
console.log(gyazoimgUrl);
})
.catch(function (err) {
console.error(err);
});
await client.pushMessage(userId, {
type: 'image',
originalContentUrl: gyazoimgUrl,
previewImageUrl: gyazoimgUrl
});
}
app.listen(PORT);
console.log(`Server running at ${PORT}`);
動いていないところ
最新じゃなくて1個前の写真しか持ってこれない。
await/asyncがうまく使えていない感じ。。。
OKと送ったというconsole.logの間でGyazoに取りに行っちゃう
(ログ↓)
ok
{
image_id: '***',
permalink_url: 'https://api.gyazo.com/***',
url: 'https://i.gyazo.com/f***',
metadata: {
app: null,
title: 'my picture',
url: null,
desc: 'upload from nodejs'
},
type: 'jpg',
thumb_url: 'https://thumb.gyazo.***ApieIALnjo-jpg.jpg',
created_at: '2020-05-07T01:06:27+0000'
}
https://i.gyazo.com/***.jpg
送った
完成した!!!
2020/05/12追記
'use strict';
const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;
const Gyazo = require('gyazo-api');
const gyazoclient = new Gyazo('Your access token');
const config = {
channelSecret: '***',
channelAccessToken: '***'
};
const app = express();
app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用
app.post('/webhook', line.middleware(config), (req, res) => {
console.log(req.body.events);
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result));
});
const client = new line.Client(config);
async function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
let mes = event.message.text;
if (event.message.text.match("ねこ")) {
await client.replyMessage(event.replyToken, {
type: "text",
text: '写真を撮ってくるからちょっと待っててね'
});
await nyanpi();
return nyancoPic(event.source.userId);
}
else {
return client.replyMessage(event.replyToken, {
type: "text", text: '何が見たいのかな?'
});
}
}
const nyanpi = async (userId) => {
const PiCamera = require('pi-camera');
const myCamera = new PiCamera({
mode: 'photo',
output: `${__dirname}/nyan.jpg`,
width: 640,
height: 480,
nopreview: true,
});
await myCamera.snap()
await gyazoclient.upload('./nyan.jpg', {
title: "my picture",
desc: "upload from nodejs"
})
}
const nyancoPic = async (userId) => {
const response = await gyazoclient.list()
const gyazoimgUrl = response.data[0].url;
return client.pushMessage(userId, {
type: 'image',
originalContentUrl: gyazoimgUrl,
previewImageUrl: gyazoimgUrl
});
}
app.listen(PORT);
console.log(`Server running at ${PORT}`);
RaspberyPiがわ 2つターミナルを開きます
node neko2.js
ngrog http 3000
起動ごとにwebhookおアドレスは変わるので都度 Messaging API settingsでngrokのアドレスを変える
参考サイト
20200504 raspberrypi handson_honpen
Node.jsでラズパイのカメラモジュールを使う – plog
gyazo-api - npm
raspbian(Raspberry Pi)のバージョン確認方法
感想
Piカメラ音がしないのでお猫様をこっそり撮影できて良い〜
スマホのシャッター音に慣れすぎか。
promise難しい。。。