LW01-NWPのセンシングデータをAWS IoTに送信し、AWS IoTからLW01-NWPの出力を制御することができます。LW01-NWPでなくてもLoRaWANデバイスなら、AWS IoTと連動することができます。
AWS IoTと連動するためにThe Things Network(無料)を利用します。有料なのはAWSだけになります。
AWS IoTにまで届けば、後はAWSサービスを使って、センシングデータを保存・分析・制御することができます。
用意するもの
LoRaWANゲートウェイは、The Things Networkと通信できるタイプであれば何でも構いません。
The Things Networkから動画で詳しい手順が公開されています。https://www.thethingsnetwork.org/docs/applications/aws/
動画で説明されていますが、連携するためのテンプレート(AWS CloudFormation)を実行します。このテンプレートを実行すると下記のことが行われます。
テンプレートの実行が成功すれば、いきなりAWS IoTでセンシングデータを確認できます。
テンプレートの入力の時にEC2のキーペアを選択する必要があるので、事前にAWS EC2キーペアの作成を行っておきます。既存のEC2のキーペアを使用する場合は作成する必要はありません。
AWS コンソール(https://aws.amazon.com/jp/console/)にログインし、EC2のサービスを選択します。
左のメニューからキーペアを選択します。右上のキーペアの作成を押します。
AWSは、キーペアを使って暗号鍵を2つ作成します。作成した2つの内AWSが1つを保管し、もう一つを自分で厳重に保管します(流出禁止、ダウンロードも1回しかできない仕様です)。
キーペアが流出してもAWS以外で暗号鍵を作り出せません。インターネット網からEC2にアクセスするときには、ダウンロードした暗号鍵を使用してアクセスします。
実際には暗号鍵自体を送信はせずに、AWSが用意したデータを暗号化したものを送り、AWSは保管している暗号鍵でそれを復号して検証しています。
AWSサービス間であれば、キーペアだけを使って関連性を設定できます。
名前を入力して、右下のキーペアを作成を押すとキーペアが作成され、自分の暗号鍵がダウンロードされます。
Quick Startページ(https://www.thethingsnetwork.org/docs/applications/aws/quick-start.html)を開きます。
赤枠のus us-west-2を選択します。その後のeu-west-1でもap-southeast-1でもかまいません。どちらにせよリージョンが違うので、次のページで東京リージョンに変更します。
右上のオレゴンを選択して、リージョンをアジアパシフィック(東京) ap-northeast-1に変更します。正確には使いたいAWS IoTがあるリージョンを選択します。
まずは、App IDを設定します。The Things Networkのコンソール(https://console.thethingsnetwork.org/)にログインして、アプリケーションの項目を開きます。
アプリケーションIDに表示されているものをApp IDの項目に入力します。
次にApp Access Keyを設定します。TTNの同じページの一番下にアクセスキーがあります。
クリップボードにコピーボタンを押してから、App Access Keyの項目で貼り付けを実行してください。文字数が多いのでCopy&Pasteの方が安全です。
次に追加されるEC2インスタンスの設定をします。
Enviroment Nameの項目は自由です。Instance Typeの項目にはt3.microを選択します。
そして、SSH Keyの項目で先ほど作成したEC2のキーペアを選択します。
次にLW01-NWPのセンサ情報の送受信先ポート番号を設定します。要は、LoRaWANデバイスのダウンリンクのポート番号を設定します。
LW01-NWPとパソコンをUSBケーブルで接続し、下記のコマンドを実行すると
xxxxxxxxxx
#?M
LW01-NWPの現在の設定情報が出力されます。
xxxxxxxxxx
...
Lora_DataPortNo:099
...
Lora-DataPortNoの項目がここで設定するLoRaWAN FPortの番号になります。
最後にAWS CloudFormationによってIAMリソースが作成される場合があることを承認しますに✓を付けてスタックの作成を実行します。成功すると、
スタックに追加された2つのステータスがCREATE_COMPLATEになります。
変更された内容は、
になります。
この段階で、LoRaWANデバイスから送信されたデータがAWS IoTに届くようになっています。
LW01-NWPは、送信データ量を少なくするためにフォーマットがバイナリデータになっています。バイナリデータのままAWS IoTに送ると後の処理が難しくなるので、The Things Networkのスクリプト機能でJSONフォーマットに変換します。
The Things NetworkのPayload Formatsを開きます。
decoderの項目に下記のコードを貼り付けます。
xfunction Decoder(bytes, port) {
// Decode an uplink message from a buffer
// (array) of bytes to an object of fields.
var decoded = {};
var payload = "";
for( i = 0; i < bytes.length; i++ ){
payload += ('00' + bytes[i].toString(16)).slice(-2);
}
var common = payload.substr(4,24);
var sw_data = parseInt(common.substr(0,4), 16);
var output;
if( (sw_data & 0x8000) == 0x8000 )
output = "on";
else
output = "off";
var lat = parseInt(common.substr(4,8), 16);
lat /= 1000000.0;
var lon = parseInt(common.substr(12,8), 16);
lon /= 1000000.0;
var battery = (parseInt(common.substr(20,2), 16) == 1 ? "backup" : "normal");
var input = [];
for( i = 0, idx = 0; i < 10; i++, idx++ ){
if( (sw_data & 0x01) == 0x01 )
input[idx] = "on";
else
input[idx] = "off";
sw_data >>= 1;
}
var code;
var ave_wind, max_wind;
var rain_power, rain;
var curr, volt, rs232, rs485;
var data = payload.substr(28);
for(i = 0; i < data.length - 4;){
var b = parseInt(data.substr(i,2), 16);
i += 2;
var len = parseInt(data.substr(i,2), 16);
i += 2;
switch(b){
case 1: // Wind
ave_wind = parseInt(data.substr(i,4), 16);
ave_wind /= 600.0; // m/s
ave_wind = Math.round(ave_wind * 100) / 100.0;
max_wind = parseInt(data.substr(i+4,4), 16);
max_wind /= 600.0; // m/s
max_wind = Math.round(max_wind * 100) / 100.0;
break;
case 2: // Rain
rain_power = parseInt(data.substr(i,4), 16);
rain_power *= 3; // mm/h
rain = parseInt(data.substr(i+4,4), 16);
rain *= 0.5; // mm
break;
case 3: // 4-20mA
curr = [];
for( k = 0, idx = 0; k < len*2; k += 4, idx++){
curr[idx] = parseInt(data.substr(i+k, 4), 16);
}
break;
case 4: // 0-10V
volt = [];
for( k = 0, idx = 0; k < len*2; k += 4, idx++){
volt[idx] = parseInt(data.substr(i+k, 4), 16);
}
break;
case 5: // RS232
rs232 = "";
// hex to ascii
for( k = 0; k < len*2; k+=2){
code = parseInt(data.substr(i+k, 2), 16);
rs232 += String.fromCharCode(code);
}
// hex
//rs232 = data.substr(i, len*2);
break;
case 6: // RS485
rs485 = "";
// hex to ascii
for( k = 0; k < len*2; k+=2){
code = parseInt(data.substr(i+k, 2), 16);
rs485 += String.fromCharCode(code);
}
// hex
//rs485 = data.substr(i, len*2);
break;
}
i += len*2;
}
decoded.input = input;
decoded.output = output;
decoded.lat = lat;
decoded.lon = lon;
decoded.battery = battery;
decoded.ave_wind = ave_wind;
decoded.max_wind = max_wind;
decoded.rain_power = rain_power;
decoded.rain = rain;
decoded.curr = curr;
decoded.volt = volt;
decoded.rs232 = rs232;
decoded.rs485 = rs485;
decoded.raw = payload;
return decoded;
}
encoderの項目に下記のコードを貼り付けます。
x
function Encoder(object, port) {
// Encode downlink messages sent as
// object to an array or buffer of bytes.
var bytes = [];
var payload = "00";
if( object.state.output == "on")
payload += "00800000000000000000000000";
else if( object.state.output == "off")
payload += "00000000000000000000000000";
var len;
if( object.state.rs232 ){
payload += "05";
// ascii to hex
len = object.state.rs232.length;
payload += ('00' + len.toString(16)).slice(-2);
for( i = 0; i < object.state.rs232.length; i++)
payload += ('00' + object.state.rs232.charCodeAt(i).toString(16)).slice(-2);
// hex
//len = object.state.rs232.length / 2;
//payload += ('00' + len.toString(16)).slice(-2);
//payload += object.state.rs232;
}
if( object.state.rs485 ){
payload += "06";
// ascii to hex
len = object.state.rs485.length;
payload += ('00' + len.toString(16)).slice(-2);
for( i = 0; i < object.state.rs485.length; i++)
payload += ('00' + object.state.rs485.charCodeAt(i).toString(16)).slice(-2);
// hex
//len = object.state.rs485.length / 2;
//payload += ('00' + len.toString(16)).slice(-2);
//payload += object.state.rs485;
}
if( payload.length > 2){
for( i = 0; i < payload.length; i += 2){
var k = payload.substr(i,2);
bytes[i/2] = parseInt(k, 16);
}
}
// if (port === 1) bytes[0] = object.led ? 1 : 0;
return bytes;
}
右下のペイロード機能を保存を押すと登録されます。
AWS IoTサービスを開いて、左メニューのテストを選択します。
赤枠の中はApp IDになります(The Things NetworkのアプリケーションID)。
トピックへのサブスクライブを実行し、LW01-NWP(LoRaWANデバイス)からセンシングデータが送信されるのを待ちます。
受信に成功すると、データがJSONフォーマットで表示されます。この中のpayload_fieldsの項目がLW01-NWPから上がってきたセンシングデータになります。
また、LW01-NWPの出力を制御するには、
左メニューでモノを選択して、シャドウを選択します。
編集を選択して、シャドウステータスを編集することでLW01-NWPの出力を制御できます。
"desired" : {}
の項目内に記述します。
"output" : "on"
を記述すると、LW01-NWPの出力端子がONします。また、"output" : "off"
を記述すると逆に出力端子がOFFします。
"rs232" : "012345"
と記述すると、LW01-NWPのRS-232C出力端子から012345と出力されます。また、"rs485" : "ABCD"
と記述すると、LW01-NWPのRS-485出力端子からABCDと出力されます。
記述した後に保存を押して確定してください。
The Things Networkの動画には、この後AWS DynamoDBに保存するまで紹介されています。データベースに保存するのであれば、グラフを表示するまで紹介したいので、これ以降については別のノートに記載したいと思います。
AWS IoTから出力の制御までできるのでアプリケーションの幅が広がります。
センシングデータをビジネスに展開できるかどうか検証するために、まずはデータを蓄積して分析したいというお話はよく聞きます。商用のIoT Platformも便利ですが、最初はシンプルな機能をAWSサービスで開発して、その結果を元に機能を充実させていくのも良いかもしれません。
AWSは固定額ではなく従量課金なので、数台の検証から始める場合にはありがたいです。ちなみに今回のノートを作成している間の費用は1日1ドル以下でした。