Victron MPPT Regler mit VEdirect

Ich hab mal was gebaut.
Die Referenzimplementation bitte downloaden
Das .zip dann via Sketch - Bibliothek einbinden - .zip-Bibliothek einbinden in die IDE integrieren.
Dann diesen Sketch mal laufen lassen:

/*************************************************************************************
  ReadVeDirectFrameHandler

  Uses VeDirectFrameHandler library

  This example and library tested with NodeMCU 1.0 using Software Serial.
  If using with a platform containing 2 harware UART's, use those, not SoftwareSerial.
  Tested with Victron BMV712.

  VEDirect Device:
   pin 1 - gnd
   pin 2 - RX
   pin 3 - TX
   pin 4 - power

  History:
   2020.05.05 - 0.3 - initial release

**************************************************************************************/

#include "Arduino.h"
#include "VeDirectFrameHandler.h"

VeDirectFrameHandler veOne;
VeDirectFrameHandler veTwo;



void setup()
{
  Serial.begin(115200);
  delay(500);
  Serial.println(F("Start..."));
  Serial1.begin(19200);
  Serial2.begin(19200);
  Serial1.flush();
  Serial2.flush();
}

void loop()
{
  ReadVEData();
  EverySecond();
}

void ReadVEData()
{
  while ( Serial1.available() )
  {
    veOne.rxData(Serial1.read());
  }
  while ( Serial2.available() )
  {
    veTwo.rxData(Serial2.read());
  }
  yield();
}

void EverySecond()
{
  static unsigned long prev_millis;
  if (millis() - prev_millis > 1000)
  {
    PrintData();
    prev_millis = millis();
  }
}

void PrintData()
{
  Serial.print(F("VE 1"));
  for ( int i = 0; i < veOne.veEnd; i++ )
  {
    Serial.print(veOne.veName[i]);
    Serial.print("= ");
    Serial.println(veOne.veValue[i]);
  }
  Serial.print(F("VE 2"));
  for ( int i = 0; i < veTwo.veEnd; i++ )
  {
    Serial.print(veTwo.veName[i]);
    Serial.print("= ");
    Serial.println(veTwo.veValue[i]);
  }
}

Vielleicht haben wir ja Glück....

Hallo,
die Bibliothek hatte ich so auch schon einmal verwendet, dann aber wieder verworfen. Sie lief so mit deinem Test Sketch schon ganz gut. Allerdings sind bei mir dann mit meinem kompletten Sketch und der verwendung von 2 Instanzen 88% meines dynamischen Speicher weg und der Arduino läuft nicht mehr richtig stabil damit. Liegt das eher am Framehandler oder an meinem Sketch?

Der Framehandler mit deinem Sketch verbraucht auch schon 75% des dynamischen Speicher.

//Tft Display
#include <Adafruit_GFX.h>
#include <TouchScreen.h>
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;

//Uhr
#include <Wire.h>
#include "RTClib.h"
RTC_DS3231 rtc;

//DHT22
#include "DHT.h"
#define DHTPIN  53
#define DHTTYPE  DHT22
DHT dht(DHTPIN, DHTTYPE);

//DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 51
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);

#include "Arduino.h"
#include "VeDirectFrameHandler.h"
VeDirectFrameHandler myve1;
VeDirectFrameHandler myve2;

// Touch Panel
#define MINPRESSURE 100
#define MAXPRESSURE 1000

//***********True Components Display*********************************************************************************************
constexpr int XP = 8, XM = A2, YP = A3, YM = 9; //320x480 
constexpr int TS_LEFT = 921, TS_RT = 107, TS_TOP = 73, TS_BOT = 923;

//****************AZ Delivery Display
//constexpr int XP = 6, XM = A2, YP = A1, YM = 7; //320x480 
//constexpr int TS_LEFT = 187, TS_RT = 916, TS_TOP = 939, TS_BOT = 211;
//********************************************************************************************************************************

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
TSPoint p;

//tft Button
Adafruit_GFX_Button page1_btn, page2_btn, page3_btn, page4_btn, page5_btn, page6_btn, page7_btn;;
Adafruit_GFX_Button menu_btn, next_btn;
int pixel_x, pixel_y;

//Relais Heizung
#define RELAISHEIZUNG  52

//Aktor Alarm
#define RELAISINNENLICHT  29

//Relais Arbeitsscheinwerfer
#define RELAISSCHEINWERFER  22

//Alarm Kontakte
#define AKONTAKT  27
#define SKONTAKT  23
int Alarm_ausgeloest = 0;

static unsigned long prev_millis;

//Farben definieren
constexpr uint16_t BLACK = 0x0000, BLUE = 0x001F, RED = 0xF800, DARKGREEN = 0x02C2, CYAN = 0x07FF, WHITE = 0xFFFF, YELLOW = 0xFFE0;

//Screen
enum pageId {MENU, BATTERIE, SOLAR, SOLAR1, SOLAR2, WETTER, HEIZUNG, ALARM, SCHEINWERFER};

//Standard Seite
unsigned int currentPage = MENU, oldPage = -1;

void setup(void) { 
  Serial.begin(115200);
  Serial1.begin(19200);
  Serial2.begin(19200);
  Serial3.begin(9600);
  Serial1.flush();
  Serial2.flush();
  tft.begin();
  tft.setRotation(0);
  tft.fillScreen(BLACK);
  rtc.begin();
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  //rtc.adjust(DateTime(2025, 1, 16, 13, 59, 0)); //zum manuellen einstellen der Uhrzeit
  dht.begin();
  DS18B20.begin();
  pinMode(RELAISHEIZUNG, OUTPUT);
  pinMode(RELAISINNENLICHT, OUTPUT);
  pinMode(RELAISSCHEINWERFER, OUTPUT);
  pinMode(SKONTAKT, INPUT_PULLUP);
  myve1.setErrorHandler(&LogHelper);
  myve1.addHexCallback(&HexCallback, (void*)42);
  currentPage = WETTER;
}

bool down;
void loop(void) {
  down = Touch_getXY();
  switch (currentPage) {
    case MENU:
      if (currentPage != oldPage)   drawMenuScreen();
        redrawButtons();
      break;

    case HEIZUNG:
      if (currentPage != oldPage) {
        Heizung();
        currentPage = MENU;
      }
      break;
    
    case WETTER:
      if (currentPage != oldPage) drawTemperaturScreen();
        getUhr();
        if (prev_millis + 2893 < millis()) { 
          getTemperatur();
          prev_millis = millis();
        }
                      
      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));

      if (menu_btn.justReleased())
        menu_btn.drawButton();

      if (menu_btn.justPressed()) {
        menu_btn.drawButton(true);
        currentPage = MENU;
      }
      break;

    case BATTERIE:
      if (currentPage != oldPage)   drawBatterieScreen();
        //ReadVEData2();
        
        if (millis() - prev_millis > 1000) {
          getShunt();
          prev_millis = millis();
        }

      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));
      
      if (menu_btn.justReleased())
        menu_btn.drawButton();

      if (menu_btn.justPressed()) {
        menu_btn.drawButton(true);
        currentPage = MENU;
      }
      break;      

    case SOLAR:
      if (currentPage != oldPage)   drawSolarScreen();
        //ReadVEData1();

        if (millis() - prev_millis > 1000) {
          getSolar();
          prev_millis = millis();
        }
               
        menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));
        next_btn.press(down && next_btn.contains(pixel_x, pixel_y));
      if (menu_btn.justReleased())
        menu_btn.drawButton();
      
      if (menu_btn.justPressed()) {
        menu_btn.drawButton(true);
        currentPage = MENU;
      }
      break;

    case SOLAR1:
      if (currentPage != oldPage)   drawSolar1Screen();
        //ReadVEData1();

        if (millis() - prev_millis > 1000) {
          getSolar1();
          prev_millis = millis();
        }
        
      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));
      next_btn.press(down && next_btn.contains(pixel_x, pixel_y));
      if (menu_btn.justReleased())
        menu_btn.drawButton();
      if (next_btn.justReleased())
        next_btn.drawButton();

      if (menu_btn.justPressed()) {
        menu_btn.drawButton(true);
        currentPage = MENU;
      }
      
      if (next_btn.justPressed()) {
        next_btn.drawButton(true);
        currentPage = SOLAR2;
        
      }
      break;

    case SOLAR2:
      if (currentPage != oldPage)   drawSolar2Screen();
        //ReadVEData1();
        
        if (millis() - prev_millis > 1000) {
          getSolar2();
          prev_millis = millis();
        }
        
      
      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));
      
      if (menu_btn.justReleased())
        menu_btn.drawButton();
      
      if (menu_btn.justPressed()) {
        menu_btn.drawButton(true);
        currentPage = MENU;
      }
      break;
    
    case ALARM:
      if (currentPage != oldPage) drawAlarmScreen();
        Ausgeloest();
        if (prev_millis + 2893 < millis()) {           
          getUhr();
          getTemperatur();
          prev_millis = millis();
        }
      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));
      
      if (menu_btn.justReleased())
        menu_btn.drawButton();

      if (menu_btn.justPressed()) {
        menu_btn.drawButton(true);
        currentPage = MENU;
      }
      break;
  
    case SCHEINWERFER:
      if (currentPage != oldPage) { 
        Scheinwerfer();
        updateScheinwerferButton();
        currentPage = MENU;
      }
      break;
  }

  if (oldPage == currentPage) {
    down = Touch_getXY();
  } 
  else {
    down = false;
  }
  Sabotage();
  Bluetooth();
  ReadVEData1();
  ReadVEData2();
}

/*****************************************************************************************************************************************************************************************
                                                                                         SCREENS 
******************************************************************************************************************************************************************************************/
void drawMenuScreen() {
  Alarm_ausgeloest = 0;
  tft.fillScreen(BLACK);
  tft.setTextColor(BLUE);
  digitalWrite(RELAISINNENLICHT, LOW);
  tft.setCursor(50, 8);
  tft.println(F("WoMo-Monitor"));
  tft.setTextSize(2);

  page1_btn.initButton(&tft, 120, 60, 210, 35 , WHITE, CYAN, BLACK, "Heizung", 2);
  page2_btn.initButton(&tft, 120, 172, 210, 35 , WHITE, CYAN, BLACK, "Batterie", 2);
  page3_btn.initButton(&tft, 175, 227, 100, 35 , WHITE, CYAN, BLACK, "Sol his", 2);
  page4_btn.initButton(&tft, 120, 115, 210, 35 , WHITE, CYAN, BLACK, "Temp", 2);
  page5_btn.initButton(&tft, 65, 227, 100, 35 , WHITE, CYAN, BLACK, "Sol akt", 2);
  page6_btn.initButton(&tft, 65, 282, 100, 35 , RED, CYAN, RED, "Alarm", 2);
  updateScheinwerferButton();
  page1_btn.drawButton(false);
  page2_btn.drawButton(false);
  page3_btn.drawButton(false);
  page4_btn.drawButton(false);
  page5_btn.drawButton(false);
  page6_btn.drawButton(false);
  
  tft.drawRoundRect(5, 32, 230, 280, 10, BLUE);
  oldPage = currentPage;
}

void updateScheinwerferButton() {
  if (digitalRead(RELAISSCHEINWERFER) == HIGH) {
    page7_btn.initButton(&tft, 175, 282, 100, 35 , WHITE, YELLOW, BLACK, "Scheinw", 2);
  } 
  else {
    page7_btn.initButton(&tft, 175, 282, 100, 35 , WHITE, CYAN, BLACK, "Scheinw", 2);
  }
  page7_btn.drawButton(false);
}

//Batterie 
void drawBatterieScreen() {
  tft.setTextSize(2);
  tft.fillScreen(BLACK);
  tft.setTextColor(WHITE,BLACK); 
  tft.setCursor(10, 10);
  tft.println(F("Batteriespannung V:"));
  tft.setCursor(10, 70);
  tft.println(F("Ladestrom A:"));
  tft.setCursor(10, 130);
  tft.println(F("verbrauchte AH:"));
  tft.setCursor(10, 190);
  tft.println(F("Ladestand %:"));
    
  menu_btn.initButton(&tft, 120, 295, 120, 35, WHITE, CYAN, BLACK, "MENU", 2);
  menu_btn.drawButton(false);
  oldPage = currentPage;
}

//Solar Leistung,Spannung
void drawSolarScreen() {
  tft.setTextSize(2); 
  tft.fillScreen(BLACK);
  tft.setTextColor(WHITE,BLACK); 
  tft.setCursor(0, 10);
  tft.println(F("Leistung W:"));
  tft.setCursor(0,70);
  tft.println(F("Spannung Panel V:"));
  tft.setCursor(0,130);
  tft.println(F("Laden Modus"));
  tft.setCursor(0, 190);
  tft.println(F("Zustand Lastausgang:"));  

  menu_btn.initButton(&tft, 120, 295, 120, 35, WHITE, CYAN, BLACK, "MENU", 2);
  menu_btn.drawButton(false);
  oldPage = currentPage;
}

//Solar Ertrag Historie
void drawSolar1Screen() {
  tft.setTextSize(2); 
  tft.fillScreen(BLACK);
  tft.setTextColor(WHITE,BLACK); 
  tft.setCursor(0, 10);
  tft.println(F("Ertrag heute Wh:"));
  tft.setCursor(0,70);
  tft.println(F("P max heute W:"));
  tft.setCursor(0,140);
  tft.println(F("Ertrag gestern Wh:"));
  tft.setCursor(0,200);
  tft.println(F("P max gestern W:"));

  menu_btn.initButton(&tft, 60, 295, 80, 35, WHITE, CYAN, BLACK, "MENU", 2);
  next_btn.initButton(&tft, 180, 295, 80, 35, WHITE, CYAN, BLACK, "INFO", 2);
  menu_btn.drawButton(false);
  next_btn.drawButton(false);
  oldPage = currentPage;
}

// MPPT Regler Info
void drawSolar2Screen() {
  tft.setTextSize(2); 
  tft.fillScreen(BLACK);
  tft.setTextColor(WHITE,BLACK); 
  tft.setCursor(0, 10);
  tft.println(F("Product ID:"));
  tft.setCursor(0,70);
  tft.println(F("Seriennummer:"));
  tft.setCursor(0,140);
  tft.println(F("Software Version:"));
  tft.setCursor(0,200);

  menu_btn.initButton(&tft,120, 295, 120, 35, WHITE, CYAN, BLACK, "MENU", 2);
  menu_btn.drawButton(false);
  oldPage = currentPage;
}

//Temperatur
void drawTemperaturScreen() {
  tft.fillScreen(BLACK);
  menu_btn.initButton(&tft, 121, 295, 100, 35 , WHITE, CYAN, BLACK, "MENU", 2);
  menu_btn.drawButton(false);
  oldPage = currentPage;
}

//Alarm
void drawAlarmScreen() {
  tft.fillScreen(BLACK);
  tft.setTextSize(2);
  tft.setTextColor(RED,BLACK);
  menu_btn.initButton(&tft,121, 295, 100, 35, WHITE, RED, BLACK, "AUS", 2);
  menu_btn.drawButton(false);
  oldPage = currentPage;
}

/*************************************************************************************************************************************************************************************************************
                                                                                                Funktionen
*************************************************************************************************************************************************************************************************************/
bool Touch_getXY() {
  p = ts.getPoint();
  pinMode(YP, OUTPUT);
  pinMode(XM, OUTPUT);
  digitalWrite(YP, HIGH);
  digitalWrite(XM, HIGH);

  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
    pixel_x = map(p.x, TS_LEFT, TS_RT, 0, tft.width());
    pixel_y = map(p.y, TS_TOP, TS_BOT, 0, tft.height());
    return true;
  }
  return false;
}

void (*resetFunc) (void) = 0;

void redrawButtons() {
  page1_btn.press(down && page1_btn.contains(pixel_x, pixel_y));
  page2_btn.press(down && page2_btn.contains(pixel_x, pixel_y));
  page3_btn.press(down && page3_btn.contains(pixel_x, pixel_y));
  page4_btn.press(down && page4_btn.contains(pixel_x, pixel_y));
  page5_btn.press(down && page5_btn.contains(pixel_x, pixel_y));
  page6_btn.press(down && page6_btn.contains(pixel_x, pixel_y));
  page7_btn.press(down && page7_btn.contains(pixel_x, pixel_y));

  if (page1_btn.justReleased()) page1_btn.drawButton();
  if (page2_btn.justReleased()) page2_btn.drawButton();
  if (page3_btn.justReleased()) page3_btn.drawButton();
  if (page4_btn.justReleased()) page4_btn.drawButton();
  if (page5_btn.justReleased()) page5_btn.drawButton();
  if (page6_btn.justReleased()) page6_btn.drawButton();
  if (page7_btn.justReleased()) page7_btn.drawButton();

  if (page1_btn.justPressed()) changePage(HEIZUNG, page1_btn);
  if (page2_btn.justPressed()) changePage(BATTERIE, page2_btn);
  if (page3_btn.justPressed()) changePage(SOLAR1, page3_btn);
  if (page4_btn.justPressed()) changePage(WETTER, page4_btn);
  if (page5_btn.justPressed()) changePage(SOLAR, page5_btn);
  if (page6_btn.justPressed()) changePage(ALARM, page6_btn);
  if (page7_btn.justPressed()) changePage(SCHEINWERFER, page7_btn);
}

void changePage(unsigned int newPage, Adafruit_GFX_Button &btn) {
  btn.drawButton(true);
  currentPage = newPage;
}

//Heizung Relais schalten
void Heizung() {
  digitalWrite(RELAISHEIZUNG, HIGH);
  delay(1000); 
  digitalWrite(RELAISHEIZUNG, LOW);
  page1_btn.drawButton(false);
}

//Uhrzeit auslesen
void getUhr() {
  char daysOfTheWeek[7][12] = { "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"};

  tft.setTextSize(3);
  tft.setTextColor(WHITE, BLACK);
  tft.setCursor(180, 15);
  DateTime now = rtc.now();
  
//Wochentag
  tft.print(daysOfTheWeek[now.dayOfTheWeek()]);

//Uhrzeit
  tft.setCursor(10, 15);
  if (now.hour() < 10) {
    tft.print(F("0"));
    tft.print(now.hour());
  }
  else{
    tft.print(now.hour(), DEC);
  }
  tft.print(':');
  if (now.minute() < 10) {
    tft.print(F("0"));
    tft.print(now.minute());
  } 
  else{
    tft.print(now.minute(), DEC);
  }
  tft.print(':');
  if (now.second() < 10) {
    tft.print(F("0"));
    tft.print(now.second());
  } 
  else{
    tft.print(now.second(), DEC);
  }
}

void getTemperatur() {  
  float h, te, h_alt, t_alt;
  h = dht.readHumidity();
  te = dht.readTemperature();
  delay(50);
  DS18B20.requestTemperatures();
  float tpa = DS18B20.getTempCByIndex(0);
  
  if (tpa == -127) {
    resetFunc();
  }

  static float lastTe = -1000.0, lastTpa = -1000.0, lastH = -1.0;
  if (te != lastTe || h != lastH || tpa != lastTpa) {
    tft.drawLine(0, 60, tft.width() * 2, 60, WHITE);  // Linie für Innenbereich
    tft.drawLine(0, 185, tft.width() * 2, 185, WHITE); // Linie für Außenbereich
    
    //Innenbereich
    tft.setCursor(10, 70);
    tft.print(F("innen:"));

    int tempColor = (te < 10) ? BLUE : (te >= 10 && te < 25) ? DARKGREEN : RED;
    tft.setTextColor(tempColor, BLACK);
    tft.setCursor(10, 105);
    tft.print(te, 1);
    tft.setTextColor(WHITE, BLACK);
    tft.write(" ");
    tft.write(0xF7);
    tft.write("C");

    int humidityColor = (h < 40) ? BLUE : (h >= 40 && h < 60) ? DARKGREEN : RED;
    tft.setTextColor(humidityColor, BLACK);
    tft.setCursor(10, 145);
    tft.print(h, 1);
    tft.setTextColor(WHITE, BLACK);
    tft.write(" ");
    tft.write("%");

    // Außenbereich
    tft.setTextColor(WHITE, BLACK);
    tft.setCursor(10, 195);
    tft.print(F("aussen:"));

    int outsideTempColor = (tpa < 0) ? BLUE : (tpa >= 0 && tpa < 10) ? BLUE : (tpa >= 10 && tpa < 25) ? DARKGREEN : RED;
    tft.setTextColor(outsideTempColor, BLACK);
    tft.setCursor(10, 235);
    tft.print(tpa, 1);
    tft.setTextColor(WHITE, BLACK);
    tft.write(" ");
    tft.write(0xF7);
    tft.write("C");

    lastTe = te;
    lastTpa = tpa;
    lastH = h;
  }
}

void ReadVEData1(){
  if (Serial1.available()) {
    //Serial.println("serial1 ok ");
    myve1.rxData(Serial1.read());
  }
}

void ReadVEData2(){
  while (Serial2.available()) {
    //Serial.println("serial2 ok ");
    myve2.rxData(Serial2.read());
  }
}

//Shunt Werte
void getShunt() {
  tft.setTextSize(2);
  for (int i = 0; i < myve2.veEnd; i++) {
    Serial.print(myve2.veName[i]);
    Serial.print("= ");
    Serial.println(myve2.veValue[i]);
    
    if (strcmp(myve2.veName[i], "V") == 0) {
      float value = atof(myve2.veValue[i]);  
      float result = value / 1000;
      tft.setTextColor(WHITE,BLACK);
      tft.setCursor(90, 35);
      tft.println(result);
    }
  
    else if (strcmp(myve2.veName[i], "SOC") == 0) {
      float value = atof(myve2.veValue[i]);  
      float result = value / 10;
      tft.setTextColor(WHITE,BLACK);
      tft.setCursor(90, 215);
      tft.println(result);
    }
  
    else if (strcmp(myve2.veName[i], "CE") == 0) {
      float value = atof(myve2.veValue[i]);  
      float result = value / 1000;
      tft.setTextColor(WHITE,BLACK);
      tft.setCursor(90, 155);
      tft.println(result);
    }
  
    else if (strcmp(myve2.veName[i], "I") == 0) {
      float value = atof(myve2.veValue[i]);  
      float result = value / 1000;
      if (value < 0) {
        tft.setTextColor(RED,BLACK);
        tft.setCursor(90, 95);
        tft.println(result);
      }
      else {
        tft.setTextColor(BLUE,BLACK);
        tft.setCursor(90, 95);
        tft.print("");
        tft.println(result);
      } 
    }
  }
}

//Solar Werte Panel
void getSolar() {
  tft.setTextColor(WHITE,BLACK);
  tft.setTextSize(2);
  for (int i = 0; i < myve1.veEnd; i++) {
    if (strcmp(myve1.veName[i], "PPV") == 0) {
      float value = atof(myve1.veValue[i]);  
      float result = value;
      tft.setTextColor(WHITE,BLACK); 
      tft.setCursor(90, 35);
      tft.println(result);
    }
  
    else if (strcmp(myve1.veName[i], "VPV") == 0) {
      float value = atof(myve1.veValue[i]);  
      float result = value /1000;
      tft.setCursor(90, 95);
      tft.println(result);
    }
 
    else if (strcmp(myve1.veName[i], "CS") == 0) {
      float value = atof(myve1.veValue[i]);  
      float result = value;
      if (value == 2) {
        tft.setTextColor(RED,BLACK);
        tft.setCursor(90,155);
        tft.write("Error");
      }
      else if (value == 3) {
        tft.setCursor(90,155);
        tft.write("BULK  ");
      }
      else if (value == 4) {
        tft.setCursor(90,155);
        tft.write("ABS   ");
      }
      else if (value == 5) {
        tft.setCursor(90,155);
        tft.write("FLOAT ");
      }
      else {
        tft.setCursor(90,155);
        tft.write("AUS ");
      }
    }
  
    else if (strcmp(myve1.veName[i], "LOAD") == 0) {
      tft.setTextColor(WHITE,BLACK);
      tft.setCursor(90, 215);
      tft.println(myve1.veValue[i]);
    }
  }
}

//Solar Ertrag
void getSolar1() {
  tft.setTextColor(WHITE,BLACK);
  tft.setTextSize(2);
  for (int i = 0; i < myve1.veEnd; i++) {
    if (strcmp(myve1.veName[i], "H20") == 0) {
      float value = atof(myve1.veValue[i]);  
      float result = value *10;
      tft.setCursor(90, 35);
      tft.println(result);
    }
  
    else if (strcmp(myve1.veName[i], "H21") == 0) {
      tft.setCursor(90, 95);
      tft.println(myve1.veValue[i]);
    }
  
    else if (strcmp(myve1.veName[i], "H22") == 0) {
      float value = atof(myve1.veValue[i]);  
      float result = value *10;
      tft.setCursor(90, 165);
      tft.println(result);
    }
  
    else if (strcmp(myve1.veName[i], "H23") == 0) {
      tft.setCursor(90, 225);
      tft.println(myve1.veValue[i]);
    }
  }
}

//MPPT Regler Daten
void getSolar2() {
  tft.setTextColor(WHITE,BLACK);
  tft.setTextSize(2);
  for (int i = 0; i < myve1.veEnd; i++) {
    if (strcmp(myve1.veName[i], "PID") == 0) {
      tft.setCursor(90, 35);
      tft.println(myve1.veValue[i]);
    }
 
    else if (strcmp(myve1.veName[i], "SER#") == 0) {
      tft.setCursor(60, 100);
      tft.println(myve1.veValue[i]);
    }
  
    else if (strcmp(myve1.veName[i], "FW") == 0) {
      float value = atof(myve1.veValue[i]);  
      float result = value /100;
      tft.setCursor(90, 165);
      tft.println(result);
    }
  }
}

hex frame callback function
void HexCallback(const char* buffer, int size, void* data) {
    char tmp[100];
    memcpy(tmp, buffer, size*sizeof(char));
    tmp[size]=0;
    Serial.print("received hex frame: ");
    Serial.println(tmp);
}

log helper
void LogHelper(const char* module, const char* error) {
    Serial.print(module);
    Serial.print(":");
    Serial.println(error);
}

//Abfrage Kontakt für MX Alarm
void Sabotage() {
 
}

//Arbeitsscheinwerfer schalten
void Scheinwerfer() {
  static boolean status=false;
  status = digitalRead(RELAISSCHEINWERFER);
  if (status == LOW) {
    digitalWrite(RELAISSCHEINWERFER, HIGH);
    delay(1000);
    page7_btn.drawButton(false);
  }  
  if (status == HIGH) {
    digitalWrite(RELAISSCHEINWERFER, LOW);
    delay(1000);
    page7_btn.drawButton(false);
  }  
}

//Bluetooth schalten
void Bluetooth() {
 
}

Der Sketch verwendet 38418 Bytes (15%) des Programmspeicherplatzes. Das Maximum sind 253952 Bytes.
Globale Variablen verwenden 7282 Bytes (88%) des dynamischen Speichers, 910 Bytes für lokale Variablen verbleiben. Das Maximum sind 8192 Bytes.

Ok, das ist zuviel.
Dann muss ich mal sehen, was sich da machen lässt.
Hab ja grad erfolgreich fast 50% Speicher im anderen Thread gewonnen :slight_smile:

Ich nehm Deinen Code mal mit.

????

exit status 1
'class VeDirectFrameHandler' has no member named 'setErrorHandler'; did you mean 'VeDirectFrameHandler'?

Irgendwas passt nicht.

ja, ich muss gestehen, dass ich auf die Funktion gar nicht so sehr geachtet habe. Was macht die? Das ist von deinem Test heute

Der Sketch verwendet 5266 Bytes (2%) des Programmspeicherplatzes. Das Maximum sind 253952 Bytes.
Globale Variablen verwenden 6162 Bytes (75%) des dynamischen Speichers, 2030 Bytes für lokale Variablen verbleiben. Das Maximum sind 8192 Bytes.

Oh, das war aus einer anderen Bibliothek mit der ich getestet hatte. Vergessen. Sorry. Das war eigentlich auskommentiert. Glaub ich verlier vor lauter Testen schon den überblick :slight_smile:

Das ist schlecht.

Das mit dem Speicherverbrauch ist richtig.
In der Referenzimplementierung ist die Definition an die mögliche Feldgröße aus den BMV gebunden.

const byte nameLen = 9;                         // VE.Direct Protocol: max name size is 9 including /0
const byte valueLen = 33;                       // VE.Direct Protocol: max value size is 33 including /0
const byte buffLen = 40;                        // Maximum number of lines possible from the device. Current protocol shows this to be the BMV700 at 33 lines.


class VeDirectFrameHandler {

public:
    VeDirectFrameHandler();
    void rxData(uint8_t inbyte);                // byte of serial data to be passed by the application

    char veName[buffLen][nameLen] = { };        // public buffer for received names
    char veValue[buffLen][valueLen] = { };      // public buffer for received values

Also 40 x 9 und 40 x 33 Bytes allein für die Bereitstellung.
Darum wollte ich ja sehen, ob und was Du heraus bekommst.
Dann könnte man das evtl. umschreiben und die Felder kleiner machen....

ok. Klingt logisch. Ich überlasse dir das mal mit dem umschreiben, ehrlich gesagt steig ich da nicht so ganz durch. Mit der Berechnung der Größe etc.

Start 0
H17= 101
H18= 66

H3= 0
H4= 0
H5= 0
H6= -76825
H7= 12712
H8= 15134
H9= 351057
H10= 0
H11= 0
H12= 0
H15= 0
H16= 0
H17= 101
H18= 66
Start...
VE 1VE 2VE 1PID= 0XA060
FW= 164
SER#= HQ2423Q2KQP
V= 13270
I= -280
VPV= 10
PPV= 0
CS= 0
MPPT= 0
OR= 0X00000001
ERR= 0
LOAD= ON
IL= 200
H19= 330
H20= 0
H21= 0
H22= 0
H23= 0
HSDS= 73
VE 2H1= -24834
H2= -24834
H3= 0
H4= 0
H5= 0
H6= -76826
H7= 12712
H8= 15134
H9= 351060
H10= 0
H11= 0
H12= 0
H15= 0
H16= 0
H17= 101
H18= 66
PID= 0XC038
V= 13306
I= -367
P= -5
CE= -24834
SOC= 784
TTG= 13141
ALARM= OFF
AR= 0
BMV= SMARTSHUNT 300A
FW= 0418
MON= 0
VE 1PID= 0XA060
FW= 164
SER#= HQ2423Q2KQP
V= 13270
I= -280
VPV= 10
PPV= 0
CS= 0
MPPT= 0
OR= 0X00000001
ERR= 0
LOAD= ON
IL= 200
H19= 330
H20= 0
H21= 0
H22= 0
H23= 0
HSDS= 73
VE 2H1= -24834
H2= -24834
H3= 0
H4= 0
H5= 0
H6= -76826
H7= 12712
H8= 15134
H9= 351060
H10= 0
H11= 0
H12= 0
H15= 0
H16= 0
H17= 101
H18= 66
PID= 0XC038
V= 13307
I= -368
P= -5
CE= -24834
SOC= 784
TTG= 13135
ALARM= OFF
AR= 0
BMV= SMARTSHUNT 300A
FW= 0418
MON= 0
VE 1PID= 0XA060
FW= 164
SER#= HQ2423Q2KQP
V= 13270
I= -280
VPV= 10
PPV= 0
CS= 0
MPPT= 0
OR= 0X00000001
ERR= 0
LOAD= ON
IL= 200
H19= 330
H20= 0
H21= 0
H22= 0
H23= 0
HSDS= 73
VE 2H1= -24834
H2= -24834
H3= 0
H4= 0
H5= 0
H6= -76826
H7= 12712
H8= 15134
H9= 351063
H10= 0
H11= 0
H12= 0
H15= 0
H16= 0
H17= 101
H18= 66
PID= 0XC038
V= 13307
I= -368
P= -5
CE= -24834
SOC= 784
TTG= 13128
ALARM= OFF
AR= 0
BMV= SMARTSHUNT 300A
FW= 0418
MON= 0
VE 1PID= 0XA060
FW= 164
SER#= HQ2423Q2KQP
V= 13270
I= -280
VPV= 10
PPV= 0
CS= 0
MPPT= 0
OR= 0X00000001
ERR= 0
LOAD= ON
IL= 200
H19= 330
H20= 0
H21= 0
H22= 0
H23= 0
HSDS= 73
VE 2H1= -24834
H2= -24834
H3= 0
H4= 0
H5= 0
H6= -76826
H7= 12712
H8= 15134
H9= 351064
H10= 0
H11= 0
H12= 0
H15= 0
H16= 0
H17= 101
H18= 66
PID= 0XC038
V= 13306
I= -368
P= -5
CE= -24834
SOC= 784
TTG= 13120
ALARM= OFF
AR= 0
BMV= SMARTSHUNT 300A
FW= 0418
MON= 0
VE 1PID= 0XA060
FW= 164
SER#= HQ2423Q2KQP
V= 13270
I= -280
VPV= 10
PPV= 0
CS= 0
MPPT= 0
OR= 0X00000001
ERR= 0
LOAD= ON
IL= 200
H19= 330
H20= 0
H21= 0
H22= 0
H23= 0
HSDS= 73
VE 2H1= -24834
H2= -24834
H3= 0
H4= 0
H5= 0
H6= -76826

Sorry, hab ich verpeilt. Du wolltest eine Ausgabe sehen. Hatte ich nicht verstanden. Das hier kommt bei deinem Code raus. Wie es sein soll.

1 Like

kommen immer 28 Zeilen. Dann können wir es kürzen oder?
Beim MPPT sind es nur 18 oder 19.

Ich muss mal schauen, ob für alle der Datensatz der selbe ist.
Aber vermutlich nicht.
Welcher MPPT ist das?

Ein 100/20 und ein 300A shunt. Bei den kleinen MPPT sollten laut victron Doku immer die selben Daten übertragen werden

1 Like

Ich habe jetzt mal aus Interesse mal die Werte geändert. Da komme ich wenn ich die Werte so anpasse, dass es meiner Meinung nach für die Zeichen ausreicht schon nur noch auf 41% Speicher Verbrauch. Das ist ja schon mal eine andere Nummer. Wo kann ich denn sehen, wie lange ein Frame ist? Braucht man da die 22?

Theoretisch...
Wenn Du Deine Ausgabe zerlegst, kommst Du bei VE 1 auf 19 Einträge und der längste ist die Seriennummer mit 11 Zeichen (+1 für \0)
Bei VE 2 sinds schon 28 Einträge und der längste ist der Bezeichner mit 15 (+1)
Bei den Bezeichnern ist ALARM der längste. Du könntest jetzt also auf 6 / 16 für die Feldlängen und 20 Elemente gehen.

Ich bin nur noch nicht vom Konzept überzeugt und überleg seit gestern ob man evtl. doch was eigenes baut. Es fehlt mir blos noch die zündende Idee. Aber ich arbeite dran :wink:

ok. Danke dir schon mal.

Gut, ich hab mir mal Gedanken gemacht...
Ich werd etwas komplett neues schreiben und für jeden Wert eine Funktion bauen, die die empfangenen Zeichen gleich in Zahlen (Soweit Zahlenwerte gegeben) oder in Zustände (z.B. Alarm) umwandelt.
Die Frage die ich jetzt habe, welche Werte brauchst Du zwingend?
Mit denen würde ich dann anfangen und zum testen geben.