ESP32 Server request issue

Hi

I have a ESP32 runing a webserver and access point on demand.
When i try to send data from the webpage to server, every thing is working fine if it's a number i send, but if i try to send data with string values, the esp32 is rebooting.

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

  server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
    uint8_t inputMessage1;
    String inputMessage2;
    uint8_t inputMessage3;
    uint8_t inputMessage4;
    uint8_t inputMessage5;
    uint8_t inputMessage6;
    uint8_t inputMessage7;
    

    if (request->hasParam(PARAM_INPUT_1) && request->hasParam(PARAM_INPUT_2)) {
      inputMessage1 = request->getParam(PARAM_INPUT_1)->value().toInt();
      inputMessage2 = request->getParam(PARAM_INPUT_2)->value();
      inputMessage3 = request->getParam(PARAM_INPUT_3)->value().toInt();
      inputMessage4 = request->getParam(PARAM_INPUT_4)->value().toInt();
      inputMessage5 = request->getParam(PARAM_INPUT_5)->value().toInt();
      inputMessage6 = request->getParam(PARAM_INPUT_6)->value().toInt();
      inputMessage7 = request->getParam(PARAM_INPUT_7)->value().toInt();

i update via this code.

<script>
function saveMidi(){
	toggleCheckbox(document.getElementById('mac1').value,document.getElementById('mac2').value,document.getElementById('mac3').value,document.getElementById('mac4').value,document.getElementById('mac5').value,document.getElementById('mac6').value,document.getElementById('pack').value);
  
}


function toggleCheckbox(mac1, mac2, mac3, mac4, mac5, mac6, beltpack){
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/update?mac1="+mac1+"&mac2="+mac2+"&mac3="+mac3+"&mac4="+mac4+"&mac5="+mac5+"&mac6="+mac6+"&beltpack="+beltpack, true);
  xhr.send();
}
</script>

It all works if i change this inputMessage2 = request->getParam(PARAM_INPUT_2)->value(); tol inputMessage2 = request->getParam(PARAM_INPUT_2)->value().toInt;

Thanks
Finn

you check for the presence of PARAM_INPUT_1 and PARAM_INPUT_2 and try to read other parameters like PARAM_INPUT_3 (and 4, 5, 6, 7) and apply to these a function calls (->value()) without knowing if the getParam() function returned an valid pointer or nullptr

if you don't check for the presence of the parameters, you would need to do something like

AsyncWebParameter * param3 = request->getParam(PARAM_INPUT_3);
if (param3 != nullptr) {
  inputMessage3 = param3->value().toInt();
} else {
  inputMessage3 = 0; // or whatever default value you want to have
}

You have to show more code.
I guess you have something like: const char* PARAM_INPUT_1 = "mac1"; somewhere.

If you include strings in the querystring:
xhr.open("GET", "/updatemac1="+mac1+"&mac2="+mac2+... ); you have to ensure these contain no spaces or other illegal characters. Otherwise, wrap the whole thing into a JSON string.

I would love to show more code.
I'm trying to pass a mac address, so only 2 char.
The truth, is that i could'nt get a json string to work.
I have seen a lot of post on the interweb, many are using the same solution.

<!DOCTYPE html>
<html>
<style>
table, th, td {
  border: 0;
  border-collapse: collapse;
}
</style>
<head>
<style>
tr.selected {
  background-color: yellow;
}
table, td {
  border: 1px solid black;
  }
.input {width: 60px;
}
</style>
</head>
<body>
<table align="center" width="400px" >
  <tr>
    <th colspan="8" >MAC address</th>     
  </tr>
  <tr>
  <td></td>
  <td><input class="input" type="tekst" id="mac1" align="center" value=%MAC1%></td>
  <td><input class="input" type="tekst" id="mac2" align="center" value=%MAC2%></td>
  <td><input class="input" type="tekst" id="mac3" align="center" value=%MAC3%></td>
  <td><input class="input" type="tekst" id="mac4" align="center" value=%MAC4%></td>
  <td><input class="input" type="tekst" id="mac5" align="center" value=%MAC5%></td>
  <td><input class="input" type="tekst" id="mac6" align="center" value=%MAC6%></td>
  <td></td>
  
  </tr>
</table>  
<table align="center" width="400px">
    
  <tr>
    <td><input type="hidden" id="switch" name="switch" value="4"></td>
    <td>Select a number for this beltpack</td>  
    <td ><input class="input" type="number" id="pack" min="1" max="3" value=%PACK%></td>     
    <td ></td>
    <td></td>  
    <td></td>
  </tr>
  <tr></tr>
  <tr >
    	<td colspan="7" align="center"><button onclick="saveMidi()"> Save Settings </button>
    </td>
  </tr>
</table>

Maybe this example helps: ESP32 ESPAsyncWebServer sample demonstration application . The example uses character strings.

Depending on where you got ESPAsyncWebServer, you may have to fix one compiler error by making one variable a const . I'll attempt to fix that sometime.

Here is my webserver setup.

I will take a close look at your exsample.

void configServer(){
   
  WiFi.softAP(ssid, password);
  delay(500);
  WiFi.softAPConfig(IP, gateway, subnet);
  IPAddress IP = WiFi.softAPIP();

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

  server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
    uint8_t inputMessage1;
    String inputMessage2;
    uint8_t inputMessage3;
    uint8_t inputMessage4;
    uint8_t inputMessage5;
    uint8_t inputMessage6;
    uint8_t inputMessage7;
    // GET input1 value on <ESP_IP>/update?output=<inputMessage1>&state=<inputMessage2>
    if (request->hasParam(PARAM_INPUT_1) && request->hasParam(PARAM_INPUT_2)) {
      inputMessage1 = request->getParam(PARAM_INPUT_1)->value().toInt();
      inputMessage2 = request->getParam(PARAM_INPUT_2)->value();
      inputMessage3 = request->getParam(PARAM_INPUT_3)->value().toInt();
      inputMessage4 = request->getParam(PARAM_INPUT_4)->value().toInt();
      inputMessage5 = request->getParam(PARAM_INPUT_5)->value().toInt();
      inputMessage6 = request->getParam(PARAM_INPUT_6)->value().toInt();
      inputMessage7 = request->getParam(PARAM_INPUT_7)->value().toInt();
      
      Serial.println(inputMessage1);
      Serial.println(inputMessage2);
      Serial.println(inputMessage3);
      Serial.println(inputMessage4);
      Serial.println(inputMessage5);
      Serial.println(inputMessage6);
      Serial0.println(inputMessage7);
          
          //macAddress[0] = inputMessage1;
          //macAddress[1] = inputMessage2;
          //macAddress[2] = inputMessage3;
          //macAddress[3] = inputMessage4;
          //macAddress[4] = inputMessage5;
          //macAddress[5] = inputMessage6;
          //packNo = inputMessage7; 
          //Serial.println(packNo);
          //midiPrefs.begin("MIDIPrefs", RW_MODE);           
 
          //midiPrefs.putBytes("macAddress", (byte*)(macAddress), sizeof(macAddress));
          //midiPrefs.putBytes("pack", (byte*)(packNo), sizeof(packNo));     

         //midiPrefs.putBytes("sw1Ch", (byte*)(switch1Ch), sizeof(switch1Ch)); 
        
    }
    else {
      //inputMessage1 = "No message sent";
      //inputMessage2 = "No message sent";
    }
    
    request->send(200, "text/plain", "OK");
  });

  // Start server
  server.begin();
}

I still don't see where or how, for example, PARAM_INPUT_1 is defined. However, it must be defined otherwise you'll get a compiler error.
From this name, I'm guessing your code is based on the Rui Santos model say at ESP32 Async Web Server – Control Outputs | Random Nerd Tutorials or some similar code. That model does not really scale up very well if you have a lot of HTML fields which you want to transfer back to the web server and then it's probably better to use the approach of using an HTML form and submitting it.

The way you appear to be transferring data with an explicit HTTP GET it probably doesn't matter but I don't believe such fields as below will be visible to the web server because there is no name attribute.
<td><input class="input" type="tekst" id="mac1" align="center" value=%MAC1%></td>

I just tried your Async Web server, and that worked after i changed AsyncWebParameter* p = request->getParam(i); to const AsyncWebParameter* p = request->getParam(i);
And your example is doing, what i want.
I use a string processor to set values.
My script works fine when i'm only working with Int. but when i try to change it to run with String, it fails.

The base for my webserver is indeed from is from Rui Santos, but it's not from the script you link to, but that scriot seems to have error handling i could use. :slight_smile:
I'm a big fan of Random Nerds.

String processor(const String& var){
  static char buf[3];

  if(var == "MAC1"){
    snprintf(buf, sizeof buf, "%02X", macAddress[0]);
    return buf;
  }
  else if(var == "MAC2"){
    snprintf(buf, sizeof buf, "%02X", macAddress[1]);
    return buf;
  } 
  else if(var == "MAC3"){
    snprintf(buf, sizeof buf, "%02X", macAddress[2]);
    return buf;
  }  
  else if(var == "MAC4"){
    snprintf(buf, sizeof buf, "%02X", macAddress[3]);
    return buf;
  }
  else if(var == "MAC5"){
    snprintf(buf, sizeof buf, "%02X", macAddress[4]);
    return buf;
  }
  else if(var == "MAC6"){
    snprintf(buf, sizeof buf, "%02X", macAddress[5]);
    return buf;
  }
  else if(var == "PACK"){
    String(packNo);
  }
  return String();
}

So everything is working now, i had my naming screwed up, pack should be beltpack.

Thanks for all your time.

OK. Good that you have found the cause.

But still interesting that it worked previously with just the following modification:

Just one of those mysteries I guess.

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