Web socket with fast throughput. a touch of a rabbit-hole.

hi all,

For a week I have been stuck inside a rabbit hole for a project of mine. Where would like to wirelessly send an int array with the size of 7 slots between two esp32.
There are many ways, to do this, this is what I have used:
I have used espNOW it was reliably but the code big and not really what I wanted.

Then i stumbled across Web sockets. Here is where I thought the rabbit hole would end…

Web sockets for how I used it really reliable and almost real-time for most of the time.
I’m totally new to this and not really knowing what I’m doing a little help is appreciated.

senders code:

#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketsServer.h>
#include <ArduinoJson.h>
#include <Ticker.h>

//audio stuff. now filled with random values
int FreqVal[7];
int spectrumValue[7];
double mult = 1.00;



// Initialize network parameters
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

// Instantiate server objects
WebServer server;
WebSocketsServer webSocket = WebSocketsServer(81);

// Declare/initialize timer variables
Ticker timer;
bool read_data = false;



// Raw string literal for containing the page to be sent to clients
char webpage[] PROGMEM = R"=====(
<html>
<head>
  <script>
    var Socket;
    function init() {
      Socket = new WebSocket('ws://' + window.location.hostname + ':81/');
      Socket.onmessage = function(event){
        // receive the color data from the server
        var data = JSON.parse(event.data);
        console.log(data);
      }
    }  
  </script>
</head>
<body onload="javascript:init()">
  <h4>Websocket client served from the Sensor Board!</h4>
</body>
</html>
)=====";

void setup() {
  // Connect to WiFi
  
  Serial.begin(115200);
  // Setting the ESP as an access point
  Serial.print("Setting AP (Access Point)…");
  // Remove the password parameter, if you want the AP (Access Point) to be open
  WiFi.softAP(ssid, password);

  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);
  
  // define the routes in which the server is accessible
  server.on("/",[](){
    server.send_P(200, "text/html", webpage);  
  });

  // initialize server and websockets
  server.begin();
  webSocket.begin();
  
  // initialize timer function
  timer.attach(/*rate in secs*/ 0.1, /*callback*/ readData);
  
  // handling incoming messages on the websocket
  webSocket.onEvent(webSocketEvent);
}

void readData() {
  // should only be used to set/unset flags
  read_data = true;
}

void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length)
{
  if(type == WStype_TEXT)
  {
    // processs any returned data
    Serial.printf("payload [%u]: %s\n", num, payload);
  }
}
int audioVal(int i){spectrumValue[i] = mult * random(0,4096); return (spectrumValue[i]);}


  
void loop() {
  webSocket.loop();
  server.handleClient();  
  if(read_data){
    //sendTest1(payload);//works but there's a bottle neck on the receiver or senders end.
    sendTest3(payload); //this sends the data as fast the esp23 could send and receive it and almost perfect real time.
  }
}

void sendTest1(uint8_t* payload){
//this kinda works but very slow and only the last json += "value" string is filled. remove 'json += moveValue(6);' and 'json += moveValue(5);' is filled nothing else is being filled.
//after a while the buffer is filled and this grinds the esp32 to a halt and only sending a message every 4 seconds.
String json = "{\"Freq0\":";
       json += moveValue(0);
       json = "{\"Freq1\":";
       json += moveValue(1);
       json = "{\"Freq2\":";
       json += moveValue(2);
       json = "{\"Freq3\":";
       json += moveValue(3);
       json = "{\"Freq4\":";
       json += moveValue(4);
       json = "{\"Freq5\":";
       json += moveValue(5);
       json = "{\"Freq6\":";
       json += moveValue(6);
       json += "}";
    Serial.println(json); // DEBUGGING
    webSocket.broadcastTXT(json.c_str(), json.length());
}
/*
void sendTest2(uint8_t* payload){
//i couldn't get this to work ('File' not declared in this scope). my tought was this would fill all doc values. and might be faster...
File file = SD.open(fileName, FILE_WRITE);
StaticJsonDocument<4096> doc;
doc["Freq0"] =  audioVal(0);
doc["Freq1"] =  audioVal(1);
doc["Freq2"] =  audioVal(2);
doc["Freq3"] =  audioVal(3);
doc["Freq4"] =  audioVal(4);
doc["Freq5"] =  audioVal(5);
doc["Freq6"] =  audioVal(6);
serializeJson(doc, file);
file.close();
Serial.println(file);
webSocket.broadcastTXT(file.c_str(), file.length());

}
*/

void sendTest3(uint8_t* payload){
//this works perfect the speed is there but i have no idea how to remove the dots or points on the receiver end, it receives fftData string as a uin8_t
//I need to send the audio data as fast as possible, this function does the job perfect without any delay 
  String fftData = ".";
  for (int i = 0; i < 7; i++) {
    fftData += moveValue(i);
    fftData += ".";
  }

    Serial.println(fftData); // DEBUGGING
    webSocket.broadcastTXT(fftData.c_str(), fftData.length());


}

receiver:

#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>
//#include <StreamUtils.h>

// Initialize sensor parameters
int spectrumValue[7];

void printSpectrum() {
  for (int i = 0; i < 7; i++) {
    Serial.print(spectrumValue[i]);
    Serial.print("\t");
  }
  Serial.println();
}


// Initialize network parameters
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

// Declare websocket client class variable
WebSocketsClient webSocket;

// Allocate the JSON document
StaticJsonDocument<200> doc;

void setup() {
  // Connect to WiFi
  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 address, port, and URL path
  webSocket.begin("192.168.4.1", 81, "/");

  // event handler
  webSocket.onEvent(webSocketEvent);

  // try ever 5000 again if connection has failed
  webSocket.setReconnectInterval(5000);
}

void webSocketEvent(WStype_t type, uint8_t* payload, size_t length) {
  // Make sure the screen is clear
  if (type == WStype_TEXT)
  {
    translatorTest1(payload);
    translatorTest2(payload);
    //  Serial.printf("payload: %s\n",payload);
  }
}

void loop() {
  webSocket.loop();
  delay(0);
}

void translatorTest1(uint8_t* payload) {
  //tried to remove the dots. the dots are removed but spectrumValue isn't filledA
  byte index = 0;
  String input_cr;
  char tempMsg[70];
  input_cr = (char*) &payload;
  input_cr.toCharArray(tempMsg, 70);
  char* spectrumChar = strtok(tempMsg, ".");
  while (spectrumChar != NULL) {
    spectrumValue[index++] = atoi(spectrumChar);
    spectrumChar = strtok(NULL, ".");
  }
  printSpectrum(); 

}
void translatorTest2(uint8_t* payload) {
  // Deserialize the JSON document
  DeserializationError error = deserializeJson(doc, payload);

  //ReadBufferingStream bufferedFile(payload, 64); //tried this but no luck compiler error
  //DeserializationError error = deserializeJson(doc, bufferedFile);

  // Test if parsing succeeds.
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.c_str());
    return;
  }
  const float Freq0 = doc["Freq0"];
  const float Freq1 = doc["Freq1"];
  const float Freq2 = doc["Freq2"];
  const float Freq3 = doc["Freq3"];
  const float Freq4 = doc["Freq4"];
  const float Freq5 = doc["Freq5"];
  const float Freq6 = doc["Freq6"];

  Serial.print("Freq0: "); Serial.print(String(Freq0).c_str());
  Serial.print("Freq1: "); Serial.print(String(Freq1).c_str());
  Serial.print("Freq2: "); Serial.print(String(Freq2).c_str());
  Serial.print("Freq3: "); Serial.print(String(Freq3).c_str());
  Serial.print("Freq4: "); Serial.print(String(Freq4).c_str());
  Serial.print("Freq5: "); Serial.print(String(Freq5).c_str());
  Serial.print("Freq6: "); Serial.println(String(Freq6).c_str());
  // Send acknowledgement to the client
  // webSocket.sendTXT("{\"status\":\"OK\"}");*/
}

a little help is appreciated.

What do you need help with exactly ?

not sure what your specific issue is, but there is something i learned recently about using UDP vs stream sockets that may be of issue.

UDP packets are not guaranteed to be received. this is appropriate for real time traffic such as voice which if received late serves no purpose.

so stream sockets (TCP) are reliable and appropriate for a continuous stream of information. unfortunately we often send information in packets and expect one or more packets of information to be carried in a single IP frame. a problem occurs when send lots of packets and a packet straddling two frames; we read a frame and don't see the start of a packet.

so, to start, you might consider sending data more slowly

the issue I’m having is not able to send data faster than 200 ms between messages and even then it halts for a few seconds.
this also persists with the simplest code I would use below.
It seems like the senders or receiver buffer is filling up and unable to process that data. I’m not sure what is causing it.

the delay between messages needs to come down to around 10 or 20 ms.
here below is the code It uses no delays or mills just go as fast as possible.
sender:

#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketsServer.h>
#include <ArduinoJson.h>
#include <Ticker.h>

// Initialize network parameters
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

// Instantiate server objects
WebServer server;
WebSocketsServer webSocket = WebSocketsServer(81);

// Declare/initialize timer variables
Ticker timer;
bool read_data = false;



// Raw string literal for containing the page to be sent to clients
char webpage[] PROGMEM = R"=====(
<html>
<head>
  <script>
    var Socket;
    function init() {
      Socket = new WebSocket('ws://' + window.location.hostname + ':81/');
      Socket.onmessage = function(event){
        // receive the color data from the server
        var data = JSON.parse(event.data);
        console.log(data);
      }
    }  
  </script>
</head>
<body onload="javascript:init()">
  <h4>Websocket client served from the Sensor Board!</h4>
</body>
</html>
)=====";

void setup() {
  // Connect to WiFi
  
  Serial.begin(115200);
  // Setting the ESP as an access point
  Serial.print("Setting AP (Access Point)…");
  // Remove the password parameter, if you want the AP (Access Point) to be open
  WiFi.softAP(ssid, password);

  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);
  
  // define the routes in which the server is accessible
  server.on("/",[](){
    server.send_P(200, "text/html", webpage);  
  });

  // initialize server and websockets
  server.begin();
  webSocket.begin();
  
  // initialize timer function
  timer.attach(/*rate in secs*/ 0.01, /*callback*/ readData);
  
  // handling incoming messages on the websocket
  webSocket.onEvent(webSocketEvent);
}

void readData() {
  // should only be used to set/unset flags
  read_data = true;
}

void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length)
{
  if(type == WStype_TEXT)
  {
    // processs any returned data
    Serial.printf("payload [%u]: %s\n", num, payload);
  }
}
double mult = 1.00;
int value[7];
int audioVal(int i){value[i] = mult * random(0,4096); return (value[i]);}

void loop() {
  webSocket.loop();
  server.handleClient();  
  if(read_data){
  String fftData = ".";
  for (int i = 0; i < 7; i++) {
    fftData += audioVal(i);
    fftData += ".";
  }

    Serial.println(fftData); // DEBUGGING
    webSocket.broadcastTXT(fftData.c_str(), fftData.length());
  }
}

receiver:

#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketsClient.h>
//#include <FastLED.h> //for a timer


// Initialize network parameters
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

// Declare websocket client class variable
WebSocketsClient webSocket;

void setup() {
  // Connect to WiFi
  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 address, port, and URL path
  webSocket.begin("192.168.4.1", 81, "/"); // change this to your esp ip.

  // event handler
  webSocket.onEvent(webSocketEvent);

  // try ever 5000 again if connection has failed
  webSocket.setReconnectInterval(2000);
}

void webSocketEvent(WStype_t type, uint8_t* payload, size_t length) {
  // Make sure the screen is clear
  if (type == WStype_TEXT)
  {
      Serial.printf("payload: %s\n",payload);
  }
}

void loop() {
//  EVERY_N_MILLISECONDS(150) webSocket.loop();
webSocket.loop();
  delay(0); // for updating some stuff
}

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