Refactor main to prepare for wifimgr lite

This commit is contained in:
Magnus Persson 2022-01-09 14:49:20 +01:00
parent 17bc23bef8
commit 7f775d78eb
3 changed files with 231 additions and 182 deletions

View File

@ -33,64 +33,68 @@ SOFTWARE.
#include <wifi.hpp> #include <wifi.hpp>
// Settings for double reset detector. // Settings for double reset detector.
#define ESP8266_DRD_USE_RTC true #define ESP_DRD_USE_LITTLEFS true
#define DRD_TIMEOUT 2 #define DRD_TIMEOUT 2
#define DRD_ADDRESS 0 #define DRD_ADDRESS 0
#include <ESP_DoubleResetDetector.h> #include <ESP_DoubleResetDetector.h>
DoubleResetDetector *drd; extern DoubleResetDetector *drd; // Declared in WifiManager_Lite
// Define constats for this program // Define constats for this program
#ifdef DEACTIVATE_SLEEPMODE #ifdef DEACTIVATE_SLEEPMODE
const int interval = 1000; // ms, time to wait between changes to output const int interval = 1000; // ms, time to wait between changes to output
bool sleepModeAlwaysSkip = true; // Web interface can override normal behaviour
#else #else
const int interval = 200; // ms, time to wait between changes to output int interval = 200; // ms, time to wait between changes to output
bool sleepModeAlwaysSkip = bool sleepModeAlwaysSkip = false; // Web interface can override normal behaviour
false; // Web interface can override normal behaviour
#endif #endif
uint32_t loopMillis = 0; // Used for main loop to run the code every _interval_ 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 runtimeMillis; // Used to calculate the total time since start/wakeup
uint32_t stableGyroMillis; // Used to calculate the total time since last uint32_t stableGyroMillis; // Used to calculate the total time since last
// stable gyro reading // stable gyro reading
bool sleepModeActive = false;
bool goToSleep = false; enum RunMode {
int loopCounter = 0; gravityMode = 0,
configurationMode = 1,
wifiSetupMode = 2
};
RunMode runMode = RunMode::gravityMode;
// //
// Check if we should be in sleep mode // Check if we should be in sleep mode
// //
void checkSleepMode(float angle, float volt) { void checkSleepMode(float angle, float volt) {
#if defined(SKIP_SLEEPMODE) #if defined(SKIP_SLEEPMODE)
sleepModeActive = false; runMode = RunMode::configurationMode;
Log.verbose(F("MAIN: Skipping sleep mode (SKIP_SLEEPMODE is defined)." CR)); Log.verbose(F("MAIN: Skipping sleep mode (SKIP_SLEEPMODE is defined)." CR));
return; return;
#endif #endif
const RawGyroData &g = myConfig.getGyroCalibration(); 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) {
if (g.ax == 0 && g.ay == 0 && g.az == 0 && g.gx == 0 && g.gy == 0 && // Will not enter sleep mode if: no calibration data
g.gz == 0) { Log.notice(F("MAIN: Missing calibration data, so forcing webserver to be active." CR));
Log.notice( runMode = RunMode::configurationMode;
F("MAIN: Missing calibration data, so forcing webserver to be " } else if (sleepModeAlwaysSkip) {
"active." CR)); // Check if the flag from the UI has been set, the we force configuration mode.
sleepModeAlwaysSkip = true;
}
if (sleepModeAlwaysSkip) {
Log.notice(F("MAIN: Sleep mode disabled from web interface." CR)); Log.notice(F("MAIN: Sleep mode disabled from web interface." CR));
sleepModeActive = false; runMode = RunMode::configurationMode;
return; } 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 switch (runMode) {
sleepModeActive = (volt < 4.15 && (angle > 85 && angle < 95)) || (volt > 4.15) case RunMode::configurationMode:
? false Log.notice(F("MAIN: run mode CONFIG (angle=%F volt=%F)." CR), angle, volt);
: true; break;
case RunMode::wifiSetupMode:
// sleep mode active when flat break;
Log.notice(F("MAIN: Deep sleep mode %s (angle=%F volt=%F)." CR), case RunMode::gravityMode:
sleepModeActive ? "true" : "false", angle, volt); Log.notice(F("MAIN: run mode GRAVITY (angle=%F volt=%F)." CR), angle, volt);
break;
}
} }
// //
@ -120,7 +124,7 @@ void setup() {
// Setup watchdog // Setup watchdog
ESP.wdtDisable(); ESP.wdtDisable();
ESP.wdtEnable(interval * 2); ESP.wdtEnable(5000); // 5 seconds
if (dt) { if (dt) {
Log.notice(F("Main: Detected doubletap on reset. Reset reason=%s" CR), Log.notice(F("Main: Detected doubletap on reset. Reset reason=%s" CR),
@ -133,44 +137,148 @@ void setup() {
dt = false; dt = false;
#endif #endif
LOG_PERF_START("main-wifi-connect"); if( !myWifi.hasConfig() ) {
myWifi.connect(dt); // This will return false if unable to connect to wifi, runMode = RunMode::wifiSetupMode;
// will be handled in loop() }
LOG_PERF_STOP("main-wifi-connect");
LOG_PERF_START("main-temp-setup"); // Do this setup for all modes exect wifi setup
myTempSensor.setup(); switch (runMode) {
LOG_PERF_STOP("main-temp-setup"); 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 default:
Log.error(F("Main: Failed to initialize the gyro." CR)); LOG_PERF_START("main-wifi-connect");
myWifi.connect();
LOG_PERF_STOP("main-wifi-connect");
LOG_PERF_START("main-gyro-read"); LOG_PERF_START("main-temp-setup");
myGyro.read(); myTempSensor.setup();
LOG_PERF_STOP("main-gyro-read"); LOG_PERF_STOP("main-temp-setup");
myBatteryVoltage if (!myGyro.setup()) {
.read(); // Takes less than 1ms, so skip this measuring time on this Log.error(F("Main: Failed to initialize the gyro." CR));
checkSleepMode(myGyro.getAngle(), myBatteryVoltage.getVoltage()); } 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) #if defined(ACTIVATE_OTA)
LOG_PERF_START("main-wifi-ota"); LOG_PERF_START("main-wifi-ota");
if (!sleepModeActive && myWifi.checkFirmwareVersion()) { if ( myWifi.checkFirmwareVersion())
myWifi.updateFirmware(); myWifi.updateFirmware();
} LOG_PERF_STOP("main-wifi-ota");
LOG_PERF_STOP("main-wifi-ota");
#endif #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_PERF_STOP("main-setup");
Log.notice(F("Main: Setup completed." CR)); Log.notice(F("Main: Setup completed." CR));
stableGyroMillis = stableGyroMillis = millis(); // Dont include time for wifi connection
millis(); // Put it here so we 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() { void loop() {
drd->loop(); drd->loop();
if (sleepModeActive || abs((int32_t)(millis() - loopMillis)) > interval) { switch (runMode) {
float angle = 0; case RunMode::configurationMode:
float volt = myBatteryVoltage.getVoltage(); myWebServer.loop();
loopCounter++; loopGravityOnInterval();
break;
#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) case RunMode::gravityMode:
Log.verbose(F("Main: Entering main loop." CR)); // If we didnt get a wifi connection, we enter sleep for a short time to
#endif // conserve battery.
if (!myWifi.isConnected()) { // no connection to wifi
// Process the sensor values and push data to targets. Log.notice(F("MAIN: No connection to wifi established, sleeping for 60s." CR));
// ------------------------------------------------------------------------------------------------ goToSleep(60);
// 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);
} }
LOG_PERF_START("loop-push"); if( loopReadGravity() )
myPushTarget.send( goToSleep(myConfig.getSleepInterval());
angle, gravity, corrGravity, temp, (millis() - runtimeMillis) / 1000,
sleepModeActive); // Force the transmission if we are going to sleep
LOG_PERF_STOP("loop-push");
// If we have completed the update lets go to sleep // If the sensor is moving and we are not getting a clear reading, we enter
if (sleepModeActive) goToSleep = true; // sleep for a short time to conserve battery.
} else { if (((millis() - stableGyroMillis) > 10000L)) { // 10s since last stable gyro reading
Log.error(F("Main: No gyro value." CR)); Log.notice(F("MAIN: Unable to get a stable reading for 10s, sleeping for 60s." CR));
} goToSleep(60);
}
#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) LOG_PERF_START("loop-gyro-read");
Log.verbose(F("Main: Sleep mode not active." CR)); myGyro.read();
#endif LOG_PERF_STOP("loop-gyro-read");
break;
int sleepInterval = myConfig.getSleepInterval(); case RunMode::wifiSetupMode:
myWifi.portalLoop();
// If we didnt get a wifi connection, we enter sleep for a short time to break;
// 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();
} }
myWebServer.loop();
} }
// EOF // EOF

View File

@ -26,7 +26,7 @@ SOFTWARE.
#include <ESP8266httpUpdate.h> #include <ESP8266httpUpdate.h>
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
#include <LittleFS.h> #include <LittleFS.h>
#include <WiFiManager.h> #include <ESP_WiFiManager_Lite.h>
#include <incbin.h> #include <incbin.h>
#include <calc.hpp> #include <calc.hpp>
@ -41,14 +41,40 @@ Wifi myWifi;
const char *userSSID = USER_SSID; const char *userSSID = USER_SSID;
const char *userPWD = USER_SSID_PWD; 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 // Connect to last known access point or create one if connection is not
// working. // working.
// //
bool Wifi::connect(bool showPortal) { // REMOVE bool Wifi::connect(bool showPortal) {
bool Wifi::connect() {
WiFi.persistent(true); WiFi.persistent(true);
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
/* REMOVE
if (!strlen(myConfig.getWifiSSID())) { if (!strlen(myConfig.getWifiSSID())) {
Log.info( Log.info(
F("WIFI: No SSID seams to be stored, forcing portal to start." CR)); F("WIFI: No SSID seams to be stored, forcing portal to start." CR));
@ -86,6 +112,7 @@ bool Wifi::connect(bool showPortal) {
ESP.reset(); ESP.reset();
} }
} }
*/
// Connect to wifi // Connect to wifi
int i = 0; int i = 0;

View File

@ -40,10 +40,13 @@ class Wifi {
public: public:
// WIFI // WIFI
bool connect(bool showPortal = false); bool connect();
bool disconnect(); bool disconnect();
bool isConnected() { return connectedFlag; } bool isConnected() { return connectedFlag; }
bool hasConfig();
String getIPAddress() { return WiFi.localIP().toString(); } String getIPAddress() { return WiFi.localIP().toString(); }
bool startPortal();
void portalLoop();
// OTA // OTA
bool updateFirmware(); bool updateFirmware();