Forum: Haus & Smart Home Modbus TCP vs. MQTT auf ESP32


von Frank (Gast)


Lesenswert?

Hallo,
ich bastel gerade etwas auf einem ESP32 und IOBroker mit Sensordaten. 
Aktuell läuft es da über MQTT, aber viele Wechselrichter und Smartmeter 
arbeiten ja mit Modbus TCP, wird ja auch nen Grund haben. Was ist den 
von der Performance her "effektiver", oder das schnellere Protokoll um 
kontinuierlich und häufig einen Datensatz zu verschicken. Also welche 
benötigt auf dem ESP32 weniger recoursen? MQTT war jetzt mit 
"boardmitteln" schnell am laufen, bei Modbus TCP habe ich nur das 
gefunden https://github.com/eModbus/eModbus...

Grüße...

von Benedikt L. (Firma: Dem Ben seine Leiche) (dembenseineleiche) Flattr this


Lesenswert?

MQTT wurde für was ganz großes entwickelt. Das solltest du nutzen!

https://en.wikipedia.org/wiki/MQTT

von Εrnst B. (ernst)


Lesenswert?

Frank schrieb:
> Also welche
> benötigt auf dem ESP32 weniger recoursen?

Warum sollte das wichtig sein? Der ESP32 hat so unfassbar viel Reserven, 
da kannst du haufenweise Modbus-TCP und MQTT-Verbindungen gleichzeitig 
benutzen, und noch zusätzlich einen HTTP-Webserver mit Templating + 
Websocket laufen lassen, ohne den auch nur ansatzweise ins Schwitzen zu 
kriegen.

von Chris K. (kathe)


Lesenswert?

Was ist einfacher viele einzelne Modbus Clients abfragen oder die 
Clients melden selber an einen zentralen Punkt?

Bleib bei MQTT denn das ist dafür ausgelegt.
Die paar modbus Clients die z.B. deine Wechselrichter sind kannst du mit 
einer Modbus - MQTT bridge mit nem ESP erledigen. Tasmota kann das auch.

von Frank (Gast)


Angehängte Dateien:

Lesenswert?

Es ging mir nicht um "einfacher" sondern um die Performance... 
eigentlich auch unabhängig vom ESP32. Nehmen wir an ich will ~50 
Datensätze oder mehr übertragen wie beim Wechselrichter. Ist dann Modbus 
TCP schneller, oder MQTT. Hängt ja vom Protokoll ab und wie in meinem µC 
die Daten aufarbeiten werden müssen. Bei MQTT ist bei mir so bei ~250ms 
Sendeintervall "ende" wobei ich das auch mal mit mehreren Werten testen 
muss... dann fängt der Client sich wohl an zu verschlucken. Liegt sicher 
auch an WLan Latenzen und so...
Die Werte sind die Millisekunden zwischen zwei Nachrichten...
1
#include <WiFi.h>
2
#include <PubSubClient.h>
3
4
// WiFi
5
const char *ssid = ""; // Enter your WiFi name
6
const char *password = "";  // Enter WiFi password
7
8
// MQTT Broker
9
const char *mqtt_broker = "192.168.178.12";
10
const char *topic = "esp32/test";
11
const int mqtt_port = 1883;
12
13
WiFiClient espClient;
14
PubSubClient client(espClient);
15
unsigned long last_msg;
16
17
void setup() {
18
 // Set software serial baud to 115200;
19
 Serial.begin(115200);
20
 // connecting to a WiFi network
21
 WiFi.begin(ssid, password);
22
 while (WiFi.status() != WL_CONNECTED) {
23
     delay(500);
24
     Serial.println("Connecting to WiFi..");
25
 }
26
 Serial.println("Connected to the WiFi network");
27
 //connecting to a mqtt broker
28
 client.setServer(mqtt_broker, mqtt_port);
29
 client.setCallback(callback);
30
31
  while (!client.connected())
32
  {
33
    Serial.print("Attempting MQTT connection...");
34
    // Attempt to connect
35
    if (client.connect("DummyESP32"))
36
    {
37
      Serial.println("connected");
38
    }
39
    else
40
    {
41
      Serial.print("failed, rc=");
42
      Serial.print(client.state());
43
      Serial.println(" try again in 5 seconds");
44
      // Wait 5 seconds before retrying
45
      delay(5000);
46
    }
47
  }
48
49
 // publish and subscribe
50
 client.subscribe(topic);
51
}
52
53
void callback(char *topic, byte *message, unsigned int length) {
54
55
  String messageTemp;
56
57
 for (int i = 0; i < length; i++) {
58
      messageTemp += (char)message[i];
59
 }
60
61
  Serial.println( (millis() - last_msg) );
62
  last_msg = millis();
63
 
64
}
65
66
void loop() {
67
 client.loop();
68
}

von Εrnst B. (ernst)


Lesenswert?

Frank schrieb:
> for (int i = 0; i < length; i++) {
>       messageTemp += (char)message[i];
>  }

Ehrlich?

von Frank (Gast)


Lesenswert?

Ja ehrlich... So zumindest in vielen, oder allen Tutorials die auf der 
Pubsub lib beruhen? Aber ich stecke da nicht so tief drin, als das ich 
eine entsprechende lib optimieren könnte. Man freut sich sicher über 
andere Ansätze.

von Chris K. (kathe)


Lesenswert?

Frank schrieb:
> Smartmeter
> arbeiten ja mit Modbus TCP, wird ja auch nen Grund haben.

Der Grund ist historisch und der das mehrere Geräte an einem Bus hängen 
können.
Aber bei Modbus sendest du eine Anfrage auf den Bus und musst hoffen der 
Client hat mitgehört und dann Antwortet er hoffentlich, in der Zeit 
musst du mithorchen und hoffen er Antwortet in dem gewissen Zeitrahmen. 
In dieser Zeit kannst du nichts anderes machen als warten auf Antwort.
Ließ dir mal die Modbus spec durch


Nimm MQTT. Da feuerst du die kleine Message an den Server so schnell 
dein ESP den Sensor auswerten kann und dein Netzwerk dies zulässt.
Was aber oft keinen Sinn macht weil sich der Wert meistens nicht so 
schnell ändert. Dich interessiert ja nur wenn sich der Wert ändert.

von Klaus S. (kseege)


Lesenswert?

Frank schrieb:
> Was ist den
> von der Performance her "effektiver"

Das hängt in hohem Maße von der Anwendung ab.

Bei MQTT wartet die Zentrale (vulgo:Host) und die vielen kleinen 
Arbeitsbienen (vulgo:Slaves) schicken von sich aus etwas, wenn sich was 
ändert.

Bei Modbus ist es umgekehrt. Die Zentrale muß ständig Meßergebnisse 
abfragen, um Änderungen zu erkennen.

Daher ist MQTT im Vorteil, wenn sich nur selten etwas ändert. Modbus hat 
die Nase vorn, wenn sich viel ändert, da es schlanker ist.

Just my 2 cents

von Εrnst B. (ernst)


Lesenswert?

Frank schrieb:
> Ja ehrlich... So zumindest in vielen, oder allen Tutorials die auf der
> Pubsub lib beruhen?

Da ist dann ein wenig Grundlagenwissen über die Programmiersprache und 
die Libraries von Vorteil.
Die Original-Beispiele machen das übrigens nicht so. Die haben zwar auch 
diese Schleife über "message", schieben das aber Buchstabenweise über 
die Serielle Schnittstelle raus, d.H. da wird kein String 
zusammengesetzt.
Irgendjemand hat dann wohl mal das Serial.print(char) durch den 
String-append ersetzt, sich nichts dabei gedacht, und das wurde dann 
x-mal im Internet rumkopiert.

> Aber ich stecke da nicht so tief drin, als das ich
> eine entsprechende lib optimieren könnte. Man freut sich sicher über
> andere Ansätze.

Das Problem ist, dass der String bei jedem Anhängen eines Buchstaben 
verlängert wird, und dabei potentiell neuen Speicher anfordert, und 
dabei erstmal alles umkopieren muss.
Ergibt damit quadratische Komplexität.
Am PC (C++, std::string) umgeht man das indem man einfach 
verschwenderisch mit dem Speicher umgeht, und die reservierte 
Speichergröße jedesmal verdoppelt.
Ergibt dann "amortised constant time" für das append.
Am µC ist das nicht so implementiert, da ist der Speicher knapp.

Verbesserung:
Vor der for-Schleife einmal mit
 messageTemp.reserve(length)
den nötigen Speicherplatz vorab reservieren.

Oder statt der Schleife einfach mit
  messageTemp.concat(message, length)
die gesamte Payload auf einmal in den String schieben.

von Frank (Gast)


Lesenswert?

Danke für den Input! Ich schaue mir das mal an...
1
void callback(char *topic, byte *message, unsigned int length) {
2
 
3
  String messageTemp = String((char*)message, length);
4
  Serial.println(messageTemp);
5
  
6
}

wäre das auch eine Variante? Ich denke der Artikel beschreibt die 
Problematik?

https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.