Skip to content

Instantly share code, notes, and snippets.

@todbot
Last active October 22, 2023 13:30
Show Gist options
  • Save todbot/877b2037b6c7b2c4c11545c83c6e2182 to your computer and use it in GitHub Desktop.
Save todbot/877b2037b6c7b2c4c11545c83c6e2182 to your computer and use it in GitHub Desktop.
UDP sender and receiver in CircuitPython
# udp_recv_code.py -- receive UDP messages from any receiver, can be another CircuitPython device
# 24 Aug 2022 - @todbot / Tod Kurt
# cribbing from code at https://github.com/adafruit/circuitpython/blob/main/tests/circuitpython-manual/socketpool/datagram/ntp.py
import time, wifi, socketpool
from secrets import secrets
print("Connecting to WiFi...")
wifi.radio.connect(ssid=secrets['ssid'],password=secrets['password'])
print("my IP addr:", wifi.radio.ipv4_address)
pool = socketpool.SocketPool(wifi.radio)
udp_host = str(wifi.radio.ipv4_address) # my LAN IP as a string
udp_port = 5005 # a number of your choosing, should be 1024-65000
udp_buffer = bytearray(64) # stores our incoming packet
sock = pool.socket(pool.AF_INET, pool.SOCK_DGRAM) # UDP socket
sock.bind((udp_host, udp_port)) # say we want to listen on this host,port
print("waiting for packets on",udp_host, udp_port)
while True:
size, addr = sock.recvfrom_into(udp_buffer)
msg = udp_buffer.decode('utf-8') # assume a string, so convert from bytearray
print(f"Received message from {addr[0]}:", msg)
# udp_send_code.py -- send UDP messages to specified receiver, can be another CircuitPython device
# 24 Aug 2022 - @todbot / Tod Kurt
# cribbing from code at https://github.com/adafruit/circuitpython/blob/main/tests/circuitpython-manual/socketpool/datagram/ntp.py
import time, wifi, socketpool
from secrets import secrets
print("Connecting to WiFi...")
wifi.radio.connect(ssid=secrets['ssid'],password=secrets['password'])
print("my IP addr:", wifi.radio.ipv4_address)
pool = socketpool.SocketPool(wifi.radio)
udp_host = "192.168.1.123" # LAN IP of UDP receiver
udp_port = 5005 # must match receiver!
my_message = "hi there from CircuitPython!"
sock = pool.socket(pool.AF_INET, pool.SOCK_DGRAM) # UDP, and we'l reuse it each time
num = 0
while True:
# stick a nubmer on the end of the message to show progress and conver to bytearray
udp_message = bytes(f"{my_message} {num}", 'utf-8')
num += 1
print(f"Sending to {udp_host}:{udp_port} message:", udp_message)
sock.sendto(udp_message, (udp_host,udp_port) ) # send UDP packet to udp_host:port
time.sleep(1)
@PaulskPt
Copy link

PaulskPt commented Feb 4, 2023

I used your receiver example (only modified to use settings.toml instead of the former secrets.py.
Script used:

# udp_recv_code.py -- receive UDP messages from any receiver, can be another CircuitPython device
# 24 Aug 2022 - @todbot / Tod Kurt
# cribbing from code at https://github.com/adafruit/circuitpython/blob/main/tests/circuitpython-manual/socketpool/datagram/ntp.py

import time, wifi, socketpool, os
print("Connecting to WiFi...")
wifi.radio.connect(ssid=os.getenv("CIRCUITPY_WIFI_SSID"), password=os.getenv("CIRCUITPY_WIFI_PASSWORD"))
print("my IP addr:", wifi.radio.ipv4_address)
pool = socketpool.SocketPool(wifi.radio)

# I, @PaulskPt, used for udp_host erroneously: os.getenv("MULTICAST_GROUP")
udp_host = str(wifi.radio.ipv4_address) # my LAN IP as a string  
udp_port = int(os.getenv("MULTICAST_PORT"))  # a number of your choosing, should be 1024-65000
udp_buffer = bytearray(64)  # stores our incoming packet

sock = pool.socket(pool.AF_INET, pool.SOCK_DGRAM) # UDP socket
sock.bind((udp_host, udp_port))  # say we want to listen on this host,port

print("waiting for packets on",udp_host, udp_port)
while True:
    size, addr = sock.recvfrom_into(udp_buffer)
    msg = udp_buffer.decode('utf-8')  # assume a string, so convert from bytearray
    print(f"Received message from {addr[0]}:", msg)

Resulting in the following output:

Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XGPS2,-85.700840,38.354860,156.1102,147.9949,0.0001,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0
Received message from 192.168.1.96: XATT2,148.0,5.9,0.5,-0.0000,0.0000,-0.0000,0.0,-0.0,-0.0,-0.01,0

Btw: the data is from a situation when the airplane was on the ground, parked. Engine running.

There is no packet reception when I use port 49707 or 49003 instead of port 49002.
Port 49707 is used for UDP datagrams (BECN and DATA packets) to Multicast group '169.255.1.1'. The DATA packets contain
data elements that I selected inside the X-Plane 12 setup

@PaulskPt
Copy link

PaulskPt commented Feb 5, 2023

Update:
I receive the DATA packets when I enter in X-Plane settings for 'General Data Output' IP Address, the IP address: 192.168.1.110, which is the IP Address of the CPY device running the script, and Port 49707. But I get a 'UnicodeError' because the received UDP packets are packed.
When I modify the line 'msg = udp_buffer.decode('utf-8')' into: 'msg = udp.buffer' then the following output is received (only one packet copied below):

Received message from 192.168.1.96: bytearray(b'DATA*\x03\x00\x00\x00\x00\x00\x00\x00:\xb9\x989\xa9\xdf\x999\xd5E\x979\x00\xc0y\xc4\x00\x00\x00\x00\x1d\x13\xb19\xe5\x14\xae9\x11\x00\x00\x00e\xc6\xbc@8\xb5\t?\x1e\xff\x13C\x00\xc0y\xc4\xcb\x10\x19')

So, I think my problem is solved!
Again thank you for your rapid responses!

@aceg00
Copy link

aceg00 commented Apr 26, 2023

Thanks, this is very helpful!

@aceg00
Copy link

aceg00 commented Apr 26, 2023

By the way, line 22 of udp_recv_code.py

msg = udp_buffer.decode('utf-8')

should be

msg = udp_buffer[:size].decode('utf-8')

or otherwise you might print unwanted things:)

@PaulskPt
Copy link

@aceg00 thank you for your response and advice.

@daanzu
Copy link

daanzu commented Oct 22, 2023

@todbot You should consider updating this with the above correction from @aceg00 . The current code is a real foot gun. Many thanks for this gist nonetheless though!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment