HTML form interface and Arduino exceptions

Hi Forum Folks,
I need help to understand what’s wrong with this Arduino/HTML page interface and how it might be fixed?

Using an ESP8266. The code defines a webpage to serve up. The page defines a form with a checkbox to enable a future timer and some start and stop times. When the webpage is filled out with the checkbox checked off, the code runs fine. Even if no inputs values are entered in the other variables, the code still runs.
However, IF the checkbox is NOT checked, the code takes an exception. I understand when the checkbox is checked the value I defined in the html form code is passed thru the URL, I further understand when the box is left unchecked no value at all is passed. Using the Exception Decoder tool it looks like something doesn’t like the empty string, but I’m not sure how to get around that.

The other variables, such as the ‘test_variable’ text, can be empty and no exception is taken so I’m not sure why the checkbox method is so different.

This is the ESP8266 code and not the HTML. Commenting out the “S_TIMER_ON_OFF = request->getParam(PARAM_TIMER_ON_OFF)->value();” line stops the exception.


#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Strings.h>


//Version of this program
#define VERSION "V0.1"


//Server setup
AsyncWebServer server(80);

// Wifi Setup
const char* ssid = "********";       //enter YOUR Network
const char* password = "*********";   //enter YOUR password

//Parameters
const char* PARAM_TIMER_ON_OFF = "timer_enable";

const char* PARAM_START_TIME = "start_time";
const char* PARAM_STOP_TIME = "stop_time";
const char* PARAM_TEST_VARIABLE = "test_variable";

String S_TIMER_ON_OFF;
  
String S_Start_Time;
String S_Stop_Time;
String S_Test_Variable;



//###############WEB PAGE DEFINITION  ################################################################

const char index_html[] PROGMEM = R"rawliteral(

<!DOCTYPE HTML><html><head>
 <h1>Kurt's Mitsubishi AC Controller</h1>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
  <form action="/action_page">
 

  <fieldset>
  <legend> Timer </legend>
  <label for="timer_enable"> Timer Enable</label>
  <input type="checkbox" id="timer_enable" name="timer_enable" value="on">
  <br><br><br>
  <label for="start_time">Start Time:</label><br>
  <input type="time" step="60" id="start_time" name="start_time">
  <small> Include AM or PM </small><br>
   <label for="stop_time">Stop Time:</label><br>
  <input type="time" id="stop_time" name="stop_time"><br>
   <small> Time will be rounded to the nearest 10 minutes, the resolution of the AC </small><br><br>
   <label for="test_variable">Test Variable:</label><br>
   <input type="text" id="test_variable" name="test_variable">
  <small> enter "on" or "off"  </small><br>
  </fieldset>

  <fieldset>
  <legend>Reset or Submit</legend>
  <input type="reset" value="Reset">
  <input type="submit" value="Submit">
  </fieldset>
  </form>
</body></html>)rawliteral";

//###############END  WEB PAGE DEFINITION  ################################################################




//===============================================================
// This routine is executed when you open its IP in a browser
//===============================================================
void handleRoot() {

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html);
  });

}
//===============================================================
// This routine is executed when you press submit
//===============================================================
void handleForm() {
  
  server.on("/action_page", HTTP_GET, [] (AsyncWebServerRequest *request) {
      Serial.println("ENTER Handler");
     
     
      //get the webpages parameter values
      S_TIMER_ON_OFF = request->getParam(PARAM_TIMER_ON_OFF)->value();
       
      S_Start_Time = request->getParam(PARAM_START_TIME)->value();
      S_Stop_Time= request->getParam(PARAM_STOP_TIME)->value();     
      S_Test_Variable= request->getParam(PARAM_TEST_VARIABLE)->value();

       
      //print out some values on the monitor to double check we are indeed receiving them
     
      Serial.print("timer enable:"); Serial.println(S_TIMER_ON_OFF);

      Serial.print("start time:"); Serial.println(S_Start_Time);
      Serial.print("stop time:"); Serial.println(S_Stop_Time);
      Serial.print("test variable:"); Serial.println(S_Test_Variable);
      
      request->send(200, "text/plain", "message received");
  }
   
  );
        
}


void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

void setup() {

  
  
  Serial.begin(9600);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WiFi Failed!");
    return;
  }
  Serial.println();
  Serial.print("This device IP Address is: ");
  Serial.println(WiFi.localIP());
  
//Greetings-------------------------------------------------------------------------------------------------------------
  Serial.print("\n\n");
  Serial.print("\n Mit AC controller ");  Serial.print(VERSION); Serial.print("\n");

  handleRoot();
  handleForm();
  server.begin();
  Serial.println("HTTP server started");
  
}


void loop() {

//nothing here yet...everything is in the handleForm() function.
    
}
  
Serial Monitor output and Exception

5:13:47.017 -> 
15:13:47.017 -> This device IP Address is: 192.168.1.134
15:13:47.052 -> 
15:13:47.052 -> 
15:13:47.052 -> 
15:13:47.052 ->  Mit AC controller V0.1
15:13:47.086 -> HTTP server started
15:15:03.274 -> ENTER Handler
15:15:03.309 -> timer enable:on
15:15:03.309 -> start time:
15:15:03.345 -> stop time:
15:15:03.345 -> test variable:ON
15:15:14.468 -> ENTER Handler
15:15:14.468 -> timer enable:on
15:15:14.502 -> start time:
15:15:14.502 -> stop time:
15:15:14.540 -> test variable:OFF
15:15:20.979 -> ENTER Handler
15:15:20.979 -> timer enable:on
15:15:21.013 -> start time:
15:15:21.013 -> stop time:
15:15:21.047 -> test variable:
15:15:40.120 -> ENTER Handler
15:15:40.120 -> timer enable:on
15:15:40.153 -> start time:21:10
15:15:40.153 -> stop time:
15:15:40.188 -> test variable:
15:15:48.476 -> ENTER Handler
15:15:48.510 -> 
15:15:48.510 -> --------------- CUT HERE FOR EXCEPTION DECODER ---------------
15:15:48.545 -> 
15:15:48.580 -> Exception (28):
15:15:48.580 -> epc1=0x4020c690 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000014 depc=0x00000000
15:15:48.685 -> 
15:15:48.685 -> >>>stack>>>
15:15:48.685 -> 
15:15:48.685 -> ctx: sys
15:15:48.685 -> sp: 3fffeb50 end: 3fffffb0 offset: 0190
15:15:48.753 -> 3fffece0:  3fff0750 3fffed00 3ffe8728 3ffe86d6  
15:15:48.787 -> 3fffecf0:  3fff0750 3fff0efc 3ffeec34 4020113d  
15:15:48.855 -> 3fffed00:  3fff15bc 000c000f 00ffed30 4020970d  
15:15:48.889 -> 3fffed10:  00000003 3fffed30 3fff0768 4020972c  
15:15:48.959 -> 3fffed20:  3fff0f40 00000003 3fffed50 3ffe86d6  
15:15:48.992 -> 3fffed30:  3fff0750 40201090 3fff073c 40208618  
15:15:49.061 -> 3fffed40:  3fff1500 00000000 3fff0efc 40206310  
15:15:49.095 -> 3fffed50:  00594e00 80000090 80ff0f30 402098a7....................................................................  




Sadly, no one provided a solution but I eventually discovered the trick. In case someone's search lands them here, this is what works:

Bracket the value assignment with a test for the existence of the parameter. An unchecked check box has no parameter in the URL at all. That is the standard html form way of doing things. Contrast that with the text based parameters, they still have parameters listed but with values of an empty string. The lack of the parameter apparently is the cause of the exception. There is a method called 'hasParam' that helps test for a parameter existence.

To the example code I replaced the assignment statement with the following:


     S_TIMER_ON_OFF = "OFF";    //add this default value assignment for an unchecked box
                                //IF the checkbox is checked, its value will replace this
      //check if the checkbox parameter is there at all before trying to assign the value
     if (request->hasParam(PARAM_TIMER_ON_OFF)) {      
      S_TIMER_ON_OFF = request->getParam(PARAM_TIMER_ON_OFF)->value();
     }

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.