html POST requests slow to update LED Array? Short cuts?

Hi,

My question is basically "am I converting a string of text from an html post request in a stupid way that is causing sluggish performance.

I have a working project, in which I can click on a series of checkboxes on a webpage (hosted on a Node MCU). When clicked these send POST requests to the server, which are processed and used to update an array which uses the HT16k33 library here:

https://github.com/lpaseen/ht16k33

to update an LED Matrix and light the LEDs matching the checkboxes currently checked.

I’ve got it all connected up, and it is essentially working as I want it to - the only issue is that the response time is pretty sluggish, which can result in queues of post requests and what you might call “poor user experience”.

I’m pretty sure that’s because my code is a bit hacky.

I suspect the issue is around the format that the POST requests are coming in and the amount of effort it is taking to parse those messages, I was hoping someone with a bit more expertise might be able to cast a glance and confirm that this is the area in which I am doing things wrong/if there’s a much simpler solution?

Currently they arrive in a string in the format:

“ledArray%5B%5D=1&ledArray%5B%5D=0&ledArray%5B%5D=0&ledArray%5B%5D=0”

the above represents four LEDs and there are 128. As you can see in the updateArray function in my code below there are four steps in converting that to the array the library expects.

Is that likely to be the bottleneck?

if so I will try to get Javascript to deliver it in a format that reduces the amount of conversion required, unless there’s a simpler way to get the data from the above into the array I need?

thanks in advance for any suggestions

#include <ht16k33.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <SPI.h>



/* WIFI DETAILS HERE..........................................*/

ESP8266WebServer server;
char* ssid = "EE-Hub-Z9Sc";
char* password = "ELM-remit-ever";

/* HTML DOC saved to Flash...................................................*/

char webpage[] PROGMEM = R"=====(
<!DOCTYPE html>
<html lang="en-gb">

<head>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    <style>
        body {
            display: grid;
            align-content: center;
            justify-content: center;
        }
        
        #container {
            display: grid;
            grid-template-columns: repeat(8, auto);
            grid-template-rows: repeat(12, auto);
            height: 95vh;
            width: 95vw;
            align-items: stretch;
            justify-items: stretch;
            row-gap: 15px;
            column-gap: 15px;
            grid-auto-flow: column;
        }
        
        #container label {
            background: #21618C;
            border-radius: 3000px;
            width: 100%;
            height: 100%;
            display: block;
        }
        
        input[type="checkbox"] {
            display: none;
        }
        
        #container input[type="checkbox"]:checked~label {
            background: red;
        }
    </style>

    <title>Twig's LED Climbing Wall</title>
</head>


<body>

    <div id="container" class="controls">
        <!-- 96 buttons IDs to match array positions numbered by LED grid -->
        <script>
            //define initial LED array

            let ledArray = [];
            ledArray.length = 128;
            ledArray.fill(0, 0, 128); // use the fill method to avoid needing longhand assignment of lots of zeroes
            console.log(ledArray);

            const $controls = document.getElementsByClassName("controls")[0];

            $controls.addEventListener("click", e => {
                // event handler on body - need to check if the orginal target of the
                // bubbled event has a value, i.e. is a checkbox
                const val = e.target.value;
                if (val) {
                    // this line gets all the checked values in one lump
                    //const $checked = document.querySelectorAll("input:checked");
                    // original code only mutates one item at a time which is cleaner
                    // so...
                    console.log(e.target, e.target.value, e.target.checked);
                    let arrayIndex = parseInt(e.target.value, 10);
                    ledArray[arrayIndex] = e.target.checked ? 1 : 0;
                    // ternary short-hand assignment
                     $.ajax({
                              type: "POST",
                              url: "/array",
                              data: {ledArray},
                             
            });
                    console.log(ledArray);

                }
            });

            // build the buttons
            const numElements = 96;
            const bodyEl = document.querySelector('body')

            for (let i = 0; i < numElements; i++) {
                const identifier = i
                const item = document.createElement('div')
                item.class = "buttondiv"

                const labelEl = document.createElement('label')
                labelEl.htmlFor = identifier;

                const checkBox = document.createElement('input')
                checkBox.type = 'checkbox'
                checkBox.id = identifier
                checkBox.value = identifier

                item.appendChild(checkBox);
                item.appendChild(labelEl);

                const container = document.getElementById('container')
                container.appendChild(item)
            }
        </script>
    </div>
</body>

</html>
)=====";

/* sET UP WIFI CONNECTION AND PRINT IP ADDRESS................*/

//define the LED driver and use library

HT16K33 HT;

//define the start state of the array to control the LEDS

uint8_t ledArray [] = 
{1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,
 1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,
 1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
 1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,
 1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,
 1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
 1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,
 1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0};

void updateArray ()
{
      String newArrayState =  server.arg("plain");
    
      int skip = 1;
      newArrayState.remove(0,15);
      for (int counter=0; counter<127; counter++){
      newArrayState.remove(skip,15);
      skip+=2;}
      //remove html bumph
      
      
      int newArrayLength = newArrayState.length()+1;
      char newCharArray[newArrayLength];
      newArrayState.toCharArray(newCharArray,newArrayLength);
      server.send(200, "text/plain", newCharArray);
      //change String to char array
      
      int intArray[128];
      int ipos = 0;
      char *tok = strtok(newCharArray, "=");
      while (tok) {
        if (ipos <128) {
          intArray[ipos++] = atoi(tok);
        }
        tok = strtok(NULL, "=");
      }
      //converting char array to in array
      
      int i;
      for (i=0; i<128; i++)
  {
  ledArray[i] = intArray[i];
  }
    // copy new int array into ledArray to control LEDs
  
       for(int i = 0; i < 128; i++)
{
  Serial.println(ledArray[i]);
}
    
      Serial.println(newArrayState);
      }

void handleNotFound(){
  server.send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request
}
void setup()
{


  WiFi.begin(ssid,password);
  Serial.begin(115200);
  while(WiFi.status()!=WL_CONNECTED)
  {
    Serial.print(".");
    delay(500);
  }
  Serial.println("");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  server.on("/",[](){server.send_P(200,"text/html", webpage);});
  server.on("/array",HTTP_POST, updateArray); 
  
            
  
  server.begin();
  
  HT.begin(0x00);
  //START UP ANIMATION GOES HERE

}

void loop()
{

//read the LED array 
  uint8_t led;
  for (led=0; led<128; led++) 
  {
  if (ledArray[led] > 0)
   { HT.setLedNow(led);}
   else {HT.clearLedNow(led);}}
  

//Handle html requests   
  server.handleClient();
  
}

what’s this supposed to do?

  int skip = 1;
  newArrayState.remove(0, 15);
  for (int counter = 0; counter < 127; counter++) {
    newArrayState.remove(skip, 15);
    skip += 2;
  }
  //remove html bumph

seems very weird

that's the bit I most thought must be able to get rid of -
it removes chunks of the string delivered from the POST request (eg: "&ledArray%5B%5D=") leaving only the states of the checkboxes (1 or 0)

The first chunk is one shorter, hence it not being in the loop (I'm sure there's a neater way to do that too)

I think perhaps I'm just sending the information from Javascript in the wrong format in the first place.

Check what’s in newArray after doing that weird stuff....

thanks for taking a look -

newArrayState is then a string of 128 1s and 0s with = signs between them as delimiters.

eg "1=0=1=0"

then the next block uses strtok and atoi to change that into an int array [1,0,1,0]

and then that gets copied to ledArray.

i'm going to try to get the javascript send the string as "1,0,1,0" in plain text, so I can drop that first loop at least.

If, on every check box change, you just send the value for that single checkbox and associated LED in a format of your choice (like: LED14:0), and then update that single value in the array, wouldn’t that speed things up and make your code simpler?

that is a very good point, I have no idea why I didn't do it that way already!
Just got fixated on the other way I guess,

thank you for the suggestion, that makes a lot of sense.