ESP und MQTT

Um die Daten von Messstationen im Rahmen einer Wetterstation einzusammeln bietet sich MQTT als ein genial einfaches Protokoll an. Man braucht lediglich einen MQTT-Broker , der auf einem Server läuft. Die Messstation sendet dann in festgelegten Zeitintervallen die jeweiligen Messwerte an den Broker.

Bei mir läuft der MQTT-Broker Mosquitto auf einem alten Raspberry Pi. Wer (noch) keinen eigenen MQTT-Broker einrichten möchte, kann auch einen öffentlichen Broker im Internet nutzen, z.B. iot.eclipse.org.
Um die Meldungen des ESP anzuzeigen, kann man z.B. das Programm mqtt-spy benutzen, das es z.B. auf GITHUB gibt.
Hat man ohnehin Mosquitto auf einem Raspi installiert, so kann man die Meldungen auch mithilfe von mosquitto_sub abonnieren.

Im meinem Beispiels-Sketch sendet der ESP in 10-Sekunden-Intervallen unter dem topic esp/uptime die jeweilige Uptime. Das Intervall in Sekunden lässt sich über die Konstante interval einstellen.

Wer gerne zusätzlich Statusmeldungen im Seriellen Monitor sehen möchte, muss die Zeilen mit Serial. … wieder einkommentieren.

Hier nun das Programm (auch zum Download):

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

#define FAKTOR 1000 // 60.000 ms = 1 min

//**** Diese Daten müssen angepasst werden *********************

#define WIFI_AP "meinWLAN"
#define WIFI_PASSWORD "meinPasswort"

#define TOKEN "ESP8266_MQTT_TOKEN"
char clientID[] = "MQTT_UPTIME";
char mqttBroker[] = "192.168.1.5"; // Adresse des MQTT-Brokers
int subNetIP = 1; //IP des Subnets
int myIP = 23; //nur der letzte Block der IP ändert sich
String myHostname = "ESP8266_MQTT";
String mqttSubject = "esp/uptime";
unsigned long lastMessage;
const int interval = 10;

//****** Ende Anpassung *****************************************

WiFiClient wifiClient;

PubSubClient client(wifiClient);

int status = WL_IDLE_STATUS;

void setup()
{
  //Serial.begin(115200);
  InitWiFi();
  client.setServer( mqttBroker, 1883 );
}

void loop() {
  if ( !client.connected() ) {
    reconnect();
  }
  if ( millis() - lastMessage > interval * FAKTOR ) { // Update and send only after 30 Seconds
    sendMQTTMessage(mqttSubject, upTime());
    lastMessage = millis();
  }
  client.loop();
}

String niceStr(int i) {  //Zahlen ggf. mit führender Null
  String out = "";
  if (i < 10) out += "0";
  out += String(i);
  return out;
}

String upTime() {
  String out = "";
  unsigned long up = millis();
  up = up / 1000;
  int d = up / 86400L; // days
  out = niceStr(d) + " d ";
  up = up % 86400;
  d = up / 3600L; // hours
  out += niceStr(d) + " h ";
  up = up % 3600;
  d = up / 60L; // minutes
  out += niceStr(d) + " m ";
  d = up % 60;
  out += niceStr(d) + " s";
  return out;
}

void sendMQTTMessage(String subject, String message) {   //hier könnte der Fehler liegen?
  char payload[100];
  char sub[100];
  message.toCharArray( payload, 100 );
  subject.toCharArray(sub, 100);
  //Serial.print("MQTT-Payload: ");
  //Serial.println(message);
  //Serial.print("MQTT-Subject: ");
  //Serial.println(sub);
  client.publish( sub, payload , true);
}

void connectToWiFi() {
  WiFi.begin(WIFI_AP, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    // Serial.print(".");
  }
  //Serial.println("Connected to AccessPoint");
}

void InitWiFi()
{
  //Serial.println("Connecting to AccessPoint ...");
  // attempt to connect to WiFi network
  IPAddress ip(192, 168, subNetIP, myIP);
  IPAddress gateway(192, 168, subNetIP, 1);
  IPAddress subnet(255, 255, 255, 0);
  IPAddress dns(192, 168, subNetIP, 1);
  WiFi.config(ip, dns, gateway, subnet); // auf feste IP einstellen
  WiFi.hostname(myHostname); //Hostnamen setzen
  WiFi.persistent(false);
  WiFi.mode(WIFI_OFF);
  WiFi.mode(WIFI_STA);
  connectToWiFi();
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    status = WiFi.status();
    if ( status != WL_CONNECTED) {
      connectToWiFi();
    }
    //Serial.print("Connecting to MQTT_Broker ...");
    // Attempt to connect (clientId, username, password)
    if ( client.connect(clientID, TOKEN, NULL) ) {
      //Serial.println( "[DONE]" );
    } else {
      //Serial.print( "[FAILED] [ rc = " );
      //Serial.print( client.state() );
      //Serial.println( " : retrying in 5 seconds]" );
      // Wait 5 seconds before retrying
      delay( 5000 );
    }
  }
}