Chat freely about anything...

User avatar
By Espradio01
#77965 Hi all

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 :-)
Code: Select all//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)
Code: Select all//#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

Code: Select all 
#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.
Code: Select allchar 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
User avatar
By Espradio01
#78034 @Phil Hello
Thanks for replying ...
The Esparto looks great by the way .. and I see Itead have discontinued those 3.3/5V AC modules sadly :-(
Yes you're right it's confusing !
Thank you kindly for the tips.
I actually had as you said
Also, take the parsing, scan code etc that isnt working and put it in a simple sketch with NOTHING else and get it working there first.
in the beginning of my post.
Send and receive loaded on same ESP work great.
I took your advice and used the TelnetToSerial example and set the client to send the data to the modified TelnetToSerial example.
The part I am really battling with is taking the received data into a char array.
Code: Select allchar tmpArray[21];
client.read(&tmpArray,sizeof(tmpArray));

OR
Code: Select allclient.readBytesUntil('\0', received_buff, MAX_READING_BUFFER);
Serial.println(tmpArray);

to split it into separate variables so I can compare them, like this :
Code: Select allsscanf(tmpArray, "%d,%d,%d,%d,%d",&gway,&hcode,&pcode,&oocode,&devcode);


Is this the correct place to get the received data from ?
Code: Select allfor(i = 0; i < MAX_SRV_CLIENTS; i++){
    if (serverClients[i] && serverClients[i].connected()){
      if(serverClients[i].available()){
        //get data from the telnet client and push it to the UART
        while(serverClients[i].available()) Serial.write(serverClients[i].read());

I tried this :
Code: Select all   char *tmpArray[21];
      while(serverClients[i].available()) Serial.write(serverClients[i].readBytesUntil('\0', &tmpArray, sizeof(tmpArray)));

and receive this error from the compiler:
Code: Select allexit status 1
no matching function for call to 'WiFiClient::read(char, char* (*)[21], unsigned int)'


I look forward to any help with this probably simple issue.

Den

PS.
Heres the server sode fo far:
Code: Select all#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";

//how many clients should be able to telnet to this ESP8266
#define MAX_SRV_CLIENTS 2


//WiFiServer server(23);
WiFiServer server(5252);
WiFiClient serverClients[MAX_SRV_CLIENTS];

void setup() {
  //Serial1.begin(115200);
  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());

  //start UART and the server
 // Serial.begin(115200);
  server.begin();
  //server.setNoDelay(true);
 
  Serial1.print("Ready! Use 'telnet ");
  Serial1.print(WiFi.localIP());
  Serial1.println(" 23' to connect");
  delay(10000);
}

void loop() {
  uint8_t i;
  //check if there are any new clients
  if (server.hasClient()){
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      //find free/disconnected spot
      if (!serverClients[i] || !serverClients[i].connected()){
        if(serverClients[i]) serverClients[i].stop();
        serverClients[i] = server.available();
        Serial.print("New client: "); Serial.print(i);
        Serial.print(" : Client data : ");
        break;
      }
    }
    //no free/disconnected spot so reject
    if ( i == MAX_SRV_CLIENTS) {
       WiFiClient serverClient = server.available();
       serverClient.stop();
        Serial.println("Connection rejected ");
    }
  }
  //check clients for data
  for(i = 0; i < MAX_SRV_CLIENTS; i++){
    if (serverClients[i] && serverClients[i].connected()){
      if(serverClients[i].available()){
        //get data from the telnet client and push it to the UART
        while(serverClients[i].available()) Serial.write(serverClients[i].read());
      }
    }
  }

 
  //check UART for data
  if(Serial.available()){
    size_t len = Serial.available();
    uint8_t sbuf[len];
    Serial.readBytes(sbuf, len);
    //push UART data to all connected telnet clients
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      if (serverClients[i] && serverClients[i].connected()){
        serverClients[i].write(sbuf, len);
        delay(1);
      }
    }
  }
}


And the Client:
Code: Select all//#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 = 5252;
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);
  Serial.setDebugOutput(true);
  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());
  WiFi.printDiag(Serial);
  Serial.printf("Started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
// print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

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);
  client.println(allDroid);
 
  Serial.println("Disconnecting...");
  client.stop();
  memset(allDroid, 0, sizeof(allDroid));
  delay(2000);
}