LoginSignup
1
0

More than 3 years have passed since last update.

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

Posted at

やったのはこんなことです

SesameとLINEを連帯させて動かしたいと思っていた所に、女児が自宅で一人でいた所襲われたという痛ましい事件がありました。施錠されていなかったという情報もありましたが、同じ歳の娘がいる親としては他人事ではなかったので、以下のようなものを作りました。
ScreenShot_iPhone.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をコピー。

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

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

[ { 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された情報が表示される。

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

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

[ { 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を以下をコピペして作成する。

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

そのまま下の方に行き、メッセージ送受信設定をコピーし、プログラム中の[[your LINE Access Token]]にペーストする。
スクリーンショット 2019-08-12 4.48.39.png

セサミをクラウドでの連帯をONにする

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


body: { error: 'CLOUD_INTEGRATION_NOT_ENABLED' } }

「管理」->「設定を変更」->「連帯」で「クラウド」をONにする
IMG-6667.jpg
IMG-6665.jpg
IMG-6666.jpg

使用してみた感想

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0