Skip to content

Commit 1d95120

Browse files
committed
chore: Complete Redesign & Documentation Update
- Redesign: Unified Data Models, Global DataManager, and Remote Persistence. - Fixes: Resolved CI/CD compilation errors and boot stability issues. - Docs: Updated README with architecture details, screen descriptions, and cross-repo links.
1 parent 3d33b7f commit 1d95120

File tree

337 files changed

+296265
-329
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

337 files changed

+296265
-329
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ build/
1818

1919
# Secrets
2020
secrets.h
21+
22+
# Design
23+
*.psd

README.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
🇺🇸 **[Read in English](README.md)** | 🇪🇸 **[Leer en Español](README_ES.md)**
77

8+
89
This project provides a base implementation for **generic 4.3-inch smart displays** (ESP32-S3 IPS 800x480) commonly found on **AliExpress** (Sunton 8048S043 models or clones).
910
The project is optimized to be uploaded from both the Arduino IDE and VS Code with PlatformIO.
1011

@@ -15,9 +16,14 @@ The project is optimized to be uploaded from both the Arduino IDE and VS Code wi
1516
- **Graphic Interface**: [LVGL v9.1.0](https://lvgl.io/).
1617
- **Graphics Library**: [Arduino_GFX](https://github.com/moononournation/Arduino_GFX).
1718
- **Anti-Flicker Stabilization**: **"Bus Isolation"** strategy (SRAM + Bounce Buffer) to eliminate flickering caused by PSRAM concurrency.
18-
- **Modular UI**: Component-based interface (Pages/Components) using LVGL 9.1.
19-
- **Persistent Configuration**: Settings (pump times) are automatically saved to flash memory (MemoryManager/NVS).
20-
- **ESP-NOW Communication**: Direct wireless communication with the Drinks Machine/Irrigation system. Sends drink selections via broadcast.
19+
- **Modular UI**: Component-based interface (Pages/Components) using LVGL 9.1 featuring **3 Main Screens**:
20+
1. **Drink Selection**: Visual gallery to browse and choose cocktails.
21+
2. **Recipe Config**: Interactive modal to adjust ingredients and quantities for each cocktail.
22+
3. **Pump Config**: Calibration and timing adjustments for the 4 peristaltic pumps.
23+
24+
[![Main Firmware](https://img.shields.io/badge/Get_Main_Firmware-Robot_Core-blueviolet?style=flat&logo=arduino)](https://github.com/Albert-Benavent-Cabrera/Robot-Core)
25+
- **Remote Configuration**: Cocktails and ingredients are received via ESP-NOW from the Drinks App (Robot Core). Adjusting slider values saves the configuration on the server remotely, not locally. Displays "Mock" data if offline.
26+
- **ESP-NOW Communication**: Direct wireless communication with the Drinks Machine. Sends drink selections via broadcast.
2127
- **Smart Channel Sync**: Automatically scans for a target WiFi network to synchronize its radio channel with the receiver.
2228

2329
<p align="center">
@@ -30,11 +36,15 @@ The project is optimized to be uploaded from both the Arduino IDE and VS Code wi
3036
This project is fully compatible with the Arduino IDE. Follow these steps to set it up:
3137

3238
### 1. 📚 Library Preparation
33-
Install the following **3 libraries** from the Arduino **Library Manager** (**Tools > Manage Libraries**):
39+
40+
Install these **2 libraries** from the Arduino **Library Manager** (**Tools > Manage Libraries**):
3441

3542
1. **lvgl** (v9.1.0) - Graphics engine.
36-
2. **Arduino_GFX_Library** - Display driver.
37-
3. **GT911** - Touch panel driver.
43+
2. **GT911** - Touch panel driver.
44+
45+
For **Arduino_GFX**, you have two options:
46+
* **Copy it**: Copy the `lib/GFX_Library_for_Arduino` folder from this project to your Arduino libraries folder.
47+
* **Download it**: Install **"GFX Library for Arduino"** selecting version **1.6.4** from the Manager.
3848

3949
> [!IMPORTANT]
4050
> If you receive `No such file or directory` errors with any of these names, it is because the corresponding library is missing from the Arduino manager.

README_ES.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
🇺🇸 **[Read in English](README.md)** | 🇪🇸 **[Leer en Español](README_ES.md)**
77

8+
89
Este proyecto proporciona una implementación base para las **pantallas inteligentes genéricas de 4.3 pulgadas** (ESP32-S3 IPS 800x480) que se encuentran fácilmente en **AliExpress** (modelos tipo Sunton 8048S043 o clones).
910
El proyecto está optimizado para ser cargado tanto desde el IDE de Arduino como desde VS Code con PlatformIO.
1011

@@ -15,9 +16,14 @@ Este proyecto proporciona una implementación base para las **pantallas intelige
1516
- **Interfaz Gráfica**: [LVGL v9.1.0](https://lvgl.io/).
1617
- **Librería de Gráficos**: [Arduino_GFX](https://github.com/moononournation/Arduino_GFX).
1718
- **Estabilización Anti-Flicker**: Estrategia de **"Aislamiento de Bus"** (SRAM + Bounce Buffer) para eliminar parpadeos por concurrencia en PSRAM.
18-
- **UI Modular**: Interfaz basada en componentes (Pages/Components) con LVGL 9.1.
19-
- **Configuración Persistente**: Los ajustes (tiempos de bomba) se guardan automáticamente en memoria flash (MemoryManager/NVS).
20-
- **Comunicación ESP-NOW**: Comunicación inalámbrica directa con la Máquina de Bebidas/Sistema de Riego. Envía selecciones de bebidas por broadcast.
19+
- **UI Modular**: Interfaz basada en componentes (Pages/Components) con LVGL 9.1 que consta de **3 Pantallas Principales**:
20+
1. **Selección de Bebidas**: Galería visual para ver y elegir cócteles.
21+
2. **Configuración de Recetas**: Modal interactivo para ajustar ingredientes y cantidades de cada cóctel.
22+
3. **Configuración de Bombas**: Ajuste de calibración y tiempos de las 4 bombas peristálticas.
23+
24+
[![Firmware Principal](https://img.shields.io/badge/Descargar_Firmware_Principal-Robot_Core-blueviolet?style=flat&logo=arduino)](https://github.com/Albert-Benavent-Cabrera/Robot-Core)
25+
- **Configuración Remota**: La pantalla recibe cócteles e ingredientes vía ESP-NOW desde la App Drinks (Robot Core). Al modificar valores en los sliders, la configuración se guarda en el servidor de forma remota, no localmente. Muestra datos "Mock" si no hay conexión estable.
26+
- **Comunicación ESP-NOW**: Comunicación inalámbrica directa con la Máquina de Bebidas. Envía selecciones de bebidas por broadcast.
2127
- **Sincronización Inteligente de Canal**: Escanea automáticamente la red WiFi objetivo para sintonizar su canal de radio con el receptor.
2228

2329
<p align="center">
@@ -30,11 +36,15 @@ Este proyecto proporciona una implementación base para las **pantallas intelige
3036
Este proyecto es totalmente compatible con el IDE de Arduino. Sigue estos pasos para configurarlo:
3137

3238
### 1. 📚 Preparación de Librerías
33-
Instala las siguientes **3 librerías** desde el **Gestor de Librerías** de Arduino (**Herramientas > Gestionar librerías**):
39+
40+
Instala estas **2 librerías** desde el **Gestor de Librerías** de Arduino (**Herramientas > Gestionar librerías**):
3441

3542
1. **lvgl** (v9.1.0) - Motor de gráficos.
36-
2. **Arduino_GFX_Library** - Driver de la pantalla.
37-
3. **GT911** - Driver del panel táctil.
43+
2. **GT911** - Driver del panel táctil.
44+
45+
Para **Arduino_GFX**, tienes dos opciones:
46+
* **Copiarla**: Copia la carpeta `lib/GFX_Library_for_Arduino` de este proyecto a tu carpeta de librerías de Arduino (`Documents/Arduino/libraries/`).
47+
* **Descargarla**: Instala **"GFX Library for Arduino"** indicando la versión **1.6.4** desde el Gestor.
3848

3949
> [!IMPORTANT]
4050
> Si recibes errores tipo `No such file or directory` con cualquiera de estos nombres, es porque falta la librería correspondiente en el gestor de Arduino.

display/display.ino

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22

33
#include "src/core/DisplayManager.hpp"
4-
#include "src/core/MemoryManager.hpp"
4+
55

66
void setup() {
77
// Initialize serial port
@@ -18,8 +18,7 @@ void setup() {
1818
Serial.println("######################################\n");
1919
Serial.flush();
2020

21-
// Initialize NVS (Preferences)
22-
MemoryManager::begin();
21+
2322

2423
// Get manager instance and start
2524
if (!DisplayManager::getInstance().begin()) {

display/src/core/Config.hpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,35 @@
101101
#define TOUCH_MAP_Y2 220 // Adjusted margin (Raw ~224 -> 480)
102102
#endif
103103

104+
105+
// --- Application Defaults (Mocks) ---
106+
#define SYNC_RETRY_INTERVAL_MS 5000
107+
108+
#include <vector>
109+
#include "models.hpp"
110+
111+
inline std::vector<ICocktail> getDefaultMockCocktails() {
112+
return {
113+
{"Cocacola", nullptr, 0xFF0000, {{"Cocacola", 1, 200}}},
114+
{"Orange Juice", nullptr, 0xFFA500, {{"Orange", 2, 200}}},
115+
{"Vodka shot", nullptr, 0x00FFFF, {{"Vodka", 3, 50}}},
116+
{"Vodka Coke", nullptr, 0x8B0000, {{"Vodka", 3, 50}, {"Cocacola", 1, 150}}},
117+
{"Screwdriver", nullptr, 0xFFD700, {{"Vodka", 3, 50}, {"Orange", 2, 150}}},
118+
{"Sex on Beach", nullptr, 0xFF1493, {{"Vodka", 3, 40}, {"Orange", 2, 100}, {"Grenadine", 4, 10}}},
119+
{"Tequila Sun", nullptr, 0xFF4500, {{"Tequila", 3, 50}, {"Orange", 2, 120}, {"Grenadine", 4, 10}}},
120+
{"Shirley T.", nullptr, 0xFF69B4, {{"Orange", 2, 100}, {"Grenadine", 4, 20}, {"Cocacola", 1, 50}}}
121+
};
122+
}
123+
124+
inline IPumpSettings getDefaultPumpSettings() {
125+
IPumpSettings s;
126+
for(int i=0; i<4; i++) {
127+
s.pwm[i] = 255;
128+
s.timeMs[i] = 1600;
129+
}
130+
s.synced = false;
131+
return s;
132+
}
133+
104134
#endif // CONFIG_HPP
135+

display/src/core/DataManager.hpp

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#ifndef DATA_MANAGER_HPP
2+
#define DATA_MANAGER_HPP
3+
4+
#include <Arduino.h>
5+
#include <vector>
6+
#include "remote_protocol.hpp"
7+
#include "models.hpp"
8+
#include "Config.hpp"
9+
#include "../ui/assets/icons.h"
10+
11+
class DataManager {
12+
public:
13+
static DataManager& getInstance() {
14+
static DataManager instance;
15+
return instance;
16+
}
17+
18+
// --- Recipes ---
19+
bool isRecipesSynced() const { return recipesSynced; }
20+
bool isUsingMocks() const { return usingMocks; }
21+
const std::vector<ICocktail>& getRecipes() const { return recipes; }
22+
23+
void clearRecipes() {
24+
recipes.clear();
25+
recipesSynced = false;
26+
usingMocks = false;
27+
}
28+
29+
void addRecipe(const RecipeSyncData& data) {
30+
// Clear if new sync session starts (Index 0) OR if we were using mocks
31+
if (data.index == 0 || usingMocks) {
32+
if (usingMocks) printf("[DataManager] Real data received. Clearing Mocks.\n");
33+
else printf("[DataManager] New Sync Session (Index 0). Clearing old data.\n");
34+
35+
recipes.clear();
36+
recipesSynced = false;
37+
usingMocks = false;
38+
}
39+
40+
if (!recipesSynced) {
41+
recipesSynced = true; // Mark as syncing started
42+
}
43+
44+
ICocktail c;
45+
c.name = String(data.name);
46+
mapMetadata(c);
47+
48+
static const char* PUMP_NAMES[] = {"Cocacola", "Orange Juice", "Vodka", "Grenadine"};
49+
for (int i=0; i<4; i++) {
50+
if (data.ingredientsMl[i] > 0) {
51+
c.ingredients.push_back({PUMP_NAMES[i], i+1, (int)data.ingredientsMl[i]});
52+
}
53+
}
54+
55+
recipes.push_back(c);
56+
lastUpdateTime = millis();
57+
}
58+
59+
void addRecipeFromConfig(const ICocktail& cocktail) {
60+
if (usingMocks) {
61+
recipes.clear();
62+
usingMocks = false;
63+
}
64+
if (!recipesSynced) {
65+
recipes.clear();
66+
recipesSynced = true;
67+
}
68+
ICocktail c = cocktail;
69+
mapMetadata(c);
70+
recipes.push_back(c);
71+
lastUpdateTime = millis();
72+
}
73+
74+
void updateRecipe(const ICocktail& updatedCocktail) {
75+
for (auto& c : recipes) {
76+
if (c.name == updatedCocktail.name) {
77+
c.ingredients = updatedCocktail.ingredients;
78+
lastUpdateTime = millis();
79+
printf("[DataManager] Optimistic Update for: %s\n", c.name.c_str());
80+
return;
81+
}
82+
}
83+
printf("[DataManager] Warning: Recipe not found for update: %s\n", updatedCocktail.name.c_str());
84+
}
85+
86+
void loadMocks() {
87+
if (recipesSynced && !recipes.empty() && !usingMocks) return; // Don't overwrite REAL live data
88+
89+
printf("[DataManager] Loading Mocks.\n");
90+
auto mocks = getDefaultMockCocktails();
91+
recipes.clear();
92+
for (const auto& m : mocks) {
93+
ICocktail c = m;
94+
mapMetadata(c);
95+
recipes.push_back(c);
96+
}
97+
recipesSynced = true;
98+
usingMocks = true; // Mark as Mocks
99+
lastUpdateTime = millis();
100+
}
101+
102+
103+
// --- Pumps ---
104+
const IPumpSettings& getPumpSettings() const { return pumps; }
105+
106+
void updatePumps(const PumpSyncData& data) {
107+
for(int i=0; i<4; i++) {
108+
pumps.pwm[i] = data.pwm[i];
109+
pumps.timeMs[i] = (int)(data.calibration[i] * 1000.0f);
110+
}
111+
pumps.synced = true;
112+
lastUpdateTime = millis();
113+
}
114+
115+
unsigned long getLastUpdate() const { return lastUpdateTime; }
116+
117+
private:
118+
DataManager() {}
119+
120+
void mapMetadata(ICocktail& c) {
121+
// Centralized logic for icon/color assignment
122+
if (c.name.indexOf("Coca") >= 0) { c.icon = ICON_COCKTAIL_COCA_COLA; c.color = 0xFF0000; }
123+
else if (c.name.indexOf("Orange") >= 0) { c.icon = ICON_COCKTAIL_GIN_TONIC; c.color = 0xFFA500; }
124+
else if (c.name.indexOf("Vodka") >= 0) { c.icon = ICON_COCKTAIL_VODKA; c.color = 0x00FFFF; }
125+
else if (c.name.indexOf("Sex") >= 0) { c.icon = ICON_COCKTAIL_SEX_ON_BEACH; c.color = 0xFF1493; }
126+
else if (c.name.indexOf("Tequila") >= 0) { c.icon = ICON_COCKTAIL_PORN_STAR; c.color = 0xFF4500; }
127+
else if (c.name.indexOf("Gin") >= 0) { c.icon = ICON_COCKTAIL_GIN_TONIC; c.color = 0xADD8E6; }
128+
else { c.icon = ICON_COCKTAIL_VODKA; c.color = 0x888888; }
129+
}
130+
131+
std::vector<ICocktail> recipes;
132+
bool recipesSynced = false;
133+
bool usingMocks = false;
134+
135+
IPumpSettings pumps = getDefaultPumpSettings();
136+
unsigned long lastUpdateTime = 0;
137+
};
138+
139+
#endif // DATA_MANAGER_HPP

display/src/core/DisplayManager.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,14 @@ class DisplayManager {
9494
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
9595
lv_indev_set_read_cb(indev, touchpad_read_cb);
9696

97+
printf("Initializing ESP-NOW Manager...\n");
98+
if (!ESPNowManager::getInstance().begin()) {
99+
printf("WARNING: ESP-NOW Init failed. Running in Offline/Mock mode.\n");
100+
}
101+
97102
printf("Initializing UI...\n");
98103
ui_init();
99104

100-
printf("Initializing ESP-NOW Manager...\n");
101-
ESPNowManager::getInstance().begin();
102-
103105
printf("System ready\n");
104106
return true;
105107
}

0 commit comments

Comments
 (0)