Wechselrichter Daten auslesen

So mein Lieber...
Nicht erschrecken, aber ich hab mir mal nen Moment Zeit genommen.
Was der Sketch machen soll:
Eigentlich nichts anderes als vorher auch. Er fordert die Daten vom WR an und verarbeitet diese.
Allerdings mit ein paar kleinen Schätzchen.
Ich habe das struct noch ein wenig umgebaut und das soweit fertig gemacht. Es fehlt noch eine byteVariable, aber das erst, wenn wir hier soweit sind, das es Fehlerfrei funktioniert.
In dem Struct werden die Werte gespeichert, die zu einem WR gehören.
Später kannst Du dann das gesamte Struct genauso weiterverwenden. Ich hab nur keine Ahnung vom Broker - aber ich kann mich dran erinnern, das es möglich sein soll, das gesamte Struct zu übertragen und der Inhalt dann beim Broker direkt aufgelöst wird.

Ich hab jetzt auch die Doku gelesen und verstanden, wie das funktioniert. Die Wr unterhalten sich mittels CAN und der Wr, den Du anfragst, gibt die Anfrage dann ggfls. darüber weiter udn die Antwort zurück zu Dir.

Damit Du das austesten kannst, ob die Auswertung und Übertragung der Daten auf dem ESP zum Broker funktioniert, habe ich eine Deiner Messages von gestern aufgeteilt und so vorbereitet, das Du diese immer als Testnachricht benutzen kannst.
Dafür ist die Variable testmessage vorgesehen - aktuell steht sie auf true. Ich wollte auch mal spielen :wink:
Wenn Du die auf false stellst, wird die aus der Schnittstelle gelesene Nachricht verwendet.
Und da kommen wir gleich zum nächsten.
Ich lese jetzt alle drei Wr nacheinander aus - und erst wenn der letzte gelesen wurde habe ich die 10 Sekunden Pause drin.
Das macht Sinn... Denn wenn Du alle 10Sekunden einen Wr ausliest, bekommst Du teils unplausible Summen-Werte.
Und damit verbunden ist dann auch gleich die nächste wichtige Änderung: Du musst den Seriellen Monitor schneller machen.
Ohne Probleme gehen 115200 überall. Die meissten hier haben das auch als Standardeinstellung schon im nakten Sketch(*)

Und weil ich mir sicher bin, das das mit dem Broker zwar schick ist, aber wenn der mal weg ist Du irgendwie an Klarmeldungen rankommen musst, hab ich die auch gleich komplett in der Ausgabe vom SerMon integriert :wink:
Das ist auch die größte Änderung. Du brauchst noch eine kleine lib - wo die zu finden ist, steht im Code.
Und ich hab die Ausgabe vom verarbeiten getrennt.

Was noch nicht dabei ist:
die CRC hab ich noch draussen gelassen. Soll aber später mit rein, dann kannst Du auf die Variablen verzichten und die zur Laufzeit berechnen. Und im Gegenzug dann auch die ankommende Nachricht validieren.

Dann würde ich ein byte in das struct aufnehmen um Nachrichten die während der Verarbeitung anfallen an den broker zu senden. Z.B. wenn eine Message nicht vollständig ist oder bei der Verarbeitung irgendwas schief gelaufen ist etc...
Das kommt aber zum Schluß.
Zudem hast Du genügend Platz auf dem ESP. Ich würde das struct für alle 3 Wr als arra anlegen und alle 3Wr erst auslesen udn dann gesammelt an den broker übertragen.
Damit hast Du dann immer zusammengehörige Werte..

So nu Sketch. Ich hoffe, das der funktioniert.
Im Trockentest mit einem ARDUINO Uno hat der die Message sauber aufgeteilt und ausgegeben. Es ist viel kommentiert.
Wenn Fragen sind: FRAG!

Sketch


// Forensketch - Wechselrichter auslesen
/*
  Phocos Any-Grid-Series PSW-H-5KW-230/48V
                         PSW-H-3KW-230/24V
                         PSW-H-5KW-120/48V
                         PSW-H-3KW-120/24V
*/
// https://forum.arduino.cc/t/wechselrichter-daten-auslesen/1104441/30
// kompiliert Fehler- und Warungsfrei
// getestet mit dem messwertearray und Seriellem Monitor

#include <Streaming.h>     // https://github.com/janelia-arduino/Streaming

#define DEBUG              // Wenn aktiviert, werden Zwischenwerte ausgegeben
#ifdef DEBUG
  #define DBG_PRINTLN(...) Serial.println( __VA_ARGS__);
  #define DBG_PRINT(...) Serial.print(__VA_ARGS__);
#else
  #define DBG_PRINTLN(...)
  #define DBG_PRINT(...)
#endif

bool testmessage = true;   // wenn true, wird der Puffer mit Testnachricht gefüllt

#include <SoftwareSerial.h>
// SoftwareSerial-Pins
constexpr auto rxPin {D2}; // RX-Pin (Wechselrichter-Ausgang)
constexpr auto txPin {D1}; // TX-Pin (Wechselrichter-Eingang)
SoftwareSerial qpgCom(rxPin, txPin);

// Testnachricht
const char messwerte[131] =
{
  /*000*/ 0x31, 0x20,                                                                               // 1
  /*002*/ 0x39, 0x32, 0x39, 0x33, 0x32, 0x30, 0x30, 0x39, 0x31, 0x30, 0x35, 0x30, 0x37, 0x31, 0x20, // 929320091050371
  /*017*/ 0x42, 0x20,                                                                               // B
  /*019*/ 0x30, 0x30, 0x20,                                                                         // 00
  /*022*/ 0x32, 0x32, 0x39, 0x2E, 0x33, 0x20,                                                       // 229.3
  /*028*/ 0x34, 0x39, 0x2E, 0x39, 0x39, 0x20,                                                       // 49.99
  /*034*/ 0x32, 0x33, 0x30, 0x2E, 0x31, 0x20,                                                       // 230.1
  /*040*/ 0x34, 0x39, 0x2E, 0x39, 0x33, 0x20,                                                       // 49.93
  /*046*/ 0x30, 0x38, 0x39, 0x37, 0x20,                                                             // 0897
  /*051*/ 0x30, 0x38, 0x33, 0x37, 0x20,                                                             // 0837
  /*056*/ 0x30, 0x31, 0x37, 0x20,                                                                   // 017
  /*060*/ 0x34, 0x39, 0x2E, 0x39, 0x20,                                                             // 49.92
  /*065*/ 0x30, 0x30, 0x30, 0x20,                                                                   // 000
  /*069*/ 0x30, 0x34, 0x37, 0x20,                                                                   // 047
  /*073*/ 0x31, 0x32, 0x30, 0x2E, 0x30, 0x20,                                                       // 120.0
  /*079*/ 0x30, 0x30, 0x32, 0x20,                                                                   // 002
  /*083*/ 0x30, 0x31, 0x32, 0x31, 0x38, 0x20,                                                       // 01218
  /*089*/ 0x30, 0x31, 0x30, 0x37, 0x35, 0x20,                                                       // 01075
  /*095*/ 0x30, 0x30, 0x37, 0x20,                                                                   // 007
  /*099*/ 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x31, 0x30, 0x20,                                     // 10100010 !!! b7b6b5b4b3b2b1b0 !!!
  /*108*/ 0x33, 0x20,                                                                               // 3
  /*110*/ 0x32, 0x20,                                                                               // 2
  /*112*/ 0x30, 0x33, 0x30, 0x20,                                                                   // 030
  /*116*/ 0x30, 0x38, 0x30, 0x20,                                                                   // 080
  /*120*/ 0x31, 0x30, 0x20,                                                                         // 10
  /*123*/ 0x30, 0x30, 0x2E, 0x34, 0x20,                                                             // 00.4
  /*128*/ 0x30, 0x31, 0x37,                                                                         // 017
  /*131*/ /* Next two Bytes(!?) is CRC16 for this Message */                                         // <CRC>
};
uint16_t messageCRC = 0;

// Inhalt der Nachricht
struct QPGMSG
{
  bool     wrType;                   // 0 single / 1 multi
  char     serialNumber[15];         // 14 Ziffern
  char     wrMode;                   // a single Char
  uint8_t  faultCode;                // 2 Ziffern
  uint16_t inputVoltageAc;           // in VAC *10  - ohne Nachkommastelle
  uint16_t inputFrequencyAc;         // in Hz *100
  uint16_t outputVoltageAc;          // in VAC *10
  uint16_t outputFrequencyAc;        // in Hz *100
  uint16_t outputVAAc;               // in VA
  uint16_t outputWAc;                // in W
  uint8_t  outputPowerPerc;          // in %
  uint16_t batteryVoltage;           // in VDC *10
  uint16_t batteryChargeCurrent;     // in ADC
  uint8_t  batteryChargeState;       // in %
  uint16_t inputPvVoltage;           // in VDC *10
  uint16_t chargingCurrentTotal;     // in ADC
  uint32_t outputVAAcTotal;          // in VA
  uint32_t outputWAcTotal;           // in W
  uint16_t outputPowerPercTotal;     // in %
  bool     mpptActive;
  bool     acCharging;
  bool     solarCharging;
  uint8_t  batteryChargeInfo;        // 2 bit!
  bool     acInputAvail;
  bool     acOutputStatus;
  bool     reserved;
  uint8_t  outputModeAc;             //
  uint8_t  battChargeSource;         //
  uint16_t maxChargeCurSet;          // in ADC
  uint16_t maxChargePossible;        // in ADC
  uint16_t maxChargeCurAc;           // in ADC
  uint16_t pvInputCur;               // in ADC *10
  uint16_t battDisChargeCur;         // in ADC
};

const byte qpgsNums = 3;             // Anzahl verwendeter Wechselrichter
byte wrNum;                          // Merker für aktuell Wechselrichternummer

QPGMSG qpgMsg;


enum {qWait, qRequest, qResponse, endMessage}; // Ablaufzustände
byte state = qWait;
constexpr auto readDelay {10000};    // Pause zwischen dem auslesen aller Wechselrichter
constexpr auto timeOut {1000};       // In der Zeit sollte eine Nachricht vollständig da sein
uint16_t intervall;                  // Umlaufvariable
uint32_t switchTime;                 // Merker wann die letzte Aktion war
const uint8_t messageLen = 130;      // Länge einer Nachricht
char messageBuf[messageLen + 1] = {'\0'}; // +1 für \0
byte idx;                            // Merker für Position


void setup()
{
  // Starten der seriellen Kommunikation
  Serial.begin(115200);
  Serial.println(F("Start..."));
  qpgCom.begin(2400);
  switchTime = millis();
}

void wrSendMessage(const byte wrNum)
{
  if (wrNum > qpgsNums - 1)           // Wenn Nummer zu hoch
  {
    DBG_PRINT(F("WR unbekannt"));
    DBG_PRINTLN(wrNum);
    DBG_PRINTLN();
    return;
  }
  // Anforderung Wechselrichter Kommandos in HEX 16-bit Kalkulation
  const byte qpgsStartSeq[] = {0x51, 0x50, 0x47, 0x53,};
  const byte qpgs[][qpgsNums] =
  {
    { 0x30, 0x3F, 0xDA }, //
    { 0x31, 0x2F, 0xFB }, //
    { 0x32, 0x1F, 0x98 }, //
  };
  DBG_PRINT(F("Frage WR "));
  DBG_PRINTLN(wrNum);
  qpgCom.write(qpgsStartSeq, sizeof(qpgsStartSeq));
  qpgCom.write(qpgs[wrNum], sizeof(qpgs[wrNum]));
  qpgCom.write('\r');
}

void loop()
{
  switch (state)
  {
    case qWait:
      while (qpgCom.available())                       // Noch Reste auf der Schnittstelle?
      { qpgCom.read(); }                               //
      if (millis() - switchTime > intervall)           // Wenn Zeit abgelaufen ...
      {
        DBG_PRINTLN("Starte Abfrage");
        state = qRequest;
      }                            // ... nächster Schritt
      break;
    case qRequest:
      wrSendMessage(wrNum); // Anforderung passend zum Wechselrichter
      switchTime = millis();                           // Zeit merken
      state = qResponse;                               // ... nächster Schritt
      break;
    case qResponse:
      if (qpgCom.available())                          // wenn was anliegt
      {
        char x = qpgCom.read();                        // Zeichen einlesen
        DBG_PRINTLN(x);
        if (idx > 0 && idx % 10 == 0)
        { DBG_PRINTLN(); }
        if (x == '(')                                  // Startzeichen erkannt
        {
          memset(messageBuf, '\0', sizeof(messageBuf));// Buffer initialisieren
          idx = 0;                                     //
        }
        else if (isControl(x))                         // Ist Steuerzeichen
        { state = endMessage; }                        // nächster Schritt
        else if (idx <= messageLen)                    // Wenn Messagebuffer nicht voll
        {
          messageBuf[idx] = x;                         // zeichen in den Buffer schreiben
          idx++;                                       // nächste Position setzen
        }
      }
      if (millis() - switchTime > timeOut)             // Zeit abgelaufen
      {
        state = endMessage;
        DBG_PRINTLN(F("NO Response"));
        DBG_PRINTLN();
      }
      break;
    case endMessage:
      if (testmessage)
      {
        DBG_PRINTLN(F("Verwende Testnachricht"));
        memcpy (messageBuf, messwerte, messageLen<sizeof(messageBuf)-1?messageLen:sizeof(messageBuf)-1);
      }
      splitResponse();
      printResponse();
      wrNum++;                                         // nächstes Gerät
      intervall = 0;
      if (wrNum >= qpgsNums)                           // Wenn letztes Gerät überlaufen
      {
        wrNum = 0;                                     // erstes Gerät setzen
        intervall = readDelay;
      }
      switchTime = millis();                           // Zeit merken
      state = qWait;                                   // beginne von vorn
      break;
  }
}
//
void splitResponse()
{
  qpgMsg.wrType               = atoi(&messageBuf[0]) ;
  memcpy(qpgMsg.serialNumber, &messageBuf[2], 14);
  qpgMsg.wrMode               = messageBuf[17];
  qpgMsg.faultCode            = atoi(&messageBuf[19]);
  qpgMsg.inputVoltageAc       = atof(&messageBuf[22]) * 10;
  qpgMsg.inputFrequencyAc     = atof(&messageBuf[28]) * 100;
  qpgMsg.outputVoltageAc      = atof(&messageBuf[34]) * 10;
  qpgMsg.outputFrequencyAc    = atof(&messageBuf[40]) * 100;
  qpgMsg.outputVAAc           = atoi(&messageBuf[46]);
  qpgMsg.outputWAc            = atoi(&messageBuf[51]);
  qpgMsg.outputPowerPerc      = atoi(&messageBuf[56]);
  qpgMsg.batteryVoltage       = atof(&messageBuf[60]) * 10;
  qpgMsg.batteryChargeCurrent = atoi(&messageBuf[65]);
  qpgMsg.batteryChargeState   = atoi(&messageBuf[69]);
  qpgMsg.inputPvVoltage       = atof(&messageBuf[73]) * 10;
  qpgMsg.chargingCurrentTotal = atoi(&messageBuf[79]);
  qpgMsg.outputVAAcTotal      = atoi(&messageBuf[83]);
  qpgMsg.outputWAcTotal       = atoi(&messageBuf[89]);
  qpgMsg.outputPowerPercTotal = atoi(&messageBuf[95]);
  qpgMsg.mpptActive           = messageBuf[99] - '0';
  qpgMsg.acCharging           = messageBuf[100]- '0';
  qpgMsg.solarCharging        = messageBuf[101]- '0';
  qpgMsg.batteryChargeInfo = 0;
  if (messageBuf[102]- '0') qpgMsg.batteryChargeInfo += 2;
  qpgMsg.batteryChargeInfo    += (messageBuf[103]- '0');
  qpgMsg.acInputAvail         = messageBuf[104]- '0';
  qpgMsg.acOutputStatus       = messageBuf[105]- '0';
  qpgMsg.reserved             = messageBuf[106]- '0';
  qpgMsg.outputModeAc         = atoi(&messageBuf[108]);
  qpgMsg.battChargeSource     = atoi(&messageBuf[110]);
  qpgMsg.maxChargeCurSet      = atoi(&messageBuf[112]);
  qpgMsg.maxChargePossible    = atoi(&messageBuf[116]);
  qpgMsg.maxChargeCurAc       = atoi(&messageBuf[120]);
  qpgMsg.pvInputCur           = atof(&messageBuf[123]) * 10;
  qpgMsg.battDisChargeCur     = atoi(&messageBuf[128]);
}
//
void printResponse()
{
  const char A = 'A';
  const char V = 'V';
  const char W = 'W';
  const char proz = '%';
  // *INDENT-OFF*
  Serial << F("wrType: ")            << (qpgMsg.wrType ? "Multi" : "Single")                        << endl;
  Serial << F("serialNumber: ")      << qpgMsg.serialNumber                                         << endl;
  Serial << F("wrMode: ")            << (qpgMsg.wrMode == 'P' ? "Powered" :
                                         qpgMsg.wrMode == 'S' ? "StandBy" :
                                         qpgMsg.wrMode == 'L' ? "InGrid" :
                                         qpgMsg.wrMode == 'B' ? "OffGrid" :
                                         qpgMsg.wrMode == 'F' ? "FAULT" :
                                         qpgMsg.wrMode == 'D' ? "ShutDown" : "n/a")                 << endl;
  Serial << F("faultCode: ")         << qpgMsg.faultCode                                            << endl;
  Serial << F("inputVoltageAc: ")    << static_cast<float>(qpgMsg.inputVoltageAc) / 10      << V    << endl;
  Serial << F("inputFrequencyAc: ")  << static_cast<float>(qpgMsg.inputFrequencyAc) / 100   << "Hz" << endl;
  Serial << F("outputVoltageAc: ")   << static_cast<float>(qpgMsg.outputVoltageAc) / 10     << V    << endl;
  Serial << F("outputFrequencyAc: ") << static_cast<float>(qpgMsg.outputFrequencyAc) / 100  << "Hz" << endl;
  Serial << F("outputVAAc: ")        << qpgMsg.outputVAAc                                   << "VA" << endl;
  Serial << F("outputWAc: ")         << qpgMsg.outputWAc                                    << W    << endl;
  Serial << F("outputPowerPerc: ")   << qpgMsg.outputPowerPerc                              << proz << endl;
  Serial << F("batteryVoltage: ")    << static_cast<float>(qpgMsg.batteryVoltage) / 10      << V    << endl;
  Serial << F("batteryChargeCurrent: ") << qpgMsg.batteryChargeCurrent                      << A    << endl;
  Serial << F("batteryChargeState: ")   << qpgMsg.batteryChargeState                        << proz << endl;
  Serial << F("inputPvVoltage: ")       << static_cast<float>(qpgMsg.inputPvVoltage) / 10   << V    << endl;
  Serial << F("chargingCurrentTotal: ") << qpgMsg.chargingCurrentTotal                      << A    << endl;
  Serial << F("outputVAAcTotal: ")      << qpgMsg.outputVAAcTotal                           << "VA" << endl;
  Serial << F("outputWAcTotal: ")       << qpgMsg.outputWAcTotal                            << W    << endl;
  Serial << F("outputPowerPercTotal: ") << qpgMsg.outputPowerPercTotal                      << proz << endl;
  Serial << F("mpptActive: ")           << (qpgMsg.mpptActive ? "a" : "ina") << F("ctive")          << endl;
  Serial << F("acCharging: ")           << 'O' << (qpgMsg.acCharging ? "N" : "FF")                  << endl;
  Serial << F("solarCharging: ")        << 'O' << (qpgMsg.solarCharging ? "N" : "FF")               << endl;
  Serial << F("batteryChargeInfo: ")    << (qpgMsg.batteryChargeInfo == 3 ? "char/dischar disable" :
                                            qpgMsg.batteryChargeInfo == 2 ? "Batt not Connect" :
                                            qpgMsg.batteryChargeInfo == 1 ? "Batt LOW" : "Normal")  << endl;
  Serial << F("acInputAvail: ")         << (qpgMsg.acInputAvail ? "nota" : "a") << F("vailable")    << endl;
  Serial << F("acOutputStatus: ")       << 'O' << (qpgMsg.acOutputStatus ? "N" : "FF")              << endl;
  Serial << F("reserved: ")             << qpgMsg.reserved                                          << endl;
  Serial << F("outputModeAc: ")         << (qpgMsg.outputModeAc == 0 ? "Singlegrid" :
                                            qpgMsg.outputModeAc == 1 ? "Parallel Output" :
                                            qpgMsg.outputModeAc == 2 ? "Phase 1" :
                                            qpgMsg.outputModeAc == 3 ? "Phase 2" :
                                            qpgMsg.outputModeAc == 4 ? "Phase 3" : "n/a")           << endl;
  Serial << F("battChargeSource: ")     << (qpgMsg.battChargeSource == 1 ? "Solar First" :
                                            qpgMsg.battChargeSource == 2 ? "Solar & Utility" :
                                            qpgMsg.battChargeSource == 3 ? "Solar Only" : "n/a")    << endl;
  Serial << F("maxChargeCurSet: ")      << qpgMsg.maxChargeCurSet                             << A  << endl;
  Serial << F("maxChargePossible: ")    << qpgMsg.maxChargePossible                           << A  << endl;
  Serial << F("maxChargeCurAc: ")       << qpgMsg.maxChargeCurAc                              << A  << endl;
  Serial << F("pvInputCur: ")           << static_cast<float>(qpgMsg.pvInputCur) / 10         << V  << endl;
  Serial << F("battDisChargeCur: ")     << qpgMsg.battDisChargeCur                            << A  << endl;
  // *INDENT-ON*
}

void printFault(const byte code)
{
// *INDENT-OFF*
  switch (code)
  {
    case  1:Serial << F("Fan locked while inverter off"); break;
    case  2:Serial << F("Over-temperature"); break;
    case  3:Serial << F("Battery voltage too high"); break;
    case  4:Serial << F("Battery voltage too low"); break;
    case  5:Serial << F("AC output short-circuit"); break;
    case  6:Serial << F("AC output voltage too high"); break;
    case  7:Serial << F("AC output overload"); break;
    case  8:Serial << F("Internal bus voltage too high"); break;
    case  9:Serial << F("Internal bus soft-start failed"); break;
    case 10:Serial << F("PV over-current"); break;
    case 11:Serial << F("PV over-voltage"); break;
    case 12:Serial << F("Internal DC converter over-current"); break;
    case 13:Serial << F("Battery discharge over-current"); break;
    case 51:Serial << F("Over-current"); break;
    case 52:Serial << F("Internal bus voltage too low"); break;
    case 53:Serial << F("Inverter soft-start failed"); break;
    case 55:Serial << F("DC over-voltage at AC output"); break;
    case 57:Serial << F("Current sensor failed"); break;
    case 58:Serial << F("AC Output voltage too low"); break;
    case 60:Serial << F("Reverse-current protection active"); break;
    case 71:Serial << F("Firmware version inconsistent"); break;
    case 72:Serial << F("Current sharing fault"); break;
    case 80:Serial << F("CAN communication fault"); break;
    case 81:Serial << F("Host loss"); break;
    case 82:Serial << F("Synchronization loss"); break;
    case 83:Serial << F("Battery voltage detected inconsistent"); break;
    case 84:Serial << F("AC in. voltage/frequency inconsistent"); break;
    case 85:Serial << F("AC output current imbalance"); break;
    case 86:Serial << F("AC output mode inconsistent"); break;
  }
  Serial<<endl;
  // *INDENT-ON*
}
//
word calculateCRC(byte *buf, byte len)
{
  word crc = 0;
  return calculateCRC(crc, buf, len);
}
//
word calculateCRC(word crc, byte *buf, byte len)
{
  byte data;
  byte crcHigh;
  byte crcLow;
  const word crcTable[16] =
  {
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef
  };
  while (len-- > 0)
  {
    data = ((byte)(crc >> 8)) >> 4;
    crc <<= 4;
    crc ^= crcTable[data ^ (*buf >> 4)];
    data = ((byte)(crc >> 8)) >> 4;
    crc <<= 4;
    crc ^= crcTable[data ^ (*buf & 0x0f)];
    buf++;
  }
  crcLow = crc;
  crcHigh = (byte)(crc >> 8);
  if (crcLow == 0x28 || crcLow == 0x0d || crcLow == 0x0a)
  {
    crcLow++;
  }
  if (crcHigh == 0x28 || crcHigh == 0x0d || crcHigh == 0x0a)
  {
    crcHigh++;
  }
  crc = ((word)crcHigh) << 8;
  crc += crcLow;
  return crc;
}

Viel Spass mit :slight_smile:
Ausgabe auf dem SerMon

16:50:45.691 -> Start...
16:50:45.691 -> Starte Abfrage
16:50:45.691 -> Frage WR 0
16:50:46.724 -> NO Response
16:50:46.724 -> 
16:50:46.724 -> Verwende Testnachricht
16:50:46.724 -> wrType: Multi
16:50:46.724 -> serialNumber: 92932009105071
16:50:46.724 -> wrMode: OffGrid
16:50:46.724 -> faultCode: 0
16:50:46.724 -> inputVoltageAc: 229.30V
16:50:46.724 -> inputFrequencyAc: 49.99Hz
16:50:46.724 -> outputVoltageAc: 230.10V
16:50:46.724 -> outputFrequencyAc: 49.93Hz
16:50:46.724 -> outputVAAc: 897VA
16:50:46.724 -> outputWAc: 837W
16:50:46.724 -> outputPowerPerc: 17%
16:50:46.758 -> batteryVoltage: 49.90V
16:50:46.758 -> batteryChargeCurrent: 0A
16:50:46.758 -> batteryChargeState: 47%
16:50:46.758 -> inputPvVoltage: 120.00V
16:50:46.758 -> chargingCurrentTotal: 2A
16:50:46.758 -> outputVAAcTotal: 1218VA
16:50:46.758 -> outputWAcTotal: 1075W
16:50:46.758 -> outputPowerPercTotal: 7%
16:50:46.758 -> mpptActive: active
16:50:46.758 -> acCharging: OFF
16:50:46.758 -> solarCharging: ON
16:50:46.758 -> batteryChargeInfo: Normal
16:50:46.758 -> acInputAvail: available
16:50:46.758 -> acOutputStatus: ON
16:50:46.758 -> reserved: 0
16:50:46.758 -> outputModeAc: Phase 2
16:50:46.758 -> battChargeSource: Solar & Utility
16:50:46.827 -> maxChargeCurSet: 30A
16:50:46.827 -> maxChargePossible: 80A
16:50:46.827 -> maxChargeCurAc: 10A
16:50:46.827 -> pvInputCur: 0.40V
16:50:46.827 -> battDisChargeCur: 1A
16:50:46.827 -> Starte Abfrage
16:50:46.827 -> Frage WR 1
16:50:47.821 -> NO Response
16:50:47.821 -> 
16:50:47.821 -> Verwende Testnachricht
16:50:47.821 -> wrType: Multi

(*) Um das dauerhaft auch bei neuen Sketches einzustellen: Den Sketch BareMinimum im example-Ordner

grafik

mit einem Editor (nicht in der IDE!) öffnen und dort die 9600 gegen 115200 austauschen - speichern fertig.

1 Like