1
0
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

Private LoRa Gateway経由でnodeのデータをAWS IoTにpublish③ E220でESP32 LoRaデバイス構築

Last updated at Posted at 2024-07-07

この記事について

前回構築したPrivate LoRa GWに接続するLoRa DeviceをESP32ボードとLoRaモジュール評価ボードで構築します。下図の色付き部分です。

  • edge node用ESP32ボードにLoRaモジュール評価ボードを接続しPrivate LoRaデバイス化
  • edge node用ESP32を仮想エッジデバイスと見立てて監視対象の数値をLoRa GWにpub

させます。



デバイス

LoRaモジュール評価ボード

LoRaモジュール評価ボード(E220-900T22S(JP)-EV1)
README.md・サンプルコード

ESP32ボード

あまり使用例がないボードですがAmazonで入手可能なACEIRMC D1 Mini NodeMCU ESP32 ESP-WROOM-32 IoT 開発ボードを使いました。

当時参照したDocのURLが探しても見つからない為、見つけたら後追いでリンクを貼ります。

本稿の話とは絡まないですが、たまねぎブログさん行き当たりばったり電子工作さんが比較的最近丁寧なレポートをまとめておられますので利用検討の際は助けになるかと思います。

Arduino

前回まで2回のPythonによる構築時に設定したsetting.iniの内容をデータとしてアップロードするためにファイルアップローダーpluginが必要になります。

記事執筆時点(2024.07.07)でもArduino IDE 2.X系でファイルアップローダーが使えなかったので1.x系を使用します。

ボードについてはESP32 DEV MODULE 3.x系のバグは解消していないようなので2.0.x系の利用を推奨します(というか修正できなかった)。

IDE:1.8.18
ボード:ESP32 DEV MODULE 2.0.17
追加ライブラリ:M5Core2 0.1.7
ファイルアップローダーplugin:ESP32FS-1.1

サンプルスケッチ

構成

ダウンロードファイルの内訳です。

  • README:esp32_e220900t22s_jp_lib/docs/README.md
  • スケッチsample code:esp32_e220900t22s_jp_lib/example/lora_multi_task/lora_multi_task.ino
  • ライブラリー:esp32_e220900t22s_jp_lib/src
  • iniファイル:esp32_e220900t22s_jp_lib/docs/e220900t22s_jp_lora_config.ini

スケッチ名変更

今回スケッチ名をE220_D1miniESP32_aws-2としてlora_multi_task.inoのファイル名を変更します。

iniファイルを格納するsub directoryをdataとするとスケッチdirectoryの構成は以下のようになります。

E220_D1miniESP32_aws-2
 ┣ data
 ┃ ┗ e220900t22s_jp_lora_config.ini
 ┣ E220_D1miniESP32_aws-2.ino
 ┣ esp32_e220900t22s_jp_lib.cpp
 ┗ esp32_e220900t22s_jp_lib.h

スケッチ

スケッチ名:E220_D1miniESP32_aws-2のプロジェクトを書き込んだESP32ボードで構築したPrivate LoRa GW とLoRa通信するためにサンプルファイルを一部変更します。

iniファイル

own_address

Pi GWでは0、Pi LoRa Deviceは1にしたので2にします。

wor_cycle

Pi GWに合わせて3000にします。

encryption_key

Pi GWに合わせて1234にします。

target_address

ffffにします。

/E220_D1miniESP32_aws-2/e220900t22s_jp_lora_config.ini
own_address=2
baud_rate=9600
bw=125
sf=9
subpacket_size=200
transmitting_power=13
own_channel=0
wor_cycle=3000
encryption_key=1234
target_address=ffff
target_channel=0

lib.cpp

主にiniファイルの変更箇所を変更します。出力も追加します。

/E220_D1miniESP32_aws-2/esp32_e220900t22s_jp_lib.cpp(修正後)
.
.
void CLoRa::SetDefaultConfigValue(struct LoRaConfigItem_t &config) {
  const LoRaConfigItem_t default_config = {
      0x0000, // own_address 0
      0b011, // baud_rate 9600 bps
      0b10000, // air_data_rate SF:9 BW:125
      0b00, // subpacket_size 200
      0b0, // rssi_ambient_noise_flag 無効
      0b0, // transmission_pause_flag 有効
      0b01, // transmitting_power 13 dBm
      0x00, // own_channel 0
      0b1, // rssi_byte_flag 有効
      0b1, // transmission_method_type 固定送信モード
      0b0, // lbt_flag 有効
      0b101, // wor_cycle 3000 msに変更
      0x0000, // encryption_key 0
      0x0000, // target_address 0
      0x00}; // target_channel 0

  config = default_config;
}
.
.
int CLoRa::OpenConfigFile(const char *filename,
                          struct LoRaConfigItem_t &config) {
  int ret = 0;

  // フラッシュメモリのファイルを開く
  File file = SPIFFS.open(filename, FILE_READ);
  if (!file) {
    SerialMon.printf("file open failed.\n");
    return 1;
  }

  while (file.available()) {
    String key = file.readStringUntil('=');
    String val = file.readStringUntil('\n');
//追加
    SerialMon.printf("%s", key.c_str());
    SerialMon.printf("%s", val.c_str());

    key.toLowerCase();
    // 設定値を内部変数に読み取る
    ReadConfigValue(key.c_str(), val.c_str());
  }

  // 設定値をセットする
  SetConfigValue(config);
//追加
  SerialMon.printf("Sat default values.\n");

  return ret;
}
.
.

  // wor_cycle
  switch (wor_cycle_val) {
  case 500:
    config.wor_cycle = 0b000;
    break;
  case 1000:
    config.wor_cycle = 0b001;
    break;
  case 1500:
    config.wor_cycle = 0b010;
    break;
  case 2000:
    config.wor_cycle = 0b011;
    break;
//3000を追加
  case 3000:
    config.wor_cycle = 0b101;
    break;
  default:
    err = 1;
    SerialMon.printf("wor_cycle invalid value.\n");
    SerialMon.printf("default wor_cycle value is used.\n");
    break;
  }
.
.

lib.h

ボードのピンアサインを変更します。

LoRaモジュール評価ボード(E220-900T22S(JP)-EV1)のピンをこれらのport番号のピンと接続します。

この5種類以外にESP32とE220ボードのVCC(5V)とGNDも接続します。

/E220_D1miniESP32_aws-2/esp32_e220900t22s_jp_lib.h(修正後)
.
.
// E220-900T22S(JP)へのピンアサイン
#define LoRa_ModeSettingPin_M0 23
#define LoRa_ModeSettingPin_M1 19
#define LoRa_RxPin 16
#define LoRa_TxPin 17
#define LoRa_AUXPin 18
.
,

E220_D1miniESP32_aws-2.ino

主な変更はLoRaSendTask()のロジックです。
サンプルコードではconsole入力をpubしますが今回は0~1000の乱数を発生させて10秒毎にpubします。

実使用場面を想定してwifiも無効にしておきます。

識別子は、own_addressを2にしたのでtopicのサフィックスとなるdevice_noも2にします。

修正したコードは以下です。

/E220_D1miniESP32_aws-2/E220_D1miniESP32_aws-2.ino(修正後)
#include "esp32_e220900t22s_jp_lib.h"
#include <Arduino.h>
#include <FS.h>
#include <SD.h>
#include <SPI.h>
//参照追加
#include <WiFi.h>


CLoRa lora;
struct LoRaConfigItem_t config;
struct RecvFrameE220900T22SJP_t data;

/** prototype declaration **/
void LoRaRecvTask(void *pvParameters);
void LoRaSendTask(void *pvParameters);
void ReadDataFromConsole(char *msg, int max_msg_len);

void setup() {
  // put your setup code here, to run once:
  SerialMon.begin(9600);
  delay(1000); // SerialMon init wait
  SerialMon.println();
  //wifi無効化
  WiFi.disconnect(true);

  // LoRa設定値の読み込み
  if (lora.LoadConfigSetting(CONFIG_FILENAME, config)) {
    SerialMon.printf("Loading Configfile failed. The default value is set.\n");
  } else {
    SerialMon.printf("Loading Configfile succeeded.\n");
  }

  // E220-900T22S(JP)へのLoRa初期設定
  if (lora.InitLoRaModule(config)) {
    SerialMon.printf("init error\n");
    return;
  }

  // ノーマルモード(M0=0,M1=0)へ移行する
  lora.SwitchToNormalMode();

  // マルチタスク
  xTaskCreateUniversal(LoRaRecvTask, "LoRaRecvTask", 8192, NULL, 1, NULL,
                       APP_CPU_NUM);
  xTaskCreateUniversal(LoRaSendTask, "LoRaSendTask", 8192, NULL, 1, NULL,
                       APP_CPU_NUM);
}

void loop() {
}

void LoRaRecvTask(void *pvParameters) {
  while (1) {
    if (lora.RecieveFrame(&data) == 0) {
      SerialMon.printf("recv data:\n");
      for (int i = 0; i < data.recv_data_len; i++) {
        SerialMon.printf("%c", data.recv_data[i]);
      }
      SerialMon.printf("\n");
      SerialMon.printf("hex dump:\n");
      for (int i = 0; i < data.recv_data_len; i++) {
        SerialMon.printf("%02x ", data.recv_data[i]);
      }
      SerialMon.printf("\n");
      SerialMon.printf("RSSI: %d dBm\n", data.rssi);
      SerialMon.printf("\n");

      SerialMon.flush();
    }

    delay(1);
  }
}

void LoRaSendTask(void *pvParameters) {
  while (1) {
    //ランダムな整数を生成してmsgとして出力
    int count = random(0, 1001);
    char msg[200] = {0};

    snprintf(msg, sizeof(msg), "%08d", count);
    // device No.2をmsg文字列に追加
    strcat(msg, "\n2\n");

    if (lora.SendFrame(config, (uint8_t *)msg, strlen(msg)) == 0) {
      SerialMon.printf("send succeeded.\n");
      SerialMon.printf("\n");
    } else {
      SerialMon.printf("send failed.\n");
      SerialMon.printf("\n");
    }

    SerialMon.flush();
    delay(10000);
  }
}

void ReadDataFromConsole(char *msg, int max_msg_len) {
  int len = 0;
  char *start_p = msg;

  while (len < max_msg_len) {
    if (SerialMon.available() > 0) {
      char incoming_byte = SerialMon.read();
      if (incoming_byte == 0x00 || incoming_byte > 0x7F)
        continue;
      *(start_p + len) = incoming_byte;
      // 最短で3文字(1文字 + CR LF)
      if (incoming_byte == 0x0a && len >= 2 && (*(start_p + len - 1)) == 0x0d) {
        break;
      }
      len++;
    }
    delay(1);
  }
  // msgからCR LFを削除
  len = strlen(msg);
  for (int i = 0; i < len; i++) {
    if (msg[i] == 0x0D || msg[i] == 0x0A) {
      msg[i] = '\0';
    }
  }
}

iniファイル書き込み

ツール > ESP32 Sketch Data Upload を実行すると/dataに格納したiniファイルがuploadされます。

スケッチ書込み

通常の「マイコンボードに書き込む」を実行します。

実行結果

通常のArduino sketchと同様に書き込みが正常終了した時点で起動しています。

シリアルモニタでも出力を確認できます。

Private LoRa GWのgateway.pyを起動させるとsubします。

gateway.py
user@privateLoRaAP1:~ $ python main.py /dev/ttyS0 --rssi
serial port:
/dev/ttyS0
receive waiting...
payload: b''
Connected
topic:  privateLoRaAP1/LoRaDev2
count :  00000897
{'Timestamp': 1720220384, 'count': 897}
topic:  privateLoRaAP1/LoRaDev2
count :  00000309
{'Timestamp': 1720220394, 'count': 309}

ラズパイ LoRa Deviceのsend.pyも実行します。
GW brokerで乱数と8888がsubされているのが確認できます。

gateway.py
.
.
.
{'Timestamp': 1720220485, 'count': 863}
topic:  privateLoRaAP1/LoRaDev1
count :  8888
{'Timestamp': 1720220489, 'count': 8888}
topic:  privateLoRaAP1/LoRaDev2
count :  00000068
{'Timestamp': 1720220495, 'count': 68}
topic:  privateLoRaAP1/LoRaDev1
count :  8888
{'Timestamp': 1720220499, 'count': 8888}
topic:  privateLoRaAP1/LoRaDev2
count :  00000453
{'Timestamp': 1720220505, 'count': 453}
.
.
.

AWS IoT CoreのMQTTクライアントでもdevice_no:1(topic:privateLoRaAP1/LoRaDev1)とdevice_no:2(topic:privateLoRaAP1/LoRaDev2)からsub出来ているのが確認できました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0