Hello,
The code that manages the (ws-data (resource)) is creating a memory corruption. The data passed from the webpage and transmitted on the socket is randomly corrupted in the process.
Here is a simple test… Use code/webpage BELOW and monitor the output from WS_EVT_DATA (*data) on the serial monitor. You will see the random corruptions, randomly. Sometimes is starts after the first few transmissions, other times it takes 100’s of transmits to show itself. Press “AUTO DATA”, the page simply pulls strings from an array and sends it on the socket.
The library is unusable as it is.
Thank you,
Chris Loubier
CODE:
// Import required libraries
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
// Replace with your network credentials
const char* ssid = "<censored>";
const char* password = "<censored>";
bool ledState = 0;
const int ledPin = 2;
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
void notifyClients() {
ws.textAll(String(ledState));
}
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
AwsFrameInfo *info = (AwsFrameInfo*)arg;
//Serial.printf("data= %s\n", data);
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
data[len] = 0;
if (strcmp((char*)data, "toggle") == 0) {
ledState = !ledState;
notifyClients();
}
}
}
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
switch (type) {
case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
Serial.printf("WS_EVT_DATA_0 = %s\n", (char*)data);
handleWebSocketMessage(arg, data, len);
break;
case WS_EVT_PONG:
case WS_EVT_ERROR:
break;
}
}
void initWebSocket() {
ws.onEvent(onEvent);
server.addHandler(&ws);
}
String processor(const String& var){
Serial.println(var);
if(var == "STATE"){
if (ledState){
return "ON";
}
else{
return "OFF";
}
}
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
if(!SPIFFS.begin()){
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
// You can remove the password parameter if you want the AP to be open.
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
Serial.println("Wait 100 ms for AP_START…");
delay(100);
Serial.println("Set softAPConfig");
IPAddress Ip(10,0,0,1);
IPAddress NMask(255, 0, 0, 0);
WiFi.softAPConfig(Ip, Ip, NMask);
IPAddress myIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(myIP);
initWebSocket();
// Route for root / web page
server.on("/html", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/index.html", "text/html");
});
server.on("/jquery-3.3.1.min.js", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/jquery-3.6.0.min.js", "text/javascript");
});
server.begin();
// Route for root / web page
//server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
// request->send_P(200, "text/html", index_html, processor);
//});
// Start server
//server.begin();
}
void loop() {
ws.cleanupClients();
digitalWrite(ledPin, ledState);
}
WEB PAGE:
<!DOCTYPE HTML><html>
<head>
<title>ESP Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<script>
var counter = 0;
var autoSend = false;
var autoDate = ['P0F0,1231', 'P0F0,1232','P0F0,1234','P0F0,1235','P0F0,1236','P0F0,1237', 'P0F0,1238','P0F0,1239','P0F0,1230','P0F0,0000',]
</script>
<style>
html {
font-family: Arial, Helvetica, sans-serif;
text-align: center;
}
h1 {
font-size: 1.8rem;
color: white;
}
h2{
font-size: 1.5rem;
font-weight: bold;
color: #143642;
}
.topnav {
overflow: hidden;
background-color: #143642;
}
body {
margin: 0;
}
.content {
padding: 30px;
max-width: 600px;
margin: 0 auto;
}
.card {
background-color: #F8F7F9;;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
padding-top:10px;
padding-bottom:20px;
}
.button {
padding: 15px 50px;
font-size: 24px;
text-align: center;
outline: none;
color: #fff;
background-color: #0f8b8d;
border: none;
border-radius: 5px;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
/*.button:hover {background-color: #0f8b8d}*/
.button:active {
background-color: #0f8b8d;
box-shadow: 2 2px #CDCDCD;
transform: translateY(2px);
}
.state {
font-size: 1.5rem;
color:#8c8c8c;
font-weight: bold;
}
</style>
<title>ESP Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
</head>
<body>
<script>
var myVar = setInterval(myTimer, 250);
function myTimer() {
if(autoSend == true)
{
counter ++;
if(counter >9)
{
counter = 0;
}
document.getElementById('autoData').value = autoDate[counter];
websocket.send(document.getElementById('autoData').value);
}
}
</script>
<div class="topnav">
<h1>ESP WebSocket Server</h1>
</div>
<div class="content">
<div class="card">
<h2>Web Socket Data Test</h2>
<p><input id="autoData"> <input id="dataIn"></p>
<p><button id="setAutoSend" onClick="toggleAutoState()" class="button">Auto Data</button> <button id="button" class="button">Send Data</button></p>
</div>
</div>
<script>
var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
window.addEventListener('load', onLoad);
function initWebSocket() {
console.log('Trying to open a WebSocket connection…');
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage; // <– add this line
}
function onOpen(event) {
console.log('Connection opened');
}
function onClose(event) {
console.log('Connection closed');
setTimeout(initWebSocket, 2000);
}
function onMessage(event) {
var state = event.data;
}
function onLoad(event) {
initWebSocket();
initButton();
}
function toggleAutoState(){
autoSend = !autoSend;
}
function initButton() {
document.getElementById('button').addEventListener('click', toggle);
}
function toggle(){
websocket.send(document.getElementById('dataIn').value);
}
</script>
</body>
</html>