In meinen Projekten habe ich es mir angewöhnt, einen einheitlichen Inlcude für die MQTT Kommunikation zu verwenden. Zusätzlich überwache ich noch die Spannungsversorgung meiner ESP8266 sowie die WLAN-Signalstärke und sende die Informationen in jeder Meldung an den Host Server gleich mit.
Ich verwende den Include zum Beispiel im Projekt „Wasserzähler Smart Home ESP8266 HMC5883L“
Hauptsächlich beruht mein Include auf dem Projekt „Async MQTT client for ESP8266 and ESP32„.
So binde ich mein Mqtt Include ein
Eingebunden wird die Include-Datei mit:
#include "MqttSetup.h"
So initialisiere ich die Kommunikation mit MQTT
In meiner .ino Datei füge ich unter setup nach dem Öffnen der seriellen Schnittstelle folgende Zeilen hinzu:
void setup() { Serial.begin(115200); setupWifiMqtt(); . . . }
Dabei werden verschiedene Wifi-Handler und Mqtt-Handler initialisiert, die für die Kommunikation mit dem Host notwendig sind. Danach wird die Verbindung zum Host aufgebaut.
Senden einer Message
In meiner Include-Datei sammle ich erst alle Daten, die ich in einer Message zusammenfassen möchte und sende mit einem separaten Aufruf die gesamten Informationen in einem.
Sammeln der Message Inhalte
Über die Funktion buildMqttMessage können Key – Value Paare übergeben werden, die beim späteren Senden zu einer Nachricht zusammengefügt werden.
Hier der Aufruf:
buildMqttMessage("--Your Key--", "--Your Value--" );
Absenden der Message
Das Senden der gesammelten Werte an den Mqtt-Host erfolgt über die Funktion sendMqttMessage. Als Parameter wird die Topic im Datentyp String übergeben.
Für meine Zwecke sende ich drei Information bei jeder Nachricht mit.
- den Wifi Hostnamen
- die Wifi Signalstärke
- die Spannungsversorgung
Die Spannungsversorgung wird nur hinzugefügt, wenn am ESP8266 über ADC0 = A0 Wert > 1 gemessen wird.
sendMqttMessage("your/nice/topic");
Empfangen einer Message (Callback)
Um eine Nachricht zu empfangen und die Include Datei nicht in jedem Projekt anpassen zu müssen, arbeite ich hier mit einer Callback-Funktion. Ich definiere eine Funktion in meiner .ino Datei. Diese gebe ich dann der Include Datei bekannt über die Funktion setWifiMqttMessageCallback. Die von mir definierte Funktion benötigt zwei Parameter vom Typ char* . Darüber erhalte ich später beim Empfangen einer Nachricht zuerst die Topic und dann die Nachricht selbst.
Beispiel Callback für die .ino Datei
In diesem Beispiel registriere ich den ESP8266 für die Topic „your/topic/for/this/“ in der setup Funktion. Die zusätzliche Funktion mySpecialCallback ermöglicht mir dann eine Steuerung je nach empfangener Topic und Message. In diesem Fall schalte ich die LED ein und aus.
void setup() { . . . setupWifiMqtt(); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); subscribeWifiMqtt("your/topic/for/this/"); setWifiMqttMessageCallback( mySpecialCallback ); . . . } void mySpecialCallback( char* messageTopic, char* message ){ Serial.println(messageTopic); if(strcmp(messageTopic, "your/topic/for/this/firstTopic") == 0){ if(strcmp(message, "on") == 0){ digitalWrite(LED_BUILTIN, LOW); } if(strcmp(message, "off") == 0){ digitalWrite(LED_BUILTIN, HIGH); } // other messages } // other topics }
MqttSetup.h
Hier die vollständige Include-Datei:
#ifndef MqttSetup_h #define MqttSetup_h #include "Arduino.h" #include <ESP8266WiFi.h> #include <Ticker.h> #include <AsyncMqttClient.h> #include <ArduinoJson.h> //WIFI configuration #define wifi_ssid "--Your Network SSID--" #define wifi_password "--Your Network Password--" //MQTT configuration #define mqtt_host "--Your Server Host IP--" #define mqtt_port --Your Server Host Port-- #define mqtt_user "--Your Server Host User--" #define mqtt_pass "--Your Server Host Password--" using CallBack = void (*)(char* value, char* value1); CallBack callBack = nullptr; AsyncMqttClient mqttClient; WiFiEventHandler wifiConnectHandler; WiFiEventHandler wifiDisconnectHandler; Ticker mqttReconnectTimer; Ticker wifiReconnectTimer; const int analogInPin = A0; // ESP8266 Analog Pin ADC0 = A0 StaticJsonDocument<200> json; void buildMqttMessage(String key, const char* value){ json[key] = String(value); } void sendMqttMessage(const char* topic){ // MAX 6V // Voltage Devider Vin -> R1 2700 Ohm -> measuring point -> R2 3300 Ohm -> Gnd // 3,3 V at 6 V // 1 Bit => 6.00 / 1023 => 0.0058651 // voltage float sensorVolt = analogRead(analogInPin) ; if(sensorVolt > 1){ sensorVolt = sensorVolt * 0.0058651; if(sensorVolt > 1){ buildMqttMessage("voltage", String( sensorVolt ).c_str() ); } } // hostname buildMqttMessage("hostname", String( WiFi.getHostname()).c_str() ); // rssi buildMqttMessage("rssi", String( WiFi.RSSI() ).c_str()); char buffer[256]; size_t length = serializeJson(json, buffer); if(mqttClient.connected()){ uint16_t packetIdPub1 = mqttClient.publish(topic, 2, true, buffer, length ); Serial.printf("Publishing on topic %s at QoS 2, packetId: %i ", topic, packetIdPub1); Serial.println(); } json.clear(); } void connectToWifi() { delay(10); Serial.print("Connecting to "); Serial.print(wifi_ssid); WiFi.begin(wifi_ssid, wifi_password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } } void connectToMqtt() { Serial.println("Connecting to MQTT..."); mqttClient.connect(); } void onWifiConnect(const WiFiEventStationModeGotIP& event) { Serial.println(); Serial.print("IP-Adresse: "); Serial.println(WiFi.localIP()); Serial.print("MAC-Adresse: "); Serial.println(WiFi.macAddress()); Serial.print("Hostname: "); Serial.println(WiFi.getHostname()); connectToMqtt(); } void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) { Serial.println("Disconnected from Wi-Fi."); mqttReconnectTimer.detach(); wifiReconnectTimer.once(2, connectToWifi); } void onMqttConnect(bool sessionPresent) { Serial.println("Connected to MQTT."); Serial.print("Session present: "); Serial.println(sessionPresent); } void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { Serial.println("Disconnected from MQTT."); if (WiFi.isConnected()) { mqttReconnectTimer.once(2, connectToMqtt); } } void onMqttSubscribe(uint16_t packetId, uint8_t qos) { Serial.println("Subscribe acknowledged."); Serial.print(" packetId: "); Serial.println(packetId); Serial.print(" qos: "); Serial.println(qos); } void onMqttUnsubscribe(uint16_t packetId) { Serial.println("Unsubscribe acknowledged."); Serial.print(" packetId: "); Serial.println(packetId); } void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { payload[len] = '\0'; char* messageReceived = (char*) payload; char* topicReceived = (char*) topic; Serial.println("Publish received."); Serial.print(" topic: "); Serial.println(topic); Serial.print(" qos: "); Serial.println(properties.qos); Serial.print(" dup: "); Serial.println(properties.dup); Serial.print(" retain: "); Serial.println(properties.retain); Serial.print(" len: "); Serial.println(len); Serial.print(" index: "); Serial.println(index); Serial.print(" total: "); Serial.println(total); Serial.print(" Message: "); Serial.println(messageReceived); if(callBack) { callBack( topicReceived, messageReceived ) ; } } void onMqttPublish(uint16_t packetId) { Serial.println("Publish acknowledged."); } void subscribeWifiMqtt(const char* topic){ mqttClient.subscribe(topic, 2); } void setupWifiMqtt(){ wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect); wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect); mqttClient.onConnect(onMqttConnect); mqttClient.onDisconnect(onMqttDisconnect); mqttClient.onSubscribe(onMqttSubscribe); mqttClient.onUnsubscribe(onMqttUnsubscribe); mqttClient.onMessage(onMqttMessage); mqttClient.onPublish(onMqttPublish); mqttClient.setServer(mqtt_host, mqtt_port); mqttClient.setCredentials(mqtt_user, mqtt_pass); connectToWifi(); } void setWifiMqttMessageCallback(CallBack tmp_callBack){ callBack = tmp_callBack; } #endif