LINE Things Messageを使ってみよう #linethings #linedc


## この資料について

この資料は[LINE Things Message ハンズオン](https://linedevelopercommunity.connpass.com/event/134539/)のハンズオン資料になります。

1.5H程度しかないので簡単な体験って感じです。

> connpassに書いてますが、PCに[Arduino IDEのインストール](https://www.arduino.cc/en/Main/Software)してありますよね？してない人は前で話してる裏でコソッと入れてください！割と時間かかる場合があります。

## 話し始める前に裏でやっててほしいところ

[Adafruit nRF52 by Adafruit](https://qiita.com/n0bisuke/private/7f3da133a2363b549e3e#adafruit-nrf52%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)のインストールを僕が前で話してる間にやっておいてくれると嬉しいです。

## 自己紹介

* のびすけ
	* LINE API Expert
* [IoT縛りの勉強会 IoTLT](https://iotlt.connpass.com/event/126701/)の主催
* 日本初のプロトタイピング専門スクール「[ProtoOut Studio](https://protoout.studio/)」
	* [プログラミング学習はもう古い。「令和」時代のイノベーションを担う日本初のプロトタイピング専門スクールを開校](https://prtimes.jp/main/html/rd/p/000000005.000020328.html)
	* [「プログラミング学習はもう古い」って言ってしまった件について](https://note.mu/n0bisuke/n/n214f041ee558)
	* 2期制募集中です！

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/6dd3bf51-85c9-ea4a-50ba-da98a3dacef4.png" width="600px">

* 今日はtogetterがバズってる
	* [前代未聞の基板発注デモプレゼン?! 5分で基板設計から基板発注までを行い会場驚愕 #iotlt](https://togetter.com/li/1369426)

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/n0bisuke?ref_src=twsrc%5Etfw">@n0bisuke</a>さんのまとめ <a href="https://t.co/iV9Axphlyn">https://t.co/iV9Axphlyn</a> を本日の編集部イチオシに選ばせていただきました！こんなLTは初めて見ました...！<br><br>特集ページでも紹介しています。<a href="https://t.co/dJHzBtMsCO">https://t.co/dJHzBtMsCO</a> みてね！</p>&mdash; トゥギャッターまとめ編集部 (@tg_editor) <a href="https://twitter.com/tg_editor/status/1143060243661746176?ref_src=twsrc%5Etfw">2019年6月24日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 今日やる内容

* LINE Thingsの概要紹介
	* LINE Things LIFFの概要紹介
	* LINE Things Messageの概要紹介
* ハンズオン
* 時間が余ったら各自もくもく会
* 懇親会

## ゴールイメージ

もの凄くシンプルですが、"デバイスでボタンを押すとLINE BOTで通知させる"がゴールになります。

> <img src="https://i.gyazo.com/30428da14aaf50db2dcca099a3c3d106.gif" width="600px">
> https://www.instagram.com/p/BzFgLk5DjL4/

## LINE Thingsの立ち位置

LINE Thingsについて、LINE Things LIFFやMessageの概要について、[LINE ThingsやLINE Beaconの立ち位置おさらいなど](https://qiita.com/n0bisuke/items/1f552f3508fe8cf22759)でおさらいします。

## 今回の構成要素

* LINE BOT
	* Node.js (v10以上だと嬉しい)
	* ngrok
	* 簡単なおうむ返しBOTを作れればOK
* LINE Things用のデバイスの何か
	* ESP32系
		* ESP32 Devkit c
		* M5Stack / M5StickC
		* NefryBT
		* nodeMCU
		* obniz
	* nRF52系
		* Adafruit Feather nRF52
		* LINE Things Dev Board (←今日の貸し出し)
	* micro:bit

## 全体イメージ

LINE Thingsデバイスでボタンを押すとLINEにメッセージが送れる仕組みを作ります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/ee2a63c8-8f8a-49b7-6ef8-3205ecf3909e.png" width="600px">

## ハンズオン

### STEP0: LINE BOTをngrokで作成

LINE BOTをngrokで立ち上げている状態まで持って行きましょう。

> 参考: [1時間でLINE BOTを作るハンズオン](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d)

### STEP1: LIFFアプリケーションを作成

今回はLIFFは使いませんが、LIFFアプリケーションにLINE Thingsが紐づくのでLIFFアプリケーションを作成する必要があります。

* 新規LIFFアプリ追加

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/69b9709c-2192-84f7-3718-86c5df361628.png" width="600px">

BOTの管理画面 > LIFFのタブ > `追加ボタン`を選択します。

* LIFFの設定

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/c081246a-ab55-cf8c-0b3f-f1d8c4968861.png" width="600px">

こんな感じで情報を入れていれて`保存するボタン`を選択します。 今回重要なのはBLE featureをオンにするところです。

```
* 名前: 任意の名前。適当で大丈夫。
* サイズ: LIFFのサイズです。FullかTall推奨。Fullだと内部で開いてる感が無いので僕はTallが好きです。)
* エンドポイントURL: 表示されるページのURL。適当で大丈夫です。
* オプション: BLE featureをオンにしましょう。必須です。
```

* LIFF IDの確認

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/01d2d20c-6151-29b6-deae-9f996e50888d.png" width="600px">

こんな感じで`LIFF URL`が発行されます。この`line://app/<ここ>`の部分がLIFFアプリケーションのIDになります。（画面例だと`1574530976-yod0JDNv`がIDです）

各自異なる値なので、控えておいてください。

### STEP2: シナリオセットの作成

LINE Things Messageではシナリオセットと呼ばれる単位で

LIFFアプリIDに紐付きます。

#### (CURLでシナリオセットを作る)

CURLでやれる(やりたい)人はがおまるさんの記事が分かりやすいです！

> [M5StickCでLINE Thingsの自動通信機能を試してみた](https://qiita.com/h-takauma/items/b9cdc48259879a37b6b2#2-line-things%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%82%92%E8%A1%8C%E3%81%86)

#### LINE Things シナリオセットジェネレータ（非公式）を使ってシナリオセットを作る

経験上、CURLでのシナリオセット登録がハマる人が多いのでGUIで登録できるツールを作ってみました。(未完成)

* LINE BOTのアクセストークンを確認

チャンネル基本設定から確認できます。

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/b3fdc36f-81b7-b6d3-0422-f8bc368d3347.png" width="600px">

* シナリオセットジェネレータ(非公式)へアクセス

> https://n0bisuke.github.io/linethingsgen/

* Setting

`Setting`へアクセストークンを設定

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/204fa594-43b3-cf12-4e38-416aa8cf82a6.png" width="600px">


* トライアルプロダクトの作成

`Create Product`で先ほど作成したLIFFアプリを選択し、トライアルプロダクトの名前を入力し作成します。

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/c98a0258-5606-01a3-c465-44aa084b0223.png" width="600px">

作成が成功するとこんな感じの表示になります。

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/32192d16-407b-32eb-8845-ab8cd471b1eb.png" width="600px">

* シナリオセットの作成

`Create Scenario`で先ほど作成したトライアルプロダクトを選択し、設定を特に変えずに`シナリオセットの登録/更新`を選択しましょう。

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/e3a451ca-4b80-2e0f-6752-ba27d67b32cb.png" width="600px">

成功すると、ページ下部にシナリオセットの情報が表示されます。

> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/e541ef64-c6a2-9bfa-6c74-79bdd0296690.png" width="600px">

ServiceUUidを控えておきましょう。

#### 補足

トリガーに`BLE_NOTIFICATION`を設定していますが、その名の通りBLEでデバイスからNOTIFICATIONが送られた時に発火するという意味合いです。

### STEP3: LINE BOT(Node.js)のコードを書き換える

server.jsの`function handleEvent()の箇所`を以下に書き変えましょう。これで通知を受け取ることができます。

```server.js
function handleEvent(event) {
  let mes = '';
  console.log('---')
  console.log(event);
  if (event.type !== 'things') {
    return Promise.resolve(null);
  }

  if(event.type === 'things' && event.things.type === 'link'){
    mes = 'デバイスと接続しました。';
  }else if(event.type === 'things' && event.things.type === 'unlink'){
    mes = 'デバイスとの接続を解除しました。';
  }else{
    const thingsData = event.things.result;    
    if (!thingsData.bleNotificationPayload) return
    // bleNotificationPayloadにデータが来る
    const blePayload = thingsData.bleNotificationPayload;
    const buffer = new Buffer.from(blePayload, 'base64');
    const data = buffer.toString('hex');  //Base64をデコード
    console.log(buffer);
    console.log("Payload=" + parseInt(data,16));
  }
}
```

server.jsを再起動してトリガーを待ち受けます。

### STEP4: デバイスにファームウェア書き込み

この辺から人によって進捗度が変わりそうな印象です。

#### LINE Things Dev Boards（今日のレンタルデバイス）の場合

##### Adafruit nRF52のセットアップ

※インストールの時間がかかるので、ここの手順は先にやっておきたいかも。

> 参考: [LINE Things Starter](https://github.com/line/line-things-starter/blob/master/nrf52/README.ja.md)
> 参考: [LINE Things dev board使用ハンズオン](https://qiita.com/cpulabs/items/3a37a70cfa41129cb024)
> FAQ: [うまく動かない場合](https://line.github.io/line-things-dev-board/docs/trouble-shooting.html)

* 1. Arduino IDE を開きます
* 2. Preferences を開いてください
* 3. Additional Board Manager URLに`https://www.adafruit.com/package_adafruit_index.json`を追加します
* 4. Tools -> Board menu　から Boards Manager を開いてください
* 5 "nRF52" と検索して、 **`Adafruit nRF52 by Adafruit`**をインストールしてください。
	* 過去に入れたことがある人も、0.10.1よりもバージョンが古い場合はアップデートして下さい。

> v0.11.0が最新の模様
> <img src="https://i.gyazo.com/edd48bdff696f9b25aef6357dbc4bd9d.png" width="600px">

**`Adafruit nRF52 by Adafruit`です`Adafruit nRF52 Boards by Arduino`があるので注意!!!!**

> これは間違い
> <img src="https://i.gyazo.com/3e9984ca7c8b23129fc3c8f1f17c2b3d.png" width="600px">

* cloudflare障害(これでいけたらしい)
	* `https://www.adafruit.com/package_adafruit_index.json`を追加した人はこのURLを削除
	* `https://raw.githubusercontent.com/adafruit/arduino-board-index/gh-pages/package_adafruit_index.json`を設定
	* ボードマネージャーから**`Adafruit nRF52 by Adafruit`**のv0.10.1のボードを追加

##### ドライバインストール

[CP2102Nドライバのインストール](https://qiita.com/cpulabs/items/3a37a70cfa41129cb024#cp2102n%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)を参考にドライバをインストールしてください。

> [CP210x USB to UART Bridge VCP Drivers](https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers)

##### Arduinoでプログラム(ファームウェア)を書き込む

[こちら](https://gist.github.com/n0bisuke/7c8635ac31ecdd5a8edc7b2a8b067a94#file-lt-ino-L7)のコードをコピペしてサービスUUIDを変更しましょう。

> ※ちなみにデフォルトファームでもやれるらしいですが、僕が試したらコンパイル通らなかったのでデフォルトファームは諦めました！！！誰か試してみて下さい。

##### コードの補足(読み飛ばしてもOK)

読み飛ばしても大丈夫ですが、[LINE Things Starterのこちらのコード](https://github.com/line/line-things-starter/blob/master/nrf52/arduino/starter-nrf52/starter-nrf52.ino)から以下のように変更しています。

* サービスUUID変更

```lt.ino
#define USER_SERVICE_UUID "ここを自分のサービスUUIDに"
```

* BUTTONのピンを変更

```lt.ino
#define BUTTON 29
```

* setup()に確認用コードを追記

```lt.ino
  Serial.begin(115200);
  Serial.println("setup done");
```

* loop()の処理の中身を変更

```lt.ino
//省略

int btnCount = 0;

void loop() {
  uint8_t btnRead;

  if(digitalRead(BUTTON) == 0){
    Serial.println(btnCount); //シリアルモニタ確認
    
    btnCount++;
    btnRead = btnCount;
    notifyCharacteristic.notify(&btnRead, sizeof(btnRead));
    delay(500);
  }

}
```

#### ESP32の場合

* ボードのインストール

[LINE Things Starterのページ](https://github.com/line/line-things-starter/blob/master/esp32/README.ja.md)を参考に書き込みができるようにしてみましょう。

* ファームウェアの書き込み

このコードを書き込んで試してみましょう。簡単に用意したサンプルです。そこまで確認できてません。

> https://gist.github.com/n0bisuke/98e386a316ea33fd47c873e768ed0391

#### その他のボードの場合

LINE Things Starterのページで基本的な書き込みを試してみたのち、サービスUUIDを書き換えることで利用できます。
そのままだとサンプルプログラムによっては無限リプライが発生してしまうので、Notifyの発火タイミングには注意して下さい。

### STEP5: LINEアプリのLINE Things有効化

この手順は忘れがちなので要注意です。

> 一回でもLINE Thingsを使ったことがある人は既に有効化されているのでこの手順はスキップして大丈夫です。

**以下のQRコードを読み込み、LINE Thingsを有効化して下さい。**

> <img src="https://i.gyazo.com/98b4c1acd4a0025318b6ea98ad64bf97.png" width="300px">

一度有効化すると、LINEアプリの設定に`LINE Thingsの項目`が追加されるので、2回目以降はここから開きましょう。

> <img src="https://i.gyazo.com/15d137fe0bc67c65ebf0a5ba3018c403.png" width="300px">

### STEP6: LINE Thingsアプリと接続

ここは画像だけで紹介

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/de3cd2db-66a3-70ab-0a55-54e0c550996b.png" width="300px">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/ca448f67-c6be-1086-05b2-739e129e51fc.png" width="300px">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/2c42cdb6-8abb-7d8f-6dc5-7bee298da345.png" width="300px">

接続すると設定したURLのLIFFが開きます。(今回は特に意味はない)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/7eeaa5de-9688-aa95-09a2-eba7fba4c8f2.png" width="300px">

* Node.js側へのWebhook

接続すると、`type: 'link'`のデータがWebhookで飛んできてNode.js側で受け取れます。

```bash
{
  type: 'things',
  replyToken: 'xxxxxxxxxxxxxxxxxxxxxxxx',
  source: { userId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', type: 'user' },
  timestamp: 1561363123027,
  things: { deviceId: 'xxxxxxxxxxxxxxxxxxxx', type: 'link' }
}
```

ちなみに消す時には`type: 'unlink'`がWebhookで飛んできます。

### STEP7: Node.jsと連携

#### デバイスのボタンを押してみる

`SW1(ディスプレイ下の二つのボタンの左側)`を押してみましょう。

> <img src="https://camo.qiitausercontent.com/14b789f22a20d37785c5f74562645c477fb49742/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3335343937382f61366265356532392d343034382d366331632d356431622d3135373161333365653963352e6a706567" width="600px">

うまくいくとNode.jsのコンソールに以下のようなデータが送られてきます。
 
```bash
---
{
  type: 'things',
  replyToken: 'xxxxxxxxxx',
  source: { userId: 'xxxxxxxxxxxxxxxxxxxx', type: 'user' },
  timestamp: 1561364660829,
  things: {
    deviceId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    result: {
      scenarioId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
      revision: 0,
      startTime: 1561364660425,
      endTime: 1561364660776,
      resultCode: 'success',
      bleNotificationPayload: 'Bw==',
      actionResults: []
    },
    type: 'scenarioResult'
  }
}
<Buffer 07>
Payload=7
```

#### server.jsを編集して仕上げ

またhandleEvent()の箇所を書き変えましょう。これでリプライが飛んでくるようになります。

```server.js
function handleEvent(event) {
  let mes = '';
  console.log('---')
  console.log(event);
  if (event.type !== 'things') {
    return Promise.resolve(null);
  }

  if(event.type === 'things' && event.things.type === 'link'){
    mes = 'デバイスと接続しました。';
  }else if(event.type === 'things' && event.things.type === 'unlink'){
    mes = 'デバイスとの接続を解除しました。';
  }else{
    const thingsData = event.things.result;    
    if (!thingsData.bleNotificationPayload) return
    // bleNotificationPayloadにデータが来る
    const blePayload = thingsData.bleNotificationPayload;
    const buffer = new Buffer.from(blePayload, 'base64');
    const data = buffer.toString('hex');  //Base64をデコード
    console.log(buffer);
    console.log("Payload=" + parseInt(data,16));
    mes = `デバイスから${parseInt(data,16)}が送られてきたよ`;
    const msgObj = {
      type: 'text',
      text: mes //実際に返信の言葉を入れる箇所
    }

    return client.replyMessage(event.replyToken, msgObj);
  }
}
```

SW1を押して確認してみましょう。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/a17fd675-6c9f-56da-09e1-b1893a4f0afe.png" width="500px">

LINEアプリを閉じてもメッセージが送られてくるので、LIFFを立ち上げずにバックグラウンドで動かしたい時に便利です。

お疲れ様でした！

## FAQ

* Arduino IDEで書き込みがうまく行かない
	* シリアルポートの選択は問題ない？
	* ボードの設定は問題ない？
	* ケーブル繋がってる？
* LINE側に反応がない
	* ngrokは起動してる?
	* server.jsは起動してる?
* それでもまだデータが飛んでこない
	* 一旦、LINE Thingsの設定をスマホから消してみましょう
	* LINEアプリを一旦落としてみよう。
	* スマホのネットワーク状態を確認しよう
		* LINE Things MessageはLINEアプリが入ってるスマホのネットワークを経由してサーバーに接続するため、スマホのネットワークが弱かったりすると調子が悪くなります。

## まとめ

お疲れ様でした！いかがでしたでしょうか？
時間間に合ったかなぁ。

LINE Thingsの開発は対象範囲が広いので中々感覚を掴みにくいかもしれません。もう一回くらい復習して感覚を掴むとよいと思います。僕も復習します。

またどこかでお会いしましょう。それでは。