obniz×LINEBOTで、鍵をいつもの場所に置いているか推しに教えてもらうことにした。

#家の鍵をなくしがち。
私は<b>家の中で家の鍵を紛失する競技種目があれば確実に金が取れるぐらいには家の中で家の鍵をよく紛失する。</b>
鍵を置く用の決まった定位置を作ってはいるが、習慣的にそこに置くことができず、
無意識にポケットに入れていることもあるし、下駄箱の上に無造作に置いていたり、
酷いときは<b>水を飲むために開けた冷蔵庫の中に入れていたりする。</b>(全然記憶が無い）
その結果、外出直前になると必ずと言っていいほどテンパりながら鍵を探す羽目になっている。
結構自分でもヤバいと思っている。

ある日、プロトアウトスタジオの授業でobnizを使ったハードのモノづくりについて学んだ。
温度センサー、LEDライト、スピーカー、超音波距離センサー、といったものを使いながら、プログラムを組んで動かしてみた。面白かった。
どうにかしてこの授業で得た知識を使って、何か日常生活に活かせるようなものを作りたい。
ふと<b>鍵が定位置にあるかを確認できるようなツールがあれば便利じゃなかろうか、</b>と思いついたので、早速作ってみた。



#やったこと
・obnizを使用した鍵定位置確認機能を作る
　〇使用した機器
　　-obniz Board
　　‐超音波測距センサ

・LINE BOTを作り、対話形式で応答させる
今回は推しに教えてもらうことにした。
名付けて、<b>鍵を見守るレオナ・キングスカラーbot。</b>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155038/47efc6d3-aee8-1b07-085b-80d31b8838d9.png)
新しくチャネルを作った。



#環境(物理)
とりあえず超音波距離センサを隣に引っ付けて、推しのレオナさんに鍵を監視してもらった。
雑ゥ～・・・



#結果
一応、動くものができた。

動画で張り付けたかったけど、うまく撮れず＋長さの問題かTwitterに載せられなかったため断念。。

10/31更新　撮れたので、載せます。

<b>◆鍵を定位置に置いている場合</b>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155038/d4ce93c0-7706-be60-b395-fdfb80bfa54a.png)


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【鍵がある場合】ちゃんと教えてくれるレオナ<br>(梅原ボイスは脳内で補完)<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/linedc?src=hash&amp;ref_src=twsrc%5Etfw">#linedc</a> <a href="https://t.co/4Uj2ZKRRi0">pic.twitter.com/4Uj2ZKRRi0</a></p>&mdash; shigeyuri (@sgyr_Xedge) <a href="https://twitter.com/sgyr_Xedge/status/1454846295793811456?ref_src=twsrc%5Etfw">October 31, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<b>◆obnizの表示</b>
![IMG_7200.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155038/42b0f7fa-64ec-f094-e951-e312cdecdc25.jpeg)

<b>◆鍵を定位置に置いていない場合</b>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155038/2c702c3f-31fb-45c8-3385-2fdf5db9bfa5.png)



<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【鍵がない場合】レオナってご愁傷さまとか言わなさそう...キャラブレ激しいし夢小説書いてるみたいで恥ずかしくなってきた<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/linedc?src=hash&amp;ref_src=twsrc%5Etfw">#linedc</a> <a href="https://t.co/AIgvPNVoau">pic.twitter.com/AIgvPNVoau</a></p>&mdash; shigeyuri (@sgyr_Xedge) <a href="https://twitter.com/sgyr_Xedge/status/1454846897370193931?ref_src=twsrc%5Etfw">October 31, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<b>◆obnizの表示</b>
![IMG_7199 (2).JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155038/ed876fc0-0a56-4d8e-cf17-e7827cb91124.jpeg)

英語があっているかはさておき、ちゃんと鍵があるかないかを見て(実際は距離の遠近を測って)
反応を返してもらうことができた。


#環境
・Visual Studio Code
・JavaScript
・Node.js


#ソースコード

<details><summary>今回も長いのでセクションに</summary><div>

```javascript
'use strict'; // エラー判定を厳しくする（推奨）


// ########################################
//               初期設定など
// ########################################

// パッケージを使用します
const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;

// Messaging APIで利用するクレデンシャル（秘匿情報）です。
const config = {
  channelSecret: 'チャネルシークレット',
  channelAccessToken: 'チャネルアクセストークン'
};

// ########################################
//  　　　　　　obnizの呼び出し
// ########################################
const Obniz = require('obniz');
const { exit } = require('process');
const obniz = new Obniz('xxxx-xxxx'); // Obniz_IDに自分のIDを入れます



// ########################################
//          Expressによるサーバー部分
// ########################################

// expressを初期化します
const app = express();

// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をします
app.post('/webhook', line.middleware(config), (req, res) => {

  // 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行
  if (req.body.events.length === 0) {
    res.send('Hello LINE BOT! (HTTP POST)'); // LINEサーバーに返答します（なくてもよい）
    console.log('検証イベントを受信しました！'); // ターミナルに表示します
    return; // これより下は実行されません
  } else {
    // 通常のメッセージなど … Webhookの中身を確認用にターミナルに表示します
    console.log('受信しました:', req.body.events);
  }

  // あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、
  // 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返します
  Promise.all(req.body.events.map(handleEvent)).then((result) => res.json(result));
});

// 最初に決めたポート番号でサーバーをPC内だけに公開します
// （環境によってはローカルネットワーク内にも公開されます）
app.listen(PORT);
console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);

// ########################################
//          　　ここから
// ########################################
const client = new line.Client(config);
// obniz接続
obniz.onconnect = async function () {
    obniz.display.clear();
    obniz.display.print("obniz turned ON!");
  }

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

    let mes = ''
  if(event.message.text === '鍵あるか見て'){
    mes = '草食動物のクセに俺に命令とはいい度胸じゃねぇか。';  //メッセージだけ先に処理
    getObnizRangeMeasure(event.source.userId);  //スクレイピング処理が終わったらプッシュメッセージ
  }else{
    mes = event.message.text;
  }

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

const getObnizRangeMeasure = async (userId) => {

    // 超音波距離センサを呼び出す
    const hcsr04 = obniz.wired('HC-SR04', { gnd: 0, echo: 1, trigger: 2, vcc: 3 });

    // ディスプレイ
    obniz.display.clear(); // クリア
    obniz.display.print('There is the key?');

     // setIntervalで一定間隔で処理
     setInterval(async function () {
        // 距離を取得
        let distance = await hcsr04.measureWait();
        // そのままだと小数点以下の桁数がやたら多いので整数に丸めてもよい
        distance = Math.floor(distance);

        // 距離(mm)をターミナルに表示
        console.log(distance + ' mm');
        // obnizディスプレイに表示
        // 一度消してから距離+mmの単位を表示
        obniz.display.clear();
        //obniz.display.print(distance + ' mm');

        // 鍵がいつもの場所にあるかどうかの判定
        if (distance > 100) { // 100mm = 10cm より離れている場合
            // obnizディスプレイに鍵がないことを表示
            obniz.display.clear();
            obniz.display.print('key is lost!!');
            // LINEメッセージに鍵がないことを返信
            await client.pushMessage(userId, {
                type: 'text',
                text: "どうやらいつもの場所に鍵を置き忘れたようだな。ご愁傷様なこった。",
              });
        } else {
            // obnizディスプレイに鍵があることを表示
            obniz.display.clear();
            obniz.display.print('key is here!!');
            // LINEメッセージに鍵があることを返信
            await client.pushMessage(userId, {
                type: 'text',
                text: "鍵ならここにあるぜ。さっさと取りに来ないと砂にするぞ。",
              });
        }

    }, 4000); // 4000ミリ秒 = 4秒おきに実行

}
   

```
</div></details>



#問題
ちょっと色々やってたら、めっちゃ大量にリクエスト送っちゃって、
それ以降実行してもエラーが返るようになってしまった。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155038/fdf1a3b3-83f9-0ef2-8cb3-72d25d856354.png)

“UnhandledPromiseRejectionWarning: Error: Request failed with status code 429”というエラーは、ユユーザーが一定時間内に送信したリクエストが多すぎた時に発生するらしい。

多分以下のコーディングを誤って<b>0.4秒おきにして実行してしまったのが原因だと思う。。</b>

```javascript
    }, 400); // 4000ミリ秒 = 4秒おきに実行

}
   

```
![LINE_capture_657140243.066546 (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155038/26b79cae-b8a5-cbc1-c350-bb6ab387420e.jpeg)
結果的にレオナから物凄い勢いでメッセージの爆撃がきてしまった。

どうしたら直るのか鋭意復旧調査中だけど、一応obniz側には正常に表示されているので
使い方としては合っているのかなと、、

(10/31　追記)
ある程度時間が経ったら許されるっぽい。今日やったらできた。
皆も予期せぬDDos攻撃は気を付けましょう。


#まとめ(感想)
実際見に行けば済む話ではあるけど、距離の計測によって｢ものがあるorない状況を判断する｣という使い方が面白いと思った。
本当は鍵のあるなしに合わせてLEDランプをつけたり、音楽を流したりもしたかったけど
前述したLINE爆撃によりパニックになり、断念。。

ただ、ハードでのモノづくりは楽しかったので、今後も色々と創作してみたい欲が刺激された。
100均のおもちゃと連動させたり、ラジコンとか、動くフィギュアとか作ってみたい。