LINE BOT経由でパパの居場所（androidスマホ）を地図で教える（失敗編）

:::note warn
本記事は最終的に思い通りに動作しませんでしたという失敗編です。
他の人が同じミスをしないように公開しております。
:::


# 前書き
1月末にRSコンポーネンツを見ていたら、Raspberry pi4b メモリ8Gが納品(2/2)になっていたのですぐに注文したのですが、2回の納期変更があり、現在は3/28到着予定になっています。jetson miniも定価で売っていないし、残念です。
無事に到着したら、色々やってみたいと思います。

前回の記事[LINE BOT経由でRaspberry Piに接続したUSBカメラの画像を取得してみる](https://qiita.com/TVCAdev/items/fc6a00d24ffa08f53c41)に引き続き、何か家族の役に立つことを考えて、家族に私がどこにいるのか知らせる機能を実装することにしました。

ご指摘・ご質問あれば、コメントいただければと思います。

# 結論（失敗した理由）
これは、フロントエンド開発している人だと常識なんでしょうけども、Webブラウザで画面が表示されている時しかJavaScriptって**動かない**んですよね。
よく考えたら当たり前なんですが、それに気づかずにパソコンのブラウザ上からアクセスして、その状態でスマホからLINE経由でパソコンの現在値を取得出来て、喜んでました・・・
実際にスマホでやってみると、ブラウザでWebサーバへアクセスした状態で、LINEを開くとブラウザ自体が非表示となってしまい、現在地が取得できず、そこで大きな間違いに気付きました。

追加で、色々調べて、Service Workerを使って位置情報を取得しようと思ったのですが、バックグラウンド状態では位置情報が取得できないようなので、あきらめました。

ですが、この失敗が誰かの役立つこともあるかもしれませんので、一応記事にします。

# 構成＆動作（失敗編）
以下に構成図と簡単な動作を示します。
![network.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704447/8b8a1ea9-fb1d-5086-22e9-5525bd14d18f.png)

居場所をみんなに知らせたいユーザはスマホから、ブラウザでheroku上のWebサーバへアクセスします。
(画面上は以下のような画面を表示します。)
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704447/9972c54c-025f-77b3-1de9-89c10513ef6a.png)
その際に、WebSocket(socket.io)を使って、接続を維持します。

確認者がLINEで居場所を確認する場合は、LINE botへメッセージを送信します。
LINE botはLINE Messageを受信したら、herokuのURLにWebhookで通知します。
herokuでは、node上のJavascriptがLine botから居場所確認のメッセージが届いたら、
WebサーバのWebSocket経由でスマホへ居場所確認のメッセージを送信します。
居場所確認のメッセージを受信したスマホは現在値を取得して、WebSocket経由で現在地を送信します。
Webサーバが現在地を取得したら、あとは、heroku→LINE bot→ユーザの順に現在地を送り返していきます。

# 構築
環境の構築については、
前回の記事[LINE BOT経由でRaspberry Piに接続したUSBカメラの画像を取得してみる](https://qiita.com/TVCAdev/items/fc6a00d24ffa08f53c41)を参照ください。
（なお、今回はRaspberry Pi以下の家のLAN環境の機材は一切不要です。）

## heroku上のコード
前回の記事[LINE BOT経由でRaspberry Piに接続したUSBカメラの画像を取得してみる](https://qiita.com/TVCAdev/items/fc6a00d24ffa08f53c41")からの差分をメインに説明します。

herokuでは、nodejsでjavascriptを動かします。
以下、コードとなります。

```javascript:heroku_app.js(クライアント側コード)

app.get("/" + process.env.LOCATIONNAME, (req, res) => {
    console.log(process.env.LOCATIONNAME + " was opend.");

    // HTML code for position get
    let html_contents =
        `<!DOCTYPE html>
<html>
    <head><meta charset="UTF-8" /><title>Get</title>
        <script src="/socket.io/socket.io.js"></script>
        <script type="text/javascript">
            // success function
            function pos_handler(position) {
                console.log("pos_handler start...");

                // send latitude, longitude to heroku
                socket.emit("POST_LOCATION", { latitude: position.coords.latitude, longitude: position.coords.longitude });
            }

            // error function
            function error_handler(err) {
                console.log("ERROR(" + err.code + "): " + err.message);

                socket.emit("POST_LOCATION", { latitude: 0.0, longitude: 0.0 });
            }

            // connect server
            const socket = io({
                query: {
                    token: "${process.env.WEBSOCKET_TOKEN}"
                },
            });

            socket.on("GET_LOCATION", () => {
                console.log("GET_LOCATION Received...");
                navigator.geolocation.getCurrentPosition(pos_handler, error_handler, { enableHighAccuracy: true });
            });
        </script>
    </head>

    <body>
        Do not close this page because of running script for getting location.
    </body>
</html>`

    // return HTML
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.write(html_contents);
    res.end();
});
```

process.env.LOCATIONNAME環境変数にURLを浮かしています。

まず、最初にsocket.ioを使用して、WebSocketの接続をしています。
接続先を指定していないので、HTTPSで接続した接続先へWebSocket接続をしています。

後は、socket.onを使用して、GET_LOCATIONイベントが発生したら、navigator.geolocation.getCurrentPositionで現在地を取得し、POST_LOCATIONイベントを発生させて、現在地情報を送ります。


```javascript:heroku_app.js(2)
    socket.on("POST_LOCATION", (data) => {
        console.log(`reply of GET_LOCATION was received. latitude:${data.latitude} longitude:${data.longitude}`)

        // push api message
        getlocIDs.forEach((senderID) => {
            client.pushMessage(senderID, {
                type: "location",
                title: "パパの現在地",
                address: "パパの現在地",
                latitude: data.latitude,
                longitude: data.longitude,
            });

            // send message to owner 
            sendOwner(senderID, "パパの現在地");
        });
        // delete all elements of getpicIDs
        getlocIDs.splice(0);
    });
```
getlocIDsは、現在値を要求してきたline IDの一覧です。
メッセージでtypeをlocationにして地図に経度・緯度をセットして送ります。

ソースコード一式は、[tvca-line-bot](https://github.com/TVCAdev/tvca-line-bot/tree/WrongCode "tvca-line-bot")にありますので、見てください。
何度も言いますが、ブラウザで開いている間しか、動作しませんので、意図している動作はしておりません。
次回、成功編を参照ください。

# 総括
Web系は詳しくないので、はまってしまった。
次回は、成功編でありましょう。