masato-ka's diary

日々思ったこととか、やったことの備忘録。

Wio LTEとRN4020を使ってBLEゲートウェイ化からのSORACOM Harvestで可視化する。

この記事について

先日SORACOMさんとSeeedさん主催の「Wio LTE ユーザイベント」と言うイベントに参加しました。その際に、会場で販売されていたWio LTEを購入したので、利用のレポートとしてこの記事を紹介します。今回はWio LTEとRN4020を接続してBLEセンサビーコンの温度情報をSORACOMのデータ可視化サービスであるSORACOM Harvestで可視化してみました。てんこ盛りの内容のようですがとても手軽に実現できます。

soracom.connpass.com

Wio LTEについて

Wio LTEArduino互換(Arduino IDEでソフトウェアが書ける)でSORACOMのSIM が刺さり単体でLTE通信ができます。また、Groveコネクタで外部のセンサや機器と接続できます。主な端子として Digital Analogの入出力端子、I2C UARTを搭載しています。Seeedさんが製造しており、日本ではSORACOMさんから購入することができます。単体の価格は9800円(税別)です。もちろん技適も通っており、LTE通信を使いセンサデータを送りたい場合には最も簡単なボードになると思います。

soracom.jp

Wio LTEの一般的な使い方はGroveコネクタにセンサを接続して、LTE経由でデータを送受信する使い方になります。今回はWio LTEに直接センサをつながずにBLEのゲートウェイとして利用します。

全体の構成

全体の構成は以下の写真のようになっています。Wio LTEのUART端子に無理やりRN4020を接続しています。また、白いものが[BLEのセンサビーコン、[Wx2Beacon]e(http://masato-ka.hatenablog.com/entry/2017/09/12/223129)です。RN4020とWx2Beaconの詳細についてはそれぞれ過去記事参照ください。 Wio LTEはシリアル経由でRN4020を操作します。RN4020はWio LTEからの指示を受けて、一定時間ごとにセントラルとしてWx2Beaconに接続し、最新のセンサ値を取得します。その後、Wio LTE側でセンサ値をデコードし、SORACOM Harvestに送っています。

f:id:masato-ka:20171212083212j:plain

  • SORACOM Harvestで可視化した温度データ。

f:id:masato-ka:20171212082230p:plain

ソースコードは以下のリポジトリに上がっています。 github.com

以下、ソースコードをかいつまんで紹介します。

RN4020との接続

過去記事で紹介したシリアルからRN4020をセントラルで使う方法をWio LTEのGrove側のシリアルから実行しただけです。Wio LTEとRN4020の結線ではRXとTXはクロスに接続してください。

masato-ka.hatenablog.com

GroveのシリアルはSerialとなります。SerialUSBはPCと接続しているUSBケーブルに割り当てられており、コンソール出力として使っています。

double get_temprature(){
  SerialUSB.println("### Connect to periferal");
  Serial.println("E,1,E6E4B1DA83BC");
  delay(2000);
  trashSerialBuffer();
  SerialUSB.println("#### Read data");
  Serial.println("CHR,0019");
  delay(500);
  copySerialBuffer(buffer);
  String raw_data = String(buffer);
  #ifdef PRINT_DEBUG
    SerialUSB.print("Dump raw_data: ");
    SerialUSB.println(raw_data.substring(2,40));
  #endif
  String data = raw_data.substring(2,40);
  double temp = templature(data.substring(2,6));
  #ifdef PRINT_DEBUG
    SerialUSB.println(temp);
  #endif
  SerialUSB.println("#### Disconnect");
  Serial.println("K");
  delay(500);
  trashSerialBuffer();
  return temp;
}

取得したセンサデータの変換

RN4020から取得されたデータは以下のような形式になっています。先頭のR,と終わりの.はバリです。それ以外は16進数表記の文字列です。つまり2文字で1byteの扱いとなります。またリトルエンディアン表記となります。

R,038C081D14070002007127420D7D1A5907650B.

Wx2Beaconの温度データは2バイト目と3バイト目に格納されています。つまりこの場合"8C08"が温度データに該当します。さらにリトルエンディアンですので"0x088C"となります。これを10進数に変換して0.01をかけると温度の値(セルシウス度)となります。以下が、変換の一連のコードです。上記のコードのようにtemplatureに文字列を渡すと変換できます。

int hex_format_char_to_decimal(const char* hex_char){
  #ifdef PRINT_DEBUG
    SerialUSB.println(hex_char);
    SerialUSB.println(sizeof(hex_char));
  #endif
  if(sizeof(hex_char) != sizeof(char)*4){return -1;}
  int result = 0;
  int base = 0;
  for(int i=0; i < 2; ++i){
    if(65 <= hex_char[i] && hex_char[i] <=70){
     result += hex_char[i]-55;
    }
    if(48 <= hex_char[i] && hex_char[i] <= 57){
     result += hex_char[i]-48;
    }
    base = (16*(1-i)==0)? 1 : 16*(1-i);
    result *= base;
  }
  #ifdef PRINT_DEBUG
    SerialUSB.println(result);
  #endif
  return result;
}


int hex_format_str_to_decimal(String str){
  #ifdef PRINT_DEBUG
    SerialUSB.println("raw:" + str);
    SerialUSB.println(str.length());
  #endif
  if(str.length() != 4){
    SerialUSB.println("break");
    return -1;
  }

  int lsb = hex_format_char_to_decimal(str.substring(0,2).c_str());
  int msb = hex_format_char_to_decimal(str.substring(2,4).c_str());
  if(msb == -1 || lsb == -1){return -1;}
  return (msb<<8) + lsb;
}


double templature(String raw){
  return hex_format_str_to_decimal(raw.c_str()) * 0.01;
}

SORACOM Harvestへの接続

SORACOM Harvestへの接続はWioLTEのサンプルコード通りです。そちらを参考にしていただいた方が良いと思います。 UDPのソケットを開き8541に送りつけます。ユーザやSIMの設定はSORACOMの管理画面から設定しているため不要のようです。これだけで マネージドな可視化サービスに遅れるのは非常にすぐれものです。

void send_to_harvest(char *data){
  int connectId;
  SerialUSB.println("### Open.");
  connectId = Wio.SocketOpen("harvest.soracom.io", 8514, WIOLTE_UDP);
  if (connectId < 0) {
    SerialUSB.println("### ERROR! ###");
    return;  
  }

  SerialUSB.println("### Send.");
  SerialUSB.print("Send:");
  SerialUSB.print(data);
  SerialUSB.println("");
  if (!Wio.SocketSend(connectId, data)) {
    SerialUSB.println("### ERROR! ###");
    return;
  }

  SerialUSB.println("### Receive.");
  int length;
  do {
    length = Wio.SocketReceive(connectId, data, sizeof (data));
    if (length < 0) {
      SerialUSB.println("### ERROR! ###");
      return;
    }
  } while (length == 0);
  SerialUSB.print("Receive:");
  SerialUSB.print(data);
  SerialUSB.println("");

  SerialUSB.println("### Close.");
  if (!Wio.SocketClose(connectId)) {
    SerialUSB.println("### ERROR! ###");
    return;
  }
}

動作の全体像。

これまで紹介したメソッドはloopメソッドで以下のように使われています。 

void loop() {
  char data[100];
  
  double temp = get_temprature();
  sprintf(data,"{\"temp\":%.1f}", temp);
  SerialUSB.println(data);

  send_to_harvest(data);
  
  delay(600000L);
}

まとめ

Wio LTEは簡単にネットワークにつなげ、SORACOMのサービスを使うライブラリも充実しているので、LTE環境で何かしようとする際にはとても強力なツールになりそうです。また、RN4020とつなぐことでIoTゲートウェイっぽい使い方ができるので、利用シーンも広がりそうです。今年の冬休みの工作にいかがでしょうか。またWx2Beaconの温度データだけ使いましたが他にもセンサがついてるので多くの情報の可視化にチャレンジしたいです。