LINE ThingsのLIFFアプリ(とデバイス)を自前で作る


[さっそくLINE Thingsを触ってみた（ESP32でリモートLチカ） #linedevday](https://qiita.com/n0bisuke/items/b0541a32f01007f938a4)の続きになるイメージです。

とりあえず`デバイス側もLIFF側も用意されてたもので試してみた`の次はLIFF側を自分で実装してみたいと思います。とはいえLINE ThingsのLIFFを自前でやるにあたり諸々必要になってデバイス側もいじることになります。

> 後から追記: 書いてて結局デバイス側もコード変更しないといけなかったので`(とデバイス)`って感じにしました。

## ソースコード

こちらの[LINE Things StarterのLIFF APPサンプル](https://github.com/line/line-things-starter/tree/master/liff-app)から

* index.html
* liff.css
* liff.js
* loading.gif

を手元に落とします。Git Cloneした方が早いかも

![](https://i.gyazo.com/de148fb393ecb2ab7d4c2cab2e15686b.png)

## ホスティングする

ngrokとpythonのサーバーでやります。8080ポートです。

* 上記のコードがあるディレクトリでローカルサーバー起動

```
$ python -m SimpleHTTPServer 8080
```

* トンネリングサーバー起動

```
$ ngrok http 8080
```

```
ngrok by @inconshreveable                                                    (Ctrl+C to quit)

Session Status                online
Account                       n0bisuke (Plan: Free)
Version                       2.2.8
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://a17dd6e4.ngrok.io -> localhost:8080
Forwarding                    https://a17dd6e4.ngrok.io -> localhost:8080

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

```

生成されるhttpsのアドレスを利用します。今回は`https://a17dd6e4.ngrok.io`です。

## LINE BOTの作成

[1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d)などを参考に作成します。

## LIFF アプリの作成

最近は管理画面からLIFFアプリを作成出来るようなったんですよね。（少し前は出来なかった）

> <img src="https://i.gyazo.com/56ab9c6463a86a341a0b23ef6f1ca4ad.png" width="400">

ただ、今回は画面からじゃなくてcurlでやる必要があるっぽいです。

こちらの[ドキュメント](https://developers.line.biz/ja/docs/line-things/regist-liff-app/)から進めましょ。

> https://developers.line.biz/ja/docs/line-things/regist-liff-app/

以下を実行します。

```
$ curl -X POST https://api.line.me/liff/v1/apps \
 -H "Authorization: Bearer {channel access token}" \
 -H "Content-Type: application/json" \
 -d '{
  "view":{
    "type":"{view size}",
    "url":"{LIFF APP URL}"
  },
  "description" : "{LIFF APP name}",
  "features" : {
    "ble": "true"
  }
}'
```

このサンプルリクエストに以下を入れ込んでリクエストしましょう。

* channel access token: BOTのチャンネル基本設定にあるアクセストークン
* view size: full / tall / compact の3種類から指定
* LIFF APP URL: 先ほどのLIFFアプリをホスティングしているURL(今回はngrokのアドレス)
* LIFF APP name: 適当に！

では実行します。xxxxxxxxxxxxxはアクセストークンです。全部書くと長いので...(この辺のトークンなどはマスクしないであとで破棄するスタイルです。)

```
$ curl -X POST https://api.line.me/liff/v1/apps \
 -H "Authorization: Bearer xxxxxxxxxxxxx" \
 -H "Content-Type: application/json" \
 -d '{
  "view":{
    "type":"tall",
    "url":"https://a17dd6e4.ngrok.io"
  },
  "description" : "のびすけのLIFF",
  "features" : {
    "ble": "true"
  }
}'
```

問題なくリクエストできると以下のようにliffidがサーバーからかえってきます。

```
{"liffId":"1483456697-oPzkQ2Rb"}
```

リクエストで`features.ble=true`があるのでここでLINE Thingsを有効にしているみたいですね。

## LINE Thingsの登録

[ドキュメント](https://developers.line.biz/ja/docs/line-things/regist-product/)通りに進めてみます。

先ほどのliffidが必要になります。

以下のサンプルリクエストにliffidを詰め込んでリクエストします。

```
$ curl -X POST https://api.line.me/things/v1/trial/products \
-H 'Authorization: Bearer {channel access token}' \
-H 'Content-Type:application/json' \
-d '{
  "name": "{trial product name}",
  "liffId": "{LIFF APP ID}"
}'
```

* channel access token: BOTのチャンネル基本設定にあるアクセストークン
* trial product nameL: 適当に！ **今回は`n0bisukeTestDevice`にしてみました**
* LIFF APP ID: 先ほど↑で取得したliffid

```
$ curl -X POST https://api.line.me/things/v1/trial/products \
-H 'Authorization: Bearer xxxxxxxxxxxxx' \
-H 'Content-Type:application/json' \
-d '{
  "name": "n0bisukeTestDevice",
  "liffId": "1483456697-oPzkQ2Rb"
}'
```

リクエストに成功すると以下のようなレスポンスが返ってきました。

```
{"id":xxxxxxxxxxxxxxx,"name":"n0bisukeTestDevice","type":"BLE","channelId":xxxxxxxxxxxxxxx,"actionUri":"line://app/1483456697-oPzkQ2Rb","serviceUuid":"1444a9ac-9aa5-42f4-9ca1-894f2a937a05","psdiServiceUuid":"e625601e-9e55-4597-a598-76018a0d293d","psdiCharacteristicUuid":"26e2b12b-85f0-4f3f-9fdd-91d114270e6e"}
```

**ここではserviceUuidの値さえ覚えればOKデス。**
僕の場合では、この`serviceUuid`の`1444a9ac-9aa5-42f4-9ca1-894f2a937a05`の値を利用します。(この値は個別に変わるので各自のserviceUuidを利用しましょう。)

諸々生のデータでちゃってるよう見えて、以下の二つの値はDeveloper Trial用という試しに使ってね的な値で固定値です。 **以下の二つの値はサンプルコードに載っているままなので特に今回書き換えは不要です。**

* psdiServiceUuid: `e625601e-9e55-4597-a598-76018a0d293d`
* psdiCharacteristicUuid: `26e2b12b-85f0-4f3f-9fdd-91d114270e6e`

> 参考: [LINE Things Developer Trial用のLINE Things対応デバイスを作成するときの制限について](https://developers.line.biz/ja/docs/line-things/about-line-things-trial/)

## デバイス側のコードを書き換え

前回（[さっそくLINE Thingsを触ってみた（ESP32でリモートLチカ） #linedevday](https://qiita.com/n0bisuke/items/b0541a32f01007f938a4)）の記事で書き込みをしている[sample.inoの10行目](https://github.com/line/line-things-starter/blob/master/esp32/arduino/sample/sample.ino#L10)を変更します。

```lifftest.ino
省略
・
・
・
// User service UUID: Change this to your generated service UUID
#define USER_SERVICE_UUID "1444A9AC-9AA5-42F4-9CA1-894F2A937A05"
・
・
・
省略
```

レスポンスが小文字で返ってきますが、大文字に直して入れ込んだ方が安心だと思います。

> 手作業で`1444a9ac-9aa5-42f4-9ca1-894f2a937a05`を`1444A9AC-9AA5-42F4-9CA1-894F2A937A05`にしておきました。

(過去にその辺でハマった記憶が...)

## LIFFアプリ側のコード書き換え

liff.jsのUSER_SERVICE_UUIDの箇所も先ほどのUUIDに書き換えます。
ここも、先ほど生成されたUUIDです。

```liff.js
// User service UUID: Change this to your generated service UUID
const USER_SERVICE_UUID         = '1444A9AC-9AA5-42F4-9CA1-894F2A937A05'; // LED, Button
・
・
・
省略
```

**LIFFアプリ側とデバイス側で同一のServiceUUIDを設定してあげる**感じですね。

あと、変更がわかりやすいように

index.htmlに以下のようにimgタグを追記しておきます。（任意）

```index.html
省略
・
・
・
    <!-- Title -->
    <h2>LINE Things Starter</h2>
    <img src="https://pbs.twimg.com/profile_images/1182958704/9a09649f-0b54-4c57-8c91-60d76cbcabfa_400x400.jpg" width="100">
・
・
・
省略
```

## 試す

実際に動かしてみましょう。

### STEP1: デバイス側

Service UUIDを書き換えたら起動させておきましょう。

> m5stackでエラー出る人はこっちでどうだろ。。。？
> https://gist.github.com/n0bisuke/7208879b47561292f621036bc6480207

### STEP2: 前回の連携削除（必要ない人は必要ない）

**ここめちゃハマりました笑** 

今回のように一回試していて同じデバイスでUUIDを書き換えた時にうまく更新されない問題みたいなのがあるみたいです。

>OS では、同じデバイスでファームウェアを書き換えた場合に、うまくデバイスを検出できなかったり、正しく Characteristic が動作しない問題が発生します。(iOS 自身のキャッシュによる問題) ファームウェアを書き換えた際には、iOS の設定画面から Bluetooth デバイスの登録を解除して、Bluetooth を一度 OFF にしたあと、もう一度 ON にすると解決する場合が多いです。 また、LINE Things の連携画面から、デバイスを一度古い product を unlink してください。

ってちゃんと[記事](https://engineering.linecorp.com/ja/blog/line-things-developer-trial/)に書いてましたね。

Androidの人は大丈夫そうなのかな？

ということでやってみます。

こんな感じでとりあえずLINE Things Starterで一回連携試したりしてるとBluetoothのペアリングログがスマホに残ってます。(iPhone画面)

<img src="https://qiita-image-store.s3.amazonaws.com/0/35387/0213db2f-3bf1-7358-fbe2-8e196cb31434.jpeg" width="200">

**これを削除して、Bluetoothをオン/オフしましょう。**

<img src="https://qiita-image-store.s3.amazonaws.com/0/35387/43ead538-51b2-4b34-b937-e3cb5c7f59c9.jpeg" width="200">

LINE Thingsのデバイス管理画面を開いて...

> このURLからもいける(LINEアプリ内から開く) https://line.me/R/nv/things/deviceLink?route=line-things-starter

前回の接続を解除します。

<img src="https://qiita-image-store.s3.amazonaws.com/0/35387/c8ff60a7-1b32-5dce-6426-66b588f4fffc.jpeg" width="200">

こんな感じで解除できます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/35387/0ad52d00-8fb7-d0f8-c2ce-76b926e610cc.jpeg" width="200">

### STEP3: デバイスを選択して開く

過去の連携ログを解除できると（Androidの人はそのまま開けるかも?）
こんな感じでさっき作った **n0bisukeTestDevice**が...!

<img src="https://qiita-image-store.s3.amazonaws.com/0/35387/f7b51a7a-7d87-00c1-1003-67d77b308362.jpeg" width="200">


これを選択すると、先ほど作ったLIFFアプリ画面が開きます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/35387/bb5ff6a6-d5fd-964f-c161-f470f5e9e871.jpeg" width="200">

あとはデバイスとLIFFアプリ画面をそれぞれ操作してみると問題なく動作するかと思います。

> 試し方の参考: [さっそくLINE Thingsを触ってみた（ESP32でリモートLチカ） #linedevday](https://qiita.com/n0bisuke/items/b0541a32f01007f938a4#step4-%E8%A9%A6%E3%81%99)

ただ、何度かやっててLIFF -> デバイス側は少し安定しない印象です。
LINEアプリを再起動したり、デバイスを再起動したりしてうまくいくことがあります。

デバイス側 -> LIFFは結構安定している印象です。

## 終わりに

LIFFをとりあえず自前で動かしてみるってところまで持っていけました。
まだJSのコードは読めてないのでその辺も進めたいですね。

**やはりデバイスやBLEは安定しないことが多いので、デバイスとアプリはそれぞれ何回か再起動して試すと良いかも**しれません。

安定性は今後に期待ですね。