LoRa P2P 通信モードは、複数の LoRa デバイスを直接通信させることができます。このモードでは LoRa 変調技術をベースにデータパケットを送信し、フレーム内容を完全にカスタマイズして独自のプライベートネットワークを構築できます。リアルタイム性が求められ、通信範囲が比較的狭く、複雑なネットワーク管理が不要なシーンに適しています。
デバイスの実際の使用に合わせて通信パラメータを設定してください。設定が一致するデバイス同士でなければ通信できません。異なる Atom プロセッサを使用する場合は、以下のマクロを参照して適切な TX/RX ピンを指定してください。
#include <M5Unified.h>
#include "rak3172_p2p.hpp"
#define LORA_CONFIG_PRLEN 8
#define LORA_CONFIG_PWR 22
#define LORA_FREQ 868E6
#define LORA_CR 0 // (4/5=0, 4/6=1, 4/7=2,4/8=3)
#define LORA_SF 7 // (6,7, 8, 9, 10, 11, 12)
#define LORA_BW 500 // (125, 250, 500)
#define ATOM_LORA_RX 19
#define ATOM_LORA_TX 22
#define ATOMS3_LORA_RX 6
#define ATOMS3_LORA_TX 5
RAK3172P2P lora;
void LoRaLoopTask(void* arg)
{
while (1) {
lora.update();
vTaskDelay(5);
}
}
void setup()
{
M5.begin();
Serial.begin(115200);
Serial.println("LoRa Init...");
while (!lora.init(&Serial2, ATOMS3_LORA_RX, ATOMS3_LORA_TX, RAK3172_BPS_115200)) {
delay(1000);
}
lora.setMode(P2P_RX_MODE, 0);
if (lora.config(LORA_FREQ, LORA_SF, LORA_BW, LORA_CR, LORA_CONFIG_PRLEN, LORA_CONFIG_PWR)) {
Serial.println("LoRa config success");
} else {
Serial.println("LoRa config failed");
}
lora.setMode(P2P_TX_RX_MODE);
xTaskCreate(LoRaLoopTask, "LoRaLoopTask", 1024 * 10, NULL, 2, NULL);
}
void loop()
{
M5.update();
if (M5.BtnA.wasPressed()) {
if (lora.print("Hello!")) {
Serial.println("Send success");
}
}
if (lora.available()) {
std::vector<p2p_frame_t> frames = lora.read();
for (int i = 0; i < frames.size(); i++) {
Serial.print("RSSI: ");
Serial.print(frames[i].rssi);
Serial.print(" SNR: ");
Serial.print(frames[i].snr);
Serial.print(" LEN: ");
Serial.print(frames[i].len);
Serial.print(" Payload: ");
for (uint8_t j = 0; j < frames[i].len; j++) {
Serial.printf("%02X", frames[i].payload[j]);
}
Serial.println();
}
lora.flush();
}
}
このサンプルをデバイスへ書き込んだ後、シリアルモニタでログを確認します。AtomS3R の中央ボタンを押すとデータが送信されます。
LoRaWAN 通信モードでは、デバイスは LoRaWAN ゲートウェイを介してデータを送受信します。周波数ホッピング技術により、多数のデバイスノードを同時に管理でき、データのセキュリティも確保されます。使用前に、公共の LoRaWAN ゲートウェイが利用可能であることを確認してください。公共ゲートウェイがない場合は、自身でゲートウェイを構築することも可能です。
OTAA 入網では DevEUI、AppEUI、AppKey パラメータを使用します。
#include <M5Unified.h>
#include "rak3172_lorawan.hpp"
#define DEVEUI "****************"
#define APPEUI "****************"
#define APPKEY "********************************"
// get or set the channel mask to close or open the channel (only for US915, AU915, CN470)
#define CHANNEL_MASK "0000"
#define ATOM_LORA_RX 19
#define ATOM_LORA_TX 22
#define ATOMS3_LORA_RX 6
#define ATOMS3_LORA_TX 5
RAK3172LoRaWAN lorawan;
bool isJoin = false;
void joinCallback(bool status)
{
isJoin = status;
if (status) {
Serial.println("[LoRaWAN] Join network successful!");
Serial.println("Device EUI: " + String(DEVEUI));
} else {
Serial.println("[LoRaWAN] Join network failed!");
}
}
void sendCallback()
{
Serial.println("[LoRaWAN] Uplink confirmed by server");
}
void errorCallback(char* error)
{
Serial.print("[LoRaWAN] Error: ");
Serial.println(error);
}
void LoRaWANLoopTask(void* arg)
{
while (1) {
lorawan.update();
vTaskDelay(5);
}
}
void setup()
{
M5.begin();
Serial.begin(115200);
Serial.println("[Init] Initializing LoRaWAN module...");
while (!lorawan.init(&Serial2, ATOMS3_LORA_RX, ATOMS3_LORA_TX, RAK3172_BPS_115200)) {
Serial.println("[Init] Failed to initialize module, retrying...");
delay(1000);
}
Serial.println("Device Init OK");
Serial.println("[Config] Setting band to EU868...");
while (!lorawan.setBAND(EU868, CHANNEL_MASK)) {
Serial.println(" failed, retrying...");
delay(1000);
}
Serial.println("[Config] Setting OTAA parameters...");
while (!lorawan.setOTAA(DEVEUI, APPEUI, APPKEY)) {
Serial.println(" failed, retrying...");
delay(1000);
}
Serial.println("[Config] Setting device mode to CLASS_C...");
while (!lorawan.setMode(CLASS_C)) {
Serial.println(" failed, retrying...");
delay(1000);
}
Serial.println("[Config] Setting data rate to DR4...");
while (!lorawan.setDR(4)) {
Serial.println(" failed, retrying...");
delay(1000);
}
Serial.println("[Config] Setting Link check...");
while (!lorawan.setLinkCheck(ALLWAYS_LINKCHECK)) {
delay(1000);
}
lorawan.onSend(sendCallback);
lorawan.onJoin(joinCallback);
lorawan.onError(errorCallback);
xTaskCreate(LoRaWANLoopTask, "LoRaWANLoopTask", 1024 * 10, NULL, 5, NULL);
Serial.println("[Info] Attempting to join the network...");
if (lorawan.join(true, false, 10, 10)) {
Serial.println("Start Join...");
} else {
Serial.println("Join Fail");
}
}
void loop()
{
M5.update();
if (M5.BtnA.wasReleased()) {
if (isJoin) {
String data = "UPlink LoRaWAN Frame: " + String(millis());
if (lorawan.send(data)) {
Serial.println("Send Successful");
} else {
Serial.println("Send fail");
}
} else {
Serial.println("LoRaWAN not joined");
}
}
if (lorawan.available()) {
std::vector<lorawan_frame_t> frames = lorawan.read();
for (int i = 0; i < frames.size(); i++) {
Serial.print("RSSI: ");
Serial.println(frames[i].rssi);
Serial.print("SNR: ");
Serial.println(frames[i].snr);
Serial.print("LEN: ");
Serial.println(frames[i].len);
Serial.print("PORT: ");
Serial.println(frames[i].port);
Serial.print("UNITCAST: ");
Serial.println(frames[i].unicast);
Serial.print("Payload: ");
for (uint8_t j = 0; j < frames[i].len; j++) {
Serial.printf("%02X", frames[i].payload[j]);
}
Serial.println();
}
lorawan.flush();
}
if (Serial.available()) {
String ch = Serial.readString();
lorawan.sendCommand(ch);
}
}
このサンプルを書き込んだ後、シリアルモニタでログを確認します。Join 成功後、AtomS3R の中央ボタンを押してデータを送信します。
TTN の該当デバイスページで現在のアップリンク/ダウンリンクデータログを確認できます。
Messaging ページに切り替えると、ダウンリンクデータの送信が可能です。
ABP 入網では DevAddr、AppSkey、NwkSkey パラメータを使用します。Join プロセスは不要で、キー情報を初期化すればすぐにデータ送信を開始できます。
#include <M5Unified.h>
#include "rak3172_lorawan.hpp"
#define DEVADDR "***********" // Device Address
#define APPSKEY "**********************" // Application Session Key
#define NWKSKEY "**********************" // Network Session Key
// get or set the channel mask to close or open the channel (only for US915, AU915, CN470)
#define CHANNEL_MASK "0000"
#define ATOM_LORA_RX 19
#define ATOM_LORA_TX 22
#define ATOMS3_LORA_RX 6
#define ATOMS3_LORA_TX 5
RAK3172LoRaWAN lorawan;
void errorCallback(char* error)
{
Serial.print("[LoRaWAN] Error: ");
Serial.println(error);
}
void LoRaWANLoopTask(void* arg)
{
while (1) {
lorawan.update();
vTaskDelay(5);
}
}
void setup()
{
M5.begin();
Serial.begin(115200);
Serial.println("[Init] Initializing LoRaWAN module...");
while (!lorawan.init(&Serial2, ATOMS3_LORA_RX, ATOMS3_LORA_TX, RAK3172_BPS_115200)) {
Serial.println("[Init] Failed to initialize module, retrying...");
delay(1000);
}
Serial.println("Device Init OK");
Serial.println("[Config] Setting band to EU868...");
while (!lorawan.setBAND(EU868, CHANNEL_MASK)) {
Serial.println(" failed, retrying...");
delay(1000);
}
Serial.println("[Config] Setting ABP parameters...");
while (!lorawan.setABP(DEVADDR, NWKSKEY, APPSKEY)) {
Serial.println(" failed, retrying...");
delay(1000);
}
Serial.println("[Config] Setting device mode to CLASS_C...");
while (!lorawan.setMode(CLASS_C)) {
Serial.println(" failed, retrying...");
delay(1000);
}
Serial.println("[Config] Setting data rate to DR4...");
while (!lorawan.setDR(4)) {
Serial.println(" failed, retrying...");
delay(1000);
}
Serial.println("[Config] Setting Link check...");
while (!lorawan.setLinkCheck(ALLWAYS_LINKCHECK)) {
delay(1000);
}
lorawan.onError(errorCallback);
xTaskCreate(LoRaWANLoopTask, "LoRaWANLoopTask", 1024 * 10, NULL, 5, NULL);
}
void loop()
{
M5.update();
if (M5.BtnA.wasReleased()) {
String data = "UPlink LoRaWAN Frame: " + String(millis());
if (lorawan.send(data)) {
Serial.println("Send Successful");
} else {
Serial.println("Send fail");
}
}
if (lorawan.available()) {
std::vector<lorawan_frame_t> frames = lorawan.read();
for (int i = 0; i < frames.size(); i++) {
Serial.print("RSSI: ");
Serial.println(frames[i].rssi);
Serial.print("SNR: ");
Serial.println(frames[i].snr);
Serial.print("LEN: ");
Serial.println(frames[i].len);
Serial.print("PORT: ");
Serial.println(frames[i].port);
Serial.print("UNITCAST: ");
Serial.println(frames[i].unicast);
Serial.print("Payload: ");
for (uint8_t j = 0; j < frames[i].len; j++) {
Serial.printf("%02X", frames[i].payload[j]);
}
Serial.println();
}
lorawan.flush();
}
if (Serial.available()) {
String ch = Serial.readString();
lorawan.sendCommand(ch);
}
}
CayenneLPP は最適化されたセンサーデータフォーマットです。TTN や Chirpstack にデータをアップロードする際、コンソールや API で取得できるデフォルトのデータは通常 Base64 でエンコードされており、可読性に欠けます。CayenneLPP はさまざまな基本センサータイプをサポートし、LoRaWAN ネットワークを利用した環境データ収集時に解析しやすいフォーマットを提供します。そのため、関連データの処理には CayenneLPP の使用を推奨します。コンソールのノード設定ページで CayenneLPP デコーダを選択するだけで、センサーデータを直感的に確認できます。詳細やサンプルについては以下をご参照ください。