ESP32 + Blynk - OTA issues

I have a successfully running ESP32 to post temperature values to Blynk. The application needs frequent changes to the posting interval - from 2 minutes to 15 minutes . So just to avoid opening the instrument I wanted to try OTA for firmware upload. That also worked on a separate ESP32. But when I merged both the posting never happens and the OTA webserver also is not firing up but only the serial monitor says that mDNS Server started. ANd this happens always irrespective of whether I press the OTA button or not …

Just reproducing the Setup() and loop() to show my logic. If the user does not press the OTA PB the code posts to Blynk and then sleeps. If OTA button is pressed I want the OTA webserver to come on line. But now neither happens … is this possible at all ?

( Since webserver based OTA code is working I did not post it … its anyway a single function call loginAndUpload() )

void setup()
{
  Serial.begin(9600);
  Serial.println("ESP32 LM35 Read and Post to Blynk.");
  pinMode(OTA_PB, INPUT);
  digitalWrite(OTA_PB, INPUT_PULLUP);              // Enable pull up resistence

  WiFi_Connect();                                  // Attempt to connect to Wi-Fi

  if (WiFi.status() == WL_CONNECTED)               // If we managed to connect to Wi-Fi then try to connect to Blynk, else go to sleep
  {
    Blynk.config(auth, blynk_server, blynk_port);  // Initialise the Blynk connection settings
    Blynk.connect();                               // Attempt to connect to Blynk
  }
  else
  {
    Serial.println ("Wi-Fi connection failed - going to sleep");
    TIME_TO_SLEEP = 30;                           // Reconnect after 30 seconds...
    deepSleepNow();
  }
  if (Blynk.connected())                          // If we manages to connect to Blynk then carry-on as normal, else go to sleep
  {
    Serial.println ("Connected to Blynk");
  }
  else
  {
    Serial.println("Blynk connection failed - going to sleep");
    TIME_TO_SLEEP = 60;                           // Reconnect after 60 seconds...
    deepSleepNow();
  }
  // CONNECTED TO BLYNK SERVER
  Blynk.run();
  readAdcPin();                   // Read the ADC pin and average it ...
  readBattVolt();                 // Read the Batt Volt and average it...
  getDegCValue();
  getBattValue();
  Blynk.virtualWrite(ambientTemp, DegC);
  Blynk.virtualWrite(batteryLevel, battPercent);

  Blynk.run();
  delay(500);

  bool sleepSelect = digitalRead(OTA_PB);  // Check if user wants to update code via OTA
  Serial.println(sleepSelect); 
  if (sleepSelect == LOW ) {
    loginAndUpload();                     // Connect to the user interface page to upload
  }
  else {
    deepSleepNow();
    delay(3000);
  }
}
//#################################

void loop()
{
  // Exceution will reach here only if OTA is required.
  server.handleClient();                  // This is required for the OTA to work !!
  delay(1);
  blinkLED(flashLED, 500, 500);
}

No idea of your background. I’m guessing you have a resistor to GRND so the pin isn’t floating? Did you add some print statements to the virtual lcd or something to see exactly where it’s going wrong?

I have done something similar except with a virtual button to halt the sleep process for 5min in case I forget so it doesn’t run the batteries dead.

Regularly updating the firmware to change the sleep time wouldn’t be my preferred way of handling that issue.

Is your HTTP OTA server configured to use the MAC address of your device? If so, is this set up correctly?

Pete.

My pin connected to the pushbutton is not floating. I have pulled it up so that its always high and pressing the PB pulls it low.

Thanks

Ok I agree that updating firmware is not the best method… maybe I should be using a Simple device server which broadcasts a webpage with a single field and the user changes the same and uploads it back. But for that i need to learn a quite a bit of web coding … JS / JSON ? :wink:

In this case I just wanted to establish the method and use it on other projects later. I am not using the MAC address . Attaching the loginAndUpload() function below which I expect to be called in setup() when the OTA button is pressed
(PS: The code below was copied from a website - honestly i do not recall which as I was searching for one such and landed on this by accident. My bad )

//%%%%%%%%%%%%%%%% WEB INTERFACE CODE %%%%%%%%%%%%%%%%%%%

// LOGIN PAGE

const char* loginIndex =
  "<form name='loginForm'>"
  "<table width='20%' bgcolor='A09F9F' align='center'>"
  "<tr>"
  "<td colspan=2>"
  "<center><font size=4><b>ESP32 Login Page</b></font></center>"
  "<br>"
  "</td>"
  "<br>"
  "<br>"
  "</tr>"
  "<td>Username:</td>"
  "<td><input type='text' size=25 name='userid'><br></td>"
  "</tr>"
  "<br>"
  "<br>"
  "<tr>"
  "<td>Password:</td>"
  "<td><input type='Password' size=25 name='pwd'><br></td>"
  "<br>"
  "<br>"
  "</tr>"
  "<tr>"
  "<td><input type='submit' onclick='check(this.form)' value='Login'></td>"
  "</tr>"
  "</table>"
  "</form>"
  "<script>"
  "function check(form)"
  "{"
  "if(form.userid.value=='admin' && form.pwd.value=='admin')"
  "{"
  "window.open('/serverIndex')"
  "}"
  "else"
  "{"
  " alert('Error Password or Username')/*displays error message*/"
  "}"
  "}"
  "</script>";

//*******************************************************

//Server Index Page

const char* serverIndex =
  "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
  "<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
  "<input type='file' name='update'>"
  "<input type='submit' value='Update'>"
  "</form>"
  "<div id='prg'>progress: 0%</div>"
  "<script>"
  "$('form').submit(function(e){"
  "e.preventDefault();"
  "var form = $('#upload_form')[0];"
  "var data = new FormData(form);"
  " $.ajax({"
  "url: '/update',"
  "type: 'POST',"
  "data: data,"
  "contentType: false,"
  "processData:false,"
  "xhr: function() {"
  "var xhr = new window.XMLHttpRequest();"
  "xhr.upload.addEventListener('progress', function(evt) {"
  "if (evt.lengthComputable) {"
  "var per = evt.loaded / evt.total;"
  "$('#prg').html('progress: ' + Math.round(per*100) + '%');"
  "}"
  "}, false);"
  "return xhr;"
  "},"
  "success:function(d, s) {"
  "console.log('success!')"
  "},"
  "error: function (a, b, c) {"
  "}"
  "});"
  "});"
  "</script>";
//******************************************

void loginAndUpload () {

  //Use mdns for host name resolution
  if (!MDNS.begin(host)) {                                 //http://esp32.local
    Serial.println("Error setting up MDNS responder!");
    while (1) {
      delay(1000);
    }
  }
  Serial.println("mDNS responder started");

  server.on("/", HTTP_GET, []() {                          //return index page which is stored in serverIndex
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", loginIndex);
  });

  server.on("/serverIndex", HTTP_GET, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", serverIndex);
  });

  server.on("/update", HTTP_POST, []() {                    //handling uploading firmware file
    server.sendHeader("Connection", "close");
    server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
    ESP.restart();
  }, []() {
    HTTPUpload& upload = server.upload();
    if (upload.status == UPLOAD_FILE_START) {
      Serial.printf("Update: %s\n", upload.filename.c_str());
      if (!Update.begin(UPDATE_SIZE_UNKNOWN)) {              //start with max available size
        Update.printError(Serial);
      }
    } else if (upload.status == UPLOAD_FILE_WRITE) {
      // flashing firmware to ESP
      if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
        Update.printError(Serial);
      }
    } else if (upload.status == UPLOAD_FILE_END) {
      if (Update.end(true)) {                                  //true to set the size to the current progress
        Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
      } else {
        Update.printError(Serial);
      }
    }
  });
  server.begin();
}

Your device is connecting to Blynk anyway, so why not use a widget (numeric input, slider or multi-function switch) to either allow the user to change the sleep time?
When your device connects to Blynk you’d need to retrieve the value using a Blynk.syncVirtual(vPin) and store the value in a global variable then use this as the basis of your next deep sleep time.
It would make sense to declare a default value for this deep sleep time, so that a failure to connect to the Blynk server doesn’t result result in a zero deep sleep time.

Pete.

Wow … never thought of the widget method. Sure it appears to be a simple and elegant solution.

Thanks a lot. Shall check it out and revert in case of any issue !

:+1:

1 Like

I created a Slider widget to send the Sleep Time in minutes. Using the below code …

    BLYNK_WRITE(V2)
{
  int TIME_TO_SLEEP = param.asInt();             // assigning incoming value from pin V1 to a variable and use it for sleeping duration..
}

But my system has only a setup() function and so where do invoke this function ? If i am able to do that I can save the value to EEPROM and read from it the next time i wake up.

Kindly advise

The BLYNK_WRITE(vPin) function is really a callback that is triggered automatically every time the value of the vPin changes on the server.

There are three things that you need to do next…

First …

Remove the “int” from the beginning of this line, as it makes the value that comes from the slider local to the BLYNK_WRITE function, but you’ll need it to be global so that it’s available outside of the callback.

Second…
Multiply the TIME_TO_SLEEP value by 10,000 (assuming that the value you are setting in the slider is the sleep time in seconds

Third…
Force the BLYNK_WRITE(V2) callback to trigger when your device wakes-up and has connected to Blynk.
You can do this by adding:

Blynk.syncVirtual(V2);

to your void setup after the connection to Blynk.

Pete.

Got it ! Works great and its so easy to change the Sleep Time ! :+1: :slight_smile:

1 Like