arduinoWebSockets
arduinoWebSockets copied to clipboard
How to connect custom Callbacks to specific Events from Server
Hi there!
I have the SocketIOClient example running on my ESP32 and I can connect to my server. Using the SocketIOEvent function and switch case from that example I can log a list of event handlers and data coming from my server upon connection, but my question now is how to attach unique, custom callbacks to run when my ESP client receives events? Can the .onEvent() method from the SocketIOclient class take both an event name and a callback function as arguments? Or, would I build a nested switch case inside of the one provided in the example where I'm scanning the incoming Event/Data string from the server and execute functions based on the handler name/incoming data?
Thank you in advance for clarifying!
Hi,
decoding and handling the JSON part is responsibility of the user code, since the lib only implements the "lower" levels to give max flexibility on the JSON data to the user.
The JSON data is typically very application dependent and this allows to handel the data in the way the user likes.
as a result there is no on
like in JS.
implementing a it via a switch case is the easiest way for most users.
having a array of const char ptr + function ptr to loop and check which to call is a more advanced way which allows the implementation of a on
to fill the array and register new callbacks.
which one makes more sense also depends on the amount of different events and if dynamic decisions are needed. to be honest I never had the need for any dynamic in my applications and a easy switch case / else if has done the job just fine :)
basic decoding of the JSON, but you most likely have found that already. https://github.com/Links2004/arduinoWebSockets/blob/a14b6b73b4f05e189ca49d6e84202c2b55db528a/examples/esp8266/WebSocketClientSocketIOack/WebSocketClientSocketIOack.ino#L37-L74
Thank you very much for this clarification! Could you also clarify the following:
- What method in this library is the closest to .emit() in JS? Is it .send or .sendTXT? Whenever emitting to the server, I would need to first JSON-ify my data into an "event: id" format and then send one entire payload, correct?
- In this library, ACK stands for "acknowledgment", correct? Are any methods that end in ACK used only for emitting to events where you expect an acknowledgment coming back to the client?
Thank you for your help!
On Tue, Mar 30, 2021 at 1:51 AM Markus @.***> wrote:
Hi,
decoding and handling the JSON part is responsibility of the user code, since the lib only implements the "lower" levels to give max flexibility on the JSON data to the user. The JSON data is typically very application dependent and this allows to handel the data in the way the user likes. as a result there is no on like in JS.
implementing a it via a switch case is the easiest way for most users. having a array of const char ptr + function ptr to loop and check which to call is a more advanced way which allows the implementation of a on to fill the array and register new callbacks.
which one makes more sense also depends on the amount of different events and if dynamic decisions are needed. to be honest I never had the need for any dynamic in my applications and a easy switch case / else if has done the job just fine :)
basic decoding of the JSON, but you most likely have found that already.
https://github.com/Links2004/arduinoWebSockets/blob/a14b6b73b4f05e189ca49d6e84202c2b55db528a/examples/esp8266/WebSocketClientSocketIOack/WebSocketClientSocketIOack.ino#L37-L74
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Links2004/arduinoWebSockets/issues/650#issuecomment-809961201, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFCD6OVNBMNYC3CHQKZ6F43TGFYGXANCNFSM42BBBYYA .
sendEVENT
is a wrapper for send
its there to make it easier for people :)
https://github.com/Links2004/arduinoWebSockets/blob/master/src/SocketIOclient.cpp#L146-L148
sendTXT
is from the underling WebSocketsClient and is protected
so you can not use it (and it makes no sense to use).
TLDR: sendEVENT
+ json = emit
https://github.com/Links2004/arduinoWebSockets/blob/a14b6b73b4f05e189ca49d6e84202c2b55db528a/examples/esp8266/WebSocketClientSocketIO/WebSocketClientSocketIO.ino#L106-L123
yes ACK = acknowledgment and in the socket.IO protocol its used for trigger a callback function on the nodejs side.
io.emit('test_cb', 'data1', function(arg1, arg2) {
console.log('this function is triggert by the ACK', arg1, arg2);
});
if you dont use the callbacks on emits then there is no need for an ACK.
Hi again,
I'm working on parsing the incoming JSON from my server, but I'm getting only errors thrown from the Deserialization of the JSON. Working off of the example you pointed me to, my code looks like this:
char * stringptr = NULL;
int id = strtol((char *)payload, &stringptr, 10);
//print the event and the id/data
Serial.printf("[IOc] get event: %s\n id: %d\n", payload, id);
if(id){
payload = (uint8_t *)stringptr;
}
DynamicJsonDocument incomingDoc(1024);
DeserializationError error = deserializeJson(incomingDoc, payload, length);
//error handling for the JSON deserialization process
if(error){
Serial.print(F("Deserialization of JSON failed: "));
Serial.println(error.c_str());
return;
}
Serial.print("Pretty JSON: ");
serializeJsonPretty(incomingDoc, Serial);
Serial.println();
However, my code never gets to Serial.print("Pretty JSON: ");
, and instead my console print out looks like this (these are just two examples, but all events received result in this):
Deserialization of JSON failed: InvalidInput
[IOc] get event: /hub, ["allUserDetails", {"users": {}]
id:0
Deserialization of JSON failed: InvalidInput
[IOc] get event: /hub, ["allUsers", {"users": {"User007", "User008"]}
id: 0
I should mention that I am connected to a specific namespace (/hub) on my server.
Is the "InvalidInput" occurring because the namespace tag (/hub) is attached to the front of my payload? I've checked on my server and I'm not sending any strings, only Objects, so there are no hidden escape characters being sent into the JSON deserializer that I know of.
Do you have any suggestions on how I can solve this?
try to print the payload
before the deserializeJson
most likely the /hub,
is the problem and need to be filtered out.
the example where not written or tested with namespace
in use.
the second JSON:
["allUsers", {"users": {"User007", "User008"]}
has ]
and }
mixed at the end, C&P error?
That is good advice, I’ll work on filtering out the /hub. At the point in this example that payload is being sent into the deserializeJSON, what is its data type? Is it a char or a string?
On Mon, Apr 5, 2021 at 2:52 AM Markus @.***> wrote:
try to print the payload before the deserializeJson most likely the /hub, is the problem and need to be filtered out. the example where not written or tested with namespace in use.
the second JSON: ["allUsers", {"users": {"User007", "User008"]} has ] and } mixed at the end, C&P error?
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Links2004/arduinoWebSockets/issues/650#issuecomment-813255549, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFCD6OS63FS6NMT6VV4E7E3THFT3RANCNFSM42BBBYYA .
the deserializeJson
is from the arduinojson
lib.
you can use many types including const char *
and string
.
docu:
https://arduinojson.org/v6/api/json/deserializejson/
And in your example where you add the ID in to the payload, you’re passing payload into deserislize as a char *, correct?
On Mon, Apr 5, 2021 at 9:15 AM Markus @.***> wrote:
the deserializeJson is from the arduinojson lib. you can but many types in including const char * and string. docu: https://arduinojson.org/v6/api/json/deserializejson/
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Links2004/arduinoWebSockets/issues/650#issuecomment-813415226, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFCD6OWR5TNMXQYNOOJSHG3THHAZRANCNFSM42BBBYYA .
Or, I should also ask: what data type does the payload regularly return as in your arduinoWebsockets library?
On Mon, Apr 5, 2021 at 9:18 AM Anthony Marasco @.***> wrote:
And in your example where you add the ID in to the payload, you’re passing payload into deserislize as a char *, correct?
On Mon, Apr 5, 2021 at 9:15 AM Markus @.***> wrote:
the deserializeJson is from the arduinojson lib. you can but many types in including const char * and string. docu: https://arduinojson.org/v6/api/json/deserializejson/
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Links2004/arduinoWebSockets/issues/650#issuecomment-813415226, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFCD6OWR5TNMXQYNOOJSHG3THHAZRANCNFSM42BBBYYA .
no the other way around the code check if there is a ID for a ACK and it yes it is "removed".
The pointer is moved to the first char of the JSON (in this case the [
)
the endptr
of strtol
is used to move the new ptr.
https://www.cplusplus.com/reference/cstdlib/strtol/
in the namespace case it comes down to find the location of the ,
and move the ptr after it (to the [
)
the payload is uint8_t *
which basically is a define to unsigned char *
in case of the ESP (and most of any other µC)
So then in my code, the pointer is being moved to the first char which is a / because of the inclusion of the “/hub,” at the start of my payload, correct?
Could I just move the pointer five characters forward to point at the [ in the payload? Do you think that would that work to filter out the error-causing portion of the payload ?
On Mon, Apr 5, 2021 at 9:22 AM Markus @.***> wrote:
no the other way around the code check if there is a ID for a ACK and it yes it is "removed". The pointer is moved to the first char of the JSON (in this case the [)
the payload is uint8_t * which basically is a define to unsigned char * in case of the ESP (and most of any other µC)
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Links2004/arduinoWebSockets/issues/650#issuecomment-813418713, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFCD6OS2EFFSHXGPBYAQ2CLTHHBTLANCNFSM42BBBYYA .
correct in the namespace
case the pointer is at the /
and all then needs to be done is to move it to the [
.
may not hardcore a +6 but as a dirty test (the space counts too)
payload += 6;
will do the trick.
untested code:
// filter namespace
if(payload[0] == '/') {
payload = strchr(&payload[0], '[');
}
http://www.cplusplus.com/reference/cstring/strchr/
So this is very helpful and I think it's on the right track. The issue I'm running into now is type conversion. Here is my new code, working right now just on stipping away the "/hub":
//parsing incoming events, data payloads requires the JSON library
//make pointer to string as a char first
char * stringptr = NULL;
int id = strtol((char *)payload, &stringptr, 10);
//print the event and the id/data
Serial.printf("%s\n id: %d\n first: %d\n", payload, id, payload[0]);
//checks to see if there is an ID for an acknowledgment, and if so, it "removes" that ID by moving the pointer to the first character of the incoming JSON message (payload)
if (id)
{
payload = (uint8_t *)stringptr;
}
//Since we receive data from a namespace, the first character of the payload array is "/". We need to check that and move the pointer to the first "[" instead
if (payload[0] == 47)
{
payload = (uint8_t *)strchr((char *)payload[0], 91);
Serial.printf("Stripped payload: %s\n", payload);
}
This causes the ESP32 to crash and restart constantly, and I'm certain it looks to be due to the Serial.printf("Stripped payload: %s\n", payload);
line. However, even without that line, trying to move on and pass the new, stripped payload into the JSON deserialization causes an ESP32 crash as well.
I must be off on my type conversions on this line payload = (uint8_t *)strchr((char *)payload[0], 91);
then. Without the uint8_t and (char *), my IDE wouldn't compile the code, so I'm attempting to convert this data into the right format but I'm missing something. Any thoughts?
Also, I was unable to actually compare payload[0] to a symbol ("/") using the if statement so I attempted comparing it to the decimal equivalent of the symbol.
if you need a char and use a single quote ' not " so "/" is a pointer to a const char and '/' is the value of / --> 0x2f or 47
looks like you miss a "&" at your strchr payload parameter and as a result you do not give the function a pointer but the char value (in this case 0x2f) which is a Invalide memory address ;)
https://www.cplusplus.com/doc/tutorial/pointers/
Hello again,
I'm back to trying to tackle this problem with no success, and I'm wondering if you can point me in the direction of how to properly convert the uint_8 payload into what strchr() needs it to be (which would be a char *, although I've tried that with no luck.
Here is my code where I am trying to dynamically grab the payload data starting from the '[' that comes after the namespace (formatted as /nameSpace,) no matter how many characters make up the namespace label.
if (payload[0] == '/')
{
payload = strchr(&payload[0], '['); //results in invalid conversion from 'char*' to 'uint8_t* {aka unsigned char*}' [-fpermissive] error
}
Any help you can provide with how to properly account for the conversions between char* and uint8_t types would be extremely helpful. Thank you!
A-ha! Solved it. Code for dynamically shifting the payload after namespace names of various character lengths works after some extra casting:
if (payload[0] == '/')
{
payload = (uint8_t *)strchr((const char *)&payload[0], '[');
}
Sorry to bother you and thank you for your previous help!