ESP32-S3-WROOM1とSIM7080G（LILYGO®T-SIM7080G-S3）でIOT開発（２日目）

前回は、T-SIM7080G-S3でGPSの座標取得ができた。

今回はLTE回線を使って、ネットワークに接続できるかに挑戦する。

といってもSIMカードが必要なので、まずは、IOT用途向きの（安い）SIMカードを探す。

Amazonで怪しさ満点の謎SIMを注文する。知る人ぞ知る、亜太電信株式会社のSIM。ちなみに私は知らん。


商品名は、

oT通信プラン｜IoTSIM｜IoT通信SIM ｜ IoT用途｜IoT向け格安SIM｜IoT特化格安SIM｜日本国内用データ通信SIMカード｜DATA SIM for JAPAN ｜docomo mvno回線｜ 格安SIMカード｜プリペイド SIM｜prepaid DATA SIM｜データ通信専用SIM｜SIMカード｜SIM CARD (使い放題（256Kbps）,1年プラン)

https://www.amazon.co.jp/gp/product/B0BSBKNCWV/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1

うーん、令和最新のタイトルが無いだけましかな。

事務手続きなし！１年4500円ぽっきり。

使い放題（256Kbps）で１日あたり12.4円。

１年目以降は１か月250円。

![IMG_1909.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473778/3ec52b22-baf7-810d-dd87-a2f7fed7ddf3.jpeg)

なーんにも印刷されてない真っ白なSIMカードです。大丈夫かこれ？

とりあえず、一番小さいnanoSIMで切り取って、基板に差し込む。

パソコンとT-SIM7080G-S3をUSBでつないで、

Arduino IDE　を起動して、ボード「ESP32S3 Dev Module」とポート「接続されているUSBのポート」を選択する。

サンプルのスケッチをコピペして、

接続先APN、
ユーザー名、
パスワード、

を入力して、コンパイル＆アップロードする。



サンプルスケッチ
```MinimalModemNBIOTExample.ino

/**
 * @file      MinimalModemNBIOTExample.ino
 * @author    Lewis He (lewishe@outlook.com)
 * @license   MIT
 * @copyright Copyright (c) 2022  Shenzhen Xin Yuan Electronic Technology Co., Ltd
 * @date      2022-09-16
 *
 */
#include <Arduino.h>
#define XPOWERS_CHIP_AXP2101
#include "XPowersLib.h"
#include "utilities.h"

XPowersPMU  PMU;

// See all AT commands, if wanted
#define DUMP_AT_COMMANDS

#define TINY_GSM_RX_BUFFER 1024

#define TINY_GSM_MODEM_SIM7080
#include <TinyGsmClient.h>
#include "utilities.h"


#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(Serial1, Serial);
TinyGsm        modem(debugger);
#else
TinyGsm        modem(SerialAT);
#endif

const char *register_info[] = {
    "Not registered, MT is not currently searching an operator to register to.The GPRS service is disabled, the UE is allowed to attach for GPRS if requested by the user.",
    "Registered, home network.",
    "Not registered, but MT is currently trying to attach or searching an operator to register to. The GPRS service is enabled, but an allowable PLMN is currently not available. The UE will start a GPRS attach as soon as an allowable PLMN is available.",
    "Registration denied, The GPRS service is disabled, the UE is not allowed to attach for GPRS if it is requested by the user.",
    "Unknown.",
    "Registered, roaming.",
};


enum {
    MODEM_CATM = 1,
    MODEM_NB_IOT,
    MODEM_CATM_NBIOT,
};

void getPsmTimer();


//const char apn[] = "iot";
const char gprsUser[] = "ここにユーザー名（ダブルクォーテーションは消さない）";
const char gprsPass[] = "ここにパスワード（ダブルクォーテーションは消さない）";
bool  level = false;

// Server details to test TCP/SSL
const char server[]   = "vsh.pp.ua";
const char resource[] = "/TinyGSM/logo.txt";

//!! Set the APN manually. Some operators need to set APN first when registering the network.
//!! Set the APN manually. Some operators need to set APN first when registering the network.
//!! Set the APN manually. Some operators need to set APN first when registering the network.
// Using 7080G with Hologram.io , https://github.com/Xinyuan-LilyGO/LilyGo-T-SIM7080G/issues/19
// const char *apn = "hologram";

const char *apn = "ここに接続先のAPN（ダブルクォーテーションは消さない）";

void setup()
{

    Serial.begin(115200);

    //Start while waiting for Serial monitoring
    while (!Serial);

    delay(3000);

    Serial.println();

    /*********************************
     *  step 1 : Initialize power chip,
     *  turn on modem and gps antenna power channel
    ***********************************/
    if (!PMU.begin(Wire, AXP2101_SLAVE_ADDRESS, I2C_SDA, I2C_SCL)) {
        Serial.println("Failed to initialize power.....");
        while (1) {
            delay(5000);
        }
    }
    //Set the working voltage of the modem, please do not modify the parameters
    PMU.setDC3Voltage(3000);    //SIM7080 Modem main power channel 2700~ 3400V
    PMU.enableDC3();

    //Modem GPS Power channel
    PMU.setBLDO2Voltage(3300);
    PMU.enableBLDO2();      //The antenna power must be turned on to use the GPS function

    // TS Pin detection must be disable, otherwise it cannot be charged
    PMU.disableTSPinMeasure();


    /*********************************
     * step 2 : start modem
    ***********************************/

    Serial1.begin(115200, SERIAL_8N1, BOARD_MODEM_RXD_PIN, BOARD_MODEM_TXD_PIN);

    pinMode(BOARD_MODEM_PWR_PIN, OUTPUT);
    pinMode(BOARD_MODEM_DTR_PIN, OUTPUT);
    pinMode(BOARD_MODEM_RI_PIN, INPUT);

    int retry = 0;
    while (!modem.testAT(1000)) {
        Serial.print(".");
        if (retry++ > 6) {
            // Pull down PWRKEY for more than 1 second according to manual requirements
            digitalWrite(BOARD_MODEM_PWR_PIN, LOW);
            delay(100);
            digitalWrite(BOARD_MODEM_PWR_PIN, HIGH);
            delay(1000);
            digitalWrite(BOARD_MODEM_PWR_PIN, LOW);
            retry = 0;
            Serial.println("Retry start modem .");
        }
    }
    Serial.println();
    Serial.print("Modem started!");


    /*********************************
     * step 3 : Check if the SIM card is inserted
    ***********************************/
    String result ;


    if (modem.getSimStatus() != SIM_READY) {
        Serial.println("SIM Card is not insert!!!");
        return ;
    }

    // Disable RF
    modem.sendAT("+CFUN=0");
    if (modem.waitResponse(20000UL) != 1) {
        Serial.println("Disable RF Failed!");
    }

    /*********************************
     * step 4 : Set the network mode to NB-IOT
    ***********************************/

    modem.setNetworkMode(2);    //use automatic

    modem.setPreferredMode(MODEM_NB_IOT);

    uint8_t pre = modem.getPreferredMode();

    uint8_t mode = modem.getNetworkMode();

    Serial.printf("getNetworkMode:%u getPreferredMode:%u\n", mode, pre);


    //Set the APN manually. Some operators need to set APN first when registering the network.
    modem.sendAT("+CGDCONT=1,\"IP\",\"", apn, "\"");
    if (modem.waitResponse() != 1) {
        Serial.println("Set operators apn Failed!");
        return;
    }

    //!! Set the APN manually. Some operators need to set APN first when registering the network.
    modem.sendAT("+CNCFG=0,1,\"", apn, "\"");
    if (modem.waitResponse() != 1) {
        Serial.println("Config apn Failed!");
        return;
    }

    // Enable RF
    modem.sendAT("+CFUN=1");
    if (modem.waitResponse(20000UL) != 1) {
        Serial.println("Enable RF Failed!");
    }

    /*********************************
    * step 5 : Wait for the network registration to succeed
    ***********************************/
    RegStatus s;
    do {
        s = modem.getRegistrationStatus();
        if (s != REG_OK_HOME && s != REG_OK_ROAMING) {
            Serial.print(".");
            PMU.setChargingLedMode(level ? XPOWERS_CHG_LED_ON : XPOWERS_CHG_LED_OFF);
            level ^= 1;
            delay(1000);
        }

    } while (s != REG_OK_HOME && s != REG_OK_ROAMING) ;

    Serial.println();
    Serial.print("Network register info:");
    Serial.println(register_info[s]);





    // Activate network bearer, APN can not be configured by default,
    // if the SIM card is locked, please configure the correct APN and user password, use the gprsConnect() method
    modem.sendAT("+CNACT=0,1");
    if (modem.waitResponse() != 1) {
        Serial.println("Activate network bearer Failed!");
        return;
    }

    // if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
    //     return ;
    // }

    bool res = modem.isGprsConnected();
    Serial.print("GPRS status:");
    Serial.println(res ? "connected" : "not connected");

    String ccid = modem.getSimCCID();
    Serial.print("CCID:");
    Serial.println(ccid);

    String imei = modem.getIMEI();
    Serial.print("IMEI:");
    Serial.println(imei);

    String imsi = modem.getIMSI();
    Serial.print("IMSI:");
    Serial.println(imsi);

    String cop = modem.getOperator();
    Serial.print("Operator:");
    Serial.println(cop);

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

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

    /*********************************
    * step 6 : Send HTTP request
    ***********************************/
    TinyGsmClient client(modem, 0);
    const int     port = 80;
    Serial.printf("Connecting to", server);
    if (!client.connect(server, port)) {
        Serial.println("... failed");
    } else {
        // Make a HTTP GET request:
        client.print(String("GET ") + resource + " HTTP/1.0\r\n");
        client.print(String("Host: ") + server + "\r\n");
        client.print("Connection: close\r\n\r\n");

        // Wait for data to arrive
        uint32_t start = millis();
        while (client.connected() && !client.available() &&
                millis() - start < 30000L) {
            delay(100);
        };

        // Read data
        start          = millis();
        char logo[640] = {
            '\0',
        };
        int read_chars = 0;
        while (client.connected() && millis() - start < 10000L) {
            while (client.available()) {
                logo[read_chars]     = client.read();
                logo[read_chars + 1] = '\0';
                read_chars++;
                start = millis();
            }
        }
        Serial.println(logo);
        Serial.print("#####  RECEIVED:");
        Serial.print(strlen(logo));
        Serial.println("CHARACTERS");
        client.stop();
    }

    /*********************************
    * step 6 : Send HTTPS request
    ***********************************/
    TinyGsmClientSecure secureClient(modem, 1);
    const int           securePort = 443;
    Serial.printf("Connecting securely to", server);
    if (!secureClient.connect(server, securePort)) {
        Serial.println("... failed");
    } else {
        // Make a HTTP GET request:
        secureClient.print(String("GET ") + resource + " HTTP/1.0\r\n");
        secureClient.print(String("Host: ") + server + "\r\n");
        secureClient.print("Connection: close\r\n\r\n");

        // Wait for data to arrive
        uint32_t startS = millis();
        while (secureClient.connected() && !secureClient.available() &&
                millis() - startS < 30000L) {
            delay(100);
        };

        // Read data
        startS          = millis();
        char logoS[640] = {
            '\0',
        };
        int read_charsS = 0;
        while (secureClient.connected() && millis() - startS < 10000L) {
            while (secureClient.available()) {
                logoS[read_charsS]     = secureClient.read();
                logoS[read_charsS + 1] = '\0';
                read_charsS++;
                startS = millis();
            }
        }
        Serial.println(logoS);
        Serial.print("#####  RECEIVED:");
        Serial.print(strlen(logoS));
        Serial.println("CHARACTERS");
        secureClient.stop();
    }
}

void loop()
{
    while (Serial1.available()) {
        Serial.write(Serial1.read());
    }
    while (Serial.available()) {
        Serial1.write(Serial.read());
    }
}



```

長い、こんなんコード絶対自分で書けんぞ。そもそも読めんぞ。ということで、ChatGPT先生に解説をお願いします。


このコードは、LilyGO T-SIM7080Gというデバイスを使用してNB-IoT（Narrowband IoT）通信を行うためのArduinoスケッチです。以下にコードの主な機能と処理を解説します。

1. ライブラリのインクルードと定義:
   - `#include <Arduino.h>`: Arduinoのコードで必要な基本的な定義や関数を含むヘッダーファイルをインクルードします。
   - `#define XPOWERS_CHIP_AXP2101`: AXP2101チップを使用するための定義です。
   - `#include "XPowersLib.h"`: AXP2101チップを制御するためのライブラリをインクルードします。
   - `#include "utilities.h"`: ユーティリティ関数を含むヘッダーファイルをインクルードします。
   - `#define TINY_GSM_RX_BUFFER 1024`: TinyGSMライブラリの受信バッファのサイズを定義します。
   - `#define TINY_GSM_MODEM_SIM7080`: TinyGSMライブラリで使用するモデムの種類を指定します。
   - `#include <TinyGsmClient.h>`: TinyGSMライブラリをインクルードします。
   - `#include "utilities.h"`: ユーティリティ関数を含むヘッダーファイルをインクルードします。

2. XPowersPMUとTinyGsmのインスタンスの作成:
   - `XPowersPMU PMU;`: XPowersPMUクラスのインスタンスを作成します。このクラスは、電源管理モジュールを制御するために使用されます。
   - `TinyGsm modem(SerialAT);`: TinyGsmクラスのインスタンスを作成します。このクラスは、SIM7080モデムとの通信を制御するために使用されます。

3. ネットワーク関連の設定:
   - `const char *register_info[]`: ネットワーク登録のステータスを示す文字列配列です。
   - `enum`: モデムのネットワークモードを示す列挙型です。
   - `const char *apn = "mmtcom.jp";`: 使用するAPN（アクセスポイント名）を設定します。
   - `const char gprsUser[] = "＊＊＊";`と`const char gprsPass[] = "＊＊＊";`: GPRS接続に必要なユーザー名とパスワードを設定します。
   - `const char server[]`と`const char resource[]`: テストするサーバーの情報を指定します。

4. setup()関数:
   - デバイスの初期化と設定を行うセットアップ関数です。以下の主なステップから成ります。
   - 電源チップの初期化とモデムの電源供給を有効化します。
   - モデムのシリアル通信ポートの設定と初期化を行います。
   - SIMカードの挿入を確認し、ネットワークモードをNB-IoTに設定します。
   - モデムのAPNを設定し、ネットワーク登録を行います。
   - GPRS接続を確立し、モデムの情報（CCID、IMEI、IMSI、信号品質など）を取得します。
   - HTTPとHTTPSリクエストをサーバーに送信し、応答を受信します。

5. loop()関数:
   - シリアル通信のデータの受信と送信を行うループ関数です。

これにより、NB-IoT通信を使用してサーバーにHTTPおよびHTTPSリクエストを送信し、応答を受信していることがわかります。応答にはサーバーからのデータが含まれている可能性があります。

でもこのサンプルコードだと、無限にHTTPリクエスト送っちゃうよな？それってDOS攻撃（HTTPフラッド攻撃）では？まぁ、長時間の電源ONはやばそうなので成功が確認できてから電源OFFにする。


そして、シリアルモニタに表示された結果

```


+CPIN: READY
AT

OK

Modem started!AT+CPIN?
AT+CPIN?

+CPIN: READY

OK
AT+CFUN=0
AT+CFUN=0

+CPIN: NOT READY

OK
AT+CNMP=2
AT+CNMP=2

OK
AT+CMNB=2
AT+CMNB=2

OK
AT+CMNB?
AT+CMNB?

+CMNB: 2

OK
AT+CNMP?
AT+CNMP?

+CNMP: 2

OK
AT+CNMP=2
AT+CNMP=2

OK
AT+CMNB=2
AT+CMNB=2

OK
AT+CMNB?
AT+CMNB?

+CMNB: 2

OK
AT+CNMP?
AT+CNMP?

+CNMP: 2

OK
getNetworkMode:2 getPreferredMode:2
AT+CGDCONT=1,"IP","mmtcom.jp"
AT+CGDCONT=1,"IP","mmtcom.jp"

OK
AT+CNCFG=0,1,"mmtcom.jp"
AT+CNCFG=0,1,"mmtcom.jp"

OK
AT+CFUN=1
AT+CFUN=1

OK
AT+CEREG?
AT+CEREG?

+CEREG: 0,0

OK
.AT+CEREG?

+CPIN: READY

SMS Ready
AT
AT+CEREG?

+CEREG: 0,2

OK
ATE0
AT

OK
AT+CMEE=0
ATE0

OK
AT+CLTS=1

OK
AT+CBATCHK=1

OK
AT+CPIN?

OK

+CPIN: READY

OK
AT+CGREG?

+CGREG: 0,2

```

うーん、よくわからん。よくわからんから、ChatGPTに解説をお願いしました。

シリアルモニタの結果を解説します。

AT+CPIN?コマンドに対する応答:

+CPIN: READY: SIMカードが挿入されており、利用可能な状態であることを示します。
OK: コマンドが正常に実行されました。
AT+CFUN=0コマンドに対する応答:

+CPIN: NOT READY: SIMカードが利用できない状態であることを示します。
OK: コマンドが正常に実行されました。
AT+CNMP=2コマンドに対する応答:

OK: コマンドが正常に実行されました。
AT+CMNB=2コマンドに対する応答:

OK: コマンドが正常に実行されました。
AT+CMNB?コマンドに対する応答:

+CMNB: 2: 現在の通信モードがNB-IoT（Narrowband IoT）であることを示します。
OK: コマンドが正常に実行されました。
AT+CNMP?コマンドに対する応答:

+CNMP: 2: ネットワークモードがNB-IoTであることを示します。
OK: コマンドが正常に実行されました。
AT+CGDCONT=1,"IP","mmtcom.jp"コマンドに対する応答:

OK: APN（アクセスポイント名）が設定されました。
AT+CNCFG=0,1,"mmtcom.jp"コマンドに対する応答:

OK: APNがネットワーク登録の設定に使用されるように設定されました。
AT+CFUN=1コマンドに対する応答:

OK: モデムのRF（Radio Frequency）が有効になりました。
AT+CEREG?コマンドに対する応答:

+CEREG: 0,0: ネットワーク登録が成功していないことを示します。
OK: コマンドが正常に実行されました。
AT+CEREG?コマンドに対する応答:

+CEREG: 0,2: ネットワーク登録が成功したことを示します。
OK: コマンドが正常に実行されました。
この結果から、モデムの初期化が成功し、NB-IoT接続が確立されていることが分かります。次に、HTTPとHTTPSリクエストが送信されていますが、これらのリクエストに対する応答は省略されています。リクエストが成功した場合、サーバーからのレスポンスが表示されるはずです。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3239313539322f66393837333834362d316362652d613834332d306365352d3566636231326262646162332e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473778/e86f4f12-e0e9-d54b-f8fa-1a5afec4d04f.png)

なるほど、よくわからんけど動いたからヨシ！


ということで、次回は センサーに反応があったら通知する、をBlynkを使って挑戦だ。


追記）

散文的なメモ用の文章なので、最後まで完成したら体系的に書くか、動画アップします。

間違いや重大なミスがあったらコメントでご指摘ください。