initial commit
This commit is contained in:
211
PLAN.md
Normal file
211
PLAN.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# Pi Dashboard — ESP32-S3 RLCD 4.2" Project Plan
|
||||
|
||||
## Goal
|
||||
|
||||
WebSocket client on the ESP32-S3 RLCD board that receives system status from a
|
||||
Raspberry Pi home server over LAN and renders a monitoring dashboard via LVGL.
|
||||
|
||||
---
|
||||
|
||||
## New project location
|
||||
|
||||
Create a new ESP-IDF project directory **outside** the Examples folder, e.g.:
|
||||
|
||||
```
|
||||
J:\dev\arduino\ESP32-S3-RLCD-4.2-main\Projects\pi_dashboard\
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Files to copy from the factory example
|
||||
|
||||
Source root: `Example\ESP-IDF\10_FactoryProgram\`
|
||||
|
||||
### Must copy (build skeleton)
|
||||
|
||||
| File / Dir | Why |
|
||||
|---|---|
|
||||
| `CMakeLists.txt` | Project root cmake — edit project name, strip `EXTRA_COMPONENT_DIRS` if not using ExternLib |
|
||||
| `partitions.csv` | Partition table (8MB app partition, NVS, PHY) |
|
||||
| `sdkconfig.defaults` | Base config — **strip BT lines**, keep SPIRAM/flash/LVGL settings |
|
||||
| `main/CMakeLists.txt` | Main component registration |
|
||||
| `main/idf_component.yml` | Managed component deps — keep `lvgl/lvgl: ^8.4.0`, drop `avi_player` and `esp_new_jpeg`, **add `espressif/esp_websocket_client`** |
|
||||
|
||||
### Must copy (display driver)
|
||||
|
||||
| File | From | Why |
|
||||
|---|---|---|
|
||||
| `display_bsp.h` | `components/port_bsp/` | DisplayPort class — RLCD SPI driver with LUT pixel mapping |
|
||||
| `display_bsp.cpp` | `components/port_bsp/` | Full implementation: SPI init, reset, command sequences, SetPixel, Display |
|
||||
|
||||
These two files are the entire RLCD hardware abstraction. No other display code
|
||||
exists. Copy them into a `components/display_bsp/` component in the new project.
|
||||
|
||||
### Must copy (LVGL port)
|
||||
|
||||
| File | From | Why |
|
||||
|---|---|---|
|
||||
| `lvgl_bsp.h` | `components/app_bsp/` | Lvgl_PortInit, Lvgl_lock/unlock declarations |
|
||||
| `lvgl_bsp.cpp` | `components/app_bsp/` | LVGL display driver registration, double-buffered PSRAM, tick timer, port task on Core 0 |
|
||||
|
||||
Copy into a `components/lvgl_port/` component. This file is self-contained — its
|
||||
only dependency is `lvgl.h` and FreeRTOS.
|
||||
|
||||
### Copy as reference (WiFi STA)
|
||||
|
||||
| File | From | Why |
|
||||
|---|---|---|
|
||||
| `esp_wifi_bsp.h` | `Example/ESP-IDF/02_WIFI_STA/components/esp_wifi_bsp/` | Cleaner than the factory version — no scan-and-destroy, no BLE entanglement |
|
||||
| `esp_wifi_bsp.c` | same | Simple STA init + connect + reconnect skeleton |
|
||||
|
||||
The `02_WIFI_STA` example is a better starting point than the factory program's
|
||||
wifi code. The factory version tears down WiFi for BLE scanning — useless for a
|
||||
persistent connection. You will need to modify the STA code to:
|
||||
- Make SSID/password configurable (NVS or Kconfig)
|
||||
- Add auto-reconnect on disconnect
|
||||
- Signal connection readiness via event group so the WebSocket task knows when to start
|
||||
|
||||
### Do NOT copy
|
||||
|
||||
| Component | Why not |
|
||||
|---|---|
|
||||
| `components/port_bsp/` (everything except display_bsp) | I2C bus, buttons, SD card, ADC, codec — none needed for a dashboard |
|
||||
| `components/ExternLib/` (SensorLib, codec_board) | Sensor drivers and audio codec — irrelevant |
|
||||
| `components/app_bsp/ble_scan_bsp.c` | BLE scanning — not needed, and conflicts with persistent WiFi |
|
||||
| `components/app_bsp/esp_wifi_bsp.c` | Factory version destroys WiFi for BLE — use 02_WIFI_STA instead |
|
||||
| `components/ui_bsp/` | NXP GUI Guider generated UI — you will design your own dashboard layout |
|
||||
| `components/user_app/` | Factory test logic — all replaced by your WebSocket + dashboard code |
|
||||
| `managed_components/` | Auto-downloaded by ESP-IDF component manager from `idf_component.yml` — never copy these |
|
||||
| `build/` | Build artifacts — never copy |
|
||||
|
||||
---
|
||||
|
||||
## New project structure
|
||||
|
||||
```
|
||||
pi_dashboard/
|
||||
CMakeLists.txt # from factory, edited
|
||||
partitions.csv # from factory, as-is
|
||||
sdkconfig.defaults # from factory, stripped (no BT)
|
||||
main/
|
||||
CMakeLists.txt # register main.cpp
|
||||
idf_component.yml # lvgl ^8.4.0, esp_websocket_client
|
||||
main.cpp # app_main: wifi init, display init, lvgl init, ws connect, task spawn
|
||||
components/
|
||||
display_bsp/
|
||||
CMakeLists.txt # new: register display_bsp.cpp, REQUIRES driver esp_lcd
|
||||
display_bsp.h # from port_bsp, as-is
|
||||
display_bsp.cpp # from port_bsp, as-is
|
||||
lvgl_port/
|
||||
CMakeLists.txt # new: register lvgl_bsp.cpp, REQUIRES lvgl__lvgl esp_timer
|
||||
lvgl_bsp.h # from app_bsp, as-is
|
||||
lvgl_bsp.cpp # from app_bsp, as-is
|
||||
wifi_sta/
|
||||
CMakeLists.txt # new: register wifi_sta.c, REQUIRES esp_wifi esp_event nvs_flash
|
||||
wifi_sta.h # based on 02_WIFI_STA, extended with reconnect + event group
|
||||
wifi_sta.c # based on 02_WIFI_STA, extended
|
||||
ws_client/
|
||||
CMakeLists.txt # new: register ws_client.cpp, REQUIRES esp_websocket_client
|
||||
ws_client.h # WebSocket connect/disconnect, message callback registration
|
||||
ws_client.cpp # esp_websocket_client wrapper, reconnect logic, JSON parse
|
||||
dashboard_ui/
|
||||
CMakeLists.txt # new: register dashboard_ui.cpp, REQUIRES lvgl__lvgl
|
||||
dashboard_ui.h # UI layout: create/update functions for dashboard widgets
|
||||
dashboard_ui.cpp # LVGL widget creation, label/bar/table updates from parsed data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## sdkconfig.defaults (modified for this project)
|
||||
|
||||
Strip from the factory version:
|
||||
- `CONFIG_BT_ENABLED=y` and all BT lines (saves ~300KB flash + significant RAM)
|
||||
- `CONFIG_BT_BLE_*` lines
|
||||
|
||||
Keep:
|
||||
- `CONFIG_IDF_TARGET="esp32s3"`
|
||||
- `CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`
|
||||
- `CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y`
|
||||
- `CONFIG_PARTITION_TABLE_CUSTOM=y`
|
||||
- `CONFIG_SPIRAM=y` / `CONFIG_SPIRAM_MODE_OCT=y` / `CONFIG_SPIRAM_SPEED_80M=y`
|
||||
- `CONFIG_FREERTOS_HZ=1000`
|
||||
- `CONFIG_LV_MEM_SIZE_KILOBYTES=64`
|
||||
- `CONFIG_LV_DISP_DEF_REFR_PERIOD=1`
|
||||
|
||||
Add:
|
||||
- `CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`
|
||||
|
||||
---
|
||||
|
||||
## Runtime architecture
|
||||
|
||||
```
|
||||
Core 0 Core 1
|
||||
------ ------
|
||||
WiFi driver (system) main task (app_main, exits after init)
|
||||
LVGL port task (priority 5) WebSocket event task (priority 3)
|
||||
- lv_timer_handler loop - receives WS messages
|
||||
- holds/releases lvgl_mux - parses JSON
|
||||
- acquires lvgl_mux
|
||||
- updates dashboard widgets
|
||||
- releases lvgl_mux
|
||||
```
|
||||
|
||||
### Boot sequence (app_main)
|
||||
|
||||
1. `wifi_sta_init()` — start WiFi STA, wait for IP
|
||||
2. `RlcdPort.RLCD_Init()` — init display over SPI
|
||||
3. `Lvgl_PortInit(400, 300, flush_cb)` — init LVGL with double-buffered PSRAM
|
||||
4. Create initial dashboard UI (under LVGL lock)
|
||||
5. `ws_client_start("ws://<pi_ip>:<port>")` — connect WebSocket, register message handler
|
||||
6. app_main returns, FreeRTOS tasks take over
|
||||
|
||||
### Data flow
|
||||
|
||||
```
|
||||
Pi server --[WebSocket JSON]--> ESP32 ws_client
|
||||
--> parse message
|
||||
--> Lvgl_lock()
|
||||
--> update lv_label / lv_bar / lv_table widgets
|
||||
--> Lvgl_unlock()
|
||||
--> LVGL port task flushes on next cycle
|
||||
--> flush_cb converts 16-bit to 1-bit, pushes to RLCD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pi side (not part of this ESP-IDF project, but for context)
|
||||
|
||||
A simple Python WebSocket server that:
|
||||
- Collects system stats (psutil or /proc reads)
|
||||
- Serializes to JSON
|
||||
- Pushes to connected clients every N seconds
|
||||
|
||||
Example payload:
|
||||
```json
|
||||
{
|
||||
"cpu_pct": 23,
|
||||
"mem_pct": 61,
|
||||
"mem_used_mb": 1952,
|
||||
"disk_pct": 44,
|
||||
"cpu_temp": 52,
|
||||
"uptime_hrs": 342,
|
||||
"services": [
|
||||
{"name": "docker", "status": "running"},
|
||||
{"name": "pihole", "status": "running"},
|
||||
{"name": "nginx", "status": "stopped"}
|
||||
],
|
||||
"net_rx_kbps": 1240,
|
||||
"net_tx_kbps": 320
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key decisions still open
|
||||
|
||||
1. **WiFi credentials** — hardcode for now, or Kconfig menuconfig, or NVS provisioning?
|
||||
2. **Dashboard layout** — what stats matter most? Single screen or multiple pages?
|
||||
3. **Update frequency** — how often should the Pi push? 2s? 5s? On-change?
|
||||
4. **Pi server location** — fixed IP or mDNS discovery?
|
||||
5. **Error states** — what to show when WiFi drops or Pi goes offline?
|
||||
Reference in New Issue
Block a user