WeMosを使ってみる

RaspberryとのMQTT通信(WeMos→Raspberry)

mosquitto-clients編


前回前々回と RaspberryとWeMosのSocket通信 を紹介しました。
そこで、今回はRaspberryとWeMosのMQTT通信を紹介します。
最初にRaspberry側に「mosquitto-clients」をインストールします。

$ sudo apt-get install mosquitto-clients

次に簡単な通信テストを行います。
MQTT Brokerは公開サーバーの「broker.hivemq.com」 を使いました。
Raspberryで2つのターミナルを開いて以下を実行します。

ターミナル1
moreutilsパッケージに含まれているts(timestamp input)を使うと、現在日時を表示することができます。
$ sudo apt install moreutils

$ mosquitto_sub -h broker.hivemq.com -p 1883 -t "nopnop2002" -v | ts "%Y/%m/%d %H:%M:%S"


ターミナル2
$ mosquitto_pub -h broker.hivemq.com -p 1883 -t "nopnop2002" -m "Hello nopnop2002"

mosquitto_pubを実行し、以下のように表示されれば通信テストは終了です。




次に以下のページよりArduinoのMQTTクライアントライブラリ(pubsubclient-master.zip)をダウンロードしま す。
https://github.com/knolleary/pubsubclient

ZIPファイルを展開したらArduino-IDEの「libraries」フォルダーにコピーします。

WeMos側のスケッチは以下の通りです。
MQTTクライアントライブラリに含まれている「pubsubclient\examples\mqtt_esp8266」を元に作りました。
10秒毎にトピックを送信します。
特に注意が必要なのはconnect関数で指定するコネクトID(クライアントID)です。
コネクトIDが他の誰かに既に使われている場合、正しく接続できなかったり、既に接続済のクライアントの接続が切れたりします。
これはこのライブラリに限らず、MQTTの仕様みたいです。
そこで、コネクトIDにはESP8266のCHIPIDを指定しています。これなら必ずユニークになります。
SSIDとPASSWORDは自分の環境に合わせて変更してください。

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define INTERVAL        1000 // MiliSecond
#define SSID            "APのSSID"
#define PASSWORD        "APのパスワード"
#define MQTT_SERVER     "broker.hivemq.com"
#define MQTT_PORT       1883
#define MQTT_TOPIC      "nopnop2002"      // You can change
#define MQTT_WILL_TOPIC "nopnop2002"      // You can change
#define MQTT_WILL_MSG   "I am leaving..." // You can change
#define PAYLOAD_SIZE    50

WiFiClient espClient;
PubSubClient client(espClient);

unsigned long lastMillis;

IPAddress localIP;

void connect_wifi() {
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Wait for WiFi...");
  WiFi.mode(WIFI_STA);
  WiFi.begin(SSID, PASSWORD);

  int retry = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    retry++;
    if (retry > 30) ESP.reset();
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("Wifi status: ");
  Serial.println(WiFi.status());
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void connect_server(char * will_topic, char * will_msg) {

  char clientid[20];

  sprintf(clientid,"ESP8266-%6x",ESP.getChipId());
  Serial.print("clientid=");
  Serial.println(clientid);
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    //if (client.connect(clientid)) {
    if (client.connect(clientid, will_topic,0, 0, will_msg )) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "mqtt_esp8266_sub_temp");
      // ... and resubscribe
      //client.subscribe("inTopic");
      //client.subscribe("nopnop2002/#");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void errorDisplay(char* buff) {
  Serial.print("Error:");
  Serial.println(buff);
  while(1) {
    delay(200);
  }
}

void setup() {
  Serial.begin(115200);
  connect_wifi();

  client.setServer(MQTT_SERVER, MQTT_PORT);
  connect_server(MQTT_WILL_TOPIC, MQTT_WILL_MSG);
 
  Serial.println("connected");
  lastMillis = millis();
}

void loop() {
  static int value = 0;
  char payload[PAYLOAD_SIZE];

  client.loop();
  if (!client.connected()) {
    Serial.println("NOT Connected");
    Serial.print("Wifi status: ");
    Serial.println(WiFi.status());
    if (WiFi.status() != WL_CONNECTED) connect_wifi();
    connect_server(MQTT_WILL_TOPIC, MQTT_WILL_MSG);
  }
    
  if (Serial.available() > 0) {
    char inChar = Serial.read();
    Serial.println("KeyIn");
    client.disconnect();
    Serial.println("Publish end");
    while(1) {
      delay(200);
    }
  }

  long now = millis();
  if (now - lastMillis > INTERVAL) {
    lastMillis = now;
    ++value;
    snprintf (payload, PAYLOAD_SIZE, "hello world #%ld", value);
    Serial.print("loalIP:");
    Serial.print(localIP);
    Serial.print(" Publish message: ");
    Serial.println(payload);
    if (!client.publish(MQTT_TOPIC, payload)) {
      Serial.println("publish fail");
      //errorDisplay("publish fail");
    }
  }
}

このスケッチを実行するとArduino-IDEのシリアルモニターはこのように表示されます。


RaspberryのSubscriberには以下のように表示されます。


WeMosの電源を切ってしばらく(最後にPublishしてから90秒以上)放置するとWillメッセージが届きます。


次は、Raspberry側のSubscriberをPythonで作ってみます。

続く....