TDD for device and screen management. Authored by gemini 3.1 pro

This commit is contained in:
2026-03-15 10:52:43 -04:00
parent f0297418cf
commit 46dfe82568
3 changed files with 61 additions and 0 deletions

View File

@@ -80,6 +80,7 @@ Read the relevant TDD before any major architectural change:
| `tdd/frontend_ota.md` | Touching frontend OTA upload or versioning |
| `tdd/concurrent_requests.md` | Changing HTTP server socket/connection config |
| `tdd/lvgl_image_generation.md` | Touching LVGL headless display or image gen |
| `tdd/device_screens.md` | Changing device registration, MAC routing, or XML layout logic |
---

View File

@@ -77,6 +77,7 @@ Always read the relevant TDD before making major architectural changes:
| [frontend_ota.md](tdd/frontend_ota.md) | Touching frontend OTA upload or versioning |
| [concurrent_requests.md](tdd/concurrent_requests.md) | Changing HTTP server socket/connection config |
| [lvgl_image_generation.md](tdd/lvgl_image_generation.md) | Touching LVGL headless display or image gen |
| [device_screens.md](tdd/device_screens.md) | Changing device registration, MAC routing, or XML layout logic |
---

View File

@@ -0,0 +1,59 @@
# Device Screens Management
**Authored by Antigravity**
**Date:** 2026-03-15
---
## 1. What (Goal)
The goal is to enable the Calendink Provider to act as a backend screen generator for dump clients (like e-ink devices) connected to the network.
We need to implement a system that:
- Allows devices to register themselves via their MAC address.
- Provides a Frontend "Device Manager" interface where a user can upload and assign a custom LVGL XML string to each registered device.
- Generates a custom PNG image on the fly when a device requests its screen, by parsing its assigned XML string using the LVGL XML runtime.
- Temporarily stores this data in RAM (as per the current project architecture), deferring persistent storage (like SQLite) to a later phase.
## 2. Why (Reasoning)
Dumb e-ink clients (like the TRMNL) typically cannot run complex UI frameworks or parse rich data formats like JSON to render screens themselves. They simply download and display a static image buffer.
By having the ESP32-S3 Provider generate these images using LVGL's headless rendering capabilities:
1. **Centralized Configuration:** The user can design and assign screens for all their devices from a single web dashboard.
2. **Dynamic UI:** Using the new `LV_USE_XML` feature in LVGL 9.4+, the layout is completely decoupled from the C++ firmware. Users can radically change what a display looks like by simply uploading a new XML string via the web interface, without needing to recompile or flash the ESP32.
3. **Payload Efficiency:** Returning a URL `{"image_url": "/api/devices/screen.png"}` in the JSON response instead of a base64 encoded binary prevents massive memory spikes and reduces transmission time for the constrained devices.
4. **Consistency:** Storing user settings in BSS static arrays aligns with the existing non-persistent data models (like Tasks). It avoids heap fragmentation risks on the ESP32 until a proper SQLite database is integrated.
## 3. How (Implementation Details)
### Backend Storage & State
Similar to the `Todo` app from `tdd/todo_list.md`, we use static arrays in the BSS segment to manage devices. The structure holds the device MAC, an `active` flag, and a statically allocated string buffer (2048 bytes) to store the uploaded LVGL XML.
```cpp
struct Device {
char mac[18];
bool active;
char xml_layout[2048];
};
extern Device g_Devices[8];
```
### API Endpoints
The following REST endpoints handle the device lifecycle and image generation:
| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/api/devices` | Returns a JSON array of all active devices, including whether they have a custom XML layout set. |
| `POST` | `/api/devices/register` | Accepts `{"mac": "..."}`. Claims a slot in `g_Devices` if not already registered. |
| `POST` | `/api/devices/layout` | Accepts `{"mac": "...", "xml": "<lvgl xml>"}`. Stores the XML string in the device's struct buffer. |
| `GET` | `/api/devices/screen?mac=XX` | Returns `{"image_url": "/api/devices/screen.png?mac=XX"}` (TRMNL API pattern). |
| `GET` | `/api/devices/screen.png?mac=XX` | Core rendering endpoint. Claims `g_LvglMutex`, clears the screen, parses the `xml_layout` buffer using `lv_xml_create()`, forces a refresh `lv_refr_now()`, encodes the buffer to PNG using `lodepng`, and streams the response. |
### Subsystems Config
The ESP-IDF project configuration (`sdkconfig.defaults`) must be modified to enable the `CONFIG_LV_USE_XML=y` flag, which compiles the LVGL XML parser component into the firmware image.
### Frontend
- **DeviceManager.svelte:** A new component accessible from the Sidebar. It fetches the device list on load.
- **XML Uploading:** For each device card, a text area allows the user to paste an LVGL XML string. Clicking "Save Layout" updates the device via `POST /api/devices/layout`.
- **Integration:** The `App.svelte` router will be updated to include the `'devices'` view state alongside Dashboard, Tasks, and Users.