外気の体感温度を教えてくれるLINEbotをAWS LambdaとSORACOMデバイスで作ってみた。

# はじめに
* 先日[SORACOMのデバイスとArduinoを用いて省エネIoT機器を作った](https://qiita.com/M1YamA00/items/7fea788f93abad5f30e8)を書いた。
    * ハッカソンでこういうモノ作ったよという記事。
    
* 完成したのがハッカソン終了の2日前とかだったので、残り時間でできることをやろうとLINE botを作ってみた。
![IMG_20200814_215613.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475530/e257b14b-b0ce-0c55-b057-0792f6220d56.jpeg)
* 話しかけると外の体感温度を教えてくれる。かわいい。アイコンをクール系美少女にしたい。
* GPS情報とかとも組み合わせられるのでは？とこれを書きながらも拡張性を感じる作品である。
* 前提として、[GPS マルチユニット SORACOM Edition](https://soracom.jp/products/kit/gps_multiunit/)を屋外に置いておく必要がある。

# なぜ作ったか
* 実は今回のデバイスの使用言語はかなり迷走しており、C → JavaScript → Pythonと行きついた感じだった。
* JavascriptのプログラムはAPI呼び出しまで行ったがArduinoとの連携がうまくいかなかったので撤退したもので、これが上手くいっていればAWS Lambdaで幅広くできたのに……と恨み言を吐いていた。
* もったいないので、AWS LambdaをAPI呼び出しのプログラムで動かしてLINE botにしようということになった。
    * 供養です。お盆なので。
   
# 構成 
* 以下のページを参考にLINE botの作り方を学んだ。いじる部分はほとんどLINE Messenger APIの周りだけだったので実質コピペ。
    * [【今日から始めるAWS】LambdaでLINEのbotをつくる](https://qiita.com/theFirstPenguin/items/8168e8ba3d65e34c24e0)
* 今になって思えばこの記事だけで構築可能だが、結構時間を溶かした。
    * API Gatewayの設定を行うときはAWS Lambdaの「トリガを追加」で追加したAPI Gatewayのリンクから飛ぶよ、などがわからず……
    * でも他と比べたらめちゃめちゃわかりやすい。
* 以下のプログラムで用いられているsoracom_apiとatobは`npm install`しなければならない。
* その後、上の記事の**3. index.jsとnode_modulesを圧縮しLambdaにアップロードする**のときに一緒に圧縮した。
    
```js:index.js
"use strict";
const line = require("@line/bot-sdk");
const atob = require("atob");
const client = new line.Client({ channelAccessToken: process.env.ACCESSTOKEN });
// ①SDKをインポート

const crypto = require("crypto");

exports.handler = function (event, context) {
    let body = JSON.parse(event.body);
    let signature = crypto
        .createHmac("sha256", process.env.CHANNELSECRET)
        .update(event.body)
        .digest("base64");
    let checkHeader = (event.headers || {})["X-Line-Signature"];

    if (signature === checkHeader) {
	// ②cryptoを使ってユーザーからのメッセージの署名を検証する
//ここから追加部分
global.atob = require("atob");
var Soracom = require('soracom_api');
var soracom = new Soracom({email: 'メールアドレスをここに',password:'パスワードをここに'});
soracom.get('/data/Subscriber/マルチユニットのSIMの番号?sort=desc&limit=1',function(err,res){
    console.log({err:err,res:res});
    console.log(res[0].content);
    var d = res[0]["content"];
	var e = JSON.parse(d);
    var decoded = atob(e["payload"]);
    var ans  =JSON.parse(decoded);
    var temp = ans["temp"];
    var humi = ans["humi"];
    var A = ((temp - 1/2.3 * (temp-10) * (0.8-humi/100)));
    global.M = A.toFixed(1);
  });
//ここまで
	if (body.events[0].replyToken === "00000000000000000000000000000000") {
	    let lambdaResponse = {
		statusCode: 200,
		headers: { "X-Line-Status": "OK" },
		body: '{"result":"connect check"}',
	    };
	    context.succeed(lambdaResponse);
	    // ③接続確認エラーを確認する。

	} else {
	    //let text = body.events[0].message.text;
//これも追加部分
	    if(global.M>26.5){
	    	var t = "エアコンをつけた方が良いです。";
	    }else{
	    	var t = "窓を開けても良いかもしれません。";
	    }
	    let text = "現在の外気の体感気温は"+global.M+"℃です。"+t;
	    const message = {
		type: "text",
		text: text,
	    };
//ここまで
	    client
	        .replyMessage(body.events[0].replyToken, message)
	        .then((response) => {
		    let lambdaResponse = {
			statusCode: 200,
			headers: { "X-Line-Status": "OK" },
			body: '{"result":"completed"}',
		    };
		    context.succeed(lambdaResponse);
		})
	        .catch((err) => console.log(err));
	    // ④リクエストとして受け取ったテキストをそのまま返す

	}
    } else {
	console.log("署名認証エラー");
    }
};
````

* 追加したのはAPIアクセス部分と出力生成部分の2か所。

### APIアクセス部分
* soracom_apiというライブラリのおかげでPythonの時よりもアクセスしやすくなっている。
* ただ、データの取得が全て関数内で行われるが故に関数スコープで関数外に持ち出せないため、持ち出したい変数には`global.`をつけないと使えない。
    * これが載ってる記事見つからなかった……常識なんだろうな、すみません。
    
* `var A`で用いられているのはミスナールの体感温度関数。
* 通常だと小数15桁まで得られてしまうので、`.toFixed(1)`で丸め込んだ。

### 出力生成部分
* 閾値以上ならエアコンを勧め、以下なら窓開けを勧める。
* [Messaging APIリファレンス](https://developers.line.biz/ja/reference/messaging-api/#message-event)曰く、文字を送るにはJSON形式の`message = {
     type: "text",
     text: text,
   };`を`client.replyMessage(replyToken, message)`のメソッドとして用いるだけでいいらしい。

# 感想
* 製作時間が短いので地味なものになってしまったが、SORACOMデバイスのデータを簡単にLINE botに活かせることが分かった。
    * それとコードの供養もできた。
    
* SORACOM Funcというものを用いるとより簡単にAWS Lambdaを活用できるらしい。
* デバイスとの連携も夢ではないかも。少なくともボタンのクリックイベントはすぐに読めるようにできそう。