Problem mit ESP32 Board Verwaltung V 3.0.2 und PWM

Hallo,
ich benutze in meiner Arduino IDE 2.3.2 die ESP32 BoardVerwaltung V2.0.17 von Espressif Systems und alles lässt sich problemlos compilieren.
Wenn ich auf die neue Version 3.0.2 (oder 3.0.1) ESP32 Boardvervaltung aktualisiere, gibt es beim compilieren plötzlich ein Problem mit den Befehlen ledcAttachPin und ledcSetup.
Wie gesagt - vorher hat alles funktioniert.

Anbei mal die Fehlermeldung:

C:\Users\Peter\_docs\Arduino_ESP_main\Code\_Projekt Controlcenter\ESP_CoC_V3_3\ESP_CoC_V3_3.ino:618:1: error: 'ledcSetup' was not declared in this scope; did you mean 'tempSetup'?
  618 | pinMode(WWPUMPE, OUTPUT);
      | ^~~~~~~~~
      | tempSetup
C:\Users\Peter\_docs\Arduino_ESP_main\Code\_Projekt Controlcenter\ESP_CoC_V3_3\ESP_CoC_V3_3.ino:619:1: error: 'ledcAttachPin' was not declared in this scope; did you mean 'ledcAttach'?
  619 | pinMode(EPATRONE, OUTPUT);
      | ^~~~~~~~~~~~~
      | ledcAttach

exit status 1

Compilation error: 'ledcSetup' was not declared in this scope; did you mean 'tempSetup'?

.. und dann die dazugehörige Stelle im Code:

pinMode(HEIZPUMPE, OUTPUT);
pinMode(WWPUMPE, OUTPUT);
pinMode(EPATRONE, OUTPUT);
ledcSetup(pwmchannelfreigabeled, pwmchannelfrequency, pwmchannelresolution);              // Definition des PWM Channels unter Verwendung des ledc-libraries 
ledcAttachPin(FREIGABELED, pwmchannelfreigabeled);                                        // Zuweisung #PWM Channel0 zur Freigabeled 
ledcSetup(pwmchannelgetdataled, pwmchannelfrequency, pwmchannelresolution);               // Definition des PWM Channels 
ledcAttachPin(GETDATALED, pwmchannelgetdataled);                                          // Zuweisung #PWM Channel0 zur Freigabeled 

Versteh das nicht und finde auch keine Lösung. Fehlt mir da plötzlich eine Library für die PWM Befehle?
(der gesamte Code ist ein paar 1000 Zeilen, daher hier mal nur der direkt betroffene Codeteil,

Es braucht den kompletten Code - sonst wird das nix.
Wer soll das mit den Infos nachbauen?

versteh ich ... aber habe den gesamten Code in 20 Tabs in der IDE.

Kann dir gerne mal den Code vom Haupttab geben .. die anderen 19 Tabs lass ich mal ..
in 2.0.17 lief das alles problemlos....


#include "espdef.h"    // Definition der ESPs  

// -------------------------- weitere Netzwerkdefinitionen --------------------

const IPAddress gateway(192,168,178,1);           // Abdresse des Routers
const IPAddress subnet(255,255,255,0);            // und der IP SubnetMaske
const IPAddress dns(192,168,178,1);               // Router = DNS 
const char* otahost = myhostname;                 // OTA hostname
const String sIPrumpf = "192.168.178";            // wird für die links auf der Haupt_HTML verwendet 
const String startIP = ".20";


// ---------------------- die Schnittstellen -----------------
String sdatatransfer;                           // string für SendData  - Messwerte für andere ESPs
String whatsapptext;                            // text für Whatsapp Messages
String seingabe;                                // ### Eingabestring vom seriellen Monitor Serial.read(...)
String text;                                    // allgemeiner String für Zwischenspeicher von text bei zB Meldungen oder display.print

int16_t testzaehler;                            //  zählt die Durchläufe im 13 sec Loop für die Laufzeitmeldungen alle 24h
bool starttestmeldung;                          // stellt sicher, dass die erste testmeldung nur einmal abgesetzt wird
bool testoutputzyklus;                          // bei jedem 2. Durchlauf L4 on, zum  ein/aus Schalten der Ausgaenge
byte testoutputzaehler = 2;                     // ### für die Aktivierung der Testoutputroutine 4,5,6   bei 2 x ">" Touch
bool testoutputon;                              // ### generell Testroutine ON/OFF  - für Output 4,5,6, on oder off

// alle fix ------- Wifi Connect und Satus ------------------
byte wificonnectversuchemax = 100;              //  x * 100msec  ;  wird in der Wifiroutine für anzahl verbindungsversuche verwendet und danach wird abgebrochen
const byte intervallwificonnectversuch = 300;   // in sec -  wenn Wifibeim Sart nicht verbunden werden konnte, wird alle x sec versucht die Verbindung herzustellen
unsigned long letzterwificonnectversuch;        // speichert zeit des letzten Versuchs
bool wifistatusconnect;                         //  bei false -  druckt Wifi Fehler auf das Display, wenn die Verbindung nicht gelingt
bool wifinotconnectedgemeldet;                  // bei Fehler wird der Text nur einmal in der Meldeschnittstelle gemeldet

// -----------------------  Get Data -----------------------
const String sdatenurl = "/data";               //  192.168.178.02x/data  ist die url für alle ESP-data Schnittstellen  - defintion in der Exceltabelle zum Projekt
const byte maximalfeldergetdata = 45;           // zur Definition des espx.idx[] arrays in der getData Routine - maximum aller getData Schnittstellen
const byte getdatafehlertoleranz = 4;           // die maximale Anzahl an Fehlversuchen, bevor der espx.swerte String mit -x- überschrieben wird
uint16_t getdatafehlergesamt;                   // Summe der getdatafehler aus espa und espb
unsigned long getdatastartzeit;                 // zur Messung der durchschnittlichen Datenempfangszeit in msec
const String sprueftext = "z2601";              // erste Zelle im Send und getData String - zur Prüfung ob der Empfang OK ist
const String swertedatenfehler = "-98";         // wenn der getdata Empfang gestört ist, wird -98 in die swerte[] geschrieben  - war früher mal "-x-"


class cGetDataInterface {                                   // die Klasse für die GetDataroutine
  public:
    cGetDataInterface (String sif, char* ip, byte anzahl) {    // constructor definiert das Variablenset für den Start
      sinterfacename = sif;
      ipsource = ip;
      anzahlwerte = anzahl;
    }; 
    String sinterfacename;                      // Name der Schnittstelle
    char* ipsource;                             // const char* oder char[16] funktioniert nicht - es muss ein char* sein
    byte anzahlwerte;                           // Anzahl Werte der Schnittstelle
    int16_t getdatazeit;                        // Zeit in ms bis die Daten empfangen wurden
    unsigned long getdatastartzeit;             // Startzeit für Zeitmessung getdatazeit
    int16_t getdatazeitzulange;                 // zählt wie oft die getdatazeit bereits zu lange war
    int16_t getdatafehler;                      // zählt die getdatafehler der schnittstelle - wird auf Null gesetz beim nächsten  erfolgreichen Datanaustausch
    int16_t getdatafehlergemeldet;              // verhindert Mehrfachmeldungen bei getdatafehler
    String swerte[maximalfeldergetdata];        // liefert die Daten des Empfangsstring in die einzelnen Datenfelder (swerte[x])
  };

cGetDataInterface espa (sinterface_a, ip_a, anzahlwerte_a);     // Definition der 2 Objekte der Klasse
cGetDataInterface espb (sinterface_b, ip_b, anzahlwerte_b);

byte espbinterfacezaehler;                       // zählt die Durchläufe für getData bei zB KHz              

// -------------------die eigenen Definitionsdateien einbinden -----------------------
#include "htmp.h"                               // Definition der Parameter und Variablen der DS18B20 Sensoren
#include "htft.h"                               // Definition der TFT Parameter und Variablen
#include "html.h"                               // Definition der Strings für die HTML Seite, die fix bleiben

// ------------------ Stoerungsmeldungen -----------------
// max 30-35 Zeichen lang
class cstoerungsmeldung {                       // Jede Datazeile ist dann ein einzelnes Objekt der Klasse
  public:
    int16_t idx;                                // index-Nr der Meldung   
    String sdatum;                              // Datum des Meldungseingangs
    String sdatumkurz;                          // Kurzversion des Datums  (nur Tag und Monat)
    String suhrzeit;                            // uhrzeit des Meldungseinganges
    char farbe;                                 // Farbcode für die Meldung 
    String smeldung;                            // der eigentliche Meldungstext
};
                                                // midxmax ist entscheidend für gutes Funktionieren.  in Summe sollte Freeheap > 50kB bleiben für WLAN , OTA use
const int16_t midxmax  = 130;                   // Größe des Meldearrays = Zeilen Meldungen  (bei 300 bleibt Platz für weitere Messwerte - ca. 30)  - 
const int16_t midxmax2 = midxmax + 3;           // 2 Felder Reserve im Meldearray
cstoerungsmeldung meldung[midxmax2];            // Definition des Arrays (jedes einzelne Feld des Arrays ist eine Meldung  bzw ein Objekt der Klasse)
int16_t midx;                                   // = meldeindex ,  zeiger auf das aktuelle Feld des meldeindex  = sammlung aller meldungen
bool meldebedienung;                            // = 0 wenn die MEldungen automatisch laufen, = 1 wenn in den MEldungen geblättert wird 
int16_t letzteangezeigtemeldung;                // speichert die Meldungen seit dem letzten Aufruf - zur Anzeige in der Topzeile
int16_t angezeigtemeldungenueberlauf;           // zählt die Durchgänge durch das Array 
int16_t versaeumtemeldungen;                    // zählt ide Meldungen , seite letzten Besuch der Meldeseite am TFT oder HTML
int16_t anzeigehtmlmeldunganfang;               // Zähler zur Generierung der  HML Seite  - 1. Meldung auf der Seite
int16_t anzeigehtmlmeldungende;                 // Zähler zur Generierung der HTML Seite  - letzte Meldung der Seite


#if TFTVorhanden == 1     // ******************************************************

// ---------------------- für die Transformation / Querverweise Messwerte standardisiert ------------------ 
class cdataesp {
  public:
    String feuchte;
    String temp;
    String licht;
    String dbm;
    String laufzeit;
    String ESPtemp;
    String agetdata;            // getdata Zeit in ms der A-Schnittstelle
    String bgetdata;            //                ....der B-Schnittstelle
    String versaeumtemeldungen; 
  };

      // Objekte der Klasse cdataesp:    
cdataesp pKHz;                  // p..für "print" - wird gebraucht um die TFT Anzeige und HTML Ausgabe einheitlch zu halten
cdataesp pEG;
cdataesp pDG;
cdataesp pKWr;
cdataesp pKGr;

String pAussenfeuchte;          // die Werte die nicht auf jedem ESP vertreten sind, werden als eigene pStrings dargestellt
String pAussentemp;
String pWWoben;
String pWWunten;
String pVL;
String pRL;
String pFernwaerme;
String pVLsolar;
String pRLsolar;
String pDachsolar;
String pSonne;
String pKlima; 
String pWasser;

//  -------------  Werte für die Diagramme -------------------
class cWerteDiagramm {
  public:
  cWerteDiagramm (String gruppe, String name, String einheit, int16_t anfang, int16_t ende, uint16_t f) {
    sanzeigegruppe = gruppe;
    sanzeigename = name;        
    seinheit = einheit;
    anzeigebereichanfang = anfang;
    anzeigebereichende = ende;
    farbe = f;
  };
  String sanzeigegruppe;
  String sanzeigename;
  String seinheit;                                 //  
  int16_t anzeigewert[idxdmax + 3];
  int16_t anzeigebereichanfang;                   // y-achse Skala im Daigramm - Start
  int16_t anzeigebereichende;                     // y-achse Skala im Diagramm - Ende  - Bereich muss gut durch 4 teilbar sein
  uint16_t farbe;                                 // muss uint16_t sein  :    https://rgbcolorpicker.com/565 
};

//  max 26 DiagrammWerte bei 250 Meldungen max. - Free Heap sollte ca bei <50kB sein   (oder 300 Meldungen und 15 Diagrammwerte)
// brauchbare Farben:  w white, y yellow, g green, o orange,    ::  blue und red sind zu dunkel auf schwarzem Hintergrund
// der erste Wert einer Diagrammseite definiert die linke Skala, der letzte Wert einer Seite definiert die rechte Skala
cWerteDiagramm dwert[] = {
{"Aussen: ", "Temp                 ", "C", -15, 45, orange},     //[0]   = 1
{"", "Feuchte", "%", 20, 100, tuerkis},

{"EG: ", "Temp                  ", "C", 10, 30, orange},     
{"", "Feuchte", "%", 20, 100, tuerkis},

{"WWTemp:", "WWO", "C", 30, 70, magenta},
{"", "WWU     ", "C", 30, 70, gruen},
{"", "VLSolar", "C", 20, 120, gelb},
{"", "DachSolar", "C", 20, 120, rot},

{"Heiz.Temp.: ", "VL", "C", 20, 80, orange},
{"", "RL", "C", 20, 80, tuerkis},    
{"", "Fernwaerme", "C", 20, 80, gelb},                //[10]  = 11.Datensatz    

{"KG Feuchte: ", "Hz", "%", 20, 100, orange},    
{"", "Wr", "%", 20, 100, gelb},    
{"", "Gr  ", "%", 20, 100, gruen},

{"KG Temp.:", "Hz", "C", 10, 30, orange},    
{"", "Wr", "C", 10, 30, gelb},    
{"", "Gr", "C", 10, 30, gruen},    

{"Licht: ", "EG", "%", 0, 100, tuerkis},    
{"", "KHz", "%", 0, 100, orange},
{"", "KWr", "%", 0, 100, gelb},
{"", "KGr", "%", 0, 100, gruen},                      //[20]
{"", "DG", "%", 0, 100, magenta},

{"WiFi: ", "EG", "dbm", -90, -10, tuerkis},    
{"", "KHz", "dbm", -90, -10, orange},
{"", "KWr", "dbm", -90, -10, gelb},
{"", "KGr", "dbm", -90, -10, gruen},
{"", "DG", "dbm", -90, -10, magenta},                 // bei 250 Meldungen sind max.  26 Diagrammwerte möglich beim 4" TFT 

{"GetData: ", "EG", "ms", 0, 800, tuerkis},    
{"", "KHz", "ms", 0, 800, orange},
{"", "KWr", "ms", 0, 800, gelb},
{"", "KGr", "ms", 0, 800, gruen},
{"", "DG", "ms", 0, 800, magenta}                     // [31]

};

String duhrzeit[idxdmax + 3];                       // speichert uhrzeit und datum zu den gespeicherten Messwerten für das Diagramm 
//byte anzeigeintervalldiagramme;                   // bei Loop5 kann die freuquenz der Anzeigenudates gesteuert werden  ;  im Normalfall auf 1; 
int16_t diagrammseite;                              // für das Blättern durch die Seiten
int16_t diagrammseitemax;                           // die maximale Anzahl der Diagrammseiten

#endif        // ***************************************

// ----------------  Freigaben und Masterupdate ----------------  
const int16_t intervallmasterupdate = 300;          // in sec -  update der schaltzustände vom Master (ESS KHz an den ESP EG)
unsigned long letztermasterupdate;                  // Zeit in mills , wann der letzte Masterupdate durchgeführt wurde  
unsigned long letztesmasterupdatenachlaufzeit;    
bool masterupdate;                                  // wird true, wenn masterupdate läuft
bool masterupdatealt;                               // speichert den vorherigen Status zum erkennen der fallenden Flanke
byte sendDatazaehler;                               // zählt die Durchläufe  für sendData (Zeitverzögerung im L2)

bool bediensperregetdata;                           // bei GetData-Empfang werden die anderen Bedienkanäle gesperrt
bool freigabeweb;                                   // Erteilung der Freigabe per HTML (Sperre des Touchkanals)
bool freigabegesamt;                                // Summe aller Freigaben
bool freigabegesamtalt;                             // speichert den vorherigen Freigabestatus - zur Erkennung der fallenden Flanke für NAchlaufzeit Freigabe
unsigned long letztefreigabegesamt;                 // Zeit seit letzter Freigabegesamt für die Nahclaufzeit Freigabe
const int16_t nachlaufzeitfreigabegesamt = 6000;    // nachlaufzeit in msec für die Freigabe - damit kann der Empfänger die Steuerbefehle noch in seinem  nächsten GetDataDurchlauf übernehmen
unsigned long letztefreigabeweb;
bool triggerfreigabegesamt;                         // zum Auslösen der freigabegesamt, wenn ein Ausgang geschalten wird
bool anzeigetft;
const byte laufzeit_resetesp = 10;                  // in sec - bis zum Löschen der ResetESP-Freigabe per HTML
bool resetesp;                                      // für den ESP Reset per HTML
unsigned long letztefreigabe_resetesp;              // Zeit seit ResetESP-Anwahl - Start des Zeitfenster für Resetfreigabe


// ----------------------- libraries  ---------------------------
#include <Preferences.h>                            // zumschreiben und lesen im Flash Memory
Preferences preferences;                            // Namespace preferences .. bezeichnung frei vergebbar
#include <UrlEncode.h>
//#include <WifiClient.h>                           // wird für whats app messages gebraucht - relativ einfach - infos von randomnerdtutorials.com
#include <HTTPClient.h>                             // wird gebraucht zum empfangen der Daten von einem  Webserver -  auch für whats app
#include <AsyncTCP.h>                               // async Webserver 
#include <ESPAsyncWebServer.h>                      // async Webserver
AsyncWebServer server(80);
#include <ArduinoOTA.h>                             //  OTA - Over the  Air Update: Kennwort in IOS PAsswortspeicher


// ======================== Ein- und Ausgänge ===============================

// ----------------------- DHT - Temp und Feuchte -----------------
#include "Adafruit_Sensor.h"      // für DHT
#include "DHT.h"                  // für DHT
//#include "DHTesp.h"             // ### Test mit einer anderen DHT-Library  - DHT sensor library for ESPx von beegee_tokyo - ging auch , allerding sdie Sensoren von Temu wollten nicht mit der 2. Library

#define HEIZPUMPE 33              // Relais 1, geht nach  ESP_EG und wird dort geschalten .. pin nur vorläufig
#define WWPUMPE 17                // Relais 2 
#define MISCHER_AUF 16            // Relais 3   
#define MISCHER_ZU 2              // Relais 4 
#define EPATRONE 32               // Relais 5

#define FREIGABELED 13            // GPIO 1 und 3 geht nicht - der serielle Monitor geht dann nicht;
#define GETDATALED 12             // blaue LED , wenn Daten empfangen, oder bei ESP ohne Empfang gesendet werden
#define KHZLUEFTER_EGBEEPER 21    // EG Beeper , KHz Lüfteransteuerung   - Output 7
#define DHTPIN 25                 // ist ein Output - reine Input GPIOs gehen nicht, wie zB 34,35,36,39

#define LICHTSENSOR 39            // analog input 0-4095 (12 bit ADC) 
#define WASSERSENSOR 36           // analog Input 0-4095
#define SONNENLICHTSENSOR 34      // analog Input    // ist im KHz auch Inputreserve
#define DACHSOLARSENSOR 35        // analog Input    // wird nur im KHz vernwendet  

#if TFTVorhanden == 1  //********************  // nur am KHz und EG - am DG hängt da der DHT AF
  #define SOLARPUMPE 26           // Relais 6 
#endif   // ********************

#define DHTTYPE DHT22             // DHT11 oder DHT22
DHT dht = DHT(DHTPIN, DHTTYPE);   // dht (Kleinbuchstaben) ist die veränderbare Bezeichnung  - Raumsensor Temp und Feuchte
//DHTesp dht;                     // ### Test mit einer anderen DHT-Library

#if ESP_DEVICE == 22   // ***********************************************
    #define DHTPIN_AF 26          // 2. DHT für AF
    DHT dhtAF = DHT(DHTPIN_AF, DHTTYPE);
#endif   // *************************************************

//  -------------- PWM Channels  ---------------------------------
const byte pwmchannelfreigabeled = 0;                   // PWM kanal 0  , es gibt 16 Kanäle  PWM= Pulsweitenmodulation
const byte pwmchannelgetdataled = 1;                    // PWM Kanal- es gibt 16 Kanäle,  0-15
const int16_t pwmchannelfrequency = 100;                // Frequenz des PWM Kanals in Hz
const byte pwmchannelresolution = 8;                    // Resolution 8 bit   => 0-255
int16_t freigabeledhelligkeit;                          // speichert die Helligkeit der FreigabeLED 0-255
int16_t getdataledhelligkeit;                            // speichert die Helligkeit der GetDataLED 0-255
const byte pwmchannelbeeper = 2;                        // ein weiterer PWM Channel - der ist für den Beeper
const int16_t pwmchannelfrequencybeeper = 200;          // 200 Hz gibt ertraeglichen Warnton
unsigned long letztesschnellesblinkenfreigabeled;       // start/Stop Zeit in mills for das schnelle Blinken der Freigabeled
const byte pwmchannelkhzluefter = 3;                    // PWM Kanal 3 
float khzluefterspeed;                                  // Geschwindigkeit Luefter Khz
byte luefterzaehler;                                    // zaehlt die durchläufe durch L3, alle x mal wird der lüfter upgedatet

const float korrfakttempdht = 0.22;                     // Korrekturfaktor für Raumtemperaturmessung bei verbauten ESPs


#if TFTVorhanden == 1  // *******************************************

// ========================== Reglereinstlellungen  ===================================
const byte solarobergrenze = 61;          // max. Speichertemp. bei Betrieb Solarkollektoren
const byte solardiff = 4;                 // Schaltdifferenz (Schalthysterese) Solar
const byte wwobergrenze = 43;             // max. Speichertemp bei Heizung mit Elektro oder WArmwasserpumpe
const byte wwdiff = 5;                    // Schaltdifferenz (Schalthysterese) Warmwasser
const byte korrwertWWO = 4;               // Korrekturwert für Warmwasserfühleroben  (### weil er nicht zur Gänze in den Boilerslot passt)

// =====================================================================================

// --------------------- Variablen für Messwerte  - hauptsächlich für Regler ---------------------
float WWU;              // Temp Warmwasserspeicher oben ; für die Übernahme der Messwerte temp[1] - temp[6]  in sprechende Namen bei ESP KHz
float WWO;              // Temp Warmwasserspeicher unten
float VL;               // Temp Vorlauf Heizung
float RL;               // Temp Rücklauf Heizung
float FW;               // Temp Fernwärme 
float VLS;              // Temp Vorlauf Solar
float RLS;              // Temp Rücklauf Solar
float Dachsolar;        // Temp Fühler in Solarkollektor
float Aussentemp;       // Aussentemperatur
float Sonnenstrahlung;  // % Sonnenstrahlung am Dach

// ----------------------- Variablen für Schlatzustände und Meldetexte ------------------------------
String sFreigabe;                             // speichert die Freigabe JA/NEIN - die Schaltzustände der anderen Outputs sind direkt im Output (digitaWririte / digitalRead) bzw in den sanzeige0buttontext[1][x] Stringd
String smasterupdate;                         // geht auf "MAU", wenn ein Masterupdate durchgeführt wird
bool heizungauto;                             // Status heizung Automatik oder Handsteuerung
bool warmwasserauto;                          // Status Warmwasser Automatik ode Handsteuerung
bool steuerunghand;                           // speichert Zustand HAND - Auto steuerung  ,  true = HAND, false = AUTO

const String smheizungauto = "++++  Heizung AUTO";    // Meldetexte für Schaltbefehle
const String smheizungaus = "-----  Heizung AUS";
const String smwarmwasserauto = "++++  Warmwasser AUTO";
const String smwarmwasseraus = "-----  Warmwasser AUS";
const String smsteuerunghand = "-----  Steuerung HAND";
const String smsteuerungauto = "++++  Steuerung AUTO";
const String smepatroneein = "++++  E-Patrone EIN";
const String smepatroneaus = "-----  E-Patrone AUS";


// --------------- Durchschnitt- und Integralberechnung ---------------------
byte samplezeitzaehler;                   // zählt die 15 sec  Durchläufe  bis eine ganze Minute voll ist 
const int16_t ds_indexmax = 243;          //  240 + 3 ,  Sampleanzahl in Minutenraster für Durchschnitt     (240 = 4 Std)

class cDurchschnittsberechnung {                                   // die Klasse für die Durchschnittsberechnung und die dazugehörige Funktion
  public:
    cDurchschnittsberechnung (String name, String einheit, int16_t anz, int16_t idx) {    // constructor definiert das Variablenset für den Start
      sname = name;
      seinheit = einheit;
      anzahl = anz;
      index = idx;
    }; 
    String sname;                         // Name des Wertes - Anzeige HTML
    String seinheit;                      // Einheit - Anzeige HTML
    float summe;                          // lfd Summe der Werte
    float wert;                           // der aktuelle Wert
    float durchschnitt;                   // aktueller Durchschnitt
    int16_t anzahl;                       // anzahl der Werte für diese Durchschnittsberechnung   - max. zyklus 
    float wertspeicher[ds_indexmax];      // array in dem die einzelnen werte gespeichert werden
    int16_t index;                             
    bool speichervoll;
};

cDurchschnittsberechnung dslichtsonne ("Sonnenlicht", "%", 240, 1);     // Definition der Onjekte der Klasse     ....   180 min,   Index muss 1 sein
cDurchschnittsberechnung dsaussentemp ("Aussentemp", "&deg;C", 30, 1);

//  --------------- Integrale ---------------------
const byte integralarraymax = 33;                             // 31 Tage + 2 Reserve
String swochentag[integralarraymax];

class cIntegralberechnung {                                   // die Klasse für die Integralberechnung und die dazugehörige Funktion
  public:
    cIntegralberechnung (String name, String einheit, float sta, float end) {    // constructor definiert das Variablenset für den Start
      sname = name;
      seinheit = einheit;
      start = sta;
      ende = end;
    }; 
    String sname;                           // Name des Wertes - Anzeige HTML
    String seinheit;                        // Eingeit des fertigen Integrals - Anzeige HTML
    float summe;                            // lfd Summe der Werte
    float summealt[integralarraymax];       // speichert die alten summen der vorangegangenen Integralperioden
    float durchschnitt;                     // durchschnittswert aus summe / zaehler    
    float durchschnittalt[integralarraymax];
    float wert;                             // der aktuelle Wert
    String sdatum[integralarraymax];        // datum in kurzform 
    float start;                            //  Startzeit in Dezimalform
    float ende;                             // Endezeit des Integrals   in Dezimalform  
    uint16_t zaehler;                       // anzahl der integrationen
    bool integralfertig;
};

                                                                        // Start und Endzeit sllte dann gleich sein, wenn sie ale auf einer tabelle angeziegt werden
cIntegralberechnung isolarenergie ("Solar", "k&deg;Cmin", 0, 23.9);     // Definition der Objekte der Klasse     ....   180 min,   Index muss 1 sein
cIntegralberechnung itagesaussentemp ("Aussen", "&deg;C", 0, 23.9);
cIntegralberechnung iheizenergie ("Heizg.", "k&deg;Cmin", 0, 23.9);
cIntegralberechnung iwarmwasserenergie ("WW", "k&deg;Cmin", 0, 23.9);
cIntegralberechnung isonnenstrahlung ("Sonne", "k%min", 0, 23.9);

const int16_t solar_zu_kwh_umrechnung = 280;         // umrechnung der gradCelsius * minuten in kwH: Erhebung 2024/05 anhand längerer MEssung

#endif // *****************************************

// ----------------------- Wasseralarm --------------------
unsigned long letzterwasseralarm;             // speichert Zeit des letzten Wasseralarms  
const byte intervallwasseralarm = 6;          // in sec ###
int16_t wasser;                               // Messwert für Wassermelder
String swasser;                               // ... und der dazugehörige String

// ------------------------ E- Patrone / Mischer-----------------
const int16_t laufzeit_epatrone = 1800;       // Ausschaltverzoegerung E-Patrone in sec (maximal Einschaltzeti)
unsigned long einschaltzeitpunkt_epatrone;    // speichert Zeit zu der Epatrone eingschalten wurde
const int16_t laufzeit_mischer = 120;
unsigned long einschaltzeitpunkt_mischer;

// -------------------- Lichtsensoren --------------------------
int16_t lichtwert;                            // Messwert Lichtsensor  0-100%
int16_t lichtwertalt;                         // speichert den vorherigen Messwert des Lichtsensors (1 Zyklus alt) wird gebraucht für das lichtabhängige einschalten des TFT

String slicht; String slicht1; String slicht2;
bool lichtzeileanzeige0;              // Schaltet in der Anzeige 0 zwischen Anzeige Lichtwerte und Status Ausgänge um
int16_t lichtwertsonne;                      // Messwert für Eingang Sonnestrahlung 0-100%

// ------------------Variablen für DHT und DHT AF --------- ---------------
float feuchtedht;
String sfeuchtedht;                           // s steht für String AnzeigeWert  ... ist immer parallel zu einem float , in dem der Messwert gespeichert ist
float tempdht;
String stempdht;
byte dhtsensorfehler;
bool tempdhtgemeldet;                         // wenn feuchteüberschreitung gemeldet wurde, wird das auf true gesetzt und bei geringerem Wert zurück gestezt
bool feuchtedhtgemeldet;                      // wenn temp ..........

float feuchtedhtAF;
String sfeuchtedhtAF;                         // s steht für StringAnzeigeWert  ... ist immer parallel zu einem float , in dem der Messwert gespeichert ist
float tempdhtAF;
String stempdhtAF;
byte dhtAFsensorfehler;
bool tempdhtAFgemeldet;
bool feuchtedhtAFgemeldet;

// ------------------------ NTP ------------------------------
#include <WiFi.h>
#include "time.h"
#include "sntp.h"                             // Bsp von der library
const char* ntpServer1 = "fritz.box";         // die eigene Fritz box
const char* ntpServer2 = "pool.ntp.org";      // offizieller NTP Server
const long  gmtOffset_sec = 3600;             // immter auf 3600
const int   daylightOffset_sec = 3600;        // im sommer auf 3600 , winter auf 0
const char* time_zone = "CET-1CEST,M3.5.0/02,M10.5.0/03";  // M3.5.0: 3 = 3rd month, 5 =last 0 = sunday,   M10.5.0 = last sunday in 19th month ;  TimeZone rule for Europe/Rome including daylight adjustment rules (optional)

// --------------------- Loop und Infrastruktur -----------------------
bool imsetup;                                 // ist true, wenn die setuproutine durchlaufen wird
unsigned long letzterloop1;                   // gespeicherte Zeit des letzten Loop-Durchaufs
unsigned long letzterloop2;
unsigned long letzterloop3;
unsigned long letzterloop4;
unsigned long letzterloop5;
unsigned long messzeitstart;                  // für die Zeitmessungen der einzelnen Prozesse
unsigned long startzeithauptloop;             // zur Messung und Anzeige der loop durchlaufzeiten
        
unsigned long letztermeldetest;               // für Belastungstest mit Testmeldungen

uint32_t laufzeitsec;                         // ESP laufzeit in sec    ...millis()/1000
// Verwendung in funktion sLaufzeit
uint16_t lzwochen;
uint16_t lztage; 
uint16_t lzstunden;
uint16_t lzminuten;
uint16_t lzsekunden;
String slzstunden;
String slzminuten;
String slzsekunden;
uint32_t lzsec;

bool ntptimevorhanden;                       // Zeit und Datum aus NTP
byte ntpsek;
byte ntpmin;
byte ntpstd;
byte ntptag;
byte ntpwochentag;
byte ntpmonat;
byte ntpjahr;
uint16_t ntpjahrkurz;
//int ntpdaylightsavingflag;    // ###
String suhrzeit;
String sdatum;
String sdatumkurz;


// ##########################################  SETUP  #########################################################################

void setup() {

imsetup = true;                              // steuert die Infos am Startdisplay zu Beginn - für WiFi Status Infos
Serial.begin(115200);
delay(1500);                                 // wird gebraucht, bevor die serielle schnittstelle zur verfügung steht
Serial.println(F(" ------------------ SETUP START --------------------"));
Serial.println(F("  "));

NTPStart(); 
                                // NetworkTimePRotocoll - muss vor dem IPStart sein
pinMode(HEIZPUMPE, OUTPUT);
pinMode(WWPUMPE, OUTPUT);
pinMode(EPATRONE, OUTPUT);
ledcSetup(pwmchannelfreigabeled, pwmchannelfrequency, pwmchannelresolution);              // Definition des PWM Channels unter Verwendung des ledc-libraries 
ledcAttachPin(FREIGABELED, pwmchannelfreigabeled);                                        // Zuweisung #PWM Channel0 zur Freigabeled 
ledcSetup(pwmchannelgetdataled, pwmchannelfrequency, pwmchannelresolution);               // Definition des PWM Channels 
ledcAttachPin(GETDATALED, pwmchannelgetdataled);                                          // Zuweisung #PWM Channel0 zur Freigabeled 
pinMode(MISCHER_ZU, OUTPUT);
pinMode(MISCHER_AUF, OUTPUT);

#if ESP_DEVICE == 20   // ******************************
  ledcSetup(pwmchannelkhzluefter, pwmchannelfrequency, pwmchannelresolution);              // Definition des PWM Channels unter Verwendung des ledc-libraries 
  ledcAttachPin(KHZLUEFTER_EGBEEPER, pwmchannelkhzluefter);
#endif  // ******************************

#if ESP_DEVICE == 21   // ******************************
  ledcSetup(pwmchannelbeeper, pwmchannelfrequencybeeper, pwmchannelresolution);              // Definition des PWM Channels unter Verwendung des ledc-libraries 
  ledcAttachPin(KHZLUEFTER_EGBEEPER, pwmchannelbeeper);
#endif  // ******************************

pinMode(LICHTSENSOR, INPUT_PULLDOWN);
pinMode(WASSERSENSOR, INPUT_PULLDOWN);
pinMode(SONNENLICHTSENSOR, INPUT_PULLDOWN);
pinMode(DACHSOLARSENSOR, INPUT);
//pinMode(TFTLED, OUTPUT);                      // muss nicht sein
pinMode(TIRQ_PIN, INPUT_PULLUP);                // wird gebraucht, - IRQ is down bzw fallende Flanke (Falling), daher interner PULLUP


#if TFTVorhanden == 1   // *****************************************

  pinMode(SOLARPUMPE, OUTPUT);

  tftbrightness = 130;     // LED des displays  - PWM Ansteuerung 0-255 = 0-100% Helligkeit

  // String Speicherreservierungen  (in 16 Byte Schritten):
  //pAussenfeuchte.reserve(6);                    // ### Beispiel für Größenreservierung bei String (bessere Speicheraufteilung, weniger Fragemntierung im Heap)
  //sFreigabe.reserve(5);                         // angeblich werden String sin 16 Byte Blöcken reserviet  - dh. bei  5 Byte automatscih 16 Byte belegt
  //sMasterupdate.reserve(5);

#endif // **************************************************

ts.begin();                                     // start des Touchscreen
ts.setRotation(tftrotation);                    // Rotation TS 0-3

Serial.println("Start Display");
display.begin();                                // ### Fehlermeldung bei 2.8" Display - macht aber nichts im Betrieb
Serial.println("Start set Rotation");           // start des TFT 
display.setRotation(tftrotation);               // 90 grad    ist Querformat , 0 = hochformat, 2 und 3 geht auch noch
 
if (azdeliverygehaeuse == true) tftbrightness = 255 - tftbrightness;
analogWrite(TFTLED, tftbrightness);   

  #if TFTVorhanden == 1 //*****************************************

      display.fillScreen(BLACK);
      display.setTextColor(weiss);
      (tftx == 480) ? (display.setFont(&FreeSansBold9pt7b)) : (display.setFont(&FreeSans8pt7b));   // kleinere Schriftgröße bei 2,8" display
      display.drawLine(0, 2, tftx, 2, WHITE);
      display.setCursor(2, 20);  // horizontal, vertikal
      display.println(F("ControlCenter  by P.Petschauer"));
      (tftx == 480) ? (display.setFont(&FreeSans9pt7b)) : (display.setFont(&FreeSans8pt7b));   // kleinere Schriftgröße bei 2,8" display
      display.print(F("CC-ESP: "));
      display.print(myhostname);
      display.print("; ");      // mit #if TFTVorhanden
      display.println(softwareversion);
      display.print("Sketch: " + String(ESP.getSketchSize() / 1024) + " kB, ");
      display.println("HW: " + String(ESP.getChipModel()));
      byte zeilenanzahlkopf = 3;
      display.drawLine(0, (4 + zeilenabstand * zeilenanzahlkopf), tftx, (4 + zeilenabstand * zeilenanzahlkopf), WHITE);
      display.setCursor(2, 27 + zeilenabstand * zeilenanzahlkopf);  // horizontal, vertikal
      
  #endif   //*******************************************

dht.begin();                                    // DHT Sensor starten
//dht.setup(25, DHTesp::DHT22);                 // ### Test mit einer anderen DHT-Library 

#if ESP_DEVICE == 22 // ***************************** 2.DHT nur am DG ESP
      dhtAF.begin();
#endif   // *********************************

tempSetup();                                    // Setup DS18B20 Temperatursensoren

display.print(F("Verbindungsaufbau Wifi: "));
ledcWrite(pwmchannelgetdataled, 255);           // schaltet GetDataLEd auf 100%  (8 bit 0-255)
Wifistart();                                    // Teile des Code als Funktion in eigenm Tab ausgelagert  - m_wifi.ino  -- achtung - die tabs werden alphabetisch aufgerufen
ledcWrite(pwmchannelgetdataled, 0);
delay(1000);   

OTAstart();                                     // Over the Air updates

startAsyncServermitURLs();                      // Serverdefinition mit Unterseiten

//  ========= Master / Slave Regelung für Start und die Steuerungskommandos ===================
// Holen des Zustands der Ausgänge vom anderen ESP  (KG/EG)


#if TFTVorhanden == 1       // ******************************************

  if (WiFi.status() == WL_CONNECTED) {
    
    display.print(F("GetData gestartet: Versuche: "));

    while (espa.swerte[0] != sprueftext && espa.getdatafehler < 8) {                                           // erstes Datenfeld muss prüftext enthalten, dann gehts weiter - max 8 Fehlversuche
      (digitalRead(FREIGABELED) == LOW) ? digitalWrite(FREIGABELED, HIGH): digitalWrite(FREIGABELED, LOW);    // ist so wie if (...)  ...  else ..
      sendData();                                                                                             // wenn beide gleichzeitig starten, warten sie sonst zu lange (zb nach Stromausfall)
      espa = ESPInterface(espa);                                                                              //gibt einen Klasse an die Funktion und bringt eine Klasse  zurück
      if (espa.getdatafehler > 0 ) display.print("X");                                                        // Fehlversuche werden mit einem X angezeigt
      delay(1000);  
    }     // end while
    
    if (espa.getdatafehler == 0 ) display.print(" OK");
    display.println("");
    
    if (espa.swerte[0] == sprueftext && (espa.swerte[2] == sbutAUTO || espa.swerte[2] == sbutAUS)) {            // Schaltbefehle übernehmen, wenn Daten in Ordnung sind
      unsigned long laufzeit = espa.swerte[14].toInt();                                                     // wandelt string in int um
      
      if (smyname == "EG") {
        display.setTextColor(gruen);
        display.println(F("Update OK, Status Ausgaenge aktualisiert"));
        Meldung("Update OK, Ausgaenge uebernommen", 'g');
        display.setTextColor(weiss);
      }

      if (smyname == "KHz") {                                             // Übernahme der Schaltzustände des EG, wenn er ausreichend lange läuft
          float f = laufzeit;
          String slaufzeit;
          if (laufzeit > 3600 * 2) {f = laufzeit / 3600; slaufzeit = String(f, 1) + "h";}
          else slaufzeit = String(laufzeit) + "s";
              
        if (laufzeit > millis() / 1000 + 120) {                           // ESP im EG muss x sec länger laufen als KG-Hz 
          switchGetDataBefehle();
          display.setTextColor(gruen);
          display.println(F("Update erfolgt - Ausgaenge geschalten"));
          Meldung("Update OK, Ausgaenge geschalten", 'g');
          Meldung("lokalerESP: " + String (millis() / 1000) + "s, 2.ESP: " + slaufzeit, 'w');
          display.setTextColor(weiss);
          }    // end if
        else {
          display.print(F("Datentransfer OK, "));
          display.setTextColor(rot);
          display.println(F("aber kein Update"));
          display.println(F("Laufzeit des anderen ESP zu kurz"));
          display.setTextColor(weiss);
          Meldung("Update erfolgt, Ausgaenge nicht geschalten", 'w');
          Meldung("lokalerESP: " + String (millis() / 1000) + "s, 2.ESP: " + slaufzeit, 'w');
        }   // end else
      }     // end if smyname
      else switchGetDataBefehle();                                      // wenn nicht KHz , dann wird geschalten ohne Laufzeitabfrage
    
    }       // end if swerte
    
    else {                                                              // Wenn der Inhalt der Datenfelder nicht OK ist
      display.setTextColor(rot);
      display.println(F("Datentransfer fehlerhaft!"));
      Meldung("Datentransf.Update Ausgaenge fehlerhaft", 'o');
      display.setTextColor(weiss);  
    }
  
  }   // end if wifi.status
display.drawLine(0, tfty - 10, tftx, tfty - 10, WHITE);
delay(1000);

// ==================  WHATs APP ========================  
    String appmessage = ("ESP Neustart: " + smyname + ",  IP: " +  String(WiFi.localIP()) + ",  WLAN: " + String(WiFi.RSSI()) + "dBm, " +  String(millis()) + "ms");
    Serial.println("WhatsAppMessage:");
    Serial.println(appmessage);
     //### sendWhatsAppMessage(appmessage);  

#endif       // *****************************************

// ----------  Freigabe- und GetDataLED werden langsam heller ------------------  (auch WArtezeit zum Lesen des Startscreens)
lichtwert = analogRead(LICHTSENSOR) * 100 / 4095;                                // misst Raumhelligkeit bei jedem ESP
int zeit = 10;
if (lichtwert < 10 || lichtwert > 90) zeit = 1;                                  // wenn der Lichtsensor verdunkelt ist oder sehr hell ist, geht der Start schneller
for (freigabeledhelligkeit = 0; freigabeledhelligkeit < 130; freigabeledhelligkeit++) {
  ledcWrite(pwmchannelfreigabeled, freigabeledhelligkeit);
  delay(zeit);
  if (TFTVorhanden == 1) delay(zeit * 2);
}
for (getdataledhelligkeit = 0; getdataledhelligkeit < 130; getdataledhelligkeit++) {
  ledcWrite(pwmchannelgetdataled, getdataledhelligkeit);
  delay(zeit);
  if (TFTVorhanden == 1) delay(zeit * 2);
}
getdataledhelligkeit = 0;
freigabeledhelligkeit = 0;
ledcWrite(pwmchannelfreigabeled, freigabeledhelligkeit);
ledcWrite(pwmchannelgetdataled, getdataledhelligkeit);


#if TFTVorhanden == 1      // ******************* 
  display.fillScreen(BLACK);
#endif   // **********************************

/*  // druckt alle Charzeichen von 0 -130 ASCII Code
char zeichen;
int z = 1;
Serial.println(F("ASCII Zeichencode - TFT Displaytreiber kann nur ASCII-Zeichen: "));
for (int i = 0; i <= 130; i++)  {zeichen = char(i); Serial.print(String(i) + " "+ zeichen + ", "); z++; if (z == 10) {Serial.println(); z = 1;}} 
Serial.println();
*/

letzteslichtraschheller = millis();
lichtraschheller = true;

imsetup = false;

#if TFTVorhanden == 1   //*********************************************
isolarenergie = Datumerstbefuellung(isolarenergie);                          //  das Wochentagarray in den Objekten der Integralklasse werden befüllt
itagesaussentemp = Datumerstbefuellung(itagesaussentemp);
#endif   // **************************************************

Serial.println(F(" ------------------ SETUP ENDE --------------------"));
Serial.println(F("  "));
Meldung("Setuproutine beendet", 'w');
}     //  Ende SETUP

#if TFTVorhanden == 1    // ************************************************
// --------------------------------------------
cIntegralberechnung Datumerstbefuellung (cIntegralberechnung integralx) {   // befüllt zu Beginn die Arrays  er Integralklasse mit den Wochentagen
    
    for (int i = 0; i < integralarraymax; i++) {
      integralx.sdatum[i] = "----";
      }

return integralx;
}  // end String sWochentagerstbefuellung
#endif  // ***************************************************


// ####################  LOOP  ###############################################################################

void loop() {

/* Struktur Loop:
1. sehr schnelle Abfragen - OTA, Touch, Freigabegesamt
2. Rücksetzen der Zeitzähler bei Neustart millis nach ca 50 Tagen
3. 1 Sek Loop1  Screensaver, TFT Helligkeitsteuerung, FreigabeLED
4. 4 Sek Loop2 - Display Anzeigen, SendData, GetData und Stringzerlegung, Schalten der Kommandos  
5. 7 Sek Loop3 - Temperaturabfrage , Lichtwerte, Löschen DL und % Anzeigen
6. 15 Sek Loop4 - DHT Abfrage, Wifi Verbindungsversuche, Epatrone
7. 6 min Loop5 - für Messwerte für die Diagramme  (Zeit bestimmt über diagrammscannintervall in sec)
*/

// =========================== die schnellen Aufgaben   ===================================

startzeithauptloop = micros();

// -----------------------  50 Tage millis() reset ----------

if (millis() > 5 && millis() < 2000) {   
  Meldung("Millisueberlauf - ms>5&<2000!", 'y');
  letzterloop1 = millis();
  letzterloop2 = millis();
  letzterloop3 = millis();
  letzterloop4 = millis();
  letzterloop5 = millis();
  letztertouchscreensaver = millis();
  letzteslichtraschheller = millis();
  letzterwificonnectversuch = millis();
  letztefreigabe_resetesp = millis();
  letztermeldetest = millis();
  letztefreigabegesamt = millis();
  letztefreigabeweb = millis();  
  letzterwasseralarm = millis();
  letztertouchbutton = millis();
  letztermasterupdate = millis();
  letztesmasterupdatenachlaufzeit = millis();
  einschaltzeitpunkt_epatrone = millis();
  einschaltzeitpunkt_mischer = millis(); 
  
  for (int i = 0; i < felderfusszeile; i++) {          // Variablen aus TouchScreen Buttons
    freigabetouchunten[i] = false; 
    letztefreigabetouchunten[i] = 0;
    freigabetouchmitte[i] = false; 
    letztefreigabetouchmitte[i] = 0;
  }   
  touchbuttondazwischennichtgedrueckt = false;
  letztetftaenderungoben = millis();
  
}   // end if millis()

ArduinoOTA.handle();

#if TFTVorhanden == 1     // *****************************************                        

  Touchscreen();    

  // -------- Nachlaufzeit Freigabegesamt bei getData-Freigabe  ------------------- muss in der schnellen loop bleiben  - loop1 ist zu langsam für erkennung schaltbefehle bzw freigabe bei touch
  if (freigabegesamt == true || millis() < letztefreigabegesamt + nachlaufzeitfreigabegesamt) {    // nachlaufzeit für Freigabe, damit die steuerbefehle noch übertragen werden
      sFreigabe = "JA"; 
      if (freigabegesamt == true) freigabegesamtalt = freigabegesamt;
    }  
    else if (freigabegesamt == false && freigabegesamtalt == true) {                               // erkennen fallende Flanke bei freigabegesamt
      letztefreigabegesamt = millis(); 
      freigabegesamtalt = freigabegesamt;
    }         
    else if (freigabegesamt == false) {
      sFreigabe = "NEIN";
      freigabeweb = false;
    }

  //  ------------------------- Freigabeweb retour setzen  ---------------------------- (wird gebraucht, falls die Freigabe per web erteilt wird, die webseite dann aber vor dem zurücksetzen der Freigabe wieder verlassen wird)
  if (millis() > letztefreigabeweb + nachlaufzeitfreigabegesamt && millis() < letztefreigabeweb + nachlaufzeitfreigabegesamt + 3000) {
    freigabeweb = false;
  }  

  // ------------------ Nachlaufzeit Masterupdate - wird gleich behandelt wie Freigabe - Verlängerung der Laufzeit         ---------------- 
  if (smyname == "KHz") {
    if (masterupdate == true || millis() < letztesmasterupdatenachlaufzeit + nachlaufzeitfreigabegesamt) {        // nachlaufzeit für Freigabe, damit die steuerbefehle nochübertragen werden
      sFreigabe = "JA";
      smasterupdate = "MAU"; 
      if (masterupdate == true) masterupdatealt = masterupdate;
    }  
    else if (masterupdate == false && masterupdatealt == true) {                                         // erkennen fallende Flanke bei freigabegesamt
      letztesmasterupdatenachlaufzeit = millis(); 
      masterupdatealt = masterupdate;
    }         
    else if (masterupdate == false) {
      smasterupdate = "NEIN";
    }
  }    // end if smyname

# endif   // *****************************************


  //  ---------------------- Freigabegesamt  -----------------------------------
  if (freigabeweb == true || freigabetouchunten[0] == true || freigabetouchunten[1] == true || freigabetouchunten[2] == true || freigabetouchmitte[0] == true || freigabetouchmitte[1] == true || freigabetouchmitte[2] == true)  {
    freigabegesamt = true;
  }
  else freigabegesamt = false;


// ------------------- Versaeumte Meldungen berechnen ----------------------------
  versaeumtemeldungen = midx + midxmax * angezeigtemeldungenueberlauf - letzteangezeigtemeldung;        // berechnet die summe an meldungen - den aus der letztenanzeige
  if (versaeumtemeldungen >= midxmax - 1) versaeumtemeldungen = midxmax - 1;  
  if (versaeumtemeldungen >= 99) versaeumtemeldungen = 99;                                            // damit nicht mehr angezeigt wird als 99, egal wie hoch midxmax ist
  if (angezeigtemeldungenueberlauf > 5) angezeigtemeldungenueberlauf = 5;                               // Begrenzung für Variable 


if (zeitmessunghauptloop == true) Serial.println("LOOP - OOOOO  schnelle HauptLoopdurchlaufzeit: " + String(micros() - startzeithauptloop) + " microsec.");


// ======================  1 Sec  Loop1  -------  Screensaver, TFT ein bei hell ==================
// wenn 1 sek loop zu  zeitaufwändig wird evt Problem in touchroutine   nichtTouchProzesseStop()
if (millis() > letzterloop1 + 1000) {
  letzterloop1 = millis();
  Loop1();
  if (zeitmessung == true) Serial.println("LOOP 1 - OOOOO  Loopdurchlaufzeit 1: " + String(micros() - startzeithauptloop)  + " microsec.");
}  // end if loop1

//  ===================   4 sec Loop2   ---   TFT Refresh  (Fusszeile in x sec , Werte in 2x sec)===============================
if (millis() > letzterloop2 + 4000) {
  letzterloop2 = millis();
  Loop2();
  if (zeitmessung == true) Serial.println("LOOP 2 - OOOOO  Loopdurchlaufzeit 2: " + String(millis() - letzterloop2) + " ms");
}   // end if loop2  

// =====================  7 sec Loop3  -----  Temperatur async, Datenempfang , Stringaufteilung, Lichtwerte  ========================== 
if (millis() > letzterloop3 + 7000) {
  letzterloop3 = millis();
  Loop3(); 
  if (zeitmessung == true) Serial.println("LOOP 3 - OOOOO  Loopdurchlaufzeit 3: " + String(millis() - letzterloop3) + " ms");
}   // end if loop3

//  ==================  15 sec loop4   -----   E-Patrone , DHT Abfrage ============  
if (millis() > letzterloop4 + 15000) {
  letzterloop4 = millis();
  Loop4();
  if (zeitmessung == true) Serial.println("LOOP 4 - OOOOO  Loopdurchlaufzeit 4: " + String(millis() - letzterloop4) + " ms");
}   // end if loop 4


#if TFTVorhanden == 1   // *****************************************

  // -----------------  schnelles Blinken FreigabeLED bei Bediensperre ------------------------
  if ((bediensperregetdata == true || freigabeweb == true) && millis() > letztesschnellesblinkenfreigabeled + 250) {
    if (freigabeledhelligkeit == 0)  freigabeledhelligkeit = Helligkeitssteuerung();
    else freigabeledhelligkeit = 0;
    ledcWrite(pwmchannelfreigabeled, freigabeledhelligkeit);
    letztesschnellesblinkenfreigabeled = millis();
  } 

//  ==================  loop5  für Diagrammdatenbefüllung  ============  

  if (millis() > letzterloop5 + diagrammscanintervall * 1000) {             
    letzterloop5 = millis();
    Loop5();                                            // ist in Tab nAnz5.ino
    if (anzeige == 5) AnzeigeDiagramme();
    if (zeitmessung == true) Serial.println("LOOP 5 - OOOOO  Loopdurchlaufzeit 5: " + String(millis() - letzterloop5) + " ms");
  }     // end if loop 5

#endif      // *****************************************


if (zeitmessunghauptloop == true) Serial.println("LOOP - OOOOO  GESAMTE  HauptLoopdurchlaufzeit: " + String(micros() - startzeithauptloop) + " microsec. ");


// =======================================================
}  //  Ende void LOOP()



Dann wird das nix.
Wie stellst Du Dir das vor, soll das irgendwer selbst kompilieren?

Noch eines:
Stelle in den Voreinstellungen die vollständige Ausgabe beim kompilieren ein und dann kopiere die vollständige Fehlermeldung hier rein.

Bei 19 Tabs hört sich das eher danach an, dass die Reihenfolge des Zusammenbaus des Compilat sich verändert und es an einer Vorwärtsdelaration fehlt oder sowas.

Aber ohne zu sehen, was Du da hast, wird das nix.

alles klar ...
die vollständige Fehlermeldung beim compilieren war schon im meinem ersten Beitrag .
Fehlt dir da noch etwas? (Nachtrag: hab das mit den vollständigen Compilermeldungen gefunden - kommt gleich)
Der Punkt ist einfach der, dass das mit der 2.0.17 läuft und die PWM Befehle ja im Grunde Standard sind. Alle Infos sid im Haupttab, den ich vorher kopiert habe. In den anderen Tabs gibt es dazu kiene speziellen xxxxx.h Dateien oder ähnliches. Das spielt sich alles im sEtup und Definitionsteil des Haupttabs ab.
Sieht so aus als würde da plötzlich eine library fehlen, wen ich die esp32 BoardVerwaltung auf 3.0.2 umstelle.
Vlt hatte das ja schon mal jemand .. oder so was ähnliches.

mit 3.0.0 gab es einige breaking changes:

darunter auch das alte LED Control.

An deiner Stelle würde ich zunächst mal in den Beispielen nach neuen Mustern suchen und dann den Sketch umbauen.

Im Link den ich dir gepostet habe findest eine Kurzfassung der Änderungen.

error: 'ledcSetup' was not declared in this scope;

Was könnte der Compiler damit gemeint haben? Hinweis: LED Control (LEDC) - - — Arduino ESP32 latest documentation

Für die dreier Version sind noch nicht alle Bibliotheken angepasst.

Vielen Dank ...
wäre nicht auf die Idee gekommen, dass Befehle von einer Major Release zu nächsten sich so ändern, dass der alte Code von der 2.x.x nicht mehr funktioniert.
Habe auch die Stelle in der Dokumentation schon gefunden und such mir noch die Beispiele dazu ...

das war in meinem Umfeld bei einer Major durchaus üblich.
Heute versionieren wir auch anders.

P.S.:
Derartige Konstrukte meiden wir (hier) eigentlich:

if (millis() > letzterloop4 + 15000)

nutze den unsigned overflow so wie im "Blink Without Delay" gezeigt und du hast keine Probleme.

if (millis() - letzterloop4 > 15000)

alles klar ... war die erste Major Release Änderung für mich...

Neuen Beispielcode für PWM suche ich noch ..

Ok, Danke ... dh dann wohl , dass ich mir noch länger Zeit lassen sollte für die Umstellung ?

Nutze Portable IDE 1.8.19 wo die neue ESP Core Version drauf ist, funktioniert ist OK, wen nicht wird die Zweier, was ist in anderer IDE, genutzt, bin eben alter fauler Sack :wink:

zu den millis():
ah , Danke ..
dh wenn es dann nach ca 50 Tagen den overflow gibt , bekomme ich keine Probleme ?

genau deswegen macht man es so.

As of Board ver 3, many API changes have happened. Check the migration document at https://docs.espressif.com/projects/arduino-esp32/en/latest/migration_guides/2.x_to_3.0.html
Here is a screen grab that is relevant to your first error.
Screenshot 2024-07-28 at 12.50.54

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.