MQTTbrokerを使ってみる(その2)通信編

前回の続きです。無料MQTTbrokerであるicecreamにRaspberryPiとESP32を接続してみます。💪

RaspberryPiの接続はpythonで書いてあるのでwin10やMacでも接続できます。


前回の記事で接続パラメーターについては確認済みなので、あとはこれを設定していくだけで動きます。

1、RaspberryPi側

⭐️Subscribe

import paho.mqtt.client as mqtt
host = 'mqtt.uko.jp'
username = "icecream"
password = "STvvhbn2"
clientID = "Raspberry456"
name ="raspberry"
port = 1883
topic = 'tp1/sub1'
def on_connect(client, userdata, flags, respons_code):
   print('status {0},{1}'.format(respons_code,userdata))
#topicを複数登録してみた
   client.subscribe(topic)
   
def on_message(client, userdata, msg):
   
   #topic QOS payloadを取得
   print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
if __name__ == '__main__':
   # Publisherと同様に v3.1.1を利用
   #client = mqtt.Client(client_id = clientID,clean_session=True,userdata=name,protocol=mqtt.MQTTv311,transport="tcp")
   client = mqtt.Client(client_id = clientID,clean_session=True,protocol=mqtt.MQTTv311,transport="tcp")
   client.username_pw_set(username, password=password)
   
   client.on_connect = on_connect
   client.on_message = on_message
   client.connect(host, port=port, keepalive=60)
   # 待ち受け状態にする
   client.loop_forever()

接続のポイントはここですね。設定不要なパラメーターもあるのですが、あえてフルスペックで設定をいれてみました。

#client = mqtt.Client(client_id = clientID,clean_session=True,userdata=name,protocol=mqtt.MQTTv311,transport="tcp")
   client = mqtt.Client(client_id = clientID,clean_session=True,protocol=mqtt.MQTTv311,transport="tcp")
   
   client.username_pw_set(username, password=password)

⭐️Publisher

こちらも、ほぼ同じですが接続とpublishしたあとにwaitを入れました。

これは通信環境などによってはコマンドが実行されてないのに、次のコマンドが実行されないようにするために簡易的にsleepを入れています。

今回のプログラムには接続完了やPublish完了のコールバック関数を組み込んであるので、その呼び出しがあったら次の制御に進むように組んでもよいと思います。

初めは、そんなプログラムを書いたのですが、接続に失敗した場合無限ループになったり、そのためのタイムアウトを設定したりしたら、分かりにくいプログラムになってしまい紹介するには適さないようだったのでシンプルにsleepを入れました。

from time import sleep
import paho.mqtt.client as mqtt
host = 'mqtt.uko.jp'
username = "icecream"
password = "STvvhbn2"
clientID = "Raspberry123"
name ="raspberry"
port = 1883
topic = 'tp1/sub1'
qos = 0
# ブローカーに接続できたときの処理
def on_connect(client, userdata, flag, rc):
 print("Connected with result code " + str(rc))

# publishが完了したときの処理
def on_publish(client, userdata, mid):
 print("publish: {0},{1}".format(userdata,mid))
# インスタンス作成時に protocol v3.1.1 を指定します
#client = mqtt.Client(client_id = clientID,clean_session=True,userdata=name,protocol=mqtt.MQTTv311,transport="tcp")
client = mqtt.Client(client_id = clientID,clean_session=True,protocol=mqtt.MQTTv311,transport="tcp")
client.username_pw_set(username, password=password)
client.on_connect = on_connect         # 接続時のコールバック関数を登録
client.on_publish = on_publish         # メッセージ送信時のコールバック
client.connect(host, port=port, keepalive=60)
client.loop_start()
sleep(1)
client.publish(topic, 'testmessage',qos = qos)
sleep(2)
client.disconnect()

まずは、ターミナルを2つ立ち上げて、RaspberryPiで通信してみましょう!

Subscribe側にメッセージが表示されれば通信成功です。💯

ちなにみPublisher、Subscrideで違うclientIDを設定しで下さい。MQTTの仕様で同じclientIDの接続あると先に接続しているclientの接続を切られてしまいます。

もし動かない場合はMQTTXの使えばPublisher、Subscrideのどちらがバグってるか分かると思います。

2、ESP32側

こちらはPublish、Subscribe両方組み込んでいます。ボタンを押すとPublishします。こちらもパラメーターはフルスペックで組み込んでありますが、RaspberryPi側でいうnamedata(connectname)の設定がありません。

PubsubClientライブラーを覗いたのですが、設定できるライブラリーがなかったので設定できないようです。(なくても問題ありませんが)

#include <WiFi.h>
#include <PubSubClient.h>
   // WiFi
   const char ssid[] = "your ssid";
   const char passwd[] = "your password";
   // Pub/Sub
   const char* mqttHost = "mqtt.uko.jp"; // MQTTのIPかホスト名
   const int mqttPort = 1883;       // MQTTのポート
   const char* mqttUser = "icecream";
   const char* mqttPassword = "STvvhbn2";
   int qos =0;
   WiFiClient wifiClient;
   PubSubClient mqttClient(wifiClient);
   const char* topic =  "tp1/sub1";     // リクエストするトピック名
   const char* topicesp = "esp/sub";     // リクエストするトピック名
   char* payload;                   // 受信データ
   /**
    * Connect WiFi
    */
   void connectWiFi()
   {
       WiFi.begin(ssid, passwd);
       Serial.print("WiFi connecting...");
       while(WiFi.status() != WL_CONNECTED) {
           Serial.print(".");
           delay(100);
       }
       Serial.print(" connected. ");
       Serial.println(WiFi.localIP());
   }
   /**
    * Connect MQTT
    */
    void callback(char* topic, byte* payload, unsigned int length)
  {
    Serial.print("Message arrived in topic: ");
    Serial.println(topic);
    Serial.print("Message:");
  for (int i = 0; i < length; i++)
  {
    Serial.print((char)payload[i]);
  }
   Serial.println();
   Serial.println("-----------------------");
 }   
   void connectMqtt()
   {
       mqttClient.setServer(mqttHost, mqttPort);
       mqttClient.setCallback(callback);
       Serial.println("Connecting to MQTT...");
       
       while( ! mqttClient.connected() ) {
         
           if (mqttClient.connect("ESP32Client", mqttUser, mqttPassword )) {
               Serial.println("connected"); 
           }
           delay(1000);
   }
        mqttClient.subscribe(topic);
        mqttClient.subscribe(topic2);
}
   void setup() {
       Serial.begin(115200);
       pinMode(0, INPUT_PULLUP);     // Initialize the BUILTIN_LED pin as an output
       // Connect WiFi
       connectWiFi();
       // Connect MQTT
       connectMqtt();
       
   }
int count=0;
   void loop() {
  
       // 送信処理 topic, payloadは適宜
       int a=digitalRead(0);
         if(a==0) {
                  count++;
                  if(count > 250){count =250;}
         }else{
                  count=0;
          }
        if(count ==2){
         payload = "Hello ESP32";
         mqttClient.publish(topic, payload,qos);
        }
      
       delay(100);
       mqttClient.loop();  
   }


RaspberryPi側でPublishして、RaspberryPi側のSubscribeをESP32の両方でメッセージを受信できれば、通信成功です。💮

ボタンを押すとESP32でもPublishできます。

3、まとめ

MQTTBrokerを使うこで、出先などからも簡単にマイコンをコントロールできます。💮

今回herokuCloudMQTTを組み込んで無料でMQTTサーバーを立ち上げようと思ったのですが、無料使用できるアカウントが空いてないとかで設定できませんでした。😅

MQTTは月500円程度で使えるものもあるので、常時可動で使いたい場合は契約してみても面白かもしれませんね。

では🤚



この記事が気に入ったらサポートをしてみませんか?