I'm building an android app that should talk to an ESP32. The setup is the following:
- The ESP32 configures itself as an access point
- The ESP32 regularly sends a connection request via UDP broadcast
- The APP connects the phone to the WiFi of the ESP32 (Credentials hardcoded for the moment)
- The APP receives the connection request
Here is where I am stuck:
- The APP answers to the sender (The ESP32) with an acknowledgement. Now ESP32 and APP should know each other.
I joined the WiFi with my laptop and watch the traffic via WireShark. All broadcast messages (and lots of other stuff) are visible, however, the APP never sends out an UDP packet.
I am very sure that the ESP32 side works, everytime I send udp packets from my laptop via python, they arrive at the ESP. I setup the Accespoint like this:
const IPAddress gateWay(192, 168, 1, 1);
const IPAddress localIP(192, 168, 1, 1);
const IPAddress subnet(0, 0, 0, 0);
void setup(){
Serial.begin(115200);
// sdUtils.begin();
imu.begin(FILTER_UPDATE_RATE_HZ);
// configure esp as access point
WiFi.softAP(SSID, PASS);
//WiFi.config(localIP, gateWay, subnet);
WiFi.softAPConfig(localIP, gateWay, subnet);
Serial.println(udp.begin(2255));
}
void loop(){
// initiate connection
while (!client.connected()) {
Serial.println("Initializing connection");
// broadcast IP via UDP broadcast
String ipAddress = WiFi.localIP().toString();
udp.beginPacket(WiFi.broadcastIP().toString().c_str(), 2255);
udp.println(ipAddress);
udp.endPacket();
// parse answer
int packetSize;
unsigned long startTime = millis();
do {
packetSize = udp.parsePacket();
} while (!packetSize && (millis() - startTime) < 5000);
if (packetSize) {
// read answer which is IP adress
char buffer[packetSize];
Serial.println(udp.remoteIP().toString());
udp.read(buffer, packetSize);
String phoneIP = buffer;
Serial.println(phoneIP);
// Establish a TCP connection to the phone
client.connect(phoneIP.c_str(), 8080);
// Send data to the phone
client.println("Hello from the ESP32!");
} else {
Serial.println("Server dindn't answer...");
}
}
}
This is how I try to send UDP packages in my android app:
public class Connectivity {
private final Context context;
private WifiManager wifiManager;
private Handler handler;
private DatagramSocket socket;
public Connectivity(Context context) {
this.context = context;
this.handler = new Handler(Looper.getMainLooper());
try {
wifiManager = (WifiManager) this.context.getSystemService(Context.WIFI_SERVICE);
socket = new DatagramSocket(2255);
socket.setBroadcast(true);
} catch (IOException e) {
Log.e(TAG, "failed to create UDP socket", e);
}
}
public void connectSensor(String ssid, String password) {
// make sure wifi is enabled
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true);
}
establishConAfterQ(ssid, password);
}
public void disconnectSensor() {
if (wifiManager.isWifiEnabled()) {
wifiManager.disconnect();
wifiManager.setWifiEnabled(false);
}
}
public void start() {
new Thread(this::receive).start();
}
public void receive() {
while (true) {
byte[] buffer = new byte[128];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try {
socket.receive(packet);
} catch (IOException e) {
Log.e(TAG, "Failed to receive UDP packet", e);
continue;
}
String message = new String(buffer, 0, packet.getLength());
Log.d(TAG, "Received UDP packet: " + message.replace("\n", "") + " from IP address: " + packet.getAddress().toString() + " at port: " + packet.getPort());
// Send the answer
Log.i(TAG, "Sending Answer");
String answer = "Heureka it works!!";
byte[] data = answer.getBytes();
DatagramPacket response = new DatagramPacket(data, data.length, packet.getAddress(), packet.getPort());
try {
socket.send(response);
} catch (IOException e) {
Log.e(TAG, "Failed to send UDP packet", e);
}
}
}
The function where I connect to the wifi looks like the following:
private void establishConAfterQ(String ssid, String password) {
WifiEnterpriseConfig config = new WifiEnterpriseConfig();
config.enableTrustOnFirstUse(true);
config.setPassword(password);
WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
.setSsid(ssid)
.setWpa2Passphrase(password)
.build();
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setNetworkSpecifier(specifier)
.build();
ConnectivityManager connectivityManager = (ConnectivityManager) this.context.getSystemService(Context.CONNECTIVITY_SERVICE);
// Register a callback to listen for the connection result
ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(android.net.Network network) {
super.onAvailable(network);
Log.d(TAG, "Connected to WiFi network: " + ssid);
}
@Override
public void onUnavailable() {
super.onUnavailable();
Log.d(TAG, "Failed to connect to WiFi network: " + ssid);
}
};
// Request the network connection
connectivityManager.requestNetwork(networkRequest, networkCallback);
}
Weirdly enough, everything worked nicely for a brief time, when I disconnected the phone from the computer and logged into the wifi hotspot manually. However, I could not reproduce this behaviouir thereafter.
Am I missing something like a configuration for the connection so that I cannot send UDP commands? I have searched Google quite intensively, however I haven't found anything.
UPDATE I found out that I can send udp packages from android to the broadcast address (255.255.255.255) or to the IP address of the phone hosting the APP. However, I cannot reach any IP other than those (or at least I haven't found one). So is there maybe a hidden firewall built into android?
Thanks for any help!