Bizzare behaviour of ESP32 websocket webserver when not connected to the internet - websocket

I am working on a project that uses the ESP32 C3 dev board and runs a webserver with dns, and comunicates with the client via websocket. here is the arduino code (the part of it relevent to the webserver):
#include <math.h>
#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <WiFiClient.h>
#include <time.h>
#include "SPIFFS.h"
#include <FS.h>
#include <EEPROM.h>
#include <ArduinoOTA.h>
#include <WiFiUdp.h>
#include <ESPmDNS.h>
#include <WebSocketsServer.h>
#include <DNSServer.h>
#include <NTPClient.h>
#include <Adafruit_NeoPixel.h>
#include <driver/adc.h>
WebServer server(8000);
DNSServer dnsServer;
WebSocketsServer webSocket = WebSocketsServer(81);
WiFiServer server2(80);
IPAddress apIPDNS(8,8,4,4);
IPAddress testIP1(192,168,1,4);
IPAddress testIP2(192,168,1,5);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
IPAddress apIP(192, 168, 4, 3);
IPAddress netMsk(255, 255, 255, 0);
uint8_t* data;
void onWebSocketEvent(uint8_t num,
WStype_t type,
uint8_t * data1,
size_t length) {
// Figure out the type of WebSocket event
switch(type) {
// Client has disconnected
case WStype_DISCONNECTED:
Serial.printf("[%u] Disconnected!\n", num);
break;
// New client has connected
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
// Serial.printf("[%u] Connection from ", num);
// Serial.println(ip.toString());
}
break;
// Echo text message back to client
case WStype_TEXT:
data = data1;
parsedata();
break;
case WStype_BIN:
case WStype_ERROR:
case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START:
case WStype_FRAGMENT:
case WStype_FRAGMENT_FIN:
default:
break;
}
}
void setup() {
Serial.begin(115200);
EEPROM.begin(512);
time_now = millis();
WiFi.mode(WIFI_AP_STA);
WiFi.softAPConfig(testIP1, testIP1, netMsk);
WiFi.softAP(ssid, password);
WiFi.hostname("esp32server");
WiFi.begin(sta_ssid, sta_password);
dnsServer.start(53, "*", WiFi.softAPIP());
Serial.println("connecting to wifi1...");
delay(6000);
if(WiFi.status() == WL_CONNECTED) { current_connected_wifi = String(sta_ssid); current_connected_password = String(sta_password);Serial.println("connected to:" + current_connected_wifi);}
else {WiFi.begin(sta_ssid2, sta_password2);delay(6000);Serial.println("connecting to wifi2...");
if(WiFi.status() == WL_CONNECTED) { current_connected_wifi = String(sta_ssid2); current_connected_password = String(sta_password2);Serial.println("connected to:" + current_connected_wifi);}
else {WiFi.begin(sta_ssid3, sta_password3);delay(6000);
Serial.println("connecting to wifi3...");
if(WiFi.status() == WL_CONNECTED) { current_connected_wifi = String(sta_ssid3); current_connected_password = String(sta_password3);Serial.println("connected to:" + current_connected_wifi);}
else { Serial.println("NO INTERNET"); WiFi.disconnect();dnsServer.start(53, "*", WiFi.softAPIP());}
}
}
SPIFFS.begin();
MDNS.begin("espserver");
server.on("/", handle_root);
server.on("/Chart",HTTP_GET, handle_chart);
server.on("/Style",HTTP_GET, handle_chartcss);
server.on("/mark",HTTP_GET, handle_img);
server.on("/nonet",HTTP_GET, handle_img2);
server.on("/wifilogo",HTTP_GET, handle_img3);
server.on("/adressip", handle_adressip);
server.on("/maxcoff", handle_maxcoff);
server.on("/request", handle_request);
server.on("/mintime", handle_mintime);
server.on("/maxtime", handle_maxtime);
server.on("/dailychart", handle_dailychart);
server.on("/hourlychart", handle_hourlychart);
server.on("/monthlychart", handle_monthlychart);
server.on("/cumulative", handle_cumulative);
server.on("/monthly", handle_monthly);
server.on("/SSIDnames", handle_SSIDnames);
server.on("/getmaxenergy", handle_maxenergy);
server.begin();
webSocket.begin();
webSocket.onEvent(onWebSocketEvent);
server2.begin();
MDNS.addService("http", "tcp", 80);
}
void loop() {
WiFiClient client = server2.available();
dnsServer.processNextRequest();
server.handleClient();
webSocket.loop();
delay(20);
}
quick explenation:
when the ESP32 starts, it checks if it can connect to the internet with any of the 3 saved credentials from eeprom (sta_ssid, sta_password). If it manages to connect with any of them, the webserver can be accesed either when connecting to the wifi of the ESP or on the network that the ESP32 is connected to. When it is unable to find a a network it can only be accesed when connected to the wifi AP of the ESP32. The webserver is accesed from either 192.168.1.4:8000 or espserver.local:8000.
This works great regardless of internet access. When i connect to the webserver i send my html and javascript code to the client and then establish a websocket connection. When the esp doesnt have internet acces the websocket connection works fine, and packets get recieved within milieconds, worst case scenario a couple of them take 2 seconds to arrive.
HOWEVER, when the ESP is not connected to the internet, the packets get stuck on pending and take forever to arive (even 10 seconds), or dont arive at all. Its almost like the webserver is too busy, even tho it has far less to do compered to when it is connected to the internet.
My question is, do i have to use a special function to disconect the webserver from the internet (where WiFi.disconect() is not enough?) or how can I make the WebServer library work better to not lose any packets?
(i have tried using the asynch websocket library, however it does not work on my specific chipset (esp32 c3) so i have to make it work with this library)

I figured it out. the problem was as some people hinted, that the wifi status was 1, which meant it was constantly trying to reconnect (and using cpu time). I used WiFi.disconnect(true); to disconnect the wifi if it didnt connect to any network during setup. that solved the problem.

Related

ESP32 How to change default port of AsyncWebServer from 80 to any other port number

I have application that I need to run multiple ESP32s in same network which publishes webserver, in my case multi device is broadcasting in same port as 80. This causing port issue I guess because only one device at a time is working on browser. When I change port number to 8080, I cannot make it work. Is there any configuration that I need to do before working with multi webserver?
I shared the code below which working, my purpose is make it work with multi device in same network.
#include <ESPmDNS.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
const char* ssid = "XXXX";
const char* password = "XXXX";
AsyncWebServer server(80);
void setup(){
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
if(!MDNS.begin("esp32")) {
Serial.println("Error starting mDNS");
return;
}
Serial.println(WiFi.localIP());
server.on("/hello", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", "Hello World");
});
server.begin();
}
void loop(){}

Esp32-WROOM-32D can't connect to my home wifi

I am trying to get my esp32 to connect to my wifi, but it attempts forever without connecting. I don't think there is anything wrong with the code. I'm thinking the issue is something with my router.
#include<WiFi.h>
const char *ssid = "mySSID";
const char *password = "myPW";
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void setup() {
Serial.begin(115200);
initWiFi();
Serial.print("RRSI: ");
Serial.println(WiFi.RSSI());
}
void loop() {
// put your main code here, to run repeatedly:
}
I have a netgear router that puts out a 2.4G and 5G network. I ran a WiFi scan sketch on my esp32 and it successfully saw my 2.4Ghz wifi and identified it was using WPA2. I checked my router log and saw it thought my esp32 connection attempts were DoS attacks so i disabled DoS protection, and added my esp32's mac address to the allow list. None of that worked. any ideas here?
I checked my code vs your code. I can only see one difference.
// Debug information
#define DEBUG 1
#if DEBUG ==1
#define debug(x) Serial.print(x)
#define debugln(x) Serial.println(x)
#else
#define debug(x)
#define debugln(x)
#endif
#define vtDelay(x) vTaskDelay(x / portTICK_PERIOD_MS)
void initWiFi() {
debug("Start initWiFi");
// Set WiFi to station mode and disconnect from an AP if it was previously connected
WiFi.mode(WIFI_STA);
//WiFi.disconnect();
vtDelay(1000);
WiFi.begin(ssid, password);
debugln("Connecting to WiFi ..");
WiFiAttempts = 1;
while (WiFiRet != WL_CONNECTED ) {
WiFiRet = WiFi.status();
debug("WiFi.status = ");
debug(WiFiRet);
debug(" WiFiAttempts = ");
debugln(WiFiAttempts++);
vtDelay(1000);
if (WiFiAttempts > 20) {
debugln("Restarting the ESP32");
ESP.restart();
}
}
debugln(WiFi.localIP());
}
This works for me the only difference was the vtDelay for 1000 milliseconds. I am also using my 2.4G and have security set to 'WPA2-PSK'.
I hope this helps.

ArduinoHTTPClient websocket undocumented max message size?

I have an Arduino MKRNB 1500 (with LTE-M network capability).
My code uses a websocket to upload messages to a server. The messages are uploaded every second or so of around 800-1000 bytes. My websocket server accepts these messages (i have tried with a browser client). But the ArduinoHTTPClient library WebSocketClient refuses to send messages that are over 128 bytes. The Arduino just hangs from that point onwards.
Because of the network latency, this means i cannot send more than around 600 bytes a second.
This limitation seems arbitrary, and is not documented as far as i have seen. It can be easily reproduced using the following code. Sending smaller messages more frequently is not an option because the network latency of LTE-M is around 150ms.
How can i send larger messages?
#include <ArduinoHttpClient.h>
#include <MKRNB.h> //For LTE-M or NB-IOT connections
#include "arduino_secrets.h"
// initialize the LTE-M library instance
NBClient nbClient;
GPRS gprs;
NB nbAccess;
char server[] = "echo.websocket.org"; // server address
const char PINNUMBER[] = "0000"; // = SIM SECRET_PINNUMBER;
int port = 80; // port 80 is the default for HTTP
WebSocketClient client = WebSocketClient(nbClient, server, port);
int count = 120;
void setup() {
Serial.begin(9600);
// LTE-M connection
Serial.println(F("Connecting to LTE-M network"));
boolean connected = false;
while (!connected) {
if ((nbAccess.begin(PINNUMBER) == NB_READY) &&
(gprs.attachGPRS() == GPRS_READY)) {
connected = true;
} else {
Serial.println("Not connected");
delay(1000);
}
}
}
void loop() {
Serial.println("starting WebSocket client");
client.begin();
while (client.connected() and count <= 1000) {
Serial.print("Sending hello ");
Serial.println(count);
// send a hello #
client.beginMessage(TYPE_TEXT);
client.print(count);
client.print(": ");
int i = 0;
while (i<= count){
client.print("X");
i++;
}
client.endMessage();
// increment count for next message
count++;
// check if a message is available to be received
int messageSize = client.parseMessage();
if (messageSize > 0) {
Serial.println("Received a message:");
Serial.println(client.readString());
}
delay(1000);
}
Serial.println("disconnected");
}
After examining the ArduinoHttpClient library, it turns out the WebSocketClient.h file has a limited buffer defined on line 89:
uint8_t iTxBuffer[128];
i changed that to
uint8_t iTxBuffer[4096];
And the problem was resolved.
custom size must be supported soon.
https://github.com/arduino-libraries/ArduinoHttpClient/issues/68

RPi + ESP8266 stability issues

I was recently working on a home automation project which has finally come to end and I am thinking to install it in my home. First of all, I would like to brief you with the basic architecture.
I am using a Raspberry Pi 3 as the central controller node which is running Node-Red and its Mosca palette. Currently, there are 5 ESP-01 in the project. Four of them are wired up with a relay and the remaining ESP is wired up with a DHT11 temperature sensor. Almost everything is running good but I am facing some stability issues, like, when I recycle the power the ESP-01 doesn't run the program. Serial monitor stays blank. However, when I disconnect the GPIO2 from the relay and then power up the ESP. The program begins. So, I have to pull out the GPIO2 then power up the ESP then connect the GPIO2 with the relay on every power recycle. Another problem which I am facing is sometimes the ESP crashes automatically. It sometimes prints out fatal exception(0) or soft wdt reset even though I have added a watchdog timer.
Here is the code for one of the client ESP:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* ssid = "........";
const char* password = ".........";
const int led = 13;
const char* mqtt_server = "192.168.1.8";
WiFiClient espClient;
PubSubClient client(espClient);
const int ledGPIO2 = 2;
void setup_wifi() {
int i;
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("WIFI BEGUN");
while (WiFi.status() != WL_CONNECTED) {
ESP.wdtFeed();
delay(500);
i++;
if ((i&0x01)==0){
digitalWrite(led, 0);
} else {
digitalWrite(led, 1); // led should start blinking at .5 seconds
}
Serial.print(".");
if (i>1000) break; // get out after 50 seconds
if (i==1000){
}
Serial.print(".");
Serial.println("");
Serial.print("WiFi connected - ESP IP address: ");
Serial.println(WiFi.localIP());
}
}
void callback(String topic, byte* message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
if(topic=="Lamp1"){
Serial.print("Changing GPIO 2 to ");
if(messageTemp == "on"){
digitalWrite(ledGPIO2, HIGH);
Serial.print("On");
}
else if(messageTemp == "off"){
digitalWrite(ledGPIO2, LOW);
Serial.print("Off");
}
}
Serial.println();
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect("ESP8266Client")) {
Serial.println("connected");
client.subscribe("Lamp1");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
pinMode(ledGPIO2, OUTPUT);
digitalWrite(ledGPIO2, true);
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
if(!client.loop())
client.connect("ESP8266Client");
}
Also, I have been thinking for an efficient power supply for ESP. Batteries cannot be reliable for long-term and powering up via an adapter would be unfeasible as the module is going to be mounted on the wall. Moreover, ac to dc converter was something which seems to be a decent way for power supply.
Vcc - 3.3V
CH_PD - 3.3V
Tx - Tx (Arduino)
Rx - Rx (Arduino)
GPIO0 - GND (while uploading the sketch)/ 3.3V
GND - GND
I am not using capacitors or resistors. I am getting a 5V supply from Arduino which is regulated to 3.3V using LD33V voltage regulator.
Any suggestions would be appreciated. Thank You!!

Why doesn't this boost asio code work correctly?

This boost udp server doesn't function as expected.
It is identical to the blocking UDP echo server EXCEPT for a minor change.
I'm using a different socket to return the response, i.e. sock2.
Now this code works perfectly if the client is on the same machine as the server.
But the moment I run this on a different machine, the response is not received.
However, if I change the sending socket to be sock rather than sock2 it does work
across machines.
Any idea why that would be? wireshark is not showing any errors at all. Client uses random source port, but then calls recv_from on the same random port. Server sends response back to that same port number that the client then listens on.
#include <cstdlib>
#include <iostream>
#include <boost/asio.hpp>
using boost::asio::ip::udp;
enum { max_length = 1024 };
void server(boost::asio::io_service& io_service, short port)
{
udp::socket sock(io_service, udp::endpoint(udp::v4(), port));
udp::socket sock2(io_service, udp::endpoint(udp::v4(), 0));
for (;;)
{
char data[max_length];
udp::endpoint sender_endpoint;
size_t length = sock.receive_from(
boost::asio::buffer(data, max_length), sender_endpoint);
printf("Got data, sending response to %s:%d\n", sender_endpoint.address().to_string().c_str(), sender_endpoint.port());
sock2.send_to(boost::asio::buffer(data, length), sender_endpoint);
}
}
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: blocking_udp_echo_server <port>\n";
return 1;
}
boost::asio::io_service io_service;
using namespace std; // For atoi.
server(io_service, atoi(argv[1]));
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
Answering my own question again!
Check there is no firewall software running on the other machine!. It turns out that the windows machine running in the VM was running a windows firewall.
I didn't immediately suspect this because when I send the UDP response on the original socket using the port number passed into the server, it worked.
I guess the windows firewall is maintaining some state.

Resources