この投稿は IoTLT Advent Calendar 2019の11日目の投稿です。
こんにちは!もちゃんと申します!
LINE ThingsやLINE Beaconが好きです。
この夏、**LINE Thingsのアワード**が開催され、私もたくさんの作品を応募し大盛況のうちに幕を閉じました。

作品を応募するにあたり、多くのセンサーやデバイスを購入していたのですがM5StickCに関しては安かった(1,000円ぐらい)のもあり気が付いたら余るレベルの数を購入しておりました...
下記は**LINE対応ビーコンですが何かM5StickC**と形似てませんか?もうM5StickCがビーコンにしか見えなくなりました。少なくとも私はそう思います。(余ってるし)こいつをビーコン化してやろうと...(2019年秋)
はじめに
前置きが長くなりました。。
今回はオープンなLINE Beaconデバイスの仕様である、「LINE Simple Beacon」の仕組みを使ってLINE Beacon化していきます。
LINE Simple Beaconとは
LINE Simple Beaconとは、LINE Bot開発者向けのビーコンデバイス仕様です。 LINE Simple BeaconはBluetooth Low Energy (以下、「BLE」という)の仕様にもとづいており、 汎用のデバイスでLINE Beaconのサービスを利用することを可能とします。
さっそくBeacon化してみる
必要なもの
- 余ったM5StickC
- LINE Bot
- LINE Beacon化したいと思うお気持ち
事前準備
事前にLINE Botが必要になります。
ここでは簡単にですが、下記にLINE Botの準備手順を記載します。
◆ まずMessaging APIのチャネルを作成します。
下記URLからチャネルを作成します。
https://developers.line.me/ja/services/messaging-api/
作成後、Messaging API設定タブに移動し、QRコードでBotと友だちになっておきましょう。

◆ そしてwebhookの設定
webhook URLを入力し、webhookの利用をONにします。

◆ 応答メッセージの無効
応答メッセージを利用しないので編集ボタンからLINE公式アカウント画面で無効にしましょう。

◆ LINE Bot のコードは下記のような感じです
'use strict';
const line = require('@line/bot-sdk');
const config = {
    channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN,
    channelSecret: process.env.CHANNEL_SECRET
};
const client = new line.Client(config);
module.exports = async( req, res ) => {
  Promise
    .all(req.body.events.map(await handleEvent))
    .then((result) => res.json(result))
    .catch((err) => {
      console.error(err);
      res.status(200).end();
    });
};
// event handler
async function handleEvent(event, session) {
  console.log(event);
  let echo = [];
  // 参考:https://developers.line.biz/ja/reference/messaging-api/#beacon-event
  if (event.type === 'beacon') {
    if (event.beacon.type === 'enter') {
      // LINE Botと友だちになっている方がLINE Beaconの近くにきたら、その人の情報を送る
      await client.pushMessage(process.env.USER_ID, [
        { 'type': 'text', 'text': event.source.userId + 'さんが来店しました。' }
      ]);
    }
    return;
  } else if (event.type === 'follow') {
    return;
  } else {
    echo = { 'type': 'text', 'text': '申し訳ありませんが、お返事できません。' }; 
  }
  // use reply API
  return client.replyMessage(event.replyToken, echo);
}
※ 上記ではプッシュメッセージ機能を使ってLINE Botにメッセージを送信しています。1か月あたり1,000通までの制限はありますが無料でも利用できます。
https://engineering.linecorp.com/ja/blog/line-developer-trial-migration/
LINE Beacon化の作業
ここからがLINE Beacon化の作業です。
下記の手順に従えば3分ぐらいでいけると思います!
◆ 環境構築
Arduino IDEはお手持ちのPCに入っている前提で
ESP32のボード開発用のライブラリをインストールしていきます。
メニューバーの「Arduino」->「Preference(環境設定)」を開きましょう。

https://dl.espressif.com/dl/package_esp32_index.json
上記をコピーして、赤枠に入力して、「OK」ボタンを押しましょう。

次にメニューバーの「ツール」->「ボード」->「ボードマネージャー」を開きましょう。

上の入力欄にESP32を検索して表示されたたものをインストールしていきます。

次にM5StickCのライブラリをインストールします。「ツール」->「ライブラリを管理」を開きましょう。

同様に入力欄にM5StickCで検索し赤枠をインストールしましょう。

M5StickCをPCと接続して、メニューバーの「ツール」から下記のように設定をします。他はデフォルトのままでOKです。

上記のインストールを進めながら、下記のLINE Simple BeaconのハードウェアIDの設定も実施します。
◆ LINE Simple BeaconのハードウェアID
下記URLから [LINE Simple BeaconのハードウェアIDを発行]ボタンを押します。
https://manager.line.biz/beacon/register

アカウントリストから、上記で作成したチャネルの選択ボタンを押して、ハードウェアIDを発行します。

発行したハードウェアIDをM5StickCのコードの「YOUR_HWID」に書き換えます。

◆ M5StickCのコードは下記のような感じです
下記がM5StickCをLINE Simple Beaconとして動作させるコードになります。Arduino IDEを使って書き込みます。
# include <M5StickC.h>
# include <string>
# include "BLEDevice.h"
# include "BLEAdvertising.h"
/**
 * Bluetooth TX power level(index), it's just a index corresponding to power(dbm).
 * * ESP_PWR_LVL_N12 (-12 dbm)
 * * ESP_PWR_LVL_N9  (-9 dbm)
 * * ESP_PWR_LVL_N6  (-6 dbm)
 * * ESP_PWR_LVL_N3  (-3 dbm)
 * * ESP_PWR_LVL_N0  ( 0 dbm)
 * * ESP_PWR_LVL_P3  (+3 dbm)
 * * ESP_PWR_LVL_P6  (+6 dbm)
 * * ESP_PWR_LVL_P9  (+9 dbm)
 */
# define POWER_LEVEL ESP_PWR_LVL_P9
// 発行したハードウェアIDを書き換える
# define HWID "YOUR_HWID"
bool beaconFlg = false;
BLEAdvertising *pAdvertising;
std::string hexEncode(std::string raw) {
  const char *hexMap = "0123456789abcdef";
  std::string hex = "";
  for(int i=0; i<raw.size(); i++) {
    hex += hexMap[(raw[i] >> 4) & 0x0F];
    hex += hexMap[raw[i] & 0x0F];
  }
  return hex;
}
int htoi (unsigned char c)
{
  if ('0' <= c && c <= '9') return c - '0';
  if ('A' <= c && c <= 'F') return c - 'A' + 10;
  if ('a' <= c && c <= 'f') return c - 'a' + 10;
  return 0;
}
std::string hexDecode(std::string hex) {
  if (hex.size() % 2) return "";
  std::string raw = "";
  for(int i=0; i<hex.size(); i+=2) {
    raw += (char) ( htoi(hex[i]) * 16 + htoi(hex[i+1]) );
  }
  return raw;
}
bool setLINEBeacon (std::string hwid, std::string msg) {
  // check hwid
  if (hwid.size() != 5 || msg.size() > 13) return false;
  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
  BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
  BLEUUID line_uuid("FE6F");
  // flag
  // LE General Discoverable Mode (2)
  // BR/EDR Not Supported (4)
  oAdvertisementData.setFlags(0x06);
  // LINE Corp UUID
  oAdvertisementData.setCompleteServices(line_uuid);
  // Service Data
  std::string payload = "";
  payload += (char) 0x02; // Frame Type of the LINE Simple Beacon Frame
  payload += hwid; // HWID of LINE Simple Beacon
  payload += 0x7F; // Measured TxPower of the LINE Simple Beacon Frame
  payload += msg; // Device message of LINE Simple Beacon Frame
  oAdvertisementData.setServiceData(line_uuid, payload);
  pAdvertising->setAdvertisementData(oAdvertisementData);
  pAdvertising->setScanResponseData(oScanResponseData);
  return true;
}
void setup() {
  M5.begin();
  BLEDevice::init("");
  esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, POWER_LEVEL);
  pAdvertising = BLEDevice::getAdvertising();
  M5.Lcd.setCursor(0, 30);
  M5.Lcd.print("Ready");
}
void loop()
{
  // The underlying framework will advertise periodically.
  // we simply wait here.
  if (digitalRead(M5_BUTTON_HOME) == LOW) {
    if (!beaconFlg) {
      // LINE BeaconをONにする
      setLINEBeacon(hexDecode(HWID), hexEncode(std::string((const char*) BLEDevice::getAddress().getNative(), 6)));
      pAdvertising->start();
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setCursor(0, 30);
      M5.Lcd.print("line beacon! ON");
      beaconFlg = true;
    } else {
      // LINE BeaconをOFFにする
      //// LINE Beaconをストップする機能は現在動作しないようです。下記URLを参考にしてください。
      //// https://github.com/nkolban/esp32-snippets/issues/797
      pAdvertising = BLEDevice::getAdvertising();
      pAdvertising->stop();
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setCursor(0, 30);
      M5.Lcd.print("line beacon! OFF");
      beaconFlg = false;
    }
    while(digitalRead(M5_BUTTON_HOME) == LOW);
  }
}
これでLINE Beacon化完了です!
活用アイディア
ジャストアイディアですが、お得意さんが来店された時に名前思い出せないッ!...みたいな時にもLINE BeaconとLINE Botで来店時にお客様のuserIdからお名前をそっと教えてくれる仕組みとか色々できそうではないでしょうか!(LINEのuserIdと顧客情報を紐づける仕組みは別途必要)
その他、LINE Beacon活用事例など
- LINE DEVELOPER DAY 2019でもLINE Beaconを活用した可視化の取り組みがあったようです!
https://speakerdeck.com/line_devday2019/the-iot-technology-inside-line-developer-day-2019?slide=11
- 出退勤をLINE Beaconで自動化
他にも様々な場面でLINE Beaconは活用されています。
お・ま・け
ちなみに、Micro:bit ならもっと簡単にLINE Beacon化できるやり方がありますので下記のハンズオン資料を参考にしていただけれ幸いです。
- LINE Simple Beacon × Micro:bit ハンズオン
  
 https://speakerdeck.com/mochan_tk/line-simple-beacon-microbit-hands-on
まとめ
LINE Botと友達になるだけでLINE Beaconと連携できる手軽さが良いですよね。
既存のBotにも活用できると思いますので、新しい展望が出てくる可能性もあるのではないでしょうか。
年末年始でお時間ある方も是非試してみてください。





