PicoFramework User Guide
Pico-Framework: A web-first embedded framework for C++
Pico-Framework is a modern, modular framework designed for embedded systems like the Raspberry Pi Pico W. It is engineered to bring order, structure, and maintainability to applications that might otherwise be a tangled web of global variables, interrupt handlers, and ad-hoc state machines. Drawing inspiration from web frameworks and real-time design principles, Pico-Framework provides a clean separation of concerns and a foundation for building robust, feature-rich embedded systems.
Event-Driven Architecture
At its heart, Pico-Framework is based on an event-driven architecture. Rather than tightly coupling logic into monolithic loops or callback chains, it introduces the idea of framework tasks and controllers that communicate via a shared event bus. This approach mirrors patterns used in desktop and distributed systems, where separation and encapsulation improve clarity and testing.
Applications built on Pico-Framework subclass FrameworkApp
. This base class is responsible for initializing the system, configuring core services, and starting the task scheduler. Developers define routes, register services, and manage global models here. FrameworkApp
acts as the glue that binds together the HTTP server, router, logging system, time manager, and storage backend. It also owns the startup sequence and is the natural place to define application-level routes or respond to global events like network availability.
Services
Supporting this core is a collection of services that provide persistence, scheduling, communication, and diagnostics. For example, the StorageManager
abstraction allows the application to read and write files without knowing whether the underlying storage is an SD card (via FatFsStorageManager
) or internal flash memory (via LittleFsStorageManager
). This separation is critical in embedded systems, where different platforms may impose different constraints. The storage API is simple but powerful: read and write files, stream data, append logs, and list directories — all through a unified interface. The JsonService
builds on this by exposing a clean JSON-based persistence layer, while FrameworkModel
enables object collections (e.g., zone definitions, schedules) to be manipulated like in-memory databases with automatic saving.
Logging, too, is elevated beyond simple printf
calls. The Logger
component provides structured logging with timestamps, log levels, and the ability to persist logs to storage. This enables diagnostics that survive reboots and can be viewed remotely via the web interface. Logs can be rotated manually and displayed through simple routes or HTML views.
Time Management
Time is another foundational concern in real-world embedded applications, and Pico-Framework addresses this with the TimeManager
class. Upon startup, the device syncs with an NTP server and sets the system time. TimeManager can also detect the correct timezone via a public geolocation API and convert timestamps to local time for logging, scheduling, or UI display. It provides human-readable strings, UTC conversion, and broadcasts system events when time becomes valid or synced. This greatly simplifies tasks like showing the current clock on a dashboard or triggering jobs at a local time.
Once time is valid, TimerService
provides a powerful mechanism for scheduling. Whether you need one-shot timers, repeated intervals, or structured daily events (like irrigation schedules), TimerService
allows you to describe your intent declaratively. Events are posted to subscribers at the right time — there are no callbacks to manage or timer handles to track. Duration-based scheduling (start/stop pairs) is supported directly, enabling robust time-based automation patterns.
Networking
Networking is managed by the Network
utility class, which handles Wi-Fi startup, reconnection, and retry logic. It ensures that the system boots in a network-ready state before attempting tasks that depend on connectivity. The Tcp
class builds on this, wrapping low-level socket operations in a clean, reusable client-side API. It handles TLS setup, DNS resolution, and connection management, allowing developers to implement secure protocol clients (e.g., HTTP, MQTT) without depending on high-level libraries.
Interaction with the outside world is enabled through an HTTP server integrated into the framework. Developers define routes in each controller and can serve static files or generate responses dynamically. Views can be rendered with variable substitution using FrameworkView
, allowing simple embedded UIs that can be served directly from device storage. Multipart form uploads are supported for file transfers, and JSON APIs can be built effortlessly using the renderJson()
helpers.
Framework Controllers
All of these features are organized around the core concept of controllers, which are long-lived, independently scheduled tasks derived from FrameworkController
. Each controller can define its own routes, subscribe to events, poll periodically, and respond to system changes. This modularity makes large applications easier to maintain and extend. For example, one controller might manage a file browser, another a weather integration, and another a scheduler — all running concurrently and responding to events.
In sum, Pico-Framework is not just a set of utilities — it is an architecture. It promotes maintainability through abstraction, testability through modularity, and clarity through structured task design. It brings web-level development concepts like routing, event-driven logic, and service layering into the embedded domain without sacrificing performance or control. Whether you're building an IoT sprinkler controller, a smart sensor gateway, or an automation hub, Pico-Framework offers the foundation to build confidently and cleanly.
Pico-Framework Overview
Pico-Framework is a modern, event-driven application framework designed for embedded systems like the Raspberry Pi Pico W. It brings high-level structure to bare-metal and FreeRTOS-based systems, while remaining modular, portable, and efficient. This document provides a high-level overview of all key components and how they fit together, based on the complete suite of user guides.
Core Concepts
At the heart of Pico-Framework is the idea of structured, service-oriented embedded programming. Applications are composed of tasks, controllers, services, and views—all coordinated through FreeRTOS and a lightweight router/event system.
The framework promotes:
- Loose coupling via service registration
- Modular design using FrameworkController
- Fully event-driven flow using EventManager
- Persistent storage and structured logging
- Declarative scheduling and clean routing
Everything is designed to work in resource-constrained environments with optional features enabled via modular configuration.
Application Structure
Your main application derives from FrameworkApp
, which:
- Sets up the HTTP server and router
- Registers services like StorageManager
, JsonService
, and Logger
- Starts system components like FrameworkManager
- Initializes all user-defined routes
Controllers (FrameworkController
) implement discrete logic (e.g., GPIO control, scheduling, or file management). They handle requests, events, and background polling in an isolated task context.
Key Services and Subsystems
Storage System
The StorageManager
interface abstracts persistent file access:
- FatFsStorageManager
for SD cards (large, removable, compatible)
- LittleFsStorageManager
for flash (always available, small-footprint)
On top of this:
- JsonService
persists flat JSON config and settings
- FrameworkModel
stores and retrieves structured object arrays (e.g., zones or programs)
This architecture allows your application to remain independent of the storage medium.
HTTP Server and Routing
The framework includes a minimalist HTTP server with routing, request/response objects, and multipart/form parsing.
Routes are registered via:
router.addRoute("GET", "/status", [](HttpRequest& req, HttpResponse& res, const RouteMatch&) {
res.send("OK");
});
Static file serving and uploads are supported when StorageManager
is enabled.
Event and Notification System
The EventManager
provides indexed task notifications via onEvent()
handlers in controllers. It supports:
- System notifications (e.g., network ready, time valid)
- User-defined event enums
- Publish/subscribe model via subscribe()
and postEvent()
This separates concerns cleanly and avoids direct task-to-task coupling.
Time and Scheduling
The TimeManager
handles:
- SNTP time sync
- Timezone detection via Open-Meteo
- AON/RTC initialization
- Time formatting and validity checks
The TimerService
lets you schedule one-shot, recurring, or daily events using:
- scheduleAt()
- scheduleEvery()
- scheduleDailyAt()
- scheduleDuration()
All timers post events—not callbacks—maintaining the event-driven design.
Logging
The Logger
provides timestamped, level-based logging:
- Console + optional file logging
- Thread-safe
- Compatible with all storage types
- Viewable via web routes
Advanced use includes manual log rotation and embedded log viewers.
Networking and TCP
Networking is initialized by the Network
class with:
- Retry logic
- Status polling
- LED feedback
- Reconnection helpers
The Tcp
class abstracts both TLS and plain sockets for client-side communication, enabling:
- Secure APIs
- MQTT or FTP-style protocols
- Lightweight, testable client code
User Interface and Views
The FrameworkView
supports rendering HTML files with variable substitution or returning structured JSON using:
res.send(FrameworkView::render("/index.html", context));
res.send(FrameworkView::renderJson(object));
Combined with static file support, this enables lightweight frontends hosted entirely from the device.
Development Approach
- Register all services and models at startup using
AppContext::register<T>()
- Define routes in
initRoutes()
- Use
onEvent()
to respond to notifications - Use
poll()
in each controller for periodic logic - Keep logging minimal but structured
The framework is event-first, file-aware, and task-structured by default.
Summary
Pico-Framework gives embedded developers:
- A clean and testable architecture
- Structured persistence and logging
- A full HTTP server and JSON stack
- Safe task scheduling and timer-driven events
- Web-capable APIs and file hosting
It is ideal for connected, sensor-driven, or user-interfaced devices like automation controllers, monitoring systems, or IoT prototypes.
Feature Checklist
Pico-Framework Feature Checklist
This document outlines the current features of Pico-Framework as of the latest development state. All features are grouped by subsystem. Checkmarks (✓) indicate completed features, and future plans are noted where relevant. Designed to be used in HTML-rendered markdown without advanced bullet formatting.
Core Architecture
✓ Modular MVC-inspired structure
✓ FrameworkApp
base class for main application
✓ FrameworkController
base class for logic and routes
✓ FrameworkTask
abstraction for FreeRTOS tasks
✓ FrameworkManager
for ordered startup and service registration
✓ Application-defined initRoutes()
and poll()
support
✓ Multicore-safe service access and task startup
HTTP Server
✓ Lightweight HTTP server with request parsing
✓ REST-style routing with method/path match
✓ Route parameters and wildcards
✓ Middleware support (authentication, logging, etc.)
✓ HttpRequest
and HttpResponse
abstractions
✓ Static file serving from SD or flash
✓ Multipart file upload support
✓ MIME type detection
✓ Automatic fallback to embedded assets if file not found
✓ Optional TLS support via socket wrapper
HTTP Client
✓ HttpClient
abstraction
✓ Fluent API via HttpRequest::setUri()
, headers, body, etc.
✓ Full TLS with root certificate verification
✓ Handles chunked responses and file writes
✓ Designed for weather, cloud API, or OTA fetches
✓ Uses Tcp
abstraction to support multiple implementations
Application Services
✓ AppContext
for service registration and lookup
✓ Structured StorageManager
abstraction
✓ JsonService
for simple config persistence
✓ FrameworkModel
for object storage (arrays of items)
✓ FrameworkView
for templated HTML or JSON rendering
✓ JWT authentication (middleware + route protection)
✓ GPIO event handler and GpioEventManager
✓ Embedded asset support for no-SD fallback
Event System
✓ Event
struct with type, payload, and source
✓ Notification
enum system with system/user distinction
✓ EventManager
with pub/sub task model
✓ Per-task onEvent()
delivery
✓ Indexed task notifications using enums
✓ ISR-safe event posting
✓ Task event masks for filtering
Timer and Scheduling
✓ TimerService
for one-shot timers
✓ Recurring interval events
✓ Daily scheduling by time and weekday
✓ Duration start/stop scheduling
✓ Job cancellation by ID
✓ Thread-safe job registry
✓ Planned: Persistent jobs via JSON
✓ Planned: Missed job replay after reboot
Time and RTC Support
✓ TimeManager
with SNTP sync
✓ Time validity tracking and retries
✓ AON/RTC setup on RP2040 and RP2350
✓ Timezone detection via Open-Meteo
✓ Human-readable formatting for timestamps
✓ UTC/local conversion via PicoTime
Storage Support
✓ Abstract StorageManager
interface
✓ FatFsStorageManager
for SD card
✓ LittleFsStorageManager
for internal flash
✓ File API: read, write, append, delete, mkdir
✓ Thread-safe access
✓ Safe formatting and fallback mounting
✓ Optional file streaming (read/write in chunks)
Logging
✓ Logger
with INFO/WARN/ERROR levels
✓ Timestamps in YYYY-MM-DD HH:MM:SS
format
✓ Console + file logging (SD or flash)
✓ Log truncation warning
✓ Manual log rotation logic
✓ Web route integration for log viewing
✓ Safe from multiple tasks
Debug Tracing
✓ Lightweight macro-based trace system
✓ Per-module enable/disable via flags
✓ Optional timestamping
✓ Output to console or file
✓ Controlled via framework_config.h
Utilities and Diagnostics
✓ MIME type mapping
✓ URL parsing/encoding helpers
✓ Task stats reporting
✓ Heap/stack diagnostics
✓ TCP memory diagnostics
✓ Idle memory tracking
✓ Memory-safe file uploads
✓ Framework memory reporting planned for dashboard
Testing and QA
✓ CppUTest integration
✓ Embedded tests for core features
✓ Route + HTTP end-to-end testing
✓ File and model persistence tests
✓ TLS + chunked stream test coverage
✓ Mocha tests for web UI integration
✓ Planned: Mock-based unit tests for client code
Documentation
✓ Full Doxygen coverage (headers only)
✓ Custom style and GitHub integration
✓ HTML rendering with graphs and hierarchy
✓ Markdown reference guides per subsystem
✓ GitHub Pages support
✓ Feature checklists and architecture overview
Build System and Structure
✓ Modular CMake build for app and framework
✓ Configurable build flags
✓ Optional feature toggles (auth, storage, client)
✓ Single-task or multi-task HTTP server modes
✓ LittleFS flash linker support
✓ Directory-mirrored header layout for organization
Example Apps
✓ SD or flash-backed website with login
✓ JWT-authenticated routes
✓ Event driven sprinkler programming with persistance via JSON
✓ Uploads and file browsing
✓ GPIO control via API
✓ Weather forecast integration
✓ Fully portable between SD and flash
✓ Interactive web dashboard and logs