#linethings でバイクの盗難防止装置作ってみた

<img width="１０００" alt="LINE Things anti-theft system" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164153/126aeee9-79bd-efa7-0490-5fbba61ace94.png">

2019年4月にリリースされたLINE Things 自動通信機能を利用してバイクの盗難防止装置を作ってみました。本投稿では、その概要と開発手法を解説します。自動通信機能の詳しい解説を知りたい方は[公式ブログ](https://engineering.linecorp.com/ja/blog/line-things-automatic-communication/)をご確認下さい。

# 作ったもの

* 帰宅後バイクのマフラーにセットし電源を入れると動作開始
* マフラーの温度、加速度センサーの値をLINE App経由でサーバーに送信し続ける
* 値が著しく変化すると盗難されそうになっていると判断し、LINEに通知する

# 開発

## デバイス側

今回はセンサーが内蔵されている[LINE Things development board](https://github.com/line/line-things-dev-board)を利用します。

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

[こちら](https://github.com/line/line-things-dev-board)を参考に、Arduino IDEのセットアップを完了させます。空のスケッチを書き込みエラーが出ないことを確認します。

次に、development board用のライブラリをインクルードします。`スケッチ > ライブラリをインクルード > ライブラリを管理`と進み、検索窓にキーワードを入力してフィルタリングし、以下を追加します。

|検索キーワード|インストールするライブラリ|
|----|----|
|MMA8452Q|SparkFun MMA8452Q Accelerometer by SparkFun Electronics|
|Adafruit SSD1306|Adafruit SSD1306 by Adafruit|
|Adafruit GFX Library|Adafruit GFX Library by Adafruit|

`things_temp_lib`については手動でインクルードする必要があります。以下のコマンドでzipに固め、`スケッチ > ライブラリをインクルード > .ZIP形式のライブラリをインクルード`からインクルードして下さい。

```shell
$ git clone https://github.com/line/line-things-dev-board.git
$ cd line-things-dev-board/library/
$ zip -r linethings_temp_lib.zip linethings_temp_lib/
```

新規ファイルを作成し、[https://github.com/line/line-things-dev-board/blob/master/arduino/linethings-dev-default/linethings-dev-default.ino](https://github.com/line/line-things-dev-board/blob/master/arduino/linethings-dev-default/linethings-dev-default.ino)の中身をコピーして書き込み、エラーが出ないことを確認します。

### Trial Productの作成

[Developer Center](https://developers.line.biz/console)からMessaging APIのチャネルを作成し、アクセストークンを取得します。

また自動通信においてもLIFFの作成は必須のため、適当なURLで`BLE feature`をONにしたLIFFを作成し、`app/`のあとのIDを控えておいて下さい。

取得したアクセストークを利用し、ターミナル等から以下のコマンドを実行します。

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

以下のような形で値が返却されるので、控えておいて下さい。

```shell
{
  "id": 000000000000,
  "name": "Sample Product",
  "type": "BLE",
  "channelId": 00000000,
  "actionUri": "line://app/XXXXXXXX-XXXXXXXX",
  "serviceUuid": "",
  "psdiServiceUuid": "e625601e-9e55-4597-a598-76018a0d293d",
  "psdiCharacteristicUuid": "26e2b12b-85f0-4f3f-9fdd-91d114270e6e"
}
```

戻ってきた値を控えておきます。ついでにMessaging APIチャネルのQRコードを撮影し友だち追加をし、アプリの設定画面からペアリングを完了させておきます。

### ファームウェアのUUIDの値を書き換えて書き込み

```c++
define DEFAULT_ADVERTISE_UUID "f2b742dc-35e3-4e55-9def-0ce4a209c552"
.
.
define USER_SERVICE_UUID "f2b742dc-35e3-4e55-9def-0ce4a209c552"
```
の2行の値を、Trial Product作成APIを叩いた戻り値内の`serviceUuid`のものに置き換え、更に下部を以下の通り変更し、

```c
// Notify Timing
// コメントアウト
// if (g_flag_notify && Bluefruit.connected()) {
  int16_t sw1 = (sw1_value) ? 1 : 0;
  int16_t sw2 = (sw2_value) ? 1 : 0;
  int16_t tx_frame[6] = {
    (int16_t) temperature * 100,
    accel.cx * 1000,
    accel.cy * 1000,
    accel.cz * 1000,
    sw1,
    sw2
  };
  blesv_devboard_notify.notify((uint8_t*)tx_frame, sizeof(tx_frame));
  g_flag_notify = 0;
// コメントアウト
//}
// delay(100);
delay(10000); // 変更
```

書き込みます。

キャッシュが残ってしまうことがあるので、連携解除、ペアリング解除、LINEアプリの再起動、Dev Boardの情報リセット(SW1を押しながら起動)等をお試し下さい。

### シナリオセットの登録

最後にTrial Productにシナリオセットを登録し、development boardからの値を自動通信を利用してNotifyするよう設定しましょう。以下のコマンドを実行します。

```shell
curl -v -X PUT https://api.line.me/things/v1/products/<TRIAL PRODUCT ID>/scenario-set \
-H "Authorization: Bearer {YOUR_CHANNEL_ACCESS_TOKEN}" \
-H 'Content-Type:application/json' \
-d '
{
  "autoClose": false,
  "suppressionInterval": 0,
  "scenarios": [
    {
      "trigger": {
        "type": "BLE_NOTIFICATION",
        "serviceUuid": "<YOUR SERVICE UUID>",
        "characteristicUuid": "e90b4b4e-f18a-44f0-8691-b041c7fe57f2"
      },
      "actions": [
      ]
    }
  ]
}'
```

これでペアリングが終わっている端末がBluetoothの範囲にいる間でかつLIFFを開いていない時には、スケッチに記述の通り、10秒おきに以下のようなJSONがWebhookとしてBotのWebhook URLに飛ぶようになります。

```javascript
{
  "events": [
    {
      "type": "things",
      "replyToken": "",
      "source": {
        "userId": "",
        "type": "user"
      },
      "timestamp": 1557027988663,
      "things": {
        "deviceId": "",
        "result": {
          "scenarioId": "01D99MDBF1HFTV16FFD0YMX8G0",
          "revision": 2,
          "startTime": 1557027978,
          "endTime": 1557027988,
          "resultCode": "success",
          "bleNotificationPayload": "jArd/wIA9gMAAAAA/+nVpQ==",
          "actionResults": []
        },
        "type": "scenarioResult"
      }
    }
  ],
  "destination": ""
}
```

## サーバー側

### 監視サーバーの開発

監視サーバーはdevelopment board上のセンサーの値を前項記載のフォーマットでWebhookを通じて定期的に値を受け取り、以下の条件が発生するとLINEアプリに通知します。

* 加速度センサーのx,y,z合計値の前回との差分が`0.15`以上
* 温度センサーの値が前回との差分が10度以上

Heroku用のプロジェクトを[こちら](https://github.com/stachibana/linethings-motorbike-security)で公開しているので`git clone`して`/static/liff-starter.js`の`USER_SERVICE_UUID`の値を前項と同じものに書き換え、Herokuにデプロイします。データベースにRedisを利用しておりますので、Add onから有効化して下さい。

値の読み取りの部分だけ特有の形になりますので貼っておきます。

```python
    # Read value end decode
    decoded = base64.b64decode(
        event["things"]["result"]["bleNotificationPayload"])

    temperature = float(numpy.frombuffer(
        buffer=decoded, dtype='int16', count=1, offset=0)[0] / 100.0)

    acx = float(numpy.frombuffer(buffer=decoded,
                                 dtype='int16', count=1, offset=2)[0] / 1000.0)
    acy = float(numpy.frombuffer(buffer=decoded,
                                 dtype='int16', count=1, offset=4)[0] / 1000.0)
    acz = float(numpy.frombuffer(buffer=decoded,
                                 dtype='int16', count=1, offset=6)[0] / 1000.0)
    accelerometer = acx + acy + acz
```

デプロイが完了したら、LIFFのエンドポイントURLを`https://<your app name>.herokuapp.com/`に、Messaging APIの`Webhookを利用する`をONにしWebhook URLを`https://<your app name>.herokuapp.com/callback`に設定します。

注意点として、LIFFはキャッシュされることがあります。その際は`templates/index.html`下部の`liff-starter.js`読み込み部の`?id=XXXX`を置き換えると再度読み込まれます。

# デモ

自分のバイクで試してみたのですが、急激に温度が上がるところがなく温度検知の部分はデモできず。

傾き検知 → LINEで通知は以下のようになります。見えにくいですがサイドスタンドで駐車中のバイクを真っ直ぐにすると通知が来ていることが分かります。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">大型新機能リリース！ &gt; LINE Things新機能の自動通信でバイクの盗難防止装置作ってみた <a href="https://t.co/wSDdhJrIHG">https://t.co/wSDdhJrIHG</a> <a href="https://twitter.com/hashtag/linethings?src=hash&amp;ref_src=twsrc%5Etfw">#linethings</a> <a href="https://twitter.com/hashtag/line_api?src=hash&amp;ref_src=twsrc%5Etfw">#line_api</a> <a href="https://t.co/6D591t46Of">https://t.co/6D591t46Of</a></p>&mdash; tachibana (@stachibana) <a href="https://twitter.com/stachibana/status/1126063815290802176?ref_src=twsrc%5Etfw">May 8, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

なおUSBからの給電になっていますが、はんだ付けすれば電池駆動も可能です。

[@ufoo68さん](https://qiita.com/ufoo68)の記事「[LINE Thingsでパトランプを回してみた](https://qiita.com/ufoo68/items/63dc64958cddd6bfb36a)」と組み合わせてパトランプが回るようにしたりするのも面白いかもしれませんね。

# もっと詳しく知りたい方は

公式ドキュメント
https://developers.line.biz/ja/docs/line-things/about-auto-communication/

公式ブログ
https://engineering.linecorp.com/ja/blog/line-things-automatic-communication/

また現在のところ、以下のイベントが予定されています。両方共既に満員ですがキャンセルも出ると思いますので是非お申し込み下さい。

LINE Things 自動通信機能のハンズオン(LINE Things開発者によるハンズオン)
https://code4osaka.connpass.com/event/129124/

デジットハッカソン令和(LINE Things開発者がメンターとして参加)
https://digithack.jp/

# 他LINE Things関連記事

[M5StickCでLINE Thingsの自動通信機能を試してみた](https://qiita.com/h-takauma/items/b9cdc48259879a37b6b2)

[LINE Thingsでウェアラブルデバイスつくってみた](https://qiita.com/K_M95/items/a1d461334441147df652)

[LINE Things とM5Stack で子どもの帰宅／外出を通知できる仕組みを作ってみた]
https://qiita.com/sumihiro3/items/965998815a0b975a465a

# まとめ

これまではLIFFを経由した通信のみでしたが、自動通信機能が追加され出来ることが大幅に増えました。また、開発も簡単でLINEを利用することでユーザーにとって格段にIoT機器の導入の障壁が下がることが予想されます。

皆様も是非何か作ってみて下さい。

既に製品化やリリース済み製品への導入をお考えの方は[LINE Things Partnership Form](https://feedback.line.me/enquete/public/4156-QNwBKF85)からお問い合わせ頂くとスムーズです。