adafruit / Adafruit_CircuitPython_ESP32SPI

ESP32 as wifi with SPI interface
MIT License
103 stars 75 forks source link

New function get_remote_data() to expose NINA getRemoteData() #161

Closed anecdata closed 2 years ago

anecdata commented 2 years ago

Expose NINA getRemoteData() function https://github.com/adafruit/nina-fw/blob/d73fe315cc7f9148a0918490d3b75430c8444bf7/main/CommandHandler.cpp#L779 This returns the IP address and port number of the remote host. Especially useful for UDP server.

Adafruit CircuitPython 7.2.0 on 2022-02-24; Adafruit PyPortal with samd51j20 UDP server code:

import time
import board
from digitalio import DigitalInOut
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
from adafruit_esp32spi import adafruit_esp32spi
from secrets import secrets

PORT = 5000

spi = board.SPI()

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

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

esp.connect_AP(secrets["ssid"], secrets["password"])
print("Connected:", "RSSI =", esp.rssi)

print("Create UDP Server Socket")
s = socket.socket(type=socket.SOCK_DGRAM)
esp.start_server(PORT, s.socknum, conn_mode=1)  # UDP_MODE = const(1)
while True:
    numbytes_avail = esp.socket_available(s.socknum)
    if numbytes_avail:
        print(numbytes_avail)
        bytes_read = esp.socket_read(s.socknum, numbytes_avail)
        print(bytes_read)

        remote_data = esp.get_remote_data(s.socknum)
        remote_ip = esp.pretty_ip(remote_data["ip_addr"])
        remote_port = remote_data["port"]
        print("REMOTE:", remote_ip, remote_port)

Result:

code.py output:
Connected: RSSI = -60
Create UDP Server Socket
12
b'Hello, world'
REMOTE: 192.168.5.32 14290
12
b'Hello, world'
REMOTE: 192.168.5.32 59860
12
b'Hello, world'
REMOTE: 192.168.5.32 47857

CPython UDP client code:

#!/usr/bin/env python3
import time
import socket

# edit host and port to match server
HOST = "192.168.6.39"
PORT = 5000
TIMEOUT = 5
INTERVAL = 5

while True:
    print("Create UDP Client Socket")
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.settimeout(TIMEOUT)

    size = s.sendto(b"Hello, world", (HOST, PORT))
    print("Sent", size, "bytes")

    s.close()

    time.sleep(INTERVAL)
tekktrik commented 2 years ago

Is there any benefit to returning a dictionary as opposed to a tuple of the two values?

anecdata commented 2 years ago

Not particularly, I was just mimicking the return from network_data, which is also a dictionary with an "ip_addr" element. Readability vs. byte count? I don't have a strong opinion either way. At the next layer down (sockets), there is a commonly-used tuple for address which is (host, port), but in that case host is a string like "localhost" or "127.0.0.1". In the present case, the "ip_addr" value for both network data and get_remote_datais a bytes. The only other return in the module that isn't just a single value is the return from scan_networks, which is a list of dictionaries.