LoginSignup
9
8

More than 3 years have passed since last update.

LINE Things development boardをMotionBoardに繋げてみる

Last updated at Posted at 2019-07-02

1. はじめに

LINE Things development boardを入手して、今現在できることをいろいろ試した(つもり)なので、他システム連携から利活用含めて考えてみました。

2. LINE Thingsとは

公式によると、

LINE Thingsは、LINEを介して、チャネルとBluetooth® Low Energy対応デバイスを連携し、操作を可能にするIoTプラットフォームです。

とあり、LINEをインターフェースとしたIoTセンサーの利活用だったり、IoTデバイスの制御ができる仕組みを有しています。
誰もが使っているLINEをインターフェースとして活用できるのは大きな利点で、アイデア次第で無限の可能性を秘めていると言えます。

これから開発を考えているのであれば、Messaging APILINE Front-end Framework(LIFF)については頻繁にでてくる用語なので合わせて知っておきましょう。

LINE Things developer board

温度センサー、3軸加速度センサー、ボタン、有機ELなどを搭載しているLINE Thingsの開発用ボードです。
Bluetooth通信用としてNordic社のnRF52モジュールが搭載されており、高速にプロト開発ができます。
デフォルトでファームウェアが入っていたため、開発用ボード->LINE->LINEプラットホームの疎通確認はすぐにできました。
もっていなくとも、市販の対応ボードで同様のことはできますが、センサーなどは自前で用意する必要があります。

https://github.com/line/line-things-starter/blob/master/README.ja.md
のREADMEによると、

  • LINE Things dev board
  • Espressif ESP32-DevKitC
  • M5Stack (ESP32)
  • Adafruit Feather nRF52 Bluefruit LE - nRF52832
  • Adafruit Feather nRF52840 Express
  • BBC micro:bit
  • Obniz

が現在対応しています。

自動通信機能

LINE Thingsには自動通信機能という機能があります。
事前に、シナリオセットと呼ばれるものをLINEプラットホームに登録しておくことで、LINEがIoTデバイスから受け取ったデータをLIFFを経由することなく、Webhookで指定したURLに流してくれる機能です。
他システムと連携するときに、自前でLIFF上で通信機能を実装する必要がありませんし、LINEアプリを開いておかなくても通信ができます。
またLIFFはCookieやLocalStorageの永続性が保証されておらず、将来的に削除の可能性もあるとのことなので、その点も考慮する必要があります。
image.png

3. MotionBoardとは

データベースやセンサーデータなどを可視化できるソフトウェアです。
商用ソフトウェアですが、各種データベースとの接続や高度な可視化・分析機能が使用できます。

4. 連携のまえに

デフォルトファームウェアをいろいろ試しておくと、何ができるかなんとなく見えてきます。

5. MotionBoardと連携してみる

事前準備

シナリオセットの作成と登録

シナリオセットの登録には、プロダクトIDService UUIDCharacteristic UUIDチャンネルアクセストークンが必要です。

準備

  • プロダクトID:プロダクト登録時のプロダクトID。
    参考:LINE Things 自動通信機能 ハンズオン - LINE Things プロダクトの作成

  • Service UUID

    • アドバタイズ用UUIDGATT通信用UUIDを分けて考える必要があります。
    • LINE Things developer boardであれば個体によらずf2b742dc-35e3-4e55-9def-0ce4a209c552で固定。
  • Characteristic UUID:https://github.com/line/line-things-dev-board のthings-dev-board.js あたりに書いてます。

    • LINE Things dev boardのセンサーとボタン情報をひととおり送信したければe90b4b4e-f18a-44f0-8691-b041c7fe57f2とします。
  • チャンネルアクセストークンLINE Developersコンソールの[チャネル基本設定]から取得することができます。

シナリオセットの作成

LINE Things dev board`のセンサーとボタン情報をひととおりを定期的に自動送信したければ以下のjsonファイルのようになります。

{
    "autoClose": false, 
    "suppressionInterval": 0,  
    "scenarios": [
        {
            "trigger": {
                "type": "BLE_NOTIFICATION",
                "serviceUuid": "f2b742dc-35e3-4e55-9def-0ce4a209c552",
                "characteristicUuid": "e90b4b4e-f18a-44f0-8691-b041c7fe57f2"
            },
            "actions": [
            ]
        }
    ]
}

シナリオセットの登録

LinuxやMacの場合

$ curl -X PUT https://api.line.me/things/v1/products/<YOUR 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": "f2b742dc-35e3-4e55-9def-0ce4a209c552",
                "characteristicUuid": "e90b4b4e-f18a-44f0-8691-b041c7fe57f2"
            },
            "actions": [
            ]
        }
    ]
}'


Windowsの場合
curl.exeでもいいのですが、私はchrome拡張のRestlet Client - REST API Testing
を使っています。リクエスト・レスポンス内容も保存出来て便利です。
image.png

一回登録してしまえば、シナリオセットの変更がない限り、繰り返す必要はありません。
シナリオセットを更新する際は、同じURLに対して再度リクエストを行ってください。

Node-REDの設定

Webhookの受信用+[MQTTブローカー]の送信先として、Node-REDのフローを作成します。
Node-REDはフロー(ロジックシナリオ)のインポート機能がありますので、[メニュー]->[読み込み]->[クリップボード]の順でクリックします。
image.png

下をまるごとコピーして、貼り付けます。

[{"id":"f53f6be6.d8d288","type":"http in","z":"3c49d6d6.16594a","name":"","url":"/line","method":"post","upload":false,"swaggerDoc":"","x":100,"y":220,"wires":[["acd8c0cb.af5a3","c526bc83.d739e"]]},{"id":"acd8c0cb.af5a3","type":"http response","z":"3c49d6d6.16594a","name":"","statusCode":"","headers":{},"x":270,"y":160,"wires":[]},{"id":"3c5f01ec.3d92be","type":"function","z":"3c49d6d6.16594a","name":"MB対応形式に変換","func":"let buffer = msg.payload.events[0].things.result.bleNotificationPayload;\nbuffer = Buffer.from(buffer,'base64');\n\n\nlet temperature = buffer[1].toString(16) + buffer[0].toString(16);\nmsg.temperature = parseInt(temperature, 16) / 100;\n\nif (buffer[3] >= 128) {\n    let accelX = buffer[3].toString(16) + buffer[2].toString(16);\n    msg.accelX = (parseInt(accelX, 16) - 65535) / 1000.0;\n} else {\n    let accelX = buffer[3].toString(16) + buffer[2].toString(16);\n    msg.accelX = parseInt(accelX, 16) / 1000.0;\n}\n\nif (buffer[5] >= 128) {\n    let accelY = buffer[5].toString(16) + buffer[4].toString(16);\n    msg.accelY = (parseInt(accelY, 16) - 65535) / 1000.0;\n} else {\n    let accelY = buffer[5].toString(16) + buffer[4].toString(16);\n    msg.accelY = parseInt(accelY, 16) / 1000.0;\n}\n\nif (buffer[7] >= 128) {\n    let accelZ = buffer[7].toString(16) + buffer[6].toString(16);\n    msg.accelZ = (parseInt(accelZ, 16) - 65535) / 1000.0;\n} else {\n    let accelZ = buffer[7].toString(16) + buffer[6].toString(16);\n    msg.accelZ = parseInt(accelZ, 16) / 1000.0;\n}\n\nlet btn1 = buffer[9].toString(16) + buffer[8].toString(16);\nmsg.btn1 = parseInt(btn1, 16);\n\nlet btn2 = buffer[11].toString(16) + buffer[10].toString(16);\nmsg.btn2 = parseInt(btn2, 16);\n\nmsg.payload = '{\"protocol\": \"1.0\",\"loginId\": \"2\",\"template\": \"iot\",\"tenant\": \"cdl002mb\",\"status\":[{\"time\":' + msg.payload.events[0].timestamp + ',\"enabled\": \"true\",\"values\":[{\"name\":\"temp\",\"type\":\"3\",\"value\":' + msg.temperature + '},{\"name\":\"hash\",\"type\":\"2\",\"value\":\"'  + msg.md5 + '\"},{\"name\":\"accelX\",\"type\":\"3\",\"value\":' + msg.accelX + '},{\"name\":\"accelY\",\"type\":\"3\",\"value\":' + msg.accelY + '},{\"name\":\"accelZ\",\"type\":\"3\",\"value\":' + msg.accelZ + '},{\"name\":\"sw1\",\"type\":\"3\",\"value\":' + msg.btn1 + '},{\"name\":\"sw2\",\"type\":\"3\",\"value\":' + msg.btn2 + '}]}]}';\n\nreturn msg;\n","outputs":1,"noerr":0,"x":450,"y":220,"wires":[["7b1087df.ad6828","f8f67a08.883318"]]},{"id":"c526bc83.d739e","type":"md5","z":"3c49d6d6.16594a","name":"","fieldToHash":"payload","fieldTypeToHash":"msg","hashField":"md5","hashFieldType":"msg","x":270,"y":220,"wires":[["3c5f01ec.3d92be"]]},{"id":"7b1087df.ad6828","type":"debug","z":"3c49d6d6.16594a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":650,"y":160,"wires":[]},{"id":"f8f67a08.883318","type":"mqtt out","z":"3c49d6d6.16594a","name":"","topic":"","qos":"","retain":"","broker":"9cb4f2c2.97e06","x":650,"y":220,"wires":[]},{"id":"9cb4f2c2.97e06","type":"mqtt-broker","z":"","name":"","broker":"","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

[mqttノード]をダブルクリックし、編集します。[鉛筆アイコン]をクリックします。
image.png

予め準備した[MQTTブローカー]のサーバーアドレスを入力します。また、[セキュリティ]タブから[MQTTブローカー]の認証情報を入力し、最後に[更新]をクリックし、保存します。
image.png

設定が終わったら[デプロイ]ボタンを押下して、変更を適用します。
image.png

Webhookの設定

LINE Developersにアクセスし、[プロバイダーリスト]から事前に作成したものをクリックします。
[基本設定]タブから、[Webhook送信]を編集して、[利用する]に変更します。
また、[Webhook URL]を編集して、作成したサーバーのURLを指定します。
設定した後、[接続確認]をクリックすることで疎通確認ができます。
image.png

ボードの作成

MotionBoardで可視化ボードを作成します。
ステップバイステップで書いてしまうと長くなるので、大まかに書くと、

  • ボードの新規作成
  • [データソース]を指定します。
    • WebAPIやMQTTでデータを送信すると、[system datasources]という専用の領域に格納されますので作成したテンプレート名を指定します。
  • リアルタイム分析機能をオンにします。
  • チャートデザインを選択する(折れ線、棒グラフ、画像、シグナル、シングル数値などから選択)
  • アイテムを画面に配置する。(漫画のコマ割りの要領で)

のような手順になります。

image.png

6. シナリオを考える

  • トラック運転手の毎日の脈拍や体温などの健康状態を登録してもらい、支援部門が全体を管理。
    • 未入力の運転手には入力を促すメッセージ送信(Messaging API)
  • 学校のプール授業前に生徒に体温測定を義務付け
  • イベント運営がボランティアスタッフの位置情報把握と最適タスク分配

7. 参考

9
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8