ESP32をLTEに接続する

センサーの値をネットワーク経由で送信するにはwi-fiがある範囲ではESP32やESP8266を使い行うことができます。しかしwi-fiが無い場合にはLTEや3Gなどの回線を使うことになります。しかし入手可能なハードが高価であまり情報がありません。比較的安価に入手可能なハードウェアで行う方法を紹介します。

センサーやデバイスをインターネットにつなぐいわゆるIoTですが、Sakura.ioがあります。しかしSakura.ioはハードウェアの販売をやめてしまったようです。「sakura.io LTEモジュール」製造終了のお知らせ
サービスは継続するようですが、儲かってないのかな?と推測。


他にはこんな商品も
TABRAIN接続モジュール
スイッチサイエンスで販売しています。24,750円とちょっと高いし、受注生産っぽい。
4GIM V1.0(LTE版フレキアンテナ付き)

あとはソラコムというのが有名らしいですが、接続可能なハードを見るとちょっと違う気がする。

購入したハードウェア

ということで適した商品をAliExpressで見つけました。

Lilygo®Ttgo T PCIE ESP32 WROVER B AXP192チップwifi bluetoothナノカードsimシリーズ構成可能開発ボード
以下の2点を購入しました。
T-PCIE 4MB(1,233円)
PCIE-SIM7600JC(3,972円)
価格は購入時点になります。先程見たら値段が上がっているようです。

SIM7600JCには技適マークも入っているので日本国内で使えます。T-PCIEはESP32を積んだ開発ボードですUSB接続がtype-C。このボードにSIMを入れるスロットが付いています。

メーカーのサイトはこちら
Lilygo
githubはこちら
Xinyuan-LilyGO/LilyGO-T-SIM7600X
Xinyuan-LilyGO/LilyGo-T-PCIE

通信回線 SIM

通信回線はMVNOのiijmioを使います。理由は現在使っているからというだけです。ファミリープランでの契約なのでデータ通信SIMを1枚追加で注文しました。NTT docomo経由で接続することになります。

マルチサイズSIMで届くので一番小さいnano SIMのサイズで取り出してボードに刺します。
SIM7600JCの情報を探すと日本語のページでは法人向けのサイトばかりが出てきます。データシートと言って販売向けみたいなPDFばかり。以下のサイトで詳しい情報はダウンロードできます。

SIM Com SIM7600X-PCIE

PDFのダウンロードにはユーザー登録が必要ですが、普通に登録できました。

動作確認

動作確認は次のスケッチを使いました。ESP32にインストールするとATコマンドがArduino IDEのシリアルモニタから使えます。

LilyGo-T-PCIE/examples/ATDebug/

で色々とやったのですがATコマンドだけでは接続できなかったです。ATコマンドわかんない。他のモジュールの例を参考にしてあれこれやりましたが接続の時にERRORしか出てこなくて?でした。
ATを入れてOKが返ってくるのでちゃんと動いているな、程度の確認にはなりました。

動作確認できたスケッチ

結局のところ
LilyGo-T-PCIE/examples/SIM7600/
にあるSIM7600.inoを参考にしながら以下のコードで動作確認が出来ました。
ライブラリは「TinyGSM」が必要になるのでインストールしておきます。

動作確認できたコード

//https://github.com/Xinyuan-LilyGO/LilyGo-T-PCIE/blob/master/examples/SIM7600/SIM7600.inoを元にして作成
//通信モデムの設定
#define TINY_GSM_MODEM_SIM7600

//シリアルモニタに出力するためのserialを設定
#define SerialMon Serial

//通信モデムとESP32がやりとりするためのSerialポートを設定
#define SerialAT Serial1

#include <TinyGsmClient.h>
#include <Ticker.h>
#include <ArduinoHttpClient.h>

//通信先を設定。自分の通信会社のAPNとUser名、パスワードを設定
const char apn[] = "iijmio.jp";
const char gprsUser[] = "mio@iij";
const char gprsPass[] = "iij";

//アクセス先の設定 http://mkbtm.net//SIM7600/test.txt
//httpsを使いたい時には、BasicHttpsClientのサンプルを見る
const char server[]   = "mkbtm.net";
const char resource[] = "/SIM7600/test.txt";
const int  port       = 80;

TinyGsm modem(SerialAT);

Ticker tick;//LEDの点滅用

#define uS_TO_S_FACTOR          1000000ULL  //Conversion factor for micro seconds to seconds 
#define TIME_TO_SLEEP           60          //Time ESP32 will go to sleep (in seconds) 
//ボーdの設定
#define PIN_TX                  27
#define PIN_RX                  26
#define UART_BAUD               115200
#define PWR_PIN                 4
#define LED_PIN                 12
#define POWER_PIN               25
#define IND_PIN                 36



void setup()
{
  SerialMon.begin(115200);
  delay(10);

  // Onboard LED light, it can be used freely
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  // POWER_PIN : This pin controls the power supply of the SIM7600
  pinMode(POWER_PIN, OUTPUT);
  digitalWrite(POWER_PIN, HIGH);

  // PWR_PIN : This Pin is the PWR-KEY of the SIM7600
  // The time of active low level impulse of PWRKEY pin to power on module , type 500 ms
  pinMode(PWR_PIN, OUTPUT);
  digitalWrite(PWR_PIN, HIGH);
  delay(500);
  digitalWrite(PWR_PIN, LOW);

  // IND_PIN: It is connected to the SIM7600 status Pin,
  // through which you can know whether the module starts normally.
  pinMode(IND_PIN, INPUT);

  attachInterrupt(IND_PIN, []() {
    detachInterrupt(IND_PIN);
    // If SIM7600 starts normally, then set the onboard LED to flash once every 1 second
    tick.attach_ms(1000, []() {
      digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    });
  }, CHANGE);

  SerialMon.println("Wait...");

  delay(3000);

  SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);

  //モデムの初期化
  SerialMon.println("Initializing modem...");
  if (!modem.init()) {
    SerialMon.println("Failed to restart modem, delaying 10s and retrying");
    return;
  }
  SerialMon.println("enter setNetwork Mode");

//接続開始
  bool result;
  do {
    result = modem.setNetworkMode(38);//2 Automatic, 13 GSM only,  38 LTE only,  51 GSM and LTE only
    delay(500);
  } while (result != true);

  SerialMon.println("Waiting for network...");
  if (!modem.waitForNetwork()) {
    delay(10000);
    return;
  }

  if (modem.isNetworkConnected()) {
    SerialMon.println("Network connected");
  }

  SerialMon.print("Connecting to:");
  SerialMon.println(apn);
  if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
    delay(10000);
    return;
  }

  bool res = modem.isGprsConnected();
  SerialMon.print("GPRS status:");
  SerialMon.println(res);

  IPAddress local = modem.localIP();
  SerialMon.print("Local IP:");
  SerialMon.println(local);

  int csq = modem.getSignalQuality();
  SerialMon.print("Signal quality:");
  SerialMon.println(csq);


  //httpの接続開始
  TinyGsmClient client(modem);
  HttpClient    http(client, server, port);

  SerialMon.println("HTTP GET request... ");
  int err = http.get(resource);
  if (err != 0) {
    SerialMon.println("failed to connect");
    delay(10000);
    return;
  }

//httpの通信結果を表示
  String body = http.responseBody();
  SerialMon.println("============Response===========");
  SerialMon.println(body);
  SerialMon.println("============Response end========");

  http.stop();
  SerialMon.println("Server disconnected");

  modem.poweroff();//モデムオフ
  SerialMon.println("Poweroff.");
}



void loop()
{
//スリープへ
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(200);
  esp_deep_sleep_start();
}

コードの中身についてはコメントを読んでください。
ネットに接続してhttp://mkbtm.net/SIM7600/test.txtを読み込んでいるだけです。このテキストファイルの中身は3行の普通のテキスト。
接続に成功すると読み込んだテキストをシリアルモニタに表示します。

というところで後はhttpのリクエスト部分をあれこれやれば色々と出来ます。

これでwi-fiの無い環境でもデバイスをネットに繋げます!

消費電力

PPK2を使って消費電流を測定してみました。

測定結果は次のグラフを見てください。

ピークはESP32の起動時で139.82mA
通信時の平均は58.81mA、ピークは66.41mA
待機時(sleep)時は3.52mA

1分間のchargeが0.93C
ここからバッテリーでの動作時間を計算してみます。
cheero Slim 5000mAh IoT機器対応を使うと仮定します。5000mAhは18,000C
18,000/0.93 = 19,354分 = 322時間 = 13.4日間
ほんとにそんなに動くのかな???

2021.6.27追記
動作時間の実験結果です。
cheeroの3200mAhのモバイルバッテリーで29時間程度
リチウムイオンのCR123A充電池700mAhで8時間程度
リチウムイオンの16650充電池2500mAhで24時間程度
という結果でした。