Expand description
§device-envoy
Build Pico applications with LED panels, easy WiFi, and composable device abstractions.
device-envoy is a library for building embedded applications in Rust, built on the Embassy framework. It organizes hardware around device abstractions.
A device abstraction is a software encapsulation of hardware that manages timing, tasks, control flow, interrupts, channels, and state within the abstraction.
Rather than replacing HALs or drivers, device-envoy builds on them. It defines device abstractions that expose a small set of simple operations to the rest of the program.
Currently targeting Raspberry Pi Pico 1 and Pico 2 (ARM cores). RISC-V core support exists but is not actively tested.
§Status
⚠️ Alpha / Experimental
The API is actively evolving. Not recommended for production use, but excellent for experimentation, learning, and exploratory projects.
§Features
- LED Strips & Panels - NeoPixel-style (WS2812) LED arrays with 2D text rendering, animation, embedded-graphics support. Provides efficient options for power limiting and color correction.
- WiFi (Pico W) - Connect to the Internet with automatic credentials management. On boot, opens a web form if WiFi credentials aren’t saved, then connects seamlessly to a stored network. Requires Pico W; WiFi is not supported on non-W boards.
- Button Input - Button handling with debouncing
- Servo Control - Servo positioning and animation
- Flash Storage - Type-safe, on-board persist storage
- LCD Display - Text display (HD44780)
- IR Remote - Remote control decoder (NEC protocol)
- RFID Reader - Card detection and reading (MFRC522)
- Clock Sync - Network time synchronization utilities
- LED4 Display - 4-digit, 7-segment LED display control with optional animation and blinking
- Single LED - Single digital LED control with animation support
§Article
- How Rust & Embassy Shine on Embedded Devices by Carl M. Kadie and Brad Gibson.
§Forum
- Using Embassy to build applications
A place to talk about writing embedded applications with Embassy: sharing code, asking practical questions, and learning what works in practice.
Not limited to Pico boards or todevice-envoy.
§Examples & Demos
The project includes examples (single-device tests) in examples/ and demo applications in demos/ showing integration patterns:
§Example: animated LED strip
This example cycles a 96-LED strip through red, green, and blue frames.

It shows how device-envoy generates a struct (device abstraction) for an LED strip and then animates a sequence of frames.
use device_envoy::{Result, led_strip::{Frame1d, colors}};
use device_envoy::led_strip;
led_strip! {
LedStripAnimated {
pin: PIN_4,
len: 96,
}
}
async fn example(spawner: embassy_executor::Spawner) -> Result<Infallible> {
let p = embassy_rp::init(Default::default());
let led_strip_animated = LedStripAnimated::new(p.PIN_4, p.PIO0, p.DMA_CH0, spawner)?;
// Create a sequence of frames and durations and then animate them (looping, until replaced).
let frame_duration = embassy_time::Duration::from_millis(300);
led_strip_animated.animate([
(Frame1d::filled(colors::RED), frame_duration),
(Frame1d::filled(colors::GREEN), frame_duration),
(Frame1d::filled(colors::BLUE), frame_duration),
])?;
core::future::pending().await // run forever
}For complete, runnable examples (including wiring and setup), see the
examples/anddemos/directories.
-
Basic LED Examples: Simple on/off control with blinky pattern
-
LED Strip Examples: Simple animations, color control, text rendering
-
LED Panel Examples: 12×4, 12×8, and multi-panel configurations with graphics

- Button Examples: Debouncing and state handling
- Servo Examples: Position sweeps and animation playback
- WiFi Examples: WiFi setup, time sync, DNS
- Flash Examples: Configuration persistence and data reset
See the examples/ and demos/ directories for complete runnable code.
§Building & Running
§Prerequisites
# Add Rust targets for Pico boards
rustup target add thumbv6m-none-eabi # Pico 1 (ARM)
rustup target add thumbv8m.main-none-eabihf # Pico 2 (ARM)§Quick Start
# Run examples using convenient aliases
cargo blinky # Simple LED blinky (Pico 1)
cargo blinky-2 # Simple LED blinky (Pico 2)
cargo clock-lcd-w # LCD clock with WiFi (Pico 1 WiFi)
cargo clock-lcd-2w # LCD clock with WiFi (Pico 2 WiFi)
cargo clock-led12x4-w # LED panel clock (Pico 1 WiFi)
cargo clock-led12x4-2w # LED panel clock (Pico 2 WiFi)
# Check without running (faster builds)
cargo blinky-check # Compile only
cargo clock-lcd-w-check # Check Pico 1 WiFi version
# Build and check everything
cargo check-allTools:
just- Optional command runner (install withcargo install justor your package manager). Seejustfilefor commands.xtask- Project’s custom automation tool (built-in, use viacargo xtask --help)
See .cargo/config.toml for all cargo aliases.
§Hardware Notes
§Standard Pinouts
Examples use conventional pin assignments for consistency:
- PIN_0: LED strip (8-pixel simple example)
- PIN_1: Single LED (blinky patterns) - Built-in LEDs are modeled as active-high (OnLevel::High) on all supported boards
- PIN_3: LED panel (12×4, 48 pixels)
- PIN_4: Extended LED panel (12×8, 96 pixels)
- PIN_5: Long LED strip (160 pixels, broadway/marquee effects)
- PIN_6: Large LED panel (16×16, 256 pixels)
- PIN_13: Button (active-low)
- PIN_11, PIN_12: Servo signals
§Testing
Host-side tests run on your development machine without hardware:
just check-alljust is the optional command runner (install with cargo install just or your package manager). See Tools above.
Tests include:
- LED text rendering comparisons against reference images
- 2D LED matrix mapping algebra
- LED color space conversions
§Policy on AI-assisted development and contributions
The use of AI tools is permitted for development and contributions to this repository. AI may be used as a productivity aid for drafting, exploration, and refactoring.
All code and documentation contributed to this repository must be reviewed, edited, and validated by a human contributor. AI tools are not a substitute for design judgment, testing, or responsibility for correctness.
AGENTS.md contains the general instructions and constraints given to AI tools used during development of this repository.
§License
Licensed under either:
- MIT license (see LICENSE-MIT file)
- Apache License, Version 2.0
at your option.
§Glossary
Resources available on the Pico 1 and Pico 2:
- PIO (Programmable I/O): Pico 1 has 2. Pico 2 has 3.
- DMA (Direct Memory Access): Both Pico 1 and 2 have 12 channels.
- PWM (Pulse Width Modulation) Slices: Both Pico 1 and 2 have 8 slices (& 16 channels). These “slices” are unrelated Rust slices.
Modules§
- button
target_os=none - A device abstraction for buttons with debouncing and press duration detection.
- char_
lcd target_os=none - A device abstraction for HD44780-compatible character LCDs (e.g., 16x2, 20x2, 20x4).
- clock_
sync wifiandtarget_os=none - A device abstraction that combines time sync with a local clock.
See
ClockSyncfor the full usage example. - flash_
array target_os=none - A device abstraction for type-safe persistent storage in flash memory.
- ir
target_os=none - A device abstraction for infrared receivers using the NEC protocol.
- led
target_os=none - A device abstraction for a single digital LED with animation support.
- led4
target_os=none - A device abstraction for a 4-digit, 7-segment LED display for text with optional animation and blinking.
- led2d
- A device abstraction for rectangular NeoPixel-style (WS2812) LED panel displays.
For 1-dimensional LED strips, see the
led_stripmodule. - led_
strip - A device abstraction for 1-dimensional NeoPixel-style (WS2812) LED strips. For 2-dimensional
panels, see the
led2dmodule. - rfid
target_os=none - A device abstraction for RFID readers using the MFRC522 chip.
- servo
target_os=none - A device abstraction for hobby servos.
- servo_
player target_os=none - A device abstraction for hobby servos that can animate motion sequences.
- wifi_
auto wifiandtarget_os=none - A device abstraction that connects a Pico with WiFi to the Internet and, when needed, creates a temporary WiFi network to enter credentials.
Enums§
- Error
- Define a unified error type for this crate.
Type Aliases§
- Result
- A specialized
Resultwhere the error is this crate’sErrortype.