Victron MPPT Regler mit VEdirect

Hallo,
ich versuche mit einem Arduino Mega einen Victron MPPT Regler und einen Shunt über Vedirect auszulesen und die Daten auf einem TFT anzuzeigen. Das auslesen an sich funtioniert so auch ganz Ok. Allerdings bekomme ich die Checksumme nicht hin und kann somit die Volständigkeit der Daten nicht prüfen. Es hat hier schon mal jemand für ein Wohnmobil Projekt unterstützt, der das gut hinbekommen hat. Leider schaffe ich es nicht die Prüfung der Checksumme in meinen Sketch zu integrieren. Hat evtl. jemand Lust sich das mal anzuschauen?

Der "jemand" ist @my_xy_projekt, der sich im Thema Bluetooth mit WLAN verlängern mit vergleichbaren Dingen beschäftigt. Allerdings bist Du schon weiter, Du bekommst immerhin schon Daten. Möglicherweise lassen sich ja Synergien nutzen :wink:

Super, genau der ist das. Die Frage ist, wie kann ich jemand hier im Forum kontaktieren?

In dem du deine Frage hier stellst. Und ein @Name hinzufügst.

super Danke dir.

Dadurch, daß ich ihn erwähnt habe, ist er schon benachrichtigt worden.

Im nächsten Schritt könntest Du Dein bisheriges, um die Prüfzahl zu erweiterndes Programm hier zeigen und was es im seriellen Monitor oder auf dem Display anzeigt. Da sollte auch die von Dir errechnete und die übertragene Prüfzahl vorkommen.

Auf diesen Infos kann man dann eine Hilfe aufbauen :slightly_smiling_face:

Ok. Das wird jetzt wohl dann peinlich für mich, aber da muss ich wohl durch :hugs:

//**********************************************
// Display Typ zuweisen  1 = True Components   *
#define Display 0     /* 0 = AzDelivery        *
***********************************************/

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

// Fastwrite Pin Steuerung
#include <digitalWriteFast.h>

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

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

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

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

#if Display
//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;
#else
//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;
#endif

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

// tft Button
Adafruit_GFX_Button on_btn, off_btn, page1_btn, page2_btn, page3_btn, page4_btn, page5_btn, page6_btn, page7_btn;;
Adafruit_GFX_Button ok_btn, cncl_btn, plus_btn, minus_btn;
Adafruit_GFX_Button menu_btn, info_btn, back_btn, next_btn;
int pixel_x, pixel_y;

//Button entprellen
unsigned long lastPressTime = 0;
const unsigned long debounceDelay = 950; // Entprellzeit

// Relais Heizung
constexpr int RELAISHEIZUNG = 52; 

// Aktor Alarm
constexpr int RELAISINNENLICHT = 29;

// Relais Arbeitsscheinwerfer
constexpr int RELAISSCHEINWERFER = 22;

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

// Timer 
unsigned long Timer1500 = 1500;
unsigned long Timer2500 = 2500;
unsigned long Timer5000 = 5000;

unsigned long oldMillis_1500 = 0;
unsigned long oldMillis_2500 = 0;
unsigned long oldMillis_5000 = 0;

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

// Victron MPPT + Shunt
char buf[33];
char bufShunt[33];

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

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

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

bool down ;
void loop(void) {
  down = Touch_getXY();
  switch (currentPage) {
    case MENU:
      if (currentPage != oldPage)   drawMenuScreen();
      redrawButtons();
      
      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);
      break;

    case HEIZUNG:
      if (currentPage != oldPage) {
        Heizung();
        currentPage = MENU;
      }
      break;
    
    case WETTER:
      if (currentPage != oldPage) drawWetterScreen();
        getUhr();
        if (millis() - oldMillis_1500 >= Timer1500) {
        getTemperatur();
        oldMillis_1500 = millis();
        }
                              
      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));

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

      if (millis() - lastPressTime > debounceDelay) {
        if (menu_btn.justPressed()) {
          menu_btn.drawButton(true);
          currentPage = MENU;
          lastPressTime = millis();
        }
      }
      break;

    case BATTERIE:
      if (currentPage != oldPage)   drawBatterieScreen();
      getShunt();
             
      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));
      
      if (menu_btn.justReleased())
        menu_btn.drawButton();

      if (millis() - lastPressTime > debounceDelay) {
        if (menu_btn.justPressed()) {
          menu_btn.drawButton(true);
          currentPage = MENU;
          lastPressTime = millis();
        }
      }
      break;      

    case SOLAR:
      if (currentPage != oldPage)   drawSolarScreen();
      getSolar();
       
      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 (millis() - lastPressTime > debounceDelay) {
        if (menu_btn.justPressed()) {
          menu_btn.drawButton(true);
          currentPage = MENU;
          lastPressTime = millis();
        }
      }
      break;

    case SOLAR1:
      if (currentPage != oldPage)   drawSolar1Screen();
      getSolar1();
      
      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 (millis() - lastPressTime > debounceDelay) {
        if (menu_btn.justPressed()) {
          menu_btn.drawButton(true);
          currentPage = MENU;
          lastPressTime = millis();
        }
      }
      if (millis() - lastPressTime > debounceDelay) {
        if (next_btn.justPressed()) {
          next_btn.drawButton(true);
          currentPage = SOLAR2;
          lastPressTime = millis();
        }
      }
      break;

    case SOLAR2:
      if (currentPage != oldPage)   drawSolar2Screen();
      getSolar2();
      
      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));
      
      if (menu_btn.justReleased())
        menu_btn.drawButton();
      
      if (millis() - lastPressTime > debounceDelay) {
        if (menu_btn.justPressed()) {
          menu_btn.drawButton(true);
          currentPage = MENU;
          lastPressTime = millis();
        }
      }
      break;
    
    case ALARM:
      if (currentPage != oldPage) drawAlarmScreen();
      Ausgeloest();
      if (millis() - oldMillis_2500 >= Timer1500) {
        getUhr();
        getTemperatur();       
        oldMillis_2500 = millis();
        }

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

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

/*  if (oldPage == currentPage) {
    down = Touch_getXY();
  } 
  else {
    down = false;
  }*/
  Sabotage();
  Bluetooth();
}

/**********************************************************************************************************************************************************************************************************************************
                                                                                                   SCREENS 
***********************************************************************************************************************************************************************************************************************************/
// Hauptbildschirm
void drawMenuScreen() {
  Alarm_ausgeloest = 0;
  tft.fillScreen(BLACK);
  tft.setTextColor(BLUE);
  digitalWriteFast(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;
}

// Farbe Scheinwerfer Button nach Zustand ändern
void updateScheinwerferButton() {
  if (digitalReadFast(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);
}

// Shunt Werte 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, Modus Laden, Zustand Lastausgang
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 heute und gestern
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,130);
  tft.println(F("Ertrag gestern Wh:"));
  tft.setCursor(0,190);
  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 Product ID, Seriennummer, Sofwarestand
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,130);
  tft.println(F("Software Version:"));
  tft.setCursor(0,190);

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

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

// Alarm, Temperatur, Uhrzeit
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
*************************************************************************************************************************************************************************************************************************************/
//Touch display
bool Touch_getXY() {
  p = ts.getPoint();
  pinModeFast(YP, OUTPUT);
  pinModeFast(XM, OUTPUT);
  digitalWriteFast(YP, HIGH);
  digitalWriteFast(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 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();
}

void changePage(unsigned int newPage, Adafruit_GFX_Button &btn) {
  if (millis() - lastPressTime > debounceDelay) {
    btn.drawButton(true);
    currentPage = newPage;
    lastPressTime = millis();
  }
}

//Heizung Relais schalten
void Heizung() {
  digitalWriteFast(RELAISHEIZUNG, HIGH);
  delay(1000); 
  digitalWriteFast(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();
  DS18B20.requestTemperatures();
  float tpa = DS18B20.getTempCByIndex(0);
  
  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);
    tft.drawLine(0, 185, tft.width() * 2, 185, WHITE);
    
    // 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;
  }
}

//*******************************************************************Shunt Werte***********************************************************
void getShunt() {
  if (Serial2.available() > 0) {
    char firstChar = Serial2.peek();  

    // Falls HEX-Daten erkannt werden, ignorieren
    if (firstChar < 32 || firstChar > 126) {
      Serial2.read();  
      return;
    }

    String labelS = Serial2.readStringUntil('\t');  
    String valS = Serial2.readStringUntil('\n');  
    valS.trim();  
    
    Serial.println(labelS);
    Serial.println(valS);

    valS.toCharArray(bufShunt, sizeof(bufShunt));  
    float messwert = atof(bufShunt); 

     tft.setTextSize(2);

    // Batterieladung (SOC)
    if (labelS == "SOC") {
      float result = messwert / 10;  
      tft.setTextColor(WHITE, BLACK);
      tft.setCursor(90, 215);
      tft.println(static_cast<int>(result));  
    }

    // Batteriespannung (V)
    else if (labelS == "V") {
      float result = messwert / 1000.0;  
      tft.setTextColor(WHITE, BLACK);
      tft.setCursor(90, 35);
      tft.println(result);
    }

    // Ladestrom (I)
    else if (labelS == "I") {
      float result = messwert / 1000.0;  
      tft.setCursor(90, 95);
           
      if (messwert < 0) {
        tft.setTextColor(RED, BLACK);  
      } 
      else {
        tft.print(" ");
        tft.setTextColor(BLUE, BLACK);  
      }
      tft.println(result);
    }

    // Verbrauchte Ah (CE)
    else if (labelS == "CE") {
      float result = messwert / 1000.0;  
      tft.setTextColor(WHITE, BLACK);
      tft.setCursor(90, 155);
      tft.println(static_cast<int>(result));  
    }
  }
}

//*******************************************************************Solar Werte Panel*****************************************************
void getSolar() {
  if (Serial1.available() > 0) {
    char firstChar = Serial1.peek();  

    // Falls HEX-Daten erkannt werden, ignorieren
    if (firstChar < 32 || firstChar > 126) {
      Serial1.read();  
      return;
    }

    String label = Serial1.readStringUntil('\t');
    String val = Serial1.readStringUntil('\n');
    val.trim(); 

    Serial.println(label);
    Serial.println(val);

    val.toCharArray(buf, sizeof(buf));  
    float messwert = atof(buf);  

    // Solarleistung (PPV)
    if (label == "PPV") {
      tft.setTextColor(WHITE, BLACK);
      tft.setCursor(90, 35);
      tft.println(static_cast<int>(messwert)); 
    }

    // Solarspannung (VPV)
    else if (label == "VPV") {
      tft.setCursor(90, 95);
      tft.println(messwert / 1000.0); 
    }

    // Lademodus (CS)
    else if (label == "CS") {
      int mode = val.toInt();
      tft.setCursor(90, 155);

      if (mode == 2) {
        tft.setTextColor(RED, BLACK);
        tft.println("Error");
      }
      else if (mode == 3) {
        tft.setTextColor(BLUE, BLACK);
        tft.println("BULK  ");
      }
      else if (mode == 4) {
        tft.setTextColor(BLUE, BLACK);
        tft.println("ABS   ");
      }
      else if (mode == 5) {
        tft.setTextColor(BLUE, BLACK);
        tft.println("FLOAT ");
      }
      else {
        tft.setCursor(90, 155);
        tft.println("OFF ");
      }
    }

    // Lastausgang (LOAD)
    else if (label == "LOAD") {
      tft.setTextColor(WHITE, BLACK);
      tft.setCursor(90, 215);
      tft.println(val);
    }
  }
}

//*******************************************************************Solar Ertrag**********************************************************
void getSolar1() {
  if (Serial1.available() > 0) {
    char firstChar = Serial1.peek();  

    // Falls HEX-Daten erkannt werden, ignorieren
    if (firstChar < 32 || firstChar > 126) {
      Serial1.read();  
      return;
    }

    String labelE = Serial1.readStringUntil('\t');  
    String valE = Serial1.readStringUntil('\n');    
    valE.trim();  

    Serial.println(labelE);
    Serial.println(valE);

    valE.toCharArray(buf, sizeof(buf));  
    float messwert = atof(buf);  

    tft.setTextSize(2);
    tft.setTextColor(WHITE, BLACK);  

    // Solar Ertrag heute (H20)
    if (labelE == "H20") {
      tft.setCursor(90, 35);
      tft.println(static_cast<int>(messwert * 10));  
    }

    // Max. Solar Leistung heute (H21)
    else if (labelE == "H21") {
      tft.setCursor(90, 95);
      tft.println(static_cast<int>(messwert));
    }

    // Solar Ertrag gestern (H22)
    else if (labelE == "H22") {
      tft.setTextColor(WHITE, BLACK);  // Andere Farbe für gestern
      tft.setCursor(90, 155);
      tft.println(static_cast<int>(messwert * 10));
    }

    // Max. Solar Leistung gestern (H23)
    else if (labelE == "H23") {
      tft.setTextColor(WHITE, BLACK); 
      tft.setCursor(90, 215);
      tft.println(static_cast<int>(messwert));
    }
  }
}

//*******************************************************************MPPT Regler Daten*****************************************************
void getSolar2() {
  static String PID = "";  
  static String SER = "";  

  if (Serial1.available() > 0) {
    char firstChar = Serial1.peek();

    // Falls HEX-Daten erkannt werden, ignorieren
    if (firstChar < 32 || firstChar > 126) {
      Serial1.read();  
      return;
    }

    String labelD = Serial1.readStringUntil('\t');  
    String valD = Serial1.readStringUntil('\n');    
    valD.trim();  

    Serial.println(labelD);
    Serial.println(valD);

    tft.setTextSize(2);
    tft.setTextColor(WHITE, BLACK);  

    // Produkt ID (PID)
    if (labelD == "PID") {
      PID = valD;  
      tft.setCursor(50, 35);
      tft.println(PID);
    }

    // Seriennummer (SER#)
    else if (labelD == "SER#") {
      SER = valD;  
      tft.setCursor(30, 95);
      tft.println(SER);
    }

    // Firmware Version (FW)
    else if (labelD == "FW") {
      valD.toCharArray(buf, sizeof(buf));
      float messwert = atof(buf);
      float result = messwert / 100;

      tft.setCursor(70, 155);
      tft.println(result);
    }
  }
}

nicht wundern. Der Teil ab dem Alarm ist bewußt nicht veröffentlicht.

Guten Tag....
ALSO!
Ich hab das ja alles schon mal gemacht - das wird auch für Dich fertig werden.

Die Frage ist: Da Du bereits eine funktinierende Konfiguration hast: Würdest Du Dich darauf einlassen für mich mal was auszutesten?
Dann brauchst Du das alles nicht selber machen.

Wenn das so funktioniert, wie ich das will, dann gibt es von mir eine Kurzdoku auch für alle anderen, in der Hoffnung was allgemein gültiges zu erstellen und einige Leute glücklich zu machen.

Auf Deine Code schaue ich nebenbei gleich mal. Allerdings ist das Wifi der Bahn heute zickig, was meine Verfügbarkeit etwas einschränkt.

Nee, nur für die, die dumme Bemerkungen machen. "Ein Programm, das tut, was es soll, ist ein gutes Prigramm!" hat mir @Serenifly in meinen Anfängen mal geschrieben.

Hättest Du die Funktionen geleert und nicht gelöscht, wäre das Programm compilierbar geblieben :wink:

Kurz mal drauf geschaut.
Da ist noch ganz viel Baustelle, was die Wiederverwendbarkeit von Code angeht.
Da muss einiges gekürzt werden :slight_smile:

Und ich kann Dir schonmal sagen, dass das hier:

    else if (labelD == "FW")
    {
      valD.toCharArray(buf, sizeof(buf));
      float messwert = atof(buf);
      float result = messwert / 100;
      tft.setCursor(70, 155);
      tft.println(result);
    }

nicht das macht, was es soll.

Du kannst aus dem Regler eine Antwort bekommen, die z.B. C343 heisst.
Daraus wird dann: FW: 3.43 RelaeseCandidate C

Den Rest löse ich auf, wenn ich erstmal rausgefunden habe, was Du da alles für libs drin hast, damit ich irgendwelchen kompilierbaren Code bauen kann.

ok. Dann stelle ich den Code noch einmal mit mit leeren Funktionen rein.

//**********************************************
// Display Typ zuweisen  1 = True Components   *
#define Display 0     /* 0 = AzDelivery        *
***********************************************/

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

// Fastwrite Pin Steuerung
#include <digitalWriteFast.h>

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

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

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

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

#if Display
//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;
#else
//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;
#endif

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

// tft Button
Adafruit_GFX_Button on_btn, off_btn, page1_btn, page2_btn, page3_btn, page4_btn, page5_btn, page6_btn, page7_btn;;
Adafruit_GFX_Button ok_btn, cncl_btn, plus_btn, minus_btn;
Adafruit_GFX_Button menu_btn, info_btn, back_btn, next_btn;
int pixel_x, pixel_y;

//Button entprellen
unsigned long lastPressTime = 0;
const unsigned long debounceDelay = 950; // Entprellzeit

// Relais Heizung
constexpr int RELAISHEIZUNG = 52; 

// Aktor Alarm
constexpr int RELAISINNENLICHT = 29;

// Relais Arbeitsscheinwerfer
constexpr int RELAISSCHEINWERFER = 22;

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

// Timer 
unsigned long Timer1500 = 1500;
unsigned long Timer2500 = 2500;
unsigned long Timer5000 = 5000;

unsigned long oldMillis_1500 = 0;
unsigned long oldMillis_2500 = 0;
unsigned long oldMillis_5000 = 0;

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

// Victron MPPT + Shunt
char buf[33];
char bufShunt[33];

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

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

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

bool down ;
void loop(void) {
  down = Touch_getXY();
  switch (currentPage) {
    case MENU:
      if (currentPage != oldPage)   drawMenuScreen();
      redrawButtons();
      
      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);
      break;

    case HEIZUNG:
      if (currentPage != oldPage) {
        Heizung();
        currentPage = MENU;
      }
      break;
    
    case WETTER:
      if (currentPage != oldPage) drawWetterScreen();
        getUhr();
        if (millis() - oldMillis_1500 >= Timer1500) {
        getTemperatur();
        oldMillis_1500 = millis();
        }
                              
      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));

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

      if (millis() - lastPressTime > debounceDelay) {
        if (menu_btn.justPressed()) {
          menu_btn.drawButton(true);
          currentPage = MENU;
          lastPressTime = millis();
        }
      }
      break;

    case BATTERIE:
      if (currentPage != oldPage)   drawBatterieScreen();
      getShunt();
             
      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));
      
      if (menu_btn.justReleased())
        menu_btn.drawButton();

      if (millis() - lastPressTime > debounceDelay) {
        if (menu_btn.justPressed()) {
          menu_btn.drawButton(true);
          currentPage = MENU;
          lastPressTime = millis();
        }
      }
      break;      

    case SOLAR:
      if (currentPage != oldPage)   drawSolarScreen();
      getSolar();
       
      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 (millis() - lastPressTime > debounceDelay) {
        if (menu_btn.justPressed()) {
          menu_btn.drawButton(true);
          currentPage = MENU;
          lastPressTime = millis();
        }
      }
      break;

    case SOLAR1:
      if (currentPage != oldPage)   drawSolar1Screen();
      getSolar1();
      
      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 (millis() - lastPressTime > debounceDelay) {
        if (menu_btn.justPressed()) {
          menu_btn.drawButton(true);
          currentPage = MENU;
          lastPressTime = millis();
        }
      }
      if (millis() - lastPressTime > debounceDelay) {
        if (next_btn.justPressed()) {
          next_btn.drawButton(true);
          currentPage = SOLAR2;
          lastPressTime = millis();
        }
      }
      break;

    case SOLAR2:
      if (currentPage != oldPage)   drawSolar2Screen();
      getSolar2();
      
      menu_btn.press(down && menu_btn.contains(pixel_x, pixel_y));
      
      if (menu_btn.justReleased())
        menu_btn.drawButton();
      
      if (millis() - lastPressTime > debounceDelay) {
        if (menu_btn.justPressed()) {
          menu_btn.drawButton(true);
          currentPage = MENU;
          lastPressTime = millis();
        }
      }
      break;
    
    case ALARM:
      if (currentPage != oldPage) drawAlarmScreen();
      Ausgeloest();
      if (millis() - oldMillis_2500 >= Timer1500) {
        getUhr();
        getTemperatur();       
        oldMillis_2500 = millis();
        }

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

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

/*  if (oldPage == currentPage) {
    down = Touch_getXY();
  } 
  else {
    down = false;
  }*/
  Sabotage();
  Bluetooth();
}

/**********************************************************************************************************************************************************************************************************************************
                                                                                                   SCREENS 
***********************************************************************************************************************************************************************************************************************************/
// Hauptbildschirm
void drawMenuScreen() {
  Alarm_ausgeloest = 0;
  tft.fillScreen(BLACK);
  tft.setTextColor(BLUE);
  digitalWriteFast(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;
}

// Farbe Scheinwerfer Button nach Zustand ändern
void updateScheinwerferButton() {
  if (digitalReadFast(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);
}

// Shunt Werte 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, Modus Laden, Zustand Lastausgang
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 heute und gestern
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,130);
  tft.println(F("Ertrag gestern Wh:"));
  tft.setCursor(0,190);
  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 Product ID, Seriennummer, Sofwarestand
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,130);
  tft.println(F("Software Version:"));
  tft.setCursor(0,190);

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

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

// Alarm, Temperatur, Uhrzeit
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
*************************************************************************************************************************************************************************************************************************************/
//Touch display
bool Touch_getXY() {
  p = ts.getPoint();
  pinModeFast(YP, OUTPUT);
  pinModeFast(XM, OUTPUT);
  digitalWriteFast(YP, HIGH);
  digitalWriteFast(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 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();
}

void changePage(unsigned int newPage, Adafruit_GFX_Button &btn) {
  if (millis() - lastPressTime > debounceDelay) {
    btn.drawButton(true);
    currentPage = newPage;
    lastPressTime = millis();
  }
}

//Heizung Relais schalten
void Heizung() {
  digitalWriteFast(RELAISHEIZUNG, HIGH);
  delay(1000); 
  digitalWriteFast(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();
  DS18B20.requestTemperatures();
  float tpa = DS18B20.getTempCByIndex(0);
  
  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);
    tft.drawLine(0, 185, tft.width() * 2, 185, WHITE);
    
    // 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;
  }
}

//*******************************************************************Shunt Werte***********************************************************
void getShunt() {
  if (Serial2.available() > 0) {
    char firstChar = Serial2.peek();  

    // Falls HEX-Daten erkannt werden, ignorieren
    if (firstChar < 32 || firstChar > 126) {
      Serial2.read();  
      return;
    }

    String labelS = Serial2.readStringUntil('\t');  
    String valS = Serial2.readStringUntil('\n');  
    valS.trim();  
    
    Serial.println(labelS);
    Serial.println(valS);

    valS.toCharArray(bufShunt, sizeof(bufShunt));  
    float messwert = atof(bufShunt); 

     tft.setTextSize(2);

    // Batterieladung (SOC)
    if (labelS == "SOC") {
      float result = messwert / 10;  
      tft.setTextColor(WHITE, BLACK);
      tft.setCursor(90, 215);
      tft.println(static_cast<int>(result));  
    }

    // Batteriespannung (V)
    else if (labelS == "V") {
      float result = messwert / 1000.0;  
      tft.setTextColor(WHITE, BLACK);
      tft.setCursor(90, 35);
      tft.println(result);
    }

    // Ladestrom (I)
    else if (labelS == "I") {
      float result = messwert / 1000.0;  
      tft.setCursor(90, 95);
           
      if (messwert < 0) {
        tft.setTextColor(RED, BLACK);  
      } 
      else {
        tft.print(" ");
        tft.setTextColor(BLUE, BLACK);  
      }
      tft.println(result);
    }

    // Verbrauchte Ah (CE)
    else if (labelS == "CE") {
      float result = messwert / 1000.0;  
      tft.setTextColor(WHITE, BLACK);
      tft.setCursor(90, 155);
      tft.println(static_cast<int>(result));  
    }
  }
}

//*******************************************************************Solar Werte Panel*****************************************************
void getSolar() {
  if (Serial1.available() > 0) {
    char firstChar = Serial1.peek();  

    // Falls HEX-Daten erkannt werden, ignorieren
    if (firstChar < 32 || firstChar > 126) {
      Serial1.read();  
      return;
    }

    String label = Serial1.readStringUntil('\t');
    String val = Serial1.readStringUntil('\n');
    val.trim(); 

    Serial.println(label);
    Serial.println(val);

    val.toCharArray(buf, sizeof(buf));  
    float messwert = atof(buf);  

    // Solarleistung (PPV)
    if (label == "PPV") {
      tft.setTextColor(WHITE, BLACK);
      tft.setCursor(90, 35);
      tft.println(static_cast<int>(messwert)); 
    }

    // Solarspannung (VPV)
    else if (label == "VPV") {
      tft.setCursor(90, 95);
      tft.println(messwert / 1000.0); 
    }

    // Lademodus (CS)
    else if (label == "CS") {
      int mode = val.toInt();
      tft.setCursor(90, 155);

      if (mode == 2) {
        tft.setTextColor(RED, BLACK);
        tft.println("Error");
      }
      else if (mode == 3) {
        tft.setTextColor(BLUE, BLACK);
        tft.println("BULK  ");
      }
      else if (mode == 4) {
        tft.setTextColor(BLUE, BLACK);
        tft.println("ABS   ");
      }
      else if (mode == 5) {
        tft.setTextColor(BLUE, BLACK);
        tft.println("FLOAT ");
      }
      else {
        tft.setCursor(90, 155);
        tft.println("OFF ");
      }
    }

    // Lastausgang (LOAD)
    else if (label == "LOAD") {
      tft.setTextColor(WHITE, BLACK);
      tft.setCursor(90, 215);
      tft.println(val);
    }
  }
}

//*******************************************************************Solar Ertrag**********************************************************
void getSolar1() {
  if (Serial1.available() > 0) {
    char firstChar = Serial1.peek();  

    // Falls HEX-Daten erkannt werden, ignorieren
    if (firstChar < 32 || firstChar > 126) {
      Serial1.read();  
      return;
    }

    String labelE = Serial1.readStringUntil('\t');  
    String valE = Serial1.readStringUntil('\n');    
    valE.trim();  

    Serial.println(labelE);
    Serial.println(valE);

    valE.toCharArray(buf, sizeof(buf));  
    float messwert = atof(buf);  

    tft.setTextSize(2);
    tft.setTextColor(WHITE, BLACK);  

    // Solar Ertrag heute (H20)
    if (labelE == "H20") {
      tft.setCursor(90, 35);
      tft.println(static_cast<int>(messwert * 10));  
    }

    // Max. Solar Leistung heute (H21)
    else if (labelE == "H21") {
      tft.setCursor(90, 95);
      tft.println(static_cast<int>(messwert));
    }

    // Solar Ertrag gestern (H22)
    else if (labelE == "H22") {
      tft.setTextColor(WHITE, BLACK);  // Andere Farbe für gestern
      tft.setCursor(90, 155);
      tft.println(static_cast<int>(messwert * 10));
    }

    // Max. Solar Leistung gestern (H23)
    else if (labelE == "H23") {
      tft.setTextColor(WHITE, BLACK); 
      tft.setCursor(90, 215);
      tft.println(static_cast<int>(messwert));
    }
  }
}

//*******************************************************************MPPT Regler Daten*****************************************************
void getSolar2() {
  static String PID = "";  
  static String SER = "";  

  if (Serial1.available() > 0) {
    char firstChar = Serial1.peek();

    // Falls HEX-Daten erkannt werden, ignorieren
    if (firstChar < 32 || firstChar > 126) {
      Serial1.read();  
      return;
    }

    String labelD = Serial1.readStringUntil('\t');  
    String valD = Serial1.readStringUntil('\n');    
    valD.trim();  

    Serial.println(labelD);
    Serial.println(valD);

    tft.setTextSize(2);
    tft.setTextColor(WHITE, BLACK);  

    // Produkt ID (PID)
    if (labelD == "PID") {
      PID = valD;  
      tft.setCursor(50, 35);
      tft.println(PID);
    }

    // Seriennummer (SER#)
    else if (labelD == "SER#") {
      SER = valD;  
      tft.setCursor(30, 95);
      tft.println(SER);
    }

    // Firmware Version (FW)
    else if (labelD == "FW") {
      valD.toCharArray(buf, sizeof(buf));
      float messwert = atof(buf);
      float result = messwert / 100;

      tft.setCursor(70, 155);
      tft.println(result);
    }
  }
}

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

}

// Alarm ausgelöst
void Ausgeloest() {
}

// Arbeitsscheinwerfer schalten
void Scheinwerfer() {
  static boolean status=false;
  status = digitalReadFast(RELAISSCHEINWERFER);
  if (status == LOW) {
    digitalWriteFast(RELAISSCHEINWERFER, HIGH);
    page7_btn.drawButton(false);
  }  
  if (status == HIGH) {
    digitalWriteFast(RELAISSCHEINWERFER, LOW);
    page7_btn.drawButton(false);
  }  
}

// Bluetooth schalten
void Bluetooth() {
}

Ich denke mir schon, daß der Code nicht sehr gut ist. Bei deinem Beispiel, dass du rausgesucht hast, kommt Version 1.64 raus. Das soll eigentlich auch so sein.

Danke schon mal. Klar kann ich etwas testen. Kann nur evtl. mal etwas dauern, da ich die Regler in meinem Bus verbaut habe.

Dein Projekt.
Deine Timeline.

Morgen ist Samstag. Ich nehm mir das mal mit und mach zu morgen einen Anfang.
Victron hat nämlich einen seit Jahren nicht mehr überarbeiteten Code für Arduino.
Ich würde gerne sehen, ob der noch funktioniert.

Ja. weil es gerade passt.
Wie gesagt: Es gibt auch Versionen, die nicht numerisch sind.

OK. Bei dem Code den du schon mal für ein anderes Projekt geschrieben hast, kommt schon immer 0 raus, was ja bei der checksumme bei victron so sein soll.? Allerdings bekomme ich den Code nicht mit meinen zu laufen.

Die Integration sehe ich nicht so problematisch.
Und 0 ist gut :slight_smile: