3
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Wio LTE M1/NB1(BG96) でパケ死せずにデータを受け取る

目次

  • Wio LTEを受信用デバイスとして使いたい
  • SORACOM Air plan-KM1 はパケ死する
  • Lambdaの作成
  • API Gatewayの作成
  • SORACOM Beamの設定
  • Wio LTEのコード
  • 実際の通信料は

Wio LTEを受信用デバイスとして使いたい

以前、SORACOM LTE-M ButtonからLINEにメッセージを送る - Qiita という記事を書きまして、その後も日々このボタンをポケットに入れ、機会あるたびに人にデモしていたのですが、ボタンを押したらLINEメッセージが届くだけでは、「すごい」と言われても、「それで?」「だから?」という気持ちが透けて見えてきました。

そのため、LTE-Mボタンを押したら、パトランプが光るようなデモができたらと考えました。そして、どうせなら、受信側も、LTE-M回線を経由して、Wio LTEを使えたら良いのではと考えました。

LTE-Mボタンを押したら、その情報を何らかのサーバを経由してWio-LTEにおくり、パトランプを点灯させるという簡単な仕組みです。
いろいろ調べて、今回は、個人が簡単に安価でできる範囲で実現するため、Wio-LTEから数秒おきにサーバに状態を問い合わせる方式とすることにしました。

スクリーンショット 2019-04-21 22.21.46.png

SORACOM Air plan-KM1 はパケ死する

元々IoT用の Lte-M1 という通信方式は、大量に撒いたデバイスから、1日1回とか、1週間に1回、それも数十バイトといった頻度・データ量の通信を想定しているため、月額利用料は安いものの、通信料は一昔前のパケット代レベル( 1MBあたり 500円超! )になっています。
日本向け Air SIM のご利用料金
スクリーンショット 2019-04-21 19.52.48.png

そのため、例えば、数秒おきに、HTTPSで外部サーバに接続に行くなんてことをすると、 たった1時間で数千円の請求 になりかねません。
参考:HTTP(S)とMQTT(S)の消費電流とデータサイズを計測する - Qiita

なので、今回は、便利なSORACOM Beamの、UDPを使ってデータを受信することとします。
SORACOM Beam : Beamを使用したデータの送信 | 開発者ガイド | SORACOM Developers によれば、APIのレスポンスのBody部分が、そのままデバイスに返信されます。
スクリーンショット 2019-04-21 22.24.04.png
SORACOM Beamを設定するには、まず通信先のAPIが必要になるため、AWSのLambdaとAPI Gatewayを利用して、APIを作成します。

Lambdaの作成

将来的には直近のボタンの状態を取得して返しますが、現時点では、単純に1を返すことにします。

  • ボタンが1回押された:1
  • ボタンがダブルクリックされた:2
  • ボタンが長押しされた(リセット):0
exports.handler = async(event) => {
    return ("1\n");
};

あとで気づいたのですが、最後に改行\nを付け加えないと、Beam側でデータを受け取ってくれない様です。特にドキュメントには書いてなかったのですが・・・。

API Gatewayの作成

LambdaをSORACOM Beamから呼べるように、API Gatewayを作成します。
普通にPOSTメソッドを先ほどのLambdaに設定すればいいのですが、1点だけ、「Lambda プロキシ統合の使用」のチェックは入れません。

SORACOM Beamの設定

SIM グループ - SORACOM ユーザーコンソール で、SIMグループの作成し、SORACOM Beamの設定で、「UDPToHTTP」を設定します。
その際、「ステータスコードを省略」をONにしておくと、さらにバイト数を節約できます。

スクリーンショット 2019-04-21 22.30.43.png

Wio LTEのコード(都度接続版)

公式のサンプルコードにある、「soracom/soracom-harvest」を編集して、SORACOM Beamに空データを送るコードを書きました。5秒おきに接続する様になっています。
Wiki/home-ja.md at master · SeeedJP/Wiki · GitHub

#include <WioCellLibforArduino.h>

#define INTERVAL        (5000)
#define RECEIVE_TIMEOUT (10000)

WioCellular Wio;

void setup() {
  delay(200);

  SerialUSB.begin(115200);
  SerialUSB.println("");
  SerialUSB.println("--- START ---------------------------------------------------");

  SerialUSB.println("### I/O Initialize.");
  Wio.Init();

  SerialUSB.println("### Power supply ON.");
  Wio.PowerSupplyCellular(true);
  delay(500);

  SerialUSB.println("### Turn on or reset.");
#ifdef ARDUINO_WIO_LTE_M1NB1_BG96
  Wio.SetAccessTechnology(WioCellular::ACCESS_TECHNOLOGY_LTE_M1);
  Wio.SetSelectNetwork(WioCellular::SELECT_NETWORK_MODE_MANUAL_IMSI);
#endif
  if (!Wio.TurnOnOrReset()) {
    SerialUSB.println("### ERROR! ###");
    return;
  }

  SerialUSB.println("### Connecting to \"soracom.io\".");
  if (!Wio.Activate("soracom.io", "sora", "sora")) {
    SerialUSB.println("### ERROR! ###");
    return;
  }

  SerialUSB.println("### Setup completed.");
}

void loop() {
  char data[100];

  sprintf(data, "{}");

  SerialUSB.println("### Open.");
  int connectId;
  //beam.soracom.io:23080
  connectId = Wio.SocketOpen("beam.soracom.io", 23080, WIO_UDP);
  if (connectId < 0) {
    SerialUSB.println("### ERROR! ###");
    goto err;
  }

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

  SerialUSB.println("### Receive.");
  int length;
  length = Wio.SocketReceive(connectId, data, sizeof (data), RECEIVE_TIMEOUT);
  if (length < 0) {
    SerialUSB.println("### ERROR! ###");
    goto err_close;
  }
  if (length == 0) {
    SerialUSB.println("### RECEIVE TIMEOUT! ###");
    goto err_close;
  }
  SerialUSB.print("Receive:");
  SerialUSB.print(data);
  SerialUSB.println("");

err_close:
  SerialUSB.println("### Close.");
  if (!Wio.SocketClose(connectId)) {
    SerialUSB.println("### ERROR! ###");
    goto err;
  }

err:
  delay(INTERVAL);
}

プログラムを書き込んで実行すると、下記のようなログがシリアルモニタに出力されました。

--- START ---------------------------------------------------
### I/O Initialize.
### Power supply ON.
### Turn on or reset.
### Connecting to "soracom.io".
### Setup completed.
### Open.
### Send.
Send:{}
### Receive.
Receive:1

### Close.
### Open.
### Send.
Send:{}
### Receive.
Receive:1

実際の通信料は

実際に起動して数分放置させ、180回弱ほど通信した後、SIM 管理 - SORACOM ユーザーコンソール から通信料履歴タブを見ると、21.9KBほどの通信が発生していました。
1回の通信で、約120byteほどのデータを消費しているようです。
これでも、5秒おきに通信するとなると、 120byte * 12回/分 * 60分 * 24時間 * 30日 = 40MB = 3万円/月 ぐらいの通信料になるので、素直に plan-K か plan-D を使うことをおすすめします。

スクリーンショット 2019-04-21 19.31.07.png

Wio LTEのコード(接続しっぱなし版)

先ほどのコードでは、Socket通信を毎回オープン・クローズしていたので、もしかしたらオーバーヘッドがあるかもしれないと思い、接続しっぱなしのバージョンも試してみました。
コードはこちら。

#include <WioCellLibforArduino.h>

#define INTERVAL        (10000)
#define RECEIVE_TIMEOUT (10000)

#define RED_PIN      (WIO_D20)
#define YELLOW_PIN      (WIO_D19)

WioCellular Wio;
bool socketStatus;

void setup() {
  delay(200);

  SerialUSB.begin(115200);
  SerialUSB.println("");
  SerialUSB.println("--- START ---------------------------------------------------");

  SerialUSB.println("### I/O Initialize.");
  Wio.Init();

  SerialUSB.println("### Power supply ON.");
  Wio.PowerSupplyCellular(true);
  delay(500);

  SerialUSB.println("### Turn on or reset.");
#ifdef ARDUINO_WIO_LTE_M1NB1_BG96
  Wio.SetAccessTechnology(WioCellular::ACCESS_TECHNOLOGY_LTE_M1);
  Wio.SetSelectNetwork(WioCellular::SELECT_NETWORK_MODE_MANUAL_IMSI);
#endif
  if (!Wio.TurnOnOrReset()) {
    SerialUSB.println("### ERROR! ###");
    return;
  }

  SerialUSB.println("### Connecting to \"soracom.io\".");
  if (!Wio.Activate("soracom.io", "sora", "sora")) {
    SerialUSB.println("### ERROR! ###");
    return;
  }

  socketStatus = false;

  SerialUSB.println("### Setup completed.");
}

void loop() {
  char data[100];
  int v;
  int connectId;
  sprintf(data, "0");

  if(!socketStatus){
    SerialUSB.println("### Open.");
    //beam.soracom.io:23080
    connectId = Wio.SocketOpen("beam.soracom.io", 23080, WIO_UDP);
    if (connectId < 0) {
      SerialUSB.println("### ERROR! ###");
      goto err;
    }
    socketStatus = true;
  }

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

  SerialUSB.println("### Receive.");
  int length;
  length = Wio.SocketReceive(connectId, data, sizeof (data), RECEIVE_TIMEOUT);
  if (length < 0) {
    SerialUSB.println("### ERROR! ###");
    goto err_close;
  }
  if (length == 0) {
    SerialUSB.println("### RECEIVE TIMEOUT! ###");
    goto err_close;
  }
  SerialUSB.print("Receive:");
  SerialUSB.print(data);
  SerialUSB.println("");

  goto err;

err_close:
  SerialUSB.println("### Close.");
  if (!Wio.SocketClose(connectId)) {
    SerialUSB.println("### ERROR! ###");
    goto err;
  }
  socketStatus = false;

err:
  delay(INTERVAL);
}

65回ほど通信させて、8.1KB。1回の通信で約120バイト。
残念ながら、消費するバイト数は同じくらいでした。もしかしたらもう少し放置したら違いが出るかも?
スクリーンショット 2019-04-27 15.55.29.png

続き

完成したものは、こちら。
「ボタンを押したらパトランプ点灯してブザーを鳴らす」を、すべてLTE-M回線で実現してみた。 - Qiita

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
3
Help us understand the problem. What are the problem?