A firmware project for a "flowing water" LED effect controller built for Raspberry Pi Pico 2 W. The application is written for MicroPython and exposes a REST API for device configuration, user management, and diagnostics.
⚠️ Important (production configuration): before running on a target device, you must change values inconfig.py, especially:
secured['secure']device['uuid']The current values in this repository are examples and must not remain unchanged on the final device.
This project is intended to be installed on:
- Raspberry Pi Pico 2 W
- together with a dedicated expansion board (I/O and power handling for LED strip / actuators).
The code uses specific GPIO pins (including 18, 19, 20), so hardware compatibility with the target expansion module is assumed.
main.pystarts:- the LED controller task (
WaterflowDriver.run()) - the HTTP server (
phew.server.run()).
- the LED controller task (
myhttp.py:- connects to Wi‑Fi (or starts AP fallback mode),
- registers REST API endpoints,
- handles authentication/authorization.
waterflowdriver.pyimplements LED strip runtime logic with dependencies on:- time schedule,
- sensor state,
- configuration loaded from JSON files.
The project reads and writes data in JSON files stored on the device.
A static file with device metadata and security settings:
device– device metadata (uuid, app name, etc.),secured– security section (secure,api-key).
Before deployment:
- set your own
device['uuid'], - set your own
secured['secure'](recommended: also updatesecured['api-key']).
net.json– Wi‑Fi/AP configuration:ssid,pass,ap-ssid,ap-pass
users.json– users, passwords, tokensgroups.json– role mapping (admin,designer,editor)data.json– device runtime configuration (e.g.pixelProgram,brightness,stepTime,onTime,offTime,on,nol, ...)pixelprograms.json– list of pixel animation programs- log file (
logging.log_file, depending onphew.loggingsetup)
On first startup, the backend ensures a default RBAC structure (roles +
adminaccount).
- Authentication: user + token passed in request headers.
- Authorization: role/group based (
admin,editor,designer).
Login endpoint:
POST /api/secure/auth
Credentials handling:
- API accepts Basic Auth (
Authorization: Basic base64(user:pass)), - on successful login it returns a fresh token.
For protected endpoints send headers:
user: <username>token: <token_from_login>
Many endpoints also refresh token and return newCredentials in response.
POST /api/secure/admin/resetrequires header:secure: <value_of_config.secured['secure']>
Below is a complete endpoint list based on the current backend code.
Returns device metadata (config.device).
200 OK (JSON)
{
"uuid": "...",
"manufacturer": "Raspberry Pi",
"product-name": "Pico 2 W",
"application-name": "Waterflow Pixel Unit"
}Returns log entries as an array of text lines.
200 OK (JSON)
["line 1", "line 2", "..."]Returns current runtime configuration from data.json.
200 OK (JSON) – schema depends on current file content.
Returns current driver state (driver.current_state()), including current action (extending/reducing) and runtime parameters.
200 OK (JSON) – dynamic structure (current state + driver object fields).
Returns list of pixel programs from pixelprograms.json.
200 OK (JSON)
[
[[255,0,0],[0,0,255]],
[[0,255,0],[0,0,0]]
]Clears log file.
- Required role:
admin
200 OK
{
"logs": ["...previous logs..."],
"newCredentials": {"user":"...","token":"..."}
}Errors: 401, 403, 500.
Starts countdown to soft restart (machine.soft_reset()).
- Required role:
adminoreditor
200 OK
{
"restartCountdown": 10,
"newCredentials": {"user":"...","token":"..."}
}Changes password for currently authenticated user.
- Minimum password length: 7
Body (JSON)
{"pass":"NewPassword123"}202 Accepted
{
"username":"admin",
"newCredentials":{"user":"admin","token":"..."}
}Errors: 401, 406, 500.
Replaces full data.json configuration.
Partially updates data.json configuration.
- Required role:
adminoreditor - If
nolis missing, API setsnol = 3.
202 Accepted
{
"before": {"...": "..."},
"after": {"...": "..."},
"newCredentials": {"user":"...","token":"..."}
}Updates network configuration (net.json).
- Required role:
admin - Accepted fields:
ssid,pass,ap-ssid,ap-pass
Body (JSON)
{
"ssid":"MyNetwork",
"pass":"MyPassword",
"ap-ssid":"Waterflow-Setup",
"ap-pass":"SetupPass123"
}202 Accepted
{
"net": {
"ssid": "...",
"pass": "...",
"ap-ssid": "...",
"ap-pass": "..."
},
"newCredentials": {"user":"...","token":"..."}
}Overwrites full list of pixel programs.
Appends programs to existing list.
- Required role:
adminordesigner
202 Accepted – returns before, after, newCredentials.
Returns secured section from config.py.
- Required role:
admin
200 OK
{
"secure": {"secure":"...","api-key":"..."},
"newCredentials": {"user":"...","token":"..."}
}Returns mapping of users to roles.
- Required role:
admin
200 OK
{
"users": {
"admin": ["admin"],
"operator": ["editor"]
},
"newCredentials": {"user":"...","token":"..."}
}Creates user and assigns groups.
- Required role:
admin
Body (JSON)
{
"user":"operator",
"pass":"StrongPassword123",
"groups":["editor"]
}200 OK
{
"username":"operator",
"groups":["editor"],
"newCredentials":{"user":"admin","token":"..."}
}Errors: 400, 401, 403, 409.
Deletes user (except admin) and related roles.
- Required role:
admin
200 OK
{
"username":"operator",
"groups":["editor"],
"newCredentials":{"user":"admin","token":"..."}
}Emergency reset of admin account password.
Required headers
secure: <config.secured['secure']>
Body (JSON)
{"pass":"NewAdminPassword"}Response codes
202 Accepted– password changed400 Bad Request– missingpass401 Unauthorized– wrong/missingsecure406 Not Acceptable– password too short500 Internal Server Error– save error
User login endpoint.
Header
Authorization: Basic base64(user:pass)
200 OK
{"token":"...","user":"admin"}401 Unauthorized – invalid credentials.
For non-existing paths backend returns:
404- body:
{"massage": "Page not exists"}
curl -X POST http://<DEVICE_IP>/api/secure/auth \
-H "Authorization: Basic $(printf 'admin:administrator' | base64)"curl http://<DEVICE_IP>/api/current-statecurl -X PATCH http://<DEVICE_IP>/api/data \
-H "Content-Type: application/json" \
-H "user: admin" \
-H "token: <TOKEN>" \
-d '{"brightness":128,"on":true}'curl -X POST http://<DEVICE_IP>/api/secure/admin/reset \
-H "Content-Type: application/json" \
-H "secure: <CONFIG_SECURED_SECURE>" \
-d '{"pass":"NewAdminPassword"}'A practical and safe deployment path:
-
Flash MicroPython UF2
- Disconnect Pico from USB.
- Hold
BOOTSELand connect USB. - Pico appears as
RPI-RP2mass storage. - Copy MicroPython
.uf2firmware for Pico 2 W.
-
Copy project files to device
- Most convenient via Thonny (Interpreter: MicroPython (Raspberry Pi Pico)).
- Copy to device storage:
main.py,myhttp.py,waterflowdriver.py,waterflowpixel.py,auth.py,utils.py,config.py,ktime.py,neopixel.pylib/folder- required JSON files (
net.json,users.json,groups.json,data.json,pixelprograms.json) configured for your environment.
-
Adjust configuration before first run
- Set unique values in
config.py, especially:secured['secure']device['uuid']
- Set Wi‑Fi/AP credentials in
net.json.
- Set unique values in
-
Restart and test API
- Restart device (soft/hard reset).
- Read IP from serial/log output.
- Verify
GET /api/infoandPOST /api/secure/auth.
- Do not use example secrets or UUIDs in production.
- Use strong user passwords (minimum 7 chars required; significantly longer recommended).
- Restrict network access to API (VLAN/firewall).
- Treat tokens as sensitive secrets (API rotates them frequently).
This repository contains MicroPython application firmware for a Pico 2 W based LED controller with a REST API for remote management.