ESP8266 EPEVER Laderegler Modbus Problem

Hallo.

Gerne würde ich einen EPEVER Solarladeregler auslesen. Verwendet wird ein RS458 zu TTL Converter (mit RX/TX Pins). Der originale Code war für den ESP32 gedacht und scheint auf solchem zu funktionieren. Nach der Anforderung kommen Antworten vom Laderegler. Allerdings werden hier RX2 und TX2 genutzt.
Portiert auf den ESP8266 funktioniert es aber nicht mehr. Es werden Daten gesendet, der Laderegler antwortet nicht.
Kann es sein dass hier der serielle Port irgendwie falsch konfiguriert ist?

Hier der Original Code

#include <ModbusMaster.h>

#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))

float battChargeCurrent, battDischargeCurrent, battOverallCurrent, battChargePower;
float bvoltage, ctemp, btemp, bSOC, lpower, lcurrent, pvvoltage, pvcurrent, pvpower;
float stats_today_pv_volt_min, stats_today_pv_volt_max;
uint8_t result;
unsigned long previousMillis = 0;

ModbusMaster node;

void preTransmission() {
}
void postTransmission() {
}

// A list of the regisities to query in order
typedef void (*RegistryList[])();

RegistryList Registries = {
  AddressRegistry_3100,
  AddressRegistry_3106,
  AddressRegistry_310D,
  AddressRegistry_311A,
  AddressRegistry_331B,
};

// keep log of where we are
uint8_t currentRegistryNumber = 0;

// function to switch to next registry
void nextRegistryNumber() {
  currentRegistryNumber++;
  if (currentRegistryNumber >= ARRAY_SIZE(Registries)) {
    currentRegistryNumber = 0;
  }
}

// exec a function of registry read (cycles between different addresses)
void executeCurrentRegistryFunction() {
  Registries[currentRegistryNumber]();
}

void AddressRegistry_3100() {
  result = node.readInputRegisters(0x3100, 6);

  if (result == node.ku8MBSuccess) {
    pvvoltage = node.getResponseBuffer(0x00) / 100.0f;
    pvcurrent = node.getResponseBuffer(0x01) / 100.0f;
    pvpower = (node.getResponseBuffer(0x02) | node.getResponseBuffer(0x03) << 16) / 100.0f;
    bvoltage = node.getResponseBuffer(0x04) / 100.0f;
    battChargeCurrent = node.getResponseBuffer(0x05) / 100.0f;
  }
}

void AddressRegistry_3106() {
  result = node.readInputRegisters(0x3106, 2);

  if (result == node.ku8MBSuccess) {
    battChargePower = (node.getResponseBuffer(0x00) | node.getResponseBuffer(0x01) << 16)  / 100.0f;
  }
}

void AddressRegistry_310D() {
  result = node.readInputRegisters(0x310D, 3);

  if (result == node.ku8MBSuccess) {
    lcurrent = node.getResponseBuffer(0x00) / 100.0f;
    lpower = (node.getResponseBuffer(0x01) | node.getResponseBuffer(0x02) << 16) / 100.0f;
  }
}

void AddressRegistry_311A() {
  result = node.readInputRegisters(0x311A, 2);

  if (result == node.ku8MBSuccess) {
    bSOC = node.getResponseBuffer(0x00) / 1.0f;
    btemp = node.getResponseBuffer(0x01) / 100.0f;
  }
}

void AddressRegistry_331B() {
  result = node.readInputRegisters(0x331B, 2);

  if (result == node.ku8MBSuccess) {
    battOverallCurrent = (node.getResponseBuffer(0x00) | node.getResponseBuffer(0x01) << 16) / 100.0f;
  }
}

void setup() {
  Serial.begin(115200);
  // Modbus slave ID 1
  node.begin(1, Serial);

  // callbacks to toggle DE + RE on MAX485
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}

void loop() {
  unsigned long currentMillis = millis();
  const long interval = 5000;
  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;

    executeCurrentRegistryFunction();
    nextRegistryNumber();
  }
}

bitte zeichne einen Schaltplan esp + max + Solarregler.
insbesondere wie du den Max ansteuerst - da preTransmission/postTransmission komplett leer gelassen wurden.
und auch Bilder - sodass jedes Kabel eindeutig zuordenbar ist

weiters, was möchtest du überhaupt sehen? du hast kein Webinterface, keine Serielle Ausgabe ... also wie stellst du überhaupt fest dass du Werte gelesen (oder eben nicht gelesen) hast?

Hier der Link zum Anschlussplan

Hallo. Ich habe den Converter so angeschlossen wie hier auf github zu sehen, jedoch beim ESP8266 natürlich an RX/TX. Mit dem ESP32 funktioniert das an RX2/TX2 mit dem originalen Code oben von github. Daten werden gelesen. Mit dem ESP8266 nicht obwohl ich die serielle Schnittstelle entsprechend umbenannt habe.

Mein kompletter Code verwendet WiFi und sendet die Daten direkt an ThingSpeak sobald alle 5 Register gelesen wurden. Das funktioniert auch. Jedoch wird bei allen 8 Werten der Register welche ich mir herausgesucht habe immer eine Null gesendet.

Nun hier doch einmal der komplette Code:

#include <ModbusMaster.h>
#include <ESP8266WiFi.h>
#include "ThingSpeak.h"

#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
#define LED LED_BUILTIN

float battChargeCurrent, battDischargeCurrent, battOverallCurrent, battChargePower;
float bvoltage, ctemp, btemp, bSOC, lpower, lcurrent, pvvoltage, pvcurrent, pvpower;
float stats_today_pv_volt_min, stats_today_pv_volt_max;
uint8_t result;
int ledState = LOW;
unsigned long previousMillis = 0;
unsigned long myChannelNumber = XXXXXXXXXX;
const char * myWriteAPIKey = "XXXXXXXXXX";
//const char* ssid = "XXXXXXXXXX";
//const char* password = "XXXXXXXXXX";
const char* ssid = "XXXXXXXXXX";
const char* password = "XXXXXXXXXX";

ModbusMaster node;
WiFiClient client;

void preTransmission() {
}
void postTransmission() {
}

// A list of the regisities to query in order
typedef void (*RegistryList[])();

RegistryList Registries = {
  AddressRegistry_3100,
  AddressRegistry_3106,
  AddressRegistry_310D,
  AddressRegistry_311A,
  AddressRegistry_331B,
};

// keep log of where we are
uint8_t currentRegistryNumber = 0;

// function to switch to next registry
void nextRegistryNumber() {
  currentRegistryNumber++;
  if (currentRegistryNumber >= ARRAY_SIZE(Registries)) {
    ThingSpeak.setField(1, pvvoltage);
    ThingSpeak.setField(2, pvcurrent);
    ThingSpeak.setField(3, pvpower);
    ThingSpeak.setField(4, bvoltage);
    ThingSpeak.setField(5, battChargeCurrent);
    ThingSpeak.setField(6, battChargePower);
    ThingSpeak.setField(7, bSOC);
    ThingSpeak.setField(8, ctemp);
    ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
    currentRegistryNumber = 0;
  }
}

// exec a function of registry read (cycles between different addresses)
void executeCurrentRegistryFunction() {
  Registries[currentRegistryNumber]();
}

void AddressRegistry_3100() {
  result = node.readInputRegisters(0x3100, 6);

  if (result == node.ku8MBSuccess) {
    pvvoltage = node.getResponseBuffer(0x00) / 100.0f;
    pvcurrent = node.getResponseBuffer(0x01) / 100.0f;
    pvpower = (node.getResponseBuffer(0x02) | node.getResponseBuffer(0x03) << 16) / 100.0f;
    bvoltage = node.getResponseBuffer(0x04) / 100.0f;
    battChargeCurrent = node.getResponseBuffer(0x05) / 100.0f;
  }
}

void AddressRegistry_3106() {
  result = node.readInputRegisters(0x3106, 2);

  if (result == node.ku8MBSuccess) {
    battChargePower = (node.getResponseBuffer(0x00) | node.getResponseBuffer(0x01) << 16)  / 100.0f;
  }
}

void AddressRegistry_310D() {
  result = node.readInputRegisters(0x310D, 3);

  if (result == node.ku8MBSuccess) {
    lcurrent = node.getResponseBuffer(0x00) / 100.0f;
    lpower = (node.getResponseBuffer(0x01) | node.getResponseBuffer(0x02) << 16) / 100.0f;
  }
}

void AddressRegistry_311A() {
  result = node.readInputRegisters(0x311A, 2);

  if (result == node.ku8MBSuccess) {
    bSOC = node.getResponseBuffer(0x00) / 1.0f;
    btemp = node.getResponseBuffer(0x01) / 100.0f;
  }
}

void AddressRegistry_331B() {
  result = node.readInputRegisters(0x331B, 2);

  if (result == node.ku8MBSuccess) {
    battOverallCurrent = (node.getResponseBuffer(0x00) | node.getResponseBuffer(0x01) << 16) / 100.0f;
  }
}

void setup() {
  Serial.begin(115200);
  // Modbus slave ID 1
  node.begin(1, Serial);

  // callbacks to toggle DE + RE on MAX485
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  pinMode(LED, OUTPUT);

  WiFi.mode(WIFI_STA);
  ThingSpeak.begin(client);  // Initialize ThingSpeak
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    while (WiFi.status() != WL_CONNECTED) {
      ledState = LOW;
      digitalWrite(LED, ledState);
      WiFi.begin(ssid, password);
      delay(5000);
    }
  }
  unsigned long currentMillis = millis();
  const long interval = 5000;
  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;

    executeCurrentRegistryFunction();
    nextRegistryNumber();
  }
  if (WiFi.status() == WL_CONNECTED) {
    ledState = HIGH;
    digitalWrite(LED, ledState);
  }
}

ich habe mir die Zeit genommen dein Post zu lesen.

Nimm du dir bitte die Zeit und zeichne DEINEN Schaltplan
und poste DEINE Bilder.

Ich will nicht irgend was sehen wie es vieleicht funktionieren soll, sondern ich will sehen was du hast und aktuell nicht funktioniert.

Du könntest einen Test mit SoftwareSerial machen und am seriellen Monitor auslesen.
Damit prüfst du die grundsätzliche Funktion. Die Baudrate der SoftwareSerial evt. runter nehmen.

Dank @noiasca funktioniert bei mir das auslesen mit einem Mega so wie ESP8266 mit LCD2004Display + werte werden gesendet auf Webseite. Nur der Sketsch Aufbau ist komplett anders.
Die ganze Geschichte:

Testaufbau:

EDIT: NICHT BEACHTEN. DER STROM DES ESP IST ZU HOCH FÜR DEN ANSCHLUSS AM EPEVER!

Öhm... Deinem Schaltplan nach hast Du RX mit RXD und TX mit TXD verbunden - müsste das nicht gekreuzt sein?

Die 5V am Tracer liefern nur 50mA ich wurde nicht ein ESP dran hängen, was bei Wlan um die 400mA braucht

"WARNING: Die RJ45 Schnittstelle darf nur mit unseren Produkten
verbunden werden und muss von einem Fachmann installiert
werden. Schnittstellenspannung = 5V - Strom = 50mA)"

Ja das dachte ich auch. So hatte ich es erst auch. Aber hier muss TX tatsächlich an TX.
Wie gesagt: Genau so funktioniert das ganze mit dem ESP32. Jedoch nicht mit dem ESP8266.

Ja danke, das habe ich gelesen. Leider auch zu spät. Werde einen DC-DC-Wandler benutzen und nicht mehr die Buchse als Versorgung nehmen.

Ich benutze die Module
https://www.reichelt.de/entwicklerboards-ttl-zu-rs485-max3485-debo-rs485-ttl-p282703.html?PROVID=2788&gclid=EAIaIQobChMIuaSN2Oml9wIVA57VCh3C2gVWEAQYASABEgKfk_D_BwE

Machen keine Probleme, und funktionieren auch bei 3,3V

Mein Adapter hat einen eingebauten HEX-Inverter. Jedoch funktioniert es auf dem ESP32 ja. Da ich die gleiche Verdrahtung (nur eben Serial statt Serial2) verwende gibt es ja nicht viele Möglichkeiten:

  • Es ist ein Problem mit der Modbus Library und dem ESP8266
  • Das ganze klappt nicht so einfach wie ich mir das gedacht habe da ich statt den Serial2 des ESP32 den Serial des ESP8266 nehme
  • Ein weiterer kleiner Fehler im Code hat sich beim Portieren eingeschlichen

Wie gesagt, der serielle Anschluss gibt ja schon befehle in der richtigen Geschwindigkeit aus. Leider kommt aber keine Antwort. Nun habe ich mir den anderen Adapter bestellt da das mit diesem ja erprobt ist. Habe noch eine Modbus Relais-Platine, vielleicht kommt der andere Converter nochmal zum Einsatz.

Mal die Gegenfrage, warum verwendest du nicht den ESP32, wenn es doch damit schon funktioniert ?

gib den ESP8266 mal echte 5V - nicht vom EPEVER(!) - und auch nicht von dessen Solarbatterie. ebenso gibst deinem RS485 Wandler die gleichen 5V.
Schließ einen EPEVER mit Solar-Batterie an.
Mach ein neues Bild von der Verkabelung (inkl. was am EPEVER Display steht).
Siehst du geflackere von TX / RX LEDs auf deinem RS485 Wandler?

Danke, es hat geklappt. Mit externer 5V Versorgung über USB und umlegen des RS485 Wandlers von 3.3 auf 5V funktioniert es.

Einen kleinen Fehler habe ich wohl noch im Code aus post #3. Leider werden beispielsweise die ausgelesenen Werte aus void AddressRegistry_3100() nicht übergeben. Es ist vielleicht eine Anfängerfrage aber wie bekomme ich den Wert auf die globale Variable geschrieben?
Beispiel: pvvoltage = node.getResponseBuffer(0x00) / 100.0f;

Danach sollte es laufen.

reduzier mal die Abfrage auf eine Adresse
gib dir (in hex) aus was du von der Funktion als "result " zurück erhältst und schau in der ModbusMaster.h nach, was der Langtext vom Fehlercode ist.

wenn du 0xE.. Fehler erhältst, setzt mal ein kurzes Delay (500) vor der Abfrage.

Solltest du überraschender weise ein result = 0 (OK) bekommen,
gib dir mal den Wert aus ohne Umrechnung ob der für dich einen Sinn ergibt.

Und ja ... ein Controller mit Debug-Möglichkeit wäre praktisch. Der ESP8266 hätte aber zumindest einen freien Serial1 TX ... da bräuchtest halt einen TTL/USB wandler damit du den lesen kannst. Für Debug Ausgaben soll das reichen.

result = node.readInputRegisters(0x3100, 1);

  if (result == node.ku8MBSuccess) {
    Serial1.print(node.getResponseBuffer(0));
}
Serial1.print(F("result=")); Serial1.println(result, HEX);

und nur so als Kontrollfrage:
3100 ... Solar charge controller--PV array voltage

du hat ein Panel dranhängen und siehst am Display eine Spannung > 0?

Danke für die Mühe. Also der Regler ist im normalen Betrieb an der Zelle mit Batterie.

Es ist jetzt nach den Versorgungsproblemen mal so weit dass die RX LED auf dem Adapter kurz nach der TX LED aufflackert. Jetzt hoffe ich dass ich das so interpretieren kann dass auch Daten nach einer Anfrage zurück kommen.

Den Code habe ich wie von dir beschrieben einmal verwendet.
Ich bekomme seriell immer den Wert "E2" ausgegeben.
Nun habe ich auch einmal den originalen Code von github mit Serial statt Serial2 verwendet und auch hier flackern beide LED's immer kurz aber es kommt nie als result 0 zurück sodass ein error ausgegeben wird.

gib mal in dein preTransmission einen kleinen Delay rein:

void preTransmission() {
 delay(500);
}

ändert das was am E2?

Wurde schon RX mit TX getauscht und A mit B?