diff --git a/README.md b/README.md index 32405e52..b57aa348 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,11 @@ Wifi & OTA update manager for IOT devices (ESP8266 and ESP32). ESP8266's need at least 1MB flash. You will need a free account at IOTAppStory.com - -Wiki pages: https://iotappstory.com/wiki/arduino-esp

-## Latest stable release 2.0.0 +## Latest stable release 2.0.1 https://github.com/iotappstory/ESP-Library/releases/latest +

## Arduino IDE librairy manager @@ -29,255 +28,8 @@ https://github.com/iotappstory/ESP-Library/releases/latest ## Develop branch If you want to fork or contribute to the library. Please send your pull request to the "develop" branch.

-## API 2.0.0 - -### `IOTAppStory(const char* compDate, const int modeButton)` - -Tells IAS the compilation date and what digital input is the force-update/reset button. Note: the EEPROM size and number of firmware variables are limited to 1024 and 12 respectively. If additional resources are needed beyond these limits `EEPROM_SIZE` and `MAXNUMEXTRAFIELDS` can be defined / modified in `IOTAppStory.h`. - -```c -#define COMPDATE __DATE__ __TIME__ -#define MODE_BUTTON 0 - - -#include -IOTAppStory IAS(COMPDATE, MODEBUTTON); - -setup () { ... } -loop () { ... } -``` -
- -### `preSet...()` -With preSet's you can set various options to influence how `begin()` sets things up. All calls to -these function's must be done before calling `begin()`. - -#### `preSetBoardname(String)` -Set the boardname, this is used as your Wifi Ap name in WIFI_AP mode. And is also used for your MDNS responder: http://example-name.local - -#### `preSetAutoUpdate(bool)` -Setting to `true` will make the device do an update-check immediately after calling `begin()`. The default is `true` - -#### `preSetAutoConfig(bool)` -Set whether or not the device should go into config mode after after failing to connect to a Wifi AP. The default is `true` - -#### `preSetWifi(String, String)` -Set the WiFi credentials without going through the captive portal. For development only! Make sure to delete this preSet when you publish your App. - - -Example of using preSet's: - -```c -... - -setup () { - ... - - IAS.preSetBoardname("virginsoil-full"); - IAS.preSetAutoUpdate(true); - IAS.preSetAutoConfig(true); - IAS.preSetWifi("ssid","password"); - - - IAS.begin(); -} -``` -
- -### `addField(char* var, string fieldLab, uint maxLen, char type = 'L')` -reference to org variable | html field label | max nr of char | Optional "special field" char - -These fields are added to the "App Settings" page in config mode and saved to eeprom. Updated values are returned to the original variable. - - - -By default added fields will be renderd like the input field "TEXTLINE" in the pic above. You can use the other field types by adding the optional "special field" char. For more info about these fields have a look at the "VirginSoil-Full" example. - - -Currently only char arrays are supported. -Use functions like atoi() and atof() to transform the char array to integers or floats -Use dPinConv() to convert Dpin numbers(pin-name) to integers (D6 > 14) - - - - -Example: - -```c -... - -char* LEDpin = "D4"; -char* lbl1 = "Light Show"; - -setup () { - ... - - IAS.addField(LEDpin, "ledPin", 2, 'P'); - IAS.addField(lbl1, "Label 1", 16); - - IAS.begin(); -} -``` -
- -### `callbacks...()` -Thanks to [izanette](https://github.com/izanette) you can now configure callback functions that do something or give feedback to the user about the current state of the application. We have added a few of our own and hope you like it! - - -#### `onFirstBoot(THandlerFunction)` -Called on the first boot of this app. Will only run once. After serial or ota upload. - -#### `onModeButtonNoPress(THandlerFunction)` -Called when state is changed to idle. (mode button is not pressed) - -#### `onModeButtonShortPress(THandlerFunction)` -Called when state is changed to short press. - -#### `onModeButtonLongPress(THandlerFunction)` -Called when state is changed to long press. - -#### `onModeButtonVeryLongPress(THandlerFunction)` -Called when state is changed to very long press. - -#### `onFirmwareUpdateCheck(THandlerFunction)` -Called when the app is about to check for firmware updates. - -#### `onFirmwareUpdateDownload(THandlerFunction)` -Called when the app starts to download updates. - -#### `onFirmwareUpdateError(THandlerFunction)` -Called when downloading firmware updates end in error. - -#### `onConfigMode(THandlerFunction)` -Called when the app enters configuration mode. - -In this example we use serial print to demonstrate the call backs. But you could use leds etc: -```c -... - -setup () { - ... - - IAS.onModeButtonShortPress([]() { - Serial.println(F(" If mode button is released, I will enter in firmware update mode.")); - Serial.println(F("*-------------------------------------------------------------------------*")); - }); - - IAS.onModeButtonLongPress([]() { - Serial.println(F(" If mode button is released, I will enter in configuration mode.")); - Serial.println(F("*-------------------------------------------------------------------------*")); - }); - - IAS.begin(); -} -``` -
- -### `begin(char eraseEeprom)` -Set up IAS and start all dependent services. - -If `eraseEeprom` is 'F' (full), the entire EEPROM (including wifi credentials and IAS activation code) will be -erased on first boot of the sketch/app. - -If `eraseEeprom` is 'P' (partial)(DEFAULT), some of the EEPROM (excluding wifi credentials and IAS activation code) will be -erased on first boot of the sketch/app. - -If `eraseEeprom` is 'L' (leave intact), none of the EEPROM (including wifi credentials and IAS activation code) will be -erased on first boot of the sketch/app.

- -Example: - -```c -... - -setup () { - ... - - IAS.begin('P'); -} -``` -
- - -### `setCallHome(bool)` -Set to 'true' to enable calling home frequently (disabled by default)

- -### `setCallHomeInterval(int)` -Call home interval in seconds, use 60s only for development. Please change it to at least 2 hours in production. - -Example: - -```c -... - -setup () { - ... - - IAS.begin(); - - IAS.setCallHome(true); - IAS.setCallHomeInterval(60); -} -``` -
- -### `loop()` -This function ensures the library performs all the periodic tasks it needs to performm: - -* [`buttonLoop()`](#buttonLoop()) -* [`callHome()`](#callHome()): This will be called if you have previously called [`setCallHome(true)`](#setCallHome(bool)) and if the timer set by [`setCallHomeInterval()`](#setCallHomeInterval(int)) (default = 7200 seconds or 2 hours) has expired. - -It is essential that this function called on the first line of your main sketch's `loop()`. - -### `buttonLoop()` -Checks if the button is depressed and what mode to enter when once it is released. Also returns the buttonstate in `ModeButtonState` format: -``` -ModeButtonNoPress, // mode button is not pressed -ModeButtonShortPress, // short press - will enter in firmwareupdate mode -ModeButtonLongPress, // long press - will enter in configurationmode -ModeButtonVeryLongPress, // very long press - won't do anything (but the app developer might want to do something) -ModeButtonFirmwareUpdate, // about to enter in firmware update mode -ModeButtonConfigMode // about to enter in configuration mode -``` - -### `callHome(bool spiffs)` -Calls IOTAppStory.com to check for updates. The `setCallHomeInterval()` function mentioned above already handles calling home at a certain interval. But if you would like to decide yourself under which circumstances and when to call home. This is for you. - -Write whatever conditions you want and simply add the callHome() function. - -If `spiffs` is true, the call also checks if there is a new filesystem image to download.

- -```c -... - -void loop() { - IAS.loop(); - - if(batLvl >= 20 && lstUpd != today){ - IAS.callHome(); - lstUpd = today; - } -} -``` -
- -### `dPinConv(...)` -Use dPinConv() to convert Dpin & Ppin numbers to integers (D6 > 14) - -We advise to use the original Gpio numbers used by the ESP. However a lot of our users use boards like the “Wemos” & “NodeMCU”. They tend to use the silkscreen numbering like D6, D2 etc. - -Normally this would be handled by the defined ”const” in your boards [pins_arduino.h](https://github.com/esp8266/Arduino/tree/master/variants) file during compilation. However when entered after compilation, like with the added fields in the html config pages “addField(.. .. .. ..)”, these values get returned as ”String” instead of being translated to a “int” - -And if you originally developed your code for these “Special ESP’s”. This part makes makes it compatible when compiling for "Generic ESP's" - - -
- ## IAS WIKI -https://iotappstory.com/wiki/arduino-esp -

+https://iotappstory.com/wiki/arduino-esp

## Contributions and thanks -Thanks to [msiebuhr](https://github.com/msiebuhr) for this readme file. - -And thankyou to all of you who made a [pull request](https://github.com/iotappstory/ESP-Library/graphs/contributors) +Thankyou to all of you who made a [pull request](https://github.com/iotappstory/ESP-Library/graphs/contributors) diff --git a/keywords.txt b/keywords.txt index 8bc09ae3..73f34630 100644 --- a/keywords.txt +++ b/keywords.txt @@ -32,6 +32,7 @@ onFirstBoot KEYWORD2 onFirmwareUpdateCheck KEYWORD2 onFirmwareUpdateDownload KEYWORD2 onFirmwareUpdateError KEYWORD2 +onFirmwareUpdateSuccess KEYWORD2 onConfigMode KEYWORD2 addField KEYWORD2 @@ -41,6 +42,7 @@ callHome KEYWORD2 setCallHome KEYWORD2 setCallHomeInterval KEYWORD2 dPinConv KEYWORD2 +eepFreeFrom KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/library.json b/library.json index 7c660e0f..4e7343b5 100644 --- a/library.json +++ b/library.json @@ -9,5 +9,11 @@ }, "frameworks": "arduino", "platforms": "espressif32", - "version": "2.0.0" + "dependencies": + { + "name": "ESP Async WebServer", + "platforms": ["espressif8266", "espressif32"], + "authors": "Hristo Gochkov" + }, + "version": "2.0.1" } diff --git a/library.properties b/library.properties index 9af4b247..4caefa53 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=IOTAppStory-ESP -version=2.0.0 +version=2.0.1 author=SensorsIot maintainer=iotappstory sentence=Update your ESP8266 & ESP32 modules over the air(OTA) diff --git a/src/ESPhttpUpdateIasMod.cpp b/src/ESPhttpUpdateIasMod.cpp index a2755a56..fbfa7c41 100644 --- a/src/ESPhttpUpdateIasMod.cpp +++ b/src/ESPhttpUpdateIasMod.cpp @@ -155,6 +155,7 @@ bool ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, int len, bool spiffs){ } #endif } + return false; } diff --git a/src/IOTAppStory.cpp b/src/IOTAppStory.cpp index 32c4e81e..66f926a9 100644 --- a/src/IOTAppStory.cpp +++ b/src/IOTAppStory.cpp @@ -1,9 +1,6 @@ #include "IOTAppStory.h" - - - IOTAppStory::IOTAppStory(const char *compDate, const int modeButton) : _compDate(compDate) , _modeButton(modeButton) @@ -70,7 +67,8 @@ void IOTAppStory::firstBoot(char ea){ boardMode = 'N'; bootTimes = 0; - writePref(); + boardInfo boardInfo(bootTimes, boardMode); + boardInfo.write(); // update first boot config flag (date) strcpy(config.compDate, _compDate); @@ -143,11 +141,11 @@ void IOTAppStory::preSetServer(String HOST1, String FILE1){ void IOTAppStory::setCallHome(bool callHome) { - _callHome = callHome; + _callHome = callHome; } void IOTAppStory::setCallHomeInterval(unsigned long interval) { - _callHomeInterval = interval * 1000; //Convert to millis so users can pass seconds to this function + _callHomeInterval = interval * 1000; //Convert to millis so users can pass seconds to this function } void IOTAppStory::begin(char ea){ @@ -192,7 +190,9 @@ void IOTAppStory::begin(char ea){ pinMode(_modeButton, INPUT_PULLUP); // Read the "bootTime" & "boardMode" from the Non-volatile storage on ESP32 processor - readPref(); + //readPref(); + boardInfo boardInfo(bootTimes, boardMode); + boardInfo.read(); // on first boot of the app run the firstBoot() function if(strcmp(config.compDate,_compDate) != 0){ @@ -202,10 +202,11 @@ void IOTAppStory::begin(char ea){ // BOOT STATISTICS read and increase boot statistics (optional) #if BOOTSTATISTICS == true && DEBUG_LVL >= 1 bootTimes++; - writePref(); + //writePref(); + boardInfo.write(); #if DEBUG_LVL >= 1 - printPref(); + printBoardInfo(); #endif #endif @@ -246,94 +247,31 @@ void IOTAppStory::begin(char ea){ } -/** read / get the stored preferences */ -void IOTAppStory::readPref() { - #ifdef ESP32 - Preferences preferences; - - // Open Preferences - preferences.begin("pref", false); - - // Get the bootTimes value, if the key does not exist, return a default value of 0 - bootTimes = preferences.getUInt("bootTimes", 0); - - // Get the boardMode value, if the key does not exist, return a default value of 'N' - boardMode = preferences.getUInt("boardMode", 'N'); - - // Close the Preferences - preferences.end(); - - #else - - system_rtc_mem_read(RTCMEMBEGIN, &rtcMem, sizeof(rtcMem)); - if (rtcMem.markerFlag != MAGICBYTE) { - rtcMem.markerFlag = MAGICBYTE; - rtcMem.bootTimes = 0; - rtcMem.boardMode = 'N'; - system_rtc_mem_write(RTCMEMBEGIN, &rtcMem, sizeof(rtcMem)); - } - boardMode = rtcMem.boardMode; - bootTimes = rtcMem.bootTimes; - #endif -} - - -/** store preferences */ -void IOTAppStory::writePref(){ - #ifdef ESP32 - Preferences preferences; - - // Open Preferences - preferences.begin("pref", false); - - // Store the bootTimes value - preferences.putUInt("bootTimes", bootTimes); - - // Store the boardMode value - preferences.putUInt("boardMode", boardMode); - - // Close the Preferences - preferences.end(); - - #else - rtcMem.boardMode = boardMode; - rtcMem.bootTimes = bootTimes; - - rtcMem.markerFlag = MAGICBYTE; - system_rtc_mem_write(RTCMEMBEGIN, &rtcMem, sizeof(rtcMem)); - #endif -} - - #if DEBUG_LVL >= 1 -/** print preferences */ -void IOTAppStory::printPref(){ - #ifdef ESP32 - DEBUG_PRINTF_P(SER_BOOTTIMES_UPDATE, bootTimes, boardMode); - #else - DEBUG_PRINTF_P(SER_BOOTTIMES_POWERUP, rtcMem.bootTimes, rtcMem.boardMode); - #endif +/** print BoardInfo */ +void IOTAppStory::printBoardInfo(){ + DEBUG_PRINTF_P(SER_BOOTTIMES_UPDATE, bootTimes, boardMode); DEBUG_PRINTLN(FPSTR(SER_DEV)); } #endif /** send msg to iasLog */ -void IOTAppStory::iasLog(char* msg) { +void IOTAppStory::iasLog(String msg) { // notifi IAS & enduser about the localIP String url = F("https://"); url += _updateHost; url += F("/ota/cfg-sta.php"); url += "?msg="; url += msg; - + HTTPClient http; httpClientSetup(http, url, false); - + #if DEBUG_LVL >= 3 DEBUG_PRINTLN(SER_UPDATE_IASLOG); #endif - + if(http.GET() != HTTP_CODE_OK){ #if DEBUG_LVL >= 3 DEBUG_PRINTLN(SER_FAILED_COLON); @@ -353,11 +291,11 @@ void IOTAppStory::runConfigServer() { if (_configModeCallback){ _configModeCallback(); } - + #if DEBUG_LVL >= 1 DEBUG_PRINT(SER_CONFIG_MODE); #endif - + if(WiFi.status() != WL_CONNECTED){ // when there is no wifi setup server in AP mode @@ -395,16 +333,16 @@ void IOTAppStory::runConfigServer() { } - server->on("/", HTTP_GET, [&](AsyncWebServerRequest *request){ servHdlRoot(request); }); - server->on("/i", HTTP_GET, [&](AsyncWebServerRequest *request){ servHdlDevInfo(request); }); - #if defined ESP8266 + server->on("/", HTTP_GET, [&](AsyncWebServerRequest *request){ servHdlRoot(request); }); + server->on("/i", HTTP_GET, [&](AsyncWebServerRequest *request){ servHdlDevInfo(request); }); + #if defined ESP8266 server->on("/fp", HTTP_POST, [&](AsyncWebServerRequest *request){ servHdlFngPrintSave(request); }); #endif - server->on("/wsc", HTTP_GET, [&](AsyncWebServerRequest *request){ servHdlWifiScan(request); }); - server->on("/wsa", HTTP_POST, [&](AsyncWebServerRequest *request){ servHdlWifiSave(request); }); - server->on("/app", HTTP_GET, [&](AsyncWebServerRequest *request){ servHdlAppInfo(request); }); - server->on("/as", HTTP_POST, [&](AsyncWebServerRequest *request){ servHdlAppSave(request); }); - + server->on("/wsc", HTTP_GET, [&](AsyncWebServerRequest *request){ servHdlWifiScan(request); }); + server->on("/wsa", HTTP_POST, [&](AsyncWebServerRequest *request){ servHdlWifiSave(request); }); + server->on("/app", HTTP_GET, [&](AsyncWebServerRequest *request){ servHdlAppInfo(request); }); + server->on("/as", HTTP_POST, [&](AsyncWebServerRequest *request){ servHdlAppSave(request); }); + server->on("/ds", HTTP_POST, [&](AsyncWebServerRequest *request){ #if DEBUG_LVL >= 3 DEBUG_PRINT(SER_REC_ACT_CODE); @@ -539,16 +477,15 @@ void IOTAppStory::connectNetwork() { #endif #if WIFI_MULTI == true - wifiMulti.addAP(config.ssid[0], config.password[0]); - wifiMulti.addAP(config.ssid[1], config.password[1]); - wifiMulti.addAP(config.ssid[2], config.password[2]); + wifiMulti.addAP(config.ssid[0], config.password[0]); + wifiMulti.addAP(config.ssid[1], config.password[1]); + wifiMulti.addAP(config.ssid[2], config.password[2]); #else WiFi.begin(config.ssid[0], config.password[0]); #endif - - //if(WiFi.status() != WL_CONNECTED) { + if(!isNetworkConnected()) { @@ -556,58 +493,57 @@ void IOTAppStory::connectNetwork() { if(boardMode == 'N'){ boardMode = 'C'; - writePref(); + //writePref(); + boardInfo boardInfo(bootTimes, boardMode); + boardInfo.write(); } #if DEBUG_LVL >= 1 DEBUG_PRINT(SER_CONN_NONE_GO_CFG); - #endif + #endif }else{ #if DEBUG_LVL >= 1 // this point is only reached if _automaticConfig = false DEBUG_PRINT(SER_CONN_NONE_CONTINU); - #endif + #endif } - + }else{ #if DEBUG_LVL >= 1 DEBUG_PRINTLN(SER_CONNECTED); #endif - + #if DEBUG_LVL >= 2 DEBUG_PRINT(SER_DEV_MAC); DEBUG_PRINTLN(WiFi.macAddress()); #endif - + #if DEBUG_LVL >= 1 DEBUG_PRINT(SER_DEV_IP); DEBUG_PRINTLN(WiFi.localIP()); #endif - + #if USEMDNS == true // Register host name in WiFi and mDNS String hostNameWifi = config.deviceName; hostNameWifi += ".local"; - - // wifi_station_set_hostname(config.deviceName); - // WiFi.hostname(hostNameWifi); - + if(MDNS.begin(config.deviceName)){ - + #if DEBUG_LVL >= 1 DEBUG_PRINT(SER_DEV_MDNS); DEBUG_PRINT(hostNameWifi); #endif - + #if DEBUG_LVL >= 2 DEBUG_PRINTLN(SER_DEV_MDNS_INFO); #endif #if DEBUG_LVL == 1 DEBUG_PRINTLN(F("")); #endif - + }else{ #if DEBUG_LVL >= 1 DEBUG_PRINTLN(SER_DEV_MDNS_FAIL); @@ -615,7 +551,7 @@ void IOTAppStory::connectNetwork() { } #endif } - + #if DEBUG_LVL >= 1 DEBUG_PRINTLN(FPSTR(SER_DEV)); @@ -633,11 +569,11 @@ bool IOTAppStory::isNetworkConnected(bool multi) { #elif defined ESP32 int retries = (MAX_WIFI_RETRIES/2); #endif - + #if DEBUG_LVL >= 1 DEBUG_PRINT(F(" ")); #endif - + #if WIFI_MULTI == true if(multi){ while (wifiMulti.run() != WL_CONNECTED && retries-- > 0 ) { @@ -669,14 +605,13 @@ bool IOTAppStory::isNetworkConnected(bool multi) { } -/** +/** call home and check for updates */ void IOTAppStory::callHome(bool spiffs /*= true*/) { // update from IOTappStory.com - bool updateHappened = false; - + #if DEBUG_LVL >= 2 DEBUG_PRINTLN(SER_CALLING_HOME); #endif @@ -684,14 +619,14 @@ void IOTAppStory::callHome(bool spiffs /*= true*/) { if (_firmwareUpdateCheckCallback){ _firmwareUpdateCheckCallback(); } - + // try to update from IOTAppStory - updateHappened = iotUpdater(0); - + iotUpdater(0); + // try to update spiffs from IOTAppStory if(spiffs){ - - updateHappened = iotUpdater(1); + + iotUpdater(1); } #if DEBUG_LVL >= 2 @@ -704,10 +639,10 @@ void IOTAppStory::callHome(bool spiffs /*= true*/) { } -/** +/** IOT updater */ -bool IOTAppStory::iotUpdater(bool spiffs) { +void IOTAppStory::iotUpdater(bool spiffs) { String url = ""; #if DEBUG_LVL >= 2 @@ -762,37 +697,17 @@ bool IOTAppStory::iotUpdater(bool spiffs) { int len = http.getSize(); if(code == HTTP_CODE_OK){ - + ESP8266HTTPUpdate ESPhttpUpdate; - + #if DEBUG_LVL >= 1 DEBUG_PRINT(SER_DOWN_AND_PROC); #endif - + if (_firmwareUpdateDownloadCallback){ _firmwareUpdateDownloadCallback(); } - #if DEBUG_LVL >= 3 - DEBUG_PRINTLN("[httpUpdate] Header read fin.\n"); - DEBUG_PRINTLN("[httpUpdate] Server header:\n"); - DEBUG_PRINTF_P("[httpUpdate] - code: %d\n", code); - DEBUG_PRINTF_P("[httpUpdate] - len: %d\n", len); - - if(http.hasHeader("x-MD5")) { - DEBUG_PRINTF_P("[httpUpdate] - MD5: %s\n", http.header("x-MD5").c_str()); - } - - DEBUG_PRINTLN("[httpUpdate] ESP8266 info:\n"); - #if defined ESP32 - - #elif defined ESP8266 - DEBUG_PRINTF_P("[httpUpdate] - free Space: %d\n", ESP.getFreeSketchSpace()); - DEBUG_PRINTF_P("[httpUpdate] - current Sketch Size: %d\n", ESP.getSketchSize()); - #endif - DEBUG_PRINTF_P("[httpUpdate] - current version: %s\n", config.appVersion); - - #endif if(ESPhttpUpdate.handleUpdate(http, len, spiffs)) { // succesfull update @@ -812,7 +727,6 @@ bool IOTAppStory::iotUpdater(bool spiffs) { // reboot ESP.restart(); } - return true; }else{ #if DEBUG_LVL >= 1 @@ -825,23 +739,13 @@ bool IOTAppStory::iotUpdater(bool spiffs) { #endif #if defined ESP32 - if(code == 399){ - return true; - }else{ - if (_firmwareUpdateErrorCallback){ - _firmwareUpdateErrorCallback(); - } - return false; + if(code != 399 && _firmwareUpdateErrorCallback){ + _firmwareUpdateErrorCallback(); } #elif defined ESP8266 - if(code == HTTP_CODE_NOT_MODIFIED){ - return true; - }else{ - if (_firmwareUpdateErrorCallback){ - _firmwareUpdateErrorCallback(); - } - return false; + if(code != HTTP_CODE_NOT_MODIFIED && _firmwareUpdateErrorCallback){ + _firmwareUpdateErrorCallback(); } #endif @@ -870,7 +774,7 @@ void IOTAppStory::addField(char* &defaultVal,const char *fieldLabel, int length, - load stored values */ void IOTAppStory::processField(){ - + eepFreeFrom = sizeof(config)+2; // to prevent longer then default values overwriting each other // temp save value, overwrite variable with longest value posible // and then resave the temp value to the original variable @@ -914,9 +818,8 @@ void IOTAppStory::processField(){ prevTotLength += fieldStruct[i].length; } const int sizeOfVal = fieldStruct[nr-1].length; - const int sizeOfConfig = sizeof(config)+2; - const int eeBeg = sizeOfConfig+prevTotLength+nr+((nr-1)*2); - const int eeEnd = sizeOfConfig+(prevTotLength+sizeOfVal)+nr+1+((nr-1)*2); + const unsigned int eeBeg = eepFreeFrom+prevTotLength+nr+((nr-1)*2); + const unsigned int eeEnd = eepFreeFrom+(prevTotLength+sizeOfVal)+nr+1+((nr-1)*2); #if DEBUG_LVL >= 2 DEBUG_PRINTF_P(PSTR(" %02d | %-30s | %03d | %04d to %04d | %-30s | "), nr, fieldStruct[nr-1].fieldLabel, fieldStruct[nr-1].length-1, eeBeg, eeEnd, (*fieldStruct[nr-1].varPointer)); @@ -975,8 +878,14 @@ void IOTAppStory::processField(){ #if DEBUG_LVL >= 2 DEBUG_PRINTLN(); #endif + + if(nr == _nrXF){ + eepFreeFrom = eeEnd+ 2; + } } EEPROM.end(); + + #if DEBUG_LVL >= 1 DEBUG_PRINTLN(FPSTR(SER_DEV)); #endif @@ -1075,7 +984,8 @@ void IOTAppStory::espRestart(char mmode) { delay(500); boardMode = mmode; - writePref(); + boardInfo boardInfo(bootTimes, boardMode); + boardInfo.write(); ESP.restart(); } @@ -1105,7 +1015,7 @@ void IOTAppStory::writeConfig(bool saveXF) { EEPROM.begin(EEPROM_SIZE); // WRITE CONFIG TO EEPROM - for (int t = 0; t < sizeof(config); t++) { + for (unsigned int t = 0; t < sizeof(config); t++) { EEPROM.write(t, *((char*)&config + t)); #if DEBUG_EEPROM_CONFIG @@ -1123,10 +1033,10 @@ void IOTAppStory::writeConfig(bool saveXF) { if(saveXF == true && _nrXF > 0){ // LOOP THROUGH ALL THE ADDED FIELDS, CHECK VALUES AND IF NECESSARY WRITE TO EEPROM - for (int nr = 1; nr <= _nrXF; nr++){ + for (unsigned int nr = 1; nr <= _nrXF; nr++){ int prevTotLength = 0; - for(int i = 0; i < (nr-1); i++){ + for(unsigned int i = 0; i < (nr-1); i++){ prevTotLength += fieldStruct[i].length; } const int sizeOfVal = fieldStruct[nr-1].length; @@ -1199,7 +1109,7 @@ void IOTAppStory::readConfig() { DEBUG_PRINTLN(SER_EEPROM_FOUND); #endif - for(int t = 0; t < sizeof(config); t++){ + for(unsigned int t = 0; t < sizeof(config); t++){ char valueReaded = EEPROM.read(t); *((char*)&config + t) = valueReaded; @@ -1228,17 +1138,17 @@ void IOTAppStory::readConfig() { void IOTAppStory::loop() { - if (_callHome && millis() - _lastCallHomeTime > _callHomeInterval) { - this->callHome(); - _lastCallHomeTime = millis(); - } + if (_callHome && millis() - _lastCallHomeTime > _callHomeInterval) { + this->callHome(); + _lastCallHomeTime = millis(); + } - this->buttonLoop(); + this->buttonLoop(); } ModeButtonState IOTAppStory::buttonLoop() { - return getModeButtonState(); + return getModeButtonState(); } @@ -1248,11 +1158,11 @@ bool IOTAppStory::isModeButtonPressed() { ModeButtonState IOTAppStory::getModeButtonState() { - + while(true) { unsigned long buttonTime = millis() - _buttonEntry; - + switch(_appState) { case AppStateNoPress: if (isModeButtonPressed()) { @@ -1261,7 +1171,7 @@ ModeButtonState IOTAppStory::getModeButtonState() { continue; } return ModeButtonNoPress; - + case AppStateWaitPress: if (buttonTime > MODE_BUTTON_SHORT_PRESS) { _appState = AppStateShortPress; @@ -1273,7 +1183,7 @@ ModeButtonState IOTAppStory::getModeButtonState() { _appState = AppStateNoPress; } return ModeButtonNoPress; - + case AppStateShortPress: if (buttonTime > MODE_BUTTON_LONG_PRESS) { _appState = AppStateLongPress; @@ -1331,7 +1241,7 @@ ModeButtonState IOTAppStory::getModeButtonState() { -/** +/** callBacks */ void IOTAppStory::onFirstBoot(THandlerFunction value) { @@ -1372,64 +1282,64 @@ void IOTAppStory::onConfigMode(THandlerFunction value) { /** Handle root */ void IOTAppStory::servHdlRoot(AsyncWebServerRequest *request) { - - String retHtml; - retHtml += FPSTR(HTTP_TEMP_START); - - if (WiFi.status() == WL_CONNECTED) { - - retHtml.replace("{h}", FPSTR(HTTP_STA_JS)); - }else{ - - retHtml.replace("{h}", FPSTR(HTTP_AP_CSS)); - retHtml += FPSTR(HTTP_WIFI_FORM); - retHtml.replace("{r}", strWifiScan()); - retHtml += FPSTR(HTTP_AP_JS); - } - - retHtml += FPSTR(HTTP_TEMP_END); - - hdlReturn(request, retHtml); + String retHtml; + retHtml += FPSTR(HTTP_TEMP_START); + + if (WiFi.status() == WL_CONNECTED) { + + retHtml.replace("{h}", FPSTR(HTTP_STA_JS)); + + }else{ + + retHtml.replace("{h}", FPSTR(HTTP_AP_CSS)); + retHtml += FPSTR(HTTP_WIFI_FORM); + retHtml.replace("{r}", strWifiScan()); + retHtml += FPSTR(HTTP_AP_JS); + } + + retHtml += FPSTR(HTTP_TEMP_END); + + hdlReturn(request, retHtml); } /** Handle device information */ void IOTAppStory::servHdlDevInfo(AsyncWebServerRequest *request){ - #if DEBUG_LVL >= 3 - DEBUG_PRINTLN(SER_SERV_DEV_INFO); - #endif - - String retHtml; - retHtml += FPSTR(HTTP_DEV_INFO); - retHtml.replace(F("{s1}"), config.ssid[0]); - retHtml.replace(F("{s2}"), config.ssid[1]); - retHtml.replace(F("{s3}"), config.ssid[2]); + #if DEBUG_LVL >= 3 + DEBUG_PRINTLN(SER_SERV_DEV_INFO); + #endif - #if defined ESP8266 - retHtml.replace(F("{cid}"), String(ESP.getChipId())); - retHtml.replace(F("{fid}"), String(ESP.getFlashChipId())); - retHtml.replace(F("{fss}"), String(ESP.getFreeSketchSpace())); - retHtml.replace(F("{ss}"), String(ESP.getSketchSize())); - retHtml.replace(F("{f}"), config.sha1); - #elif defined ESP32 - retHtml.replace(F("{cid}"), ""); // not available yet - retHtml.replace(F("{fid}"), ""); // not available yet - #endif - - retHtml.replace(F("{fs}"), String(ESP.getFlashChipSize())); - retHtml.replace(F("{ab}"), ARDUINO_BOARD); - retHtml.replace(F("{mc}"), WiFi.macAddress()); - retHtml.replace(F("{xf}"), String(_nrXF)); - - if(String(config.actCode) == "000000" || String(config.actCode) == ""){ - retHtml.replace(F("{ac}"), "0"); - }else{ - retHtml.replace(F("{ac}"), "1"); - } - - hdlReturn(request, retHtml, F("text/json")); + String retHtml; + retHtml += FPSTR(HTTP_DEV_INFO); + retHtml.replace(F("{s1}"), config.ssid[0]); + retHtml.replace(F("{s2}"), config.ssid[1]); + retHtml.replace(F("{s3}"), config.ssid[2]); + + #if defined ESP8266 + retHtml.replace(F("{cid}"), String(ESP.getChipId())); + retHtml.replace(F("{fid}"), String(ESP.getFlashChipId())); + retHtml.replace(F("{fss}"), String(ESP.getFreeSketchSpace())); + retHtml.replace(F("{ss}"), String(ESP.getSketchSize())); + retHtml.replace(F("{f}"), config.sha1); + #elif defined ESP32 + retHtml.replace(F("{cid}"), ""); // not available yet + retHtml.replace(F("{fid}"), ""); // not available yet + #endif + + retHtml.replace(F("{fs}"), String(ESP.getFlashChipSize())); + retHtml.replace(F("{ab}"), ARDUINO_BOARD); + retHtml.replace(F("{mc}"), WiFi.macAddress()); + retHtml.replace(F("{xf}"), String(_nrXF)); + + if(String(config.actCode) == "000000" || String(config.actCode) == ""){ + retHtml.replace(F("{ac}"), "0"); + }else{ + retHtml.replace(F("{ac}"), "1"); + } + + hdlReturn(request, retHtml, F("text/json")); } @@ -1566,31 +1476,31 @@ void IOTAppStory::servHdlWifiSave(AsyncWebServerRequest *request) { /** Handle app / firmware information */ void IOTAppStory::servHdlAppInfo(AsyncWebServerRequest *request){ - #if DEBUG_LVL >= 3 - DEBUG_PRINTLN(SER_SERV_APP_SETTINGS); - #endif - - String retHtml = F("["); - - for (int i = 0; i < _nrXF; ++i) { - - // return html results from the wifi scan - if(i > 0){ - retHtml += F(","); - } - retHtml += FPSTR(HTTP_APP_INFO); - retHtml.replace(F("{l}"), String(fieldStruct[i].fieldLabel)); - retHtml.replace(F("{v}"), String((*fieldStruct[i].varPointer))); - retHtml.replace(F("{n}"), String(i)); - retHtml.replace(F("{m}"), String(fieldStruct[i].length)); - retHtml.replace(F("{t}"), String(fieldStruct[i].type)); - delay(10); + #if DEBUG_LVL >= 3 + DEBUG_PRINTLN(SER_SERV_APP_SETTINGS); + #endif + + String retHtml = F("["); + + for (unsigned int i = 0; i < _nrXF; ++i) { + + // return html results from the wifi scan + if(i > 0){ + retHtml += F(","); } - retHtml += F("]"); - #if DEBUG_LVL >= 3 - DEBUG_PRINTLN(retHtml); - #endif - hdlReturn(request, retHtml, F("application/json")); + retHtml += FPSTR(HTTP_APP_INFO); + retHtml.replace(F("{l}"), String(fieldStruct[i].fieldLabel)); + retHtml.replace(F("{v}"), String((*fieldStruct[i].varPointer))); + retHtml.replace(F("{n}"), String(i)); + retHtml.replace(F("{m}"), String(fieldStruct[i].length)); + retHtml.replace(F("{t}"), String(fieldStruct[i].type)); + delay(10); + } + retHtml += F("]"); + #if DEBUG_LVL >= 3 + DEBUG_PRINTLN(retHtml); + #endif + hdlReturn(request, retHtml, F("application/json")); } diff --git a/src/IOTAppStory.h b/src/IOTAppStory.h index 86696631..13f30b34 100644 --- a/src/IOTAppStory.h +++ b/src/IOTAppStory.h @@ -1,46 +1,46 @@ #ifndef IOTAppStory_h #define IOTAppStory_h - - - /** + + + /** ------ ------ ------ ------ ------ ------ library includes ------ ------ ------ ------ ------ ------ */ + #include "config.h" #ifdef ESP32 - #include - #include - #include - #include - #include // https://github.com/me-no-dev/AsyncTCP - #include - #else - #include - #include - #include - extern "C" { - #include "user_interface.h" // used by the RTC memory read/write functions - } - #include - #include // https://github.com/me-no-dev/ESPAsyncTCP - #include + #include + #include + #include + #include "esp32/boardInfo.h" + #include // https://github.com/me-no-dev/AsyncTCP + #include + #elif defined ESP8266 + #include + #include + #include + #include "esp8266/boardInfo.h" + #include + #include // https://github.com/me-no-dev/ESPAsyncTCP + #include #endif - + #include "ESPhttpUpdateIasMod.h" #include #include #include - #include // https://github.com/me-no-dev/ESPAsyncWebServer + #include // https://github.com/me-no-dev/ESPAsyncWebServer - /** + /** ------ ------ ------ ------ ------ ------ macros for debugging ------ ------ ------ ------ ------ ------ */ + #if DEBUG_LVL >= 1 - + // set to true to include code for show EEPROM contents in debug #ifndef DEBUG_EEPROM_CONFIG #define DEBUG_EEPROM_CONFIG false @@ -58,86 +58,79 @@ #define DEBUG_PRINTF_P(...) { Serial.printf_P(__VA_ARGS__); } #define DEBUG_PRINTLN(x) { Serial.println(x); } #endif - - - - /** + + + + /** ------ ------ ------ ------ ------ ------ STRUCTURES ------ ------ ------ ------ ------ ------ - **/ - #ifndef ESP32 - typedef struct { - byte markerFlag; - int bootTimes; - char boardMode = 'N'; // Normal operation or Configuration mode? - } rtcMemDef __attribute__((aligned(4))); - #endif - - typedef struct { + */ + typedef struct { const char *fieldLabel; char* (*varPointer); int length; char type; } eFields; - - typedef struct { - char actCode[7]; // saved IotAppStory activation code + + typedef struct { + char actCode[7]; // saved IotAppStory activation code char appName[33]; char appVersion[12]; - char ssid[3][STRUCT_CHAR_ARRAY_SIZE]; // 3x SSID - char password[3][STRUCT_PASSWORD_SIZE]; // 3x PASS + char ssid[3][STRUCT_CHAR_ARRAY_SIZE]; // 3x SSID + char password[3][STRUCT_PASSWORD_SIZE]; // 3x PASS char deviceName[STRUCT_BNAME_SIZE]; - char compDate[STRUCT_COMPDATE_SIZE]; // saved compile date time + char compDate[STRUCT_COMPDATE_SIZE]; // saved compile date time #if defined ESP8266 char sha1[60]; #endif #if CFG_AUTHENTICATE == true char cfg_pass[17]; #endif - const char magicBytes[4]; - } strConfig; - + const char magicBytes[4]; + } strConfig; + enum ModeButtonState { - ModeButtonNoPress, // mode button is not pressed - ModeButtonShortPress, // short press - will enter in firmware update mode - ModeButtonLongPress, // long press - will enter in configuration mode - ModeButtonVeryLongPress, // very long press - won't do anything (but the app developer might want to do something) - ModeButtonFirmwareUpdate, // about to enter in firmware update mode - ModeButtonConfigMode // about to enter in configuration mode + ModeButtonNoPress, // mode button is not pressed + ModeButtonShortPress, // short press - will enter in firmware update mode + ModeButtonLongPress, // long press - will enter in configuration mode + ModeButtonVeryLongPress, // very long press - won't do anything (but the app developer might want to do something) + ModeButtonFirmwareUpdate, // about to enter in firmware update mode + ModeButtonConfigMode // about to enter in configuration mode }; - typedef std::function THandlerFunction; + typedef std::function THandlerFunction; - - - - /** + + + + /** ------ ------ ------ ------ ------ ------ PROGMEM ------ ------ ------ ------ ------ ------ */ - const char SER_DEV[] PROGMEM = "*-------------------------------------------------------------------------*"; + + const char SER_DEV[] PROGMEM = "*-------------------------------------------------------------------------*"; const char HTTP_200[] PROGMEM = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"; - const char HTTP_TEMP_START[] PROGMEM = "{h}Config"; - const char HTTP_TEMP_END[] PROGMEM = ""; - - const char HTTP_STA_JS[] PROGMEM = ""; - const char HTTP_AP_JS[] PROGMEM = ""; + const char HTTP_TEMP_START[] PROGMEM = "{h}Config"; + const char HTTP_TEMP_END[] PROGMEM = ""; - const char HTTP_AP_CSS[] PROGMEM = ""; + const char HTTP_STA_JS[] PROGMEM = ""; + const char HTTP_AP_JS[] PROGMEM = ""; - const char HTTP_WIFI_SCAN[] PROGMEM = "{s}{q} dBm"; - const char HTTP_WIFI_FORM[] PROGMEM = "

WIFI CONNECTION

{r}




"; + const char HTTP_AP_CSS[] PROGMEM = ""; + + const char HTTP_WIFI_SCAN[] PROGMEM = "{s}{q} dBm"; + const char HTTP_WIFI_FORM[] PROGMEM = "

WIFI CONNECTION

{r}




"; + + const char HTTP_APP_INFO[] PROGMEM = "{\"l\":\"{l}\", \"v\":\"{v}\", \"n\":\"{n}\", \"m\":\"{m}\", \"t\":\"{t}\"}"; - const char HTTP_APP_INFO[] PROGMEM = "{\"l\":\"{l}\", \"v\":\"{v}\", \"n\":\"{n}\", \"m\":\"{m}\", \"t\":\"{t}\"}"; - #if defined ESP8266 - const char HTTP_DEV_INFO[] PROGMEM = "{\"s1\":\"{s1}\", \"s2\":\"{s2}\", \"s3\":\"{s3}\", \"cid\":\"{cid}\", \"fid\":\"{fid}\", \"fss\":\"{fss}\", \"ss\":\"{ss}\", \"fs\":\"{fs}\", \"ab\":\"{ab}\", \"ac\":\"{ac}\", \"mc\":\"{mc}\", \"xf\":\"{xf}\", \"f\":\"{f}\"}"; + const char HTTP_DEV_INFO[] PROGMEM = "{\"s1\":\"{s1}\", \"s2\":\"{s2}\", \"s3\":\"{s3}\", \"cid\":\"{cid}\", \"fid\":\"{fid}\", \"fss\":\"{fss}\", \"ss\":\"{ss}\", \"fs\":\"{fs}\", \"ab\":\"{ab}\", \"ac\":\"{ac}\", \"mc\":\"{mc}\", \"xf\":\"{xf}\", \"f\":\"{f}\"}"; #endif - - #if defined ESP32 - const char HTTP_DEV_INFO[] PROGMEM = "{\"s1\":\"{s1}\", \"s2\":\"{s2}\", \"s3\":\"{s3}\", \"cid\":\"{cid}\", \"fid\":\"{fid}\", \"fss\":\"{fss}\", \"ss\":\"{ss}\", \"fs\":\"{fs}\", \"ab\":\"{ab}\", \"ac\":\"{ac}\", \"mc\":\"{mc}\", \"xf\":\"{xf}\"}"; - - const char ROOT_CA[] PROGMEM = \ + + #if defined ESP32 + const char HTTP_DEV_INFO[] PROGMEM = "{\"s1\":\"{s1}\", \"s2\":\"{s2}\", \"s3\":\"{s3}\", \"cid\":\"{cid}\", \"fid\":\"{fid}\", \"fss\":\"{fss}\", \"ss\":\"{ss}\", \"fs\":\"{fs}\", \"ab\":\"{ab}\", \"ac\":\"{ac}\", \"mc\":\"{mc}\", \"xf\":\"{xf}\"}"; + + const char ROOT_CA[] PROGMEM = \ "-----BEGIN CERTIFICATE-----\n" \ "MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB\n" \ "hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n" \ @@ -173,258 +166,236 @@ "NVOFBkpdn627G190\n" \ "-----END CERTIFICATE-----\n"; #endif + + + + class IOTAppStory { + + public: + /** + ------ ------ ------ ------ ------ ------ VARIABLES ------ ------ ------ ------ ------ ------ + */ + + int bootTimes; // nr of times this device booted since powerup + char boardMode = 'N'; // Normal operation or Configuration mode? + unsigned int eepFreeFrom; // From where can I use eeprom? + + + strConfig config = { + "", + "", + "", + {"","",""}, + {"","",""}, + "yourESP", + "", + #if defined ESP8266 + "34:6D:0A:26:F0:40:3A:0A:1B:F1:CA:8E:C8:0C:F5:14:21:83:7C:B1", + #endif + #if CFG_AUTHENTICATE == true + "admin", + #endif + "CFG" // Magic Bytes + }; + + + // similar to the ModeButtonState but has some extra states + // that are used internally by the state machine method + enum AppState { + AppStateNoPress, // mode button is not pressed + AppStateWaitPress, // mode button is pressed but not long enough for a short press + AppStateShortPress, // mode button is pressed for a short time. Releasing it will make it go to firmware update mode. + AppStateLongPress, // mode button is pressed for a long time. Releasing it will make it go to config mode. + AppStateVeryLongPress, // mode button is pressed for a very long time. Releasing it won't do anything. + AppStateFirmwareUpdate, // about to enter in firmware update mode + AppStateConfigMode // about to enter in config mode + }; + + + /** + ------ ------ ------ ------ ------ ------ FUCNTION DEFINITIONS ------ ------ ------ ------ ------ ------ + */ + + IOTAppStory(const char *compDate, const int modeButton); + + // function for pre setting config parameters ssid & password, deviceName, automatic update, HOST1 and FILE1 + void preSetAppName(String appName); + void preSetAppVersion(String appVersion); + void preSetDeviceName(String deviceName); + void preSetAutoUpdate(bool automaticUpdate); + void preSetAutoConfig(bool automaticConfig); + void preSetWifi(String ssid, String password); + //void preSetServer(String HOST1, String FILE1); + + void setCallHome(bool callHome); + void setCallHomeInterval(unsigned long interval); + + void begin(char ea); + + void loop(); + + + void writeConfig(bool wifiSave = false); + void readConfig(); + void espRestart(char mmode); + void eraseFlash(int eepFrom, int eepTo); + + void connectNetwork(); + bool isNetworkConnected(bool multi = true); + + void callHome(bool spiffs = true); + void iotUpdater(bool spiffs); + void addField(char* &defaultVal,const char *fieldLabel, int length, char type = 'L'); + void iasLog(String msg = ""); + void runConfigServer(); + int dPinConv(String orgVal); + + void onFirstBoot(THandlerFunction fn); // called at the end of firstBoot + //void onWifiConnected(THandlerFunction fn); // called on succesfull Wifi connection SYSTEM_EVENT_STA_GOT_IP + //void onWifiDisonnected(THandlerFunction fn); // called when Wifi is dissconnected SYSTEM_EVENT_STA_DISCONNECTED + + void onModeButtonNoPress(THandlerFunction fn); // called when state is changed to idle (mode button is not pressed) + void onModeButtonShortPress(THandlerFunction fn); // called when state is changed to short press + void onModeButtonLongPress(THandlerFunction fn); // called when state is changed to long press + void onModeButtonVeryLongPress(THandlerFunction fn); // called when state is changed to very long press + + void onFirmwareUpdateCheck(THandlerFunction fn); // called when the app checks for firmware updates + void onFirmwareUpdateDownload(THandlerFunction fn); // called when firmware update + void onFirmwareUpdateError(THandlerFunction fn); // called when firmware update ends in an error + void onFirmwareUpdateSuccess(THandlerFunction fn); // called when firmware update ends in success + + void onConfigMode(THandlerFunction fn); // called when the app is about to enter in configuration mode + + + + + private: + + std::unique_ptr dnsServer; + std::unique_ptr server; + //std::unique_ptr preferences; + + #if WIFI_MULTI == true + #ifdef ESP32 + WiFiMulti wifiMulti; + #elif defined ESP8266 + ESP8266WiFiMulti wifiMulti; + #endif + #endif + + const char *_compDate; + const int _modeButton; + unsigned int _nrXF = 0; // nr of extra fields required in the config manager + + + const char* _updateHost = "iotappstory.com"; // ota update host + #if defined ESP8266 + const char* _updateFile = "/ota/esp8266-v2.0.1.php"; // loc1, file at host that handles 8266 updates + #elif defined ESP32 + const char* _updateFile = "/ota/esp32-v1.php"; // loc1, file at host that handles 32 updates + #endif + + + bool _updateOnBoot = true; // update on boot? (end of begin();) + bool _automaticConfig = true; // automaticly go to config on boot if there is no wifi connection present + + bool _setPreSet = false; // ;) have there been any preSets set? + bool _setDeviceName = false; // is the device name set? + bool _configReaded = false; // has the config already been read? + bool _callHome = false; + + bool _tryToConn = false; // try to connect to wifi bool + bool _tryToConnFail = false; // try to connect to wifi bool + bool _connected = false; // wifi connection status bool + bool _tryToConf = false; // try to confirm device registration bool + int _confirmed = false; // confirmed status bool + bool _writeConfig = false; + bool _changeMode = false; + + unsigned long _lastCallHomeTime = 0; // Time when we last called home + unsigned long _callHomeInterval = 7200000; // Interval we want to call home at in milliseconds, default start at 2hrs + + unsigned long _buttonEntry; + unsigned long _debugEntry; + AppState _appState; + + eFields fieldStruct[MAXNUMEXTRAFIELDS]; + + + THandlerFunction _firstBootCallback; + //THandlerFunction _wifiConnectedCallback; + //THandlerFunction _wifiDisonnectedCallback; + + THandlerFunction _noPressCallback; + THandlerFunction _shortPressCallback; + THandlerFunction _longPressCallback; + THandlerFunction _veryLongPressCallback; + + THandlerFunction _firmwareUpdateCheckCallback; + THandlerFunction _firmwareUpdateDownloadCallback; + THandlerFunction _firmwareUpdateErrorCallback; + THandlerFunction _firmwareUpdateSuccessCallback; + + THandlerFunction _configModeCallback; + + + /** + ------ ------ ------ ------ ------ ------ FUNCTION DEFINITIONS ------ ------ ------ ------ ------ ------ + */ + + void firstBoot(char ea); + void printBoardInfo(); + void processField(); + void httpClientSetup(HTTPClient& http, String url, bool spiffs=false); + + String strWifiScan(); + + void servHdlRoot(AsyncWebServerRequest *request); + void servHdlDevInfo(AsyncWebServerRequest *request); + #if defined ESP8266 + void servHdlFngPrintSave(AsyncWebServerRequest *request); + #endif + void servHdlWifiScan(AsyncWebServerRequest *request); + void servHdlWifiSave(AsyncWebServerRequest *request); + void servHdlAppInfo(AsyncWebServerRequest *request); + void servHdlAppSave(AsyncWebServerRequest *request); + //void servHdlDevSave(AsyncWebServerRequest *request); + + void hdlReturn(AsyncWebServerRequest *request, String &retHtml, String type = "text/html"); + + void updateLoop(); + bool isModeButtonPressed(); + ModeButtonState getModeButtonState(); + ModeButtonState buttonLoop(); + + + + + /** + ------ ------ ------ ------ ------ ------ AUXILIARY FUNCTIONS ------ ------ ------ ------ ------ ------ + */ + bool SetConfigValueCharArray(char* a, String &b, int len, bool &changeFlag) { + if (b != a) { + b.toCharArray(a, len); + changeFlag = true; + return true; + } else { + return false; + } + } + /* ------ */ + + /* ------ CONVERT BYTE TO STRING */ + String GetCharToDisplayInDebug(char value) { + if (value>=32 && value<=126){ + return String(value); + } else if (value == 0){ + return "."; + } else { + return String("[" + String(value, DEC) + "]"); + } + } - - - class IOTAppStory { - - public: - /** - ------ ------ ------ ------ ------ ------ VARIABLES ------ ------ ------ ------ ------ ------ - */ - - #ifndef ESP32 - rtcMemDef rtcMem; - #endif - - int bootTimes; - char boardMode = 'N'; // Normal operation or Configuration mode? - - - strConfig config = { - "", - "", - "", - {"","",""}, - {"","",""}, - "yourESP", - "", - #if defined ESP8266 - "34:6D:0A:26:F0:40:3A:0A:1B:F1:CA:8E:C8:0C:F5:14:21:83:7C:B1", - #endif - #if CFG_AUTHENTICATE == true - "admin", - #endif - "CFG" // Magic Bytes - }; - - - // similar to the ModeButtonState but has some extra states - // that are used internally by the state machine method - enum AppState { - AppStateNoPress, // mode button is not pressed - AppStateWaitPress, // mode button is pressed but not long enough for a short press - AppStateShortPress, // mode button is pressed for a short time. Releasing it will make it go to firmware update mode. - AppStateLongPress, // mode button is pressed for a long time. Releasing it will make it go to config mode. - AppStateVeryLongPress, // mode button is pressed for a very long time. Releasing it won't do anything. - AppStateFirmwareUpdate, // about to enter in firmware update mode - AppStateConfigMode // about to enter in config mode - }; - - - /** - ------ ------ ------ ------ ------ ------ FUCNTION DEFINITIONS ------ ------ ------ ------ ------ ------ - */ - IOTAppStory(const char *compDate, const int modeButton); - - // function for pre setting config parameters ssid & password, deviceName, automatic update, HOST1 and FILE1 - void preSetAppName(String appName); - void preSetAppVersion(String appVersion); - void preSetDeviceName(String deviceName); - void preSetAutoUpdate(bool automaticUpdate); - void preSetAutoConfig(bool automaticConfig); - void preSetWifi(String ssid, String password); - //void preSetServer(String HOST1, String FILE1); - - void setCallHome(bool callHome); - void setCallHomeInterval(unsigned long interval); - - void begin(char ea); - - void loop(); - - - void writeConfig(bool wifiSave = false); - void readConfig(); - void espRestart(char mmode); - void eraseFlash(int eepFrom, int eepTo); - - void connectNetwork(); - bool isNetworkConnected(bool multi = true); - - void callHome(bool spiffs = true); - bool iotUpdater(bool spiffs); - void addField(char* &defaultVal,const char *fieldLabel, int length, char type = 'L'); - void iasLog(char* msg = ""); - void runConfigServer(); - int dPinConv(String orgVal); - - void onFirstBoot(THandlerFunction fn); // called at the end of firstBoot - //void onWifiConnected(THandlerFunction fn); // called on succesfull Wifi connection SYSTEM_EVENT_STA_GOT_IP - //void onWifiDisonnected(THandlerFunction fn); // called when Wifi is dissconnected SYSTEM_EVENT_STA_DISCONNECTED - - void onModeButtonNoPress(THandlerFunction fn); // called when state is changed to idle (mode button is not pressed) - void onModeButtonShortPress(THandlerFunction fn); // called when state is changed to short press - void onModeButtonLongPress(THandlerFunction fn); // called when state is changed to long press - void onModeButtonVeryLongPress(THandlerFunction fn); // called when state is changed to very long press - - void onFirmwareUpdateCheck(THandlerFunction fn); // called when the app checks for firmware updates - void onFirmwareUpdateDownload(THandlerFunction fn); // called when firmware update - void onFirmwareUpdateError(THandlerFunction fn); // called when firmware update ends in an error - void onFirmwareUpdateSuccess(THandlerFunction fn); // called when firmware update ends in success - - void onConfigMode(THandlerFunction fn); // called when the app is about to enter in configuration mode - - - - - private: - - std::unique_ptr dnsServer; - std::unique_ptr server; - //std::unique_ptr preferences; - - #if WIFI_MULTI == true - #ifdef ESP32 - WiFiMulti wifiMulti; - #else - ESP8266WiFiMulti wifiMulti; - #endif - #endif - - const char *_compDate; - const int _modeButton; - int _nrXF = 0; // nr of extra fields required in the config manager - - - const char* _updateHost = "iotappstory.com"; // ota update host - #if defined ESP8266 - char* _updateFile = "/ota/esp8266-v2.0.1.php"; // loc1, file at host that handles 8266 updates - #elif defined ESP32 - char* _updateFile = "/ota/esp32-v1.php"; // loc1, file at host that handles 32 updates - #endif - - - bool _updateOnBoot = true; // update on boot? (end of begin();) - bool _automaticConfig = true; // automaticly go to config on boot if there is no wifi connection present - - bool _setPreSet = false; // ;) have there been any preSets set? - bool _setDeviceName = false; // is the device name set? - bool _configReaded = false; // has the config already been read? - const static bool _boolDefaulValue = false; - bool _callHome = false; - - bool _tryToConn = false; // try to connect to wifi bool - bool _tryToConnFail = false; // try to connect to wifi bool - bool _connected = false; // wifi connection status bool - bool _tryToConf = false; // try to confirm device registration bool - int _confirmed = false; // confirmed status bool - bool _writeConfig = false; - bool _changeMode = false; - - unsigned long _lastCallHomeTime = 0; //Time when we last called home - unsigned long _callHomeInterval = 7200000; //Interval we want to call home at in milliseconds, default start at 2hrs - - unsigned long _buttonEntry; - unsigned long _debugEntry; - AppState _appState; - - eFields fieldStruct[MAXNUMEXTRAFIELDS]; - - - THandlerFunction _firstBootCallback; - //THandlerFunction _wifiConnectedCallback; - //THandlerFunction _wifiDisonnectedCallback; - - - THandlerFunction _noPressCallback; - THandlerFunction _shortPressCallback; - THandlerFunction _longPressCallback; - THandlerFunction _veryLongPressCallback; - - THandlerFunction _firmwareUpdateCheckCallback; - THandlerFunction _firmwareUpdateDownloadCallback; - THandlerFunction _firmwareUpdateErrorCallback; - THandlerFunction _firmwareUpdateSuccessCallback; - - THandlerFunction _configModeCallback; - - - /** - ------ ------ ------ ------ ------ ------ FUNCTION DEFINITIONS ------ ------ ------ ------ ------ ------ - */ - void firstBoot(char ea); - - void readPref(); - void writePref(); - void printPref(); - void processField(); - void httpClientSetup(HTTPClient& http, String url, bool spiffs=false); - - String strWifiScan(); - - void servHdlRoot(AsyncWebServerRequest *request); - void servHdlDevInfo(AsyncWebServerRequest *request); - - #if defined ESP8266 - void servHdlFngPrintSave(AsyncWebServerRequest *request); - #endif - - void servHdlWifiScan(AsyncWebServerRequest *request); - void servHdlWifiSave(AsyncWebServerRequest *request); - - void servHdlAppInfo(AsyncWebServerRequest *request); - void servHdlAppSave(AsyncWebServerRequest *request); - - //void servHdlDevSave(AsyncWebServerRequest *request); - - void hdlReturn(AsyncWebServerRequest *request, String &retHtml, String type = "text/html"); - //int getDevConf(); - - void updateLoop(); - bool isModeButtonPressed(); - ModeButtonState getModeButtonState(); - ModeButtonState buttonLoop(); - - - - - /** - ------ ------ ------ ------ ------ ------ AUXILIARY FUNCTIONS ------ ------ ------ ------ ------ ------ - */ - /* ------ CHANGE CONFIG VALUES */ - template bool SetConfigValue(T &a, T2 &b, bool &changeFlag = _boolDefaulValue) { - if (a != b) { - a = b; - changeFlag = true; - return true; - } else { - return false; - } - } - - bool SetConfigValueCharArray(char* a, String &b, int len, bool changeFlag = &_boolDefaulValue) { - if (b != a) { - b.toCharArray(a, len); - changeFlag = true; - return true; - } else { - return false; - } - } - /* ------ */ - - /* ------ CONVERT BYTE TO STRING */ - String GetCharToDisplayInDebug(char value) { - if (value>=32 && value<=126){ - return String(value); - } else if (value == 0){ - return "."; - } else { - return String("[" + String(value, DEC) + "]"); - } - } - - }; + }; #endif diff --git a/src/ardmkr/boardInfo.cpp b/src/ardmkr/boardInfo.cpp new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/ardmkr/boardInfo.cpp @@ -0,0 +1 @@ + diff --git a/src/ardmkr/boardInfo.h b/src/ardmkr/boardInfo.h new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/ardmkr/boardInfo.h @@ -0,0 +1 @@ + diff --git a/src/esp32/boardInfo.cpp b/src/esp32/boardInfo.cpp new file mode 100644 index 00000000..9c54e858 --- /dev/null +++ b/src/esp32/boardInfo.cpp @@ -0,0 +1,43 @@ +#ifdef ESP32 + #include "boardInfo.h" + + boardInfo::boardInfo(int &bootTimes, char &boardMode){ + _bootTimes = &bootTimes; + _boardMode = &boardMode; + } + + + + void boardInfo::read(){ + Preferences preferences; + + // Open Preferences + preferences.begin("boardInfo", false); + + // Get the boardMode value, if the key does not exist, return a default value of 'N' + (*_boardMode) = preferences.getUInt("boardMode", 'N'); + + // Get the bootTimes value, if the key does not exist, return a default value of 0 + (*_bootTimes) = preferences.getUInt("bootTimes", 0); + + // Close the Preferences + preferences.end(); + } + + + void boardInfo::write(){ + Preferences preferences; + + // Open Preferences + preferences.begin("boardInfo", false); + + // Store the boardMode value + preferences.putUInt("boardMode", (*_boardMode)); + + // Store the bootTimes value + preferences.putUInt("bootTimes", (*_bootTimes)); + + // Close the Preferences + preferences.end(); + } +#endif diff --git a/src/esp32/boardInfo.h b/src/esp32/boardInfo.h new file mode 100644 index 00000000..3ecfd922 --- /dev/null +++ b/src/esp32/boardInfo.h @@ -0,0 +1,22 @@ +#ifdef ESP32 + #ifndef boardInfo_h + #define boardInfo_h + + #include + + + + class boardInfo { + public: + boardInfo(int &bootTimes, char &boardMode); + void read(); + void write(); + + + private: + int* _bootTimes; + char* _boardMode; + + }; + #endif +#endif \ No newline at end of file diff --git a/src/esp8266/boardInfo.cpp b/src/esp8266/boardInfo.cpp new file mode 100644 index 00000000..34f0fefc --- /dev/null +++ b/src/esp8266/boardInfo.cpp @@ -0,0 +1,35 @@ +#ifdef ESP8266 + #include "boardInfo.h" + + boardInfo::boardInfo(int &bootTimes, char &boardMode){ + _bootTimes = &bootTimes; + _boardMode = &boardMode; + } + + + + void boardInfo::read(){ + rtcMemDef rtcMem; + + system_rtc_mem_read(RTCMEMBEGIN, &rtcMem, sizeof(rtcMem)); + if (rtcMem.markerFlag != MAGICBYTE) { + rtcMem.markerFlag = MAGICBYTE; + rtcMem.bootTimes = 0; + rtcMem.boardMode = 'N'; + system_rtc_mem_write(RTCMEMBEGIN, &rtcMem, sizeof(rtcMem)); + } + (*_boardMode) = rtcMem.boardMode; + (*_bootTimes) = rtcMem.bootTimes; + } + + + void boardInfo::write(){ + rtcMemDef rtcMem; + + rtcMem.boardMode = (*_boardMode); + rtcMem.bootTimes = (*_bootTimes); + + rtcMem.markerFlag = MAGICBYTE; + system_rtc_mem_write(RTCMEMBEGIN, &rtcMem, sizeof(rtcMem)); + } +#endif \ No newline at end of file diff --git a/src/esp8266/boardInfo.h b/src/esp8266/boardInfo.h new file mode 100644 index 00000000..b04c09c2 --- /dev/null +++ b/src/esp8266/boardInfo.h @@ -0,0 +1,37 @@ +#ifdef ESP8266 + #ifndef boardInfo_h + #define boardInfo_h + + #define MAGICBYTE 85 + #define RTCMEMBEGIN 68 + + extern "C" { + #include "user_interface.h" // used by the RTC memory read/write functions + } + + + + /** + ------ ------ ------ ------ ------ ------ STRUCTURES ------ ------ ------ ------ ------ ------ + **/ + typedef struct { + uint8_t markerFlag; + int bootTimes; + char boardMode = 'N'; // Normal operation or Configuration mode? + } rtcMemDef __attribute__((aligned(4))); + + + + class boardInfo { + public: + boardInfo(int &bootTimes, char &boardMode); + void read(); + void write(); + + private: + int* _bootTimes; + char* _boardMode; + + }; + #endif +#endif