ESP hotspot, on connect send TCP packets

Hey guys!

For a project, I want to use an ESP to set up a hotspot that broadcasts some data when another ESP connects to the hotspot.

I have made some code for the hotspot. And when I connect with my laptop and send a TCP packet I get the correct response. But I would like to send the data when another ESP connects.

I can't really find any guides or codes that show this use case. All guides just connect both ESP to a wifi point.

Code on the Hotspot:

#include <Arduino.h>
#include "wifiHandler.h"
#include <eepromHandler.h>
WiFiUDP UDP;

byte macRecieved[6];
uint8_t sizeMac = 17;
uint8_t sizeResponse = 2;
char lastTwoChars[2];
const char* SSID  = "netwerkNaam";
const char* PSW = "netwerkWachtwoord";

unsigned int localUdpPort = 4210;  // local port to listen on
char  incomingPacket[255];  // buffer for incoming packets
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];

const int port = 23;
#define MAX_SRV_CLIENTS 25
WiFiServer server(port);
WiFiClient serverClients[MAX_SRV_CLIENTS];

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  wifiHandler hotspot;
  hotspot.setupSoftAp();
  eepromHandler eeprom;

  eeprom.saveData(SSID, PSW, PARAMETER_SIZE_IN_BYTES);
  eeprom.dumbData();

  server.begin();
  server.setNoDelay(true);  

}

void loop() {
   // wait for a new client:
  WiFiClient client = server.available();
  if (client) { 
    Serial.printf("Client connected, IP: %s,port: %s", client.remoteIP().toString().c_str(), client.remotePort());
    // clead out the input buffer:
    while (client.connected()){
      if (client.available()){
      //String line = client.readStringUntil('\r');
      // Read incoming message
      char inChar = client.read();
      // Echo input on Serial monitor
      Serial.write(inChar);       
      }
      client.printf("%s / %s", SSID, PSW);
      client.stop();
      Serial.println("Client disconnected.");
    }   
  }
}

connect to the 'hotspot' esp from other esp the same way as you connect to any other WiFi network

It looks like you are waiting for a TCP client to connect to the TCP server you set up on port 23. Is that what your other ESP (32? 8266?) does when it connects to the WiFi access point?

ESP8266? ESP32?

I haven't tested it yet, but you could try registering a callback function for when a Station connects to the AP:

void stationConnected(system_event_id_t event);

void setup() {
  .
  .
  WiFi.onEvent(stationConnected, SYSTEM_EVENT_AP_STACONNECTED);
  .
  .
}

void loop() {
}

void IRAM_ATTR stationConnected(system_event_id_t event) {
  // do stuff here when station connects
}

Like I said, haven't tested it yet. But, it complies for ESP32.

The other ESP8266 connects fine to the hotspot, but went it connects it needs to send a TCP packet, so that the hotspot knows there is a connection. I want to skip that part

Tested it on an Adafruit ESP32 Huzzah and it works. The event handler function is called whenever a Station connects to the AP. Although, somewhere along the line getting to ver 2.0.1 of the ESP32 core, the API calls were changed. With this later core they're now:

void stationConnected(arduino_event_id_t event);

void setup() {
  .
  .
  WiFi.onEvent(stationConnected, ARDUINO_EVENT_WIFI_AP_STACONNECTED);
  .
  .
}

void loop() {
}

void IRAM_ATTR stationConnected(arduino_event_id_t event) {
  // do stuff here when station connects
}

Are these Callbacks available in the esp8266WiFi library?

I found this online, but not sure if that is correct.

Give it a try.

I have made this now, and it sort of works, the callback is being done:
But I keep getting:

Client connected(IP unset)

When a device connects to it.

#include <ESP8266WiFi.h>

const char* SSID  = "netwerkNaam";
const char* PSW   = "netwerkWachtwoord";
WiFiEventHandler connectAp;

bool ledState;
const int port = 23;
WiFiServer server(port);

void setup()
{
  Serial.begin(115200);
  Serial.println();

  pinMode(LED_BUILTIN, OUTPUT);

  connectAp = WiFi.onSoftAPModeStationConnected([](const WiFiEventSoftAPModeStationConnected & event)
  {
    Serial.printf("Client connected\r\n");
    WiFiClient client = server.available();
    Serial.printf("%s\r\n", client.remoteIP().toString().c_str());
    client.printf("%s / %s", SSID, PSW);
  });

  WiFi.softAP(SSID);
  server.begin();
}

void loop()
{
  digitalWrite(LED_BUILTIN, ledState);
  ledState = !ledState;
  delay(250);
}

I think that is because there isn't a TCP connection so there is no "remoteIP".

You could send a UDP packet to the broadcast address (255.255.255.255) but if the new station doesn't have an IP address assigned it will not get the broadcast.

Does the "Soft AP" provide DHCP services so the 'station' can get an IP address? If you want to send a UDP packet or establish a TCP connection you will need to find out the IP address. Maybe the IP stack will let you see the routing table and you can figure out from that when a new IP address becomes available.

Yes, it does. But, the IP Address hasn't yet been assigned when the OP's callback is invoked. The code below works on an ESP32. The ESP8266 API appears to be different.

#include "Arduino.h"
#include <WiFi.h>

void handleEvent(arduino_event_id_t event, arduino_event_info_t info);

const char *ssid = "AccessPointESP32";

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.println("Configuring access point...");
  WiFi.softAP(ssid);

  WiFi.onEvent(handleEvent, ARDUINO_EVENT_WIFI_AP_STACONNECTED);
  WiFi.onEvent(handleEvent, ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED);

  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
}

void loop() {
}

void IRAM_ATTR handleEvent(arduino_event_id_t event, arduino_event_info_t info) {
  uint8_t mac[6];
  IPAddress stationIP;

  switch (event) {
    case ARDUINO_EVENT_WIFI_AP_STACONNECTED:
      memcpy(mac, info.wifi_ap_staconnected.mac, 6);
      Serial.printf("Station Connected to AP, Station MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3],
                    mac[4], mac[5]);
      break;

    case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED:
      stationIP = info.wifi_ap_staipassigned.ip.addr;
      Serial.print("My Station Assigned IP: ");
      Serial.println(stationIP);
      break;

    default:
      break;
  }
}

1 Like

why just don't wait for the WiFi to connect and then make the request in setup() as all basic examples show?

have you tried esp now for communicating with other esp devices?

I am trying this out, I think an ESP32 is better suited for the task.
But I am getting this error:

Is it looking for this file?

I have the Arduino wifi lib, v1.2.7

Check your Arduino IDE / ESP32 Package versions and board selection. The code from Post #11 compiles with Arduino v1.8.15, ESP32 v3.0.2, and Adafruit ESP32 Feather.

?? If I go to the board manager, the max is 2.0.1.

Sorry. Correct, 2.0.1.

I made this code:

#include <WiFi.h>

const char* ssid = "hello";

void WiFiEvent(WiFiEvent_t event) {
  Serial.printf("[WiFi-event] event: %d\n", event);
  if (event == ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED) {
    Serial.print("Obtained IP address: ");
    Serial.println(WiFi.localIP());
    Serial.print("Great");
  } else if (event == ARDUINO_EVENT_WIFI_AP_STACONNECTED) {
    Serial.print("station connected to AP");
  }
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Start");
  // delete old config
  WiFi.disconnect(true);
  WiFi.mode(WIFI_AP);
  delay(3000);
  WiFi.softAPConfig(IPAddress(192,168,1,1), IPAddress(192,168,1,1), IPAddress(255,255,255,0));
  WiFi.softAP(ssid);
  WiFi.onEvent(WiFiEvent);
  delay(3000);
  
}

void loop() {
  // put your main code here, to run repeatedly:

}

Based on: this example

When an devices connect to the AP, it should print a 15 ->
ARDUINO_EVENT_WIFI_AP_STACONNECTED < a station connected to ESP32 soft-AP

But I'm getting:

[WiFi-event] event: 11
[WiFi-event] event: 10
[WiFi-event] event: 12
station connected to AP[WiFi-event] event: 14
Obtained IP address: 0.0.0.0

12 ARDUINO_EVENT_WPS_ER_PIN < ESP32 station wps pin code in enrollee mode
14 ARDUINO_EVENT_WIFI_AP_STOP < ESP32 soft-AP stop

this makes not a lot of sense to me.

Below are the event type values in the latest ESP32 core. When you label the events with the right meanings they seem to make sense.

[WiFi-event] event: ARDUINO_EVENT_WIFI_AP_STOP
[WiFi-event] event: ARDUINO_EVENT_WIFI_AP_START
[WiFi-event] event: ARDUINO_EVENT_WIFI_AP_STACONNECTED,
station connected to AP
[WiFi-event] event: ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED
Obtained IP address: 0.0.0.0

Note: When you display the IP address you are displaying the Ardiuno's local address, not the address assigned to the newly connected station. Try info.wifi_ap_staipassigned.ip.addr instead of localIP(). You will need to add the 'info' argument to your event handler.

0	ARDUINO_EVENT_WIFI_READY
1	ARDUINO_EVENT_WIFI_SCAN_DONE,
2	ARDUINO_EVENT_WIFI_STA_START,
3	ARDUINO_EVENT_WIFI_STA_STOP,
4	ARDUINO_EVENT_WIFI_STA_CONNECTED,
5	ARDUINO_EVENT_WIFI_STA_DISCONNECTED,
6	ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE,
7	ARDUINO_EVENT_WIFI_STA_GOT_IP,
8	ARDUINO_EVENT_WIFI_STA_GOT_IP6,
9	ARDUINO_EVENT_WIFI_STA_LOST_IP,
10	ARDUINO_EVENT_WIFI_AP_START,
11	ARDUINO_EVENT_WIFI_AP_STOP,
12	ARDUINO_EVENT_WIFI_AP_STACONNECTED,
13	ARDUINO_EVENT_WIFI_AP_STADISCONNECTED,
14	ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED,
15	ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED,
16	ARDUINO_EVENT_WIFI_AP_GOT_IP6,
17	ARDUINO_EVENT_WIFI_FTM_REPORT,
	ARDUINO_EVENT_ETH_START,
	ARDUINO_EVENT_ETH_STOP,
	ARDUINO_EVENT_ETH_CONNECTED,
	ARDUINO_EVENT_ETH_DISCONNECTED,
	ARDUINO_EVENT_ETH_GOT_IP,
	ARDUINO_EVENT_ETH_GOT_IP6,
	ARDUINO_EVENT_WPS_ER_SUCCESS,
	ARDUINO_EVENT_WPS_ER_FAILED,
	ARDUINO_EVENT_WPS_ER_TIMEOUT,
	ARDUINO_EVENT_WPS_ER_PIN,
	ARDUINO_EVENT_WPS_ER_PBC_OVERLAP,
	ARDUINO_EVENT_SC_SCAN_DONE,
	ARDUINO_EVENT_SC_FOUND_CHANNEL,
	ARDUINO_EVENT_SC_GOT_SSID_PSWD,
	ARDUINO_EVENT_SC_SEND_ACK_DONE,
	ARDUINO_EVENT_PROV_INIT,
	ARDUINO_EVENT_PROV_DEINIT,
	ARDUINO_EVENT_PROV_START,
	ARDUINO_EVENT_PROV_END,
	ARDUINO_EVENT_PROV_CRED_RECV,
	ARDUINO_EVENT_PROV_CRED_FAIL,
	ARDUINO_EVENT_PROV_CRED_SUCCESS,
	ARDUINO_EVENT_MAX

Do you have a link to the git of this? (Just Ctrl + left mouse)n platformio takes me to the declaration.