M5Stackで、シリアル通信メッセージをJSON形式に変換してWi-Fi(MQTT)でラズパイに送る方法

JSON

今回は、ArduinoIDEのシリアルモニタで、シリアル通信メッセージを送って、これを受信したM5StackがJSON形式に変換して、Wi-Fi(MQTT)で、ラズパイに送る方法を紹介します。

想定ケースは、車両のECUからの車両情報を、M5Stack経由で、AWSなどのクラウドへアップロードするケースです。シリアル通信部分を、CANやLIN、SPI等の通信に差し替えることで、様々な用途があると思っています。

スポンサーリンク

前提

・M5Stack

・Raspberry Pi4

 ラズパイには、MQTTブローカであるmosquitto、MQTTクライアントのmosquitto-clientsがインストールされていることが前提です。

M5StackとRaspberry Piは、同じWi-Fiを使います。

M5StackとラズパイをWi-Fi(MQTT)で繋ぎ、JSONデータを通信する方法

構成

ArduinoIDEに、必要なライブラリをインストールする

ライブラリは、以下をインストールします。

・PubSubClient

・ArduinoJSON

ArduinoIDEの「スケッチ」-「ライブラリをインクルード」-「ライブラリを管理」を選択する

ライブラリマネージャでは、「PubSubClient」と入力すると、PubSubClientを見つけられます。インストールボタンがありますので、これを押してインストールします。

「ArdunioJSON」ライブラリも、同様にインストールします。

サンプルコード(M5Stack)

ArduinoIDEを起動して、以下のサンプルコードをコピーしてください。


#define M5STACK_MPU6886

#include <WiFi.h>
#include <PubSubClient.h>
#include <M5Stack.h>
#include <stdio.h>
#include <string.h>
#include <ArduinoJson.h>

////////////////////////////////////////////////////////////////////////////////

// Wi-FiのSSID
char *ssid = "**********";

// Wi-Fiのパスワード
char *password = "************";

// MQTTの接続先(ラズパイ)のIP
const char *endpoint = "***.***.***.***";

// MQTTのポート
const int port = 1883;

// デバイスID デバイスIDは機器ごとにユニークにします
char *deviceID = "M5Stack";

// メッセージを知らせるトピック
char *pubTopic = "/pub/M5Stack";

// メッセージを待つトピック
char *subTopic = "/sub/M5Stack";

////////////////////////////////////////////////////////////////////////////////

WiFiClient httpsClient;
PubSubClient mqttClient(httpsClient);

// シリアル通信の初期化
void setup_serial(){
  Serial.begin(115200);
  while (!Serial) continue;
}

// Wi-Fiモジュールの初期化と開始
void setup_wifi(){
  
  Serial.println("Connecting to ");
  Serial.print(ssid);

  // WiFi接続性改善のため、いったん切断
  WiFi.disconnect( true, true ); //WiFi OFF, eraseAP=true
  delay(500);

  // WiFi開始
  WiFi.begin(ssid, password);
 
  // Wi-Fi接続待ち
  while (WiFi.status() != WL_CONNECTED){
    delay(500);
    M5.Lcd.print(".");
  }

  // WiFi接続成功メッセージの表示
  Serial.println("\nWiFi Connected.");
  M5.Lcd.setCursor(10, 40);
  M5.Lcd.setTextSize(2);
  M5.Lcd.println("WiFi Connected.");

  // M5StackのIPアドレスを表示
  M5.Lcd.print("IP address: ");
  M5.Lcd.println(WiFi.localIP());
  
}

void setup(){

  // M5Stack objectの初期化
  M5.begin();
  M5.Power.begin();
  M5.IMU.Init();

  setup_serial();

  // 画面初期設定
  M5.Lcd.fillScreen(TFT_NAVY);
  M5.Lcd.setCursor(10, 10);
  M5.Lcd.setTextSize(3);
  M5.Lcd.printf("START");

  // Wi-Fi処理の開始
  setup_wifi();

  // MQTTクライアントの初期化
  mqttClient.setServer(endpoint, port);

  // MQTT接続開始
  connectMQTT();

}

// MQTT接続処理
void connectMQTT(){

  // MQTT接続待ち
  while (!mqttClient.connected()){
    if (mqttClient.connect(deviceID)){
      // 所定のデバイスと接続した
      Serial.println("Connected.");
      int qos = 0;
      mqttClient.subscribe(subTopic, qos);
      Serial.println("Subscribed.");
    }else{
      // 所定のデバイスと接続失敗 ⇒ 再トライする
      Serial.print("Failed. Error state=");
      Serial.print(mqttClient.state());
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

// MQTT接続管理
void mqttLoop(){
  // MQTT接続状態を監視し、切断されていたら、再接続を試みる
  if (!mqttClient.connected()){
    connectMQTT();
  }
  // MQTTクライアント側の定期処理の実行
  mqttClient.loop();
}

// 文字列 = split(元の文字列,分割文字列,分割した後何番目の文字列か)
String split(String data, char separator, int index){
    int found = 0;
    int strIndex[] = {0, -1};
    int maxIndex = data.length();
    int endcheck = false;

    for(int i=0; i < maxIndex; i++){
        if( data.charAt(i) == separator ){
            found++;
            if ( found == index ){ strIndex[0] = i+1; }
            if ( found == index+1 ){ strIndex[1] = i; endcheck=true; }
            if(endcheck){ break; }
        }
    }
    return (strIndex[1]==-1) ? data.substring(strIndex[0]) : data.substring(strIndex[0], strIndex[1]);
}
//分割文字の数
int Keywordcounter(String Original,char Keyword){
    int Keywordcount = 0;
    for (int i = 0; i < Original.length(); i++){
        if (Original.charAt(i) == Keyword) { 
          Keywordcount++; 
        }
    }
    return Keywordcount;
}

void loop(){

  StaticJsonDocument<500> doc;
  char pubMessage[256];

  // MQTT接続監視
  mqttLoop();

  // シリアル通信受信時にメッセージを送信する
  int recieved_byte_size = Serial.available();
  if (recieved_byte_size){
    String recieveData = Serial.readStringUntil('\n');

    //描画!
    M5.Lcd.fillScreen(TFT_DARKGREEN);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(0,10);
    M5.Lcd.println(recieveData);      
          
    Serial.println("シリアル通信データ:" + String(recieveData));

    //分割文字の数
    int count = Keywordcounter(recieveData, ',');
    String part[count+1];

    // シリアルデータの分割
    for (int i = 0; i < count+1; i++){
        part[i] = split(recieveData,',',i);
    }

    // JSONメッセージの作成
    JsonArray idValues = doc.createNestedArray("ID");
    idValues.add(part[0]);

    JsonArray dataValues = doc.createNestedArray("data");
    dataValues.add(part[1]);

    serializeJson(doc, pubMessage);

    // メッセージの画面表示
    Serial.print("topic= ");
    Serial.println(pubTopic);
    Serial.print("Message= ");
    Serial.println(pubMessage);
    M5.Lcd.print(pubMessage);  

    // メッセージのPublish
    mqttClient.publish(pubTopic, pubMessage);
    Serial.println("Published.");
    Serial.println("");
    
  }else{
  }

}

M5Stackへの書き込みが完了し起動をすると、M5Stackは、Wi-Fiルータと接続  → MQTTの接続を行い、PCからのシリアル通信を待ち受けます。

JSONデータを作成するのに、ArduinoJSONというライブラリを使いました。とても簡単に、JSONデータを扱うことができ、とても便利です。

ラズパイ側のmosquittoを起動する

ラズパイのコンソールを起動して、mosquittoを動作させます。

> mosquitto_sub -d -t /pub/M5Stack

PCのArduinoIDEのシリアルモニターからメッセージを送信する

ArduinoIDEのシリアルモニターを起動させます。

上部の欄に、以下を入力して、Enterを押します。

123,1122334455

ラズパイのコンソールに、以下のメッセージが表示され、シリアル通信メッセージが、ラズパイに伝わっていることがわかります。

Received message 'b'{"ID":["123"],"data":["1122334455"]}'' on topic '/pub/M5Stack' with QoS 0

まとめ

今回は、ArduinoIDEのシリアルモニタで、シリアル通信メッセージを送って、これを受信したM5StackがJSON形式に変換して、Wi-Fi(MQTT)で、ラズパイに送る方法を紹介します。

参考

2.2 Arduino シリアル通信で文字列の入力(2)
Arduinoで通信する方法 Arduinoで通信する 文字列を受け取る ※1 123と入力して送信すると 1…

コメント

タイトルとURLをコピーしました