日記帳

プログラミングのことをつぶやく日記です。

眠っているRaspberry pi 3をLINEのビーコンにしてみた

眠っているRaspberry pi 3をLINEのビーコンにしてみた

f:id:leokun0210:20171208005242p:plain

この記事はGMOペパボ Advent Calendar 2017の8日目の記事です

なぜつくったか

GMOペパボ Advent Calendar 2017の3日目の記事、「"Hello, World."の次としてのチャットボット」に触発されて、大急ぎでつくりました。家でRaspberry pi 3を眠らせておくのももったいなかったので、活用してみました。

どのようにして使える想定か

趣味で外回りの営業さん向けに、営業さんがLINE@にメッセージを送ると自動的にメールで本社宛に転送できるシステムを昔につくりました。実際に帰社したら、帰社をビーコンにより検知してイベント発火させて色々できることを想定してつくりました。(想定であり、実運用はしてません)

ソースコード github.com

どうやってつくるか

準備編

前提知識

  • LINE BOTHello Worldをリプライできる
  • Raspberry piBluetoothを使える状態にできるぐらいの習熟度

用意するもの

動作環境

  • PHP5.6.32
  • line-bot-sdk1.1

今回つくったLINEbotはline-bot-sdkを導入しています。

LINE Bot SDK

LINE BOTを作成したことがない人は、こちらのページを見れば比較的に簡単につくれます。

codezine.jp

作成編

まずは、Raspberry pi 3側の設定をします。

LINEの公式ブログで詳しい記事があるので、詳細はそちらを参照してください。

engineering.linecorp.com

HWIDの発行

LINE@MANAGER ビーコン設定画面

上記のサイトのLINE Simple BeaconのハードウェアIDの払い出し > アカウント一覧で連携したいアカウントを選択 > ハードウェアID発行でHWIDの発行は完了です。

f:id:leokun0210:20171208004935g:plain

次にRaspberry pi 3側でコマンドを実行していきます。

まずはパッケージのインストールです。Linux向けのBluetoothプロトコルスタックであるbluezおよび関連するパッケージをインストールします。

sudo apt-get install bluetooth bluez libbluetooth-dev libudev-dev

パッケージがインストールできたら、実行します。

# 発行されたHWIDを2桁ごとにスペースで区切ったものを指定
# ここで気をつけるのが、英字がLINE@MANAGERでは小文字なので大文字にします
HWID='01 0C 36 A2 95'

ADVERTISE_DATA="13 02 01 06 03 03 6F FE 0B 16 6F FE 02 ${HWID} 7F 00"

# Bluetooth HCIを有効にし、初期化します
sudo hciconfig hci0 up

# LE Controller Commands(OGF: 0x08), HCI_LE_Set_Advertising_Data(OCF: 0x0008) を実行し、
# 出力データを設定します
sudo hcitool -i hci0 cmd 0x08 0x0008 ${ADVERTISE_DATA}

#  Non connectable undirected advertising(3)で、Bluetooth LEのアドバタイズを有効にします
sudo hciconfig hci0 leadv 3

以上でRaspberry pi 3側の処理は完了です。次はwebhook先の処理です。

PHPでコードを書く

webhookとして設定しているサーバー側のエンドポイントに、ビーコンイベントをキャッチできるコードを書きます。これはビーコンイベント処理周辺部分のみを切り取ったものです。

<?php
// SDKをrequire
require __DIR__ . '/vendor/autoload.php'; // path to vendor/
$httpClient = new \LINE\LINEBot\HTTPClient\CurlHTTPClient(getenv('CHANNEL_ACCESS_TOKEN'));
$bot = new \LINE\LINEBot($httpClient, ['channelSecret' => getenv('CHANNEL_SECRET')]);
$signature = $_SERVER["HTTP_" . \LINE\LINEBot\Constant\HTTPHeader::LINE_SIGNATURE];
$events = $bot->parseEventRequest(file_get_contents('php://input'), $signature);

//ユーザーからのメッセージ取得
$json_string = file_get_contents('php://input');
$json_object = json_decode($json_string);

foreach ($events as $event) {
    // ビーコン処理
    if (($event instanceof \LINE\LINEBot\Event\BeaconDetectionEvent)) {
        $type = $json_object->{"events"}[0]->{"beacon"}->{"type"};
        if ($type === "enter") {
            $message = "お帰りなさい";
        } elseif (($type === "leave")) {
            $message = "行ってらっしゃい";
        }
        $body = <<<EOD
{$message}!!
EOD;
        replyTextMessage($bot, $event->getReplyToken(), $body);
        exit;
    }
}

function replyTextMessage($bot, $replyToken, $text) {
    $response = $bot->replyMessage($replyToken, new \LINE\LINEBot\MessageBuilder\TextMessageBuilder($text));
    if (!$response->isSucceeded()) {
        error_log('Failed!'. $response->getHTTPStatus . ' ' . $response->getRawBody());
    }
}
?>

ビーコン処理部分のみ解説していきます。

    if (($event instanceof \LINE\LINEBot\Event\BeaconDetectionEvent)) {

line-bot-sdkを利用して、LINEビーコンのイベントを簡単にハンドリングできるようになります。

        $type = $json_object->{"events"}[0]->{"beacon"}->{"type"};

LINEビーコンイベントによりwebhookされて送られてくるjson形式は、このような形になっています。

{
  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
  "type": "beacon",
  "timestamp": 1462629479859,
  "source": {
    "type": "user",
    "userId": "U4af4980629..."
  },
  "beacon": {
    "hwid": "d41d8cd98f",
    "type": "enter"
  }
}

詳細なドキュメントは、こちらを参照してください。

APIリファレンス

webhookされて送られてきたjsonオブジェクトの{"events"}[0]->{"beacon"}->{"type"}を参照して、ビーコンのイベントにより文言を変更します。

        if ($type === "enter") {
            $message = "お帰りなさい";
        } elseif (($type === "leave")) {
            $message = "行ってらっしゃい";
        }

テスト

早速ビーコンの範囲外に出てから範囲内に入ってみましょう。

f:id:leokun0210:20171208004501p:plain

赤丸の部分がleaveイベント(ビーコンの範囲外になる)とenterイベント(ビーコンの範囲内になる)を拾っています。

ビーコンから離れると行ってらっしゃい!!、ビーコンに近くとお帰りなさい!!が返ってきました!うれしいですね!ここからさらにIFTTTなどを使えば様々な応用が効きそうです。

大変だったこと

テストです。ビーコンの有効範囲が10メートル近くあり、物理的に移動しないとビーコンが反応しないので、外出から帰宅時しかテストできないのが辛かったです。

またline-bot-sdkの仕様のドキュメントが無さすぎて、手探りな感じも辛かったです。コードをみて使い方を覚えよみたいな感じでした。

それらの困難を乗り越えて動いたら楽しいですよ!!!家で余っているRaspberry piがあったらぜひ試してみてください。