NEWS
CAN-BUS Interface ESP32 > MQTT und Stiebel Eltron WP steuern
-
Ich habe für die Bauteile mal ein Gehäuse designed.
Die STL files findet Ihr hier: https://www.thingiverse.com/thing:6796812 -
ich verfolge nun das System seit geraumer Zeit. Leider hat sich gezeigt, dass so nach 2-3 Tagen der ESP instabil wird. Es kommen dann zwar noch Daten im ioBroker an aber nicht mehr unter pload.
Als workaround habe ich nun erst einmal einen reset eingebaut, der den ESP nach 12 Stunden neu startet. Da das offensichtlich sporadisch geschieht dürfte es schwer sein, dies zu debuggen.
Dazu muss ich das System laufen lassen und sehen was da genau geschieht und selbst dann ist noch nicht sicher ob man es herausfindet.
Ob der workaround auch einer ist kann ich noch nicht sagen, da ich das erst gestern festgestellt habe.
Mal sehen ob ich das hinbekomme.
Hilfe gerne willkommen. Skript habt Ihr ja. -
bei mir läuft der Sniffer nun seit ein paar Wochen. ICh denke ich habe ein ähnliches PRoblem wie Du und von Zeit zu Zeit hängt sich das System auf. Ich habe nun mal die Buffergröße verändert und (Daumen drücken) seit 2 Tagen alles ok. Hast Du das Problem gelöst ?
Die Buffergröße scheint es zu sein. Ich beobachte das nun noch ein wenig und dann poste ich mal meine Firmware.
-
@randyandy sagte in CAN-BUS Interface ESP32 > MQTT und Stiebel Eltron WP steuern:
bei mir läuft der Sniffer nun seit ein paar Wochen. ICh denke ich habe ein ähnliches PRoblem wie Du und von Zeit zu Zeit hängt sich das System auf. Ich habe nun mal die Buffergröße verändert und (Daumen drücken) seit 2 Tagen alles ok. Hast Du das Problem gelöst ?
Die Buffergröße scheint es zu sein. Ich beobachte das nun noch ein wenig und dann poste ich mal meine Firmware.
Hier noch die letzte Firmware. Läuft nun seit Tagen ohne Probleme.
#include <Arduino.h> #include <mcp2515.h> #include <WiFi.h> #include <ArduinoOTA.h> #include <PubSubClient.h> #include <ArduinoJson.h> const char* ssid = "..."; // Ersetze mit deinem WiFi-Namen const char* password = "..."; // Ersetze mit deinem WiFi-Passwort const char* mqtt_server = "..."; // Dein MQTT Broker Server const int mqtt_port = ...; const char* mqtt_user = "..."; const char* mqtt_password = "..."; const char* mqtt_topic = "..."; void(* resetFunc) (void) = 0; // Timer declare hw_timer_t * timer = NULL; volatile SemaphoreHandle_t timerSemaphore; portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; volatile uint32_t isrCounter = 0; volatile uint32_t lastIsrAt = 0; void ARDUINO_ISR_ATTR onTimer(){ // Increment the counter and set the time of ISR portENTER_CRITICAL_ISR(&timerMux); isrCounter = isrCounter + 1; lastIsrAt = millis(); portEXIT_CRITICAL_ISR(&timerMux); // Give a semaphore that we can check in the loop xSemaphoreGiveFromISR(timerSemaphore, NULL); // It is safe to use digitalRead/Write here if you want to toggle an output } WiFiClient espClient; PubSubClient client(espClient); MCP2515 mcp2515(5); // Der CS-Pin muss entsprechend deiner Schaltung angepasst werden. // Diese Funktion wird aufgerufen, wenn eine Nachricht auf einem abonnierten Thema ankommt void callback(char* topic, byte* payload, unsigned int length) { Serial.println("Callback aufgerufen: " + String(topic)); char canSendTopic[128]; //War vorher 64 snprintf(canSendTopic, sizeof(canSendTopic), "%s/canRawGesendet", mqtt_topic); String topicString = String(topic); // Überprüfe, ob das Topic stimmt if (topicString.equals(String(mqtt_topic) + "/canSend")) { // Konvertiere payload in einen String zur Verarbeitung String payloadString; for (int i = 0; i < length; i++) { payloadString += (char)payload[i]; } if (length == 0 || payloadString == "0" || payloadString == "OK" || payloadString == "INIT" ) { Serial.println("Leere Nachricht "); return; } // Parse die JSON-Nachricht StaticJsonDocument<200> doc; DeserializationError error = deserializeJson(doc, payloadString); if (error || !doc.is<JsonObject>()) { Serial.println("Fehler beim Parsen von JSON"); client.publish(canSendTopic, ("JSON PARS ERROR: " + payloadString).c_str()); return; } String tempDataString = doc["Data"].as<String>(); // Konvertiert den Wert zu einem String tempDataString.replace(" ", ""); // Entfernt alle Leerzeichen doc["Data"] = tempDataString.c_str(); // Speichert den geänderten Wert zurück im JSON-Objekt // Extrahiere ID und Daten aus dem JSON const char* idString = doc["ID"]; const char* dataString = doc["Data"]; // Umwandeln der ID in einen Integer uint16_t id = strtol(idString, NULL, 16); // Umwandeln des Datenstrings in ein Byte-Array uint8_t data[10]; size_t dataLength = strlen(dataString) / 2; for (size_t i = 0; i < dataLength; i++) { char byteString[] = {dataString[i * 2], dataString[i * 2 + 1], 0}; data[i] = strtol(byteString, NULL, 16); } // Erstelle CAN-Nachricht und sende sie can_frame canMsg; canMsg.can_id = id; canMsg.can_dlc = dataLength; memcpy(canMsg.data, data, dataLength); // Erstelle einen String, um die Hex-Darstellung zu speichern char msgString[35]; // Länge = Anzahl der Bytes * 2 (für Hex) + 1 (für '\0') // Konvertiere jeden Byte der Daten in einen Hex-String for (int i = 0; i < canMsg.can_dlc; i++) { sprintf(&msgString[i * 2], "%02X", canMsg.data[i]); } // Sende CAN-Nachricht if (mcp2515.sendMessage(&canMsg) != MCP2515::ERROR_OK) { Serial.println("Fehler beim Senden der CAN-Nachricht"); client.loop(); delay(100); client.publish(canSendTopic, "SEND ERROR"); // Initialisiere den MCP2515 CAN Controller neu mcp2515.reset(); mcp2515.setBitrate(CAN_20KBPS, MCP_8MHZ); // Setze die Masken und Filter mcp2515.setFilterMask(MCP2515::MASK0, true, 0x000); // Maske 0 auf 0 setzen (alle Nachrichten akzeptieren) mcp2515.setFilterMask(MCP2515::MASK1, true, 0x000); // Maske 1 auf 0 setzen (alle Nachrichten akzeptieren) // Setze alle Filter auf 0, um alle Nachrichten zu akzeptieren //for (int filter = 0; filter < 6; filter++) { //mcp2515.setFilter((MCP2515::RXF)filter, true, 0x000); //} mcp2515.setNormalMode(); } else { // Gib den Hex-String aus Serial.print("Raw CAN Data: "); Serial.println(msgString); client.publish(canSendTopic, msgString); // Sende die Daten zum MQTT-Broker client.loop(); Serial.println("Erfolgreich gesendet"); client.publish(topicString.c_str(), "OK", false); } } else { Serial.println("Falsches Topic"); return; } } void setup() { // Timer Setup timerSemaphore = xSemaphoreCreateBinary(); // Create semaphore to inform us when the timer has fired timer = timerBegin(1000000); // Set timer frequency to 1Mhz = 1µs timerAttachInterrupt(timer, &onTimer); // Attach onTimer function to our timer. timerAlarm(timer, 1000000, true, 0); // Set alarm to call onTimer function every second (value in microseconds). Repeat the alarm (third parameter) with unlimited count = 0 (fourth parameter). // Initialisiere die serielle Kommunikation Serial.begin(115200); pinMode(2, OUTPUT); // Setze GPIO 26 als Ausgang für die LED // Warte auf die serielle Verbindung, falls nötig while (!Serial) { ; // warte auf die Verbindung der seriellen Schnittstelle } // Verbinde mit WiFi-Netzwerk WiFi.begin(ssid, password); Serial.print("Verbinde mit WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nWiFi verbunden!"); Serial.print("IP-Adresse: "); Serial.println(WiFi.localIP()); connectMQTT(); // Initialisiere den MCP2515 CAN Controller mcp2515.reset(); mcp2515.setBitrate(CAN_20KBPS, MCP_8MHZ); // Setze die Masken und Filter mcp2515.setFilterMask(MCP2515::MASK0, true, 0x000); // Maske 0 auf 0 setzen (alle Nachrichten akzeptieren) mcp2515.setFilterMask(MCP2515::MASK1, true, 0x000); // Maske 1 auf 0 setzen (alle Nachrichten akzeptieren) // Setze alle Filter auf 0, um alle Nachrichten zu akzeptieren //for (int filter = 0; filter < 6; filter++) { //mcp2515.setFilter((MCP2515::RXF)filter, true, 0x000); //} mcp2515.setNormalMode(); Serial.println("CAN-Bus Monitor gestartet!"); //Starte OTA ArduinoOTA.setHostname("esp32-ota"); ArduinoOTA.setPassword("..."); //Hier das Passowrd für OTA setzen ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) { type = "sketch"; } else { // U_SPIFFS type = "filesystem"; } // Hinweis: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() Serial.println("Start updating " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) { Serial.println("Auth Failed"); } else if (error == OTA_BEGIN_ERROR) { Serial.println("Begin Failed"); } else if (error == OTA_CONNECT_ERROR) { Serial.println("Connect Failed"); } else if (error == OTA_RECEIVE_ERROR) { Serial.println("Receive Failed"); } else if (error == OTA_END_ERROR) { Serial.println("End Failed"); } }); ArduinoOTA.begin(); } void loop() { static unsigned long lastMillis = 0; char aliveTopic[64]; char timestampString[32]; // Genug Platz für die Darstellung des Zeitstempels connectMQTT(); if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){ uint32_t isrCount = 0, isrTime = 0; // Read the interrupt count and time portENTER_CRITICAL(&timerMux); isrCount = isrCounter; isrTime = lastIsrAt; portEXIT_CRITICAL(&timerMux); // Print it Serial.print("onTimer no. "); Serial.print(isrCount); Serial.print(" at "); Serial.print(isrTime); Serial.println(" ms"); if (isrTime > 1000 * 60 * 60 * 12) { resetFunc(); } } // Sende alle 5 Sekunden eine Nachricht an das Thema "alive" if (millis() - lastMillis > 5000) { lastMillis = millis(); snprintf(aliveTopic, sizeof(aliveTopic), "%s/alive", mqtt_topic); // Kombiniere das Hauptthema mit "/alive" snprintf(timestampString, sizeof(timestampString), "%lu", millis()); // Konvertiere den Zeitstempel in einen String client.publish(aliveTopic, timestampString); // Sende das Zeichen "!" an das Unterthema "alive" Serial.println("Alive-Nachricht gesendet!"); digitalWrite(2, HIGH); // LED einschalten //delay(10); // Kurz warten digitalWrite(2, LOW); // LED ausschalten Serial.println(timestampString); } can_frame canMsg; if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) { digitalWrite(2, HIGH); // LED einschalten delay(100); // Kurz warten digitalWrite(2, LOW); // LED ausschalten char msgString[128]; // Ein Array, um die Daten zu speichern sprintf(msgString, "{\"ID\": \"0x%03X\", \"Len\": \"%1d\", \"Data\": \"", canMsg.can_id, canMsg.can_dlc); for (int i = 0; i < canMsg.can_dlc; i++) { sprintf(msgString + strlen(msgString), "%02X ", canMsg.data[i]); } sprintf(msgString + strlen(msgString) - 1, "\"}"); snprintf(aliveTopic, sizeof(aliveTopic), "%s/pload", mqtt_topic); // Kombiniere das Hauptthema mit "/alive" client.publish(aliveTopic, msgString); // Sende die Daten zum MQTT-Broker Serial.println(msgString); } // Kurze Verzögerung, um den CAN-Bus nicht zu überlasten //Serial.print("."); //delay(10); ArduinoOTA.handle(); client.loop(); } void connectMQTT() { // Verbinde mit MQTT Broker while (!client.connected()) { client.setServer(mqtt_server, mqtt_port); Serial.print("Verbinde mit MQTT..."); if (client.connect("CAN_MQTT_Client", mqtt_user, mqtt_password)) { Serial.println("verbunden"); // Setze MQTT-Callback-Funktion client.setCallback(callback); // Erstelle das Topic für das Senden von CAN-Nachrichten char canSendTopic[64]; snprintf(canSendTopic, sizeof(canSendTopic), "%s/canSend", mqtt_topic); client.publish(canSendTopic, "INIT"); // Sende die Daten zum MQTT-Broker delay(200); Serial.print("Abonniere Topic: "); Serial.println(canSendTopic); if (client.subscribe(canSendTopic)) { Serial.println("Abonnement erfolgreich!"); } else { Serial.println("Abonnement fehlgeschlagen!"); } delay(200); } else { Serial.print("Fehler, rc="); Serial.print(client.state()); Serial.println(" Versuche es erneut in 5 Sekunden"); delay(5000); } } };
Ich habe im Übrigen noch einen timer eingebaut, der nach 12 Stunden den ESP32 resettet.
War die Übergangslösung die aber keine war. Ich gehe davon aus, dass man dies abschalten kann.
Auf der anderen Seite ein Softreset alle 12 Stunden kann nicht schaden.Was aber bleibt ist die Fehlermeldungen im Javascript (füllen halt das log, aber das Skript läuft prinzipiell). Ich bin mir sicher, dass es sich dabei um ein nicht definiertes Objekt handelt. Ich find aber leider nicht in welchem Bereich der Fehler ausgelöst wird. Da ich nun nicht wirklich der Javaskript Guru bin vielleicht kann sich das ein Experte mal ansehen.
-
@waly_de ich wäre interessiert, zumindest bis zu MQTT :). Auch die WP13 im Einsatz.
-
Hallo, würde dann eine LWZ304 Stiebel Eltron sich damit ansteuern lassen?
Welche aktuelle Hardware sollte man dazu nun am besten nehmen? Danke im Voraus Holli -
@holli-0 ich kann mir vorstellen, dass die den gleichen CAN Bus nutzen.
Als Hardware ist nach meiner Recherche aktuell
ESP32 und MCP2515 CAN-Bus Modul empfehlenswert. -
Tach Zusammen !!
..bin neu hier und duch Zufall auf das für mich hochinteressante Thema gestossen. ( Vielen Dank an waly_de )
..bei mir läuft eine Stiebel-Eltron WPL 09 ACS Classic draussen + das Teil innen nennt sich HM Trend VM3 mit einem WPM3 verbaut.
Das Teil hat intern NUR EINEN CAN-Bus Anschluß, an dem alles parallel aufgelegt ist.
Frage: Kann das CAN-BUS-Interface einfach dort mit aufgelegt werden ??
..und WP vorher stromlos schalten oder geht das im laufenden Betrieb ??
Besten Dank schon mal für Eure Tipps !! -
Moin zusammen,
habe das Sketch auf dem ESP32 bekommen. Aber mit scheinen die Daten nicht richtig zu sein.
Bei mir ist eine Tecalor 5.5 eco verbaut.
Vllt habt ja eine idee.
Danke
-
@hugo1217 Ich habe die gleiche LWWP, meinen letzten Stand findest du hier:
https://forum.iobroker.net/topic/70215/can-bus-interface-esp32-mqtt-und-stiebel-eltron-wp-steuern/34Ich wäre auch für Hilfe dankbar.
-
Hey hey. Ich möchte ein interface bauen mit dem ich sensordaten (temperatur und feuchtigkeit) mit einem esp32 erfassen und diese per can bus an mein WPM sende und so tue als wäre ich eine Fernbedienung FET damit ich die kühlfunktion verwenden kann.
Hier meine Hardware:- ESP 32
- DHT22 AM2302 Temperatursensor und Luftfeuchtigkeitssensor
- MCP2515 CAN Bus Shield
Ich weiß irgendwie nicht genau wie ich anfangen soll. Freue mich über Tips
LG Laurin
-
Hallo zusammen,
zuerst einmal möchte ich mich herzlich bei allen hier im Forum bedanken! Ohne die vielen hilfreichen Beiträge hätte ich es wohl nie geschafft, das System zum Laufen zu bringen.
Ich hatte das Projekt fast ein Jahr ruhen lassen, da ich es einfach nicht zum Laufen bekommen habe und irgendwann auch keine Zeit mehr dafür hatte. Über die Feiertage habe ich mich jedoch erneut daran gewagt – mit Erfolg! !
Das Problem, dass mein Netzwerk immer abgebrochen ist und somit auch die Verbindung zum MQTT-Server verloren ging, konnte ich nun endlich lösen. Der ESP32 in Kombination mit dem MCP2525 hat über einen USB-Plug einfach nicht genug Spannung/Strom bekommen. Am Laptop über die USB-Schnittstelle funktionierte es, aber mit keinem der vier getesteten USB-Plugs. Erst als ich eine Steckdose mit USB-Schnittstelle verwendet habe, lief es endlich stabil.
Jetzt werden die Daten unter 0_userdata angezeigt, und ich bin echt happy! Allerdings fehlen mir noch ein paar Datenpunkte, und hier hoffe ich auf eure Unterstützung:
1. Warmwasser starten und stoppen
• Ist das möglicherweise der Datenpunkt „Betriebsart_WP Wert 4“?
2. Warmwasser Soll-Temperaturen (Tag/Nacht)
• Diese Werte werden aktuell nicht angezeigt. Weiß jemand, wie ich diese einbinden kann?
3. Ferienparameter
• Auch diese werden nicht angezeigt. Gibt es hier vielleicht einen Trick, wie ich sie sichtbar machen kann?Mein Ziel ist es, PV-optimiertes Laden umzusetzen (Punkt 3 spielt keine Rolle dafür), daher wären diese Datenpunkte echt wichtig.
Vielen Dank schon mal für eure Hilfe.
-
@dtopic Hallo,
das hört sich super an. Du hast aber nicht die Tecalor 5.5 Eco??
Wie ist der anschluss bei deiner?? Aus dem Automobilsektor kenne ich es so das am ende ein Endwiederstand wieder drauf muss.
Bei mir kommen Irgendwelche daten aber glaube nicht das richtige. Wie bekommt man das ganze Richtig ausgelesen??Gruß
-
@hugo1217
Hi,ich habe eine Stiebel wp18e. Habe mich an die Anleitungen von Waley gehalten und die beiden Scripte aus diesem Forumsbeitrag genutzt. Das JavaScript muss bei IoBroker eingespielt werden. Dieses entschlüsselt die die Canbus Daten, die vorher an den mqtt Server verschickt werden, in eine lesbare Variante. Die ElsterTable.inc Datei muss vorher als Datei abgelegt sein, damit daraus die Daten interpretiert werden. Eigentlich habe ich alles so gemacht wie es zuvor beschrieben wurde.
Grüße
-
@rushmed leider ist das auch mein Stand.
Anbei ein kleines video welche daten gesendet werden.
Leider kann ich diese auch nicht nachvollziehen. Sobal ich das Script starte kommen jedemenge fehlermeldungen im Script. Und es werden jedemenge Datenpunkte angelegt.Ist das bei dir auch so??
-
@leitwolf said in CAN-BUS Interface ESP32 > MQTT und Stiebel Eltron WP steuern:
Problem gefunden. war eine falsche mcp2515.h. Ausgetauscht und es funzt.
Wo finde ich denn die richtige mcp2515.h
Als Hardware habe ich einen ESP32 D1 Mini und AZDelivery MCP2515 CAN Bus Shield
Danke euch & guten Rutsch
Marcus