adafruit / Adafruit_CircuitPython_ESP32SPI

ESP32 as wifi with SPI interface
MIT License
101 stars 74 forks source link

Arduino RP2040 connect wifi UDP - Multicast group not working #139

Open manpowre opened 2 years ago

manpowre commented 2 years ago

CircuitPython version

Adafruit 7.0 latest, and master branch (yeah I compiled master).

esp32 wifi chip:
Firmware vers. bytearray(b'1.4.8\x00')

Code/REPL

import time
import board
import busio
from digitalio import DigitalInOut
import adafruit_requests as requests
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
from adafruit_esp32spi import adafruit_esp32spi
import neopixel
from rainbowio import colorwheel
import gc
from secrets import secrets

UDP_IN_ADDR="224.1.1.1"
UDP_IN_PORT = 5500

UDP_TIMEOUT = 20

esp32_cs = DigitalInOut(board.CS1)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)

spi = busio.SPI(board.SCK1, board.MOSI1, board.MISO1)

esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
socket.set_interface(esp)

s_in = socket.socket(type=socket.SOCK_DGRAM)
s_in.settimeout(UDP_TIMEOUT)

if esp.status == adafruit_esp32spi.WL_IDLE_STATUS:
    print("ESP32 found and in idle mode")
print("Firmware vers.", esp.firmware_version)
print("MAC addr:", [hex(i) for i in esp.MAC_address])
print("Connecting to AP...")
while not esp.is_connected:
    try:
        esp.connect_AP(secrets["ssid"], secrets["password"])
    except RuntimeError as e:
        print("could not connect to AP, retrying: ", e)
        continue
print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi)
#esp.ifconfig = (IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS, DNS_SERVER)
time.sleep(1)
IP_ADDR = esp.pretty_ip(esp.ip_address)
print("ip:", esp.ip_address)
print("My IP address is", esp.pretty_ip(esp.ip_address))
print("udp in addr: ", UDP_IN_ADDR, UDP_IN_PORT)

socketaddr_udp_in = socket.getaddrinfo(UDP_IN_ADDR, UDP_IN_PORT)[0][4] 
s_in.connect(socketaddr_udp_in, conntype=esp.UDP_MODE) 
print("connected local UDP")

while True:
    data = s_in.recv(1205)
    if len(data)>=1:
        data=data.decode('utf-8')
        print(len(data), data)

Python on Ubuntu:
# Untitled - By: svein - fre. okt. 15 2021

import socket
import time

def run(group, port):
    MULTICAST_TTL = 40
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
    sock.sendto(b'from multicast_send.py: ' +
                f'group: {group}, port: {port}'.encode(), (group, port))
if __name__ == '__main__':
    while True:
        #run('224.1.1.1', 5500)
        run('192.168.2.147', 5500)
        time.sleep(1)

Behavior

ESP32 found and in idle mode Firmware vers. bytearray(b'1.4.8\x00') MAC addr: ['0xd0', '0xb1', '0x78', '0xa8', '0xcc', '0x84'] Connecting to AP... Connected to zone RSSI: -47 ip: bytearray(b'\xc0\xa8\x02\x93') My IP address is 192.168.2.147 udp in addr: 224.1.1.1 5500 connected local UDP -->>> NO PACKETS recieved

ESP32 found and in idle mode Firmware vers. bytearray(b'1.4.8\x00') MAC addr: ['0xd0', '0xb1', '0x78', '0xa8', '0xcc', '0x84'] Connecting to AP... Connected to zone RSSI: -47 ip: bytearray(b'\xc0\xa8\x02\x93') My IP address is 192.168.2.147 udp in addr: 192.168.2.147 5500 connected local UDP 56 from multicast_send.py: group: 192.168.2.147, port: 5500 56 from multicast_send.py: group: 192.168.2.147, port: 5500 56 from multicast_send.py: group: 192.168.2.147, port: 5500 56 from multicast_send.py: group: 192.168.2.147, port: 5500

Description

So Ive been testing the wifi part of the circuitpython on the Arduino rp2040 connect. The circuitpython esp32 wifi integration doesnt allow to set a static IP (Im gonna make a separate bug report on this), and I want to be able to communicate with the rp2040 chip through wifi and send datapackets, but since I dont know the IP adress, I figured I could send a multicast IP instead. On my ubuntu, I do recieve these packages on same multicast IP and port. so the router is out of the question.(As I made a multicast data logger from my rp2040 chip to get debug data from it).

The UDP reciever works with the IP adress of the wifi chip eg. 192.168.2.147:5500, but NOT the multicast adress 224.1.1.1:5500.

I hope you guys can fix this.. and the dhcp=True/False issue aswell.

Additional information

No response

ladyada commented 2 years ago

not surprising as we dont know anyone who has used UDP - the library has strong TCP/SSL support which is what most people use. if you find a fix for the bug please submit a PR!

sullivanst commented 2 years ago

I'm trying to work out if I can implement a discovery protocol like mDNS, DNS-SD or SSDP so I'm interested too. From spellunking through this repo and the one for the NINA firmware library it seems that to set the socket to multicast mode you have to tweak your connect to something like this:

    UDPMULTI_MODE = const(3)
    s_in.connect(socketaddr_udp_in, conntype=UDPMULTI_MODE)

Hope to find out whether that actually works soon.

anecdata commented 2 years ago

What version of ESP32SPI library are you using? Static IP was added last month in 4.1.0 https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/releases/tag/4.1.0 (should work with both the Arduino and Adafruit versions of NINA firmware)

mattwTS commented 2 years ago

I'm still super early in the whole project, only downloaded the libraries this week so I assume I'm recent enough to have that. I can also set a static DHCP lease if I need to.

I'm hoping to get this thing working in SmartThings and haven't worked out the flow that expects to pick up a device yet & the few examples I've found so far have a discovery stage, so first stab was to look at the plausibility of that.

sullivanst commented 2 years ago

Oops I guess I was logged in with my work account in the iOS app for the previous comment.

It didn't work, and I can see why.

In adafruit_esp32spi.socket_connect are the following lines:

        self.socket_open(socket_num, dest, port, conn_mode=conn_mode)
        if conn_mode == self.UDP_MODE:
            # UDP doesn't actually establish a connection
            # but the socket for writing is created via start_server
            self.start_server(port, socket_num, conn_mode)
            return True

It looks like socket_open will fail if conntype isn't one of TCP_MODE, UDP_MODE or TLS_MODE because those are the only values the nina-fw firmware will accept; conntype=3 is only valid for the call to start_server.

The nina-fw doesn't appear to offer any way to set socket options directly so I think the only way to get multicast UDP working would be to tweak socket_connect to know some way about when it should call socket_open with conntype=1 and start_server server with conntype=3, whether that's by passing in conntype=3, by adding a multicast flag (defaults false of course), or by identifying a multicast address and conntype=1 (not so feasible if host is a name).