UDP over wifi between arduino uno R4 WiFi and win11 pc not working

I've been trying to get this connection established for some time, using several different AI-generated sketches but have been unable to get anything to work. UDP is working on other scripts between the arduino & NTP servers though. I have both the arduino & pc on the same wireless router, on the same subnet on a Mikrotik router running torch. I never see any UDP traffic show up from either end. both are connecting to the router.

arduino code:

#include <WiFiS3.h>
#include <WiFiUdp.h>
#include "arduino-secrets.h"
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;
int status = WL_IDLE_STATUS;

WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  while (!Serial) {};


  // Connect to Wi-Fi
  while (status != WL_CONNECTED) {
    status = WiFi.begin(ssid, pass);
    delay(5000);
  }

  server.begin();
  printWifiStatus();
}

void loop() {
  // Listen for incoming Windows 11 clients
  WiFiClient client = server.available();

  if (client) {
    Serial.println("New Windows client connected!");

    // Transfer packet data
    client.println("Hello from Arduino UNO R4 WiFi!");

    // Close the connection to allow a clean reset
    client.stop();
    Serial.println("Packet sent and client disconnected.");
  }
}

void printWifiStatus() {
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
}

Python code Running on Thonny (if that makes a difference):

import socket

# Replace with your Arduino's IP address printed to the Serial Monitor
arduino_ip = '192.168.88.118' 
arduino_port = 80

try:
    # Create a TCP socket
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect((arduino_ip, arduino_port))
    
    # Receive the packet data
    data = client_socket.recv(1024)
    print("Received Packet:", data.decode('utf-8'))

except Exception as e:
    print(f"Error: {e}")
finally:
    client_socket.close()

The arduino makes it through the setup, but prints nothing else on the serial console after that. The python console gives me the error message: Error: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
Both sketch & script were generated in the same request for an example of how to transfer several bytes between machines. I updated the WiFiS3 firmware to 0.6.0, which seems to be the latest.

In addition to the base R4 WiFi, I have a 3/5" touchscreen display & a custom board attached to D10-D13 which work on my main script. I will be using this code to transfer a timestamp from the arduino to the PC to be used as a file name for a 4 byte data packet to be stored on the pc. Initially I had the pc connected to a wired ethernet connection on the same subnet but when I couldn't see any UDP packets making it thouugh the router, I shifted to wireless.

I tried several other options, other UDP code, POST, RUDP, nothing works. (I don't really care what protocol I end up with, the 2 machines will be same subnet & if I loose a packet it won't be the end of the world.)

Almost all my experience has been in hardware design for over 50 years & needless to say going from assembly language back then to C now is being quite a learning curve!

I'd say that this is giving me grey hair if I didn't already have it!
Peace, Pat

Have a look at the following examples from within the IDE:

File -> Examples -> WiFiS3 -> WiFiUdpSendReceiveString.ino

File -> Examples -> WiFiS3 -> WifiUdpNtpClient.ino

It seems the R4 does things a little differently.

Are you using TCP or UDP?

SuferTim, I'm trying to use UDP because it was recommended as being easier to implement than TCP but I don't really care. I'll look into the library examples as BitSeeker suggested.

UDP is easier. No connection to maintain. Give those a try.

I have Python code also. I use it with Ubuntu and RPi OS.

Edit: Last I used Windows, you must modify the firewall to let the UDP port through.

Your Python code is TCP but your Arduino code uses a UDP library. You can't mix the two. UDP and TCP are not compatible with each other. Also, you talk of a 'connection', UDP is connectionless. UDP works by sending the data to the other IP address and forgetting about it. TCP makes a connection, sends the data and checks for correct delivery.

I can't help with Python, but there are UDP examples in the Arduino IDE.

Of course not. First of all, never trust 100% what the AI ​​tells you. If you use UDP, there's no "connection," and what you're doing on the PC side is a TCP connection (and port 80 is typically an HTTP port...), so there's clearly a lot of misunderstanding.
Choosing between UDP and TCP isn't a matter of "alternative": if you just need to send a message (aka a "packet") and forget about it including if the target receives it, UDP is good. The "packet" format and size can be part of kinda basic protocol you can/must define, there's no "standard". You can even send "broadcast" packets/messages, to be received by any device listening for that UDP port, and that's what you do when the sender doesn't need to know (or doesn't know yet) the target IP address. I did that for a power meter I installed on my PV inverter, to send current power to a device inside home to be displayed and stored.

But if you instead need to establish a "connection" and make sure the other party is "alive and kicking", TCP connections are the best, choosing the port and communication protocol. It gives you better performance and reliability but requires a bit more planning.

That said, it's now up to you (not the AI) to decide, depending on what you need to do with this communication channel, along with the format and data type. If you plan to use UDP, you need to make sure you use the same protocol on both ends and the same "packet" format. I can try to show you some UDP code snippets and definitions for both the sender and receiver, but you should first stop using AI unless you understand what you're talking about.

It's included -- unnecessarily -- but not used. For the recent R4 board, WiFiS3.h is effectively just

#include "WiFi.h"

and that then includes several subcomponents automatically

#include "WiFiClient.h"
#include "WiFiServer.h"
#include "WiFiUdp.h"
#include "WiFiSSLClient.h"

(The ESP32 version of WiFi.h has the first three, but not that last WiFiSSLClient.h)

Manually including WiFiUdp.h of course doesn't hurt and signals intent, but that only make sense if you actually use it.

I was going to comment on the AI-generated code, but frankly, the library example code, like WiFiUdpSendReceiveString has the same whoppers

It's pointless to assign the macros defined in arduino_secrets.h to variables. Just use the macros: WiFi.begin(SECRET_SSID, SECRET_PASS)

!Serial fails immediately on R4 WiFi, which uses the ESP32 chip. This never waits.

Conversely, this always waits. But with WiFiS3, WiFi.begin is a blocking call -- it has the wait loop that everyone manually codes at the end. So that will take maybe a few seconds for it to connect successfully or a little longer to time out (if the password is wrong, for example), and then you will always wait ten more seconds for nothing, every time you restart.

The stripped-down AI-generated code in the OP only pointlessly waits five seconds, then doesn't use UDP at all.

As mentioned, one advantage of UDP is broadcast -- so you don't necessarily have to hard-code your peer(s) address. Everyone agrees on a port, and they talk to each other semi-reliably.

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

WiFiUDP udp;
IPAddress myIP, broadcastIP;
constexpr uint16_t PORT{ 2390 };  // used in WiFiS3 UDP examples

struct : public String {
  bool drain(Stream &s, int size) {
    remove(0);
    char buf[64];
    while (size > 0) {
      int r = s.readBytes(buf, sizeof(buf));
      if (r > 0) {
        if (r > size) r = size;
        if (concat(buf, r)) {
          size -= r;
          continue;
        }
      }
      return false;
    }
    return true;
  }
} payload;

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

  WiFi.begin(SECRET_SSID, SECRET_PASS);
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("WiFi failed to connect: ");
    Serial.println(SECRET_SSID);
    for (;;);
  }

  myIP = WiFi.localIP();
  Serial.print("WiFi address: ");
  Serial.println(myIP);
  auto mask = static_cast<uint32_t>(WiFi.subnetMask()) ^ -1;
  broadcastIP = IPAddress{ static_cast<uint32_t>(myIP) | mask };
  Serial.print("Broadcast address: ");
  Serial.println(broadcastIP);

  if (!udp.begin(PORT)) {
    Serial.print("UDP init failed");
    for (;;);
  }

  payload.reserve(100);
}

void loop() {
  static auto last = millis();
  int packetSize = udp.parsePacket();
  if (packetSize) {
    Serial.print("received: ");
    Serial.print(packetSize);
    Serial.print(" from: ");
    Serial.println(udp.remoteIP());
    payload.drain(udp, packetSize);
    Serial.println(payload);
  }

  auto now = millis();
  if (now - last < 2500) {
    return;
  }
  last = now;

  payload.remove(0);
  payload += "R4 WiFi ";
  payload += myIP.toString();
  payload += " at: ";
  payload += now;
  udp.beginPacket(broadcastIP, PORT);
  udp.write(payload.c_str(), payload.length());
  if (udp.endPacket()) {
    Serial.print("UDP broadcast sent at: ");
    Serial.println(now);
  } else {
    Serial.print("UDP failed to send at: ");
    Serial.println(now);
    for (;;);
  }
}

This computes the broadcast address based on your assigned IP after connecting to WiFi. The top of the loop listens for a packet. If one is found, the content is drained and displayed. If you don't do this, you won't see another. Then periodically, it sends a broadcast.

One potential complication with a desktop computer is multiple network interfaces. So if you start broadcasting from there, you'd have to pick one (or do multiple). It's easier to listen for everything; and in your use case, you don't even need to send anything back.