Soyosource über Shelly Pro 3EM Modbus limitieren [ Abgeschlossen ]

Hi, ich wollte eins meiner Projekte mit euch Teilen, es ermöglicht euch den Shelly Pro 3EM mittels Modbus ( Ethernet / WiFi ) auszulesen und damit den Soyosource über RS485 zu limitieren.

Bitte steinigt mich nicht für die leihen hafte Programmierung / Zusammensetzung ( Es geht sicherlich auch eleganter ). Die Funktion ist jedenfalls gegeben und seit Monaten ohne ausfälle im betrieb. ( Wer spaß dran hat, kann gerne aufräumen ;p )
Ich habe es Endbenutzer tauglich abgeschlossen, so das im im Nachhinein alles über ein Webinterface eingestellt werden kann.
Es können auch mehrere Soyosoure parallel betrieben werden ( Leistung wird einfach durch die Anzahl geteilt ).

Als Hardware benötigt ihr:

  • wt32-eth01 Board ( ESP32 mit Ethernet Port )
  • Einen Programmieradapter für das wt32-eth01 ( USB zu Serial )
  • Ein TTL zu RS485 Board ( Siehe Bild )
  • Ein 5V Netzteil für die Betriebsspannung ( z.b. USB Ladegerät )
  • ggf. für das Gehäuse einen 3D Drucker, 2x 2Pol. Klipp Wagos und eine USB-C Buchse.

Als erstens flasht ihr den Sketch ( Siehe unten ) über die Arduino IDE auf den ESP32 mittels Programmieradapter ( ggf. braucht ihr noch einige Bibliotheken ( Siehe unten)).
Als Board wählt ihr das wt32-eth01 Ethernet Module aus.

Danach verdrahtet ihr die USB Buchse und das TTL zu RS485 Board wie folgt:
Versorgungsspannung ( 5V )
5V => 5V
GND => GND
TTL zu RS485 Board
ESP 3.3V => VCC
ESP GND => GND
ESP IO32 => TXD
ESP IO33 => RXD

Jetzt müsst ihr noch die index.html in den Speicher laden und noch Einstellungen vornehmen.
Falls ihr die Wifi Daten nicht bereits im Sketch angepasst habt, benötigt ihr beim Start eine Ethernet Verbindung ( Hier könnt ihr im Webinterface noch die Wifi Daten anpassen ).
Durch DHCP sollte eurer Router dem ESP nun eine IP zuweisen ( Schaut in euer Router Webinterface nach ).
Ihr könnt auch GPIO 2 beim Start auf HIGH setzen um DHCP zu erzwingen ( Sollte bereits eine falsche statische IP zugewiesen worden sein ).

index.html hochladen:
Geht nun mit euren Browser auf das Upload Webinterface des ESP ( http://192.168.???.???/upload ) und gebt euren Benutzername und Passwort ein ( Standard Benutzername / Passwort: admin / admin ). Klickt auf Upload File und wählt die index.html auf euren Computer aus. Fertig !
( Achtet darauf das die Endung der Datei .html ist und nicht nur .htm )

Einstellungen vornehmen:
Geht nun mit euren Browser auf das Webinterface des ESP ( http://192.168.???.??? ) und klickt dort auf "Details einblenden", hier könnt ihr mit einen Klick auf das Handsymbol alle Einstellungen ändern.
Sollte eine Fehlermeldung kommen "Nicht eingeloggt, keine Änderungen vorgenommen" müsst ihr euch vorher einloggen ( Text Link "Einloggen" direkt unter "Details ausblenden" ).
Standard Benutzer / Passwort ist: admin / admin.

Folgende Einstellungen sind möglich ( Mit ! gekennzeichnet sind erforderlich ):
- WiFi Name
- Wifi Passwort
- ! Pro3EM IP
Die IP Adresse des Shelly Pro 3EM
- !
Invertel Anzahl
Anzahl der Soyosource die ihr parallel betreibt.
- Mod. UDP Intervall
Wie oft die Werte über RS485 an den Soyosource gesendet werden in Millisekuden. ( Ich habe dort aktuell den wert “100” )
- Mod. TCP Intervall
Wie oft eine abfrage an den Shelly stattfindet in Millisekunden ( Habe dort aktuell den wert “100” )
- Mod. TCP Timeout
Wie lange die Antwort vom Shelly brauchen darf, damit die abgefragte Leistung verwendet wird. ( Ich habe dort den Wert “1500” )
- URL Push Service Aktiv (Variablename: json)
Zum Ein oder Ausschalten des HTTP GET Push Service ( 0 = Aus / 1 = EIN ).
Diese Funktion ruft alle X Sekunden die hinterlegte URL auf und überträgt mittels GET Methode ein json String in der variable “json”.
- URL Push Service
Die URL an die alle X Sekunden der JSON String gesendet wird.
- URL Push Intervall
Die Zeitspanne zwischen den URL aufrufen.
- Inverter Max. Leistung
Hier kann die Maximale Leistung gedrosselt werden.
- Leistung um Fixwert reduzieren
Dieser Wert wird ständig von der Leistung abgezogen. ( Solltet ihr Permanent 50 Watt ins Netz drücken, könnt ihr dies hiermit Korrigieren ).
- Eth. Static IP Aktiv
Statische IP Adresse Ein ( 1 ) oder Ausschalten ( 0 )
- Eth. Static IP
Die gewünschte Statische IP Adresse
- Eth. Gateway
- Eth. Subnet
- Prim. DNS
- Sec. DNS
- Benutzer
Benutzername ändern.
- Passwort
Passwort ändern.

Benötigte Bibliotheken:

  • ModbusClientTCPasync
  • Der Rest an Bibliotheken sollte in der Arduino IDE auffindbar sein, ansonsten helfe ich auch gerne weiter.

transparent

Sketch ( ESP32 ):

#include <Arduino.h>
#include <WiFi.h>
#include <ModbusClientTCPasync.h>
#include <WiFiUdp.h> 
#include <ArduinoOTA.h>
#include <HTTPClient.h> 
#include <AsyncTCP.h> 
#include <SPIFFS.h>
#include <ESPAsyncWebServer.h>
#include <Preferences.h>
Preferences preferences;
#include "webpages.h" //file Upload helper
const String default_httpuser = "admin";
const String default_httppassword = "admin";
// configuration structure
struct Config {
  String httpuser;           // username to access web admin
  String httppassword;       // password to access web admin
};
Config config;                        // configuration
String listFiles(bool ishtml = false);




//Div. globale Variablen
#define FIRMWARE_VERSION "v1.0.0"
int debuglevel = 0;
bool L1_error; //Stromklemme Error
bool L2_error; //Stromklemme Error
bool L3_error; //Stromklemme Error
bool N_error; //Stromklemme Error
bool S_error; //Phasen sequenz Error

float N_A; //Neutalleiter Strom
bool N_A_error; //Neutralleiter Nichtübereinstimmung
bool N_O_error; //Neutrallleiter Überstrom Error

float Total_A; //Strom Ingesamt
float Total_W; //Leistung Ingesamt
float Total_sch; //Scheinleistung Insgesamt

float L1_V; //Spannung der Phase
float L1_A; //Strom der Phase
float L1_W; //Leistung der Phase
float L1_SCH; //Scheinleistung der Phase
float L1_PF; //Powerfactor der Phase
bool L1_O_W_error; //Überleistung Error
bool L1_O_V_error; //Überspannung Error
bool L1_O_A_error; //Überstrom Error
float L1_Hz; //Freuqenz der Phase

float L2_V; //Spannung der Phase
float L2_A; //Strom der Phase
float L2_W; //Leistung der Phase
float L2_SCH; //Scheinleistung der Phase
float L2_PF; //Powerfactor der Phase
bool L2_O_W_error; //Überleistung Error
bool L2_O_V_error; //Überspannung Error
bool L2_O_A_error; //Überstrom Error
float L2_Hz; //Freuqenz der Phase

float L3_V; //Spannung der Phase
float L3_A; //Strom der Phase
float L3_W; //Leistung der Phase
float L3_SCH; //Scheinleistung der Phase
float L3_PF; //Powerfactor der Phase
bool L3_O_W_error; //Überleistung Error
bool L3_O_V_error; //Überspannung Error
bool L3_O_A_error; //Überstrom Error
float L3_Hz; //Freuqenz der Phase
static unsigned long push_lastMillis = 0;
int pushservice = 0;
String pushservice_url = "";
long push_interval = 900000; 
String modbus_ip; //nur zu ausgabe für get json 
int  sip_ipa;
int  sip_ipb;
int  sip_ipc;
int  sip_ipd;
 
int  gip_ipa;
int  gip_ipb;
int  gip_ipc;
int  gip_ipd;
 
int sub_ipa;
int sub_ipb;
int sub_ipc;
int sub_ipd;
 
int pdns_ipa;
int pdns_ipb;
int pdns_ipc;
int pdns_ipd;

int sdns_ipa;
int sdns_ipb;
int sdns_ipc;
int sdns_ipd;

int modbus_ipa;
int modbus_ipb;
int modbus_ipc;
int modbus_ipd;

//Modbus 
int modbus_interval = 100; 
static unsigned long Modbus_lastMillis = 0;
int modbus_timeout = 1500; //Dauert die Antwort länger, werden keine Daten zum Soyo geschickt ( Power = 0 )
int modbus_fehler_count = 0;


//RS485 control
#define RS485_RXPin        32  // Serial Receive pin ( Pin CFG)
#define RS485_TXPin        33  // Serial Transmit pin ( Pin RS485_EN)
#define RS485_TX_PIN_VALUE HIGH
#define RS485_RX_PIN_VALUE LOW
HardwareSerial RS485Serial(1);

//Webserver instanz
AsyncWebServer server(80);

//Wifi zugangsdaten
String ssid = "MeinWlanName";
String password = "MeinWlanPasswort";
//Ethernet
#ifndef ETH_PHY_TYPE
#define ETH_PHY_TYPE  ETH_PHY_LAN8720
#define ETH_PHY_ADDR  0
#define ETH_PHY_MDC   23
#define ETH_PHY_MDIO  18
#define ETH_PHY_POWER -1
#define ETH_CLK_MODE  ETH_CLOCK_GPIO0_IN
#endif
#include <ETH.h>
int eth_static_ip = 0; //Ob static ip verwendet wird oder nicht ( Wird überschrieben von Preference weiter unten )


//Soyo Timer / Variablen
int soyo_power_data[8] = {0x24, 0x56, 0x00, 0x21, 0x00, 0x00, 0x80, 0x08}; // 0 Watt
float power_total;
int anz_soyo = 1;
unsigned long Soyo_previousMillis = 0;
int Soyo_interval = 50; 
long max_einspeisung = 1200;
int long einspeisung_reduzieren = 7;


static bool eth_connected = false;

// WARNING: onEvent is called from a separate FreeRTOS task (thread)!
void onEvent(arduino_event_id_t event) {
  switch (event) {
    case ARDUINO_EVENT_ETH_START:
      Serial.println("ETH Started");
      // The hostname must be set after the interface is started, but needs
      // to be set before DHCP, so set it from the event handler thread.
      ETH.setHostname("Pro3M-TCP2RTU");
      break;
    case ARDUINO_EVENT_ETH_CONNECTED: Serial.println("ETH Connected"); break;
    case ARDUINO_EVENT_ETH_GOT_IP:
      Serial.println("ETH Got IP");
      Serial.println(ETH);
      eth_connected = true;
      break;
    case ARDUINO_EVENT_ETH_LOST_IP:
      Serial.println("ETH Lost IP");
      eth_connected = false;
      break;
    case ARDUINO_EVENT_ETH_DISCONNECTED:
      Serial.println("ETH Disconnected");
      eth_connected = false;
      break;
    case ARDUINO_EVENT_ETH_STOP:
      Serial.println("ETH Stopped");
      eth_connected = false;
      break;
    default: break;
  }
}



IPAddress ip = {192, 168, 178, 1};          // IP address of modbus server wird später durch eeprom überschrieben
uint16_t port = 502;                      // port of modbus server
// Create a ModbusTCP client instance
  ModbusClientTCPasync MB(ip, port);





void setup() {
  //preferences.clear();
  Serial.begin(115200);
  preferences.begin("speicher", false); 
  anz_soyo = preferences.getInt("anz_soyo", 3);
  pushservice = preferences.getInt("pushser", 0);
  pushservice_url = preferences.getString("pushserurl", "");
  push_interval = preferences.getInt("pushinv", 900000); 
  ssid = preferences.getString("ssid", "");
  password = preferences.getString("wpass", "");
  config.httpuser = preferences.getString("uploadu", "admin");
  config.httppassword = preferences.getString("uploadp", "admin");
  max_einspeisung = preferences.getInt("max_eins", 3000);
  einspeisung_reduzieren = preferences.getInt("einsp_red", 0);
  Soyo_interval = preferences.getInt("soyo_intv", 100);
  modbus_interval = preferences.getInt("mod_intv", 100);
  modbus_timeout = preferences.getInt("mod_timeo", 3000);
  modbus_ipa = preferences.getInt("mod_ipa", 192);
  modbus_ipb = preferences.getInt("mod_ipb", 168);
  modbus_ipc = preferences.getInt("mod_ipc", 178);
  modbus_ipd = preferences.getInt("mod_ipd", 71);
  IPAddress ip = {modbus_ipa, modbus_ipb, modbus_ipc, modbus_ipd};
  modbus_ip = String(modbus_ipa)+"."+String(modbus_ipb)+"."+String(modbus_ipc)+"."+String(modbus_ipd);
  Serial.println("Booting");
  Serial.print("Firmware: "); Serial.println(FIRMWARE_VERSION);
  WiFi.mode(WIFI_STA); 
  RS485Serial.begin(4800, SERIAL_8N1, RS485_RXPin, RS485_TXPin);

//Pin für DHCP erzwingen
  pinMode(2, INPUT_PULLUP);


//Ethernet
  Network.onEvent(onEvent);
  ETH.begin();
  eth_static_ip = preferences.getInt("ip-static", 0);
  sip_ipa = preferences.getInt("sip_ipa", 192);
  sip_ipb = preferences.getInt("sip_ipb", 168);
  sip_ipc = preferences.getInt("sip_ipc", 178);
  sip_ipd = preferences.getInt("sip_ipd", 182);
  IPAddress local_IP(sip_ipa, sip_ipb, sip_ipc, sip_ipd);   // Static IP Address
  gip_ipa = preferences.getInt("gip_ipa", 192);
  gip_ipb = preferences.getInt("gip_ipb", 168);
  gip_ipc = preferences.getInt("gip_ipc", 178);
  gip_ipd = preferences.getInt("gip_ipd", 1);
  IPAddress gateway(gip_ipa, gip_ipb, gip_ipc, gip_ipd);       // Gateway
  sub_ipa = preferences.getInt("sub_ipa", 255);
  sub_ipb = preferences.getInt("sub_ipb", 255);
  sub_ipc = preferences.getInt("sub_ipc", 255);
  sub_ipd = preferences.getInt("sub_ipd", 0);
  IPAddress subnet(sub_ipa, sub_ipb, sub_ipc, sub_ipd);      // Subnet Mask
  pdns_ipa = preferences.getInt("pdns_ipa", 8);
  pdns_ipb = preferences.getInt("pdns_ipb", 8);
  pdns_ipc = preferences.getInt("pdns_ipc", 8);
  pdns_ipd = preferences.getInt("pdns_ipd", 8);
  IPAddress primaryDNS(pdns_ipa, pdns_ipb, pdns_ipc, pdns_ipd);        // Primary DNS
  sdns_ipa = preferences.getInt("sdns_ipa", 8);
  sdns_ipb = preferences.getInt("sdns_ipb", 8);
  sdns_ipc = preferences.getInt("sdns_ipc", 4);
  sdns_ipd = preferences.getInt("sdns_ipd", 4);
  IPAddress secondaryDNS(sdns_ipa, sdns_ipb, sdns_ipc, sdns_ipd);      // Secondary DNS
  if(eth_static_ip == 1 && digitalRead(2) == HIGH){
    Serial.println("Setze feste IP Adresse");
    ETH.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
    delay(500);
  }
  
// Connect to WiFi
  WiFi.begin(ssid.c_str(), password.c_str());
  delay(200);
  Serial.println("Baue WiFi verbindung auf...");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(". ");
    delay(1000);
  }
  IPAddress wIP = WiFi.localIP();
  Serial.printf("WIFi IP address: %u.%u.%u.%u\n", wIP[0], wIP[1], wIP[2], wIP[3]);
  




// Set up ModbusTCP client.
// - provide onData handler function
  MB.onDataHandler(&handleData);
// - provide onError handler function
  MB.onErrorHandler(&handleError);
// Set message timeout to 2000ms and interval between requests to the same host to 200ms
  MB.setTimeout(2000);
// Start ModbusTCP background task
  MB.setIdleTimeout(60000);
MB.disconnect();
MB.connect(ip, 502);


//filesystem
Serial.println("Mounting SPIFFS ...");
  if (!SPIFFS.begin(true)) {
    // if you have not used SPIFFS before on a ESP32, it will show this error.
    // after a reboot SPIFFS will be configured and will happily work.
    Serial.println("ERROR: Cannot mount SPIFFS, Rebooting");
    ESP.restart();
  }
  Serial.print("SPIFFS Free: "); Serial.println(humanReadableSize((SPIFFS.totalBytes() - SPIFFS.usedBytes())));
  Serial.print("SPIFFS Used: "); Serial.println(humanReadableSize(SPIFFS.usedBytes()));
  Serial.print("SPIFFS Total: "); Serial.println(humanReadableSize(SPIFFS.totalBytes()));



//Server Antworten
server.onNotFound(notFound);
server.onFileUpload(handleUpload);
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html");

server.on("/einstellungen", HTTP_GET, [](AsyncWebServerRequest *request)
  {
   if (checkUserWebAuth(request)) {
    if (request->hasParam("wert")){
      String wert = request->getParam("wert")->value();
    

        if(wert == "anz_soyo" && request->hasParam("value")){
          anz_soyo  = request->getParam("value")->value().toInt();
          preferences.putInt("anz_soyo", anz_soyo);
          String json;
          json += "{";
          json += "\"meldung\":\"Anzahl Inverter eingestellt.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "pushservice" && request->hasParam("value")){
          pushservice = request->getParam("value")->value().toInt();
          preferences.putInt("pushser", pushservice);
          String json;
          json += "{";
          if(pushservice == 1){
            json += "\"meldung\":\"Pushservice Eingeschaltet.\"";
          }else{
            json += "\"meldung\":\"Pushservice Ausgeschaltet.\"";
          }
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "pushservice_url" && request->hasParam("value")){
          pushservice_url = request->getParam("value")->value();
          preferences.putString("pushserurl", pushservice_url);
          delay(1000); //Gib pref ne Sekunde
          String json;
          json += "{";
          json += "\"meldung\":\"Pushservice URL geändert\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "push_interval" && request->hasParam("value")){
          push_interval = request->getParam("value")->value().toInt();
          preferences.putLong("pushinv", push_interval);
          String json;
          json += "{";
          json += "\"meldung\":\"Pushservice Intervall eingestellt.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "httpuser" && request->hasParam("value")){
          config.httpuser = request->getParam("value")->value();
          preferences.putString("uploadu", config.httpuser);
          String json;
          json += "{";
          json += "\"meldung\":\"Benutzer geändert\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "httppassword" && request->hasParam("value")){
          config.httppassword = request->getParam("value")->value();
          preferences.putString("uploadp", config.httppassword);
          String json;
          json += "{";
          json += "\"meldung\":\"Passwort geändert\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "wifipassword" && request->hasParam("value")){
          password = request->getParam("value")->value();
          preferences.putString("wpass", password);
          String json;
          json += "{";
          json += "\"meldung\":\"Wifi Passwort geändert\"";
          json += "}";
          request->send(200, "application/json", json);
          WiFi.begin(ssid.c_str(), password.c_str());
        }

        if(wert == "wifissid" && request->hasParam("value")){
          ssid = request->getParam("value")->value();
          preferences.putString("ssid", ssid);
          String json;
          json += "{";
          json += "\"meldung\":\"Wifi SSID geändert\"";
          json += "}";
          request->send(200, "application/json", json);
          WiFi.begin(ssid.c_str(), password.c_str());
        }

        if(wert == "max_einspeisung" && request->hasParam("value")){
          max_einspeisung  = request->getParam("value")->value().toInt();
          preferences.putLong("max_eins", max_einspeisung);
          String json;
          json += "{";
          json += "\"meldung\":\"Maximale Inverter Power gesetzt.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "einspeisung_reduzieren" && request->hasParam("value")){
          einspeisung_reduzieren = request->getParam("value")->value().toInt();
          preferences.putLong("einsp_red", einspeisung_reduzieren);
          String json;
          json += "{";
          json += "\"meldung\":\"Leistungsdrossel gesetzt.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "Soyo_interval" && request->hasParam("value")){
          Soyo_interval = request->getParam("value")->value().toInt();
          preferences.putInt("soyo_intv", Soyo_interval);
          String json;
          json += "{";
          json += "\"meldung\":\"Inverter RTU Intervall geändert.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "modbus_interval" && request->hasParam("value")){
          modbus_interval = request->getParam("value")->value().toInt();
          preferences.putInt("mod_intv", modbus_interval);
          String json;
          json += "{";
          json += "\"meldung\":\"Pro3EM TCP Intervall geändert.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "modbus_timeout" && request->hasParam("value")){
          modbus_timeout = request->getParam("value")->value().toInt();
          preferences.putInt("mod_timeo", modbus_timeout);
          String json;
          json += "{";
          json += "\"meldung\":\"Pro3EM TCP Timeout geändert.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "modbus_ipa" && request->hasParam("modbus_ipa") && request->hasParam("modbus_ipb") && request->hasParam("modbus_ipc") && request->hasParam("modbus_ipd")){
          modbus_ipa = request->getParam("modbus_ipa")->value().toInt();
          modbus_ipb = request->getParam("modbus_ipb")->value().toInt();
          modbus_ipc = request->getParam("modbus_ipc")->value().toInt();
          modbus_ipd = request->getParam("modbus_ipd")->value().toInt();
          IPAddress ip = {modbus_ipa, modbus_ipb, modbus_ipc, modbus_ipd};
          MB.disconnect();
          MB.connect(ip, 502);
          preferences.putInt("mod_ipa", modbus_ipa);
          preferences.putInt("mod_ipb", modbus_ipb);
          preferences.putInt("mod_ipc", modbus_ipc);
          preferences.putInt("mod_ipd", modbus_ipd);
          String json;
          json += "{";
          json += "\"meldung\":\"Pro3EM TCP IP geändert.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "eth_static_ip" && request->hasParam("value")){
          eth_static_ip = request->getParam("value")->value().toInt();
          preferences.putInt("ip-static", eth_static_ip);
          String json;
          json += "{";
          if(eth_static_ip == 1){
            json += "\"meldung\":\"Static IP Eingeschaltet.\"";
          }else{
            json += "\"meldung\":\"Static IP Ausgeschaltet.\"";
          }
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "sip_ipa" && request->hasParam("sip_ipa") && request->hasParam("sip_ipb") && request->hasParam("sip_ipc") && request->hasParam("sip_ipd")){
          sip_ipa = request->getParam("sip_ipa")->value().toInt();
          sip_ipb = request->getParam("sip_ipb")->value().toInt();
          sip_ipc = request->getParam("sip_ipc")->value().toInt();
          sip_ipd = request->getParam("sip_ipd")->value().toInt();
          IPAddress local_IP(sip_ipa, sip_ipb, sip_ipc, sip_ipd);
          preferences.putInt("sip_ipa", sip_ipa);
          preferences.putInt("sip_ipb", sip_ipb);
          preferences.putInt("sip_ipc", sip_ipc);
          preferences.putInt("sip_ipd", sip_ipd);
          String json;
          json += "{";
          json += "\"meldung\":\"Static IP geändert.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "gip_ipa" && request->hasParam("gip_ipa") && request->hasParam("gip_ipb") && request->hasParam("gip_ipc") && request->hasParam("gip_ipd")){
          gip_ipa = request->getParam("gip_ipa")->value().toInt();
          gip_ipb = request->getParam("gip_ipb")->value().toInt();
          gip_ipc = request->getParam("gip_ipc")->value().toInt();
          gip_ipd = request->getParam("gip_ipd")->value().toInt();
          IPAddress gateway(gip_ipa, gip_ipb, gip_ipc, gip_ipd);
          preferences.putInt("gip_ipa", gip_ipa);
          preferences.putInt("gip_ipb", gip_ipb);
          preferences.putInt("gip_ipc", gip_ipc);
          preferences.putInt("gip_ipd", gip_ipd);
          String json;
          json += "{";
          json += "\"meldung\":\"Gateway IP geändert.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        
        if(wert == "sub_ipa" && request->hasParam("sub_ipa") && request->hasParam("sub_ipb") && request->hasParam("sub_ipc") && request->hasParam("sub_ipd")){
          sub_ipa = request->getParam("sub_ipa")->value().toInt();
          sub_ipb = request->getParam("sub_ipb")->value().toInt();
          sub_ipc = request->getParam("sub_ipc")->value().toInt();
          sub_ipd = request->getParam("sub_ipd")->value().toInt();
          IPAddress subnet(sub_ipa, sub_ipb, sub_ipc, sub_ipd);
          preferences.putInt("sub_ipa", sub_ipa);
          preferences.putInt("sub_ipb", sub_ipb);
          preferences.putInt("sub_ipc", sub_ipc);
          preferences.putInt("sub_ipd", sub_ipd);
          String json;
          json += "{";
          json += "\"meldung\":\"subnet IP geändert.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "pdns_ipa" && request->hasParam("pdns_ipa") && request->hasParam("pdns_ipb") && request->hasParam("pdns_ipc") && request->hasParam("pdns_ipd")){
          pdns_ipa = request->getParam("pdns_ipa")->value().toInt();
          pdns_ipb = request->getParam("pdns_ipb")->value().toInt();
          pdns_ipc = request->getParam("pdns_ipc")->value().toInt();
          pdns_ipd = request->getParam("pdns_ipd")->value().toInt();
          IPAddress primaryDNS(pdns_ipa, pdns_ipb, pdns_ipc, pdns_ipd);
          preferences.putInt("pdns_ipa", pdns_ipa);
          preferences.putInt("pdns_ipb", pdns_ipb);
          preferences.putInt("pdns_ipc", pdns_ipc);
          preferences.putInt("pdns_ipd", pdns_ipd);
          String json;
          json += "{";
          json += "\"meldung\":\"primaryDNS IP geändert.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

        if(wert == "sdns_ipa" && request->hasParam("sdns_ipa") && request->hasParam("sdns_ipb") && request->hasParam("sdns_ipc") && request->hasParam("sdns_ipd")){
          sdns_ipa = request->getParam("sdns_ipa")->value().toInt();
          sdns_ipb = request->getParam("sdns_ipb")->value().toInt();
          sdns_ipc = request->getParam("sdns_ipc")->value().toInt();
          sdns_ipd = request->getParam("sdns_ipd")->value().toInt();
          IPAddress secondaryDNS(sdns_ipa, sdns_ipb, sdns_ipc, sdns_ipd);
          preferences.putInt("sdns_ipa", sdns_ipa);
          preferences.putInt("sdns_ipb", sdns_ipb);
          preferences.putInt("sdns_ipc", sdns_ipc);
          preferences.putInt("sdns_ipd", sdns_ipd);
          String json;
          json += "{";
          json += "\"meldung\":\"secondaryDNS IP geändert.\"";
          json += "}";
          request->send(200, "application/json", json);
        }

      }
   }else{
      String json;
        json += "{";
        json += "\"meldung\":\"Nicht eingeloggt, keine Änderungen vorgenommen.\"";
        json += "}";
        request->send(200, "application/json", json);
    }
  });


server.on("/quicklogin", HTTP_GET, [](AsyncWebServerRequest *request)
  {
    if (checkUserWebAuth(request)) {
      request->redirect("/");
    }else{
    return request->requestAuthentication();
    }
  });


server.on("/werksreset", HTTP_GET, [](AsyncWebServerRequest *request)
  {
 
      preferences.clear();
      ESP.restart();
 
});

/*
server.on("/reboot", HTTP_GET, [](AsyncWebServerRequest *request)
  {
    String json;
        json += "{";
        json += "\"meldung\":\"Wird neugestartet.\"";
        json += "}";
        request->send(200, "application/json", json);
        request->redirect("/");
    delay(3000);
    ESP.restart();
  });
*/

server.on("/json", HTTP_GET, [](AsyncWebServerRequest *request)
  {
    String json;
        json += "{";
        json += "\"antwort\":\"json_all\",";
        json += "\"pro3em_ip\":\""+modbus_ip+"\",\"L1_error\":\""+String(L1_error)+"\",\"L2_error\":\""+String(L2_error)+"\",\"L3_error\":\""+String(L3_error)+"\",\"N_error\":\""+String(N_error)+"\",\"S_error\":\""+String(S_error)+"\",\"N_A\":\""+String(N_A)+"\",\"N_A_error\":\""+String(N_A_error)+"\",\"N_O_error\":\""+String(N_O_error)+"\",\"Total_A\":\""+String(Total_A)+"\",\"Total_W\":\""+String(Total_W)+"\",\"Total_sch\":\""+String(Total_sch)+"\",\"L1_V\":\""+String(L1_V)+"\",\"L1_A\":\""+String(L1_A)+"\",\"L1_W\":\""+String(L1_W)+"\",\"L1_SCH\":\""+String(L1_SCH)+"\",\"L1_PF\":\""+String(L1_PF)+"\",\"L1_O_W_error\":\""+String(L1_O_W_error)+"\",\"L1_O_V_error\":\""+String(L1_O_V_error)+"\",\"L1_O_A_error\":\""+String(L1_O_A_error)+"\",\"L1_Hz\":\""+String(L1_Hz)+"\",\"L2_V\":\""+String(L2_V)+"\",\"L2_A\":\""+String(L2_A)+"\",\"L2_W\":\""+String(L2_W)+"\",\"L2_SCH\":\""+String(L2_SCH)+"\",\"L2_PF\":\""+String(L2_PF)+"\",\"L2_O_W_error\":\""+String(L2_O_W_error)+"\",\"L2_O_V_error\":\""+String(L2_O_V_error)+"\",\"L2_O_A_error\":\""+String(L2_O_A_error)+"\",\"L2_Hz\":\""+String(L2_Hz)+"\",\"L3_V\":\""+String(L3_V)+"\",\"L3_A\":\""+String(L3_A)+"\",\"L3_W\":\""+String(L3_W)+"\",\"L3_SCH\":\""+String(L3_SCH)+"\",\"L3_PF\":\""+String(L3_PF)+"\",\"L3_O_W_error\":\""+String(L3_O_W_error)+"\",\"L3_O_V_error\":\""+String(L3_O_V_error)+"\",\"L3_O_A_error\":\""+String(L3_O_A_error)+"\",\"L3_Hz\":\""+String(L3_Hz)+"\",\"wifi_signal\":\""+String(WiFi.RSSI())+"\",";
        json += "\"anz_soyo\":\""+String(anz_soyo)+"\",\"pushservice\":\""+String(pushservice)+"\",\"pushservice_url\":\""+String(pushservice_url)+"\",";
        json += "\"push_interval\":\""+String(push_interval)+"\"";
        json += ",\"httpuser\":\""+String(config.httpuser)+"\",\"max_einspeisung\":\""+String(max_einspeisung)+"\",\"einspeisung_reduzieren\":\""+String(einspeisung_reduzieren)+"\",\"Soyo_interval\":\""+String(Soyo_interval)+"\",\"modbus_interval\":\""+String(modbus_interval)+"\",\"modbus_timeout\":\""+String(modbus_timeout)+"\",\"modbus_ipa\":\""+String(modbus_ipa)+"\",\"modbus_ipb\":\""+String(modbus_ipb)+"\",\"modbus_ipc\":\""+String(modbus_ipc)+"\",\"modbus_ipd\":\""+String(modbus_ipd)+"\",\"eth_static_ip\":\""+String(eth_static_ip)+"\",\"sip_ipa\":\""+String(sip_ipa)+"\",\"sip_ipb\":\""+String(sip_ipb)+"\",\"sip_ipc\":\""+String(sip_ipc)+"\",\"sip_ipd\":\""+String(sip_ipd)+"\",\"gip_ipa\":\""+String(gip_ipa)+"\",\"gip_ipb\":\""+String(gip_ipb)+"\",\"gip_ipc\":\""+String(gip_ipc)+"\",\"gip_ipd\":\""+String(gip_ipd)+"\",\"sub_ipa\":\""+String(sub_ipa)+"\",\"sub_ipb\":\""+String(sub_ipb)+"\",\"sub_ipc\":\""+String(sub_ipc)+"\",\"sub_ipd\":\""+String(sub_ipd)+"\",\"pdns_ipa\":\""+String(pdns_ipa)+"\",\"pdns_ipb\":\""+String(pdns_ipb)+"\",\"pdns_ipc\":\""+String(pdns_ipc)+"\",\"pdns_ipd\":\""+String(pdns_ipd)+"\",\"sdns_ipa\":\""+String(sdns_ipa)+"\",\"sdns_ipb\":\""+String(sdns_ipb)+"\",\"sdns_ipc\":\""+String(sdns_ipc)+"\",\"sdns_ipd\":\""+String(sdns_ipd)+"\",\"ssid\":\""+String(ssid)+"\"";
        json += "}";
    request->send(200, "application/json", json);
  });


//File upload sever gedöns

  
  // visiting this page will cause you to be logged out
  server.on("/logout", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->requestAuthentication();
    request->send(401);
  });

  // presents a "you are now logged out webpage
  server.on("/logged-out", HTTP_GET, [](AsyncWebServerRequest * request) {
    String logmessage = "Client:" + request->client()->remoteIP().toString() + " " + request->url();
    Serial.println(logmessage);
    request->send_P(401, "text/html", logout_html, processor);
  });

  server.on("/upload", HTTP_GET, [](AsyncWebServerRequest * request) {
    String logmessage = "Client:" + request->client()->remoteIP().toString() + + " " + request->url();

    if (checkUserWebAuth(request)) {
      logmessage += " Auth: Success";
      Serial.println(logmessage);
      request->send_P(200, "text/html", index_html, processor);
    } else {
      logmessage += " Auth: Failed";
      Serial.println(logmessage);
      return request->requestAuthentication();
    }

  });


  server.on("/listfiles", HTTP_GET, [](AsyncWebServerRequest * request)
  {
    String logmessage = "Client:" + request->client()->remoteIP().toString() + " " + request->url();
    if (checkUserWebAuth(request)) {
      logmessage += " Auth: Success";
      Serial.println(logmessage);
      request->send(200, "text/plain", listFiles(true));
    } else {
      logmessage += " Auth: Failed";
      Serial.println(logmessage);
      return request->requestAuthentication();
    }
  });

  server.on("/file", HTTP_GET, [](AsyncWebServerRequest * request) {
    String logmessage = "Client:" + request->client()->remoteIP().toString() + " " + request->url();
    if (checkUserWebAuth(request)) {
      logmessage += " Auth: Success";
      Serial.println(logmessage);

      if (request->hasParam("name") && request->hasParam("action")) {
        const char *fileName = request->getParam("name")->value().c_str();
        const char *fileAction = request->getParam("action")->value().c_str();

        logmessage = "Client:" + request->client()->remoteIP().toString() + " " + request->url() + "?name=" + String(fileName) + "&action=" + String(fileAction);
        File root = SPIFFS.open("/");
        if (!SPIFFS.exists(String(fileName))) {
          Serial.println(logmessage + " ERROR: file does not exist");
          request->send(400, "text/plain", "ERROR: file does not exist");
        } else {
          Serial.println(logmessage + " file exists");
          if (strcmp(fileAction, "download") == 0) {
            logmessage += " downloaded";
            request->send(SPIFFS, fileName, "application/octet-stream");
          } else if (strcmp(fileAction, "delete") == 0) {
            logmessage += " deleted";
            SPIFFS.remove(fileName);
            request->send(200, "text/plain", "Deleted File: " + String(fileName));
          } else {
            logmessage += " ERROR: invalid action param supplied";
            request->send(400, "text/plain", "ERROR: invalid action param supplied");
          }
          Serial.println(logmessage);
        }
      } else {
        request->send(400, "text/plain", "ERROR: name and action params required");
      }
    } else {
      logmessage += " Auth: Failed";
      Serial.println(logmessage);
      return request->requestAuthentication();
    }
  });

//ARDUINO OTA ( IN LOOP SCHLIEFE HÄNDLE WIEDER AUSKOMMENTIEREN !!! )#####################################################################

  // Port defaults to 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  ArduinoOTA.setHostname("Pro3EM-TCP2RTU");

  // No authentication by default
   ArduinoOTA.setPassword("ABCDEF");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

  ArduinoOTA.begin();

//Webserver Starten
  DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
  server.begin();

}







void loop() {
  ArduinoOTA.handle();



//reconnect wifi
if (WiFi.status() != WL_CONNECTED && eth_connected != true){WiFi.begin(ssid.c_str(), password.c_str());  delay (5000); Serial.println("WIFI VERBINDUNG NEU AUFBAUEN");}// connect to the network


if (millis() - Modbus_lastMillis > modbus_interval) {
    Modbus_lastMillis = millis();

    //Serial.printf("sending request ");
     //Serial.println("##################################################################");
    Error err;

    //text[token] = "hallo"; //Modbus_lastMillis
    //Modbus Anfage (Beliebiger Token der im Handler zur Anfrage indifizieren hilft, Modbus Geräte Adresse, Register (Input register), Register Start Adresse, Anzahl an register die ausgelesen werden )
    err = MB.addRequest(Modbus_lastMillis, 1, 0x04, 1002, 77); 
    //token = token + 1;
    //if(token > 48){token = 0; memset(text, 0, sizeof(text));}
    if (err != SUCCESS) {
      ModbusError e(err);
      Serial.printf("Error creating request: %02X - %s\n", (int)e, (const char *)e);
      modbus_fehler_count = modbus_fehler_count + 1;
      if(modbus_fehler_count > 5000){ ESP.restart(); }
    }
  }


if (millis() - push_lastMillis > push_interval) {
  if(pushservice == 1 && pushservice_url != ""){ pushservicestart(); }
  push_lastMillis = millis();
}

}




void pushservicestart(){
  if(WiFi.status()== WL_CONNECTED || eth_connected == true){
    HTTPClient http;
    String json;
          json += "{";
          json += "\"antwort\":\"json_all\",";
          json += "\"from\":\"Pro3EM_TCP2UDP\",\"L1_error\":\""+String(L1_error)+"\",\"L2_error\":\""+String(L2_error)+"\",\"L3_error\":\""+String(L3_error)+"\",\"N_error\":\""+String(N_error)+"\",\"S_error\":\""+String(S_error)+"\",\"N_A\":\""+String(N_A)+"\",\"N_A_error\":\""+String(N_A_error)+"\",\"N_O_error\":\""+String(N_O_error)+"\",\"Total_A\":\""+String(Total_A)+"\",\"Total_W\":\""+String(Total_W)+"\",\"Total_sch\":\""+String(Total_sch)+"\",\"L1_V\":\""+String(L1_V)+"\",\"L1_A\":\""+String(L1_A)+"\",\"L1_W\":\""+String(L1_W)+"\",\"L1_SCH\":\""+String(L1_SCH)+"\",\"L1_PF\":\""+String(L1_PF)+"\",\"L1_O_W_error\":\""+String(L1_O_W_error)+"\",\"L1_O_V_error\":\""+String(L1_O_V_error)+"\",\"L1_O_A_error\":\""+String(L1_O_A_error)+"\",\"L1_Hz\":\""+String(L1_Hz)+"\",\"L2_V\":\""+String(L2_V)+"\",\"L2_A\":\""+String(L2_A)+"\",\"L2_W\":\""+String(L2_W)+"\",\"L2_SCH\":\""+String(L2_SCH)+"\",\"L2_PF\":\""+String(L2_PF)+"\",\"L2_O_W_error\":\""+String(L2_O_W_error)+"\",\"L2_O_V_error\":\""+String(L2_O_V_error)+"\",\"L2_O_A_error\":\""+String(L2_O_A_error)+"\",\"L2_Hz\":\""+String(L2_Hz)+"\",\"L3_V\":\""+String(L3_V)+"\",\"L3_A\":\""+String(L3_A)+"\",\"L3_W\":\""+String(L3_W)+"\",\"L3_SCH\":\""+String(L3_SCH)+"\",\"L3_PF\":\""+String(L3_PF)+"\",\"L3_O_W_error\":\""+String(L3_O_W_error)+"\",\"L3_O_V_error\":\""+String(L3_O_V_error)+"\",\"L3_O_A_error\":\""+String(L3_O_A_error)+"\",\"L3_Hz\":\""+String(L3_Hz)+"\",\"wifi_signal\":\""+String(WiFi.RSSI())+"\"";
          json += "}";
    String serverPath = pushservice_url + "?json="+json;
    http.begin(serverPath.c_str());
    int httpResponseCode = http.GET();
    http.end();
  }
}



//Soyosource Daten aufbereiten
void setSoyoPowerData(int power){
  soyo_power_data[0] = 0x24;
  soyo_power_data[1] = 0x56;
  soyo_power_data[2] = 0x00;
  soyo_power_data[3] = 0x21;
  soyo_power_data[4] = power >> 0x08;
  soyo_power_data[5] = power & 0xFF;
  soyo_power_data[6] = 0x80;
  soyo_power_data[7] = calc_checksumme(soyo_power_data[1], soyo_power_data[2], soyo_power_data[3], soyo_power_data[4], soyo_power_data[5], soyo_power_data[6]);
}

int calc_checksumme(int b1, int b2, int b3, int b4, int b5, int b6 ){
  int calc = (0xFF - b1 - b2 - b3 - b4 - b5 -b6) % 256;
  return calc & 0xFF;
}


//Modbus Daten Handler
// plus a user-supplied token to identify the causing request
void handleData(ModbusMessage response, uint32_t token) 
{
  //uint16_t aa = response.get(uint16_t index, float& value);
  //Serial.print(text[token]); Serial.println(token);
  if(debuglevel == 1 || debuglevel == 3){Serial.printf("Response: serverID=%d, FC=%d, Token=%08X, length=%d:\n", response.getServerID(), response.getFunctionCode(), token, response.size());}
  int antwortzeit = millis() - token;
  
  if(debuglevel == 1 || debuglevel == 3){
  Serial.print("Modbus antwortzeit: ");
  Serial.println(antwortzeit);
  }
  /* //Hex ausgabe
  for (auto& byte : response) {
    Serial.printf("%02X ", byte);
  }
  */

  uint16_t offs = 3;


float floatValue = 0.0;
uint16_t boolValue;
  offs = response.get(offs, boolValue); //31002
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase A meter error ( Bool ):    "); Serial.println(String(boolValue)); }
  L1_error = boolValue;
  offs = response.get(offs, boolValue); //31003
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase B meter error ( Bool ):    "); Serial.println(String(boolValue));}
  L2_error = boolValue;
  offs = response.get(offs, boolValue); //31004
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase C meter error ( Bool ):    "); Serial.println(String(boolValue));}
  L3_error = boolValue;
  offs = response.get(offs, boolValue); //31005
  if(debuglevel == 2 || debuglevel == 3){Serial.print("N meter error ( Bool ):          "); Serial.println(String(boolValue));}
  N_error = boolValue;
  offs = response.get(offs, boolValue); //31006
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase sequence meter error(Bool):"); Serial.println(String(boolValue)); }
  S_error = boolValue;

  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31007-31008
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Neutral current, A ( Float ):    "); Serial.println(String(floatValue));}
  N_A = floatValue;

  offs = response.get(offs, boolValue); //31009
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Neutral current mismatch ( Bool ):"); Serial.println(String(boolValue));}
  N_A_error = boolValue;
  offs = response.get(offs, boolValue); //31010
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Neutral overcurrent error ( Bool ):"); Serial.println(String(boolValue)); }
  N_O_error = boolValue;

  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31011 - 12
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Total current, A  ( Float ):       "); Serial.println(String(floatValue));}
  Total_A = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31013 -14
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Total active power, W  ( Float ):  "); Serial.println(String(floatValue));}
  Total_W = floatValue;
      if (millis() - Soyo_previousMillis >= Soyo_interval){
            power_total = floatValue; 
            int value_power=(int)power_total;
            value_power = value_power / anz_soyo;
            value_power = value_power - einspeisung_reduzieren;
            if(value_power > max_einspeisung){ value_power = max_einspeisung;}
            if(value_power < 0){value_power = 0;}
            setSoyoPowerData(value_power);
            

            //send data to RS485 
              if(antwortzeit <= modbus_timeout){
                            if(debuglevel == 1 || debuglevel == 3){Serial.print("Sende ");Serial.print(value_power);Serial.println("W an Soyo");}
                            if(debuglevel == 1 || debuglevel == 3){Serial.println("############################################");}
                            for(int i=0; i<8; i++){
                              RS485Serial.write(soyo_power_data[i]);
                              if(debuglevel == 1 || debuglevel == 3){Serial.print(soyo_power_data[i], HEX);}
                              if(debuglevel == 1 || debuglevel == 3){Serial.print(" ");}
                            }
                            if(debuglevel == 1 || debuglevel == 3){Serial.println("");Serial.println("############################################");}
              }else{Serial.print("Modbus Timeout !!! Die Modbusantwort hat länger als ");Serial.print(modbus_timeout);Serial.println("ms gedaudert.");}
          Soyo_previousMillis = millis(); 
          value_power = 0;
    } 
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31015 -16
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Total apparent power, VA ( Float ):"); Serial.println(String(floatValue));}
  Total_sch = floatValue;

  //3 reserve registers
  offs = response.get(offs, boolValue); //31017
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Reserve Register:         (bool)    "); Serial.println(String(boolValue)); }
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31018 - 19
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Reserve Register: ( Float ):        "); Serial.println(String(floatValue));}

  //Phase A
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31020 - 21
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase A voltage, V  ( Float ):       "); Serial.println(String(floatValue));}
  L1_V = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31022 - 23
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase A current, A  ( Float ):       "); Serial.println(String(floatValue));}
  L1_A = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31024 - 25
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase A active power, W  ( Float ):  "); Serial.println(String(floatValue));}
  L1_W = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31026 - 27
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase A apparent power  ( Float ):    "); Serial.println(String(floatValue));}
  L1_SCH = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31028 - 29
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase A power factor  ( Float ):       "); Serial.println(String(floatValue));}
  L1_PF = floatValue;

  offs = response.get(offs, boolValue); //31030
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase A overpower error:     (bool)    "); Serial.println(String(boolValue)); }
  L1_O_W_error = boolValue;
  offs = response.get(offs, boolValue); //31031
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase A overvoltage error     (bool)    "); Serial.println(String(boolValue)); }
  L1_O_V_error = boolValue;
  offs = response.get(offs, boolValue); //31032
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase A overcurrent error:    (bool)    "); Serial.println(String(boolValue)); }
  L1_O_A_error = boolValue;

  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31033 - 34
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase A frequency, Hz  ( Float ):       "); Serial.println(String(floatValue));}
  L1_Hz = floatValue;


  //5 reserve registers
  offs = response.get(offs, boolValue); //31035
  //Serial.print("Reserve Register:         (bool)    "); Serial.println(String(boolValue)); 
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31036 - 37
  //Serial.print("Reserve Register: ( Float ):        "); Serial.println(String(floatValue));
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31038 - 39
  //Serial.print("Reserve Register: ( Float ):        "); Serial.println(String(floatValue));


  //Phase B
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31040 - 41
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase B voltage, V  ( Float ):       "); Serial.println(String(floatValue));}
  L2_V = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31042 - 43
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase B current, A  ( Float ):       "); Serial.println(String(floatValue));}
  L2_A = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31044 - 45
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase B active power, W  ( Float ):  "); Serial.println(String(floatValue));}
  L2_W = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31046 - 47
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase B apparent power  ( Float ):    "); Serial.println(String(floatValue));}
  L2_SCH = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31048 - 49
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase B power factor  ( Float ):       "); Serial.println(String(floatValue));}
  L2_PF = floatValue;

  offs = response.get(offs, boolValue); //31050
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase B overpower error:     (bool)    "); Serial.println(String(boolValue)); }
  L2_O_W_error = boolValue;
  offs = response.get(offs, boolValue); //31051
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase B overvoltage error     (bool)    "); Serial.println(String(boolValue)); }
  L2_O_V_error = boolValue;
  offs = response.get(offs, boolValue); //31052
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase B overcurrent error:    (bool)    "); Serial.println(String(boolValue)); }
  L2_O_A_error = boolValue;

  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31053 - 54
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase B frequency, Hz  ( Float ):       "); Serial.println(String(floatValue));}
  L2_Hz = floatValue;


  //5 reserve registers
  offs = response.get(offs, boolValue); //31055
  //Serial.print("Reserve Register:         (bool)    "); Serial.println(String(boolValue)); 
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31056 - 57
  //Serial.print("Reserve Register: ( Float ):        "); Serial.println(String(floatValue));
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31058 - 59
  //Serial.print("Reserve Register: ( Float ):        "); Serial.println(String(floatValue));


  //Phase C
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31060 - 61
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase C voltage, V  ( Float ):       "); Serial.println(String(floatValue));}
  L3_V = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31062 - 63
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase C current, A  ( Float ):       "); Serial.println(String(floatValue));}
  L3_A = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31064 - 65
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase C active power, W  ( Float ):  "); Serial.println(String(floatValue));}
  L3_W = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31066 - 67
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase C apparent power  ( Float ):    "); Serial.println(String(floatValue));}
  L3_SCH = floatValue;
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31068 - 69
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase C power factor  ( Float ):       "); Serial.println(String(floatValue));}
  L3_PF = floatValue;

  offs = response.get(offs, boolValue); //31070
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase C overpower error:     (bool)    "); Serial.println(String(boolValue)); }
  L3_O_W_error = boolValue;
  offs = response.get(offs, boolValue); //31071
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase C overvoltage error     (bool)    "); Serial.println(String(boolValue)); }
  L3_O_V_error = boolValue;
  offs = response.get(offs, boolValue); //31072
  if(debuglevel == 2 || debuglevel == 3){Serial.print("Phase C overcurrent error:    (bool)    "); Serial.println(String(boolValue)); }
  L3_O_A_error = boolValue;

  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31073 - 74
  if(debuglevel == 1 || debuglevel == 3){Serial.print("Phase C frequency, Hz  ( Float ):       "); Serial.println(String(floatValue));}
  L3_Hz = floatValue;

  //5 reserve registers
  offs = response.get(offs, boolValue); //31055
  //Serial.print("Reserve Register:         (bool)    "); Serial.println(String(boolValue)); 
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31056 - 57
  //Serial.print("Reserve Register: ( Float ):        "); Serial.println(String(floatValue));
  offs = response.get(offs, floatValue, SWAP_REGISTERS); //31058 - 59
  //Serial.print("Reserve Register: ( Float ):        "); Serial.println(String(floatValue));
}

//Error Handler für Modbus (Nicht weiter ausgeführt für das Projekt)
// Define an onError handler function to receive error responses
// Arguments are the error code returned and a user-supplied token to identify the causing request
void handleError(Error error, uint32_t token) 
{
  // ModbusError wraps the error code and provides a readable error message for it
  ModbusError me(error);
  Serial.printf("Error response: %02X - %s token: %d\n", (int)me, (const char *)me, token);
}












//Filesystem html upload
void notFound(AsyncWebServerRequest *request) {
  String logmessage = "Client:" + request->client()->remoteIP().toString() + " " + request->url();
  Serial.println(logmessage);
  request->send(404, "text/plain", "Not found");
}


// list all of the files, if ishtml=true, return html rather than simple text
String listFiles(bool ishtml) {
  String returnText = "";
  Serial.println("Listing files stored on SPIFFS");
  File root = SPIFFS.open("/");
  File foundfile = root.openNextFile();
  if (ishtml) {
    returnText += "<table><tr><th align='left'>Name</th><th align='left'>Size</th><th></th><th></th></tr>";
  }
  while (foundfile) {
    if (ishtml) {
      returnText += "<tr align='left'><td>" + String(foundfile.name()) + "</td><td>" + humanReadableSize(foundfile.size()) + "</td>";
      returnText += "<td><button onclick=\"downloadDeleteButton(\'" + String(foundfile.name()) + "\', \'download\')\">Download</button>";
      returnText += "<td><button onclick=\"downloadDeleteButton(\'" + String(foundfile.name()) + "\', \'delete\')\">Delete</button></tr>";
    } else {
      returnText += "File: " + String(foundfile.name()) + " Size: " + humanReadableSize(foundfile.size()) + "\n";
    }
    foundfile = root.openNextFile();
  }
  if (ishtml) {
    returnText += "</table>";
  }
  root.close();
  foundfile.close();
  return returnText;
}

// Make size of files human readable
// source: https://github.com/CelliesProjects/minimalUploadAuthESP32
String humanReadableSize(const size_t bytes) {
  if (bytes < 1024) return String(bytes) + " B";
  else if (bytes < (1024 * 1024)) return String(bytes / 1024.0) + " KB";
  else if (bytes < (1024 * 1024 * 1024)) return String(bytes / 1024.0 / 1024.0) + " MB";
  else return String(bytes / 1024.0 / 1024.0 / 1024.0) + " GB";
}



String processor(const String& var) {
  if (var == "FIRMWARE") {
    return FIRMWARE_VERSION;
  }

  if (var == "FREESPIFFS") {
    return humanReadableSize((SPIFFS.totalBytes() - SPIFFS.usedBytes()));
  }

  if (var == "USEDSPIFFS") {
    return humanReadableSize(SPIFFS.usedBytes());
  }

  if (var == "TOTALSPIFFS") {
    return humanReadableSize(SPIFFS.totalBytes());
  }
}


// used by server.on functions to discern whether a user has the correct httpapitoken OR is authenticated by username and password
bool checkUserWebAuth(AsyncWebServerRequest * request) {
  bool isAuthenticated = false;

  if (request->authenticate(config.httpuser.c_str(), config.httppassword.c_str())) {
    Serial.println("is authenticated via username and password");
    isAuthenticated = true;
  }
  return isAuthenticated;
}

// handles uploads to the filserver
void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
  // make sure authenticated before allowing upload
  if (checkUserWebAuth(request)) {
    String logmessage = "UploadClient:" + request->client()->remoteIP().toString() + " " + request->url();
    Serial.println(logmessage);

    if (!index) {
      logmessage = "Upload Start: " + String(filename);
      // open the file on first call and store the file handle in the request object
      request->_tempFile = SPIFFS.open("/" + filename, "w");
      Serial.println(logmessage);
    }

    if (len) {
      // stream the incoming chunk to the opened file
      request->_tempFile.write(data, len);
      logmessage = "Writing file: " + String(filename) + " index=" + String(index) + " len=" + String(len);
      Serial.println(logmessage);
    }

    if (final) {
      logmessage = "Upload Complete: " + String(filename) + ",size: " + String(index + len);
      // close the file handle as the upload is now done
      request->_tempFile.close();
      Serial.println(logmessage);
      request->redirect("/");
    }
  } else {
    Serial.println("Auth: Failed");
    return request->requestAuthentication();
  }
}

webpages.h ( in der Arduino IDE auf + drücken und als webpages.h hinzufügen )

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html lang="en">
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta charset="UTF-8">
</head>
<body>
  <p>Main page</p>
  <p>Firmware: %FIRMWARE%</p>
  <p>Free Storage: <span id="freespiffs">%FREESPIFFS%</span> | Used Storage: <span id="usedspiffs">%USEDSPIFFS%</span> | Total Storage: <span id="totalspiffs">%TOTALSPIFFS%</span></p>
  <p>
  <button onclick="logoutButton()">Logout</button>
  <button onclick="rebootButton()">Reboot</button>
  <button onclick="listFilesButton()">List Files</button>
  <button onclick="showUploadButtonFancy()">Upload File</button>
  </p>
  <p id="status"></p>
  <p id="detailsheader"></p>
  <p id="details"></p>
<script>
function logoutButton() {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/logout", true);
  xhr.send();
  setTimeout(function(){ window.open("/logged-out","_self"); }, 1000);
}
function rebootButton() {
  document.getElementById("statusdetails").innerHTML = "Invoking Reboot ...";
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/reboot", true);
  xhr.send();
  window.open("/reboot","_self");
}
function listFilesButton() {
  xmlhttp=new XMLHttpRequest();
  xmlhttp.open("GET", "/listfiles", false);
  xmlhttp.send();
  document.getElementById("detailsheader").innerHTML = "<h3>Files<h3>";
  document.getElementById("details").innerHTML = xmlhttp.responseText;
}
function downloadDeleteButton(filename, action) {
  var urltocall = "/file?name=/" + filename + "&action=" + action;
  xmlhttp=new XMLHttpRequest();
  if (action == "delete") {
    xmlhttp.open("GET", urltocall, false);
    xmlhttp.send();
    document.getElementById("status").innerHTML = xmlhttp.responseText;
    xmlhttp.open("GET", "/listfiles", false);
    xmlhttp.send();
    document.getElementById("details").innerHTML = xmlhttp.responseText;
  }
  if (action == "download") {
    document.getElementById("status").innerHTML = "";
    window.open(filename,"_blank");
  }
}
function showUploadButtonFancy() {
  document.getElementById("detailsheader").innerHTML = "<h3>Upload File<h3>"
  document.getElementById("status").innerHTML = "";
  var uploadform = "<form method = \"POST\" action = \"/upload/\" enctype=\"multipart/form-data\"><input type=\"file\" name=\"data\"/><input type=\"submit\" name=\"upload\" value=\"Upload\" title = \"Upload File\"></form>"
  document.getElementById("details").innerHTML = uploadform;
  var uploadform =
  "<form id=\"upload_form\" enctype=\"multipart/form-data\" method=\"post\">" +
  "<input type=\"file\" name=\"file1\" id=\"file1\" onchange=\"uploadFile()\"><br>" +
  "<progress id=\"progressBar\" value=\"0\" max=\"100\" style=\"width:300px;\"></progress>" +
  "<h3 id=\"status\"></h3>" +
  "<p id=\"loaded_n_total\"></p>" +
  "</form>";
  document.getElementById("details").innerHTML = uploadform;
}
function _(el) {
  return document.getElementById(el);
}
function uploadFile() {
  var file = _("file1").files[0];
  // alert(file.name+" | "+file.size+" | "+file.type);
  var formdata = new FormData();
  formdata.append("file1", file);
  var ajax = new XMLHttpRequest();
  ajax.upload.addEventListener("progress", progressHandler, false);
  ajax.addEventListener("load", completeHandler, false); // doesnt appear to ever get called even upon success
  ajax.addEventListener("error", errorHandler, false);
  ajax.addEventListener("abort", abortHandler, false);
  ajax.open("POST", "/");
  ajax.send(formdata);
}
function progressHandler(event) {
  //_("loaded_n_total").innerHTML = "Uploaded " + event.loaded + " bytes of " + event.total; // event.total doesnt show accurate total file size
  _("loaded_n_total").innerHTML = "Uploaded " + event.loaded + " bytes";
  var percent = (event.loaded / event.total) * 100;
  _("progressBar").value = Math.round(percent);
  _("status").innerHTML = Math.round(percent) + "% uploaded... please wait";
  if (percent >= 100) {
    _("status").innerHTML = "Please wait, writing file to filesystem";
  }
}
function completeHandler(event) {
  _("status").innerHTML = "Upload Complete";
  _("progressBar").value = 0;
  xmlhttp=new XMLHttpRequest();
  xmlhttp.open("GET", "/listfiles", false);
  xmlhttp.send();
  document.getElementById("status").innerHTML = "File Uploaded";
  document.getElementById("detailsheader").innerHTML = "<h3>Files<h3>";
  document.getElementById("details").innerHTML = xmlhttp.responseText;
}
function errorHandler(event) {
  _("status").innerHTML = "Upload Failed";
}
function abortHandler(event) {
  _("status").innerHTML = "inUpload Aborted";
}
</script>
</body>
</html>
)rawliteral";

const char logout_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html lang="en">
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta charset="UTF-8">
</head>
<body>
  <p><a href="/upload/">Log Back In</a></p>
</body>
</html>
)rawliteral";

// reboot.html base upon https://gist.github.com/Joel-James/62d98e8cb3a1b6b05102
const char reboot_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html lang="en">
<head>
  <meta charset="UTF-8">
</head>
<body>
<h3>
  Rebooting, returning to main page in <span id="countdown">30</span> seconds
</h3>
<script type="text/javascript">
  var seconds = 20;
  function countdown() {
    seconds = seconds - 1;
    if (seconds < 0) {
      window.location = "/upload";
    } else {
      document.getElementById("countdown").innerHTML = seconds;
      window.setTimeout("countdown()", 1000);
    }
  }
  countdown();
</script>
</body>
</html>
)rawliteral";

index.html ( Später über den Browser hochladen )


<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Pro3EM TCP 2 UDP.</title>
  <style>

  
    body {
		
		overflow: auto;
		background: rgb(0,190,255);
		background: linear-gradient(197deg, rgba(0,190,255,1) 12%, rgba(64,124,231,1) 51%, rgba(0,190,255,1) 94%);
		background-attachment: fixed;
		padding:35px 0px;
		margin: 5px 5px 5px 5px;
		font-family: 'Poppins', sans-serif;
		font-size: 14px;
		font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
    }
	
	#head{
		
		background: linear-gradient(197deg, rgba(0,190,255,1) 12%, rgba(64,124,231,1) 51%, rgba(0,190,255,1) 94%);
		background-attachment: fixed;
		top: 0px;
		height: 30px;
		width: 100%;
		position:fixed;
		padding:10px 0px;
		text-align: middle;
		border-bottom: 2px solid;
		border-color: white;
		z-index: 1;
		font-size:2.5em;
		
	}
	
	
	#body_div{
	z-index: 0;
	//top: 30px;
	position: relative;
	top: 30px;
	
	}
	




.details_info{
  border-radius: 15px;
  background-color: rgba(0, 128, 172, 1);
  border: 3px solid #FFFFFF;
  color: white;
  width: 95%s;
  margin: 3px;
  padding: 5px;
  text-align: left;
  
}

#total{
  border-radius: 15px;
  background-color: rgba(0, 128, 172, 1);
  border: 3px solid #FFFFFF;
  color: white;
  width: fit-content;
  margin: 3px;
  padding: 5px;
}

#leiter{
  border-radius: 15px;
  background-color: rgba(0, 128, 172, 1);
  border: 3px solid #FFFFFF;
  color: white;
  width: fit-content;
  margin: 3px;
  padding: 5px;

}		

#details_infos{
  border-radius: 15px;
  background-color: rgba(0, 128, 172, 1);
  border: 3px solid #FFFFFF;
  color: white;
  width: fit-content;
  margin: 3px;
  padding: 5px;
}			
				

.text {
  width: 100%;
  height: 100%;
  /*BLUE BG*/
  background: radial-gradient(
    ellipse at center,
    rgba(0, 128, 172, 1) 0%,
    rgba(0, 128, 172, 1) 70%,
    rgba(0, 128, 172, 0) 70.3%
  );
  position: relative;
  margin: 0;
  color: white;
}
	
	
	

  </style>

<script>
var url_logger="./"; //./
</script>
   


<script type="text/javascript">
    function onBodyLoad(){
      console.log("we are loaded!!");
    }
	
	
	
	let myVar = setInterval(sync,1000);
	
	function sync(){
		holeDaten('json');
	}
    
    function getJson(file, callback) { 
      var rawFile = new XMLHttpRequest();
      rawFile.overrideMimeType("application/json");
      rawFile.open("GET", file, true);
      rawFile.onreadystatechange = function() { 
          if (rawFile.readyState === 4 && rawFile.status == "200") {
              callback(rawFile.responseText);
          }
      }
      rawFile.send(null);
    }
    
    function holeDaten(anfrage){
        	//document.getElementById('loading').style.display = 'block';
        getJson(url_logger+anfrage, function(text){
            var data = JSON.parse(text);
        	//document.getElementById('loading').style.display = 'none';
        	
        		if(data.antwort == "json_all"){
        			//document.getElementById('stand').value = data.stand;
					document.getElementById('pro3em_ip').innerHTML = data.modbus_ipa+"."+data.modbus_ipb+"."+data.modbus_ipc+"."+data.modbus_ipd;
					document.getElementById('modbus_ipa').value = data.modbus_ipa;
					document.getElementById('modbus_ipb').value = data.modbus_ipb;
					document.getElementById('modbus_ipc').value = data.modbus_ipc;
					document.getElementById('modbus_ipd').value = data.modbus_ipd;
					//document.getElementById('L1_error').innerHTML = data.L1_error;
					//document.getElementById('L2_error').innerHTML = data.L2_error;
					//document.getElementById('L3_error').innerHTML = data.L3_error;
					//document.getElementById('N_error').innerHTML = data.N_error;
					//document.getElementById('S_error').innerHTML = data.S_error;
					//document.getElementById('N_A').innerHTML = data.N_A;
					//document.getElementById('N_A_error').innerHTML = data.N_A_error;
					//document.getElementById('N_O_error').innerHTML = data.N_O_error;
					document.getElementById('Total_A').innerHTML = data.Total_A;
					document.getElementById('Total_W').innerHTML = data.Total_W;
					document.getElementById('Total_sch').innerHTML = data.Total_sch;
					
					document.getElementById('L1_V').innerHTML = data.L1_V;
					document.getElementById('L1_A').innerHTML = data.L1_A;
					document.getElementById('L1_W').innerHTML = data.L1_W;
					document.getElementById('L1_SCH').innerHTML = data.L1_SCH;
					document.getElementById('L1_PF').innerHTML = data.L1_PF;
					//document.getElementById('L1_O_W_error').innerHTML = data.L1_O_W_error;
					//document.getElementById('L1_O_V_error').innerHTML = data.L1_O_V_error;
					//document.getElementById('L1_O_A_error').innerHTML = data.L1_O_A_error;
					document.getElementById('L1_Hz').innerHTML = data.L1_Hz;
					
					document.getElementById('L2_V').innerHTML = data.L2_V;
					document.getElementById('L2_A').innerHTML = data.L2_A;
					document.getElementById('L2_W').innerHTML = data.L2_W;
					document.getElementById('L2_SCH').innerHTML = data.L2_SCH;
					document.getElementById('L2_PF').innerHTML = data.L2_PF;
					//document.getElementById('L2_O_W_error').innerHTML = data.L2_O_W_error;
					//document.getElementById('L2_O_V_error').innerHTML = data.L2_O_V_error;
					//document.getElementById('L2_O_A_error').innerHTML = data.L2_O_A_error;
					document.getElementById('L2_Hz').innerHTML = data.L2_Hz;
					
					document.getElementById('L3_V').innerHTML = data.L3_V;
					document.getElementById('L3_A').innerHTML = data.L3_A;
					document.getElementById('L3_W').innerHTML = data.L3_W;
					document.getElementById('L3_SCH').innerHTML = data.L3_SCH;
					document.getElementById('L3_PF').innerHTML = data.L3_PF;
					//document.getElementById('L3_O_W_error').innerHTML = data.L3_O_W_error;
					//document.getElementById('L3_O_V_error').innerHTML = data.L3_O_V_error;
					//document.getElementById('L3_O_A_error').innerHTML = data.L3_O_A_error;
					document.getElementById('L3_Hz').innerHTML = data.L3_Hz;
					
					
					
					document.getElementById('anz_soyo').innerHTML = data.anz_soyo;
					document.getElementById('pushservice').innerHTML = data.pushservice;
					document.getElementById('pushservice_url').innerHTML = data.pushservice_url;
					document.getElementById('push_interval').innerHTML = data.push_interval;
					document.getElementById('httpuser').innerHTML = data.httpuser;
					document.getElementById('max_einspeisung').innerHTML = data.max_einspeisung;
					document.getElementById('einspeisung_reduzieren').innerHTML = data.einspeisung_reduzieren;
					document.getElementById('Soyo_interval').innerHTML = data.Soyo_interval;
					document.getElementById('modbus_interval').innerHTML = data.modbus_interval;
					document.getElementById('modbus_timeout').innerHTML = data.modbus_timeout;
					
					document.getElementById('eth_static_ip').innerHTML = data.eth_static_ip;
					document.getElementById('eth_static_ipadresse').innerHTML = data.sip_ipa+"."+data.sip_ipb+"."+data.sip_ipc+"."+data.sip_ipd;
					document.getElementById('sip_ipa').value = data.sip_ipa;
					document.getElementById('sip_ipb').value = data.sip_ipb;
					document.getElementById('sip_ipc').value = data.sip_ipc;
					document.getElementById('sip_ipd').value = data.sip_ipd;
					
					document.getElementById('eth_static_gateway').innerHTML = data.gip_ipa+"."+data.gip_ipb+"."+data.gip_ipc+"."+data.gip_ipd;
					document.getElementById('gip_ipa').value = data.gip_ipa;
					document.getElementById('gip_ipb').value = data.gip_ipb;
					document.getElementById('gip_ipc').value = data.gip_ipc;
					document.getElementById('gip_ipd').value = data.gip_ipd;
					
					document.getElementById('eth_static_subnet').innerHTML = data.sub_ipa+"."+data.sub_ipb+"."+data.sub_ipc+"."+data.sub_ipd;
					document.getElementById('sub_ipa').value = data.sub_ipa;
					document.getElementById('sub_ipb').value = data.sub_ipb;
					document.getElementById('sub_ipc').value = data.sub_ipc;
					document.getElementById('sub_ipd').value = data.sub_ipd;
					
					document.getElementById('eth_static_pdns').innerHTML = data.pdns_ipa+"."+data.pdns_ipb+"."+data.pdns_ipc+"."+data.pdns_ipd;
					document.getElementById('pdns_ipa').value = data.pdns_ipa;
					document.getElementById('pdns_ipb').value = data.pdns_ipb;
					document.getElementById('pdns_ipc').value = data.pdns_ipc;
					document.getElementById('pdns_ipd').value = data.pdns_ipd;
					
					document.getElementById('eth_static_sdns').innerHTML = data.sdns_ipa+"."+data.sdns_ipb+"."+data.sdns_ipc+"."+data.sdns_ipd;
					document.getElementById('sdns_ipa').value = data.sdns_ipa;
					document.getElementById('sdns_ipb').value = data.sdns_ipb;
					document.getElementById('sdns_ipc').value = data.sdns_ipc;
					document.getElementById('sdns_ipd').value = data.sdns_ipd;
					
					
					
					
					document.getElementById('ssid').innerHTML = data.ssid;
					document.getElementById('wifi_signal').innerHTML = data.wifi_signal;
					
					
					
        		}
				
			if(data.meldung != undefined){
					alert(data.meldung);
					holeDaten('json');
				}
        	
        
        });
      }
  </script>
</head>
<body id="index" onload="onBodyLoad()">
<center>
<div id="seite">
<div id="head"><b>Pro3EM TCP 2 UDP</b></div>

<div id="body_div">
<div id="total" style="display:show;">
<div style="font-size:1.3em;"> <b>Gesamt </b></div>
<div class="details_info"><B>Leistung:</B> <a id="Total_W">XXX</a> W </div>
<div class="details_info"><B>Strom:</B> <a id="Total_A">XXX</a> A</div>
<div class="details_info"><B>Scheinleistung:</B> <a id="Total_sch">XXX</a> V/A</div>
</div>

<table>
<tr>
<td>
<div id="leiter" style="display:show;">
<div style="font-size:1.3em;text-align:center;"> <b>L1 </b></div>
<div class="details_info"><B>Leistung:</B> <a id="L1_W">XXX</a> W </div>
<div class="details_info"><B>Spannung:</B> <a id="L1_V">XXX</a> V</div>
<div class="details_info"><B>Strom:</B> <a id="L1_A">XXX</a> A</div>
<div class="details_info"><B>Scheinleistung:</B> <a id="L1_SCH">XXX</a> V/A</div>
<div class="details_info"><B>Frequenz:</B> <a id="L1_Hz">XXX</a> Hz</div>
<div class="details_info"><B>Powerfactor:</B> <a id="L1_PF">XXX</a> Pf</div>
</div>
</td>

<td>
<div id="leiter" style="display:show;">
<div style="font-size:1.3em;text-align:center;"> <b>L2 </b></div>
<div class="details_info"><B>Leistung:</B> <a id="L2_W">XXX</a> W </div>
<div class="details_info"><B>Spannung:</B> <a id="L2_V">XXX</a> V</div>
<div class="details_info"><B>Strom:</B> <a id="L2_A">XXX</a> A</div>
<div class="details_info"><B>Scheinleistung:</B> <a id="L2_SCH">XXX</a> V/A</div>
<div class="details_info"><B>Frequenz:</B> <a id="L2_Hz">XXX</a> Hz</div>
<div class="details_info"><B>Powerfactor:</B> <a id="L2_PF">XXX</a> Pf</div>
</div>
</td>

<td>
<div id="leiter" style="display:show;">
<div style="font-size:1.3em;text-align:center;"> <b>L3 </b></div>
<div class="details_info"><B>Leistung:</B> <a id="L3_W">XXX</a> W </div>
<div class="details_info"><B>Spannung:</B> <a id="L3_V">XXX</a> V</div>
<div class="details_info"><B>Strom:</B> <a id="L3_A">XXX</a> A</div>
<div class="details_info"><B>Scheinleistung:</B> <a id="L3_SCH">XXX</a> V/A</div>
<div class="details_info"><B>Frequenz:</B> <a id="L3_Hz">XXX</a> Hz</div>
<div class="details_info"><B>Powerfactor:</B> <a id="L3_PF">XXX</a> Pf</div>
</div>
</td>
</table>







<br>
<hr>

<div style="color:white;cursor:pointer;"><a id="details_button" onclick="show_hide_details();" >&#9660; Einstellungen öffnen &#9660;</a></div>
<div id="details_infos" style="display:none;">
<div style="font-size:1em;text-align:center;"> <a href="./quicklogin">Einloggen</a> | <a href="#" onclick="holeDaten('reboot')";>Neustarten</a></div>
<div class="details_info">Wifi Signal: <a id="wifi_signal">XXX</a> db</div>
<div class="details_info">Wifi Name: <a id="ssid">XXX</a> <button onclick="edit('ssid',document.getElementById('ssid').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">Wifi Passwort: <a id="wifipassword">*****</a> <button onclick="edit('wifipassword','');" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">Pro3EM IP: <a id="pro3em_ip">XXX.XXX.XXX.XXX</a> <button onclick="edit('pro3em_ip','');" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<input type="hidden" id="modbus_ipa" value="">
<input type="hidden" id="modbus_ipb" value="">
<input type="hidden" id="modbus_ipc" value="">
<input type="hidden" id="modbus_ipd" value="">
<div class="details_info">Invertel Anzahl: <a id="anz_soyo">XXX</a> <button onclick="edit('anz_soyo',document.getElementById('anz_soyo').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">Mod. UDP Intervall: <a id="Soyo_interval">XXX</a> <button onclick="edit('Soyo_interval',document.getElementById('Soyo_interval').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">Mod. TCP Intervall: <a id="modbus_interval">XXX</a> <button onclick="edit('modbus_interval',document.getElementById('modbus_interval').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">Mod. TCP Timeout: <a id="modbus_timeout">XXX</a> <button onclick="edit('modbus_timeout',document.getElementById('modbus_timeout').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">URL Push Service Aktiv (Variablename: json): <a id="pushservice">XXX</a> <button onclick="edit('pushservice',document.getElementById('pushservice').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">URL Push Service: <a id="pushservice_url">XXX</a> <button onclick="edit('pushservice_url',document.getElementById('pushservice_url').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">URL Push Intervall: <a id="push_interval">XXX</a> <button onclick="edit('push_interval',document.getElementById('push_interval').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">Inverter Max. Leistung: <a id="max_einspeisung">XXX</a> <button onclick="edit('max_einspeisung',document.getElementById('max_einspeisung').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">Leistung um Fixwert reduzieren: <a id="einspeisung_reduzieren">XXX</a> <button onclick="edit('einspeisung_reduzieren',document.getElementById('einspeisung_reduzieren').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">Eth. Static IP Aktiv: <a id="eth_static_ip">XXX</a> <button onclick="edit('eth_static_ip',document.getElementById('eth_static_ip').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">Eth. Static IP: <a id="eth_static_ipadresse">XXX</a> <button onclick="edit('eth_static_ipadresse',document.getElementById('eth_static_ipadresse').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<input type="hidden" id="sip_ipa" value="">
<input type="hidden" id="sip_ipb" value="">
<input type="hidden" id="sip_ipc" value="">
<input type="hidden" id="sip_ipd" value="">
<div class="details_info">Eth. Gateway: <a id="eth_static_gateway">XXX</a> <button onclick="edit('eth_static_gateway',document.getElementById('eth_static_gateway').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<input type="hidden" id="gip_ipa" value="">
<input type="hidden" id="gip_ipb" value="">
<input type="hidden" id="gip_ipc" value="">
<input type="hidden" id="gip_ipd" value="">
<div class="details_info">Eth. Subnet: <a id="eth_static_subnet">XXX</a> <button onclick="edit('eth_static_subnet',document.getElementById('eth_static_subnet').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<input type="hidden" id="sub_ipa" value="">
<input type="hidden" id="sub_ipb" value="">
<input type="hidden" id="sub_ipc" value="">
<input type="hidden" id="sub_ipd" value="">
<div class="details_info">Prim. DNS: <a id="eth_static_pdns">XXX</a> <button onclick="edit('eth_static_pdns',document.getElementById('eth_static_pdns').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<input type="hidden" id="pdns_ipa" value="">
<input type="hidden" id="pdns_ipb" value="">
<input type="hidden" id="pdns_ipc" value="">
<input type="hidden" id="pdns_ipd" value="">
<div class="details_info">Sec. DNS: <a id="eth_static_sdns">XXX</a> <button onclick="edit('eth_static_sdns',document.getElementById('eth_static_sdns').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<input type="hidden" id="sdns_ipa" value="">
<input type="hidden" id="sdns_ipb" value="">
<input type="hidden" id="sdns_ipc" value="">
<input type="hidden" id="sdns_ipd" value="">
<div class="details_info">Benutzer: <a id="httpuser">XXX</a> <button onclick="edit('httpuser',document.getElementById('httpuser').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>
<div class="details_info">Passwort: <a id="httppassword">*****</a> <button onclick="edit('httppassword',document.getElementById('httppassword').innerHTML);" style="float:right;padding:0px;margin:0px;width:20px;height:20px;border-radius:10px;">&#9997;</button></div>

</div>

</center>
</body>
</html>
<script>
function edit(was, aktu_wert){
	if(was == "pro3em_ip"){
		let S1 = prompt("Erstes Segment eingeben ( ???.XXX.XXX.XXX )", document.getElementById('modbus_ipa').value);
		let S2 = prompt("Zweites Segment eingeben ( XXX.???.XXX.XXX )", document.getElementById("modbus_ipb").value);
		let S3 = prompt("Drittes Segment eingeben ( XXX.XXX.???.XXX )", document.getElementById("modbus_ipc").value);
		let S4 = prompt("Viertes Segment eingeben ( XXX.XXX.XXX.??? )", document.getElementById("modbus_ipd").value);
		if(S1 == undefined || S2 == undefined || S3 == undefined || S4 == undefined){alert('Abgebrochen'); return false }
		if(S1 > 255 || S1 <  1 || S2 > 255 || S2 <  1 || S3 > 255 || S3 <  1 || S4 > 255 || S4 <  1 ){alert('Werte nicht Stimmig'); return false }
		holeDaten('einstellungen?wert=modbus_ipa&modbus_ipa='+S1+'&modbus_ipb='+S2+'&modbus_ipc='+S3+'&modbus_ipd='+S4);
	}
	
	if(was == "anz_soyo"){
		let eingabe = prompt("Anzahl der Inverter angeben.", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=anz_soyo&value='+eingabe);
	}
	
	if(was == "pushservice"){
		let eingabe = prompt("Pushservice einschalten ? ( 1 = Ein / 0 = Aus )", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=pushservice&value='+eingabe);
	}
	
	if(was == "pushservice_url"){
		let eingabe = prompt("Pushservice Adresse eingeben.", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		//eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=pushservice_url&value='+eingabe);
	}
	
	if(was == "push_interval"){
		let eingabe = prompt("Pushintervall in Millisekunden angeben.", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=push_interval&value='+eingabe);
	}
	
	if(was == "httpuser"){
		let eingabe = prompt("Neuen Login Benutzernamen eingeben.", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		//eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=httpuser&value='+eingabe);
	}
	
	if(was == "httppassword"){
		let eingabe = prompt("Neues Login Passwort eingeben.", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		//eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=httppassword&value='+eingabe);
	}
	
	if(was == "max_einspeisung"){
		let eingabe = prompt("Maximale Inverterleistung beschränken (Angabe in  Watt).", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=max_einspeisung&value='+eingabe);
	}
	
	if(was == "einspeisung_reduzieren"){
		let eingabe = prompt("Leistung um Fixen Wert beschränken (Angabe in  Watt).", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=einspeisung_reduzieren&value='+eingabe);
	}
	
	if(was == "Soyo_interval"){
		let eingabe = prompt("Intervall wie oft Daten an den Inverter geschickt werden (Angabe in  Millisekunden).", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=Soyo_interval&value='+eingabe);
	}
	
	if(was == "modbus_interval"){
		let eingabe = prompt("Intervall wie oft Daten aus dem Pro3EM gelesen werden (Angabe in  Millisekunden).", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=modbus_interval&value='+eingabe);
	}
	
	if(was == "modbus_timeout"){
		let eingabe = prompt("Wie lange darf das auslesen aus dem Pro3EM Maximal dauern ? (Angabe in  Millisekunden).", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=modbus_timeout&value='+eingabe);
	}
	
	if(was == "eth_static_ip"){
		let eingabe = prompt("Static IP Aktivieren ? ( 1 = Ein / 0 = Aus )", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		eingabe = eingabe.replace(",", ".");
		holeDaten('einstellungen?wert=eth_static_ip&value='+eingabe);
	}
	
	if(was == "eth_static_ipadresse"){
		let S1 = prompt("Erstes Segment eingeben ( ???.XXX.XXX.XXX )", document.getElementById('sip_ipa').value);
		let S2 = prompt("Zweites Segment eingeben ( XXX.???.XXX.XXX )", document.getElementById("sip_ipb").value);
		let S3 = prompt("Drittes Segment eingeben ( XXX.XXX.???.XXX )", document.getElementById("sip_ipc").value);
		let S4 = prompt("Viertes Segment eingeben ( XXX.XXX.XXX.??? )", document.getElementById("sip_ipd").value);
		if(S1 == undefined || S2 == undefined || S3 == undefined || S4 == undefined){alert('Abgebrochen'); return false }
		if(S1 > 255 || S1 <  1 || S2 > 255 || S2 <  1 || S3 > 255 || S3 <  1 || S4 > 255 || S4 <  1 ){alert('Werte nicht Stimmig'); return false }
		holeDaten('einstellungen?wert=sip_ipa&sip_ipa='+S1+'&sip_ipb='+S2+'&sip_ipc='+S3+'&sip_ipd='+S4);
	}
	
	if(was == "eth_static_gateway"){
		let S1 = prompt("Erstes Segment eingeben ( ???.XXX.XXX.XXX )", document.getElementById('gip_ipa').value);
		let S2 = prompt("Zweites Segment eingeben ( XXX.???.XXX.XXX )", document.getElementById("gip_ipb").value);
		let S3 = prompt("Drittes Segment eingeben ( XXX.XXX.???.XXX )", document.getElementById("gip_ipc").value);
		let S4 = prompt("Viertes Segment eingeben ( XXX.XXX.XXX.??? )", document.getElementById("gip_ipd").value);
		if(S1 == undefined || S2 == undefined || S3 == undefined || S4 == undefined){alert('Abgebrochen'); return false }
		if(S1 > 255 || S1 <  1 || S2 > 255 || S2 <  1 || S3 > 255 || S3 <  1 || S4 > 255 || S4 <  1 ){alert('Werte nicht Stimmig'); return false }
		holeDaten('einstellungen?wert=gip_ipa&gip_ipa='+S1+'&gip_ipb='+S2+'&gip_ipc='+S3+'&gip_ipd='+S4);
	}
	
	if(was == "eth_static_subnet"){
		let S1 = prompt("Erstes Segment eingeben ( ???.XXX.XXX.XXX )", document.getElementById('sub_ipa').value);
		let S2 = prompt("Zweites Segment eingeben ( XXX.???.XXX.XXX )", document.getElementById("sub_ipb").value);
		let S3 = prompt("Drittes Segment eingeben ( XXX.XXX.???.XXX )", document.getElementById("sub_ipc").value);
		let S4 = prompt("Viertes Segment eingeben ( XXX.XXX.XXX.??? )", document.getElementById("sub_ipd").value);
		if(S1 == undefined || S2 == undefined || S3 == undefined || S4 == undefined){alert('Abgebrochen'); return false }
		if(S1 > 255 || S1 <  0 || S2 > 255 || S2 <  0 || S3 > 255 || S3 <  0 || S4 > 255 || S4 <  0 ){alert('Werte nicht Stimmig'); return false }
		holeDaten('einstellungen?wert=sub_ipa&sub_ipa='+S1+'&sub_ipb='+S2+'&sub_ipc='+S3+'&sub_ipd='+S4);
	}
	
	if(was == "eth_static_pdns"){
		let S1 = prompt("Erstes Segment eingeben ( ???.XXX.XXX.XXX )", document.getElementById('pdns_ipa').value);
		let S2 = prompt("Zweites Segment eingeben ( XXX.???.XXX.XXX )", document.getElementById("pdns_ipb").value);
		let S3 = prompt("Drittes Segment eingeben ( XXX.XXX.???.XXX )", document.getElementById("pdns_ipc").value);
		let S4 = prompt("Viertes Segment eingeben ( XXX.XXX.XXX.??? )", document.getElementById("pdns_ipd").value);
		if(S1 == undefined || S2 == undefined || S3 == undefined || S4 == undefined){alert('Abgebrochen'); return false }
		if(S1 > 255 || S1 <  1 || S2 > 255 || S2 <  1 || S3 > 255 || S3 <  1 || S4 > 255 || S4 <  1 ){alert('Werte nicht Stimmig'); return false }
		holeDaten('einstellungen?wert=pdns_ipa&pdns_ipa='+S1+'&pdns_ipb='+S2+'&pdns_ipc='+S3+'&pdns_ipd='+S4);
	}
	
	if(was == "eth_static_sdns"){
		let S1 = prompt("Erstes Segment eingeben ( ???.XXX.XXX.XXX )", document.getElementById('sdns_ipa').value);
		let S2 = prompt("Zweites Segment eingeben ( XXX.???.XXX.XXX )", document.getElementById("sdns_ipb").value);
		let S3 = prompt("Drittes Segment eingeben ( XXX.XXX.???.XXX )", document.getElementById("sdns_ipc").value);
		let S4 = prompt("Viertes Segment eingeben ( XXX.XXX.XXX.??? )", document.getElementById("sdns_ipd").value);
		if(S1 == undefined || S2 == undefined || S3 == undefined || S4 == undefined){alert('Abgebrochen'); return false }
		if(S1 > 255 || S1 <  1 || S2 > 255 || S2 <  1 || S3 > 255 || S3 <  1 || S4 > 255 || S4 <  1 ){alert('Werte nicht Stimmig'); return false }
		holeDaten('einstellungen?wert=sdns_ipa&sdns_ipa='+S1+'&sdns_ipb='+S2+'&sdns_ipc='+S3+'&sdns_ipd='+S4);
	}
	
	if(was == "ssid"){
		let eingabe = prompt("Wifi SSID eingeben.", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		holeDaten('einstellungen?wert=wifissid&value='+eingabe);
	}
	
	if(was == "wifipassword"){
		let eingabe = prompt("Wifi Passwort eingeben.", aktu_wert);
		if(eingabe == undefined){alert('Abgebrochen'); return false}
		holeDaten('einstellungen?wert=wifipassword&value='+eingabe);
	}
}

function show_hide_details(){

  var x = document.getElementById('details_infos');
  if (x.style.display == 'none') {
    x.style.display = 'block';
	document.getElementById('details_button').innerHTML = '&#9650; Details ausblenden &#9650;';
	
  } else {
    x.style.display = 'none';
	document.getElementById('details_button').innerHTML = '&#9660; Details anzeigen &#9660;';
  }
}


function addZeroes(num) { //Es wurden die Nullen nach den Komma beim rechnen vergessen so wurde z.b. 10.30 + 10.120 = 10.420 gerechnet statt 10.030 + 10.120 = 10.150 java ist dumm
  dec = num.split('.')[1];
	if(dec.length < 3){
		//console.log("*****"+werte[i]+"*******"); 
		return num.split('.')[0] +".0"+ dec;
		//console.log("*****"+dec+"*******");
	}else{
		return num;
	}
}

</script>