ESP-NOW Applied Exercises with Peripherals
Exercise 1 — One-to-one: wireless button to LED
Pattern: one-to-one
Peripherals: pushbutton on Board A, LED on Board B
Goal
When the student presses a button on Board A, Board B turns an LED on. When the button is released, the LED turns off.
Exercise 2 — One-to-one: potentiometer-controlled dimmer
Pattern: one-to-one
Peripherals: potentiometer on Board A, PWM LED on Board B
Goal
Board A reads an analog potentiometer and sends the value to Board B. Board B adjusts the brightness of an LED using PWM.
Exercise 3 — Two-way: ping and acknowledgment with buzzer
Pattern: two-way / symmetric
Peripherals: pushbutton on Board A, buzzer on Board B, status LED on Board A
Goal
When the user presses a button on Board A, it sends a command to Board B. Board B activates a buzzer briefly and returns an ACK. Board A lights a status LED only if the ACK arrives before timeout.
Exercise 4 — One-to-many: one controller, three actuators
Pattern: one-to-many
Peripherals: one controller board with 3 buttons, three receiver boards with different outputs
- Board B: LED
- Board C: buzzer
- Board D: servo
Goal
One master board sends commands to three different boards. Each button triggers a different remote actuator.
Example behavior
- Button 1 toggles the LED on Board B
- Button 2 activates a short beep on Board C
- Button 3 moves the servo on Board D to a defined angle
Exercise 5 — One-to-many with targeted NeoPixel control from terminal
Pattern: one-to-many
Peripherals: one sender board connected to the serial terminal, multiple receiver boards each with a NeoPixel ring
Goal
The sender board reads commands from the serial terminal and sends them to a selected ESP node so it changes one pixel on its NeoPixel ring.
Terminal command format
Example commands
Meaning:
- esp1 selects receiver board 1
- pixel# selects which LED in the ring to modify
- R, G, B are the color values from 0 to 255
Required setup
- One transmitter board connected to the computer
- At least 3 receiver ESP boards
- One NeoPixel ring or circle array per receiver board
- Add the NeoPixel component to each receiver project with:
idf.py add-dependency "zorxx/neopixel" - A lookup table on the transmitter that maps:
esp1→ MAC of Board Besp2→ MAC of Board Cesp3→ MAC of Board D
NeoPixel quick reference
Add the dependency to your project with
from the terminal in your project directory.The zorxx/neopixel library exposes three things you need: an init function, a pixel-set function, and a color macro.
#include "neopixel.h"
#define NEOPIXEL_PIN GPIO_NUM_8 // data pin wired to the ring's DIN
#define NEOPIXEL_COUNT 12 // number of LEDs in the ring
// 1. Initialize once, e.g. inside app_main()
tNeopixelContext np = neopixel_Init(NEOPIXEL_COUNT, NEOPIXEL_PIN);
// 2. To set a single pixel, fill a tNeopixel struct and call neopixel_SetPixel()
tNeopixel pixel;
pixel.index = 5; // which LED in the ring (0-based)
pixel.rgb = NP_RGB(255, 0, 0); // red — NP_RGB(R, G, B) packs the color
neopixel_SetPixel(np, &pixel, 1); // last argument = number of pixels in the array
// 3. To set multiple pixels in one call, use an array
tNeopixel pixels[3] = {
{ .index = 0, .rgb = NP_RGB(255, 0, 0) }, // red
{ .index = 1, .rgb = NP_RGB(0, 255, 0) }, // green
{ .index = 2, .rgb = NP_RGB(0, 0, 255) }, // blue
};
neopixel_SetPixel(np, pixels, 3);
// 4. To turn a pixel off, set its color to black
pixel.index = 5;
pixel.rgb = NP_RGB(0, 0, 0);
neopixel_SetPixel(np, &pixel, 1);
Exercise 6 — Many-to-one: sensor hub printed in terminal
Pattern: many-to-one
Peripherals:
- Board B: LDR
- Board C: potentiometer
- Board D: temperature sensor or second analog source
- Board A: serial terminal monitor
Goal
Three sensor nodes send measurements to one gateway. The gateway prints the latest data from all nodes in the terminal.
Example terminal output
Exercise 7 — Everyone-to-everyone: distributed quiz buzzer
Pattern: everyone-to-everyone
Peripherals: pushbutton and LED on every board
Goal
Each board has a button. When any student presses their button, all boards receive the event and display who buzzed first by lighting LEDs in a defined pattern.
Example behavior
- Every board has a local button and LED
- Pressing a button sends a "buzz" message to every other board
- The first received buzz wins
- All boards indicate the winner
- Later presses are ignored until reset
Exercise 8 — Group Assignment: range-extended chat system
Pattern: everyone-to-everyone with relay forwarding
Peripherals: serial terminal on every board
Goal
Each board can send and receive messages to/from every other board. The user types a message in the terminal of any board and it is broadcast to all other boards, which print it in their terminals. Boards that are out of direct range of the sender can still receive the message because intermediate boards repeat it, extending the network's reach.
Example behavior
- Each board has a unique name (e.g.,
Oscar,Sumie,Carlos) - The user types a message in the terminal prefixed by the board's name (e.g.,
Oscar: Hello everyone!) - The message is broadcast to all reachable neighbors
- Any board that receives the message prints it to its own terminal and rebroadcasts it once, so boards beyond direct range also receive it
- To prevent the message from bouncing forever, include a TTL (time-to-live) counter in the packet struct — each board decrements it before forwarding, and discards the packet when it reaches zero