I want to send data, via WiFi, from my ESP32 to my laptop, but am not having success in doing so. It just always fails to connect, the failure code coming back to my ESP32 sketch. The C# program running on the laptop, waiting for a connection request, runs merrily along and never thinks any request is coming in.
I have internet cable which is connected to a router. The router is connected to a WiFi station. My laptop has its internet access via WiFi connection with that WiFi station.
I've written a C# Windows Form application that sets itself up to listen for a connection request. That application seems to be working properly, in that it keeps checking for whether or not a connection request has been made and, if it has, it will respond by making the connection and then accepting any data coming in across that connection.
I've also written a sketch for the ESP32 that makes a connection with the WiFi station and then attempts to establish a connection through to my laptop. It does indeed succeed in establishing the connection with the WiFi station, but it always fails to connect through to the laptop. The C# program running on the laptop never gets an indication that anything is attempting to connect to it.
Most of the code that I'm using, both for the C# program and the ESP32 sketch comes from examples and sources I've come across on the Internet, most significantly from a YouTube video:
https://www.youtube.com/watch?v=c9M8QWsYGRM
But it's not working. I'm hoping someone might be able to figure out what I'm doing wrong.
In my ESP32 sketch I call a function I call WiFinit, as follows:
Code: Select all
bool WifiInit()
{
WiFi.mode(WIFI_STA);
WiFi.disconnect();
if (esp_now_init() == ESP_OK)
{
return true;
}
else
{
ESP.restart();
}
return false;
}
I then call a function, ConnectToWiFiServerStation(), which attempts to find the desired WiFi Station (by name and password) and to connect to it...
Code: Select all
esp_now_peer_info_t TheWiFiServerStation;
bool ConnectToWiFiServerStation(String DesiredWiFiServerStationName)
{
#define CHANNEL 3
int8_t scanResults = WiFi.scanNetworks();
bool TheWiFiServerStationFound = false;
memset(&TheWiFiServerStation, 0, sizeof(TheWiFiServerStation));
if (scanResults == 0)
{
Serial.println("In ConnectToWiFiServerStation: No WiFi devices in AP Mode found");
}
else
{
for (int i = 0; i < scanResults; ++i)
{
String SSID = WiFi.SSID(i);
int32_t RSSI = WiFi.RSSI(i);
String BSSIDstr = WiFi.BSSIDstr(i);
delay(10);
// Check if the current device is DesiredWiFiServerStationName
if (SSID.indexOf(DesiredWiFiServerStationName) == 0)
{
// It's the one we're looking for.
// Get BSSID => Mac Address of the TheWiFiServerStation
int mac[6];
if ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) )
{
for (int ii = 0; ii < 6; ++ii )
{
TheWiFiServerStation.peer_addr[ii] = (uint8_t) mac[ii];
}
}
TheWiFiServerStation.channel = CHANNEL; // This is 3. That number was specified
// in the example code I located
// but I have no clue what that means or
// or if there is significance to that number.
TheWiFiServerStation.encrypt = 0; // No encryption
TheWiFiServerStationFound = true;
break;
}
}
}
if (TheWiFiServerStationFound)
{
// Add TheWiFiServerStation as peer if it has not been added already.
bool isPaired = PairWithWiFiStation();
if (isPaired)
{
// pair success or already paired.
Serial.println("In ConnectToWiFiServerStation: SUCCESSFULLY PAIRED with TheWiFiServerStation");
}
else
{
// Failed to pair this machine with target
Serial.println("In ConnectToWiFiServerStation: FAILED TO PAIR with TheWiFiServerStation");
}
}
else
{
Serial.println("TheWiFiServerStation Not Found, trying again.");
}
// clean up ram
WiFi.scanDelete();
esp_now_register_send_cb(OnDataSent);
return TheWiFiServerStationFound;
}
A couple of notes about it, though:
A CHANNEL number is specified, in:
Code: Select all
TheWiFiServerStation.channel = CHANNEL;
That ConnectToWiFiServerStation() function also calls another function, PairWithWiFiStation(), as follows:
Code: Select all
bool PairWithWiFiStation()
{
if (TheWiFiServerStation.channel == CHANNEL)
{
// check if the peer exists
bool exists = esp_now_is_peer_exist(TheWiFiServerStation.peer_addr);
if ( exists)
{
// TheWiFiServerStation already paired.
Serial.println("Already Paired");
return true;
}
else
{
// TheWiFiServerStation not paired, attempt pair
esp_err_t addStatus = esp_now_add_peer(&TheWiFiServerStation);
if (addStatus == ESP_OK)
{
// Pair success
Serial.println("Pair success");
return true;
}
else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT)
{
// How did we get so far!!
Serial.println("ESPNOW Not Init");
return false;
}
else if (addStatus == ESP_ERR_ESPNOW_ARG)
{
Serial.println("Invalid Argument");
return false;
}
else if (addStatus == ESP_ERR_ESPNOW_FULL)
{
Serial.println("Peer list full");
return false;
}
else if (addStatus == ESP_ERR_ESPNOW_NO_MEM)
{
Serial.println("Out of memory");
return false;
}
else if (addStatus == ESP_ERR_ESPNOW_EXIST)
{
Serial.println("Peer Exists");
return true;
} else
{
Serial.println("Not sure what happened");
return false;
}
}
}
else
{
// No TheWiFiServerStation found to process
Serial.println("IN PairWithWiFiStation() : No TheWiFiServerStation found to pair\n");
return false;
}
}
So far, so good.
After the successful call to ConnectToWiFiServerStation() I then try to connect THROUGH that WiFi connection to get to my laptop. I've determined that the IP of my laptop is 192.168.0.106, and I've set up the C# program running on my laptop to be accessing port 1000,i.e. checking that port for incoming connection requests. That number, 1000, for the port, again comes from the sample code I've been basing my programs in.
Is 1000 a valid port number? Should I be using something different? I tried 80, having recalled that number from some code I wrote years ago, but that also didn't work.
Anyway, my current code uses 1000 as the port, both in the ESP32 sketch and the C# program.
Here's what I'm doing in my ESP32 sketch AFTER the ConnectToWiFiServerStation() succeeds:
Code: Select all
const uint16_t port = 1000;
const char * host = "192.168.0.106";// MY COMPUTER !!!
WiFiClient ThisESP32_Wifi_Client;
if (ThisESP32_Wifi_Client.connect(host, port) == 0)
{
Serial.print("Connection failed\n");
}
else
{
Serial.print("Connection SUCCESS!\n");
}
I should note that when I run this sketch on my ESP32 I have previously started up the Windows App that's running there waiting for connection requests, so I think it SHOULD succeed in connecting. But it never does.
One thought that comes to mind is this: The successful connection that's established with the WiFi station is done using:
Code: Select all
esp_now_peer_info_t TheWiFiServerStation;
So that TheWiFiServerStation is what knows about the WiFi server. But when I attempt to connect to the laptop via:
Code: Select all
WiFiClient ThisESP32_CAM_Wifi_Client;
if (ThisESP32_CAM_Wifi_Client.connect(host, port) == 0)
BIG QUESTION
How does the WiFiClient object know to use the connection that's been set up and is connected to the WiFi Station?
I don't see anything in the WiFiClient.h file, like an init() method, that would tell it about the WiFiServerStation, or even maybe speficy what "channel" it should use.
SOMETHING WRONG WITH MY SKETCH?
Does it look like there's something wrong with my ESP32 sketch? Am I connecting incorrectly to the WiFi station? Conecting incorrectly to the laptop? Using an ivalid channel number?
IF EVERYTHING'S OK WITH THE SKETCH
Let's take a look at my C# code, the imprortant part of which is in ClassWiFiServer:
Code: Select all
class ClassWiFiServer
{
static string ThisComputerIPAddress = "192.168.0.106";
public event MessageEventHandler Message;
public delegate void MessageEventHandler(ClassWiFiServer sender, string Data);
// Server Control
public IPAddress ServerIP = IPAddress.Parse(ThisComputerIPAddress);
static public int ServerPort = 1000; // NO idea why this number is used.
public TcpListener myserver;
public Thread Comthread;
public bool IsListening = true;
// Clients
private TcpClient client = null;
private StreamReader clientdata = null;
public ClassWiFiServer() // CONSTRUCTOR
{
myserver = new TcpListener(ServerIP, ServerPort);
myserver.Start();
Comthread = new Thread(new ThreadStart(Hearing));
Comthread.Start();
}
private void Hearing() // Listening for incoming connection requests
{
while (!IsListening == false)
{
if (myserver.Pending() == true) // Pending means that a connection request is pending
{
// It NEVER GETS HERE, never recognizes that my ESP32 sketch is trying to connect with this computer
client = myserver.AcceptTcpClient();
clientdata = new StreamReader(client.GetStream());
}
if (clientdata != null)
{
try
{
Message?.Invoke(this, clientdata.ReadLine());
}
catch (Exception ex)
{
}
}
Thread.Sleep(10);
}
}
}
It sets up the Hearing() function (I would have called it "Listening" which waits for myserver.Pending() to be true, which appears to mean that someone is trying to connect into it.
But Pending() always remains false, even though my ESP32 sketch is running and has connected to the WiFi station and is attempting to connect through to the computer, using the correct ISP and port number.
By running this C# program in debug mode I can see that it does repeatedly get to the
Code: Select all
if (myserver.Pending() == true)
So what am I doing wrong? Is there something that I'm misunderstanding, something that I set up incorrectly?