Unsere Markise hat nun eine Steuerung bekommen
Wir besitzen eine funkgesteuerte Markise, die aber keine wetterabhängige Steuerung besitzt.
Darum habe ich mit dem ESP32S3 eine Steuerung bebaut, welche die Sonneneinstrahlung und den Wind misst. Daraus resultiert dann das Auf- und Zufahren der Markise. Wie das nun programmiert ist und welche Hardware ich dazu benötigt habe, ist im folgenden zu lesen.
Die Elektronik
Auf dem Schaltbild ist zu sehen, dass der ESP32S3, ein Display, und 3 Relais ansteuert. Des weiteren wird über den I2C-Bus der Lichtsensor (BH1750) und der Temperatursensor BMP280 angesteuert.
Das Anemometer
wird über eine Steckerleiste angeschlossen, wie auch die anderen Sensoren und die Taster der Markisenfunksteuerung. Ein Netzteil komplettiert die Schaltung.
Die Relais werden über jeweils einen Transistor BC337 angesteuert, um genügend Leistung für das Relais zu haben. Die Relais sind mit den Tastern in der Funksteuerung verbunden und simulieren so den jeweiligen Tastendruck (AUF, ZU, STOPP), da ich keinen Zugang zum Funkprotokoll habe.
Das Signal des Anemometers wird mit einem Operationsverstärker LM358 verstärkt.
3 LEDs zeigen zusätzlich den Status der Markise an.
Das Gehäuse
Die Hardware habe ich in eine passende Abzweigdose eingebaut, welche mir einfache Anschlüsse der externen Komponenten wie Sensoren und Spannungsversorgung bietet.
Im Bild sind gut die verwendeten Steckerleisten für die externen Komponenten zu sehen.
Auch ist die Verdrahtung zum Funkschalter, der auf dem Deckel der Abzweigdose montiert ist, gut zu erkennen.
Die Sensoren
Für die Steuerung benötige ich mindestens 2 Werte, das sin Sonne und Wind. Beide Werte haben Einfluss auf die Regelung. In der Softwarebeschreibung gehe ich darauf weiter ein. Hier soll nur die Positionierung der beiden Sensoren gezeigt werden.
Oben sehen wir das schwarze Anemometer und weiter unten den Lichtsensor mir Temperaturfühler.
Die Software
Auf dem ESP32S3 läuft die gesamte Software, welche sich in die Steuersoftware und in das Web-Interface aufteilt. Diese Aufteilung Spiegelt sich auch in der Aufteilung auf die beiden Kerne wieder. Arduino-SW mit dem Webserver läuft auf Kern 1 und die Markisensteuerung auf Kern 0.
Die Daten werden zentral im der struct MarkiseObject gehalten, welche im EEPROM-Bereich des ESP32S3 abgelegt ist.
struct MarkiseObject
{
uint16_t statusEEPROM_Values; // Status der Werte in der EEPROM, 0 = keine Werte, EEPROM_VALID_FLAG = Werte vorhanden
uint16_t sonneSollWert; // Schwellwert für Sonne
uint16_t windSollWert; // Schwellwert für Wind
uint16_t windSicherheitsZeitSekunden; // Zeit, die die Markise bei starkem Wind eingefahren bleibt, um Schäden zu vermeiden in Sekunden
uint16_t markiseLaufzeitSekunden; // Zeit, die die Markise zum Ein- oder Ausfahren benötigt in Sekunden
uint16_t sonneIstWert; // aktueller Wert für Sonne
uint16_t windIstWert; // aktueller Wert für Wind
uint16_t markiseStatus; // 0 = eingefahren, 1 = ausgefahren, 2 = Einfahren, 3 = Ausfahren
uint16_t markiseBleibtZuZeit; // Zeitintervall für die "bleibt zu Zeit" in Sekunden
uint16_t counterMarkiseAufAbtastung; // Aktueller Counter Wert für die Sonne-Auf-Abtastung der Markise
uint16_t counterMarkiseZuAbtastung; // Aktueller Counter Wert für die Sonne-Zu-Abtastung der Markise
uint16_t counterWindZuAbtastung; // Aktueller Counter Wert für die Wind-Zu-Abtastung der Markise
uint16_t markiseAufAbtastungSekunden; // Zeitintervall für die Auf-Abtastung der Sensoren in Sekunden
uint16_t markiseZuAbtastungSekunden; // Zeitintervall für die Zu-Abtastung der Sensoren in Sekunden
uint16_t windAbtastungSekunden; // Zeitintervall für die Zu-Abtastung der Windstärke in Sekunden
uint16_t countMarkiseAufAbtastung; // Soll für die Auf-Abtastung der Lichtstärke
uint16_t countMarkiseZuAbtastung; // Soll für die Zu-Abtastung der Lichtstärke
uint16_t countWindZuAbtastung; // Soll für die Zu-Abtastung der Windstärke
uint16_t automatikStatus; // Status der Automatik Aus=0, EIN=1
};
Die Task-Struktur
Die Haupttask „MarkiseTask“ steuert den Markise. „TaskMarkiseAuf“ und „TaskMarkiseZu“ übernehmen die zeitaufwendigen Funktionen.
„TaskWindSensor“ ist getrennt vom Sonnensensor, da Wind häufiger abgefragt wird. Die anderen Tasks stellen weitere Werte zur Verfügung. „TaskDisplay“ übernimmt die wechselnde Anzeige der Werte.
„MarkiseTask“ kommuniziert mit „TaskMarkiseAuf“ und „TaskMarkiseZu“ über je ein Semaphore.
TaskHandle_t MarkiseTask;
TaskHandle_t TaskMarkiseAuf;
TaskHandle_t TaskMarkiseZu;
TaskHandle_t TaskWindSensor;
TaskHandle_t TaskLichtMessen;
TaskHandle_t TaskBME280Messen;
TaskHandle_t TaskDisplay;
SemaphoreHandle_t MarkiseZuSemaphore = NULL;
SemaphoreHandle_t MarkiseAufSemaphore = NULL;
Die Reglung "MarkiseTask"
Die Regelung hat 3 State machines.
1. Markise zu: Warten auf Sonne ohne Wind
2. Markise auf: Prüfe auf Sonne und Wind
3. Markise fährt AUF/ZU: Warten
Die Regelung erfolgt über die Soll-und IstWerte von Sonne und Wind, die in den Werten „counterMarkiseAufAbtastung“und „counterMarkiseZuAbtastung“ mit den Schwellwerten „countMarkiseAufAntastung“ und „countMarkiseZuAbtastung“ verglichen werden. Hierdurch werden die Zeitglieder der Regelung erstellt.
Der Wind fließt im gleichen System mit „counterWindZuAbtastung“ und „countWindZuAbtastung“ in die Regelung mit ein.
Die Sonnenwerte werden in dieser Task verarbeitet, die Windwerte werden aber in der Wind-Task aufbereitet, da die Abtastung häufiger erfolgt als bei der Sonne.
void Markise( void * pvParameters ){
Serial.println("Starte Task Markise");
CheckLichtSensor(&markiseObject); // Init Lichtwert
FahreMarkiseZu(&markiseObject,true); // Nach Programmstart
//int windStatus=KEIN_WIND;
for(;;){
// Markise eingefahren
Serial.println("wdt_markise_task==="+String(wdt_markise_task));
wdt_markise_task = WDT_TIMEOUT; //Trigger watchdog
if(markiseObject.automatikStatus == EIN){
if(markiseObject.markiseStatus == EINGEFAHREN){
display_ctrl.setStatus("MARKISE-ZU", String(markiseObject.sonneIstWert)+"lx");
Serial.println("Markise eingefahren warten auf Sonne ohne Wind");
if(trace_on == true) appendFile(LittleFS, "/trace.txt", get_time_stamp("Markise zu").c_str());
digitalWrite(LED_ROT, LOW); // turn the LED on Markise zu
vTaskDelay((markiseObject.markiseAufAbtastungSekunden*1000) / portTICK_PERIOD_MS);
if(CheckLichtSensor(&markiseObject) == true) // Sonne Zähler hochzählen
markiseObject.counterMarkiseAufAbtastung++;
else if(markiseObject.counterMarkiseAufAbtastung>0) // Sonne wieder weg, Zähler runterzählen
markiseObject.counterMarkiseAufAbtastung--;
if(markiseObject.counterMarkiseAufAbtastung >markiseObject.countMarkiseAufAbtastung)
markiseObject.counterMarkiseAufAbtastung=markiseObject.countMarkiseAufAbtastung;// Max-Wert begrenzen
if(markiseObject.counterMarkiseAufAbtastung == markiseObject.countMarkiseAufAbtastung &&
markiseObject.counterWindZuAbtastung <= 2) { // Viel Sonne und fast kein Wind?
FahreMarkiseAuf(&markiseObject, false);
markiseObject.counterMarkiseAufAbtastung=0;
}
String cnt = "cntMarkAuf=" + String(markiseObject.counterMarkiseAufAbtastung) +
" Sonne="+ String(markiseObject.sonneIstWert) + " Wind="+ String(markiseObject.windIstWert);
Serial.println(cnt);
if(trace_on == true) appendFile(LittleFS, "/trace.txt", get_time_stamp(cnt).c_str());
}
// Markise offen
if(markiseObject.markiseStatus == AUSGEFAHREN){
display_ctrl.setStatus("MARKISE-AUF", String(markiseObject.sonneIstWert)+"lx");
Serial.println("Markise ausgefahren warten auf Wind und Sonne");
if(trace_on == true) appendFile(LittleFS, "/trace.txt", get_time_stamp("Markise Auf").c_str());
vTaskDelay((markiseObject.markiseZuAbtastungSekunden*1000) / portTICK_PERIOD_MS);
if(CheckLichtSensor(&markiseObject) == false)
markiseObject.counterMarkiseZuAbtastung++;
else if(markiseObject.counterMarkiseZuAbtastung>0) // Sonne wieder da, Zähler runterzählen
markiseObject.counterMarkiseZuAbtastung--;
if(markiseObject.counterMarkiseZuAbtastung >markiseObject.countMarkiseZuAbtastung)
markiseObject.counterMarkiseZuAbtastung=markiseObject.countMarkiseZuAbtastung;// Max-Wert begrenzen
if(markiseObject.counterMarkiseZuAbtastung == markiseObject.countMarkiseZuAbtastung ||
markiseObject.counterWindZuAbtastung>=markiseObject.countWindZuAbtastung) {
FahreMarkiseZu(&markiseObject,false);
markiseObject.counterMarkiseZuAbtastung=0;
}
String cnt = "cntMarkZu=" + String(markiseObject.counterMarkiseZuAbtastung) +
" Sonne="+ String(markiseObject.sonneIstWert)+ " Wind="+ String(markiseObject.windIstWert);
Serial.println(cnt);
if(trace_on == true) appendFile(LittleFS, "/trace.txt", get_time_stamp(cnt).c_str());
}
while(markiseObject.markiseStatus == FAHRE_AUF || markiseObject.markiseStatus == FAHRE_ZU){
Serial.println("Markise fährt AUF oder ZU -- Warten");
if(trace_on == true) appendFile(LittleFS, "/trace.txt", get_time_stamp("Markise fährt AUF oder ZU -- Warten").c_str());
vTaskDelay((10000) / portTICK_PERIOD_MS); // 10 Sek warten
}
}
else {
vTaskDelay((markiseObject.markiseAufAbtastungSekunden*1000) / portTICK_PERIOD_MS);
Serial.println("Automatik ist aus");
}
}
}
Die WindTask
In der WindTask werden die eingelesenen Werte des AD-Wandlers auf die Werte 0-100 mit der map-Funktion umgesetzt.
Dieser wert wird dann mit dem „windSollWert“ verglichen um festzustellen, ob es ein böiger Wind oder ein normaler wind ist.
Bei Böen wird ein Offset auf „counterWindZuAbtastung“ aufaddiert.
Mit „counterWindZuAbtastung“ wir die Winderfassung in die Regelung eingespeist.
void TaskWind(void * pvParameters){
Serial.println("Starte TaskWind");
for(;;){
Serial.println("wdt_wind_task==="+String(wdt_wind_task));
wdt_wind_task = WDT_TIMEOUT; //Trigger watchdog
vTaskDelay((markiseObject.windAbtastungSekunden*1000) / portTICK_PERIOD_MS);
int wert=0;
wert = analogRead(WIND_AEROMETER);
//Serial.println("Wert="+ String(wert));
wert= map(wert,0,4096,0,100);
#ifdef TESTHW
wert = windSensorWert;
#endif
Serial.println("Analoger WIND-Wert= "+ String(wert));
//Serial.println("CheckWindSensor->AktuellerWindWert="+ String(windSensorWert)+"km/h");
markiseObject.windIstWert = wert;
// Starker WIND?
if(wert >= markiseObject.windSollWert+10){
Serial.println("Markise zufahren Starker Wind");
markiseObject.counterWindZuAbtastung=markiseObject.countWindZuAbtastung; // Starker Wind zählt mehr
markiseObject.counterWindZuAbtastung+=4; // Starker Wind zählt mehr
Serial.println("WindSensor stark->>windIstWert="+ String(markiseObject.windIstWert));
Serial.println("WindSensor stark->>counterWindZuAbtastung="+ String(markiseObject.counterWindZuAbtastung));
continue;
}
// Normaler Wind oder kein Wind
else if(wert>= markiseObject.windSollWert)
markiseObject.counterWindZuAbtastung++;
else if(markiseObject.counterWindZuAbtastung>0) // Wind wieder weg, Zähler runterzählen
markiseObject.counterWindZuAbtastung--;
Serial.println("WindSensor normal->>windIstWert="+ String(markiseObject.windIstWert));
Serial.println("WindSensor normal->>counterWindZuAbtastung="+ String(markiseObject.counterWindZuAbtastung));
}
}
Die Antriebssteuerung der Markise
Unspektakulär wird hier jeweils das Semaphore gesetzt, was die Markise dann AUF oder ZU fahren lässt.
void FahreMarkiseAuf(MarkiseObject *markise, bool manuell){
if(markise->markiseStatus == EINGEFAHREN || manuell==true){
Serial.println("Fahre Markise Auf (Set Semaphore)");
markise->markiseStatus = FAHRE_AUF;
xSemaphoreGive(MarkiseAufSemaphore);
}
}
void TaskFahreMarkiseAuf(void * pvParameters){
Serial.println("Starte TaskFahreMarkiseAuf");
for(;;){
//Semaphore abfragen
if (xSemaphoreTake(MarkiseAufSemaphore, portMAX_DELAY)) {
display_ctrl.setStatus("MARKISE", "--> AUF");
Serial.println("Task-->Fahre Markise Auf -- Start");
if(trace_on == true) appendFile(LittleFS, "/trace.txt", get_time_stamp("Task-->Fahre Markise Auf").c_str());
digitalWrite(LED_GELB, LOW);
digitalWrite(LED_ROT, HIGH); // turn the LED off
digitalWrite(LED_GRUEN, LOW); // turn the LED on
// Schalte Relais für Markise auf
digitalWrite(PIN18AUF, HIGH);
vTaskDelay((500) / portTICK_PERIOD_MS); //500MS Tastendruck
digitalWrite(PIN18AUF, LOW);
vTaskDelay((markiseObject.markiseLaufzeitSekunden*1000) / portTICK_PERIOD_MS);
digitalWrite(PIN20STOPP, HIGH);
vTaskDelay((500) / portTICK_PERIOD_MS); //500MS Tastendruck "Relais Stopp"
digitalWrite(PIN20STOPP, LOW);
markiseObject.counterMarkiseAufAbtastung=0;
markiseObject.counterMarkiseZuAbtastung=0;
markiseObject.markiseStatus = AUSGEFAHREN;
Serial.println("Task-->Fahre Markise Auf -- End");
digitalWrite(LED_ROT, HIGH); // turn the LED off
digitalWrite(LED_GRUEN, LOW); // turn the LED on
digitalWrite(LED_GELB, HIGH);
}
}
}
//**************************************************
//**************************************************
void FahreMarkiseZu(MarkiseObject *markise, bool manuell){
digitalWrite(LED_ROT, LOW); // turn the LED on
if(markise->markiseStatus == AUSGEFAHREN || manuell==true){
Serial.println("Fahre Markise ZU (Set Semaphore)");
markise->markiseStatus = FAHRE_ZU;
xSemaphoreGive(MarkiseZuSemaphore);
}
}
void TaskFahreMarkiseZu(void * pvParameters){
Serial.println("Starte TaskFahreMarkiseZu");
for(;;){
//Semaphore abfragen
if (xSemaphoreTake(MarkiseZuSemaphore, portMAX_DELAY)) {
Serial.println("Task-->Fahre Markise Zu -- Start");
display_ctrl.setStatus("MARKISE", "--> ZU");
if(trace_on == true) appendFile(LittleFS, "/trace.txt", get_time_stamp("Task-->Fahre Markise Zu").c_str());
digitalWrite(LED_GELB, LOW);
digitalWrite(LED_GRUEN, HIGH);
digitalWrite(LED_ROT, LOW);
// Schalte Relais für Markise zu
digitalWrite(PIN19ZU, HIGH);
vTaskDelay((500) / portTICK_PERIOD_MS); //500MS Tastendruck "Relais zu"
digitalWrite(PIN19ZU, LOW);
vTaskDelay((markiseObject.markiseLaufzeitSekunden*1000) / portTICK_PERIOD_MS);
digitalWrite(PIN20STOPP, HIGH);
vTaskDelay((500) / portTICK_PERIOD_MS); //500MS Tastendruck "Relais Stopp"
digitalWrite(PIN20STOPP, LOW);
markiseObject.markiseStatus = EINGEFAHREN;
markiseObject.counterMarkiseAufAbtastung=0;
markiseObject.counterMarkiseZuAbtastung=0;
Serial.println("Task-->Fahre Markise Zu -- End");
digitalWrite(LED_ROT, LOW);
digitalWrite(LED_GRUEN, HIGH);
digitalWrite(LED_GELB, HIGH);
}
}
}
Setup()
Hier im Setup() sieht man das anlegen der Tasks und Semaphores sowie das Aufsetzen des LittleFS, welches für das Traceing und den Webserver benötigt wird. Auch ist zu sehen das die Uhrzeit über NTC geholt wird und die interne Uhr (rtc) gesetzt wird.
Das Starten des Webservers leitet dann über zum Web-Interface welches auch auf dem ESP32S3 gehostet ist.
void setup() {
Serial.begin(115200);
//Wire.setPins(SDA, SCL);
Wire.begin(SDA,SLC);
pinMode(LED_GELB, OUTPUT);
pinMode(LED_ROT, OUTPUT);
pinMode(LED_GRUEN, OUTPUT);
pinMode(PIN18AUF, OUTPUT);
pinMode(PIN19ZU, OUTPUT);
pinMode(PIN20STOPP, OUTPUT);
digitalWrite(LED_GELB, HIGH); // turn the LED off
digitalWrite(LED_ROT, HIGH); // turn the LED off
digitalWrite(LED_GRUEN, HIGH); // turn the LED off
digitalWrite(PIN18AUF, LOW); // Turn Transistor closed
digitalWrite(PIN19ZU, LOW); // Turn Transistor closed
digitalWrite(PIN20STOPP, LOW); // Turn Transistor closed
lightMeter.begin();
/*bool status = bme.begin();
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}*/
sensor.begin(Bme280TwoWireAddress::Primary); // Also for BMP
sensor.setSettings(Bme280Settings::weatherMonitoring());
DisplayMutex = xSemaphoreCreateMutex();
if (DisplayMutex == NULL) {
Serial.println("Failed to create DISPLAY mutex!");
while (1);
}
EEPROM.begin(EEPROM_SIZE);
int eepromSize = EEPROM.length();
Serial.println("EEPROM_SIZE=="+ String(eepromSize));
uint16_t statusEEPROM_Values;
EEPROM.get(0, statusEEPROM_Values);
Serial.println("statusEEPROM_Values==="+ String(statusEEPROM_Values));
EEPROM.get(0, markiseObject);
PrintMarkiseStruct(&markiseObject);
if (statusEEPROM_Values == uint16_t(EEPROM_VALID_FLAG)) // Überprüfen, ob Werte im EEPROM gültig sind
{
EEPROM.get(0, markiseObject);
Serial.println("EEPROM holen= "+ String(markiseObject.statusEEPROM_Values));
PrintMarkiseStruct(&markiseObject);
}
else
{
InitMyData(&markiseObject);
//EEPROM.put(0, markiseObject);
//EEPROM.commit();
//EEPROM.get(0, markiseObject);
//markiseObject.statusEEPROM_Values= EEPROM_VALID_FLAG;
Serial.println("EEPROM schreiben= "+ String(markiseObject.statusEEPROM_Values));
PrintMarkiseStruct(&markiseObject);
}
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
u8g2_for_adafruit_gfx.begin(display); // connect u8g2 procedures to Adafruit GFX
u8g2_for_adafruit_gfx.setFont(u8g2_font_helvR14_tf); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
u8g2_for_adafruit_gfx.setFontMode(1); // use u8g2 transparent mode (this is default)
u8g2_for_adafruit_gfx.setFontDirection(0); // left to right (this is default)
u8g2_for_adafruit_gfx.setForegroundColor(WHITE); // apply Adafruit GFX color
//print_display("WAIT FOR", "COMMAND");
timer= timerBegin(1000000000); // Set IR pulse counter to 1MS resolution
initWiFi();
initLittleFS();
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
if(!getLocalTime(&timeinfo)){
Serial.println("Zeit konnte nicht geholt werden");
return;
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
rtc.setTimeStruct(timeinfo);
display_ctrl.setTime(rtc.getTime(), ""); // Set time for display
MarkiseZuSemaphore = xSemaphoreCreateCounting(SEMAPHORE_MAX_COUNT, 0);
if (MarkiseZuSemaphore == NULL) {
Serial.println("Failed to create MarkiseZuSemaphore!");
while (1);
}
MarkiseAufSemaphore = xSemaphoreCreateCounting(SEMAPHORE_MAX_COUNT, 0);
if (MarkiseAufSemaphore == NULL) {
Serial.println("Failed to create MarkiseAufSemaphore!");
while (1);
}
xTaskCreatePinnedToCore(
TaskFahreMarkiseZu, /* Funktion */
"TaskFahreMarkiseZu", /* Name */
10000, /* Stackgröße */
NULL, /* Parameter */
2, /* Priorität */
&TaskMarkiseZu, /* Task-Handle */
0); /* Kern 1 */
xTaskCreatePinnedToCore(
TaskFahreMarkiseAuf, /* Funktion */
"TaskFahreMarkiseAuf", /* Name */
10000, /* Stackgröße */
NULL, /* Parameter */
2, /* Priorität */
&TaskMarkiseAuf, /* Task-Handle */
0); /* Kern 1 */
xTaskCreatePinnedToCore(
TaskWind, /* Funktion */
"TaskWind", /* Name */
10000, /* Stackgröße */
NULL, /* Parameter */
2, /* Priorität */
&TaskWindSensor, /* Task-Handle */
0); /* Kern 1 */
xTaskCreatePinnedToCore(
TaskMesseLicht, /* Funktion */
"LichtMessen", /* Name */
10000, /* Stackgröße */
NULL, /* Parameter */
2, /* Priorität */
&TaskLichtMessen, /* Task-Handle */
0); /* Kern 1 */
xTaskCreatePinnedToCore(
TaskCheck_BME280, /* Funktion */
"BME280Messen", /* Name */
10000, /* Stackgröße */
NULL, /* Parameter */
2, /* Priorität */
&TaskBME280Messen, /* Task-Handle */
0); /* Kern 1 */
xTaskCreatePinnedToCore(
Markise, /* Funktion */
"MarkiseTask", /* Name */
10000, /* Stackgröße */
NULL, /* Parameter */
1, /* Priorität */
&MarkiseTask, /* Task-Handle */
0); /* Kern 1 */
xTaskCreatePinnedToCore(
TaskChangeDisplay, /* Funktion */
"DisplayTask", /* Name */
10000, /* Stackgröße */
NULL, /* Parameter */
2, /* Priorität */
&TaskDisplay, /* Task-Handle */
0); /* Kern 1 */
// Activate watchdog with system reset after timeout
//esp_task_wdt_init(&twdt_config);
Watchdog = xTimerCreate("WatchdogTimer",
1000/portTICK_PERIOD_MS, // 1 Sek period
pdTRUE,
NULL,
WDTCallback);
if (Watchdog == NULL) {
Serial.println("Failed to create Watchdogtimer!");
while (1);
}
xTimerStart(Watchdog, 0); // Starte Watchdog
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
request->send(LittleFS, "/index.html", "text/html", false);
});
server.serveStatic("/", LittleFS, "/");
//Response for all states
server.on("/states", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("Response for all states");
String json = getOutputStates();
request->send(200, "application/json", json);
json = String();
});
// Response for current sun/wind values
server.on("/current", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("Response for current sun/wind values");
String json = getOutputStates2();
request->send(200, "application/json", json);
json = String();
});
//GET request to /update?output=