IBM Bluemix を使って
モバイルのセンサーデータ
を利用する
IoTの時代が到来
家電や車、ビルや工場、橋など、世界中の様々なモノがインターネットにつ
ながり始めています。
Smart Scales
Connected car
Mobile
Heating and Air
Conditioning
Building
Security
Smart Deliveries
Smart Meter
Vending
Machine
HealthCare
Container
Tracking
クラウドサービスを使ったIoT アプリの構成例
クラウド・サービス
センサ
デバイス
iBeacon
(BLEデバイス)
(BLE検知デバイス)
OpenBlocks
検知デバイス
DB
分析
モバイル
通知
接続
バック
エンド
連携
IBM Bluemix
Bluetooth
例: ビーコンを活用した、新しい顧客体験
IoTを支える次世代の通信プロトコル、MQTTとは?
M2MやIoTの実現に適したシンプルで軽量なプロトコル
•
双方向、1対Nの通信
•
プロトコルヘッダーは最小2バイト(HTTPだと50バイト~、HTTPの1/10のトラフィック)
•
省電力
•
Publish/Subscribe型であり、同期処理が必要となるHTTPより、処理が高速
•
不安定な環境での通信に強い
Topicに投稿
購読者に配信
Topicを購読
Bluemix上で利用出来るMQTT関連サービス
IoT Foundation
Bluemix IoT Service
IoT Foundation
•
クラウド上で提供される、「MQTTサーバーサービス」(MQTT Broker)
•
認証なしで、誰でも使用出来る「Quick Start Service」が使える!
Bluemix IoT Service
ハンズオンで作成するアプリケーション
IBM IoT
Foundatio
n
デバイス
IBM
Bluemix
アプリケーション
スマホのセンサーで計測した位置情報を
MQTT BrokerにPublish
MQTT Broker
位置情報をSubscribeし、Google
Map上に表示
IoT Foundationサービスは
センサーデータを仲介
スマホをセンサとみなし、スマホからMQTTで送信される位置情報をリアルタイムで
Google Mapに表示する
最終形のイメージ1 : スマホのセンサーデータの取得
下記のQRコードから、「センサーデータ取得 & MQTT送信」を行うWebページにアクセ
スし、Device ID / 位置情報 / 傾きのデータがリアルタイムで取得されていることを確
認
Geo Location API
で位置情報を取得
(Javascript)
MQTTで位置情報を
MQTTサーバに送信
(Javascript)
Bluemix上で稼働
最終形のイメージ2 : Node-Red アプリケーション
MQTT Subscribe
(センサデータ取得)
位置情報を抽出
Web Socketで位置情報
をリアルタイム通信
HTTP GET Requestの待
最終形のイメージ3 : Google Mapでスマホの位置を表示
スマホの位置情報がリアル
Webアプリケーション・サーバー作成(Node-RED Starter)
スマホセンサーを取得するWebページをホストするサーバーを作成
• 単純なHTML + Javascriptであり、どのランタイム(言語)でも良い
• 今回はMQTT SubscribeするアプリをNode-Redで作成するため、Node-RED
Starterを使用することとする
Node-RED スターターコードのダウンロード
Node-REDを含むWebアプリケーションのひな形をLocal PCにダウンロードします。
• ひな形に、スマホのセンサーデータを取得するHTML / Javascriptを加え、再度
スターターコードを作業フォルダに配置
作業フォルダを作成し、スターターコードをフォルダごとCopy
• フォルダ名や場所は任意
Githubからソースコードを取得
1.
Githubにアクセス
し、ソースコードをダウンロード
• https://github.com/MasayaFujita/Phone_Sensor
2. ファイルを解凍し、スターターコードの「public」フォルダの中にCopy
ダウンロード
解凍した中身のsensor_mqtt_htmlとjs フォ
ルダを、スターターコードのpublic下にCopy
ソースコードの概要
sensor_mqtt.html
• スマホからアクセスすると、位置情報や傾き等のセンサーデータを取得し、表示する
HTML
js/sensor_mqtt.js
• Geolocation API等を用いて、センサー情報を取得
• MQTT Broker(IoT Foundation)にデータを送信
js/mqttws31.js
• Paho MQTT Javascript client library
• JavascriptでMQTT Client(Publisher, Subscriber)を構成する際に必要な
Library
HTML : sensor_mqtt.html
head要素でPaho MQTT
Javascript ClientのJS Fileを読み込
む
jQuery
センサ値取得 & MQTT
送信を行うJavascript
Geolocation API
Geolocation API
• javascriptでユーザーの位置情報を扱うためのAPI。主要ブラウザでサポートされている。
• 無線LAN・WiFi・携帯電話基地局・GPS・IPアドレスなどから位置情報を取得
位置情報を含むpositionオブジェクトが渡され、
コールバック関数が実施される
Paho MQTT Javascript client: 概要
Paho MQTT Javascript Client
• WebsocketでMQTT Brokerとデータを双方向通信するためのJavascript Library
http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.javascript.git/plain/src/mqtt
ws31.js
• データはJSON形式で送受信する。
MQTT Broker情報を指定し、
接続用Objectを生成
User情報
MQTTサーバへ接続
Topic: /WorldをSubscribe
データをTopic: /WorldへPublish
Paho MQTT Javascript client: コード説明
デバイスを識別するID
IoT FoundationのQuickstart
(MQTTサーバ)のアドレス
接続Object作成
送信データObjectの作成。
JSONに変換して送信
MQTT Publish
cf コマンドのインストール
Local PC上のソースコードをBluemixにデプロイするツールである「cf コマンド」をインスト
ールする。
1.
Githubにアクセス
(https://github.com/cloudfoundry/cli)し、ダウンロード
2. コマンドプロンプト(OS Xではターミナル)で動作確認:cf -v
バージョンが無事表示さ
れればOK
※ Macで、「開発元が未確認のため開けません」と表示される場合は、「システム環境設定」 >> セキュリティーと
プライバシーにて、「ダウンロードしたアプリケーションの実行許可」にて、「すべてのアプリケーションを許可」するように設
定を変更して下さい
cf コマンドでBluemixへログイン
1.
コマンドプロンプトでルートフォルダへ移動(package.jsonが存在するフォルダ)
2.
cf login コマンドでBluemix環境へログイン
Bluemixにアプリケーションをデプロイ
1. cf push コマンドでBluemixにアプリケーションをPush
•
> cf push (アプリケーション名)
スマホセンサーの稼働確認
スマートフォンからデプロイしたWebページにアクセス
2. 位置情報をGoogle
Mapに表示するアプリをNode-REDで作成する
Node-RED について
IBM 英国Hursley 研究所の Emerging Technology Teamで開発されたソ
フトウェア
• 2013年、社内ハッカソンで堂々一位、GitHub に登録
• 2014年 Qcon で発表
Node-REDの特徴
ブラウザベース UI
node.js で動作
• 軽量
機能をカプセル化してNodeと
して利用
独自Nodeを作成・追加可能
Bluemixの様々なサービスを
簡単に利用可能
ハードウェアデバイス,API,オンラインサービスが画期的な
方法で結合された"仮想環境をブラウザ上で実現
Bluemixでなくて
も使用可能です
Node-RED 画面
デプロイ実行
シート
ノード
表示情報の
切り替え
実装UI
処理フロー
①ノードを選択し
ドラッグ&ドロップ
Node-RED実装方法
②ノード間を
接続
④Deployを選択
Node-RED画面
③ノードプロパティ設定
Node分類
機能
Input
イベントの起動条件の設定
Output
外部アプリへの送信
Function
イベント分岐、受信データの変換、一時停止 等
Social
Twitter/Mail/ircの送受信
Storage
DBへの保存、DB検索
Analysis
分析
Advanced
RSS/atomの更新受信時にイベント起動
コネクタが右側に存在
⇒①イベントの起動
イベント起動条件を満たし
コネクタが左右に存在
⇒②データ変換/分岐
左からデータ受信。
コネクタが左側に存在
⇒③外部アプリ起動/DB保存
左からデータを受信し、それを送
Node-RED搭載ノードの紹介 (代表的なもの)
①イベントの起動
Node名称
イベント開始条件
後続フローに送信する内容
Inject
定期起動orノードのクリック
指定文字列or現在時刻or
情報なし(起動のみ)
デバック向けの機能。
http
http://[xxxxxxx].mybluemix
.net/[ノードのURL]リクエスト送信
時
リクエスト情報
メール受信時、または未読メール存
在時定期起動
メール本文(text/plain)
指定メッセージのTweet時に自動
起動
Tweet情報
(本文、発言場所、国…)
Feedparse
RSS/atomの更新受信時
-コネクタが右側に存在するもの
Node名称
機能
後続フローに送信する内容
Function
受領データの更新
更新済データ
Switch
条件に応じて、フローを分岐させる
受信データ
Delay
フローを待機
受信データ
http request
指定サイトに接続
接続サイトのソース
Cloudant
DB検索
DBの検索結果
Sentiment
受信データをセンチメント分析
評価情報を追加した受信データ
Html
HTMLソースのうち、指定タグをすべ
て取得
指定したタグの情報
コネクタが左右に存在するもの
②データ変換/分岐
Node名称
機能
Debug
フロー上に流れている情報を画面表示
http response http requestを返す
Cloudant
DBへのデータ保存
メール送信
コネクタが左側に存在するもの
③外部アプリ起動/DB保存
プログラミング
JavaScriptで記述します
• 簡易エディターが付属
• 非同期処理も可能
※より複雑な処理は node の作
成をお勧めします。
覚えておくNode-RED固有変数
“msg”
“msg” オブジェクト: node 間を流れるメッセージを表す JSON オブジェクト。
msg.payload はかならず存在する。msg.<string> で新しい属性を追加できる。
“context” オブジェクト: node 内部で保存される任意の JSON オブジェクト
“context.global” オブジェクト: node 間で共有されるグローバルオブジェクト
“context”
“context.global”
Node-REDの起動
IoT Foundation(MQTTサーバー)からのデータ取り出し
「ibmiot」ノードをドラッグ & ドロップ
• MQTTサーバー上のDevice IDに紐づくデー
タをSubscribeする
• MQTTサーバー上にスマホの位置情報が届い
たら、取り出す。
「ibmiot」ノードの設定
1. ノードをダブルクリック
2. Quickstartを選択
3. スマホの画面に表示されている
Device IDを入力
ドラッグ&ドロップ
スマホに表示され
ているDevice
ID
データ受信ができているかどうかの確認
debugウィンドウに受信データを表示
1. 「debug」ノードを「ibmiot」と接続
2. 「Deploy」ボタンをを押し、Node-REDアプ
リケーションをDeploy
3. debugウィンドウにJSON形式でセンサーデ
ータが流れてきていればOK
データの絞り込み
1秒に1Messageのみ処理する
1. 「delay」ノードを接続
2. Actionを「Limit rate to」に設定
3. Rateを「1」 msg(s) per Secondに
設定
4. drop intermediate messageをチ
ェック (余計なデータを廃棄する)
5. Deploy
6. 1秒間でdebugウィンドウにメッセージ
が流れてくることを確認
緯度・経度情報の抜き出し
var latitude = msg.payload.d.location.
lat
;
var longitude = msg.payload.d.location.
lng
;
msg.payload = '[{"lat":"' + latitude +
「function」ノードで、センサーデータから、緯度・経度データのみを抜き出す
1. 「function」ノードを接続
2. 「function」に下記のjavascript コードを記載
•
msg.payloadに、MQTTサーバーから取得したJSONデータが含まれる
•
緯度・経度のみをmsg.payloadに設定し、次のノードに流す
3. Deployし、結果を確認
Google Map APIを使った位置情報の可視化 1
WebSocketの通信チャネルの構成
位置情報をリアルタイムで送信
/locationにて、HTTP GET リ
Google Map APIを使った位置情報の可視化 2
NodeフローのImport
1. 次のページのJSON形式のデータをクリップ
ボードにCopy
2. 右上のMenuボタンからImport画面を表
示
3. 入力ボックスにペーストしてImport
4. 既存のNodeと接続する
接続する
ImportするNodeフローの情報
[{"id":"9457624.f6ba8a","type":"websocket-listener","path":"/ws/phone_location","wholemsg":"false"},{"id":"e0e0edd5.1f1f1","type":"function","name":"function 1","func":"// The received message is stored in 'msg'¥n// It will have at least a 'payload' property:¥n// console.log(msg.payload);¥n// The 'context' object is available to store state¥n// between invocations of the function¥n// context = {};¥ncontext.global.location = msg.payload;¥n¥nreturn
msg;","outputs":1,"noerr":0,"x":460,"y":178,"z":"b92fcfc3.46d03","wires":[["79854d92.867ab4"]]},{"id":"e2cc9f01.1d336","type":"function","name":"function 2","func":"// The received message is stored in 'msg'¥n// It will have at least a 'payload' property:¥n// console.log(msg.payload);¥n// The 'context' object is available to store state¥n// between invocations of the function¥n// context = {};¥n¥nmsg.payload = context.global.location;¥n¥nreturn
msg;","outputs":1,"noerr":0,"x":446.9999694824219,"y":239,"z":"b92fcfc3.46d03","wires":[["79854d92.867ab4"]]},{"id":"79854d92.867ab4","type":"websock et out","name":"","server":"9457624.f6ba8a","client":"","x":662.9999847412109,"y":239,"z":"b92fcfc3.46d03","wires":[]},{"id":"d38b4a94.2c74b8","type":"http response","name":"","x":648.9999847412109,"y":315,"z":"b92fcfc3.46d03","wires":[]},{"id":"9280276.f6d7fd8","type":"template","name":"Google Map HTML","field":"","template":"<!DOCTYPE html>¥n<html>¥n<head>¥n <title>Phone Location</title>¥n <script type=¥"text/javascript¥"
src=¥"http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js¥"></script>¥n <script type=¥"text/javascript¥" src=¥"http://maps.google.com/maps/api/js?sensor=true¥"></script>¥n <script type=¥"text/javascript¥"
src=¥"http://yourjavascript.com/4594301102/gmaps.js¥"></script>¥n ¥n <style type=¥"text/css¥" media=¥"screen¥">¥n #map {¥n position:absolute;¥n top: 0; bottom: 0; left: 0; right: 0;¥n }¥n </style>¥n</head>¥n<body>¥n ¥n <div id=¥"map¥"></div>¥n <script type=¥"text/javascript¥">¥n var socketaddy = ¥"ws://phonefujita.mybluemix.net/ws/phone_location¥";¥n var map;¥n var sock;¥n
$(document).ready(function(){¥n map = new GMaps({¥n div: '#map',¥n lat: -12.043333,¥n lng: -77.028333¥n });¥n sock = new WebSocket(socketaddy);¥n sock.onopen = function(){ console.log(¥"Connected websocket¥");¥n console.log(¥"Sending ping..¥");¥n sock.send(¥"Ping!¥");¥n console.log(¥"Ping sent..¥");¥n };¥n sock.onerror = function(){ console.log(¥"Websocket error¥"); };¥n
sock.onmessage = function(evt){¥n var latlng = JSON.parse(evt.data);¥n var array = $.map(latlng, function(el) {¥n return [[el.lat, el.lng]];¥n });¥n ¥n map.removeMarkers();¥n map.removePolylines();¥n console.log(¥"Got marker at ¥" + latlng[0].lat + ¥", ¥" + latlng[0].lng,
latlng);¥n map.setZoom(17);¥n map.setCenter(latlng[0].lat, latlng[0].lng);¥n map.addMarkers(latlng);¥n map.drawPolyline({¥n path: array,¥n strokeColor: '#131540',¥n strokeOpacity: 0.6,¥n strokeWeight: 6¥n });¥n }¥n });¥n
</script>¥n</body>¥n</html>","x":431,"y":316,"z":"b92fcfc3.46d03","wires":[["d38b4a94.2c74b8"]]},{"id":"19638c78.e69c74","type":"http
in","name":"","url":"/location","method":"get","swaggerDoc":"","x":207.99998474121094,"y":315,"z":"b92fcfc3.46d03","wires":[["9280276.f6d7fd8"]]},{"id":"fd 0f1e9b.02f0e","type":"websocket