IOTのためのAWS試験環境

# 概要
　LoRaへのアクセスを例に手軽に実現できるIOT環境を構築します
# 背景
　気軽に検討できる環境としてのIOT開発環境を構築するのが目的です。特にIOTと言えども、Webなどを使用した見せ方が大事であるのは言うまでもありません。AWSを使って気軽に測定し、解析し、表示できる環境を目指します。

# 環境

* ESPRESSIF:ESP32-WROOM-32
* MacBook Air M1
* Windows10 64bit PC
* AWS環境
* ES920LR3EB x 2（ES920LR3SDK1セットから）

　AWSについては、簡易的な構成管理環境などを用意し、ECSでのコンテナ管理やBeansTalkでの開発環境を用意します。右にあるIOTデバイスで取得した情報を直ちに処理しDBへの登録を行い、それを解析に用いたり、視覚的に表現できるようにします。参照系については、デモ用途も考えある程度拡張性を持たせています。
　今回、AWSにデータを送信するデバイスの１例にESP32側のペリフェラル環境として、EASEL製のES920LR3EBをUARTで制御します（ESP32からの制御対象は後に説明する親機になり、対向の子機からデータ取得することを想定しています。）。


* ESP32
![image0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/d24b097f-fd97-bba2-3ea8-f06db9610dd3.jpeg)

* AWS環境
![bb618830071d69513795d238d8836455.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/c6ecde87-b4f8-2c71-818f-7d196d12af16.png)

* LoRa環境（ES920LR3EB x 2）
![1493e57b86bc3e421ee7f1363dad1dea.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/6295b06b-ccd7-b267-e451-104dc324288b.png)



# ステップ１　AWS S3←ESP32　
　ESP32で取得したデータをS3に保存することを検討し始めたのですが、、ほぼやりたいことが、@tsugunao さんのページ [ESP32のデバイスから AWS IoTに接続してみる](https://qiita.com/tsugunao/items/e6058df682728a94ef40) と [ESP32のカメラでドラえもんを撮影しAmazon Lookout for Visionで異常箇所を検知する](https://qiita.com/tsugunao/items/c0e45b34a5852857ee41) に記載されており、ほぼそのまま試してみると、あっさりテキスト形式のデータを３０分程度でS3に保存できるようになりました。

　画像ではなく「Hello World」をテキストでS3に保存できた。

![スクリーンショット 2023-06-26 23.23.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/ad7cb69c-9cab-5144-4220-bc0addf62cc4.png)

# ステップ２　ターミナルモードでES920LR3EBに接続する
　まずは、Windows PCからTeratermを使用して、ES920LR3EBに接続する環境を作る。株式会社EASELの開発環境であるES920LR3SDK1セットを使用しており、以下の資料を用いている。

## ES920LR3EB関連資料
### Web公開されているもの（EASELのホームページで確認可能）
* 特定⼩電⼒無線モジュール ES920LR3 データシート Version 1.04
* 特定小電力無線モジュール ES920LR3 ソフトウエア開発環境説明書 Version 1.01
* 特定小電力無線モジュール ES920LR3 コマンド仕様ソフトウェア説明書 Version 1.04

### Web公開されていないもの（SDKの納品物）
* ES920LRx設定ツール取扱説明書及びツール
* ES920LR3のソースコード一式（....太っ腹....）

## WindowsからTeratermを使用したES920LR3EBの制御
　このステップでは１台のWindowsPC（ES920LR3Ex設定ツールがWindowsのみでしか使えない）で、２台のES920LR3を接続し、Teratermで制御する。このツールを利用した経緯は、以下のとおり。

* ES920LR3EBがきちんと動作することを確認するため
* ESP32での制御実装を検討するため
* 最低限制御必要なコマンドを理解するため

　そのため、以下の図のようにまずはES920LR3x設定ツールで制御し、そのあとにTeratermで制御する。

![方針.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/3acc9ca2-86aa-7d2e-dbcf-6d188688cc14.png)

## ES920LR3Ex設定ツールでの制御
基本的には、「ES920LRx設定ツール取扱説明書」を参照し、以下のとおり進めれば簡単にできる。

* ES920LR3のドライバのインストール
* ES920LRx設定ツールの起動

また、このツールを起動することで、ツールと同じフォルダにlogフォルダができるため、それを確認することで、Teratermで初期値以外に設定する値が以下だとわかる。

* 親機
通信設定bw:125kHz,sf:7,ch:1:panid:0001,ownid:0001,dstid:0000,ack:ON,power13
* 子機
通信設定bw:125kHz,sf:7,ch:1:panid:0001,ownid:0000,dstid:0001,ack:ON,power13

## Teratermでの設定方法

下記は、親機の例ですが、子機も同じように設定すればOKです（ただし、子機のownidは0001、dstidは0000とする。）。
![設定例.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/6dff3e77-7c57-8448-622a-af81a1fc8db0.png)

親機、子機設定後にともに、startコマンドを以下のように呼べば、通信が可能となる。
なお、途中パラメータのセーブ等をする場合は、saveコマンドを使用する。

![設定例２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/db92b56e-42ac-8145-4e49-f3e4817ef1cb.png)

上記の例でもわかるように接続後は、親機及び子機の両方から双方向通信ができる。

![communication.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/5acc1483-b4fd-65cb-dbd8-c91f5c379dd1.jpeg)



# ステップ３　ESP32←ES920LR3EB←ES920LR3EB
　ESP32のUARTとES920LR3EBをジャンパーでクロスさせて飛ばす。そして、コントローラをPCからESP32に切り替えて、ES920LR3EB間の通信試験を実行する。通信試験としては、ステップ２で実施した内容をそのままESP32に実装する。



* ベースのソースコードはステップ１で使用したもの
下記の中身はawsにアクセスして、指定の文字列（Hello World）を一定間隔で送信しているものだが、uart制御を入れてそのデータ送受信結果をAWSに送る変更をする。
```bash:awsアクセス
~/Work/esp32/esp-aws-iot/examples/mqtt/tls_mutual_auth
```
* uart制御の参考になるサンプルは以下を使用する
```bash:uart
~/Work/esp32/v44/esp-idf/examples/peripherals/uart/uart_repl
```
* サンプルコードをとりあえず動く形に修正したもの（プロセッサ側からの送信）
改行コード等はさることながら、タイマー値やレスポンス読み出し等の処理もないと動かないため改造時には注意が必要です。

```c:~/Work/esp32/v44/esp-idf/examples/peripherals/uart/uart_repl/uart_repl_example_main.c
static void send_commands(void* arg) {
    static char data[READ_BUF_SIZE];
    char command0[] = "config\r\n";
    char command[]  = "processor\r\n";
    char command2[] = "bw 4\r\n";
    char command3[] = "sf 7\r\n";
    char command4[] = "channel 1\r\n";
    char command5[] = "panid 0001\r\n";
    char command6[] = "ownid 0000\r\n";
    char command7[] = "dstid 0001\r\n";
    char command9[] = "power -4\r\n";
    char command10[] = "start\r\n";
    char command11[] = "abcdefg\r\n";

    int len = 0;
    void* substring = NULL;

    printf("%s\n","test1\n");
    const TickType_t delay = 3000 / portTICK_PERIOD_MS;  // 3sec.
    const TickType_t delay2 = 5000 / portTICK_PERIOD_MS;  // 5sec.
    vTaskDelay(delay);

    /* Send the command `consoletest` to the console UART. */
    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command0, sizeof(command0));
    if ( len == -1 ) {
       goto end;
    }
    vTaskDelay(delay);

    do {
       len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);

    printf("%s\n",data);



    /* Send the command `consoletest` to the console UART. */
    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command, sizeof(command));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);

    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command2, sizeof(command2));
    if ( len == -1 ) {
       goto end;
    }
    vTaskDelay(delay);

    do {
       len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);

    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command3, sizeof(command3));
    if ( len == -1 ) {
       goto end;
    }
    vTaskDelay(delay);

    do {
       len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);

    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command4, sizeof(command4));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);


    printf("%s",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command5, sizeof(command5));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);


    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command6, sizeof(command6));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);


    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command7, sizeof(command7));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);


    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command9, sizeof(command9));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);


    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command10, sizeof(command10));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);

    vTaskDelay(delay2);

    printf("%s\n",data);

    while(1)
    {
        len = uart_write_bytes(DEFAULT_UART_CHANNEL, command11, sizeof(command11));
        if ( len == -1 ) {
            goto end;
        }
        vTaskDelay(delay);
    }

    /**
     * Check whether we can find test_message in the received message. Before
     * that, we need to add a NULL character to terminate the string.
     */
    data[len] = 0;
    substring = strcasestr(data, test_message);

end:
    /* This is a must to not send anything to the console anymore! */
    disconnect_uarts();
    printf("Result: %s\n", substring == NULL ? "Failure" : "Success");
    vTaskDelete(NULL);
}

```

* サンプルコードをとりあえず動く形に修正したもの（host側からの送信）
改行コード等はさることながら、タイマー値やレスポンス読み出し等の処理もないと動かないため改造時には注意が必要です。
```c:~/Work/esp32/v44/esp-idf/examples/peripherals/uart/uart_repl/uart_repl_example_main.c
static void send_commands(void* arg) {
    static char data[READ_BUF_SIZE];
    char command0[] = "config\r\n";
    char command[]  = "processor\r\n";
    char command2[] = "bw 4\r\n";
    char command3[] = "sf 7\r\n";
    char command4[] = "channel 1\r\n";
    char command5[] = "panid 0001\r\n";
    char command6[] = "ownid 0000\r\n";
    char command7[] = "dstid 0001\r\n";
    char command9[] = "power -4\r\n";
    char command10[] = "start\r\n";
    char command11[] = "abcdefg\r\n";

    int len = 0;
    void* substring = NULL;

    printf("%s\n","test1\n");
    const TickType_t delay = 3000 / portTICK_PERIOD_MS;  // 3sec.
    const TickType_t delay2 = 5000 / portTICK_PERIOD_MS;  // 5sec.
    vTaskDelay(delay);

    /* Send the command `consoletest` to the console UART. */
    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command0, sizeof(command0));
    if ( len == -1 ) {
       goto end;
    }
    vTaskDelay(delay);

    do {
       len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);

    printf("%s\n",data);



    /* Send the command `consoletest` to the console UART. */
    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command, sizeof(command));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);

    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command2, sizeof(command2));
    if ( len == -1 ) {
       goto end;
    }
    vTaskDelay(delay);

    do {
       len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);

    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command3, sizeof(command3));
    if ( len == -1 ) {
       goto end;
    }
    vTaskDelay(delay);

    do {
       len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);

    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command4, sizeof(command4));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);


    printf("%s",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command5, sizeof(command5));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);


    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command6, sizeof(command6));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);


    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command7, sizeof(command7));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);


    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command9, sizeof(command9));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);


    printf("%s\n",data);

    len = uart_write_bytes(DEFAULT_UART_CHANNEL, command10, sizeof(command10));
    if ( len == -1 ) {
        goto end;
    }
    vTaskDelay(delay);

    do {
        len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
    } while (len == 0);

    vTaskDelay(delay2);

    printf("%s\n",data);

    while(1)
    {
      int counter = 0;
      char dataBuff[50] = {}; /*max 50bytes*/
      len = 0;

      do {
          len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
          vTaskDelay(delay);
      } while (len == 0);

      /*ascii mode only*/
      for(int i = 0; i < 50; i++)
      {
        counter++;
        dataBuff[i] = data[i];
        if(data[i] == '\n')
        {
          break;
        }
      }
      printf("%s\n",dataBuff);
    }

```



* 上記接続が成功した時のTeraterm側設定
![tera.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/8898ce21-017a-20c6-1646-688b3e010009.png)

* 端子設定は次のとおり

||es920lr3eb（図１）|esp32（図２）|備考|
|-|-|-|-|
|(N)RST|CN4:2|適当なgpio|現在は放置|
|uart|CN4:10|J3:4||
|uart|CN4:12|J3:5||
|GND|CN4:1, CN4:29|J2:14, J3:1, J3:7|esp32のGNDを１つでもつなぐとesp32がローダーモードにならない|

* 図１
![スクリーンショット 2023-07-20 0.36.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/89ae9415-4950-f287-f101-b9d0d987342f.png)

* 図２
![esp32-lesson01-03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423321/442d30d9-fc50-62e4-84ad-7ec510769163.jpeg)

# ステップ４　AWS ← ESP32←ES920LR3EB←ES920LR3EB
　「ステップ３で作成した読み出しコード」を「ステップ１のAWSにアップするコード」とマージして、AWS IOTから連携されたデータを読み出せるようになりました。
　ソースコードは、[github](https://github.com/Segiori/esp-aws-iot/tree/release/202210.01-LTS)にアップロードしました。