I am trying to setup/create a very simple and light low overhead TCP server and client.
It involves two ESP8266's
First of all please excuse any bad coding (I am a hobbyist) so feel free to correct and assist me for the benefit of all reading this.
Secondly please understand that I have had at least 3 weeks or more of long days and late nights battling with this , so bear with me.
In the past I have dabbled with RF modules and prior to this NRF 24L01 modules and Arduino.
My goal is to be able to send a few bytes reliably from one ESP to another, should be pretty straight-forward right ?
To start I tried the UDP examples and options but found that every now and then packets were dropped, connections not made and so forth.
I then opted for the TCP option .. a little more overhead but seemed to be the way to go.
I found that using the basic client and server examples worked fairly well and it was great to sent a URL from the client to the server to activate an LED/GPIO ..something like http://myESPIP/GPIO/0.
Then I came across the TCP client and server examples and have also found blog articles on how to create a simple TCP server and have the client connect and send some text.
GREAT STUFF !
So I was hoping to take my working older code .. which worked well for arduino environments and have it run on the two ESP's.
Summarized here is the code for a sender and receiver built to run on one ESP or ARDUINO for testing.
Try it and see if it works for you too
//declare vars for send
char hDroid[5] = {
"1234" }; //4 or less digits/keys eg 1234 + NULL
char pDroid[3] = {
"21" }; //2 digits/keys eg 12 + NULL
char ooDroid[4] = {
"123" }; //3 or less digits/keys eg 123 + NULL
char devDroid[5] = {
"1234" }; //4 or less digits/keys eg 9999 + NULL
char allDroid[18] = {
'\0' }; //total array count including NULL's
//declare vars for receive
char hDroid1[5] = {
'\0' }; //4 or less digits/keys eg 1234 + NULL
char pDroid1[3] = {
'\0' }; //2 digits/keys eg 12 + NULL
char ooDroid1[4] = {
'\0' }; //3 or less digits/keys eg 123 + NULL
char devDroid1[5] = {
'\0' }; //4 or less digits/keys eg 9999 + NULL
void setup() {
Serial.begin(115200);
}
void loop() {
sprintf(allDroid, "%s,%s,%s,%s", hDroid, pDroid, ooDroid, devDroid);
Serial.println("This is allDroid "); //show content of allDroid
Serial.println(allDroid); //show content of allDroid
delay(1000);
sscanf(allDroid, "%s,%s,%s,%s", &hDroid1, &pDroid1, &ooDroid1, &devDroid1);
Serial.println("this is hDroid1,pDroid1,ooDroid1,devDroid1 "); //show content of allDroid
Serial.println(hDroid1);
Serial.println(pDroid1);
Serial.println(ooDroid1);
Serial.println(devDroid1);
//clear the arrays
memset(allDroid, 0, sizeof(allDroid));
memset(hDroid1, 0, sizeof(hDroid1));
memset(pDroid1, 0, sizeof(pDroid1));
memset(ooDroid1, 0, sizeof(ooDroid1));
memset(devDroid1, 0, sizeof(devDroid1));
}
Now my mission is to have the sender code on the client and the receiver code on the server.
Perhaps some kind souls could explain and alternative to get it right on the server side..and possibly even use a lower overhead method..I really would appreciate it)
Starting with the client side I searched the examples and found quite a few but there is a fair amount of fuzz and variation in examples and usage for both the client and the server as I've noted in various examples and blogs etc.
I decided to use this page as a reference(but battled to find a matching server example) :
https://arduino-esp8266.readthedocs.io/ ... mples.html
So I finally settled on the code below (please feel free to identify issues and fixes and correct or incorrect procedures)
//#include <WiFi.h> //which one of these should be used ?
#include "ESP8266WiFi.h" //which one of these should be used ?
const char* ssid = "yours";
const char* password = "yours";
//Static IP address configuration
IPAddress staticIP(192, 168, 1, 120); //ESP static ip
IPAddress gateway(192, 168, 1, 1); //IP Address of your WiFi Router (Gateway)
IPAddress subnet(255, 255, 255, 0); //Subnet mask
IPAddress dns(192, 168, 1, 1); //DNS
const char *deviceName = "client";
const uint16_t port = 80;
const char* host = "192.168.1.121";
//declare vars for send
char hDroid[5] = {
"1234" }; //4 or less digits/keys eg 1234 + NULL
char pDroid[3] = {
"21" }; //2 digits/keys eg 12 + NULL
char ooDroid[4] = {
"123" }; //3 or less digits/keys eg 123 + NULL
char devDroid[5] = {
"1234" }; //4 or less digits/keys eg 9999 + NULL
char allDroid[18] = {
'\0' }; //total array count including NULL's
void setup()
{
Serial.begin(115200);
delay(1000);
WiFi.hostname(deviceName);
WiFi.config(staticIP, dns , gateway, subnet);
WiFi.begin ( ssid, password );
Serial.println ( "" );
// Wait for connection
while ( WiFi.status() != WL_CONNECTED ) {
delay ( 500 );
Serial.print ( "." );
}
Serial.println ( "" );
Serial.print ( "Connected to " );
Serial.println ( ssid );
Serial.print ( "IP address: " );
Serial.println ( WiFi.localIP() );
Serial.print("Subnet Mask ");
Serial.println(WiFi.subnetMask());
Serial.print("MAC: ");
Serial.println(WiFi.macAddress());
Serial.print("Gateway ");
Serial.println(WiFi.gatewayIP());
Serial.print("DNS: ");
Serial.println(WiFi.dnsIP());
Serial.print("Channel: ");
Serial.println(WiFi.channel());
Serial.print("Status : ");
Serial.println(WiFi.status());
Serial.printf("Started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
}
void loop()
{
WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("Connection to host failed");
delay(1000);
return;
}
Serial.println("Connected to server successful!");
sprintf(allDroid, "%s,%s,%s,%s", hDroid, pDroid, ooDroid, devDroid);
Serial.println("This is allDroid "); //show content of allDroid
Serial.println(allDroid); //show content of allDroid/client.println("123,456,789,OFF,");
client.println(allDroid); //is this correct ?
Serial.println("Disconnecting...");
client.stop();
delay(2000);
}
Now the server side.
I actually used this page as a start/reference https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/server-examples.html
But what is the difference between these two :
WiFiServer server(80);
and
ESP8266WebServer server(80);
Why is ask is because while compiling or trying to at some stage I received this error/message :
We replaced WiFiServer server(80);
with
ESP8266WebServer server(80);
Soooo
class ESP8266WebServer' has no member named 'available'
WiFiClient client = server.available();
And I have noticed some examples use WiFiServer server(80); and some use ESP8266WebServer server(80);
Then also whats a little confusing is that if you add a library from the arduino IDE menu for ESP8266 web server you also get the ESp8266WebServerSecure.h added. Is there some dependency required or can the run independently ?
include <ESP8266WebServer.h>
include <ESP8266WebServerSecure.h>
Ok heres my code ... my problem is trying to get the data i sent from the client side decoded/received properly .
By this I mean receive the code sent ( numbers separated by commas) and split it up into variables so I can properly compare each one.
What do you think is best here ? Char , String, Int etc
#include "ESP8266WiFi.h"
const char* ssid = "yours";
const char* password = "yours";
//Static IP address configuration
IPAddress staticIP(192, 168, 1, 121); //ESP static ip
IPAddress gateway(192, 168, 1, 1); //IP Address of your WiFi Router (Gateway)
IPAddress subnet(255, 255, 255, 0); //Subnet mask
IPAddress dns(192, 168, 1, 1); //DNS
const char *deviceName = "server";
WiFiServer wifiServer(80);
//declare "code-holding" vars for send
// end cold-holding vars
//serial input vars
//end of serial input vars
void setup() {
Serial.begin(115200);
delay(1000);
WiFi.hostname(deviceName); // DHCP Hostname (useful for finding device for static lease)
WiFi.config(staticIP, dns , gateway, subnet);
WiFi.begin ( ssid, password );
Serial.println ( "" );
// Wait for connection
while ( WiFi.status() != WL_CONNECTED ) {
delay ( 500 );
Serial.print ( "." );
}
Serial.println ( "" );
Serial.print ( "Connected to " );
Serial.println ( ssid );
Serial.print ( "IP address: " );
Serial.println ( WiFi.localIP() );
Serial.print("Subnet Mask ");
Serial.println(WiFi.subnetMask());
Serial.print("MAC: ");
Serial.println(WiFi.macAddress());
Serial.print("Gateway ");
Serial.println(WiFi.gatewayIP());
Serial.print("DNS: ");
Serial.println(WiFi.dnsIP());
Serial.print("Channel: ");
Serial.println(WiFi.channel());
Serial.print("Status : ");
Serial.println(WiFi.status());
//start the server
//server.begin(); <<<use this or the below ??
wifiServer.begin();
Serial.printf("Web server started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
}//end of start loop
String getStringPartByNr(String data, char separator, int index)
{
// spliting a string and return the part nr index
// split by separator
int stringData = 0; //variable to count data part nr
String dataPart = ""; //variable to hole the return text
for (int i = 0; i < data.length() - 1; i++) { //Walk through the text one letter at a time
if (data[i] == separator) {
//Count the number of times separator character appears in the text
stringData++;
} else if (stringData == index) {
//get the text when separator is the rignt one
dataPart.concat(data[i]);
} else if (stringData > index) {
//return text and stop if the next separator appears - to save CPU-time
return dataPart;
break;
}
}
//return text if this is the last part
return dataPart;
}
void loop() {
WiFiClient client = wifiServer.available(); //hoping this is the correct usage of the WiFiClient ??
if (client) { //if a client is connected
while (client.connected()) { //and they're connected
while (client.available() > 0) {//and data arrives
//read input
String line = client.readStringUntil('\r');
Serial.print(line); //print what we've received
//Example
Serial.println("");
Serial.print("0: ");
Serial.println(getStringPartByNr(line, ',', 0)); // the first part
Serial.print("1: ");
Serial.println(getStringPartByNr(line, ',', 1)); // the 2. part
Serial.print("2: ");
Serial.println(getStringPartByNr(line, ',', 2)); // the 3. part
Serial.print("3: ");
Serial.println(getStringPartByNr(line, ',', 3)); // the 4. part
getStringPartByNr(line, ',', 4); //I added this to look for a final comma because code not grabbing last character
//iff you want more carry on adding more like the below
//Serial.print("4: ");
//Serial.println(getStringPartByNr(line, ',', 4)); // this part do not exist and return ""
}
delay(10);
}
client.stop();
Serial.println("Client disconnected");
/*
* this stuff is here for when we use Char ARRAY's hopefully :-(
//clear the arrays
memset(allDroid, 0, sizeof(allDroid));// This line is for reset the StringReceived
memset(hDroid, 0, sizeof(hDroid));// This line is for reset the StringReceived
memset(pDroid, 0, sizeof(pDroid));// This line is for reset the StringReceived
memset(ooDroid, 0, sizeof(ooDroid));// This line is for reset the StringReceived
memset(devDroid, 0, sizeof(devDroid));// This line is for reset the StringReceived
*/
}
}
To split the received data and as a test becasue I couldnt get my scanf '(receiver) portion working I used this examples code which I saw in a Stackexchange question:
https://github.com/BenTommyE/Arduino_getStringPartByNr/blob/master/getStringPartByNr.ino
@ Ben if you're reading this thank you kindly.
The code sort of works ..
Apart from not being lean enough ro mean enough or even optimized,
The problems I have are :
The server side crashes after a certain amount of time ... a stack crash is reported and the ESP reboots
The server side code isn't decoding the received data correctly (probably the code I borrowed to make it work, if you can see why let me know)
The server side ... should I be using client.read(); and if so whats the correct way to do it ? Or should I use client.readStringUntil(); and whats the correct way to use it ?
I would like to rather use something like the code below (my roginal receiver side code posted at the start here) on the server side but kept getting a conversion error. about the wrong conversion type if you know why please educate me as to why ?
By the way I have left these variables out of the server side for now.
char tmpArray[21];
client.read(&tmpArray,sizeof(tmpArray));
Serial.println(tmpArray);
sscanf(tmpArray, "%s,%s,%s,%s", &hDroid1, &pDroid1, &ooDroid1, &devDroid1);
I hope some kind souls out there can help or share their experiences too
I look forward to hearing from you
D