以前の投稿で、ローカルネットワークにMosquittoによるIoTブリッジサーバを立ち上げたので、これからいろんなデータをIoTに上げてみたいと思います。
(可視化はいろいろややこしそうなので、おいおい勉強します)
今回のIoTデバイスは、Xaomi Mijia 温湿度計 です。
以下の方が詳しくご紹介されています。(参考にさせていただきました。ありがとうございます)
Xiaomi Mijia 温湿度計レビュー 表示スクリーン付き+スマホ ログ確認
https://bey.jp/?p=63555
(値段を調べてみるとわかるのですが、とにかく安いです。2千円しないです。。。)
この製品は、BLE通信で、温度と湿度を取得することができます。もちろん液晶がついているので、見ても確認できるのですが、これを継続的に蓄積しよう、ということです。
これを室内に配置し、Raspberry PiからBLE接続して、MQTTでAWS IoTに温度と湿度をアップします。AWS IoT側では、受信を契機に、DynamoDBにタンキングします。
なぜ、DynamoDBにしたかというと、今後さまざまなデバイスをIoTで上げようと思っていまして、それぞれのデータの内容が異なるため、スキーマレスなデータベースを使いたかったためです。
Xiaomi Mijia 温湿度計のセットアップ
電池入れて、好きな場所に置くだけです。理由は以降の章で分かります。
Raspberry Piのセットアップ
Node.jsからBLE通信ができるように準備をします。
私の場合は、Raspberry Pi 3ではないので、使っていなかったBLE4.0対応のUSBドングルをRaspberry Piにぶっさしています。(たいていのBLE4.0対応のUSBドングルで、大丈夫だと思います)
BLE接続に使うnpmモジュールは、毎度の「noble」です。
以下のページに、OSごとのセットアップ方法があるので、インストールしておいてください。
温湿度を取得しPublishする手順
温湿度を取得する実装に入る前に、仕組みから。
普通BLEデバイスは、ScanしてペアリングしてCharacteristicをReadして。。。などするかと思いますが、この温湿度計は、単にアドバタイズデータに温湿度が含まれているだけなのです。だから、温湿度計のセットアップもなにもいらないのです。
しかも、有志の方が、npmモジュールを用意してくださっているので、何も苦労はいりません。
node-xiaomi-gap-parser
https://github.com/LynxyssCZ/node-xiaomi-gap-parser
MQTTのPublishは、これもnpmモジュール「mqtt」を使います。
以下の流れです。
① nobleでアドバタイズデータを取得
② node-xiaomi-gap-parserでアドバタイズデータを解析して、温湿度を取得
③ mqttで、イントラネットにあるMosquittoサーバにPubish
④ Mosquittoサーバは、AWS IoTにPublishデータを転送
⑤ AWS IoTは、受け取ったPublishデータをDynamoDBに格納
※③④の部分は、すでにセットアップが完了している前提です。以下を参考にしてください。
AWS IoTにMosquittoをブリッジとしてつなぐ
温湿度を取得しPublishする実装
以下のnpmモジュールを使います。インストールしておきましょう。
npm init -y
npm install --save dotenv
npm install --save mqtt
npm install --save noble
npm install --save xiaomi-gap-parser
以下、実装です。
var noble = require('noble');
var xiaomi = require('xiaomi-gap-parser');
var mqtt = require('mqtt');
require('dotenv').config();
const MQTT_HOST = process.env.MQTT_HOST || 【Mosquittoサーバのホスト名】;
const MQTT_TOPIC = process.env.MQTT_TOPIC || 【Publishするトピック名】;
const SCAN_DURATION = process.env.SCAN_DURATION ? parseInt(process.env.SCAN_DURATION) : 【BLEスキャン時間】;
console.log('MQTT_HOST=' + MQTT_HOST);
console.log('MQTT_TOPIC=' + MQTT_TOPIC);
var client = mqtt.connect(MQTT_HOST);
function wait_async(timeout){
return new Promise((resolve, reject) =>{
setTimeout(resolve, timeout);
});
}
noble.on('stateChange', async function(state) {
console.log('stateChange: ' + state);
if (state === 'poweredOn') {
console.log('Start Scanning');
noble.startScanning(["fe95"]);
await wait_async(SCAN_DURATION);
console.log('Stop Scanning');
noble.stopScanning();
process.exit();
} else {
noble.stopScanning();
process.exit();
}
});
noble.on('discover', function(peripheral) {
var serviceData = peripheral.advertisement.serviceData;
if (serviceData && serviceData.length) {
for (var i in serviceData) {
if( serviceData[i].uuid == 'fe95' ){
var data = serviceData[i].data;
var mijia = xiaomi.readServiceData(data);
console.log(mijia);
console.log(mijia.event.data);
var date = new Date();
var message = {
productId: mijia.productId,
counter: mijia.counter,
mac: mijia.mac,
tmp: mijia.event.data.tmp,
hum: mijia.event.data.hum,
createdat: date.getTime(),
createdatstr: date.toLocaleString()
};
console.log(message);
client.publish(MQTT_TOPIC, JSON.stringify(message), 0, function(err, granted){
if( err ){
console.log(err);
return;
}
console.log('publish OK');
});
noble.stopScanning();
}
}
}
});
以下を環境に合わせて変更してください。
【Mosquittoサーバのホスト名】
【Publishするトピック名】例えば、「awsiot/mijia」とします。
【BLEスキャン時間】:温湿度計のアドバタイズ間隔は長めなので、このスキャン時間も眺めがよいです。例えば、30000(30秒)とします。
Publishするデータのフォーマットは以下の部分です。
var message = {
productId: mijia.productId,
counter: mijia.counter,
mac: mijia.mac,
tmp: mijia.event.data.tmp,
hum: mijia.event.data.hum,
createdat: date.getTime(),
createdatstr: date.toLocaleString()
};
DynamoDBのテーブルを作成する。
Publishデータを格納するDynamoDBのテーブルをあらかじめ作成しておきます。
テーブル名は例えば、「MqttDataset」とします。
パーティションキーは「type」(文字列)とし、ソートキーとして「createdat」(文字列)としました。
AWS IoT側でDynamoDBに登録されるようにする
AWS IoTで受け取ったPublishデータをDynamoDBに登録するために、AWS IoTのルールを定義します。
左側のナビゲータから、ACTを選択します。
右上の作成を押下します。
適当な名前を付けます。例えば、「IoTAnalytics_mijia」
ルールクエリステートメントには、以下のように指定します。FROMの部分はトピック名です。
SELECT * FROM 'awsiot/mijia'
「アクションの追加」ボタンを押下します。
DynamoDBテーブルにメッセージを挿入する を選択します。
テーブル名には、さきほど作成したDynamoDBのテーブル名を指定します。
そうすると、ハッシュキーやレンジキーおよびそのタイプが自動的に入力されます。
ハッシュキー値には、今後追加されるであろう他のデータと区別するために、「mijia」としました。
レンジキーの値には、「${capturedat}」としました。
このcapturedatは、さきほどの実装の中で説明しましたが、Publishデータの中の1項目で、温湿度を取得した日時です。
それから、ロールにDynamoDBに書き出す権限を与えます。ページの下の方に、アクセス権を与えるためのボタンがあります。
新規ロール作成の場合には「新しいロールの作成」ボタンを押下すればよいですが、既存のロールを再利用する場合は、「ロールの更新」ボタンを忘れずに押下しておきましょう。
実行
まずは、AWS IoT側で、Subscribe状態にしておきます。
nobleでBLEを使うので、Admin権限が必要です。
以下の感じで結果が出力されれば成功です。
> node index.js
MQTT_HOST=mqtt://【Mosquittoサーバのホスト名】
MQTT_TOPIC=awsiot/mijia
stateChange: poweredOn
Start Scanning
{ productId: 426,
counter: 252,
frameControl: [ 'MAC_INCLUDE', 'EVENT_INCLUDE' ],
mac: 'XXXXXXXXXXXX',
event:
{ eventID: 4109,
length: 4,
raw: 'ce00cd01',
data: { tmp: 20.6, hum: 46.1 } } }
{ tmp: 20.6, hum: 46.1 }
{ productId: 426,
counter: 252,
mac: 'XXXXXXXXXXXX',
tmp: 20.6,
hum: 46.1,
capturedat: '2018-12-27 18:26:20' }
publish OK
Stop Scanning
温度が20.6度、湿度が46.1% であることがわかります。
AWS IoT側にもPublishされました。
DynamoDBにも登録されました。
※ときどき、温度と湿度のいずれかが欠ける時があるようです。
今回は一例として、Mijiaを使った温湿度を取得しました。
今後も取得するデータを増やしていこうと思います。
(補足) 10分毎に温湿度を取得する
さて、node index.js とすることで、MQTT経由で温湿度がアップされるようになりました。
ただ、1実行1アップですので、定期的に実行させたいです。
そこで、以前に作った「PM2 Process Management」を使いたいと思います。
「App追加」ボタンを押下して、アプリ定義を追加します。
- name:適当な名前を付けます。例えば、「MqttMijia」とします。
- memo:適当に
- script:index.js
- cwd:index.jsを置いたフォルダを記載します。
- url:指定不要です。Webページがないため
- cron:10分間隔で起動させたいため「*/10 * * * *」としました。
- autorestart:false(cronを使うため)
そして、AppListのMqttMijiaの「開始」ボタンを押下すると、起動して、稼働監視対象になります。
statusがonlineになりますが、1分ぐらいたってから「ProcList更新」ボタンを押下すると、stoppedになります。10分間隔で、起動・停止を繰り返すためです。
以上です。