Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to make a Keep-Alive effect? #1430

Open
butaikis opened this issue Aug 12, 2024 · 5 comments
Open

Is it possible to make a Keep-Alive effect? #1430

butaikis opened this issue Aug 12, 2024 · 5 comments

Comments

@butaikis
Copy link

@me-no-dev Hello. Is it possible to make a "Keep-Alive" effect? So that the web server does not close the socket for a while?

@Belleson
Copy link

I made a keep-alive using a Ticker from this library to socket.textAll() clients every 30 seconds, and they reply back to server. It seems to work okay.

@butaikis
Copy link
Author

@Belleson Can I have an example of how the EspAsyncWebServer library works? It's just that the problem is that it is the library that forcibly closes the socket. Maybe I don't understand something)

@Belleson
Copy link

Belleson commented Aug 13, 2024

This is a very good tutorial on web socket.

Prevent watch dog time-outs by

  1. Don't use event callbacks, only socket message handlers
  2. No delays in message handler, instead make message handler asynchronous with Ticker callbacks

Be aware callbacks for a single ticker must have enough time to finish before another message arrives. If not, tickerCallback2 will stop execution of tickerCallback1, so this is good for human interface but not for fast client-server data processing.

Client javascript code will also have a message handler function.

Sample server code for asynchronous message processing (not tested to compile or run):

#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include <Ticker.h>


AsyncWebServer webServer;
AsyncWebSocket socket("/ws");
Ticker socketActionTicker;
Ticker keepAlive;

// Call from main.setup()
void initSocket()
{
	socket.onEvent(onSocketEvent);
	webServer.addHandler(&socket);
	keepAlive.attach(30, tickleSocketClient); // attach Keep Alive to timer ticker, execute twice per minute
}

void notifyClients(const char *key, const char *data)
{
	const uint8_t size = JSON_OBJECT_SIZE(8);
	StaticJsonDocument<size> json;
	json[key] = data;

	char buffer[512];
	size_t len = serializeJson(json, buffer);
	socket.textAll(buffer, len);
}

void tickerCallback1(uint_fast8_t param)
{

	// Add server processing code for client message 1

	char ld[16];
	memset(ld, 0, sizeof(ld));
	sprintf(ld, "%d", param); 

	notifyClients("paramName1", ld);
}

void tickerCallback2(uint_fast8_t param)
{
	// Add server processing code for client message 2

	char ld[16];
	memset(ld, 0, sizeof(ld));
	sprintf(ld, "%d", param); 

	notifyClients("paramName2", ld);
}

void handleSocketMsg(void *arg, uint8_t *data, size_t len)
{
	AwsFrameInfo *info = (AwsFrameInfo *)arg;
	if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT)
	{
		const uint8_t size = JSON_OBJECT_SIZE(8);
		StaticJsonDocument<size> json;
		DeserializationError err = deserializeJson(json, data);
		if (err)
		{
			// LOG ERROR HERE
			return;
		}

		if (strcmp(action, "msg1") == 0)
		{
			uint_fast8_t val1 = json["value"];	// client sends JSON to this server message handler
			socketActionTicker.once_ms(1, tickerCallback1, val1); // call function with param value sent from client
		}
		else if (strcmp(action, "msg2") == 0)
		{
			uint_fast8_t val2 = json["value"];	// client sends JSON to this server message handler
			socketActionTicker.once_ms(1, tickerCallback2, val2); // call function with param value sent from client
		}
	}
}

void onSocketEvent(AsyncWebSocket *socksvr,
					  AsyncWebSocketClient *sockclient,
					  AwsEventType type,
					  void *arg,
					  uint8_t *data,
					  size_t len)
{
		switch (type)
		{
			case WS_EVT_CONNECT:
			Serial.printf("\nWebSocket client #%u connected from %s\n", sockclient->id(), sockclient->remoteIP().toString().c_str());
			break;
		case WS_EVT_DISCONNECT:
			Serial.printf("\nWebSocket client #%u disconnected\n", sockclient->id());
			break;
		case WS_EVT_DATA:
			handleSocketMsg(arg, data, len);
			break;
		case WS_EVT_PONG:
		case WS_EVT_ERROR:
			break; // TODO something here?
	}
}

void tickleSocketClient()
{
	const uint8_t size = JSON_OBJECT_SIZE(2);
	StaticJsonDocument<size> json;
	json["keepAlive"] = WiFi.localIP().toString();
	notifyClients(json);
}

Good luck, I hope you find a solution.

@butaikis
Copy link
Author

@Belleson
Copy link

My mistake, when you said keep the socket open I made a bad assumption that you were using web sockets. Maybe you could use a Ticker in a similar way so the server reloads a one pixel graphic on the page as a refresh?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants