A professional web-based TODO management system running on the Adafruit MatrixPortal M4 with Arduino. Features a REST API, responsive web interface, LED matrix display with auto-rotation, and persistent storage.
- Web Server & REST API - Full CRUD operations for TODO management
- LED Matrix Display - 64x32 RGB display with scrolling TODO list
- Auto-Rotation - Accelerometer-based orientation detection (portrait/landscape)
- Persistent Storage - TODOs saved to QSPI flash, survive power cycles
- Auto Backup/Restore - Automatic TODO preservation during firmware updates
- Character Validation - Ensures only displayable ASCII characters (32-126)
- WiFi Auto-Reconnect - Maintains connection automatically
- Professional Architecture - Modular design with separated concerns
git clone https://github.com/johnwyles/MatrixPortalTodoServer
cd MatrixPortalTodoServer
./setup.shThis installs Arduino CLI, board support, and all required libraries automatically.
- Copy the example secrets file:
cp src/arduino_secrets.h.example src/arduino_secrets.h- Edit
src/arduino_secrets.hwith your WiFi credentials:
#define WIFI_SSID "your-network-name"
#define WIFI_PASSWORD "your-password"
#define DEVICE_IP "10.0.0.65" // Your device's IP (optional)Connect your MatrixPortal M4 via USB and run:
./sync.shThis automatically:
- Backs up current TODOs from the device
- Compiles and uploads the firmware
- Restores your TODOs after upload
- Shows the device IP when complete
# Linux
curl -fsSL https://downloads.arduino.cc/arduino-cli/arduino-cli_latest_Linux_64bit.tar.gz | tar xz -C bin/
# macOS
curl -fsSL https://downloads.arduino.cc/arduino-cli/arduino-cli_latest_macOS_64bit.tar.gz | tar xz -C bin/./bin/arduino-cli config init
./bin/arduino-cli config add board_manager.additional_urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
./bin/arduino-cli core update-index
./bin/arduino-cli core install adafruit:samd./bin/arduino-cli lib install "WiFiNINA"
./bin/arduino-cli lib install "ArduinoJson"
./bin/arduino-cli lib install "Adafruit Protomatter"
./bin/arduino-cli lib install "Adafruit SPIFlash"
./bin/arduino-cli lib install "SdFat - Adafruit Fork"
./bin/arduino-cli lib install "Adafruit LIS3DH"
./bin/arduino-cli lib install "Adafruit Unified Sensor"
./bin/arduino-cli lib install "Adafruit BusIO"After upload, the LED matrix displays the device IP address. Open in your browser:
http://[DEVICE-IP]/
The web interface provides:
- Add new TODOs
- Mark TODOs as complete/incomplete
- Edit TODO text inline
- Delete TODOs
- Character validation (ASCII 32-126 only)
| Method | Endpoint | Description | Body |
|---|---|---|---|
| GET | /api/todos |
Get all TODOs | - |
| POST | /api/todos |
Create new TODO | {"text": "Task"} |
| PUT | /api/todos/{id} |
Update TODO | {"text": "Updated", "done": true} |
| PUT | /api/todos/{id}/toggle |
Toggle done status | - |
| DELETE | /api/todos/{id} |
Delete TODO | - |
| GET | /api/config |
Get configuration | - |
# Get all TODOs
curl http://10.0.0.65/api/todos
# Add a new TODO
curl -X POST http://10.0.0.65/api/todos \
-H "Content-Type: application/json" \
-d '{"text": "Build something awesome"}'
# Mark TODO as done
curl -X PUT http://10.0.0.65/api/todos/0/toggle
# Update TODO text
curl -X PUT http://10.0.0.65/api/todos/0 \
-H "Content-Type: application/json" \
-d '{"text": "Build something MORE awesome", "done": false}'
# Delete TODO
curl -X DELETE http://10.0.0.65/api/todos/0The 64x32 RGB matrix shows:
- "Booting" message
- WiFi connection status
- Server initialization progress (red progress bar)
- IP address display (10 seconds)
- TODO list (scrolling if needed)
- Shows up to 6 TODOs in landscape, 12 in portrait
- Completed items shown with strikethrough
- Auto-scrolls long text
- Updates in real-time when modified via web
The accelerometer detects device orientation:
- Landscape (0° and 180°): 6 lines of text
- Portrait (90° and 270°): 12 lines of text
- Smooth transitions between orientations
- Text always remains upright
matrixm4portal/
├── matrixm4portal.ino # Main Arduino sketch
├── src/ # Source headers
│ ├── arduino_secrets.h # WiFi credentials (create from .example)
│ ├── arduino_secrets.h.example
│ ├── config.h # Configuration structures
│ ├── todo_manager.h # TODO data management
│ ├── simple_display.h # LED matrix control
│ ├── wifi_manager.h # WiFi connection handling
│ ├── storage_manager.h # QSPI flash storage
│ ├── http_server.h # Web server implementation
│ ├── web_content.h # HTML/CSS/JS interface
│ ├── orientation_manager.h # Accelerometer handling
│ └── Font5x5Fixed.h # Custom font definition
├── data/ # Configuration files
│ ├── config.json # Server configuration
│ ├── todos.json # User TODOs (auto-created)
│ └── todos.json.example # Default TODO template
├── bin/ # Arduino CLI binary (auto-installed)
├── setup.sh # One-command setup script
├── sync.sh # Upload with TODO backup/restore
└── .gitignore # Excludes secrets and user data
{
"server_port": 80,
"display_brightness": 50,
"scroll_speed": 50,
"auto_save": true,
"debug_mode": false
}display_brightness: 0-255 (higher = brighter)scroll_speed: Milliseconds between scroll stepsauto_save: Save TODOs to flash on change
| Problem | Solution |
|---|---|
| Upload fails | Double-click RESET (LED turns green), try within 10 seconds |
| "No device found" | Check USB cable, run ls -la /dev/ttyACM* |
| WiFi won't connect | Use 2.4GHz network only, check credentials in src/arduino_secrets.h |
| Display blank | Check power (USB may be insufficient), verify ribbon cable |
| TODOs lost | Check data/todos.json backup, TODOs persist in QSPI flash |
| Characters garbled | Only ASCII 32-126 supported, no emojis |
| "Matrix init failed" | Power cycle board, check connections |
| "Flash init failed" | Hardware issue, TODOs won't persist |
- Cyan IP - System normal
- Yellow TODOs - Tasks pending
- Green TODOs - All complete
- Red text - Error condition
# Add user to dialout group for serial access
sudo usermod -a -G dialout $USER
# Log out and back in./bin/arduino-cli compile --fqbn adafruit:samd:adafruit_matrixportal_m4 ../bin/arduino-cli upload -p /dev/ttyACM0 --fqbn adafruit:samd:adafruit_matrixportal_m4 ../bin/arduino-cli monitor -p /dev/ttyACM0- SAMD51 Processor: 512KB Flash, 192KB SRAM
- Matrix Buffer: ~16KB
- TODO Storage: ~2KB (20 items max)
- Web Server: ~10KB
- Free RAM: >150KB
- Never commit
src/arduino_secrets.h(it's in .gitignore) - The device IP in secrets is optional (used by sync.sh)
- No authentication on API endpoints (local network only)
- Character validation prevents injection attacks
MIT License - See LICENSE file for details
Connect via serial monitor for debugging:
./bin/arduino-cli monitor -p /dev/ttyACM0Useful serial commands (if implemented):
status- System overviewwifi- WiFi connection detailsmemory- RAM usage statsclear- Delete all TODOsreboot- Restart system
// Example Arduino client to control the TODO server
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* SERVER_IP = "10.0.0.65";
void addTodo(String text) {
HTTPClient http;
http.begin("http://" + String(SERVER_IP) + "/api/todos");
http.addHeader("Content-Type", "application/json");
StaticJsonDocument<200> doc;
doc["text"] = text;
String json;
serializeJson(doc, json);
int httpCode = http.POST(json);
http.end();
}If the system becomes unresponsive:
-
Enter bootloader mode:
- Hold BOOT button
- Click RESET button
- Release BOOT button
- LED should pulse
-
Re-upload firmware:
./sync.sh
Pull requests welcome! Please ensure:
- Code follows existing style conventions
- No hardcoded credentials or secrets
- Test with sync.sh before submitting
- Update README if adding features
Built with:
No CircuitPython! Pure Arduino implementation for maximum performance and stability.