Node.jsでセサミの状態をLINEグループに投稿する

# やったのはこんなことです
SesameとLINEを連帯させて動かしたいと思っていた所に、女児が自宅で一人でいた所襲われたという痛ましい事件がありました。施錠されていなかったという情報もありましたが、同じ歳の娘がいる親としては他人事ではなかったので、以下のようなものを作りました。
<img width="320" alt="ScreenShot_iPhone.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350094/b4ed086d-81a5-2863-36a1-5f95b3ebd72c.png">

# 実行環境

Rasberry Pi。

```
pi@raspberrypi:~ $ lsb_release -a
No LSB modules are available.
Distributor ID:	Raspbian
Description:	Raspbian GNU/Linux 9.4 (stretch)
Release:	9.4
Codename:	stretch
```

# LINEのMessaging APIを使える状態にする
以下のページの「1. Botアカウントを作成する」を参考に、LINEのBot環境を構築する
https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d

# LINE Botの応答プログラムを動かす
以下のページの「2. Node.jsでBot開発」を参考に、LINE Botのプログラムを動かす。
https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d

# LINEからアクセスできるようにする
以下のページの「3. ngrokでトンネリング」を参考に、ngrokでトンネリングする。
https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d

# server.jsを使って、グループIDを取得する
投稿先を指定するために投稿先のグループIDが必要だが、取得の仕方が分からない。とりあえず、LINE Botのwebhookを使って取得する。
`* すみません。このグループIDの取得はMacOS上で実行していました。`
`* 初めはトークのIDを取得を試みましたが、うまく行きませんでした。`

ngrokを起動して、URLをコピー。

```console
ngrok by @inconshreveable                                       (Ctrl+C to quit)
                                                                                
Session Status                online                                            
Session Expires               7 hours, 32 minutes                               
Version                       2.3.34                                            
Region                        United States (us)                                
Web Interface                 http://127.0.0.1:4040                             
Forwarding                    http://8f719f6c.ngrok.io -> http://localhost:3000 
Forwarding                    https://8f719f6c.ngrok.io -> http://localhost:3000
                                                                                
Connections                   ttl     opn     rt1     rt5     p50     p90       
                              3       0       0.00    0.00    1.86    5.03      
                                                                                
HTTP Requests                                                                   
-------------    
                                                                                                                                             
```

LINEのwebhookに入力して「接続確認」を押すと、うまく行っていれば「成功しました」と表示される。
![スクリーンショット 2019-08-17 15.22.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350094/7bab3504-68e7-4983-36a1-e068bd548e2e.png)

また、server.jsのログには接続確認のPOSTがきたことが表示される。

```js
[ { replyToken: '00000000000000000000000000000000',
    type: 'message',
    timestamp: 1566021124737,
    source:
     { type: 'user', userId: 'Udeadbeefdeadbeefdeadbeefdeadbeef' },
    message: { id: '100001', type: 'text', text: 'Hello, world' } },
  { replyToken: 'ffffffffffffffffffffffffffffffff',
    type: 'message',
    timestamp: 1566021124737,
    source:
     { type: 'user', userId: 'Udeadbeefdeadbeefdeadbeefdeadbeef' },
    message:
     { id: '100002', type: 'sticker', packageId: '1', stickerId: '1' } } ]
疎通確認用
```

LINE Botに「テスト」とメッセージを送ってみる。すると、以下のようにPOSTされた情報が表示される。

```js
[ { type: 'message',
    replyToken: '658f1ac5c89b43a484534554f2419aba',
    source:
     { userId: 'U019077dcf770eafc447f5f26xxxxxxxx', type: 'user' },
    timestamp: 1566021143082,
    message: { type: 'text', id: '10406822402420', text: 'テスト' } } ]
```

では、LINE Botをグループに追加してみる。すると、以下のようにPOSTされた情報が表示されて、グループIDが取得できる。

```js
[ { type: 'join',
    replyToken: 'b4062059659b470d8de8e465a5452059',
    source:
     { groupId: 'C2b7154c5f92d0435e274d38exxxxxxxx', type: 'group' },
    timestamp: 1566021198238 } ]
```


# npmプロジェクトの作成と必要なモジュールのインストール

Node.jsのプロジェクトはpackage.jsonがあるディレクトリが起点となります。
まずはnpm initコマンドでpackage.jsonを作成します。

```

$ mkdir sesame
$ cd sesame
$ npm init -y
```


requestモジュールのインストール

```

$npm install request
```

Lineモジュールのインストール

```

$ npm i @line/bot-sdk express
```

# プログラムの作成

postSesame.jsを以下をコピペして作成する。


```js:postSesame.js
"use strict";

var request = require('request');

// LINE
const Client = require('@line/bot-sdk').Client;

// LINE information
const config = {
        channelSecret: '[[your LINE Channel Secret]]',
        channelAccessToken: '[[your LINE Access Token]]'
};
const line_group_id = '[[your LINE group ID]]';

// LINE interface
const client = new Client(config);


// Sesame information
const token_sesame = '[[your Sesame Token]]';

var options_device = {
  uri: 'https://api.candyhouse.co/public/sesames',
  headers: {
    'Authorization': token_sesame,
    'Content-type': 'application/json',
  },
  json: true
};

// Variables
let device_id = "";
let locked_current;
let unlocked_count = 0;

// Configuration
let check_interval_sec = 15;
let auto_locked_sec = 5*60; // use your favorite value

// Get initial status of sesame 
request.get(options_device, function(error, response, body){
  device_id = body[0].device_id;
  console.log(device_id);

  getStatus(function(locked){
    locked_current = locked;
    console.log('first lock status: ' + locked);
  });
});

// Get sesame status
function getStatus(callback) {
  var options_status = {
    uri: 'https://api.candyhouse.co/public/sesame/' + device_id,
    headers: {
      'Authorization': token_sesame,
      'Content-type': 'application/json',
    },
    json: true
  };
  request.get(options_status, function(error, response, body){
    if ( response ){
      if (response.statusCode == 200) {
        callback(body.locked);
      }
    }else{
      console.log(error);
    }
  });
}

// Send command to Sesame
function sendCommand(command_param) {
  var options_status = {
    uri: 'https://api.candyhouse.co/public/sesame/' + device_id,
    headers: {
      'Authorization': token_sesame,
      'Content-type': 'application/json',
    },
    json: {
      'command': command_param 
    } 
  };
  request.post(options_status, function(error, response, body){
    if ( response ){
      if (response.statusCode == 200) {
        console.log(body.task_id);
      }
    }else{
      console.log(error);
    }
  });
}

// Send message to Line
function sendMessage(message) {
      //Send Line Message to Specific Group
      client
        .pushMessage(line_group_id, {
          type: 'text',
          text: message
        })
        .catch((err) => {
            console.error(err);
        });
}

// Main Loop
setInterval(function(){
  getStatus(function(locked){
    //console.log('current lock status: ' + locked);
    if ( locked ){
      unlocked_count = 0;
    }else{
      unlocked_count++;
    }
    if ( locked != locked_current ){
      console.log('lock status changed.');

      var message;
      if ( locked ){ 
        message = "玄関：鍵が閉まりました (^ ^)";
      }else{
        message = "玄関：鍵が開けれました (o o)";
      }
      sendMessage(message);

    }
    if ( unlocked_count>=auto_locked_sec/check_interval_sec ){
      console.log('locked_count = '+unlocked_count);

      sendMessage("玄関：鍵が"+unlocked_count*check_interval_sec/60+"分開いているので勝手に閉めます (' ')");
      sendCommand("lock"); 
    }
    locked_current = locked;
  });
}, check_interval_sec * 1000);
```
_[[your LINE group ID]]_は上で取得したLINEのグループIDをコピペする。

_[[your Sesame Token]]_は以下を参照してコピペする。
https://qiita.com/asakura_junji/items/baed089b52287dca3039

_[[your LINE Channel Secret]]_と_[[your LINE Access Token]]_は以下を参照してください。

# LineのChannel Secretとアクセストークンの取得

以下からラインにログイン。
https://developers.line.biz/console/

プロバイダーの選択→チャンネルの選択→「チャンネルの基本設定」からChannel Secretをコピーし、プログラム中の_[[your LINE Channel Secret]]_にペーストする。
![スクリーンショット 2019-08-12 4.35.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350094/be174c37-4787-5a71-a974-f1feb017cae0.png)

そのまま下の方に行き、メッセージ送受信設定をコピーし、プログラム中の_[[your LINE Access Token]]_にペーストする。
![スクリーンショット 2019-08-12 4.48.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350094/4455c336-1c1d-ef22-56a1-8d036e499f3c.png)

# セサミをクラウドでの連帯をONにする
プログラム実行前にセサミのクラウドでの連帯をONにしないとerrorが帰ってくる

```

body: { error: 'CLOUD_INTEGRATION_NOT_ENABLED' } }
```

「管理」->「設定を変更」->「連帯」で「クラウド」をONにする
<img width="320" alt="IMG-6667.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350094/732b3ccb-a3a9-d1ea-69ae-3bad0a99d27e.jpeg">
<img width="320" alt="IMG-6665.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350094/1261bc61-04da-ca6a-2c45-ae38f96be22a.jpeg">
<img width="320" alt="IMG-6666.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350094/fd617163-da8e-025a-c7d1-ace20569dee8.jpeg">

# 使用してみた感想
+ 自動的に閉まる機能はデフォルトであることに途中で気付いた。
+ LINEのフリープランを使っていたが、PUSHMESSGEがすぐに1000件/月に達してしまった。
+ ドアの施錠(開閉)がLINEでリアルタイムで分かるのは安全上良い機能と感じた。