RuderwegMessSensor.ino öffnet nicht in Arduino 2.0.0

Hallo zusammen,
ich bin neu hier und hab erst mit Arduino begonnen. Dieses Projekt möchte ich gerne verwirklichen. Den ESP 8266 habe ich schon mit dem MPU-6050 Sensor verbunden. Arduino und Com Schnittstelle installiert. Das zip. Verzeichnis RuderwegsMessSensor-Master konnte auch im Arduino 2.0.0 eingebunden werden, das Verzeichnis ist im Sketch Ordner sichtbar. Die Datei RuderwegMessSensor.ino lässt sich allerding nicht öffnen.
Hat jemand vielleicht eine Idee?
Danke

#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "Wire.h" // This library allows you to communicate with I2C devices.
#include "RuderwegMessSensorTypes.h"
#include "htmlRootPage.h"
#include "htmlAdminPage.h"
#include "htmlExpertPage.h"
#include "htmlScript.h"
#include "htmlCSS.h"
#include <DNSServer.h>
#include <ESP8266mDNS.h>

const char *myHostname = "UHU";
const byte DNS_PORT = 53;
DNSServer dnsServer;

#include <Adafruit_MMA8451.h>         // MMA8451 library

// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"

// #define USE_MPU6050_MPU
#ifdef USE_MPU6050_MPU
#include "MPU6050_6Axis_MotionApps20.h"
#else
#include "MPU6050.h"
#endif

// Version history
// V0.10 : full functional initial version
// V0.11 : use wifi data from private header file
// V0.12 : support for MMA8451 added (no test HW available)
// V0.13 : support for OLED
// V0.14 : displayed angle with more precision
// V0.15 : multi WiFi mode added, in addition to client mode
//         the sensor now works as AP with
// V0.16 : extract individual #define to mySettings.h
//         and do some function sorting
// V0.17 : admin page added, for individual settings support,
//         added support for precision and inverted values,
//         including persistent config support (EEPROM),
//         refactoring of AJAX procedures
// V0.18 : bugfix : wrong calculation of rudderdepth from web GUI
// V0.19 : more bugfix : wifi, config page, new amplitude prec 0.01mm
// V0.20 : bugfix : wrong setting of amplitude presision in admin page
// V0.21 : show ip address of wlan in admin page,
// V0.22 : fixed handling of starting AP, more client details in serial logging
// V0.23 : support for reset to default config when connecting D5 with GRD while startup
//         support flight phase supporting measure with neutral, min, max values
//         CSS based layout added
// V0.24 : automatic detection of I2C ports and sensor type
// V0.25 : added calibration of MPU6050 in admin page and add values to persitent config data
//         after calibration the MPU6050 is accurate < 0.5° at a range of +-45°
// V0.26 : support for measure of rudder amplitude arc / chord / vertical distance - configurable
// V0.27 : typos and coding bug in initialization of MPU6050
// V0.28 : wording, and inline documentation
// V0.29 : avoid timing problems when restart response to client is send
// V0.30 : support for different I2C addresses and better support for MMA8451 added, refactoring of sensor initialization
//         for this the Adafruit_MMA8451 library is patched and this fork [https://github.com/Pulsar07/Adafruit_MMA8451_Library] has to be used
// V0.31 : enhanced MPU6050 calibration
// V0.32 : assuming MM8452 if I2C address of MMA8451 is used but sensor ID is not as expected
// V0.33 : typo in MM8452 detection
// V0.34 : JR: AP-Name now configurable
// V0.35 : RS: typos, enhanced MPU6050 initialization output, and not activated code fore MPU usage (USE_MPU6050_MPU)
//         hw reset to default config changed to D6
// V0.36 : bug with deactivated AP and config data fixed
//         EEPROM config structure change for better intergration of future projects
//         added #define MPU6050_IS_PRECALIBRATED for precalibrated sensors to supress calibration config
// v0.37 : Target Amplitude with audio feedback
// v0.38 : adjustments for Smartphone screen
// v0.39 : bugfix: missing declaration of ap_ssid
// V0.40 : some more fixes, offset calibration added and calibration functions moved to expert page
// V0.41 : fix for responsiveness of checkbox in html pages
#define WM_VERSION "V0.41"

/**
 * \file RuderwegMessSensor.ino
 *
 * \brief small tool to measure the model glider rudders movement
 *
 * \author Author: Rainer Stransky
 *
 * \copyright This project is released under the GNU Public License v3
 *          see https://www.gnu.org/licenses/gpl.html.
 * Contact: opensource@so-fa.de
 *
 */

/**
 * \mainpage RuderwegMessSensor, ein Arduino WeMos D1 Mini Projekt zur Erstellung eines Ruderweg Mess Sensors
 *
 * \section intro_sec_de Übersicht
 * Sensor zum Messen von Ruderwinkel und Ruderweg an Modellflugzeugen und Anzeige auf Web-Seite.
 * Hier ein kurzer Überblick über die Komponenten des Sensors.
 *  Der Sensor besteht aus der GY-521/MPU6050 Sensorplatine, die über eine I2C-Bus mit der
 * Mikrokontrollerplatine Wemos D1 verbunden ist. Der Mikrokontroller liest die Werte des Sensor
 * macht die Berechnungen, stellt einen Web-Server über eine WiFi-Schnittstelle zur Verfügung,
 * über die sowohl die Messdaten als auch die Konfiguration durchgeführt werden kann.
 * ![Architektur](https://raw.githubusercontent.com/Pulsar07/RuderwegMessSensor/master/doc/img/RWMS_Architecture.png)
 *
 * \section hardware_sec_de Hardware
 * \subsection hardware_subsec_de_ms Messsensor
 * Als Messsensor wird der GY-521/MPU-6050 benutzt. Die Genauigkeit liegt nach Kalibrierung bei
 * Winkeln bis +/- 45° kleiner als 0.5°. Der Baustein MPU-6050 wird von einer wirklich sehr gut
 * gemachten Libs von J.Rowberg unterstützt (siehe Link)
 *
 * Hier ein paar Links:
 * * https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf
 * * https://www.az-delivery.de/products/gy-521-6-achsen-gyroskop-und-beschleunigungssensor
 * * https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU6050
 *
 * \subsection hardware_subsec_de_mk Mikrokontroller
 * Als Mikrokontroller wird der Wemos D1/ESP8266 benutzt, der ausreichende Rechenpower und
 * Speicherresourcen bietet und eine WLAN Schnittstelle hat. Auch dieser Mikrokontroller
 * hat super gemachte Bibliotheken, zur Nutzung der WiFi-Schnittstelle und zur Programmierung
 * des Web-Servers.
 *
 * Hier ein paar Links:
 * * https://www.az-delivery.de/products/d1-mini
 * * https://github.com/esp8266/Arduino
 *
 * \subsection hardware_subsec_de_sp Schaltplan
 * Der Schaltplan ist denkbar einfach. Es werden nur 4 Verbindungen zwischen Sensorplatine und
 * Mikrokontroller benötigt. Das Layout und die Software sind so ausgelegt, dass mit einer Stiftleiste
 * 4x1 das Sensorboard mit dem Gesicht in Richtung Mikrokontroller direkt verlötet werden kann.
 * ![Schaltplan](https://raw.githubusercontent.com/Pulsar07/RuderwegMessSensor/master/doc/img/RWMS_Schaltplan.png)
 *
 * \section hmi_sec_de Anleitung
 * \subsection hmi_subsec_de_ib Inbetriebnahme
 * * Stromversorgung
 *  * Der Sensor / das Mikroprozessorboard ist mit einem Micro-USB-Anschluss ausgestattet,
 * hier kann man jedes handelsübliche USB-Netzteil anschließen oder besser jede
 * normale Powerbank. Damit ist man in der Werkstatt oder auf dem Flugfeld mobil ausgestattet.
 * * WiFi
 *  * Der Sensor muss zuerst mit Smartphone oder PC verbunden werden. Dazu stellt
 * der Sensor per WiFi einen Accesspoint mit der SSID "UHU" und Kennwort "12345678"
 * zur Verfügung. Ist das Gerät mit diesem WLAN verbunden, kann im Web-Browser
 * über die Adresse http://192.168.4.1 die Benutzeroberfläche benutzt und der Sensor
 * konfiguriert werden. Sowohl obige SSID als auch das Kennwort können danach geändert werden.
 *  * Auf der Einstellseite kann eine SSID und ein Kennwort für ein WLAN (WLAN-Client)
 * konfiguriert werden, mit dem sich der Sensor verbinden. Dabei wird dem Sensor
 * eine IP-Adresse zugewiesen, die am WLAN-Router abgefragt werden muss. Änderungen
 * der WLAN Einstellungen müssen gespeichert werden und werden erst nach Neustart aktiv.
 *  * Ist die Verbindung zu einem WLAN konfiguriert (WLAN-Client), kann auf der
 * Einstellungsseite, der Accesspoint deaktiviert werden (nach Speichern und Neustart).
 * Kann beim Neustart keine Verbindung zum konfigurierten WLAN aufgebaut werden,
 * wird der Accesspoint-Mode aber trotzdem aktiviert, damit ein Zugang zum Gerät möglich ist.
 * * Nutzung des Sensorboard GY-521 mit MPU-6050
 *  * Genauigkeit: Der MEMS Chip des MPU-6050 sollte Winkelauflösungen besser als 0.5°
 * bei 45° Ausschlag messen können, was bei einer 60mm Rudertiefe von 60mm einen Fehler von kleiner als 0.5mm ergibt.
 * Zudem sind diverse Anzeigegenauigkeiten für die Winkel und die Ruderwegs-Messung auswählbar.
 * Die Anzeige hat zwar immer 2 Dezimalstellen, intern wird aber gerundet.
 *  * Experten-Einstellungen: Diese Seite wird erreicht indem man den "Einstellungen"-Button zusammen mit der CTRL-Taste clickt
 *   * Kalibrierung: Damit der MPU-6050 allerdings diese Genauigkeit erreicht, muss
 * er nachträglich kalibriert werden. Die Software unterstützt diese Funktion und
 * kann die Werte intern speichern. Zur Kalibrierung muss die GY-521-Sensorplatine
 * mit der flachen Rückseite möglichst exakt horizontal aufgelegt werden. Dann den
 * Kalibrier-Button drücken und ca. 5s warten bis die Kalibrierung beendet ist.
 * Dabei sollte die Auflagefläche (Tisch) nicht bewegt werden und frei von Vibrationen sein.
 *   * Einbaulage: Die Sensorplatine sollte auch genau so, wie bei der Kalibrierung,
 * betrieben werden. Also die flache Seite nach unten und die Seite mit den
 * Elektronikbausteinen nach oben. Nur so wird die oben genannte Genauigkeit erreicht.
 *   * Achsen und Anzeige-Genauigkeit: Auf der Konfigurationsseite, kann die Bezugs-Achse
 * der Winkelmessung, je nach Einbaulage in der Klemmeinrichtung ausgewählt werden.
 *   * Kalibrierungsoffset: Hier können Messwerte für +/- 45° Referenzmessungen eingebeben werden und mit der
 * und aktiviert/deaktiviert werden, um die höchst mögliche Genauigkeit zu erreichen. Damit werden
 * dann die Messwerte auf die Offsetwerte interpoliert.
 *
 * \subsection hmi_subsec_de_me  Messen
 * * Der mit dem Mikrokontroller verbundene Messensor sollte mit einer Klemmvorrichtung fest
 * verbunden sein, und kann dann einfach an eine beliebige Stelle des Ruders aufgeklemmt werden.
 * Die Ruderdrehachse, sollte möglichst parallel zur ausgewählten Dreh-Achse (X- oder Y-Achse)
 * sein. Wie schon beschrieben, muss der Sensor mit dem Gesicht nach oben auf dem Ruder
 * befestigt sein.
 * * Einschränkungen: Der Sensor kann nur Winkel in Bezug auf die Schwerkraft messen.
 * Somit sind Ruderwegsmessungen für das Seitenruder nur möglich wenn der Rumpf um
 * 90° gedreht liegt.
 * * Der Ruderweg ist abhänig von der Rudertiefe. Diese ist an der Stelle zu Messen,
 * an der man den Ruderweg messen will. In der Web-Oberfläche des Sensor kann
 * diese Rudertiefe eingegeben werden.
 * * Ist der Sensor so auf dem Ruder angebracht, und die Rudertiefe eingestellt,
 * ist die Ruderstellung in die Null-Lage zu bringen. Jetzt können Winkel
 * und Ruderweg per "Tara"-Button auf 0 gesetzt werden.
 * * Bewegt man das Ruder nun nach oben oder unten werden die Ausschläge in Grad und
 * Millimeter angezeigt. Sollte das Vorzeichen nicht den Erwartungen entsprechen,
 * kann dies bei den Einstellungen angepasst werden.
 * * Zur Flugphasenmessung kann die Min-/Max-Rudermessung benutzt werden.
 * Hier sollte man das Ruder in die Neutralstellung der Flugphase bringen.
 * Nun den Schalter für die Min-/Max-Ruderweg-Messung aktivieren. Damit wird der
 * aktuelle Ruderausschlag als Neutralwert übernommen. Jetzt können die beiden
 * Min-/Max-Werte angefahren werden. Alle drei Werte werden bis zur
 * Deaktiverung der Messung angezeigt.
 *
 * Weitere Details gibt es unter <a href="http://www.so-fa.de/nh/RuderwegMesssensor">Albatross, Seite für Modellflug und Technik</a>
 */


static Adafruit_MMA8451 mma;
static MPU6050 mpu;


#ifdef SUPPORT_OLED
#include <U8g2lib.h>         // OLED library  https://github.com/olikraus/u8g2
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ D1, /* data=*/ D2); //OLED am Wemos D1 mini Pin 1 und 2
#endif

static configData_t ourConfig;

static const uint8_t MPU6050ADDR1 = 0x68; // I2C address of the MPU-6050. If AD0 pin is set to HIGH, the I2C address will be 0x69.
static const uint8_t MPU6050ADDR2 = 0x69; // I2C address of the MPU-6050. If AD0 pin is set to HIGH, the I2C address will be 0x69.
static const uint8_t MMA8451ADDR1 = 0x1C; // I2C address of the MMA-8451. If AD0 pin is set to LOW, the I2C address will be 0x1C.
static const uint8_t MMA8451ADDR2 = 0x1D; // I2C address of the MMA-8451. If AD0 pin is set to LOW, the I2C address will be 0x1C.
static uint8_t ourSCL_Pin;
static uint8_t ourSDA_Pin;
static uint8_t ourI2CAddr;
static String ourSensorTypeName;
static boolean ourTriggerCalibrateMPU6050 = false;
static unsigned long ourTriggerRestart = 0;

int16_t ourAccelerometer_x, ourAccelerometer_y, ourAccelerometer_z; // variables for ourAccelerometer raw data
int16_t gyro_x, gyro_y, gyro_z; // variables for gyro raw data
int16_t temperature; // variables for temperature data
static double ourTara = 0;
static double ourSmoothedAngle_x = 0;
static double ourSmoothedAngle_y = 0;
static double ourSmoothedAngle_z = 0;
static double ourTaraAngle_x = 0;
static double ourTaraAngle_y = 0;
static double ourTaraAngle_z = 0;
static double ourSmoothedGyro_x = 0;
static double ourSmoothedGyro_y = 0;
static double ourSmoothedGyro_z = 0;
static double ourTaraGyro_x = 0;
static double ourTaraGyro_y = 0;
static double ourTaraGyro_z = 0;
static double ourRudderDepth = 30;
static double ourTargetAmplitude = 5;

static float ourNullAmpl;
static float ourMinAmpl;
static float ourMaxAmpl;
static boolean ourIsMeasureActive=false;

const char* ap_ssid = "UHU";

ESP8266WebServer server(80);    // Server Port  hier einstellen

#ifdef USE_MPU6050_MPU
#define INTERRUPT_PIN 15 // use pin 15 on ESP8266
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
#endif

void setup()
{
  delay(1000);
  Serial.begin(115200);
  delay(1000);
  Serial.println();
  Serial.print("Starting RuderwegMessSensor :");
  Serial.println(WM_VERSION);

  // check HW Pin 4 for HW Reset
  checkHWReset(D6);

  loadConfig();
  initConfig();
  printConfig("stored configuration:");

  detectSensor();
  if (isI2C_MPU6050Addr()) {
    Wire.begin(ourSDA_Pin, ourSCL_Pin); //SDA, SCL
    initMPU6050();
  } else if (isI2C_MMA8451Addr()) {
    initMMA8451();
  }

  #ifdef SUPPORT_OLED
    u8g2.begin();
  #endif

  setupWiFi();
  setupWebServer();
}

void loop()
{
  static unsigned long last = 0;
  dnsServer.processNextRequest();
  server.handleClient();

  readMotionSensor();
  doAsync();
  if ( (millis() - last) > 1000) {
    prepareMotionData();
    #ifdef SUPPORT_OLED
    setOLEDData();
    #endif
    last = millis();
  }
}


// =================================
// sensor data processing functions
// =================================
void initConfig() {
  // if EEPROM config was not properly stored
  if (ourConfig.amplitudeInversion != -1) {
    ourConfig.amplitudeInversion = 1;
  }
  if (ourConfig.angleInversion != -1) {
    ourConfig.angleInversion = 1;
  }
  if (String((uint8_t) ourConfig.calibrationOffsetEnabled).equals("255")) {
    // if config is not stored before
    ourConfig.calibrationOffsetEnabled = false;
    ourConfig.calibrationOffsetHigh = 450;
    ourConfig.calibrationOffsetLow = -450;
  }
}

void readMotionSensor() {

  if (isI2C_MPU6050Addr()) {
    mpu.getMotion6(&ourAccelerometer_x, &ourAccelerometer_y, &ourAccelerometer_z, &gyro_x, &gyro_y, &gyro_z);
  } else
  if (isI2C_MMA8451Addr()) {
    mma.read();
    ourAccelerometer_x = mma.x;
    ourAccelerometer_y = mma.y;
    ourAccelerometer_z = mma.z;
  }

  const static double smooth = 0.98d;
  // print out data
  // Serial.println(ourAccelerometer_x);
  ourSmoothedAngle_x = irr_low_pass_filter(ourSmoothedAngle_x,
    atan2(ourAccelerometer_y, ourAccelerometer_z) * 180 / M_PI, smooth);
  ourSmoothedAngle_y = irr_low_pass_filter(ourSmoothedAngle_y,
    atan2(ourAccelerometer_z, ourAccelerometer_x) * 180 / M_PI, smooth);
  ourSmoothedAngle_z = irr_low_pass_filter(ourSmoothedAngle_z,
    atan2(ourAccelerometer_x, ourAccelerometer_y) * 180 / M_PI, smooth);
  ourSmoothedGyro_x = irr_low_pass_filter(ourSmoothedGyro_x, gyro_x, smooth);
  ourSmoothedGyro_y = irr_low_pass_filter(ourSmoothedGyro_y, gyro_y, smooth);
  ourSmoothedGyro_z = irr_low_pass_filter(ourSmoothedGyro_z, gyro_z, smooth);
}

void prepareMotionData() {
  double effAngle_x = ourSmoothedAngle_x - ourTaraAngle_x;
  double effAngle_y = ourSmoothedAngle_y - ourTaraAngle_y;
  double effAngle_z = ourSmoothedAngle_z - ourTaraAngle_z;
  double effGyro_x = ourSmoothedGyro_x - ourTaraGyro_x;
  double effGyro_y = ourSmoothedGyro_y - ourTaraGyro_y;
  double effGyro_z = ourSmoothedGyro_z - ourTaraGyro_z;
  // Serial.print(String("WX = ") + roundToDot5(effAngle_x));
  // Serial.print(String(" WY = ") + roundToDot5(effAngle_y));
  // Serial.print(String(" WZ = ") + roundToDot5(effAngle_z));
  // Serial.print(String(" GX = ") + roundToDot5(effGyro_x));
  // Serial.print(String(" GY = ") + roundToDot5(effGyro_y));
  // Serial.print(String(" GZ = ") + roundToDot5(effGyro_z));
  // Serial.println();
}

double getAngle() {
  double theAngle = 0;
  switch (ourConfig.axis) {
    case xAxis:
      theAngle = ourSmoothedAngle_x;
    break;
    case yAxis:
      theAngle = ourSmoothedAngle_y;
    break;
    case zAxis:
      theAngle = ourSmoothedAngle_z;
    break;
  }
  // support range -180 - +180, independent from tara
  if (theAngle < (ourTara-180.0d)) {
    theAngle = theAngle + 360.0d;
  }
  double angle = (theAngle - ourTara) * ourConfig.angleInversion;
  if (ourConfig.calibrationOffsetEnabled == true) {
    long iangle = angle*100;
    if (iangle >= 0) {
      long iangle = angle*100;
      iangle = map(iangle, 0, ourConfig.calibrationOffsetHigh*10, 0, 4500);
      angle = ((double) iangle)/100;
    } else {
      long iangle = angle*100;
      iangle = map(iangle, 0, ourConfig.calibrationOffsetLow*10, 0, -4500);
      angle = ((double) iangle)/100;
    }
  }

  return angle;
}

double getAmplitude(double aAngle) {
  double res;
  if (ourConfig.amplitudeCalcMethod == CHORD) {
    // sin (angle/2) = sin(angle/2 *M_PI/180)
    res = sin(aAngle*M_PI/360) * 2 * ourRudderDepth * ourConfig.amplitudeInversion;
  } else if (ourConfig.amplitudeCalcMethod == VERTICAL_DISTANCE) {
    res =  sin(aAngle*M_PI/180) * ourRudderDepth * ourConfig.amplitudeInversion;
  } else {
    res =  (aAngle/180*M_PI * ourRudderDepth) * ourConfig.amplitudeInversion;
  }
  return res;
}


float getRoundedAngle() {
  return roundPrecision(getAngle(), ourConfig.anglePrecision);
}

float getRoundedAmplitude() {
  return roundPrecision(getAmplitude(getAngle()), ourConfig.amplitudePrecision);
}

float getRudderAmplitude() {
  float ampl = getRoundedAmplitude();
  if (ourIsMeasureActive) {
    ourMinAmpl = min(ourMinAmpl, ampl);
    ourMaxAmpl = max(ourMaxAmpl, ampl);
  }
  return ampl;
}

float roundPrecision(double aVal, precision_t aPrecision) {
  float res = aVal;
  switch(aPrecision) {
    case P001:
      break;
    case P010:
      res = round(res * 10)/10;
      break;
    case P050:
      res = round(res * 2)/2;
      break;
    case P100:
      res = round(res);
      break;
    }
  return res;
}

void taraAngle() {
  ourTaraAngle_x = ourSmoothedAngle_x;
  ourTaraAngle_y = ourSmoothedAngle_y;
  ourTaraAngle_z = ourSmoothedAngle_z;
  switch (ourConfig.axis) {
    case xAxis:
      ourTara = ourSmoothedAngle_x;
    break;
    case yAxis:
      ourTara = ourSmoothedAngle_y;
    break;
    case zAxis:
      ourTara = ourSmoothedAngle_z;
    break;
  }
  Serial.println("tara angle set to :" + String(ourTara));
}

void flightPhaseMeasure(boolean aStart) {
  Serial.println(String("flightPhaseMeasure(")+aStart+")");
  if (aStart) {
    ourNullAmpl = getRudderAmplitude();
    ourMinAmpl = ourMaxAmpl = ourNullAmpl;
    ourIsMeasureActive=true;
  } else {
    ourIsMeasureActive=false;
  }
}

// =================================
// web server functions
// =================================

void setupWebServer() {
  // react on these "pages"
  server.on("/",HTMLrootPage);
  server.on("/adminPage",HTMLadminPage);
  server.on("/expertPage",HTMLexpertPage);
  server.on("/getDataReq",getDataReq);
  server.on("/setDataReq",setDataReq);
  server.onNotFound(handleWebRequests); //Set setver all paths are not found so we can handle as per URI
  server.begin();               // Starte den Server
  Serial.println("HTTP Server gestartet");
}

void HTMLrootPage() {
  Serial.print(server.client().remoteIP().toString());
  Serial.println(" : HTMLrootPage()");
  checkHTMLArguments();
  String s = FPSTR(MAIN_page); //Read HTML contents
  s.replace("###<SCRIPT>###", FPSTR(SCRIPT));
  s.replace("###<CSS>###", FPSTR(CSS));
  server.send(200, "text/html", s); //Send web page
}

void HTMLadminPage() {
  Serial.print(server.client().remoteIP().toString());
  Serial.println(" : HTMLadminPage()");
  String s = FPSTR(ADMIN_page); //Read HTML contents
  s.replace("###<SCRIPT>###", FPSTR(SCRIPT));
  s.replace("###<CSS>###", FPSTR(CSS));
  server.send(200, "text/html", s); //Send web page
}

void HTMLexpertPage() {
  Serial.print(server.client().remoteIP().toString());
  Serial.println(" : HTMLexpertPage()");
  String s = FPSTR(EXPERT_page); //Read HTML contents
  s.replace("###<SCRIPT>###", FPSTR(SCRIPT));
  s.replace("###<CSS>###", FPSTR(CSS));
  server.send(200, "text/html", s); //Send web page
}


void setDataReq() {
  Serial.print(server.client().remoteIP().toString());
  Serial.println(" : setDataReq()");
  String name = server.arg("name");
  String value = server.arg("value");
  Serial.print("  "); Serial.print(name); Serial.print("="); Serial.println(value);
  boolean sendResponse = true;

  String retVal = "";
  int htmlResponseCode=200; // OK
  if ( name == "cmd_taraAngle") {
    taraAngle();
  } else
  if ( name == "id_targetAmplitude") {
    ourTargetAmplitude = double(atoi(value.c_str()))/10;
    Serial.println("setting targetAmplitude: " + String(ourTargetAmplitude));
  } else
  if ( name == "cmd_flightphaseActive") {
    if (value == "true") {
      flightPhaseMeasure(true);
    } else {
      flightPhaseMeasure(false);
    }
  } else
  if ( name == "id_rudderDepth") {
    ourRudderDepth = double(atoi(value.c_str()))/10;
    Serial.println("setting rudderdepth: " + String(ourRudderDepth));
  } else
  if ( name == "id_invertAngle") {
    if (value == "true") {
      ourConfig.angleInversion = -1;
    } else {
      ourConfig.angleInversion = 1;
    }
    Serial.println("setting angle factor: " + String(ourConfig.angleInversion));
  } else
  if ( name == "id_invertAmplitude") {
    if (value == "true") {
      ourConfig.amplitudeInversion = -1;
    } else {
      ourConfig.amplitudeInversion = 1;
    }
    Serial.println("setting amplitude factor: " + String(ourConfig.amplitudeInversion));
  } else
  if ( name == "id_apActive") {
    if (value == "true") {
      ourConfig.apIsActive = true;
    } else {
      ourConfig.apIsActive = false;
    }
    Serial.println("setting AP active : " + String(ourConfig.apIsActive));
  } else
  if ( name == "nm_referenceAxis") {
    if (value == "xAxis") {
      ourConfig.axis = xAxis;
    } else if (value == "yAxis") {
      ourConfig.axis = yAxis;
    } else if (value == "zAxis") {
      ourConfig.axis = zAxis;
    }
    Serial.println("setting angle reference axis: " + String(ourConfig.axis));
  } else
  if ( name == "nm_anglePrecision") {
    if (value == "P010") {
      ourConfig.anglePrecision = P010;
    } else if (value == "P001") {
      ourConfig.anglePrecision = P001;
    }
    Serial.println("setting angle precision: " + String(ourConfig.anglePrecision));
  } else
  if ( name == "nm_precisionAmplitude") {
    if (value == "P001") {
      ourConfig.amplitudePrecision = P001;
    } else if (value == "P010") {
      ourConfig.amplitudePrecision = P010;
    } else if (value == "P050") {
      ourConfig.amplitudePrecision = P050;
    } else if (value == "P100") {
      ourConfig.amplitudePrecision = P100;
    }
    Serial.println("setting amplitude precision: " + String(ourConfig.amplitudePrecision));
  } else
  if ( name == "nm_distancetype") {
    if (value == "arc") {
      ourConfig.amplitudeCalcMethod = ARC;
    } else if (value == "chord") {
      ourConfig.amplitudeCalcMethod = CHORD;
    } else if (value == "vertical_distance") {
      ourConfig.amplitudeCalcMethod = VERTICAL_DISTANCE;
    }
    Serial.println("setting calculation method : " + value + "/" + String(ourConfig.amplitudeCalcMethod));
  } else
  if ( name == "id_wlanSsid") {
    strncpy(ourConfig.wlanSsid, value.c_str(), CONFIG_SSID_L);
    Serial.println("setting wlan ssid : " + String(ourConfig.wlanSsid));
  } else
  if ( name == "id_wlanPasswd") {
    strncpy(ourConfig.wlanPasswd, value.c_str(), CONFIG_PASSW_L);
    Serial.println("setting wlan password : " + String(ourConfig.wlanPasswd));
  } else
   if ( name == "id_apSsid") {
    strncpy(ourConfig.apSsid, value.c_str(), CONFIG_SSID_L);
    Serial.println("setting AccessPoint ssid : " + String(ourConfig.apSsid));
  } else
  if ( name == "id_apPasswd") {
    if (String(value).length() >= 8) {
      strncpy(ourConfig.apPasswd, value.c_str(), CONFIG_PASSW_L);
      Serial.println("setting AP password : " + String(ourConfig.apPasswd));
    } else {
      Serial.println("not setting AP password, too short. Old PW : " + String(ourConfig.apPasswd));
    }
  } else
  if (name == "cmd_saveConfig") {
     saveConfig();
  } else
  if (name == "cmd_resetConfig") {
     setDefaultConfig();
  } else
  if (name == "cmd_mcrestart") {
    Serial.println("resetting micro controller");
    triggerRestart();
  } else
  if ( name == "id_caloffset_enabled") {
    if (value == "true") {
      ourConfig.calibrationOffsetEnabled = true;
    } else {
      ourConfig.calibrationOffsetEnabled = false;
    }
    Serial.println("calibration offset enabled : " + String(ourConfig.calibrationOffsetEnabled));
  } else
  if (name == "id_caloffset_h") {
    ourConfig.calibrationOffsetHigh = value.toInt();
    Serial.println("high calibration offset: " + String(ourConfig.calibrationOffsetHigh));
  } else
  if (name == "id_caloffset_l") {
    ourConfig.calibrationOffsetLow = value.toInt();
    Serial.println("low calibration offset: " + String(ourConfig.calibrationOffsetLow));
  } else
  if (name == "cmd_calibrate") {
    if (isI2C_MPU6050Addr()) {
      Serial.println("triggering calibration");
      triggerCalibrateMPU6050();
    }
  }

  if (sendResponse) {
    Serial.print("send response to server: ");
    Serial.println(retVal);
    server.send(htmlResponseCode, "text/plane", retVal); // send an valid answer
  }
}


void getDataReq() {
  Serial.print(server.client().remoteIP().toString());
  Serial.print(" : getDataReq() :");
  String result;
  for (uint8_t i=0; i<server.args(); i++){
    // message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
    String argName = server.argName(i);

    Serial.print(argName); Serial.print(",");
    if (argName.equals("id_angleValue")) {
      result += argName + "=" + String(getRoundedAngle()) + ";";
    } else
    if (argName.equals("id_amplitudeValue")) {
      result += argName + "=" + String(getRudderAmplitude()) + ";";
    } else
    if (argName.equals("id_targetAmplitude")) {
      result += argName + "=" + ourTargetAmplitude + ";";
    } else
    if (argName.equals("cpx_flightphase")) {
      if (ourIsMeasureActive) {
        result += String("id_rudderneutral") + "=" + String(ourNullAmpl) + ";";
        result += String("id_ruddermin" ) + "=" + String(ourMinAmpl) + ";";
        result += String("id_ruddermax" ) + "=" + String(ourMaxAmpl) + ";";
      }
    } else
    if (argName.equals("id_rudderDepth")) {
      result += argName + "=" + ourRudderDepth + ";";
    } else
    if (argName.equals("id_version")) {
      result += argName + "=" + WM_VERSION + ";";
    } else
    if (argName.equals("id_sensortype")) {
      result += argName + "=" + ourSensorTypeName + ";";
    } else
    if (argName.equals("id_wlanSsid")) {
        result += argName + "=" + ourConfig.wlanSsid + ";";
    } else
    if (argName.equals("id_wlanPasswd")) {
        result += argName + "=" + "************;";
    } else
	if (argName.equals("id_apSsid")) {
        result += argName + "=" + ourConfig.apSsid + ";";
    } else
    if (argName.equals("id_apPasswd")) {
      if (String(ourConfig.apPasswd).length() != 0) {
        result += argName + "=" + "************;";
      }
    } else
    if (argName.equals("id_invertAngle")) {
      if (ourConfig.angleInversion == -1) {
        result += argName + "=" + "checked;";
      } else {
        result += argName + "=" + "unchecked;";
      }
    } else
    if (argName.equals("id_invertAmplitude")) {
      if (ourConfig.amplitudeInversion == -1) {
        result += argName + "=" + "checked;";
      } else {
        result += argName + "=" + "unchecked;";
      }
    } else
    if (argName.equals("id_wlanConnetion")) {
      if (WiFi.status() == WL_CONNECTED) {
        result += argName + "=" + "verbunden, zugewiesene Adresse: " + WiFi.localIP().toString() +  ";";
      } else {
        result += argName + "=" + "nicht verbunden;";
      }
    } else
    if (argName.equals("id_resp_calibrate")) {
      if (!isSensorCalibrated()) {
        result += argName + "=" + "Sensor ist nicht kalibriert;";
      } else {
        if ( ourTriggerCalibrateMPU6050 ) {
          result += argName + "=" + "Kalibrierung gestartet ...;";
        } else {
          result += argName + "=" + "Sensor ist kalibriert;";
        }
      }
    } else
    if (argName.equals("id_caloffset_enabled")) {
      if (ourConfig.calibrationOffsetEnabled == true) {
        result += argName + "=" + "checked;";
      } else {
        result += argName + "=" + "unchecked;";
      }
    } else
    if (argName.equals("id_caloffset_h")) {
      result += argName + "=" + ((float)ourConfig.calibrationOffsetHigh)/10 + ";";
    } else
    if (argName.equals("id_caloffset_l")) {
      result += argName + "=" + ((float)ourConfig.calibrationOffsetLow)/10 + ";";
    } else
    if (argName.equals("nm_referenceAxis")) {
      switch (ourConfig.axis) {
         case xAxis:
           result += String("id_xAxis") + "=" + "checked;";
           break;
         case yAxis:
           result += String("id_yAxis") + "=" + "checked;";
           break;
         case zAxis:
           result += String("id_zAxis") + "=" + "checked;";
           break;
      }
    } else
    if (argName.equals("nm_anglePrecision")) {
      if (ourConfig.anglePrecision == P010) {
        result += String("id_anglePrec_P010") + "=" + "checked;";
      } else {
        result += String("id_anglePrec_P001") + "=" + "checked;";
      }
    } else
    if (argName.equals("nm_precisionAmplitude")) {
      if (ourConfig.amplitudePrecision == P001) {
        result += String("id_amplPrec_P001") + "=" + "checked;";
      } else if (ourConfig.amplitudePrecision == P010) {
        result += String("id_amplPrec_P010") + "=" + "checked;";
      } else if (ourConfig.amplitudePrecision == P050) {
        result += String("id_amplPrec_P050") + "=" + "checked;";
      } else if (ourConfig.amplitudePrecision == P100) {
        result += String("id_amplPrec_P100") + "=" + "checked;";
      }
    } else
    if (argName.equals("id_amplitudeCalcMethod")) {
      if (ourConfig.amplitudeCalcMethod == ARC) {
        result += argName + "=" + "Kreisbogen;";
      } else if (ourConfig.amplitudeCalcMethod == CHORD) {
        result += argName + "=" + "Kreissehne;";
      } else if (ourConfig.amplitudeCalcMethod == VERTICAL_DISTANCE) {
        result += argName + "=" + "senkrechter Abstand;";
      }
    } else
    if (argName.equals("nm_distancetype")) {
      if (ourConfig.amplitudeCalcMethod == ARC) {
        result += String("id_distance_arc") + "=" + "checked;";
      } else if (ourConfig.amplitudeCalcMethod == CHORD) {
        result += String("id_distance_chord") + "=" + "checked;";
      } else if (ourConfig.amplitudeCalcMethod == VERTICAL_DISTANCE) {
        result += String("id_vertical_distance") + "=" + "checked;";
      }
    } else
    if (argName.equals("id_apActive")) {
      if (ourConfig.apIsActive == true) {
        result += argName + "=" + "checked;";
      } else {
        result += argName + "=" + "unchecked;";
      }
    }
  }
  Serial.println();
  // strip last semicolon
  result.remove(result.length()-1);
  // result += String(";rudderDepth=") + ourRudderDepth;

  Serial.print("result:");
  Serial.println(result);
  server.send(200, "text/plane", result.c_str()); //Send the result value only to client ajax request
}

void handleWebRequests(){
  // if(loadFromSpiffs(server.uri())) return;
  String message = "File Not Detected\n\n";

  message += "client : ";
  message += server.client().remoteIP().toString();
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial.println(message);
}

void checkHTMLArguments() {
  Serial.println("checkHTMLArguments()");
  String name = server.arg("name");
  if (name.length() != 0) {
    setDataReq();
  }
}

// =================================
// helper function
// =================================

double irr_low_pass_filter(double aSmoothedValue, double aCurrentValue, double aSmoothingFactor) {
  // IIR Low Pass Filter
  // y[i] := α * x[i] + (1-α) * y[i-1]
  //      := α * x[i] + (1 * y[i-1]) - (α * y[i-1])
  //      := α * x[i] +  y[i-1] - α * y[i-1]
  //      := α * ( x[i] - y[i-1]) + y[i-1]
  //      := y[i-1] + α * (x[i] - y[i-1])
  // mit α = 1- β
  //      := y[i-1] + (1-ß) * (x[i] - y[i-1])
  //      := y[i-1] + 1 * (x[i] - y[i-1]) - ß * (x[i] - y[i-1])
  //      := y[i-1] + x[i] - y[i-1] - ß * x[i] + ß * y[i-1]
  //      := x[i] - ß * x[i] + ß * y[i-1]
  //      := x[i] + ß * y[i-1] - ß * x[i]
  //      := x[i] + ß * (y[i-1] - x[i])
  // see: https://en.wikipedia.org/wiki/Low-pass_filter#Simple_infinite_impulse_response_filter
  return aCurrentValue + aSmoothingFactor * (aSmoothedValue - aCurrentValue);
}

float roundToDot5(double aValue) {
  return round(aValue * 2)/2;
}

void printMPU6050Offsets() {
   Serial.print("Accel Offsets [X,Y,Z]: [");
   Serial.print(mpu.getXAccelOffset());
   Serial.print(",");
   Serial.print(mpu.getYAccelOffset());
   Serial.print(",");
   Serial.print(mpu.getZAccelOffset());
   Serial.print("] X Gyro Offset [x,Y,Z]: [");
   Serial.print(mpu.getXGyroOffset());
   Serial.print(",");
   Serial.print(mpu.getYGyroOffset());
   Serial.print(",");
   Serial.print(mpu.getZGyroOffset());
   Serial.print("]");
   Serial.println();
}
void detectSensor() {

  // supported I2C HW connection schemas
  #define I2C_CONNECTIONS_SIZE 2
  uint8_t cableConnections[2][2] = {
   {D3, D4} ,   /* SDA, SCL */
   {D2, D1}    /* SDA, SCL */
  };

  // supported I2C devices / addresses
  #define I2C_ADDR_SIZE 4
  uint8_t I2CAddresses[I2C_ADDR_SIZE] = {
    MPU6050ADDR1, MPU6050ADDR2, MMA8451ADDR1, MMA8451ADDR2,
  };



  for (int i = 0; i < I2C_CONNECTIONS_SIZE; i++) {
    ourSDA_Pin = cableConnections[i][0];
    ourSCL_Pin = cableConnections[i][1];
    Wire.begin(ourSDA_Pin, ourSCL_Pin);
    for (int j = 0; j<I2C_ADDR_SIZE; j++) {
      ourI2CAddr = I2CAddresses[j];
      mpu = MPU6050(ourI2CAddr);
      Wire.beginTransmission(ourI2CAddr);
      byte result = Wire.endTransmission();
      if (result == 0){
        if (isI2C_MPU6050Addr()) {
          ourSensorTypeName = "MPU-6050/GY521";
        }
        if (isI2C_MMA8451Addr()) {
          ourSensorTypeName = "MMA-8451";
        }
        Serial.print("Sensor [");
        Serial.print(ourSensorTypeName);
        Serial.print("] found at I2C pins ");
        Serial.print(ourSDA_Pin);
        Serial.print("/");
        Serial.print(ourSCL_Pin);
        Serial.print(" (SDA/SCL) at address 0x");
        Serial.print(ourI2CAddr, HEX);
        Serial.println();
        return;
      }
    }
  }
}


boolean isI2C_MMA8451Addr() {
  boolean retVal = false;
  if (ourI2CAddr == MMA8451ADDR1 || ourI2CAddr == MMA8451ADDR2 ) {
    retVal = true;
  }
  return retVal;
}

boolean isI2C_MPU6050Addr() {
  boolean retVal = false;
  if (ourI2CAddr == MPU6050ADDR1 || ourI2CAddr == MPU6050ADDR2 ) {
    retVal = true;
  }
  return retVal;
}

void initMMA8451() {
  Serial.println("initializing MMA8451 device");
  mma = Adafruit_MMA8451();

  Serial.println("Testing MMA-8452 device connection...");
  if (mma.begin(ourSDA_Pin, ourSCL_Pin, ourI2CAddr)) {
    Serial.print("MMA8451 connection successful at : 0x");
    Serial.println(ourI2CAddr, HEX);
  } else {
    Serial.println("MMA8451 connection failed. MMA8452 assumed");
    ourSensorTypeName="MMA-8452";
  }
  mma.setRange(MMA8451_RANGE_2_G);
}

void initMPU6050() {
  #ifdef USE_MPU6050_MPU
  Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
  #endif
  Serial.println("Initializing MPU6050 device");
  Serial.println("Testing device connection...");
  mpu = MPU6050(ourI2CAddr);
  Serial.println("resetting the MPU6050 device ...");
  mpu.reset();
  delay(50);
  mpu.initialize();
  Serial.print("MPU6050 deviceId is: 0x");
  Serial.println(mpu.getDeviceID(), HEX);
  Serial.print("MPU6050 FullScaleAccelRange: ");
  Serial.println(mpu.getFullScaleAccelRange());
  if (mpu.testConnection()) {
    Serial.print("MPU6050 connection successful at : 0x");
    Serial.println(ourI2CAddr, HEX);
  } else {
    Serial.println("ERROR: MPU6050 connection failed");
  }
  if (isSensorCalibrated()) {
    // set stored calibration data
    mpu.setXAccelOffset(ourConfig.xAccelOffset);
    mpu.setYAccelOffset(ourConfig.yAccelOffset);
    mpu.setZAccelOffset(ourConfig.zAccelOffset);
    mpu.setXGyroOffset(ourConfig.xGyroOffset);
    mpu.setYGyroOffset(ourConfig.yGyroOffset);
    mpu.setZGyroOffset(ourConfig.zGyroOffset);
    Serial.println("MPU6050 ist kalibriert mit folgenden Werten: ");
    printMPU6050Offsets();
  } else {
    Serial.println("MPU6050 ist nicht kalibriert !!!!");
    Serial.println("MPU6050 hat folgende initialen Werte: ");
    printMPU6050Offsets();
  }

  #ifdef USE_MPU6050_MPU

  // load and configure the DMP
  Serial.println(F("Initializing DMP..."));
  devStatus = mpu.dmpInitialize();

  // make sure it worked (returns 0 if so)
  if (devStatus == 0) {
    // turn on the DMP, now that it's ready
    Serial.println(F("Enabling DMP..."));
    mpu.setDMPEnabled(true);

    // enable Arduino interrupt detection
    Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
    attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
    mpuIntStatus = mpu.getIntStatus();

    // set our DMP Ready flag so the main loop() function knows it's okay to use it
    Serial.println(F("DMP ready! Waiting for first interrupt..."));
    dmpReady = true;

    // get expected DMP packet size for later comparison
    packetSize = mpu.dmpGetFIFOPacketSize();
  } else {
    // ERROR!
    // 1 = initial memory load failed
    // 2 = DMP configuration updates failed
    // (if it's going to break, usually the code will be 1)
    Serial.print(F("DMP Initialization failed (code "));
    Serial.print(devStatus);
    Serial.println(F(")"));
  }
#endif
}

volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
ICACHE_RAM_ATTR void dmpDataReady() {
    mpuInterrupt = true;
}

void triggerRestart() {
  // the restart has to be delayed to avoid, that the response to the restart request is not
  // answerd properly to the http-client. If there is no response the client, will resend the
  // restart request ;-(
  ourTriggerRestart = millis();
}

void restartESP() {
  if (ourTriggerRestart != 0) {
    unsigned long delay = millis() - ourTriggerRestart;
     // wait for 200ms with the restart
    if (delay > 200) {
      ourTriggerRestart = 0;
      ESP.restart();
    }
  }
}
void triggerCalibrateMPU6050() {
  ourTriggerCalibrateMPU6050 = true;
}

boolean isSensorCalibrated() {
  return (ourConfig.xAccelOffset != 0 || ourConfig.yAccelOffset != 0 || ourConfig.zAccelOffset != 0);
}

void calibrateMPU6050() {
  if (ourTriggerCalibrateMPU6050 == true) {
    printMPU6050Offsets();
    mpu.CalibrateAccel(15);
    mpu.CalibrateGyro(15);
    printMPU6050Offsets();
    Serial.println("\nat 1500 Readings");
    mpu.CalibrateAccel(6);
    mpu.CalibrateGyro(6);
    Serial.println("\nat 600 Readings");
    printMPU6050Offsets();
    Serial.println();
    mpu.CalibrateAccel(1);
    mpu.CalibrateGyro(1);
    Serial.println("700 Total Readings");
    printMPU6050Offsets();
    Serial.println();
    mpu.CalibrateAccel(1);
    mpu.CalibrateGyro(1);
    Serial.println("800 Total Readings");
    printMPU6050Offsets();
    Serial.println();
    mpu.CalibrateAccel(1);
    mpu.CalibrateGyro(1);
    Serial.println("900 Total Readings");
    printMPU6050Offsets();
    Serial.println();
    mpu.CalibrateAccel(1);
    mpu.CalibrateGyro(1);
    Serial.println("1000 Total Readings");
    printMPU6050Offsets();
    ourConfig.xAccelOffset = mpu.getXAccelOffset();
    ourConfig.yAccelOffset = mpu.getYAccelOffset();
    ourConfig.zAccelOffset = mpu.getZAccelOffset();
    ourConfig.xGyroOffset = mpu.getXGyroOffset();
    ourConfig.yGyroOffset = mpu.getYGyroOffset();
    ourConfig.zGyroOffset = mpu.getZGyroOffset();
    ourTriggerCalibrateMPU6050 = false;
  }
}

void doAsync() {
  calibrateMPU6050();
  restartESP();
}

// =================================
// WiFi functions
// =================================

void setupWiFi() {
  // first try to connect to the stored WLAN, if this does not work try to
  // start as Access Point

  // hardcode here to avoid setup by AP
  // strncpy(ourConfig.wlanSsid , "<SSID>", CONFIG_SSID_L);
  // strncpy(ourConfig.wlanPasswd, "<PWD>", CONFIG_PASSW_L);

  if (String(ourConfig.wlanSsid).length() != 0 ) {
    WiFi.mode(WIFI_STA) ; // client mode only
    WiFi.begin(ourConfig.wlanSsid, ourConfig.wlanPasswd);

    Serial.println();
    Serial.print("Connecting to ");
    Serial.print(ourConfig.wlanSsid);
    int connectCnt = 0;
    while (WiFi.status() != WL_CONNECTED && connectCnt++ < 20) {
      delay(500);
      Serial.print(".");
    }
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("success!");
    Serial.print("IP Address is: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.print("cannot connect to SSID :");
    Serial.println(ourConfig.wlanSsid);
    WiFi.mode(WIFI_AP) ; // client mode only
  }
  if (ourConfig.apIsActive || WiFi.status() != WL_CONNECTED) {
    Serial.print("Starting WiFi Access Point with  SSID: ");
    Serial.println(ourConfig.apSsid);
    //ESP32 As access point IP: 192.168.4.1
    // WiFi.mode(WIFI_AP) ; //Access Point mode
    boolean res = WiFi.softAP(ourConfig.apSsid, ourConfig.apPasswd);    //Password length minimum 8 char
    if(res ==true) {
      IPAddress myIP = WiFi.softAPIP();
      // DNS Server
      dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
      dnsServer.start(DNS_PORT, "*", myIP);

        // mDNS
        if (!MDNS.begin(ap_ssid)) {
          Serial.println("Error: startup mDNS!");
        } else {
          Serial.println("mDNS started");
          MDNS.addService("http", "tcp", 80);
        }

      Serial.println("AP setup done!");
      Serial.print("Host IP Address: ");
      Serial.println(myIP);
      Serial.print("Please connect to SSID: ");
      Serial.print(ourConfig.apSsid);
      Serial.print(", PW: ");
      Serial.print(ourConfig.apPasswd);
      Serial.print(", URL: http://");
      Serial.println(myIP);
    }
  }
}

// =================================
// OLED functions
// =================================

#ifdef SUPPORT_OLED
void setOLEDData() {
  double angle = getAngle();
  float outAngle = roundToDot5(angle);
  float outAmplitude = roundToDot5(getAmplitude(angle)));
  u8g2.firstPage();                                                 // Display values
  do {
    u8g2.setFontDirection(0);
    u8g2.setFont(u8g2_font_t0_14_tf);
    u8g2.setCursor(1, 15);
    u8g2.print("Winkel:");
    u8g2.setFont(u8g2_font_crox4tb_tn);
    u8g2.setCursor(78, 15);
    u8g2.print(outAngle);
    u8g2.setFont(u8g2_font_t0_14_tf);
    u8g2.setCursor(1, 35);
    u8g2.print("Rudertiefe");
    u8g2.setFont(u8g2_font_crox4tb_tn);
    u8g2.setCursor(78, 35);
    u8g2.print(ourRudderDepth);
    u8g2.setFont(u8g2_font_t0_14_tf);
    u8g2.setCursor(1, 55);
    u8g2.print("Ruderweg");
    u8g2.setFont(u8g2_font_crox4tb_tn);
    u8g2.setCursor(78, 55);
    u8g2.print(outAmplitude);
  } while (u8g2.nextPage() );
}
#endif

// =================================
// EEPROM functions
// =================================

void printConfig(const char* aContext) {
  Serial.println(aContext);
  Serial.print("cfg version              = "); Serial.println(ourConfig.version);
  Serial.print("axis                     = "); Serial.println(ourConfig.axis);
  Serial.print("amplitudePrecision       = "); Serial.println(ourConfig.amplitudePrecision);
  Serial.print("anglePrecision           = "); Serial.println(ourConfig.anglePrecision);
  Serial.print("apIsActive               = "); Serial.println(ourConfig.apIsActive);
  Serial.print("angleInversion           = "); Serial.println(ourConfig.angleInversion);
  Serial.print("amplitudeInversion       = "); Serial.println(ourConfig.amplitudeInversion);
  Serial.print("wlanSsid                 = "); Serial.println(ourConfig.wlanSsid);
  Serial.print("wlanPasswd               = "); Serial.println(ourConfig.wlanPasswd);
  Serial.print("apSsid                   = "); Serial.println(ourConfig.apSsid);
  Serial.print("apPasswd                 = "); Serial.println(ourConfig.apPasswd);
  Serial.print("xAccelOffet              = "); Serial.println(ourConfig.xAccelOffset);
  Serial.print("yAccelOffet              = "); Serial.println(ourConfig.yAccelOffset);
  Serial.print("zAccelOffet              = "); Serial.println(ourConfig.zAccelOffset);
  Serial.print("amplitudeCalcMethod      = "); Serial.println(ourConfig.amplitudeCalcMethod);
  Serial.print("calibrationOffsetEnabled = "); Serial.println(ourConfig.calibrationOffsetEnabled);
  Serial.print("calibrationOffsetHigh    = "); Serial.println(ourConfig.calibrationOffsetHigh);
  Serial.print("calibrationOffsetLow     = "); Serial.println(ourConfig.calibrationOffsetLow);
}

void setDefaultConfig() {
  Serial.println("setDefaultConfig()");
  // Reset EEPROM bytes to '0' for the length of the data structure
  printConfig("setDefaultConfig() - old data:");
  ourConfig.axis = xAxis;
  strncpy(ourConfig.version , CONFIG_VERSION, CONFIG_VERSION_L);
  ourConfig.axis = xAxis;
  ourConfig.amplitudeInversion = 1;
  ourConfig.angleInversion = 1;
  ourConfig.apIsActive=true;
  ourConfig.anglePrecision = P010;
  ourConfig.amplitudePrecision = P050;
  strncpy(ourConfig.wlanSsid , "", CONFIG_SSID_L);
  strncpy(ourConfig.wlanPasswd, "", CONFIG_PASSW_L);
  strncpy(ourConfig.apSsid , "UHU", CONFIG_SSID_L);
  strncpy(ourConfig.apPasswd, "12345678", CONFIG_PASSW_L);
  ourConfig.xAccelOffset = 0;
  ourConfig.yAccelOffset = 0;
  ourConfig.zAccelOffset = 0;
  ourConfig.amplitudeCalcMethod = ARC;
  ourConfig.calibrationOffsetHigh = 450;
  ourConfig.calibrationOffsetLow = -450;
  ourConfig.calibrationOffsetEnabled = false;
  saveConfig();
}


void saveConfig() {
  Serial.println("saveConfig()");
  printConfig("saveConfig - start");
  // Save configuration from RAM into EEPROM
  EEPROM.begin(512);
  EEPROM.put(0, ourConfig );
  delay(10);
  EEPROM.commit();                      // Only needed for ESP8266 to get data written
  EEPROM.end();                         // Free RAM copy of structure
  printConfig("saveConfig - end");
}

void loadConfig() {
  Serial.println("loadConfig()");
  // Loads configuration from EEPROM into RAM
  EEPROM.begin(512);
  EEPROM.get(0, ourConfig );
  EEPROM.end();
  // config was never written to EEPROM, so set the default config data and save it to EEPROM
  if ( String(CONFIG_VERSION) != ourConfig.version ) {
    setDefaultConfig();
  }
  if (ourConfig.amplitudeCalcMethod < 0) {
    ourConfig.amplitudeCalcMethod = ARC;
  }
}

void checkHWReset(uint8_t aPin) {
  // pull the given pin
  Serial.print("checking HW reset pin ");
  Serial.print(aPin);
  Serial.println(" for force HW config reset");
  pinMode(aPin, INPUT_PULLUP);
  delay(100);
  uint8_t cnt=0;
  for (int i=0; i<10; i++) {
    delay(20);
    if (digitalRead(aPin) == LOW) {
      cnt++;
    }
  }
  if (cnt == 10) {
    Serial.print("configuration reset by HW pin to GRD !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ");
    // Serial.println(cnt);
    setDefaultConfig();
  }
}

Dann hast du vermutlich etwas falsch gemacht.

Ich kann die Datei bei mir öffnen.

Die Version 2.0 ist ganz neu.
Hast Du es schon mit der vorherigen 1.8.19 versucht.
Wenns damit geht dann deinstalliere die IDE 2.0
und installiere diese erneut.
Grüße Uwe

Ich habe Arduino 1.8.19 installiert, damit hat es geklappt die .ino Datei aus der Bibliothek zu öffnen.
Leider bekomme ich beim Überprüfen des Sketches folgende Fehlermeldung:

Arduino: 1.8.19 (Windows 10), Board: "LOLIN(WEMOS) D1 mini (clone), 80 MHz, Flash, Disabled (new aborts on oom), Disabled, All SSL ciphers (most compatible), 32KB cache + 32KB IRAM (balanced), Use pgm_read macros for IRAM/PROGMEM, DOUT (compatible), 40MHz, 4MB (FS:2MB OTA:~1019KB), v2 Lower Memory, Disabled, None, Only Sketch, 921600"


C:\Users\Joachim Eichhorn\Documents\Arduino\libraries\RuderwegMessSensor-master\RuderwegMessSensor\RuderwegMessSensor.ino: In function 'void initMMA8451()':

RuderwegMessSensor:981:51: error: no matching function for call to 'Adafruit_MMA8451::begin(uint8_t&, uint8_t&, uint8_t&)'

  981 |   if (mma.begin(ourSDA_Pin, ourSCL_Pin, ourI2CAddr)) {

      |                                                   ^

In file included from C:\Users\Joachim Eichhorn\Documents\Arduino\libraries\RuderwegMessSensor-master\RuderwegMessSensor\RuderwegMessSensor.ino:18:

C:\Users\Joachim Eichhorn\Documents\Arduino\libraries\Adafruit_MMA8451_Library/Adafruit_MMA8451.h:99:8: note: candidate: 'bool Adafruit_MMA8451::begin(uint8_t, TwoWire*)'

   99 |   bool begin(uint8_t addr = MMA8451_DEFAULT_ADDRESS, TwoWire *theWire = &Wire);

      |        ^~~~~

C:\Users\Joachim Eichhorn\Documents\Arduino\libraries\Adafruit_MMA8451_Library/Adafruit_MMA8451.h:99:8: note:   candidate expects 2 arguments, 3 provided

exit status 1

no matching function for call to 'Adafruit_MMA8451::begin(uint8_t&, uint8_t&, uint8_t&)'

Ich komme hier nicht weiter, weiß jemand was ich hier probieren kann ?

Grüße Joachim

Da das gelöst ist, wird es schwer jemanden zu finden.
Zumal die Meldung unvollständig ist.

Du hast den MA im setup falsch angesprochen, zeige ganze Fehlermeldung. In der IDE wird angezeigt Fehlermeldung kopieren, wenn nicht, IDE einstellen Datei, Einstellungen, Fehler... Alle

Dankeschön für Eure Mühe und Hinweise,
habe soeben in einem Modellbauforum eine für dieses Projekt angepasste MMA8451.h Datei gefunden, nachdem ein anderer User das gleiche Problem geschildert hatte. Jetzt läuft der Sketch fehlerfrei und lässt sich hochladen.

..läuft..

Über diesen Link ist die Datei zu finden:
https://github.com/Pulsar07/Adafruit_MMA8451_Library

Danke an my_xy_projekt für den Hinweis :slight_smile:

Schön.
Und nicht schön, das Du verheimlichst wo das war.
Es könnte ja jemand anderem helfen. Aber das willst Du ja nicht.

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