# ESP-NOW in CircuitPython

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/138/731/medium800thumb/circuitpython_enowdemo.jpg?1754347143)

ESP-NOW is a connectionless communication protocol developed by Espressif that allows ESP32 and ESP8266 devices to communicate directly with each other without needing a WiFi router or access point. It's useful for low-power, low-latency communication between microcontrollers. Find out more details on [Espressif's site here](https://www.espressif.com/en/solutions/low-power-solutions/esp-now) and check out [their API documentation](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/network/esp_now.html).

ESP-NOW creates a peer-to-peer network where devices can send data packets directly to each other using their MAC addresses. Devices can broadcast messages to specific recipients or to all nearby devices without needing any central infrastructure.

Give it a try -- it's great for props, sensor-networks, remote controls, and mesh communications.

https://youtu.be/OL2lAx2N-Dw

![](https://cdn-learn.adafruit.com/assets/assets/000/138/732/medium800/circuitpython_etr1.jpg?1754347165)

## Parts

You can use ESP-NOW in CircuitPython and Arduino on most ESP32, ESP32-S2, ESP32-S3 boards. ESP8266 boards also support ESP-NOW.

Here are some example boards, all of which can communicate with each other using ESP-NOW:

### Adafruit QT Py ESP32-S3 WiFi Dev Board with STEMMA QT

[Adafruit QT Py ESP32-S3 WiFi Dev Board with STEMMA QT](https://www.adafruit.com/product/5426)
The ESP32-S3 has arrived in QT Py format - and what a great way to get started with this powerful new chip from Espressif! With dual 240 MHz cores, WiFi and BLE support, and native USB, this QT Py is great for powering your IoT projects.

The ESP32-S3&nbsp;is a highly-integrated,...

In Stock
[Buy Now](https://www.adafruit.com/product/5426)
[Related Guides to the Product](https://learn.adafruit.com/products/5426/guides)
![Angled shot of small purple microcontroller.](https://cdn-shop.adafruit.com/640x480/5426-00.jpg)

### Adafruit ESP32-S3 Reverse TFT Feather

[Adafruit ESP32-S3 Reverse TFT Feather](https://www.adafruit.com/product/5691)
Like Missy Elliot, we like to ["put our [Feather] down, flip it and reverse it"](https://www.youtube.com/watch?v=cjIvu7e6Wq8)&nbsp;and that's exactly what we've done with this new development board. It's basically our **<a...></a...>**

Out of Stock
[Buy Now](https://www.adafruit.com/product/5691)
[Related Guides to the Product](https://learn.adafruit.com/products/5691/guides)
![Video of a rectangular microcontroller with a TFT display. A pink manicured finger presses each of the tactile buttons, which are recognized on the TFT display.](https://cdn-shop.adafruit.com/product-videos/640x480/5691-05.jpg)

### Adafruit ESP32-S2 Feather with BME280 Sensor - STEMMA QT

[Adafruit ESP32-S2 Feather with BME280 Sensor - STEMMA QT](https://www.adafruit.com/product/5303)
What's Feather-shaped and has an ESP32-S2 WiFi module? What has a STEMMA QT connector for I2C devices and a built in ambient sensor? What has your favorite Espressif WiFi microcontroller and lots of Flash and RAM memory for your next IoT project? What will make your next IoT project sensor...

In Stock
[Buy Now](https://www.adafruit.com/product/5303)
[Related Guides to the Product](https://learn.adafruit.com/products/5303/guides)
![Angled view of rectangular microcontroller with WiFi module.](https://cdn-shop.adafruit.com/640x480/5303-18.jpg)

### Adafruit ESP32-S2 Feather - 4 MB Flash + 2 MB PSRAM

[Adafruit ESP32-S2 Feather - 4 MB Flash + 2 MB PSRAM](https://www.adafruit.com/product/5000)
What's Feather-shaped and has an ESP32-S2 WiFi module? What has a STEMMA QT connector for I2C devices? What has your favorite Espressif WiFi microcontroller and lots of Flash and RAM memory for your next IoT project? What will make your next IoT project flyyyyy?

That's right -...

In Stock
[Buy Now](https://www.adafruit.com/product/5000)
[Related Guides to the Product](https://learn.adafruit.com/products/5000/guides)
![Angled shot of rectangular microcontroller.](https://cdn-shop.adafruit.com/640x480/5000-12.jpg)

### Adafruit Metro ESP32-S3 with 16 MB Flash 8 MB PSRAM

[Adafruit Metro ESP32-S3 with 16 MB Flash 8 MB PSRAM](https://www.adafruit.com/product/5500)
What's Metro-shaped and has an ESP32-S3&nbsp;WiFi module? What has a STEMMA QT connector for I2C devices and a Lipoly charger circuit? What has your favorite Espressif WiFi microcontroller and lots of memory for your next IoT project?

That's right - it's the new...

In Stock
[Buy Now](https://www.adafruit.com/product/5500)
[Related Guides to the Product](https://learn.adafruit.com/products/5500/guides)
![Angled shot of black, credit-card-sized dev board.](https://cdn-shop.adafruit.com/640x480/5500-10.jpg)

### Adafruit ESP32-S3 Reverse TFT with w.FL Antenna

[Adafruit ESP32-S3 Reverse TFT with w.FL Antenna](https://www.adafruit.com/product/6303)
Like Missy Elliot, we like to ["put our [Feather] down, flip it and reverse it"](https://www.youtube.com/watch?v=cjIvu7e6Wq8)&nbsp;and that's exactly what we've done with this new development board. It's basically our **<a...></a...>**

Out of Stock
[Buy Now](https://www.adafruit.com/product/6303)
[Related Guides to the Product](https://learn.adafruit.com/products/6303/guides)
![Angled Shot of the Adafruit ESP32-S3 Reverse TFT with w.FL Antenna.](https://cdn-shop.adafruit.com/640x480/6303-01.jpg)

# ESP-NOW in CircuitPython

## Code ESP-NOW

In CircuitPython, the aptly named `espnow` module provides ESP-NOW functionality. The&nbsp;`wifi` module is also used during setup to turn on the radio and set the channel to 6, where ESP-NOW magic happens.

The first step is to go to the Learn Guide for your board and update the TinyUSB bootloader for CircuitPython 10 and later. For example, set up the Feather ESP32-S2 with BME280 Sensor by going&nbsp;[here](https://learn.adafruit.com/adafruit-esp32-s2-feather/update-tinyuf2-bootloader-for-circuitpython-10-4mb-boards-only) and then installing CircuitPython 10.

For a second board, set up the ESP32-S2 Reverse TFT Feather to read messages sent to it from the first board.&nbsp;&nbsp;

Primary: Thanks to Tod Kurt for posting this [simple example](https://gist.github.com/todbot/19a2823bc2318ae03203d3adf43b3078) upon which this code is based.

## Setup

To use ESP-NOW in CircuitPython you'll import `espnow` and `wifi`.

`import espnow import wifi`

Then, turn on the WiFi radio and start an access point on channel 6, which is the channel used by ESP-NOW. Immediately turn off the WiFi access because we aren't using it, we just needed to hack the channel.

`wifi.radio.start_ap(" ", "", channel=6, max_connections=0)`

`wifi.radio.stop_ap()`

Create an instance of ESP-NOW:

`e = espnow.ESPNow()`

```auto
import espnow
import wifi

# Initialize WiFi, set to channel 6 where ESP-NOW lives
wifi.radio.start_ap(" ", "", channel=6, max_connections=0)
wifi.radio.stop_ap()

# Create ESP-NOW instance
e = espnow.ESPNow()
```

## Peer List & Send Modes

There are two main modes of communications in ESP-NOW: Broadcast Mode and Peer-to-Peer Mode.

## Broadcast Mode

In Broadcast Mode, you can send messages without adding any specific peers -- any ESP-NOW device within range that's listening will receive the broadcast. This is done by specifying a special MAC address of `\xff\xff\xff\xff\xff\xff` and appending it to the `peer`&nbsp;list.

Then, in the main loop, `e.send("Hello everyone", peer)` sends a message to anyone listening.

```auto
import time
import wifi
import espnow

wifi.radio.start_ap(" ", "", channel=6, max_connections=0)
wifi.radio.stop_ap()

e = espnow.ESPNow()
peer = espnow.Peer(mac=b'\xff\xff\xff\xff\xff\xff', channel=6)  # broadcast
e.peers.append(peer)


while True:
    e.send("Hello everyone", peer)
    time.sleep(2)
```

## Peer-to-Peer Mode

In Peer-to-Peer mode, you'll explicitly add devices as peers using their MAC addresses.

```auto
# Add a peer device (replace with actual MAC address)
peer = b'\xaa\xbb\xcc\xdd\xee\xff'
e.peers.append(peer)
```

Primary: To find out the MAC address on your receiver boards, run this set of commands (from the REPL or as a **code.py**):

```auto
# find out MAC address
import wifi
wifi.radio.enabled=True
print("mac is:", wifi.radio.mac_address)
```

![](https://cdn-learn.adafruit.com/assets/assets/000/138/774/medium800/temperature___humidity_mac.jpg?1754414239)

## Receive Data
To receive the message being sent by the sender, run this code on your receiver boards:

```auto
import time
import wifi
import espnow

wifi.radio.start_ap(" ", "", channel=6, max_connections=0)
wifi.radio.stop_ap()

e = espnow.ESPNow()


while True:
    if not e:  # wait for a packet
        continue
    packet = e.read()
    print("packet message:", packet.msg)
    print("full packet:", packet)
```

With the sender running, you'll see a response in the REPL and on the TFT of the receiver like this:

`packet message: b'Hello everyone'`

`full packet: ESPNowPacket(mac=b'|\xff\xee\xdd\xcc&', msg=b'Hello everyone', rssi=-14, time=1348919)`

![](https://cdn-learn.adafruit.com/assets/assets/000/138/776/medium800/temperature___humidity_receivescreen.jpg?1754414473)

![](https://cdn-learn.adafruit.com/assets/assets/000/138/777/medium800thumb/temperature___humidity_basic.jpg?1754414915)

## Full Sender Code
```auto
# ESP-NOW Sender
import time
import wifi
import espnow

wifi.radio.start_ap(" ", "", channel=6, max_connections=0)
wifi.radio.stop_ap()

e = espnow.ESPNow()

# broadcast to everyone:
peer = espnow.Peer(mac=b'\xff\xff\xff\xff\xff\xff', channel=6) 

# or set specific mac addresses for peers:
# peer = espnow.Peer(mac=b'\xaa\xbb\xcc\xdd\xee\xff', channel=6)

e.peers.append(peer)

message = "Hello everyone"

my_mac_str = ":".join([f"{b:02x}" for b in wifi.radio.mac_address])
print("Starting sender on MAC:", my_mac_str)

while True:
    try:
        e.send(message, peer)
        print("sent packet: ", message)
    except Exception as ex:
        print("exception:", ex)

    time.sleep(2)
```

## Full Receiver Code
```auto
# ESP-NOW Receiver
import time
import wifi
import espnow

wifi.radio.start_ap(" ", "", channel=6, max_connections=0)
wifi.radio.stop_ap()

e = espnow.ESPNow()

my_mac_str = ":".join([f"{b:02x}" for b in wifi.radio.mac_address])
print("Starting receiver on MAC:", my_mac_str)

while True:
    if not e:  # wait for a packet
        continue

    packet = e.read()
    mac_str = ":".join([f"{b:02x}" for b in packet.mac])

    # Decode bytes to string for clean output
    decoded_message = packet.msg.decode('utf-8')

    print("received message:", decoded_message)
    print("from MAC:", mac_str)
    print("full packet:", packet)

    time.sleep(0.3)
```

# ESP-NOW in CircuitPython

## Sensor Data over ESP-NOW

![](https://cdn-learn.adafruit.com/assets/assets/000/138/778/medium800thumb/temperature___humidity_bme.jpg?1754415432)

Using the same setup from the previous page, the sender code can be updated to include sensor data from the on-board BME280 temperature, humidity, pressure sensor on the Feather ESP32-S2 BME280.

Here's the updated sender code:

```auto
# ESP-NOW Sender w BME280
import time
import board
import wifi
import espnow
from adafruit_bme280 import basic as adafruit_bme280

i2c = board.I2C()  # uses board.SCL and board.SDA
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)

wifi.radio.start_ap(" ", "", channel=6, max_connections=0)
wifi.radio.stop_ap()

e = espnow.ESPNow()

# broadcast to everyone:
peer = espnow.Peer(mac=b'\xff\xff\xff\xff\xff\xff', channel=6)

e.peers.append(peer)

my_mac_str = ":".join([f"{b:02x}" for b in wifi.radio.mac_address])
print("Starting sender on MAC:", my_mac_str)

while True:
    try:
        # Convert temperature to string
        sensor_msg = f"T:{bme280.temperature:.1f}C H:{bme280.relative_humidity:.1f}% P:{bme280.pressure:.1f}hPa"
        e.send(sensor_msg, peer)
        print("sent packet: ", sensor_msg)
    except Exception as ex:
        print("exception:", ex)

    time.sleep(2)
```

## Receivers

The same receiver code applies, only the message being sent has changed.

```auto
# ESP-NOW Receiver
import time
import wifi
import espnow

wifi.radio.start_ap(" ", "", channel=6, max_connections=0)
wifi.radio.stop_ap()

e = espnow.ESPNow()

my_mac_str = ":".join([f"{b:02x}" for b in wifi.radio.mac_address])
print("Starting receiver on MAC:", my_mac_str)

while True:
    if not e:  # wait for a packet
        continue

    packet = e.read()
    mac_str = ":".join([f"{b:02x}" for b in packet.mac])

    # Decode bytes to string for clean output
    decoded_message = packet.msg.decode('utf-8')

    print("received message:", decoded_message)
    print("from MAC:", mac_str)
    print("full packet:", packet)

    time.sleep(0.3)
```

# ESP-NOW in CircuitPython

## It's an ESP-NOW Party

![](https://cdn-learn.adafruit.com/assets/assets/000/138/733/medium800thumb/circuitpython_enowdemo.jpg?1754347199)

One of the best things about ESP-NOW is that one can add lots of boards to the party with very little extra work!

### Multiple Receivers

For example, add second receiver board with identical code to the first and both will get the same message from the sender containing the BME280 sensor data.

### Multiple Senders

Yep, you guessed it! Put sender code on an additional board and all receivers will get the individual messages from both senders.

https://youtu.be/OL2lAx2N-Dw

## Transcievers Too?!

"But, what about _transceivers?"_, you may ask. No problem, ESP-NOW's got you covered there, too.

You can write code that will allow multiple boards to both send and receive messages amongst each other. This can be in broadcast mode, where no specific MAC addresses are added to the peer list, or in very targeted peer-to-peer modes if you have specific transceiver pairings/groupings in mind.&nbsp;

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/ESP-NOW_basics/espnow_transceiver.py

## How It Works

### Library Import

First we import libraries.

```auto
import time
import wifi
import espnow
import board
import digitalio
import displayio
import terminalio
from adafruit_display_text import label
from adafruit_display_shapes.rect import Rect
```

### Board Setup and Identification

Each board can be set to its own unique ID:

`DEVICE_ID = "board_A"  # Change this for each board: board_A, board_B, board_C, board_D`

When you power up a board, it announces itself:

`board_A board starting - MAC: xx:xx:xx:xx:xx:xx`

### Display Setup
```auto
display = board.DISPLAY
group = displayio.Group()
background_rect = Rect(0, 0, display.width, display.height, fill=0x000000)
group.append(background_rect)
```

### Button Config

We configure the `board.BUTTON (D0)` to act as an input with pull up resistor.

```auto
button = digitalio.DigitalInOut(board.BUTTON)
button.direction = digitalio.Direction.INPUT
button.pull = digitalio.Pull.UP
```

### ESP-NOW Setup

This is the "channel switching hack" - we briefly start then stop an access point to force the WiFi radio onto channel 6. Then we create an ESP-NOW object and add a broadcast peer (the `\xff\xff\xff\xff\xff\xff` address means "send to everyone").

```auto
wifi.radio.start_ap(" ", "", channel=6, max_connections=0)
wifi.radio.stop_ap()
e = espnow.ESPNow()
peer = espnow.Peer(mac=b'\xff\xff\xff\xff\xff\xff', channel=6)
e.peers.append(peer)
```

### Color Coding

Each board ID maps to a hex color value. When we receive a message, we'll look up the sender and use their color.

```auto
SENDER_COLORS = {
    "board_A": 0x32FF32,  # Lime green
    "board_B": 0x00FFFF,  # Cyan
    "board_C": 0xC8A2C8,  # Lilac
    "board_D": 0xFFFFFF   # White
}
```

### Color Detect Function

This function parses incoming messages like "board\_B 5" and returns cyan (board\_B's color). If the sender isn't recognized, it defaults to white.

```auto
def get_sender_color(rx_message):
    for board_id in SENDER_COLORS:
        if rx_message.startswith(board_id):
            return SENDER_COLORS[board_id]
    return WHITE
```

### Display Labels

Instead of one label saying "TX'd: 5", we use two labels:

- `sent_label`: Shows "TX'd: " in red
- `sent_counter_label`: Shows just the number in the sender's color

The anchored\_position=(80, 65) for the counter positions it right after the "TX'd: " text.

```auto
sent_label = label.Label(terminalio.FONT, text="TX'd: --", color=TOMATO, ...)
sent_counter_label = label.Label(terminalio.FONT, text="", color=SENDER_COLORS.get(DEVICE_ID, WHITE), ...)
```

### Main Loop

We check if the button is pressed (`not button.value` because of pull-up) and enough time has passed since the last press (debouncing prevents multiple triggers from one press).

```auto
if not button.value and (current_time - last_button_time > button_debounce):
    message_count += 1
    message = f"{DEVICE_ID} {message_count}"
```

### Message Send

Next we try to send the message. Success shows "...\>" for 0.5 seconds. Errors show "xxx" for 2 seconds.

```auto
try:
    e.send(message, peer)
    # Update display...
    status_reset_time = current_time + 0.5
    status_needs_reset = True
except Exception as ex:
    # Show error...
    status_reset_time = current_time + 2.0
    status_needs_reset = True
```

### Status Update

We update the display status if a message has come in or gone out. The ESP-NOW object's `read()` method returns a packet if one is available, or `None` if not. We:

1. Check it's not from ourselves (avoid echo)
2. Decode the message from bytes to string
3. Determine the sender's color
4. Update the split labels (prefix stays red, message gets sender color)

```auto
if e:
    packet = e.read()
    if packet:
        sender_mac = format_mac(packet.mac)
        if sender_mac != my_mac:  # Don't process our own messages
            message = packet.msg.decode('utf-8')
            sender_color = get_sender_color(message)
            received_label.text = "RX'd: "  # Stays tomato
            received_message_label.text = message[-12:]  # In sender color
            received_message_label.color = sender_color
```


## Featured Products

### Adafruit ESP32-S3 Reverse TFT Feather

[Adafruit ESP32-S3 Reverse TFT Feather](https://www.adafruit.com/product/5691)
Like Missy Elliot, we like to ["put our [Feather] down, flip it and reverse it"](https://www.youtube.com/watch?v=cjIvu7e6Wq8)&nbsp;and that's exactly what we've done with this new development board. It's basically our **<a...></a...>**

Out of Stock
[Buy Now](https://www.adafruit.com/product/5691)
[Related Guides to the Product](https://learn.adafruit.com/products/5691/guides)
### Adafruit QT Py ESP32-S3 WiFi Dev Board with STEMMA QT

[Adafruit QT Py ESP32-S3 WiFi Dev Board with STEMMA QT](https://www.adafruit.com/product/5426)
The ESP32-S3 has arrived in QT Py format - and what a great way to get started with this powerful new chip from Espressif! With dual 240 MHz cores, WiFi and BLE support, and native USB, this QT Py is great for powering your IoT projects.

The ESP32-S3&nbsp;is a highly-integrated,...

In Stock
[Buy Now](https://www.adafruit.com/product/5426)
[Related Guides to the Product](https://learn.adafruit.com/products/5426/guides)
### Adafruit ESP32-S2 Feather - 4 MB Flash + 2 MB PSRAM

[Adafruit ESP32-S2 Feather - 4 MB Flash + 2 MB PSRAM](https://www.adafruit.com/product/5000)
What's Feather-shaped and has an ESP32-S2 WiFi module? What has a STEMMA QT connector for I2C devices? What has your favorite Espressif WiFi microcontroller and lots of Flash and RAM memory for your next IoT project? What will make your next IoT project flyyyyy?

That's right -...

In Stock
[Buy Now](https://www.adafruit.com/product/5000)
[Related Guides to the Product](https://learn.adafruit.com/products/5000/guides)
### Adafruit QT Py ESP32-S2 WiFi Dev Board with STEMMA QT

[Adafruit QT Py ESP32-S2 WiFi Dev Board with STEMMA QT](https://www.adafruit.com/product/5325)
What has your favorite Espressif WiFi microcontroller, comes with&nbsp;[our favorite connector - the STEMMA QT](http://adafruit.com/stemma), a chainable I2C port, and has lots of Flash and RAM memory for your next IoT project? What will make your next IoT project flyyyyy? What a...

In Stock
[Buy Now](https://www.adafruit.com/product/5325)
[Related Guides to the Product](https://learn.adafruit.com/products/5325/guides)
### Adafruit Metro ESP32-S3 with 16 MB Flash 8 MB PSRAM

[Adafruit Metro ESP32-S3 with 16 MB Flash 8 MB PSRAM](https://www.adafruit.com/product/5500)
What's Metro-shaped and has an ESP32-S3&nbsp;WiFi module? What has a STEMMA QT connector for I2C devices and a Lipoly charger circuit? What has your favorite Espressif WiFi microcontroller and lots of memory for your next IoT project?

That's right - it's the new...

In Stock
[Buy Now](https://www.adafruit.com/product/5500)
[Related Guides to the Product](https://learn.adafruit.com/products/5500/guides)
### Adafruit ESP32-S3 Reverse TFT with w.FL Antenna

[Adafruit ESP32-S3 Reverse TFT with w.FL Antenna](https://www.adafruit.com/product/6303)
Like Missy Elliot, we like to ["put our [Feather] down, flip it and reverse it"](https://www.youtube.com/watch?v=cjIvu7e6Wq8)&nbsp;and that's exactly what we've done with this new development board. It's basically our **<a...></a...>**

Out of Stock
[Buy Now](https://www.adafruit.com/product/6303)
[Related Guides to the Product](https://learn.adafruit.com/products/6303/guides)
### Adafruit ESP32-S2 Feather with BME280 Sensor - STEMMA QT

[Adafruit ESP32-S2 Feather with BME280 Sensor - STEMMA QT](https://www.adafruit.com/product/5303)
What's Feather-shaped and has an ESP32-S2 WiFi module? What has a STEMMA QT connector for I2C devices and a built in ambient sensor? What has your favorite Espressif WiFi microcontroller and lots of Flash and RAM memory for your next IoT project? What will make your next IoT project sensor...

In Stock
[Buy Now](https://www.adafruit.com/product/5303)
[Related Guides to the Product](https://learn.adafruit.com/products/5303/guides)

## Related Guides

- [Adafruit ESP32-S2 Feather](https://learn.adafruit.com/adafruit-esp32-s2-feather.md)
- [Adafruit QT Py ESP32-S2 and QT Py ESP32-S2 with uFL Antenna](https://learn.adafruit.com/adafruit-qt-py-esp32-s2.md)
- [Adafruit QT Py ESP32-S3](https://learn.adafruit.com/adafruit-qt-py-esp32-s3.md)
- [Adafruit ESP32-S3 Reverse TFT Feather](https://learn.adafruit.com/esp32-s3-reverse-tft-feather.md)
- [Adafruit Metro ESP32-S3](https://learn.adafruit.com/adafruit-metro-esp32-s3.md)
- [Raspberry Pi Azure IoT Hub Dashboard with CircuitPython](https://learn.adafruit.com/raspberry-pi-iot-dashboard-with-azure-and-circuitpython.md)
- [No-Code Snowfall Tracker with WipperSnapper and Adafruit IO](https://learn.adafruit.com/no-code-snow-tracker-with-wippersnapper-and-adafruit-io.md)
- [Cheekmate - a Wireless Haptic Communication System](https://learn.adafruit.com/cheekmate-wireless-haptic-communication.md)
- [ESPectre Human Detector for Feather](https://learn.adafruit.com/espectre-human-detector-for-feather.md)
- [No-Code IKEA Vindriktning Air Quality Sensor Hack with Adafruit IO](https://learn.adafruit.com/no-code-ikea-vindriktning-hack-with-qt-py-esp32-s3-and-adafruit-io.md)
- [Blinka LED Sign](https://learn.adafruit.com/blinka-led-sign.md)
- [Canary Nightlight ](https://learn.adafruit.com/canary-nightlight.md)
- [CircuitPython Day 2024 Countdown Clock](https://learn.adafruit.com/circuitpython-day-2024-countdown-clock.md)
- [Nunchuck Controlled Laser Cat Toy](https://learn.adafruit.com/nunchuck-controlled-laser-cat-toy.md)
- [CircuitPython Web Workflow Code Editor Quick Start](https://learn.adafruit.com/getting-started-with-web-workflow-using-the-code-editor.md)
- [Use Docker to Compile Linux for ESP32-S3](https://learn.adafruit.com/docker-esp32-s3-linux.md)
- [Two Way Telegraph with Analog Feedback Servos](https://learn.adafruit.com/two-way-display-with-analog-feedback-servos.md)
- [Adafruit AM2320 Sensor](https://learn.adafruit.com/adafruit-am2320-temperature-humidity-i2c-sensor.md)
