Networking
Group Assignment -
This is our EECS section page for it - I did not participate it in this time.
https://fab.cba.mit.edu/classes/MAS.863/EECS/Week11.html
For this week I made a my desktop send commands to the pico w to run on 2 leds. Initially I wanted to control a RGB Led but as you will later see that did not work out.

I gathered my parts which were the Raspberry Pi Pico W, 3 1k Ohms 1206 format resistors, and one RED LEG 4PLCC SMD from our inventory made by Cree. The Pico has a inbuilt bluetooth module which is the large silver plate. This is why it doesn’t need an antenna. This does Bluetooth Low Energy (BLE).
I have no experience in coding bluetooth / networking related things, so ChatGPT helped me a lot here - in terms of the coding and understanding. I first needed to make my board in KiCad.
Then I did the typical routing puzzle. Now here is the interesting part, when drawing the edge cuts, I was thinking since I am just using a few pins of the pico, and they are all adjacent ones on the top left, there is no need to make my PCB for the entire Pico. So what I did was make the PCB just mount to the needed pins, and I thought that would look elegant and minimal.
I milled the board and I found it the finish to not be as clean as it usually is - maybe the the end mill wasn’t that sharp? Anyway I found a screwdriver nearby to deburr the copper off.

I liked how that looked. I then soldered all the components.

But it didn’t work! Even a simple blink code wasn’t working. I checked 2 things, 1) was there any shorts; there wasn’t. 2) was the pico sending power on the GPIO pins, and yes it was sending 3.3V. Therefore, my RGB Led wasn’t working, and I know I had it in the right orientation.

I then tried to desolder the LED, but then I accidentally pulled a trace out! I put a green and red SMD LED
This worked! I am not using the third trace, but that was because the distance between the GND was too large for me to plop a LED. So for the rest of this assignment I continued with this setup.
Now for the coding, I mainly relied on ChatGPT. This is our conversation that contains the code as well: https://chatgpt.com/share/6925bbb9-8c98-8007-a271-111e64f4f0f1
I haven’t used micro python before so I followed these guides:
https://projects.raspberrypi.org/en/projects/get-started-pico-w/1
https://projects.raspberrypi.org/en/projects/getting-started-with-the-pico/5
https://www.raspberrypi.com/documentation/microcontrollers/micropython.html
Here is my final code that runs on the Pico.
import bluetooth
from machine import Pin
import time
green_led = Pin(1, Pin.OUT)
red_led = Pin(2, Pin.OUT)
# Nordic UART UUIDs
UART_SERVICE_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
UART_RX_UUID = bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E") # Write
UART_TX_UUID = bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E") # Notify
UART_SERVICE = (
UART_SERVICE_UUID,
(
(UART_TX_UUID, bluetooth.FLAG_NOTIFY,),
(UART_RX_UUID, bluetooth.FLAG_WRITE,),
),
)
# Pico W BLE IRQ event codes:
_IRQ_CENTRAL_CONNECT = 1
_IRQ_CENTRAL_DISCONNECT = 2
_IRQ_GATTS_WRITE = 3
class BLEController:
def __init__(self):
self.ble = bluetooth.BLE()
self.ble.active(True)
# Register UART service: returns ((tx_handle, rx_handle),)
((self.tx_handle, self.rx_handle),) = self.ble.gatts_register_services((UART_SERVICE,))
self.ble.irq(self._irq)
self._advertise()
def _advertise(self):
name = b"PicoLED"
adv = (
b"\x02\x01\x06" +
bytes([len(name) + 1, 0x09]) + name +
b"\x11\x07" + bytes(UART_SERVICE_UUID)
)
self.ble.gap_advertise(100_000, adv_data=adv, connectable=True)
print("Advertising as PicoLED...")
def _irq(self, event, data):
if event == _IRQ_CENTRAL_CONNECT:
print("Connected")
elif event == _IRQ_CENTRAL_DISCONNECT:
print("Disconnected")
self._advertise()
elif event == _IRQ_GATTS_WRITE:
# Client wrote to RX characteristic
handle = data[1]
if handle == self.rx_handle:
cmd = self.ble.gatts_read(self.rx_handle).decode().strip()
print("Received:", cmd)
self._handle_command(cmd)
def _handle_command(self, cmd):
if cmd == "green":
green_led.value(1)
elif cmd == "red":
red_led.value(1)
elif cmd == "off":
green_led.value(0)
red_led.value(0)
# Start BLE LED controller
ble_controller = BLEController()
while True:
time.sleep(1)

I worked with ChatGPT to understand how does BLE work, and what is the protocol. So I covered the GATT format, and I will now walk through the basic flow of the code.
UART_SERVICE_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
UART_RX_UUID = bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E") # Write
UART_TX_UUID = bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E") # Notify
These allow us to setup multiple services, the RX would be to read the LED status, and the TX is to Notify of a connection/advertising.
This is the GATT protocol
UART_SERVICE = (
UART_SERVICE_UUID,
(
(UART_TX_UUID, bluetooth.FLAG_NOTIFY,),
(UART_RX_UUID, bluetooth.FLAG_WRITE,),
),
)
Then the code advertises
adv = (
b"\x02\x01\x06" +
bytes([len(name) + 1, 0x09]) + name +
b"\x11\x07" + bytes(UART_SERVICE_UUID)
)Which contains the Flags, name (PicoLED), and the SERVICE ID. Then when there is an event we can use gatts_read to parse the rx, and based on that can turn on the green led, red led, or turn both of them off.
Then on my desktop side, I wanted to use python to send commands. So with GPT, we used a library called Bleak, which is “is a GATT client software, capable of connecting to BLE devices acting as GATT servers.” Then here is the code, we are using the RX UUID:
6E400002-B5A3-F393-E0A9-E50E24DCCA9E
import asyncio
from bleak import BleakScanner, BleakClient
UART_RX = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
async def main():
print("Scanning for PicoLED...")
devices = await BleakScanner.discover()
pico = None
for d in devices:
if d.name == "PicoLED":
pico = d
break
if not pico:
print("PicoLED not found!")
return
print("Found:", pico)
async with BleakClient(pico.address) as client:
print("Connected!")
for i in range(100):
print(f"Blink {i+1}")
# Turn LED on
await client.write_gatt_char(UART_RX, b"red")
await asyncio.sleep(0.3)
# Turn LED off
await client.write_gatt_char(UART_RX, b"off")
await asyncio.sleep(0.3)
await client.write_gatt_char(UART_RX, b"green")
await asyncio.sleep(0.3)
print("Done blinking!")
asyncio.run(main())
print("Scanning for PicoLED...")
devices = await BleakScanner.discover()
pico = None
for d in devices:
if d.name == "PicoLED":
pico = d
break
if not pico:
print("PicoLED not found!")
return
print("Found:", pico)This part tries to find the PicoLED, and the following code is used to send commands
await client.write_gatt_char(UART_RX, b"red")asyncio allows commands to run async - so it doesn’t block other processes. Is it it working, we can see on the terminal - the python is sending blink commands, and on Thonny we are receiving them!
Acknowledgements + Files
Here are the files, and as usual thank you to Anthony for helping me - would be quite lost without him.







