Pico-Framework: A Structured Embedded Framework for Real-World Applications
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.