diff --git a/src/main.cpp b/src/main.cpp index 1ed98e0..5d29c01 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,64 +33,68 @@ SOFTWARE. #include // Settings for double reset detector. -#define ESP8266_DRD_USE_RTC true +#define ESP_DRD_USE_LITTLEFS true #define DRD_TIMEOUT 2 #define DRD_ADDRESS 0 #include -DoubleResetDetector *drd; +extern DoubleResetDetector *drd; // Declared in WifiManager_Lite // Define constats for this program #ifdef DEACTIVATE_SLEEPMODE -const int interval = 1000; // ms, time to wait between changes to output -bool sleepModeAlwaysSkip = true; // Web interface can override normal behaviour +const int interval = 1000; // ms, time to wait between changes to output #else -const int interval = 200; // ms, time to wait between changes to output -bool sleepModeAlwaysSkip = - false; // Web interface can override normal behaviour +int interval = 200; // ms, time to wait between changes to output +bool sleepModeAlwaysSkip = false; // Web interface can override normal behaviour #endif -uint32_t loopMillis = 0; // Used for main loop to run the code every _interval_ -uint32_t runtimeMillis; // Used to calculate the total time since start/wakeup -uint32_t stableGyroMillis; // Used to calculate the total time since last - // stable gyro reading -bool sleepModeActive = false; -bool goToSleep = false; -int loopCounter = 0; +uint32_t loopMillis = 0;// Used for main loop to run the code every _interval_ +uint32_t runtimeMillis; // Used to calculate the total time since start/wakeup +uint32_t stableGyroMillis; // Used to calculate the total time since last + // stable gyro reading + +enum RunMode { + gravityMode = 0, + configurationMode = 1, + wifiSetupMode = 2 +}; + +RunMode runMode = RunMode::gravityMode; // // Check if we should be in sleep mode // void checkSleepMode(float angle, float volt) { #if defined(SKIP_SLEEPMODE) - sleepModeActive = false; + runMode = RunMode::configurationMode; Log.verbose(F("MAIN: Skipping sleep mode (SKIP_SLEEPMODE is defined)." CR)); return; #endif const RawGyroData &g = myConfig.getGyroCalibration(); - // Will not enter sleep mode if: no calibration data - if (g.ax == 0 && g.ay == 0 && g.az == 0 && g.gx == 0 && g.gy == 0 && - g.gz == 0) { - Log.notice( - F("MAIN: Missing calibration data, so forcing webserver to be " - "active." CR)); - sleepModeAlwaysSkip = true; - } - - if (sleepModeAlwaysSkip) { + if (g.ax == 0 && g.ay == 0 && g.az == 0 && g.gx == 0 && g.gy == 0 && g.gz == 0) { + // Will not enter sleep mode if: no calibration data + Log.notice(F("MAIN: Missing calibration data, so forcing webserver to be active." CR)); + runMode = RunMode::configurationMode; + } else if (sleepModeAlwaysSkip) { + // Check if the flag from the UI has been set, the we force configuration mode. Log.notice(F("MAIN: Sleep mode disabled from web interface." CR)); - sleepModeActive = false; - return; + runMode = RunMode::configurationMode; + } else if ( (volt < 4.15 && (angle > 85 && angle < 95)) || (volt > 4.15) ) { + runMode = RunMode::configurationMode; + } else { + runMode = RunMode::gravityMode; } - // Will not enter sleep mode if: charger is connected - sleepModeActive = (volt < 4.15 && (angle > 85 && angle < 95)) || (volt > 4.15) - ? false - : true; - - // sleep mode active when flat - Log.notice(F("MAIN: Deep sleep mode %s (angle=%F volt=%F)." CR), - sleepModeActive ? "true" : "false", angle, volt); + switch (runMode) { + case RunMode::configurationMode: + Log.notice(F("MAIN: run mode CONFIG (angle=%F volt=%F)." CR), angle, volt); + break; + case RunMode::wifiSetupMode: + break; + case RunMode::gravityMode: + Log.notice(F("MAIN: run mode GRAVITY (angle=%F volt=%F)." CR), angle, volt); + break; + } } // @@ -120,7 +124,7 @@ void setup() { // Setup watchdog ESP.wdtDisable(); - ESP.wdtEnable(interval * 2); + ESP.wdtEnable(5000); // 5 seconds if (dt) { Log.notice(F("Main: Detected doubletap on reset. Reset reason=%s" CR), @@ -133,44 +137,148 @@ void setup() { dt = false; #endif - LOG_PERF_START("main-wifi-connect"); - myWifi.connect(dt); // This will return false if unable to connect to wifi, - // will be handled in loop() - LOG_PERF_STOP("main-wifi-connect"); + if( !myWifi.hasConfig() ) { + runMode = RunMode::wifiSetupMode; + } - LOG_PERF_START("main-temp-setup"); - myTempSensor.setup(); - LOG_PERF_STOP("main-temp-setup"); + // Do this setup for all modes exect wifi setup + switch (runMode) { + case RunMode::wifiSetupMode: + myWifi.startPortal(); + Log.notice(F("Main: No wifi configuration detected, running in wifiSetupMode." CR)); + break; - if (!myGyro.setup()) // Takes less than 5ms, so skip this - Log.error(F("Main: Failed to initialize the gyro." CR)); + default: + LOG_PERF_START("main-wifi-connect"); + myWifi.connect(); + LOG_PERF_STOP("main-wifi-connect"); - LOG_PERF_START("main-gyro-read"); - myGyro.read(); - LOG_PERF_STOP("main-gyro-read"); + LOG_PERF_START("main-temp-setup"); + myTempSensor.setup(); + LOG_PERF_STOP("main-temp-setup"); - myBatteryVoltage - .read(); // Takes less than 1ms, so skip this measuring time on this - checkSleepMode(myGyro.getAngle(), myBatteryVoltage.getVoltage()); + if (!myGyro.setup()) { + Log.error(F("Main: Failed to initialize the gyro." CR)); + } else { + LOG_PERF_START("main-gyro-read"); + myGyro.read(); + LOG_PERF_STOP("main-gyro-read"); + } - if (myWifi.isConnected()) { + myBatteryVoltage.read(); + checkSleepMode(myGyro.getAngle(), myBatteryVoltage.getVoltage()); + break; + } + + // Do this setup for configuration mode + switch (runMode) { + case RunMode::configurationMode: + if (myWifi.isConnected()) { #if defined(ACTIVATE_OTA) - LOG_PERF_START("main-wifi-ota"); - if (!sleepModeActive && myWifi.checkFirmwareVersion()) { - myWifi.updateFirmware(); - } - LOG_PERF_STOP("main-wifi-ota"); + LOG_PERF_START("main-wifi-ota"); + if ( myWifi.checkFirmwareVersion()) + myWifi.updateFirmware(); + LOG_PERF_STOP("main-wifi-ota"); #endif - if (!sleepModeActive) { - myWebServer - .setupWebServer(); // Takes less than 4ms, so skip this measurement - } + myWebServer.setupWebServer(); // Takes less than 4ms, so skip this measurement + } + + interval = 1000; // Change interval from 200ms to 1s + break; + + default: + break; } LOG_PERF_STOP("main-setup"); Log.notice(F("Main: Setup completed." CR)); - stableGyroMillis = - millis(); // Put it here so we dont include time for wifi connection + stableGyroMillis = millis(); // Dont include time for wifi connection +} + +// +// Main loop that does gravity readings and push data to targets +// +// Return true if gravity reading was successful +// +bool loopReadGravity() { + float angle = 0; + +#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) + Log.verbose(F("Main: Entering main loopGravity." CR)); +#endif + + // Process the sensor values and push data to targets. + // ------------------------------------------------------------------------------------------------ + // If we dont get any readings we just skip this and try again the next + // interval. + // + if (myGyro.hasValue()) { + angle = myGyro.getAngle(); // Gyro angle + stableGyroMillis = millis(); // Reset timer + + LOG_PERF_START("loop-temp-read"); + float temp = myTempSensor.getTempC(); + LOG_PERF_STOP("loop-temp-read"); + + float gravity = calculateGravity( + angle, temp); // Takes less than 2ms , so skip this measurment + float corrGravity = gravityTemperatureCorrection( + gravity, temp, myConfig.getTempFormat()); // Takes less than 2ms , so + // skip this measurment + +#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) + Log.verbose(F("Main: Sensor values gyro angle=%F, temp=%F, gravity=%F, " + "corr=%F." CR), + angle, temp, gravity, corrGravity); +#endif + + LOG_PERF_START("loop-push"); + // Force the transmission if we are going to sleep + myPushTarget.send(angle, gravity, corrGravity, temp, (millis() - runtimeMillis) / 1000, runMode == RunMode::gravityMode ? true : false ); + LOG_PERF_STOP("loop-push"); + return true; + } else { + Log.error(F("Main: No gyro value." CR)); + } + return false; +} + +// +// Wrapper for loopGravity that only calls every 200ms so that we dont overload this. +// +void loopGravityOnInterval() { + if (abs((int32_t)(millis() - loopMillis)) > interval) { + loopReadGravity(); + loopMillis = millis(); +#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) + Log.verbose(F("Main: Heap %d kb FreeSketch %d kb HeapFrag %d %%." CR), + ESP.getFreeHeap() / 1024, ESP.getFreeSketchSpace() / 1024, + ESP.getHeapFragmentation()); +#endif + LOG_PERF_START("loop-gyro-read"); + myGyro.read(); + LOG_PERF_STOP("loop-gyro-read"); + checkSleepMode(myGyro.getAngle(), myBatteryVoltage.getVoltage()); + LOG_PERF_PUSH(); + } +} + +// +// Main loop that determines if device should go to sleep +// +void goToSleep(int sleepInterval) { + float volt = myBatteryVoltage.getVoltage(); + + Log.notice(F("MAIN: Entering deep sleep for %d s, run time %l s, " + "battery=%F V." CR), + sleepInterval, (millis() - runtimeMillis) / 1000, volt); + LittleFS.end(); + myGyro.enterSleep(); + drd->stop(); + LOG_PERF_STOP("run-time"); + LOG_PERF_PUSH(); + delay(100); + deepSleep(sleepInterval); } // @@ -179,128 +287,39 @@ void setup() { void loop() { drd->loop(); - if (sleepModeActive || abs((int32_t)(millis() - loopMillis)) > interval) { - float angle = 0; - float volt = myBatteryVoltage.getVoltage(); - loopCounter++; + switch (runMode) { + case RunMode::configurationMode: + myWebServer.loop(); + loopGravityOnInterval(); + break; -#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) - Log.verbose(F("Main: Entering main loop." CR)); -#endif - - // Process the sensor values and push data to targets. - // ------------------------------------------------------------------------------------------------ - // If we dont get any readings we just skip this and try again the next - // interval. - // - if (myGyro.hasValue()) { - angle = myGyro.getAngle(); // Gyro angle - - stableGyroMillis = millis(); // Reset timer - - LOG_PERF_START("loop-temp-read"); - float temp = myTempSensor.getTempC(); - LOG_PERF_STOP("loop-temp-read"); - - float gravity = calculateGravity( - angle, temp); // Takes less than 2ms , so skip this measurment - float corrGravity = gravityTemperatureCorrection( - gravity, temp, myConfig.getTempFormat()); // Takes less than 2ms , so - // skip this measurment - -#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) - Log.verbose(F("Main: Sensor values gyro angle=%F, temp=%F, gravity=%F, " - "corr=%F." CR), - angle, temp, gravity, corrGravity); -#endif - - // Limit the printout when sleep mode is not active. - if (loopCounter % 10 == 0 || sleepModeActive) { - Log.notice(F("Main: angle=%F, temp=%F, gravity=%F, corrGravity=%F, " - "batt=%F." CR), - angle, temp, gravity, corrGravity, volt); + case RunMode::gravityMode: + // If we didnt get a wifi connection, we enter sleep for a short time to + // conserve battery. + if (!myWifi.isConnected()) { // no connection to wifi + Log.notice(F("MAIN: No connection to wifi established, sleeping for 60s." CR)); + goToSleep(60); } - LOG_PERF_START("loop-push"); - myPushTarget.send( - angle, gravity, corrGravity, temp, (millis() - runtimeMillis) / 1000, - sleepModeActive); // Force the transmission if we are going to sleep - LOG_PERF_STOP("loop-push"); + if( loopReadGravity() ) + goToSleep(myConfig.getSleepInterval()); + + // If the sensor is moving and we are not getting a clear reading, we enter + // sleep for a short time to conserve battery. + if (((millis() - stableGyroMillis) > 10000L)) { // 10s since last stable gyro reading + Log.notice(F("MAIN: Unable to get a stable reading for 10s, sleeping for 60s." CR)); + goToSleep(60); + } - // If we have completed the update lets go to sleep - if (sleepModeActive) goToSleep = true; - } else { - Log.error(F("Main: No gyro value." CR)); - } + LOG_PERF_START("loop-gyro-read"); + myGyro.read(); + LOG_PERF_STOP("loop-gyro-read"); + break; -#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) - Log.verbose(F("Main: Sleep mode not active." CR)); -#endif - - int sleepInterval = myConfig.getSleepInterval(); - - // If we didnt get a wifi connection, we enter sleep for a short time to - // conserve battery. - // ------------------------------------------------------------------------------------------------ - // - if (!myWifi.isConnected()) { // no connection to wifi - Log.notice( - F("MAIN: No connection to wifi established, sleeping for 60s." CR)); - sleepInterval = 60; // 60s - goToSleep = true; - } - - // If the sensor is moving and we are not getting a clear reading, we enter - // sleep for a short time to conserve battery. - // ------------------------------------------------------------------------------------------------ - // - if (sleepModeActive && ((millis() - stableGyroMillis) > - 10000L)) { // 10s since last stable gyro reading - Log.notice( - F("MAIN: Unable to get a stable reading for 10s, sleeping for " - "60s." CR)); - sleepInterval = 60; // 60s - goToSleep = true; - } - - // Enter sleep mode if the conditions are right - // ------------------------------------------------------------------------------------------------ - // - if (goToSleep && !sleepModeAlwaysSkip) { - Log.notice(F("MAIN: Entering deep sleep for %d s, run time %l s, " - "battery=%F V." CR), - sleepInterval, (millis() - runtimeMillis) / 1000, volt); - LittleFS.end(); - myGyro.enterSleep(); - drd->stop(); - LOG_PERF_STOP("run-time"); - LOG_PERF_PUSH(); - delay(100); - deepSleep(sleepInterval); - } - - // If we are running in normal mode we just continue - // ------------------------------------------------------------------------------------------------ - // Do these checks if we are running in normal mode (not sleep mode) - // - checkSleepMode(angle, volt); - - LOG_PERF_START("loop-gyro-read"); - myGyro.read(); - LOG_PERF_STOP("loop-gyro-read"); - - myBatteryVoltage.read(); // Takes less than 2ms , so skip this measurment - - loopMillis = millis(); -#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) - Log.verbose(F("Main: Heap %d kb FreeSketch %d kb HeapFrag %d %%." CR), - ESP.getFreeHeap() / 1024, ESP.getFreeSketchSpace() / 1024, - ESP.getHeapFragmentation()); -#endif - LOG_PERF_PUSH(); + case RunMode::wifiSetupMode: + myWifi.portalLoop(); + break; } - - myWebServer.loop(); } // EOF diff --git a/src/wifi.cpp b/src/wifi.cpp index 1a54a6a..ae4dfd3 100644 --- a/src/wifi.cpp +++ b/src/wifi.cpp @@ -26,7 +26,7 @@ SOFTWARE. #include #include #include -#include +#include #include #include @@ -41,14 +41,40 @@ Wifi myWifi; const char *userSSID = USER_SSID; const char *userPWD = USER_SSID_PWD; +// +// Check if we have a valid wifi configuration +// +bool Wifi::hasConfig() { + if (strlen(myConfig.getWifiSSID()) ) return true; + if (strlen(userSSID) ) return true; + + return false; +} + +// +// Start the wifi manager +// +bool Wifi::startPortal() { + Log.notice(F("WIFI: Starting Wifi config portal." CR)); + return true; +} + +// +// Call the wifi manager in loop +// +void Wifi::portalLoop() { +} + // // Connect to last known access point or create one if connection is not // working. // -bool Wifi::connect(bool showPortal) { +// REMOVE bool Wifi::connect(bool showPortal) { +bool Wifi::connect() { WiFi.persistent(true); WiFi.mode(WIFI_STA); +/* REMOVE if (!strlen(myConfig.getWifiSSID())) { Log.info( F("WIFI: No SSID seams to be stored, forcing portal to start." CR)); @@ -86,6 +112,7 @@ bool Wifi::connect(bool showPortal) { ESP.reset(); } } +*/ // Connect to wifi int i = 0; diff --git a/src/wifi.hpp b/src/wifi.hpp index 154e870..ff09737 100644 --- a/src/wifi.hpp +++ b/src/wifi.hpp @@ -40,10 +40,13 @@ class Wifi { public: // WIFI - bool connect(bool showPortal = false); + bool connect(); bool disconnect(); bool isConnected() { return connectedFlag; } + bool hasConfig(); String getIPAddress() { return WiFi.localIP().toString(); } + bool startPortal(); + void portalLoop(); // OTA bool updateFirmware();