目次
はじめに
過去2回WebiotのセンサーデータをAWSに連携した見える化について記載いたしました。今回はまだまだIoTの注目が集まっている昨今の状況を鑑みて、より汎用的にセンサーデバイスからデータ取得し、AWSへの連携からデータの可視化までを2回に分けてお届けしようと思います。
過去の記事は下記よりご覧ください。
1. 今回のシナリオ
これまでは、センサー側にデータの取得、送信機能があったため、ほぼAWS側の手順となっていましたが、今回はより汎用的に、センサーデータの取得から送信機能までを含めたセンサーデータの可視化の手順を見ていこうと思います。
2. 構築するシステム構成
今回、構築するシステム構成は以下の通りです。
使用するセンサーについて
今回使用するのは、エレックス工業株式会社のμPRISMという超小型のセンサーデバイスです。μPRISMの特徴は、7種類のセンサーとBluetoothを搭載した超小型IoTセンサーで、加速度、地磁気、温度、湿度、気圧、照度、UVの測定が可能です。(μPRISM電池タイプ)
今回は、μPRISMをビーコンモードで動作させ、温度と気圧を定期的に信号を発信させてデータを取得することにしました。
また、センサーと接続して情報を発信するモニタリングボックスとして、当社グループ会社のTDIプロダクトソリューション株式会社(以下、TDIPS)製のモニタリングボックス『MB-3』を使用して、定期的にセンサーからデータを取得できるような構成にしました。(モニタリングボックスはWebSocketに対応しており、センサーからのデータをWebSocket経由で通信が可能)
モニタリングボックス『MB-3』の詳細は当社ホームページでもご紹介しておりますので、ぜひご覧いただければと思います。なお、TDIPSでは、上記のモニタリングボックスなどを使用して、各種センサーを用いたシステムで工場の機器保全を支援しておりますので、もしご興味がある方は、上記ホームページよりぜひご相談いただければと思います。
MQTT通信について
IoT(Internet of Things:モノのインターネット)デバイスでは、インターネットに接続できることが条件となっており、インターネットに接続することで、他のデバイスやサービスと通信できるようになっています。
インターネットの基礎となっているネットワークのプロトコルはTCP/IPであり、IoT通信ではTCP/IPをベースに作成されたMQTT(Message Queuing Telemetry Transport)が標準的な通信プロトコルになっています。
MQTTは、1990年代後半にIBMが考案して開発したプロトコルで、当初は油田パイプラインに取り付けられたセンサーを衛星とリンクするために使用されていましたが、そのパブリッシュ/サブスクライブモデルを採用していたことで2014年後半になって、正式にOASISオープンスタンダードになり、現在ではよくつかわれているプログラミング言語でサポートされるようになっています。
なぜIoT開発にMQTTが採用されているかというと、MQTTは軽量さと柔軟性においてIoTを開発する際にバランスが通信プロトコルといえるからです。
- 軽量なプロトコルであるということは、制約が厳しいデバイス・ハードウェア上でも、待ち時間が長かったり帯域幅がかぎられているネットワーク上でも実装し易いということを意味します。
- MQTTの柔軟性は、IoTデバイスやサービスの多種多様なアプリケーションシナリオをサポートすることができるということを意味します。
そして、MQTTプロトコルの重要な特徴は、そのパブリッシュ・サブスクライブモデルで、データの送信側と受信側をブローカーという役割を介して切り離すことが可能です。
パブリッシュ・サブスクライブモデルについてはここでは詳細な説明はしませんが、このモデルを採用することでMQTTにおいて、送信側はブローカーに対してメッセージに『トピック』をつけて送信(以下、パブリッシュ)し、クライアントである受信側もブローカーから『トピック』を受信(以下、サブスクライブ)してメッセージの転送をやり取りする仕組みとなっています。
3. センサーデータの取得
まずは、センサーとモニタリングボックスとPCを接続して、PC上のプログラムからセンサーの値が取得できることを確認します。
3-1. センサーとモニタリングボックスの接続
センサーのμPRISMとモニタリングボックス『MB-3』を繋げます。今回はμPRISM側で既にBluetoothでモニタリングボックスとの接続設定を行っています。
次に、今回はプログラムはPC上で動作させるため、モニタリングボックスとPCを接続して、PC上のネットワーク設定を行います。モニタリングボックス自体のIPアドレスが『172.28.0.3』であるため、PC上のネットワーク設定のIPアドレス(IPv4)のレンジ設定を以下のように行います。
モニタリングボックスにPingが通れば、ネットワークの設定はOKです。
ちなみにこのμPRISMのセンサーは本当に小さいのです。デバイスはどこにでも持ち運べる大きさもメリットになるのではと思います。(10円硬貨と比べても一回り大きいくらいのサイズ感)
また、モニタリングボックスで設定されたI/F仕様は以下のとおりです。
3-2. クライアントプログラムの作成
次に、データの送信元(Publish)になるクライアント側のプログラムを作成します。
今回はJavaScriptのnode.jsを使用してクライアントプログラムを作成しています。(JavaScriptを選択した理由は、簡単にコードが書け、テストがしやすいのと、WebSocket、MQTTそれぞれのプロトコルのライブラリが充実しているという2点です、後は筆者が慣れているというところが最大の要因ですが…)
node.jsになじみがない方などは、こちらの公式サイトからインストールから利用方法までが記載されているので参考にして下さい。
node.jsが正常にインストールされているPCでは、コマンドプロンプトで node --version と入力するとnode.jsのバージョン情報が返ってきます。
まずPC上で以下のプログラムを作成して、センサーの生データを受信してみます。
node.jsでプロジェクトの作成や初期化はこちらが参考になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// WebSocketClient 初期化 var WebSocketClient = require('websocket').client; var client = new WebSocketClient(); // socket接続時 client.on('connect', function(connection) { // 接続成功! console.log('websocket connected !'); // socket接続エラー時 connection.on('error', function(error) { console.log("connection error(websocket) : " + error.toString()); }); // socketデータ受信時(nodeの場合、ArrayBufferで返却) connection.on('message', function(e) { var buf = e.binaryData; console.log("received -------------------------"); console.log(buf); console.log(buf.byteLength); }); // WebSocket message.on // socket接続切断時 connection.on('close', function() { console.log('WebSocket Client Closed'); }); }); // モニタリングボックスへwebsocket接続 var con = 'ws://172.28.0.3/vreg?readBlocks=0x0300&interval=9000'; client.connect(con); |
以下のようにBufferでセンサーからのデータは取得できており、モニタリングボックスで設定されたI/F仕様の通り設定されているようですが、まだこれでは具体的に何がどうなっているか、人が解釈できる状態ではなく読み取りにくい値になっています。
byte | 値 | メモ |
1-2 | 経過時間 | 送信後の経過時間 |
3-4 | ProofIDの下12bit | 固定値、センサーのBDAddress(MACアドレス)の下12bit |
5-6 | 温度 | リトルエンディアン16進数の値、Q15フォーマット(LSB=100) |
7-8 | 湿度 | リトルエンディアン16進数の値、Q15フォーマット(LSB=100) |
例えば、Bufferが [09 00 8e ef 9f 22 b9 42] となっている場合は以下のように解釈されます。
この値はリトルエンディアンで格納されているので、各項目は逆から読み込み、Q15フォーマット(LSB=100)は、16進→10進変換した値を2^15(=32768)で割り100掛けて変換していきます。
byte | 値 | 解釈された値 |
1-2 | 09 00 | 0x0009 → 9 (秒経過時点) |
3-4 | 8e ef | 0xEF8E → f8e (センサーのBDAddress(00:08:9c:00:1F:8e)の下12bit) |
5-6 | 9f 22 | 0x229f → 8863 →27.0477… → 27.05 (温度、℃) |
7-8 | b9 42 | 0x42b9 → 17081 →52.1270… → 52.13 (湿度、%) |
3-3. センサーデータの確認
次に、上記で受信したデータを人が解釈できるようにするため、以下のようにプログラムを改修しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
// WebSocketClient 初期化 var WebSocketClient = require('websocket').client; var client = new WebSocketClient(); // 10進 → 16進変換(2byte、16bit) function decimalToHexString(number) { if (number < 0) number = 0xFFFF + number + 1; return number.toString(16).toUpperCase(); } // リトルエンディアン16進 → 10進変換(2byte、16bit) function littleEndianHexToDec(hexstring) { if (hexstring == '0') return parseInt(hexstring); var number = parseInt('0x'+ hexstring.match(/../g).reverse().join('')); return number; // decimal } // リトルエンディアン16進 → 16進変換(2byte、16bit) function littleEndianHexToHex(hexstring) { if (hexstring == '0') return parseInt(hexstring).toString(16).toUpperCase(); var number = parseInt('0x'+ hexstring.match(/../g).reverse().join('')); return number.toString(16).toUpperCase(); // Hex } // Q15フォーマットの10進を通常の10進数の固定長少数(digits=2)に変換 function q15DecToFixed(number) { // Q15フォーマット、LSB=100 を通常の10進の固定長少数に変換 var num = number * 100 / 32768; return num.toFixed(2); } // socket接続時 client.on('connect', function(connection) { // 接続成功! console.log('websocket connected !'); // socket接続エラー時 connection.on('error', function(error) { console.log("connection error(websocket) : " + error.toString()); }); // socketデータ受信時(Nodeの場合は、Bufferとなる模様) connection.on('message', function(e) { var buf = e.binaryData; console.log("received -------------------------"); console.log(buf); console.log(buf.byteLength); // buffer → ArrayBuffer var ab = new ArrayBuffer(buf.byteLength); var view = new Int8Array(ab); for ( var i=0; i < buf.byteLength; i++) { view[i] = buf[i]; } var dv = new DataView(ab); var offset = 0; // ArrayBufferのオフセット // BLE通信データ(Blob)の解析 offset = 0; // 経過時間(16進) console.log('dataAge(hex) - 0x' + littleEndianHexToHex( decimalToHexString(dv.getInt16(offset)) )); offset += 2; // major、minor(16進、プルーフID:BD Address下12bit)、2byteずらす var proofid_u12bit = littleEndianHexToHex( decimalToHexString(dv.getInt16(offset))); console.log('proofid(hex) - 0x' + proofid_u12bit); offset += 2; // 温度 value[0](10進)、2byteずらす var tempQ15Hex = littleEndianHexToHex( decimalToHexString(dv.getInt16(offset)) ); var tempQ15Dec = littleEndianHexToDec( decimalToHexString(dv.getInt16(offset)) ); var temperature = q15DecToFixed(tempQ15Dec); console.log('temperature - 0x' + tempQ15Hex + ' -> dec-q15 : [' + tempQ15Dec + '] -> dec : [' + temperature + ']'); offset += 2; // 湿度 value[1](10進)、2byteずらす var humidityQ15Hex = littleEndianHexToHex( decimalToHexString(dv.getInt16(offset)) ); var humidityQ15Dec = littleEndianHexToDec( decimalToHexString(dv.getInt16(offset)) ); var humidity = q15DecToFixed(humidityQ15Dec); console.log('humidity - 0x' + humidityQ15Hex + ' -> dec-q15 : [' + humidityQ15Dec + '] -> dec : [' + humidity + ']'); }); // WebSocket message.on // socket接続切断時 connection.on('close', function() { console.log('WebSocket Client Closed'); }); }); // モニタリングボックスへwebsocket接続 var con = 'ws://172.28.0.3/vreg?readBlocks=0x0300&interval=9000'; client.connect(con); |
下記の赤枠の値が、センサーから取得した値です、温度(temperature)と湿度(humidity)の値が10進で表示され、センサーからデータが取得できていることが確認できます。
以上で、PC上でセンサーの値が取得できることが確認できました。次回の記事で、クラウドのAWS上にデータ連携していきます。お楽しみに!
執筆者プロフィール

- tdi デジタルイノベーション技術部
- 社内の開発プロジェクトの技術支援、クラウド開発支援を担当。まずは手を動かす!をモットーになんでも屋さんとして奮闘中。最近はコンテナ技術やマイクロサービスの現場活用に向け日々精進してます。
この執筆者の最新記事
Pick UP!2020.03.27汎用的な仕組みでセンサーデータを見える化してみた――後編
Pick UP!2020.03.27汎用的な仕組みでセンサーデータを見える化してみた――前編
AWS・クラウド2019.04.01AWSでIoTデータを見える化してみた その2
AWS・クラウド2019.01.22AWSでIoTデータを見える化してみた