Newbie Question: Reliable Message Based Communication to ESP32?
Posted: Sat Jun 02, 2018 4:10 pm
Apologies for the newbie questions, I'm having a hard time using search terms for the forum since I think the stuff I'm asking about I don't know the right words for.
I build custom scientific equipment, and I'd like to shift from USB based communication to a flexible scheme that can allow wifi or ethernet control. The usual way I set this up is to have the computer emulate a serial port and I send a command to my microcontroller that it then interprets, does something, and then replies based on whether it succeeded in executing the command.
I am not quite sure how to do something along these lines over TCP/IP.
I tried using the Arduino toolchain for ESP32 (which maybe is buggy?) and set it up as a server on port 22222. Then I connect to it with ncat or LabView on that port and IP address, send a message, wait for a reply, and then (notionally) close the port. My sketch is a derivative of the SimpleWifiServer server that I excised all the HTML from.
This is my main loop():
This very nearly works, just not reliably. What I see is that I send it data and it reports the new client connection. Then I see the command I sent (with the carriage return) echoed properly on both the serial port and the TCP/IP connection. However, if I try to send it a second command it sometimes works, and by the third time it completely fails and I have to restart the ESP32 to make it communicate again. At that point it is no longer echoing the received command to the serial port either.
I think I'm probably doing this in a very naive and wrong way, but unfortunately my last networking course was in 2001... websockets and such are new terminology to me and I don't remember how ports work under the hood. The ESP32 is *not* reporting when my client disconnects, which is probably the main issue -- ncat doesn't exit on its own after sending a file or piping an echoed command, and LabView explicitly closes the connection and the ESP32 doesn't seem to register the closed connection.
Can anyone help me either make what I'm trying to do work reliably, or help me identify a better approach? I'd like to be able to give this to a client and trust that they won't run into issues. I'm not sure if I'm doing it wrong and need to add a handler to identify when the connection is closed (the example code didn't, and seemed to identify when HTTP connections closed correctly anyway), if the Arduino server implementation isn't properly handling closing connections from the client side, or if I should just use a different approach entirely to do this kind of thing.
I am also unsure what best practices are to implement a user configuring the wifi connection. I assume that I have to have them connect over USB and configure it manually, but in this day and age I am curious if there is a better way. I imagine that the initialization problem is still tricky since it can't be communicated with over wifi until it knows the ssid and password?
I build custom scientific equipment, and I'd like to shift from USB based communication to a flexible scheme that can allow wifi or ethernet control. The usual way I set this up is to have the computer emulate a serial port and I send a command to my microcontroller that it then interprets, does something, and then replies based on whether it succeeded in executing the command.
I am not quite sure how to do something along these lines over TCP/IP.
I tried using the Arduino toolchain for ESP32 (which maybe is buggy?) and set it up as a server on port 22222. Then I connect to it with ncat or LabView on that port and IP address, send a message, wait for a reply, and then (notionally) close the port. My sketch is a derivative of the SimpleWifiServer server that I excised all the HTML from.
This is my main loop():
Code: Select all
std::vector<char> commandstring;
void loop(){
WiFiClient client = server.available(); // listen for incoming clients
if (client) { // if you get a client,
Serial.println("New Client."); // print a message out the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
if (c == 13) { // if the byte is a newline or carriage return character...
commandstring.push_back(13);
commandstring.push_back(10);
commandstring.push_back('\0');
Serial.println(commandstring.data());
client.println(commandstring.data());
commandstring.clear();
}
else if ((c >= 0x20) && (c <= 0x7E)) { // Otherwise, check that the character is standard and add the character to the message.
commandstring.push_back(c);
}
}
}
client.stop();
Serial.println("Client Disconnected.");
// close the connection:
}
}
I think I'm probably doing this in a very naive and wrong way, but unfortunately my last networking course was in 2001... websockets and such are new terminology to me and I don't remember how ports work under the hood. The ESP32 is *not* reporting when my client disconnects, which is probably the main issue -- ncat doesn't exit on its own after sending a file or piping an echoed command, and LabView explicitly closes the connection and the ESP32 doesn't seem to register the closed connection.
Can anyone help me either make what I'm trying to do work reliably, or help me identify a better approach? I'd like to be able to give this to a client and trust that they won't run into issues. I'm not sure if I'm doing it wrong and need to add a handler to identify when the connection is closed (the example code didn't, and seemed to identify when HTTP connections closed correctly anyway), if the Arduino server implementation isn't properly handling closing connections from the client side, or if I should just use a different approach entirely to do this kind of thing.
I am also unsure what best practices are to implement a user configuring the wifi connection. I assume that I have to have them connect over USB and configure it manually, but in this day and age I am curious if there is a better way. I imagine that the initialization problem is still tricky since it can't be communicated with over wifi until it knows the ssid and password?