sblantipodi / arduino_bootstrapper

Utility classes for bootstrapping Arduino projects with Wifi management, OTA upload management, memory management, MQTT and queue management. (ESP8266/ESP32 ready)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Web server for OTA configuration

Pronoe opened this issue · comments

Hello,
When the Web server has been activated once, it is never possible to activate it again for any modification, excepted by flashing again the device.
Then, on my local version of bootstrapper library, I have added a boolean parameter "forceWebServer" that force the OTA configuration when set.
I use this feature to activate OTA configuration when the device is switched ON/OFF twice quickly.
I use a json file to store power ON information that allows specific ON/OFF sequence detection.
If you feel this could be useful for a future version of your library, I can provide additional information on the code.
Also, it would be useful to add the gateway IP in the config.json file.
I was not able at the beginning to set a static IP address for the controller device because the gateway IP was not set correctly.
Regards.
Patrick

Hi Pronoe,
sure it could be useful..
Can you show me your code?

Thank you very much!

Hi Davide,
I have used a very basic method, surely not very elegant but it works.
Fisrt I have added at the end of BootstrapManager.h the following variable declaration:
boolean forceWebServer; // if true, forces the use of launchWebServerForOTAConfig
Then in the void BootstrapManager::bootstrapSetup code inside BootstarpManager.cpp, I have changed
if (isWifiConfigured()) into if (isWifiConfigured() && !forceWebServer) (line 33 in the original file).

My user code is for example the following:

  const uint32_t shortPowerOn = 10; // threshold in s for identification of short power On

  // Datastore management
  // try to read a datastore file
  if (readDS(true) != NO_ERROR)
  {
    // file does not exists or integrity error
    // Then init datastore information
    devicePowerUp = 1;
    currentDeviceActivity = max(millis() / 1000, 1UL);
    deviceActivity_1 = 0;
    deviceActivity_2 = 0;
    cumulativeDeviceActivity =  millis() / 1000;
    cumulativeDeviceActivityAtPowerOn = 0;
    saveDS(); // save datastore (use readSPIFFS & data integrity checking with hash code)
  }
  else
  {
    // detection of double short power ON sequence
    bootstrapManager.forceWebServer = ((deviceActivity_1 < shortPowerOn) && (deviceActivity_1 > 0) && (deviceActivity_2 < shortPowerOn) && (deviceActivity_2 > 0));
    // note: deviceActivity_1 and deviceActivity_2 are the power ON duration of the 2 previous sequences
    // update power on information
    if (bootstrapManager.forceWebServer)
    {
      currentDeviceActivity = 120; // takes into account the webserver activity because as the ESP will be restarted, DS will not be updated - typical duration 120 s
    }
    else
    {
      currentDeviceActivity = max(millis() / 1000, 1UL);  // takes into account current elapsed time
    }
    cumulativeDeviceActivityAtPowerOn = cumulativeDeviceActivity;
    cumulativeDeviceActivity +=  currentDeviceActivity;
    // save immediatly datastore for the case of a short power ON
    saveDS(); // save datastore (use writeToSPIFFS)
  }

  // bootstrap manager setup
  bootstrapManager.bootstrapSetup(manageDisconnections, manageHardwareButton, callback);

A better method would be to add an optional parameter forceWebServer in the function bootstrapSetup , with false as default value.
Alternatively, you could add a function setWebServerOption to configure the variable forceWebServer or a function eraseSetupFile that could be called before bootstrapSetup.

For information, my code for saveDS and readDS

void saveDS()
// save current context in datastore file
{
  DynamicJsonDocument DSdoc(1024);
  DSdoc["header"] = "Header";
  DSdoc["cumulativeDeviceActivity"] = String(cumulativeDeviceActivity);
  DSdoc["lastDeviceActivity_1"] = String(currentDeviceActivity);
  DSdoc["lastDeviceActivity_2"] = String(deviceActivity_1);
  DSdoc["devicePowerUp"] = String(devicePowerUp);
  DSdoc["lastEvent"] = lastPumpControlerEvent;
  // computes and stores hash code for data integrity monitoring
  DSdoc["HC"] = "null";  // hash code is calculated on the data including the CS, then this one must be set to a fix value before
  String hashDS = hashPayload(DSdoc);// computes the hash code
  DSdoc["HC"] = String(hashDS);
  // save the file
  bootstrapManager.writeToSPIFFS(DSdoc, "DS.json");
}```
```CPP
boolean readDS(boolean initValue)
// try to read datastore file and return true if successfull
{
  enum fileErrorCode fileError = NO_ERROR;
  // retrieve DS file informations
  DynamicJsonDocument DSdoc = bootstrapManager.readSPIFFS("DS.json");
  const char* header = DSdoc["header"];
  if (header)
  {
    // file already exists and contains a header, then retrieve number of power up and cumulative up time
    if (initValue)
    {
      // init global parameter when readDS at power ON
      Serial.println("---- Init time parameters from DS file ----");
      cumulativeDeviceActivity = helper.getValue(DSdoc["cumulativeDeviceActivity"]).toInt() + millis() / 1000;
      deviceActivity_1 = helper.getValue(DSdoc["lastDeviceActivity_1"]).toInt();
      deviceActivity_2 = helper.getValue(DSdoc["lastDeviceActivity_2"]).toInt();
      devicePowerUp = 1 + helper.getValue(DSdoc["devicePowerUp"]).toInt();
      lastSavedEvent = "Last saved event : " + helper.getValue(DSdoc["lastEvent"]);
    }
    // check data integrity
    String readHashDS = helper.getValue(DSdoc["HC"]);
    Serial.println("Read hash code: " + readHashDS);
    DSdoc["HC"] = "null";  // hash code is calculated on the data including the CS, then this one must be set to a fix value before
    String hashDS = hashPayload(DSdoc);// computes the hash code 
    if (hashDS == readHashDS)
    {
      Serial.println("file hash code OK");
    }
    else
    {
      lastPumpControlerEvent = "Integrity error in data store";
      Serial.println(lastPumpControlerEvent);
      fileError = INTEGRITY_ERROR;
    }
  }
  else
  {
    // files does not exist or does not contain a header
    fileError = OPENING_ERROR;
    lastPumpControlerEvent = "DS file opening error";
    Serial.println(lastPumpControlerEvent);

  }
  return fileError;
}

These are preliminary versions. Later on I will add information on pump running time and use duplicated DS file storage to prevent total loss of information in the case of power supply lost during file writing and then corruption of the file.

Thank you for the reply,
Arduino Bootstrapper is a generic lib and can't have the "logic on a pump" inside it but I'll get the idea to implement the possibility to change the wifi settings.
I have so many things to do, it will take some time but I'll do it. :)

Thank you.

Hi Davide,
Thank you for your reply.
Actually, I imagine that the connected things that can be developed with the help of your generic library, might be given later on to people having no software skill nor any software tools (my parents, my friends, the future buyer of my house, ...).
Then I think that these smart things should be reconfigurable easily through their interfaces if any (keyboard, touch screen) or through a web server as it is the case for example with smart lamps or weather stations.
This OTA function does exist in your library and this is very appreciable but it is activated only after the initial flashing.
Then I think that a mechanism that would allow to activate it on demand would be a good enhancement.
Of course, the code that would set this activation (with double short power ON, push buttons, ...) should be in the user application and not the library.
If you agree, I could commit a new version with this feature (something more elegant than my current local version).
I just need some training with the use of Github as I don't have yet much experience.

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days

pending pull request