LINEBotからRaspberryPiで写真を撮ってLINEにおくる！

### はじめに
LINEBotでRaspberryPiで写真を撮って送るという、カメラ装置です。
ハッカソンで作成した[ねこしぇるじゅ\-自慢の猫をとにかく拡散！\- \| ProtoPedia](https://protopedia.net/prototype/a07c2f3b3b907aaf8436a26c6d77f0a2)の一部をupdateしたものです。
2020/05/12追記
完成版追記しました

### 概要
LINEBotからRaspberryPiを動かして写真を撮り、[Gyazo](https://gyazo.com/api?lang=ja)に送って写真をLINEに送るものです。
LINEBotでRaspberryPiを動かしています。
RaspberryPi node.js ngrok Gyazo API という感じです。

### できたもの
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ねこIoTLTでも発表した、にゃんこのぞき見LINEBot！<a href="https://twitter.com/hashtag/IoTLT?src=hash&amp;ref_src=twsrc%5Etfw">#IoTLT</a> <a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://t.co/0FXWXu2uB8">pic.twitter.com/0FXWXu2uB8</a></p>&mdash; 3yaka (@3yaka4) <a href="https://twitter.com/3yaka4/status/1258265976845398016?ref_src=twsrc%5Etfw">May 7, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


#### 使い方
RaspberryPiを猫がよくいる場所に置きます。
猫が見たいので　LINEBotに「ねこ」と入れます。
（「ねこ」以外のワードには「何が見たいの？」と返してきます。）
写真を撮るのに時間がかかるので、「写真撮ってくるから待っててねー」、とつなぎのワードが入ります。
10秒ほどすると写真が送られてきます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282291/64e41b23-239a-f304-e8c2-fa0838f661c0.png">

### 環境
```
MacBook Pro macOS Mojave
 Visual Studio Code 1.44.0

RaspberryPi ３B
 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](https://qiita.com/mascii/items/77c685df65c4cbca9315)
そのほかで必要な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失敗)
```node.js
'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}`);

```



### 動いていないところ
最新じゃなくて１個前の写真しか持ってこれない。
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追記

```node.js

'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](https://www.slideshare.net/kitazaki/20200504-raspberrypi-handsonhonpen-233085316)
[Node\.jsでラズパイのカメラモジュールを使う – plog](https://plog.plane-plan.com/node-js%E3%81%A7%E3%83%A9%E3%82%BA%E3%83%91%E3%82%A4%E3%81%AE%E3%82%AB%E3%83%A1%E3%83%A9%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%92%E4%BD%BF%E3%81%86/)
[gyazo\-api \- npm](https://www.npmjs.com/package/gyazo-api)
[raspbian（Raspberry Pi）のバージョン確認方法](https://www.checksite.jp/raspbian-version-check/)

### 感想
Piカメラ音がしないのでお猫様をこっそり撮影できて良い〜
スマホのシャッター音に慣れすぎか。

promise難しい。。。