LINEでメッセージを送ると メロディを奏でるBOT【IoT連携】【LINE BOT】

LINEでメッセージを送ると メロディを奏でるBOTを作成してみました。

BOTの名前は音符(ONPU)とPUSHをもじって、
"ON-PUSH"にしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/cb27333b-b7dd-d6e2-0444-1aaca3bbf48d.png)

現時点ではバッテリーが備わっていない点、Wi-Fi環境下でないと起動できない点はありますが、よくスマホ等のモノを家でどこに置いたか分からなくなることがあるので、これで好きな曲で探すことができます。

今回は、『きらきら星』の曲を鳴らしています。

##環境
- Windows 10
- Node.js 12.16.1

##必要なもの
[obniz Board](https://obniz.io/ja/products)の購入が必要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/631aec48-cfe4-f22e-a4af-aca7489bf13e.png)

[スピーカー](http://akizukidenshi.com/catalog/g/gP-04118/)の購入が必要です。
(30円で購入できました)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/f25d09b5-8301-cff9-270b-c983a08edb65.png)

##事前準備
[obniz公式サイト](https://docs.obniz.io/ja/guides/board-1y/quick-start/)を参考にWi-Fi設定、簡易プログラムのテストをします
なお、今回使用していませんが、obnizにはノンコーディングでも設計・動作可能な機能があります。

obnizにspeakerを差し込みます。(このspeakerには+-はないので差し込むのみ)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/cc13fd19-c052-db03-ee55-5bc35cc97560.png)

##BOTの動き
obnizとspeakerは音の周波数を指定することでその音階を鳴らすことができるので、
[音階の周波数](https://tomari.org/main/java/oto.html)を参考に『きらきら星』の音符に対応する周波数をコーディングしています。
そのままコーディングすると音がつながって聞こえるため、stop命令で音の区切りを入れています。

画像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/c5a5a111-72b2-5644-8375-eab0eca661f2.png)

実際の動き(音あり)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">obnizでスピーカ接続したメロディ <a href="https://t.co/YDJkcpgTHl">pic.twitter.com/YDJkcpgTHl</a></p>&mdash; Naru0607 (@2E2oAkhgdeMg8Fn) <a href="https://twitter.com/2E2oAkhgdeMg8Fn/status/1248404367947862019?ref_src=twsrc%5Etfw">April 10, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



##コード

```js
'use strict';

// obniz呼び出し
const Obniz = require('obniz');
const obniz = new Obniz("hogehoge1");  // Obniz_ID に自分のIDを入れます

const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
const PORT = process.env.PORT || 3000;

const config = {
    channelAccessToken: 'hogehoge2',
    channelSecret: 'hogehoge3'
};

const app = express();

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);

// obniz接続
obniz.onconnect = async function () {
  obniz.display.clear();
  obniz.display.print("obniz meets LINE Bot!");
}

function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  let mes = ''
  if(event.message.text === '音を鳴らして！'){
    mes = '少々お待ちください'; //待ってねってメッセージだけ先に処理
    getAskObnizSpeaker(event.source.userId); //スクレイピング処理が終わったらプッシュメッセージ
  }else{
    mes = event.message.text;
  }

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: mes
  });
}

const getAskObnizSpeaker = async (userId) => {
 // スピーカーを呼び出す
 const speaker = obniz.wired("Speaker", {signal:0, gnd:1});
 console.log("Speaker")
 await client.pushMessage(userId, {
  type: 'text',
  text: "音を鳴らしています",
});

 // 音階とhzの参考サイト https://tomari.org/main/java/oto.html
 await speaker.play(523.251); // C5 ド
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(523.251); // C5 ド
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(783.991); // C5 ソ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(783.991); // C5 ソ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(880.000); // C5 ラ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(880.000); // C5 ラ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(783.991); // C5 ソ
 await obniz.wait(1600);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(698.456); // C5 ファ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(698.456); // C5 ファ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(659.255); // C5 ミ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(659.255); // C5 ミ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(587.330); // C5 レ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(587.330); // C5 レ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(523.251); // C5 ド
 await obniz.wait(1600);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(783.991); // C5 ソ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(783.991); // C5 ソ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(698.456); // C5 ファ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(698.456); // C5 ファ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(659.255); // C5 ミ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(659.255); // C5 ミ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(587.330); // C5 レ
 await obniz.wait(1600);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(783.991); // C5 ソ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(783.991); // C5 ソ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(698.456); // C5 ファ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(698.456); // C5 ファ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(659.255); // C5 ミ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(659.255); // C5 ミ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(587.330); // C5 レ
 await obniz.wait(1600);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(523.251); // C5 ド
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(523.251); // C5 ド
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(783.991); // C5 ソ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(783.991); // C5 ソ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(880.000); // C5 ラ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(880.000); // C5 ラ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(783.991); // C5 ソ
 await obniz.wait(1600);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(698.456); // C5 ファ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(698.456); // C5 ファ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(659.255); // C5 ミ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(659.255); // C5 ミ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(587.330); // C5 レ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(587.330); // C5 レ
 await obniz.wait(800);
 await speaker.stop();
 await obniz.wait(100);
 await speaker.play(523.251); // C5 ド
 await obniz.wait(1600);
 speaker.stop();
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);
```

以下の部分はご自身のObniz_IDとLINE BOTの情報で更新します。
※Obniz_IDは、Wi-Fi接続が完了するとobniz画面に表示されるものです。

>var obniz = new Obniz("hogehoge1");  // Obniz_ID に自分のIDを入れます
>const config = {
    channelAccessToken: 'hogehoge2',
    channelSecret: 'hogehoge3'


##終わりに
・自身で音の調整をしながら設定するのは単純に楽しかったです。
・最近は画像認識技術も向上しているので、紙ベースの楽譜(五線譜と音符)を自動で読み取り、音階から周波数の値に変換して、自動で奏でるサービスがあれば面白そうだなと思いました。