1. はじめに
LINE Things development board
を入手して、今現在できることをいろいろ試した(つもり)なので、他システム連携から利活用含めて考えてみました。
2. LINE Thingsとは
公式によると、
LINE Thingsは、LINEを介して、チャネルとBluetooth® Low Energy対応デバイスを連携し、操作を可能にするIoTプラットフォームです。
とあり、LINEをインターフェースとしたIoTセンサーの利活用だったり、IoTデバイスの制御ができる仕組みを有しています。
誰もが使っているLINEをインターフェースとして活用できるのは大きな利点で、アイデア次第で無限の可能性を秘めていると言えます。
これから開発を考えているのであれば、Messaging API
とLINE 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の永続性が保証されておらず、将来的に削除の可能性もあるとのことなので、その点も考慮する必要があります。
3. MotionBoardとは
データベースやセンサーデータなどを可視化できるソフトウェアです。
商用ソフトウェアですが、各種データベースとの接続や高度な可視化・分析機能が使用できます。
4. 連携のまえに
デフォルトファームウェアをいろいろ試しておくと、何ができるかなんとなく見えてきます。
5. MotionBoardと連携してみる
事前準備
-
LINE Things dev board使用ハンズオン - Qiitaを参考に
LINE Developers にてプロダクトの登録とService UUIDの取得
まで -
Node-RED
などwebhookの受け先となるサーバー- 一番簡単に試すならIBM Cloudのライトアカウント(無償)で
Node-RED
を建てる
- 一番簡単に試すならIBM Cloudのライトアカウント(無償)で
- LINEの最新版が動作しているAndroidまたはiPhone
-
MotionBoardの
IoTエディション
- MQTTを使用してデータを送信するのであればAWS IoTなどの
MQTTブローカー
- リアルタイム連携用テンプレートの作成
- MQTTを使用してデータを送信するのであればAWS IoTなどの
シナリオセットの作成と登録
シナリオセット
の登録には、プロダクトID
、Service UUID
、Characteristic UUID
、チャンネルアクセストークン
が必要です。
準備
-
プロダクトID:プロダクト登録時のプロダクトID。
参考:LINE Things 自動通信機能 ハンズオン - LINE Things プロダクトの作成 -
Service UUID
-
アドバタイズ用UUID
とGATT通信用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
を使っています。リクエスト・レスポンス内容も保存出来て便利です。
一回登録してしまえば、シナリオセット
の変更がない限り、繰り返す必要はありません。
シナリオセット
を更新する際は、同じURLに対して再度リクエストを行ってください。
Node-REDの設定
Webhookの受信用+[MQTTブローカー]の送信先として、Node-REDのフローを作成します。
Node-REDはフロー(ロジックシナリオ)のインポート機能がありますので、[メニュー]->[読み込み]->[クリップボード]の順でクリックします。
下をまるごとコピーして、貼り付けます。
[{"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ノード]をダブルクリックし、編集します。[鉛筆アイコン]をクリックします。
予め準備した[MQTTブローカー]のサーバーアドレスを入力します。また、[セキュリティ]タブから[MQTTブローカー]の認証情報を入力し、最後に[更新]をクリックし、保存します。
設定が終わったら[デプロイ]ボタンを押下して、変更を適用します。
Webhookの設定
LINE Developersにアクセスし、[プロバイダーリスト]から事前に作成したものをクリックします。
[基本設定]タブから、[Webhook送信]を編集して、[利用する]に変更します。
また、[Webhook URL]を編集して、作成したサーバーのURLを指定します。
設定した後、[接続確認]をクリックすることで疎通確認ができます。
ボードの作成
MotionBoardで可視化ボードを作成します。
ステップバイステップで書いてしまうと長くなるので、大まかに書くと、
- ボードの新規作成
- [データソース]を指定します。
- WebAPIやMQTTでデータを送信すると、[system datasources]という専用の領域に格納されますので作成したテンプレート名を指定します。
-
リアルタイム分析
機能をオンにします。 - チャートデザインを選択する(折れ線、棒グラフ、画像、シグナル、シングル数値などから選択)
- アイテムを画面に配置する。(漫画のコマ割りの要領で)
のような手順になります。
- 参考: ボード作成ガイド
6. シナリオを考える
- トラック運転手の毎日の脈拍や体温などの健康状態を登録してもらい、支援部門が全体を管理。
- 未入力の運転手には入力を促すメッセージ送信(Messaging API)
- 学校のプール授業前に生徒に体温測定を義務付け
- イベント運営がボランティアスタッフの位置情報把握と最適タスク分配