📌

MQTTでM5StickC Plus2からPythonへデータを送信

に公開

やりたいこと

M5StickC Plus2からIMUの値を取得して、MQTTでPythonにデータを送信する検証を実施しました。

ハマった点

ファイアウォールにより接続が遮断されていました。うまく接続できない場合は、ネットワーク設定を確認してみてください。

手順

1.mosquittoのインストール

ブローカーとして使いたいPCにソフトをインストールする。
手順は以下を参考に実施しました。
https://qiita.com/koichi_baseball/items/8fa9e0bdbe6d0aebe57d
https://qiita.com/yomori/items/74a9af05a8ccdda12e2f

2.Pythonプログラム(Subscriber)の作成

import json
from datetime import datetime

import paho.mqtt.client as mqtt

# MQTT設定
MQTT_BROKER = "localhost"
MQTT_PORT = 1883
MQTT_TOPIC = "m5stick/data"


# ブローカーに接続できたときの処理
def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("MQTTブローカーに接続しました。")
        # 指定したトピックを購読(Subscribe)
        client.subscribe(MQTT_TOPIC)
    else:
        print(f"接続に失敗しました。リターンコード: {rc}")


# メッセージを受信したときの処理
def on_message(client, userdata, msg):
    try:
        # 受信したメッセージはbytes型なので、UTF-8でデコード
        payload_str = msg.payload.decode("utf-8")

        # JSON文字列をPythonの辞書型に変換
        data = json.loads(payload_str)

        print("----------------------------------------")
        print(datetime.now())
        print(f"トピック '{msg.topic}' からメッセージを受信しました:")
        print(f"  デバイスID: {data.get('deviceId', 'N/A')}")
        print(f"  加速度(X): {data.get('accel_x', 0):.2f}")
        print(f"  加速度(Y): {data.get('accel_y', 0):.2f}")
        print(f"  加速度(Z): {data.get('accel_z', 0):.2f}")
        print(f"  ボタンA: {'押された' if data.get('btnA_pressed') else '---'}")

    except json.JSONDecodeError:
        print(f"JSONのデコードに失敗しました: {msg.payload.decode('utf-8')}")
    except Exception as e:
        print(f"エラーが発生しました: {e}")


def main():
    # MQTTクライアントの作成
    client = mqtt.Client()

    # コールバック関数の設定
    client.on_connect = on_connect
    client.on_message = on_message

    print(f"{MQTT_BROKER} に接続します...")
    try:
        # ブローカーに接続
        client.connect(MQTT_BROKER, MQTT_PORT, 60)

        # 無限ループでメッセージを待機
        # (バックグラウンドで通信を処理し続ける)
        client.loop_forever()

    except KeyboardInterrupt:
        print("\nプログラムを終了します。")
        client.disconnect()
    except Exception as e:
        print(f"接続エラー: {e}")


if __name__ == "__main__":
    main()

3.M5StickC Plus2のプログラム(Publisher)の作成

#include <M5Unified.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

// WiFi設定
const char* ssid = "xxxxx";
const char* password = "xxxxx";

// MQTT設定
const char* mqtt_server = "ブローカーのIPアドレス";  // 公開MQTTブローカー
const int mqtt_port = 1883;
const char* mqtt_topic = "m5stick/data";                  // データを送信するトピック名
const char* mqtt_client_id = "m5stickc-plus2-client-01";  // 他のクライアントと重複しないように設定

// グローバル変数
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsgTime = 0;
const long msgInterval = 1000;  // メッセージ送信間隔 (ミリ秒)

// WiFi接続処理
void setup_wifi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  M5.Lcd.print("IP address: ");
  M5.Lcd.println(WiFi.localIP());
}

// MQTT再接続処理
void reconnect() {
  while (!client.connected()) {
    if (client.connect(mqtt_client_id)) {
      M5.Lcd.println("MQTT connected");
    } else {
      M5.Lcd.print("failed, rc=");
      M5.Lcd.print(client.state());
      M5.Lcd.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  // M5Stackの初期化
  auto cfg = M5.config();
  M5.begin(cfg);
  Serial.begin(115200);

  M5.Lcd.setRotation(1);  // 画面の向きを設定
  M5.Lcd.setTextSize(2);
  M5.Lcd.fillScreen(BLACK);

  // IMUの初期化
  M5.Imu.begin();

  // WiFi接続
  setup_wifi();

  // MQTTクライアントの設定
  client.setServer(mqtt_server, mqtt_port);

  delay(1500);
}

void loop() {
  // M5デバイスの状態を更新
  M5.update();

  // MQTT接続が切れていたら再接続
  if (!client.connected()){
    reconnect();
  }
  client.loop();  // MQTTクライアントの状態を維持

  // 前回の送信から指定時間が経過したかチェック
  unsigned long now = millis();
  if (now - lastMsgTime > msgInterval) {
    lastMsgTime = now;

    // IMUから加速度データを取得
    float ax, ay, az;
    M5.Imu.getAccel(&ax, &ay, &az);

    // JSONデータを作成
    StaticJsonDocument<200> doc;
    doc["deviceId"] = mqtt_client_id;
    doc["accel_x"] = ax;
    doc["accel_y"] = ay;
    doc["accel_z"] = az;
    doc["btnA_pressed"] = M5.BtnA.wasPressed();  // ボタンAが押されたか

    // JSONを文字列に変換
    char buffer[200];
    size_t n = serializeJson(doc, buffer);

    // MQTTトピックにデータをPublish
    client.publish(mqtt_topic, buffer, n);

    // LCDに送信データを表示
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 0);
    M5.Lcd.println("MQTT Publisher");
    M5.Lcd.printf("Topic: %s\n", mqtt_topic);
    M5.Lcd.println("----------------");
    M5.Lcd.printf("ax: %.2f\n", ax);
    M5.Lcd.printf("ay: %.2f\n", ay);
    M5.Lcd.printf("az: %.2f\n", az);
    M5.Lcd.println("Data sent!");

    Serial.print("Publish message: ");
    Serial.println(buffer);
  }
  delay(10);
}

Discussion