commit 1698c4d37521f396358bfa9037cb121b5342a54e Author: Clément SAILLANT Date: Fri Aug 1 17:22:17 2025 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb519f3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# PlatformIO +.pio/ +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch/ + +# Compilation +*.o +*.a +*.so +*.exe + +# IDE +.DS_Store +Thumbs.db + +# Logs +*.log + +# Backup files +*.bak +*.tmp +*~ + +# Configuration sensible (décommentez si nécessaire) +# src/config.h +# include/secrets.h + +# Documentation générée +docs/html/ +docs/latex/ + +# Archives +*.zip +*.tar.gz +*.rar + +# Fichiers de développement +test_* +debug_* +temp_* diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..cf27c54 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "files.associations": { + "*.ino": "cpp", + "platformio.ini": "ini" + }, + "C_Cpp.default.configurationProvider": "ms-vscode.vscode-json", + "editor.tabSize": 2, + "editor.insertSpaces": true, + "files.autoSave": "afterDelay", + "files.autoSaveDelay": 1000, + "terminal.integrated.defaultProfile.osx": "zsh", + "platformio-ide.forceUploadAndMonitor": false, + "platformio-ide.autoPreloadEnvTasks": true, + "explorer.fileNesting.enabled": true, + "explorer.fileNesting.patterns": { + "platformio.ini": ".vscode/*, lib/*, test/*, .pio/*, .gitignore", + "README.md": "*.md" + }, + "stm32-for-vscode.openOCDPath": false, + "stm32-for-vscode.armToolchainPath": false +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..ed8270f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,200 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "PlatformIO: Build Main Project", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "main"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Upload Main Project", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "main", "--target", "upload"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Test RTC Module", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "rtc_test", "--target", "upload"], + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Test P10 Matrix", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "p10_test", "--target", "upload"], + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Erase NVS Memory", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "nvs_erase", "--target", "upload"], + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Test Cascade (2 panels)", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "test_cascade", "--target", "upload"], + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Cascade 2x1 (64x16)", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "cascade_2x1", "--target", "upload"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Cascade 3x1 (96x16)", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "cascade_3x1", "--target", "upload"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Cascade 4x1 (128x16)", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "cascade_4x1", "--target", "upload"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Cascade 2x2 (64x32)", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "cascade_2x2", "--target", "upload"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Cascade 6x1 (192x16)", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "cascade_6x1", "--target", "upload"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Cascade 8x1 (256x16)", + "type": "shell", + "command": "pio", + "args": ["run", "-e", "cascade_8x1", "--target", "upload"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": "$gcc" + }, + { + "label": "PlatformIO: Monitor Serial", + "type": "shell", + "command": "pio", + "args": ["device", "monitor"], + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "isBackground": true + }, + { + "label": "PlatformIO: Clean Project", + "type": "shell", + "command": "pio", + "args": ["run", "--target", "clean"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + } + } + ] +} diff --git a/CASCADE_GUIDE.md b/CASCADE_GUIDE.md new file mode 100644 index 0000000..3dce1e9 --- /dev/null +++ b/CASCADE_GUIDE.md @@ -0,0 +1,226 @@ +# Guide des Panneaux P10 en Cascade + +## 🔗 Vue d'ensemble + +Ce projet supporte maintenant plusieurs panneaux P10 connectés en cascade pour créer des affichages plus larges ou plus hauts. + +## 📐 Configurations Supportées + +### Configurations Horizontales (recommandées) +- **1x1** : 32x16 pixels (1 panneau) - Configuration standard +- **2x1** : 64x16 pixels (2 panneaux) - Ideal pour texte plus long +- **3x1** : 96x16 pixels (3 panneaux) - Texte défilant étendu +- **4x1** : 128x16 pixels (4 panneaux) - Affichage type bandeau +- **6x1** : 192x16 pixels (6 panneaux) - Grand bandeau +- **8x1** : 256x16 pixels (8 panneaux) - Très grand bandeau + +### Configurations Verticales/Mixtes +- **2x2** : 64x32 pixels (4 panneaux) - Affichage carré +- **1x2** : 32x32 pixels (2 panneaux) - Plus de hauteur +- **4x2** : 128x32 pixels (8 panneaux) - Grand affichage + +## 🛠️ Connexion Physique + +### Connexion en Cascade (Chaînage) +``` +ESP32 ──── Panneau 1 ──── Panneau 2 ──── Panneau 3 ──── ... + (Premier) (Deuxième) (Troisième) +``` + +### Détails de Connexion +1. **Premier panneau** : Connecté directement à l'ESP32 (voir WIRING.md) +2. **Panneaux suivants** : Connectés via les ports de sortie du panneau précédent +3. **Alimentation** : Chaque panneau doit être alimenté en 5V individuellement + +### Important - Alimentation +``` +⚠️ ATTENTION ALIMENTATION ! + +Chaque panneau P10 consomme environ 1-2A sous 5V +- 2 panneaux : 5V/4A minimum +- 4 panneaux : 5V/8A minimum +- 6 panneaux : 5V/12A minimum + +Utilisez une alimentation adaptée ! +``` + +## 🎯 Compilation pour Cascade + +### Commandes PlatformIO + +```bash +# 2 panneaux horizontaux (64x16) +pio run -e cascade_2x1 --target upload + +# 3 panneaux horizontaux (96x16) +pio run -e cascade_3x1 --target upload + +# 4 panneaux horizontaux (128x16) +pio run -e cascade_4x1 --target upload + +# 2x2 panneaux (64x32) +pio run -e cascade_2x2 --target upload + +# 6 panneaux horizontaux (192x16) +pio run -e cascade_6x1 --target upload + +# 8 panneaux horizontaux (256x16) +pio run -e cascade_8x1 --target upload + +# Test de cascade (2 panneaux) +pio run -e test_cascade --target upload +``` + +### Configuration Personnalisée + +Pour une configuration non-standard, modifiez `platformio.ini` : + +```ini +[env:custom_cascade] +extends = env:main +build_flags = + ${env.build_flags} + -DMATRIX_WIDTH=32 ; Largeur d'un panneau + -DMATRIX_HEIGHT=16 ; Hauteur d'un panneau + -DMATRIX_PANELS_X=5 ; Nombre panneaux horizontaux + -DMATRIX_PANELS_Y=1 ; Nombre panneaux verticaux + -DCASCADE_MODE=1 +``` + +## 🧪 Test des Panneaux + +### Test d'Alignement +```bash +pio run -e test_cascade --target upload +``` + +Ce test affiche : +1. **Bordures** : Contour de chaque panneau +2. **Numérotation** : P1, P2, P3... sur chaque panneau +3. **Couleurs** : Test de toutes les couleurs +4. **Texte défilant** : Test sur toute la largeur + +### Vérifications Visuelles +- ✅ Tous les panneaux s'allument +- ✅ Bordures alignées correctement +- ✅ Numérotation séquentielle (P1, P2, P3...) +- ✅ Couleurs uniformes sur tous les panneaux +- ✅ Texte défile sans coupure + +## ⚙️ Ajustements Automatiques + +### Luminosité Auto-Adaptée +```cpp +// Le code ajuste automatiquement la luminosité : +1-2 panneaux : 125/255 (luminosité normale) +3-4 panneaux : 100/255 (réduite) +5-6 panneaux : 80/255 (plus réduite) +7+ panneaux : 60/255 (très réduite) +``` + +### Centrage Automatique +- **Horloge** : Centrée automatiquement sur la largeur totale +- **Texte défilant** : Utilise toute la largeur disponible +- **Interface web** : Fonctionne normalement + +## 🌐 Interface Web Adaptée + +L'interface web fonctionne normalement avec les cascades : +- Configuration identique +- Texte défilant adapté à la largeur +- Couleurs appliquées sur tous les panneaux +- Luminosité globale + +## 🔧 Dépannage Cascade + +### Problème : Un panneau ne s'allume pas +1. ✅ Vérifiez l'alimentation 5V de chaque panneau +2. ✅ Vérifiez les connexions en cascade +3. ✅ Testez avec moins de panneaux + +### Problème : Affichage décalé +1. ✅ Vérifiez l'ordre des panneaux (P1, P2, P3...) +2. ✅ Utilisez le test d'alignement +3. ✅ Vérifiez les paramètres PANELS_X et PANELS_Y + +### Problème : Scintillement +1. ✅ Réduisez la luminosité +2. ✅ Vérifiez l'alimentation (suffisamment puissante ?) +3. ✅ Réduisez `PxMATRIX_SPI_FREQUENCY` + +### Problème : Texte coupé +1. ✅ Vérifiez que TOTAL_WIDTH est correct +2. ✅ Utilisez le test de texte défilant +3. ✅ Vérifiez la configuration PANELS_X + +## 📋 Checklist Installation Cascade + +### Étape 1 : Préparation +- [ ] Alimentation suffisante calculée (2A × nombre de panneaux) +- [ ] Panneaux P10 testés individuellement +- [ ] Câbles de connexion préparés + +### Étape 2 : Connexion Physique +- [ ] Premier panneau connecté à l'ESP32 +- [ ] Panneaux en cascade connectés +- [ ] Alimentation 5V sur chaque panneau +- [ ] Masse commune vérifiée + +### Étape 3 : Configuration Logicielle +- [ ] Environnement cascade choisi (ex: cascade_2x1) +- [ ] Code compilé et téléversé +- [ ] Test d'alignement réussi + +### Étape 4 : Test Final +- [ ] Tous les panneaux s'allument +- [ ] Numérotation correcte visible +- [ ] Horloge centrée correctement +- [ ] Texte défile sur toute la largeur +- [ ] Interface web accessible + +## 💡 Conseils Optimisation + +### Performance +- Plus de panneaux = plus de données à traiter +- Réduisez la luminosité si nécessaire +- Utilisez une alimentation stable + +### Esthétique +- Alignez physiquement les panneaux parfaitement +- Utilisez des supports adaptés +- Protégez les connexions + +### Fiabilité +- Alimentation dimensionnée correctement +- Connexions bien fixées +- Test avant installation finale + +## 🎨 Exemples d'Utilisation + +### Bandeau d'Information (4x1) +``` +┌─────────────────────────────┐ +│ 12:34 ESP32 CLOCK │ +│ Aujourd'hui 15°C - Beau... │ +└─────────────────────────────┘ +``` + +### Affichage Carré (2x2) +``` +┌─────────────────┐ +│ 12:34 │ +│ ESP32 CLOCK │ +│ │ +│ Message long... │ +└─────────────────┘ +``` + +### Grand Bandeau (8x1) +``` +┌───────────────────────────────────────────────────────────┐ +│ 12:34 - ESP32 DIGITAL CLOCK │ +│ Très long message défilant avec beaucoup d'informations... │ +└───────────────────────────────────────────────────────────┘ +``` + +La cascade de panneaux P10 permet de créer des affichages personnalisés adaptés à vos besoins ! diff --git a/ESP32 P10 RGB 32x16 Digital Clock.txt b/ESP32 P10 RGB 32x16 Digital Clock.txt new file mode 100644 index 0000000..bacf143 --- /dev/null +++ b/ESP32 P10 RGB 32x16 Digital Clock.txt @@ -0,0 +1,2285 @@ +//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +// ################################################################################## +// # I SUGGEST YOU WATCH THE VIDEO UNTIL THE END, SO YOU KNOW HOW TO USE THIS CODE. # +// ################################################################################## +// +// Information about the P10 RGB Panel that I use : +// - P10 RGB 32x16 HUB75 Scan 1/8 Full Color SMD. +// - Information written on the P10 RGB board : P10-2727-8S-32X16-A +// - IC or Chip on the P10 RGB board : +// > RUC7258D +// > DP5125D +// > 74HC245KA +// - HUB75 (Scan 1/8) : +// ----------- +// | DR1 | DG1 | +// | DB1 | GND | +// | DR2 | DG2 | +// | DB2 | GND | +// | A | B | +// | C | GND | +// | CLK | STB | +// | OE | GND | +// ----------- +// +// Software : +// - Arduino IDE 1.8.19 +// +// Arduino core for the ESP32 : +// - Arduino core for the ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6 and ESP32-H2 (V2.0.16). +// +// Arduino Libraries : +// - Adafruit BusIO by Adafruit (V1.16.1). +// - Adafruit GFX Library by Adafruit (V1.11.9). +// - PxMatrix Library by 2dom (Dominic Buchstaller) (V1.8.2). +// - RTClib by Adafruit (V2.1.4) +// +// Hardware : +// - ESP32 DEVKIT V1. +// - P10 RGB 32x16. +// - DS3231 RTC Module. +// - 5V Power Supply. +// - For more details, see the installation picture. +// +// Troubleshooting : https://github.com/2dom/PxMatrix/tree/master?tab=readme-ov-file#troubleshooting +// +// Reference : +// - PxMatrix : https://github.com/2dom/PxMatrix/tree/master +// - Power, Power and Power! : https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA?tab=readme-ov-file#power-power-and-power +// - Micro Controller | ESP LED Matrix P10 RGB : https://andriantriputra.medium.com/micro-controller-esp-led-matrix-p10-rgb-fcb21b576296 +// - Adafruit_GFX getTextBounds() : https://forums.adafruit.com/viewtopic.php?p=486141#p486141 +// - Adafruit GFX font size points to pixels for Epapers : https://forum.arduino.cc/t/adafruit-gfx-font-size-points-to-pixels-for-epapers/556091/11 +// - localIP2st : https://gist.github.com/loosak/76019faaefd5409fca67 +// - ESP32 Save Data Permanently using Preferences Library : https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/ +// - And from other sources. +//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + + + + +//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 01_Test_and_Setup_DS3231_RTC_Module +//----------------------------------------Including Libraries. +#include "RTClib.h" +//---------------------------------------- + +char daysOfTheWeek[8][10] = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "ERROR"}; + +String inputString = ""; // a String to hold incoming data. +bool stringComplete = false; // whether the string is complete. + +int d_year; +byte d_month, d_day, daysOfTheWeek_Val; +byte t_hour, t_minute, t_second; + +unsigned long prevMill_Update_DateTime = 0; +const long interval_Update_DateTime = 1000; + +RTC_DS3231 rtc; + + + + + + +//________________________________________________________________________________ VOID SETUP() +void setup() { + // put your setup code here, to run once: + + delay(2000); + Serial.begin(115200); + + // reserve 200 bytes for the inputString. + inputString.reserve(200); + + //----------------------------------------Starting and setting up the DS3231 RTC module. + Serial.println(); + Serial.println("------------"); + Serial.println("Starting the DS3231 RTC module."); + if (!rtc.begin()) { + Serial.println("Couldn't find RTC"); + while (1); + } + Serial.println("Successfully started the DS3231 RTC module."); + Serial.println("------------"); + Serial.println(); + //---------------------------------------- + + //---------------------------------------- + Serial.println(); + Serial.println("------------"); + Serial.println("Serial monitor settings :"); + Serial.println("- End Char : Newline"); + Serial.println("- Baud Rate : 115200"); + Serial.println("------------"); + Serial.println(); + //---------------------------------------- + + Serial.println(); + Serial.println("------------"); + Serial.println("Example command to set the time and date on the RTC module : "); + Serial.println("SET,2024,7,9,12,3,0"); + Serial.println(); + Serial.println("SET = command to set."); + Serial.println("2024 = Year."); + Serial.println("7 = Month."); + Serial.println("9=Day."); + Serial.println("12 = Hour."); + Serial.println("3 = Minute."); + Serial.println("0 = Second."); + Serial.println("------------"); + Serial.println(); + + delay(3000); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ VOID LOOP() +void loop() { + // put your main code here, to run repeatedly: + + serialEvent(); + + unsigned long currentMillis_Update_DateTime = millis(); + if (currentMillis_Update_DateTime - prevMill_Update_DateTime >= interval_Update_DateTime) { + prevMill_Update_DateTime = currentMillis_Update_DateTime; + + get_DateTime(); + } + + // print the string when a newline arrives. + if (stringComplete) { + Serial.print("Input String : "); + Serial.println(inputString); + + String command = ""; + command = getValue(inputString, ',', 0); + + if (command == "SET") { + Serial.println(); + Serial.println("------------"); + Serial.println("Set the Time and Date of the DS3231 RTC Module."); + Serial.println("Incoming settings data : "); + + d_year = getValue(inputString, ',', 1).toInt(); + d_month = getValue(inputString, ',', 2).toInt(); + d_day = getValue(inputString, ',', 3).toInt(); + t_hour = getValue(inputString, ',', 4).toInt(); + t_minute = getValue(inputString, ',',5).toInt(); + t_second = getValue(inputString, ',', 6).toInt(); + + Serial.print("- Year : ");Serial.println(d_year); + Serial.print("- Month : ");Serial.println(d_month); + Serial.print("- Day : ");Serial.println(d_day); + Serial.print("- Hour : ");Serial.println(t_hour); + Serial.print("- Minute : ");Serial.println(t_minute); + Serial.print("- Second : ");Serial.println(t_second); + + Serial.println("Set Time and Date..."); + rtc.adjust(DateTime(d_year, d_month, d_day, t_hour, t_minute, t_second)); + + Serial.println("Setting the Time and Date has been completed."); + Serial.println("------------"); + Serial.println(); + } + + // clear the string: + inputString = ""; + stringComplete = false; + } +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ serialEvent() +void serialEvent() { + while (Serial.available()) { + // get the new byte. + char inChar = (char)Serial.read(); + + // if the incoming character is a newline, set a flag so the main loop can do something about it. + if (inChar == '\n') { + stringComplete = true; + return; + } + + // add it to the inputString. + inputString += inChar; + } +} +//________________________________________________________________________________ + +//________________________________________________________________________________ getValue() +// String function to process the data received +// I got this from : https://www.electroniclinic.com/reyax-lora-based-multiple-sensors-monitoring-using-arduino/ +String getValue(String data, char separator, int index) { + int found = 0; + int strIndex[] = { 0, -1 }; + int maxIndex = data.length() - 1; + + for (int i = 0; i <= maxIndex && found <= index; i++) { + if (data.charAt(i) == separator || i == maxIndex) { + found++; + strIndex[0] = strIndex[1] + 1; + strIndex[1] = (i == maxIndex) ? i+1 : i; + } + } + return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ get_DateTime() +void get_DateTime() { + DateTime now = rtc.now(); + + d_year = now.year(); + d_month = now.month(); + d_day = now.day(); + daysOfTheWeek_Val = now.dayOfTheWeek(); + if (daysOfTheWeek_Val > 7 || daysOfTheWeek_Val < 0) daysOfTheWeek_Val = 7; + t_hour = now.hour(); + t_minute = now.minute(); + t_second = now.second(); + + char full_DateTime[60]; + sprintf(full_DateTime, "%s | %02d-%02d-%d | %02d:%02d:%02d", daysOfTheWeek[daysOfTheWeek_Val], d_day, d_month, d_year, t_hour, t_minute, t_second); + + Serial.print("Date Time : "); + Serial.println(full_DateTime); +} +//________________________________________________________________________________ +//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + + + + +//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 02_Test_P10_RGB_32x16 +// This is how many color levels the display shows - the more the slower the update. +//#define PxMATRIX_COLOR_DEPTH 4 + +// Defines the speed of the SPI bus (reducing this may help if you experience noisy images). +// The original value of PxMATRIX_SPI_FREQUENCY in the PxMatrix library example is 20000000. +// I changed the value to 10000000 because if I use the value 20000000, then "ghosting" or "noise" appears on my P10 32x16 RGB panel. +// Each panel may be a different case. If "ghosting" or "noise" appears on your P10 RGB panel, try changing the PxMATRIX_SPI_FREQUENCY value. +// You can use the values ​​20000000, 15000000, 10000000 and 8000000. Or you can also try using other values. +#define PxMATRIX_SPI_FREQUENCY 10000000 + +// Creates a second buffer for backround drawing (doubles the required RAM). +//#define PxMATRIX_double_buffer true + +//----------------------------------------Including Libraries. +#include +//---------------------------------------- + +//----------------------------------------Pins for LED MATRIX. +#define P_LAT 5 +#define P_A 19 +#define P_B 23 +#define P_C 18 +#define P_OE 4 +//---------------------------------------- + +// Defines the width and height of the panel in pixels. +#define matrix_width 32 +#define matrix_height 16 + +// Timer setup. +// Create a hardware timer of ESP32. +hw_timer_t * timer = NULL; +portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; + +// This defines the 'on' time of the display is us. +// The larger this number, the brighter the display. If too large the ESP will crash. +uint8_t display_draw_time = 30; // 30-70 is usually fine. + +// Declaring the "PxMATRIX" object as a "display" and its settings. +PxMATRIX display(matrix_width, matrix_height, P_LAT, P_OE, P_A, P_B, P_C); + +//----------------------------------------Variable for some colors. +// display.color565(R value = 0-255, G value = 0-255, B value = 0-255); +uint16_t myRED = display.color565(255, 0, 0); +uint16_t myGREEN = display.color565(0, 255, 0); +uint16_t myBLUE = display.color565(0, 0, 255); +uint16_t myYELLOW = display.color565(255, 255, 0); +uint16_t myCYAN = display.color565(0, 255, 255); +uint16_t myFUCHSIA = display.color565(255, 0, 255); +uint16_t myBLACK = display.color565(0, 0, 0); +uint16_t myWHITE = display.color565(255, 255, 255); + +uint16_t myCOLOR_ARRAY[4] = {myRED, myGREEN, myBLUE, myWHITE}; +//---------------------------------------- + + + + + + +//________________________________________________________________________________ IRAM_ATTR display_updater() +// Interrupt handler for Timer. +void IRAM_ATTR display_updater(){ + // Increment the counter and set the time of ISR. + portENTER_CRITICAL_ISR(&timerMux); + display.display(display_draw_time); + portEXIT_CRITICAL_ISR(&timerMux); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ display_update_enable() +// Subroutine to enable and disable interrupt timers. +void display_update_enable(bool is_enable) { + if (is_enable){ + timer = timerBegin(0, 80, true); + timerAttachInterrupt(timer, &display_updater, true); + timerAlarmWrite(timer, 1500, true); + timerAlarmEnable(timer); + } + else{ + timerDetachInterrupt(timer); + timerAlarmDisable(timer); + } +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ VOID SETUP() +void setup() { + // put your setup code here, to run once: + + delay(2000); + Serial.begin(115200); + Serial.println(); + + // Display initialization. + display.begin(8); //--> Value 8 for 1/8 row scan panel. + delay(100); + + // Enable Timer Interrupts. + display_update_enable(true); + delay(100); + + display.clearDisplay(); + delay(1000); + + display.setBrightness(125); //--> Range from 0 to 255. + delay(100); + + display.fillScreen(myRED); + delay(1000); + display.fillScreen(myGREEN); + delay(1000); + display.fillScreen(myBLUE); + delay(1000); + display.fillScreen(myWHITE); + delay(1000); + + display.clearDisplay(); + delay(1000); + + display.setTextWrap(false); + display.setTextSize(1); + display.setRotation(0); + delay(100); + + display.fillScreen(display.color565(255, 0, 0)); + display.setTextColor(display.color565(255, 255, 255)); + display.setCursor(0, 0); + display.print("UTEH"); + display.setTextColor(display.color565(255, 255, 255)); + display.setCursor(15, 9); + display.print("STR"); + delay(2500); + + display.clearDisplay(); + delay(1000); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ VOID LOOP() +void loop() { + // put your main code here, to run repeatedly: + + int myCOLOR_ARRAY_Length = sizeof(myCOLOR_ARRAY) / sizeof(myCOLOR_ARRAY[0]); + + for (byte i = 0; i < myCOLOR_ARRAY_Length; i++) { + display.setTextColor(myCOLOR_ARRAY[i]); + display.setCursor(0, 0); + display.print("1234"); + display.setCursor(0, 9); + display.print("ABCD"); + delay(2500); + + display.clearDisplay(); + delay(1000); + + display.setTextColor(myCOLOR_ARRAY[i]); + display.setCursor(4, 0); + display.print("1234"); + display.setCursor(4, 9); + display.print("ABCD"); + delay(2500); + + display.clearDisplay(); + delay(1000); + + display.setCursor(9, 0); + display.print("1234"); + display.setCursor(9, 9); + display.print("ABCD"); + delay(2500); + + display.clearDisplay(); + delay(1000); + } +} +//________________________________________________________________________________ +//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + + + + +//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 03_P10_RGB_32x16_Digital_Clock +// This is how many color levels the display shows - the more the slower the update. +//#define PxMATRIX_COLOR_DEPTH 4 + +// Defines the speed of the SPI bus (reducing this may help if you experience noisy images). +// The original value of PxMATRIX_SPI_FREQUENCY in the PxMatrix library example is 20000000. +// I changed the value to 10000000 because if I use the value 20000000, then "ghosting" or "noise" appears on my P10 32x16 RGB panel. +// Each panel may be a different case. If "ghosting" or "noise" appears on your P10 RGB panel, try changing the PxMATRIX_SPI_FREQUENCY value. +// You can use the values ​​20000000, 15000000, 10000000 and 8000000. Or you can also try using other values. +#define PxMATRIX_SPI_FREQUENCY 10000000 + +// Creates a second buffer for backround drawing (doubles the required RAM). +//#define PxMATRIX_double_buffer true + +//----------------------------------------Including Libraries. +#include +#include "RTClib.h" +//---------------------------------------- + +//----------------------------------------Pins for LED MATRIX. +#define P_LAT 5 +#define P_A 19 +#define P_B 23 +#define P_C 18 +#define P_OE 4 +//---------------------------------------- + +// Defines the width and height of the panel in pixels. +#define matrix_width 32 +#define matrix_height 16 + +// Timer setup. +// Create a hardware timer of ESP32. +hw_timer_t * timer = NULL; +portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; + +// This defines the 'on' time of the display is us. +// The larger this number, the brighter the display. If too large the ESP will crash. +uint8_t display_draw_time = 30; // 30-70 is usually fine. + +// Declaring the "PxMATRIX" object as a "display" and its settings. +PxMATRIX display(matrix_width, matrix_height, P_LAT, P_OE, P_A, P_B, P_C); + +//----------------------------------------Variable for some colors. +uint16_t myRED = display.color565(255, 0, 0); +uint16_t myGREEN = display.color565(0, 255, 0); +uint16_t myBLUE = display.color565(0, 0, 255); +uint16_t myYELLOW = display.color565(255, 255, 0); +uint16_t myCYAN = display.color565(0, 255, 255); +uint16_t myFUCHSIA = display.color565(255, 0, 255); +uint16_t myWHITE = display.color565(255, 255, 255); +uint16_t myBLACK = display.color565(0, 0, 0); + +uint16_t myCOLOR_ARRAY[7] = {myRED, myGREEN, myBLUE, myYELLOW, myCYAN, myFUCHSIA, myWHITE}; +int cnt_Color = 0; +int myCOLOR_ARRAY_Length = sizeof(myCOLOR_ARRAY) / sizeof(myCOLOR_ARRAY[0]); +//---------------------------------------- + +// Timer/millis variables for scrolling text. +unsigned long prevMill_Scroll_Text = 0; +byte scrolling_Speed = 35; + +// Variables used to scroll text. +int scrolling_Y_Pos = 0; +long scrolling_X_Pos; +long scrolling_X_Pos_CT; +uint16_t scrolling_Text_Color; +uint16_t text_Color; +char scrolling_Text[151]; +uint16_t text_Length_In_Pixel; +bool set_up_Scrolling_Text_Length = true; +bool start_Scroll_Text = false; +byte scrolling_text_Display_Order = 0; +byte Display_Mode; + +// Timer/millis variable to update time data. +unsigned long prevMill_Update_Time = 0; +const long interval_Update_Time = 1000; + +// Timer/millis variable to display time (hours and minutes). +unsigned long prevMill_Show_Clock = 0; +const long interval_Show_Clock = 500; + +// Variables to hold date and time data. +char daysOfTheWeek[7][10] = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"}; +char t_Minute[3]; +byte minute_Val, last_minute_Val; +char t_Hour[3]; +char day_and_date_Text[25]; +bool blink_Colon = false; +uint16_t clock_Color; +uint16_t day_and_date_Text_Color; + +// Declare the “RTC_DS3231” object as “rtc”. +RTC_DS3231 rtc; + + + + + + +//________________________________________________________________________________ IRAM_ATTR display_updater() +// Interrupt handler for Timer. +void IRAM_ATTR display_updater(){ + // Increment the counter and set the time of ISR. + portENTER_CRITICAL_ISR(&timerMux); + display.display(display_draw_time); + portEXIT_CRITICAL_ISR(&timerMux); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ display_update_enable() +// Subroutine to enable and disable interrupt timers. +void display_update_enable(bool is_enable) { + if (is_enable){ + timer = timerBegin(0, 80, true); + timerAttachInterrupt(timer, &display_updater, true); + timerAlarmWrite(timer, 1500, true); + timerAlarmEnable(timer); + } + else{ + timerDetachInterrupt(timer); + timerAlarmDisable(timer); + } +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ run_Scrolling_Text() +// Subroutine for scrolling text. +void run_Scrolling_Text(uint8_t st_Y_Pos, byte st_Speed, char * st_Text, uint16_t st_Color) { + if (start_Scroll_Text == true && set_up_Scrolling_Text_Length == true) { + if (strlen(st_Text) > 0) { + text_Length_In_Pixel = getTextWidth(st_Text); + scrolling_X_Pos = matrix_width; + + set_up_Scrolling_Text_Length = false; + } else { + start_Scroll_Text = false; + return; + } + } + + unsigned long currentMillis_Scroll_Text = millis(); + if (currentMillis_Scroll_Text - prevMill_Scroll_Text >= st_Speed) { + prevMill_Scroll_Text = currentMillis_Scroll_Text; + + scrolling_X_Pos--; + if (scrolling_X_Pos < -(matrix_width + text_Length_In_Pixel)) { + set_up_Scrolling_Text_Length = true; + start_Scroll_Text = false; + + return; + } + + scrolling_X_Pos_CT = scrolling_X_Pos + 1; + + display.setTextColor(myBLACK); + display.setCursor(scrolling_X_Pos_CT, st_Y_Pos); + display.print(st_Text); + + display.setTextColor(st_Color); + display.setCursor(scrolling_X_Pos, st_Y_Pos); + display.print(st_Text); + } +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ getTextWidth() +// Subroutine to get the length of text in pixels. +uint16_t getTextWidth(const char* text) { + int16_t x1, y1; + uint16_t w, h; + display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h); + return w; +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ drawColon() +void drawColon(int16_t x, int16_t y, uint16_t colonColor) { + display.drawPixel(x, y, colonColor); + display.drawPixel(x+1, y, colonColor); + display.drawPixel(x, y+1, colonColor); + display.drawPixel(x+1, y+1, colonColor); + + display.drawPixel(x, y+3, colonColor); + display.drawPixel(x+1, y+3, colonColor); + display.drawPixel(x, y+4, colonColor); + display.drawPixel(x+1, y+4, colonColor); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ get_Time() +void get_Time() { + DateTime now = rtc.now(); + + minute_Val = now.minute(); + + sprintf(t_Hour, "%02d", now.hour()); + sprintf(t_Minute, "%02d", now.minute()); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ get_Date() +void get_Date() { + DateTime now = rtc.now(); + + sprintf(day_and_date_Text, "%s, %02d-%02d-%d", daysOfTheWeek[now.dayOfTheWeek()], now.day(), now.month(), now.year()); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ VOID SETUP() +void setup() { + // put your setup code here, to run once: + + delay(1000); + Serial.begin(115200); + Serial.println(); + + //----------------------------------------Starting and setting up the DS3231 RTC module. + Serial.println(); + Serial.println("------------"); + Serial.println("Starting the DS3231 RTC module."); + if (!rtc.begin()) { + Serial.println("Couldn't find RTC"); + while (1); + } + Serial.println("Successfully started the DS3231 RTC module."); + Serial.println("------------"); + //---------------------------------------- + + // Display initialization. + display.begin(8); //--> Value 8 for 1/8 row scan panel. + delay(100); + + // Enable Timer Interrupts. + display_update_enable(true); + delay(100); + + display.clearDisplay(); + delay(1000); + + display.setBrightness(125); //--> Range from 0 to 255. + delay(100); + + display.fillScreen(myRED); + delay(1000); + display.fillScreen(myGREEN); + delay(1000); + display.fillScreen(myBLUE); + delay(1000); + display.fillScreen(myWHITE); + delay(1000); + + display.clearDisplay(); + delay(1000); + + display.setTextWrap(false); + display.setTextSize(1); + display.setRotation(0); + delay(1000); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ VOID LOOP() +void loop() { + // put your main code here, to run repeatedly: + + //----------------------------------------Set the Clock and Date display mode. + // - Display_Mode = 1. The colors for the clock display, scrolling text for the date and other scrolling text are set manually. + // - Display_Mode = 2. The colors for the clock display, scrolling text for the date and other scrolling text change sequentially based on the color list above. + Display_Mode = 1; + //---------------------------------------- + + + + + //----------------------------------------Display_Mode = 1. + if (Display_Mode == 1) { + //::::::::::::::::::Timer/Millis to update clock data. + unsigned long currentMillis_Update_Time = millis(); + if (currentMillis_Update_Time - prevMill_Update_Time >= interval_Update_Time) { + prevMill_Update_Time = currentMillis_Update_Time; + + get_Time(); + blink_Colon = !blink_Colon; + } + //:::::::::::::::::: + + //::::::::::::::::::Timer/Millis to display hours and minutes. + unsigned long currentMillis_Show_Clock = millis(); + if (currentMillis_Show_Clock - prevMill_Show_Clock >= interval_Show_Clock) { + prevMill_Show_Clock = currentMillis_Show_Clock; + + display.setTextSize(1); + + clock_Color = myRED; + + if (last_minute_Val != minute_Val) display.fillRect(1, 0, 11, 7, myBLACK); + display.setTextColor(clock_Color); + display.setCursor(1, 0); + display.print(t_Hour); + + if (blink_Colon == true) { + drawColon(15, 1, clock_Color); + } else { + drawColon(15, 1, myBLACK); + } + + if (last_minute_Val != minute_Val) display.fillRect(20, 0, 11, 7, myBLACK); + display.setTextColor(clock_Color); + display.setCursor(20, 0); + display.print(t_Minute); + + last_minute_Val = minute_Val; + } + //:::::::::::::::::: + + //::::::::::::::::::Conditions for setting and preparing scrolling text. + // "start_Scroll_Text = false" means scrolling has not been executed. + // After the settings and preparations for scrolling text below are complete, "start_Scroll_Text = true" to start scrolling text. + // "start_Scroll_Text" will return "false" if scrolling the text is complete or the scrolled text is empty. + if (start_Scroll_Text == false) { + scrolling_text_Display_Order++; + if (scrolling_text_Display_Order > 2) scrolling_text_Display_Order = 1; + + // Conditions for scrolling text containing the name of the day and date. + if (scrolling_text_Display_Order == 1) { + get_Date(); + display.setTextSize(1); + scrolling_Y_Pos = 8; //--> Y position settings for scrolling text. + scrolling_Speed = 45; //--> Speed ​​settings for scrolling text. + day_and_date_Text_Color = myGREEN; + scrolling_Text_Color = day_and_date_Text_Color; //--> Color settings for scrolling text. You can also use: scrolling_Text_Color = display.color565(255, 0, 0); + strcpy(scrolling_Text, day_and_date_Text); //--> Sets the displayed text on scrolling text. + } + + // Conditions for scrolling the text you want. + if (scrolling_text_Display_Order == 2) { + display.setTextSize(1); + scrolling_Y_Pos = 8; //--> Y position settings for scrolling text. + scrolling_Speed = 45; //--> Speed ​​settings for scrolling text. + text_Color = myBLUE; + scrolling_Text_Color = text_Color; //--> Color settings for scrolling text. You can also use: scrolling_Text_Color = display.color565(255, 0, 0); + strcpy(scrolling_Text, "P10 RGB 32x16 Digital Clock. Display Mode : 1."); //--> Sets the displayed text on scrolling text. + } + + start_Scroll_Text = true; + } + //:::::::::::::::::: + } + //---------------------------------------- + + + + + //----------------------------------------Display_Mode = 2. + if (Display_Mode == 2) { + //:::::::::::::::::: + unsigned long currentMillis_Update_Time = millis(); + if (currentMillis_Update_Time - prevMill_Update_Time >= interval_Update_Time) { + prevMill_Update_Time = currentMillis_Update_Time; + + get_Time(); + blink_Colon = !blink_Colon; + } + //:::::::::::::::::: + + //:::::::::::::::::: + unsigned long currentMillis_Show_Clock = millis(); + if (currentMillis_Show_Clock - prevMill_Show_Clock >= interval_Show_Clock) { + prevMill_Show_Clock = currentMillis_Show_Clock; + + display.setTextSize(1); + + clock_Color = myCOLOR_ARRAY[cnt_Color]; + + if (last_minute_Val != minute_Val) display.fillRect(1, 0, 11, 7, myBLACK); + display.setTextColor(clock_Color); + display.setCursor(1, 0); + display.print(t_Hour); + + if (blink_Colon == true) { + drawColon(15, 1, clock_Color); + } else { + drawColon(15, 1, myBLACK); + } + + if (last_minute_Val != minute_Val) display.fillRect(20, 0, 11, 7, myBLACK); + display.setTextColor(clock_Color); + display.setCursor(20, 0); + display.print(t_Minute); + + last_minute_Val = minute_Val; + } + //:::::::::::::::::: + + //:::::::::::::::::: + if (start_Scroll_Text == false) { + scrolling_text_Display_Order++; + if (scrolling_text_Display_Order > 3) scrolling_text_Display_Order = 1; + + if (scrolling_text_Display_Order == 1) { + get_Date(); + display.setTextSize(1); + scrolling_Y_Pos = 8; //--> Y position settings for scrolling text. + scrolling_Speed = 45; //--> Speed ​​settings for scrolling text. + + int next_cnt_Color = cnt_Color + 1; + if (next_cnt_Color > (myCOLOR_ARRAY_Length - 1)) next_cnt_Color = cnt_Color - (myCOLOR_ARRAY_Length - 1); + day_and_date_Text_Color = myCOLOR_ARRAY[next_cnt_Color]; + + scrolling_Text_Color = day_and_date_Text_Color; //--> Color settings for scrolling text. You can also use: scrolling_Text_Color = display.color565(255, 0, 0); + strcpy(scrolling_Text, day_and_date_Text); //--> Sets the displayed text on scrolling text. + } + + if (scrolling_text_Display_Order == 2) { + display.setTextSize(1); + scrolling_Y_Pos = 8; //--> Y position settings for scrolling text. + scrolling_Speed = 45; //--> Speed ​​settings for scrolling text. + + int next_cnt_Color = cnt_Color + 2; + if (next_cnt_Color > (myCOLOR_ARRAY_Length - 1)) next_cnt_Color = cnt_Color - (myCOLOR_ARRAY_Length - 2); + text_Color = myCOLOR_ARRAY[next_cnt_Color]; + + scrolling_Text_Color = text_Color; //--> Color settings for scrolling text. You can also use: scrolling_Text_Color = display.color565(255, 0, 0); + strcpy(scrolling_Text, "P10 RGB 32x16 Digital Clock. Display Mode : 2."); //--> Sets the displayed text on scrolling text. + } + + // Conditions for changing color. + if (scrolling_text_Display_Order == 3) { + cnt_Color++; + if (cnt_Color > (myCOLOR_ARRAY_Length - 1)) cnt_Color = 0; + + strcpy(scrolling_Text, ""); + } + + start_Scroll_Text = true; + } + //:::::::::::::::::: + } + //---------------------------------------- + + + + + if (start_Scroll_Text == true) { + run_Scrolling_Text(scrolling_Y_Pos, scrolling_Speed, scrolling_Text, scrolling_Text_Color); + } +} +//________________________________________________________________________________ +//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + + + + +//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 04_Erase_and_Reformat_The_NVS_Memory +#include + +void setup() { + // put your setup code here, to run once: + Serial.begin(115200); + Serial.println(); + delay(1000); + + Serial.println("erase the NVS partition."); + nvs_flash_erase(); // erase the NVS partition and... + Serial.println("initialize the NVS partition."); + nvs_flash_init(); // initialize the NVS partition. + Serial.println("Finished."); +} + +void loop() { + // put your main code here, to run repeatedly: + delay(10); +} +//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + + + + +//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 05_P10_RGB_32x16_Digital_Clock_Web_Server_SM +// This is how many color levels the display shows - the more the slower the update. +//#define PxMATRIX_COLOR_DEPTH 4 + +// Defines the speed of the SPI bus (reducing this may help if you experience noisy images). +#define PxMATRIX_SPI_FREQUENCY 10000000 + +// Creates a second buffer for backround drawing (doubles the required RAM). +//#define PxMATRIX_double_buffer true + +//----------------------------------------Including Libraries. +#include +#include "RTClib.h" +#include +#include +#include +#include "PageIndex.h" +//---------------------------------------- + +//----------------------------------------Pins for LED MATRIX. +#define P_LAT 5 +#define P_A 19 +#define P_B 23 +#define P_C 18 +#define P_OE 4 +//---------------------------------------- + +// Defines the width and height of the panel in pixels. +#define matrix_width 32 +#define matrix_height 16 + +// Timer setup. +// Create a hardware timer of ESP32. +hw_timer_t * timer = NULL; +portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; + +// This defines the 'on' time of the display is us. +// The larger this number, the brighter the display. If too large the ESP will crash. +uint8_t display_draw_time = 30; // 30-70 is usually fine. + +// Declaring the "PxMATRIX" object as a "display" and its settings. +PxMATRIX display(matrix_width, matrix_height, P_LAT, P_OE, P_A, P_B, P_C); + +//----------------------------------------Variable for some colors. +uint16_t myRED = display.color565(255, 0, 0); +uint16_t myGREEN = display.color565(0, 255, 0); +uint16_t myBLUE = display.color565(0, 0, 255); +uint16_t myYELLOW = display.color565(255, 255, 0); +uint16_t myCYAN = display.color565(0, 255, 255); +uint16_t myFUCHSIA = display.color565(255, 0, 255); +uint16_t myWHITE = display.color565(255, 255, 255); +uint16_t myBLACK = display.color565(0, 0, 0); + +uint16_t myCOLOR_ARRAY[7] = {myRED, myGREEN, myBLUE, myYELLOW, myCYAN, myFUCHSIA, myWHITE}; +int cnt_Color = 0; +int myCOLOR_ARRAY_Length = sizeof(myCOLOR_ARRAY) / sizeof(myCOLOR_ARRAY[0]); +//---------------------------------------- + +// Timer/millis variables for scrolling text. +unsigned long prevMill_Scroll_Text = 0; + +// Variables used to scroll text. +int scrolling_Y_Pos = 0; +long scrolling_X_Pos; +long scrolling_X_Pos_CT; +uint16_t scrolling_Text_Color; +uint16_t text_Color; +char text_Scrolling_Text[151]; +uint16_t text_Length_In_Pixel; +bool set_up_Scrolling_Text_Length = true; +bool start_Scroll_Text = false; +byte scrolling_text_Display_Order = 0; +bool reset_Scrolling_Text = false; + +// Timer/millis variable to update time data. +unsigned long prevMill_Update_Time = 0; +const long interval_Update_Time = 1000; + +// Timer/millis variable to display time (hours and minutes). +unsigned long prevMill_Show_Clock = 0; +const long interval_Show_Clock = 500; + +// Variables to hold date and time data. +char daysOfTheWeek[7][10] = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"}; +char chr_t_Minute[3]; +byte minute_Val, last_minute_Val; +char chr_t_Hour[3]; +char day_and_date_Text[25]; +bool blink_Colon = false; +uint16_t clock_Color; +uint16_t day_and_date_Text_Color; + +int d_Year; +byte d_Month, d_Day; +byte t_Hour, t_Minute, t_Second; +byte input_Display_Mode, input_Brightness, input_Scrolling_Speed; +int Color_Clock_R, Color_Clock_G, Color_Clock_B; +int Color_Date_R, Color_Date_G, Color_Date_B; +int Color_Text_R, Color_Text_G, Color_Text_B; +char input_Scrolling_Text[151]; + +//----------------------------------------Variable declaration for your network credentials. +const char* ssid = "YOUR_WIFI_SSID"; //--> Your wifi name. +const char* password = "YOUR_WIFI_PASSWORD"; //--> Your wifi password. +//---------------------------------------- + +//----------------------------------------Defining the key. +// The "key" works like a password. To control the "P10 RGB 32x16", users must know the “key”. +// You can change it to another word. +#define key_Txt "p10rgbesp32ws" +//---------------------------------------- + +// Declare the “RTC_DS3231” object as “rtc”. +RTC_DS3231 rtc; + +// Declaring the "Preferences" object as "preferences". +Preferences preferences; + +// Server on port 80. +WebServer server(80); + + + + + + +//________________________________________________________________________________ IRAM_ATTR display_updater() +// Interrupt handler for Timer. +void IRAM_ATTR display_updater(){ + // Increment the counter and set the time of ISR. + portENTER_CRITICAL_ISR(&timerMux); + display.display(display_draw_time); + portEXIT_CRITICAL_ISR(&timerMux); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ display_update_enable() +// Subroutine to enable and disable interrupt timers. +void display_update_enable(bool is_enable) { + if (is_enable){ + timer = timerBegin(0, 80, true); + timerAttachInterrupt(timer, &display_updater, true); + timerAlarmWrite(timer, 1500, true); + timerAlarmEnable(timer); + } + else{ + timerDetachInterrupt(timer); + timerAlarmDisable(timer); + } +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ connecting_To_WiFi() +void connecting_To_WiFi() { + //----------------------------------------Set Wifi to STA mode. + Serial.println(); + Serial.println("-------------WIFI mode"); + Serial.println("WIFI mode : STA"); + WiFi.mode(WIFI_STA); + Serial.println("-------------"); + delay(1000); + //---------------------------------------- + + //----------------------------------------Connect to Wi-Fi (STA). + Serial.println(); + Serial.println("-------------Connection"); + Serial.print("Connecting to "); + Serial.println(ssid); + WiFi.begin(ssid, password); + + //:::::::::::::::::: The process of connecting ESP32 with WiFi Hotspot / WiFi Router. + // The process timeout of connecting ESP32 with WiFi Hotspot / WiFi Router is 20 seconds. + // If within 20 seconds the ESP32 has not been successfully connected to WiFi, the ESP32 will restart. + // I made this condition because on my ESP32, there are times when it seems like it can't connect to WiFi, so it needs to be restarted to be able to connect to WiFi. + + int connecting_process_timed_out = 20; //--> 20 = 20 seconds. + connecting_process_timed_out = connecting_process_timed_out * 2; + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); + if(connecting_process_timed_out > 0) connecting_process_timed_out--; + if(connecting_process_timed_out == 0) { + Serial.println(); + Serial.println("Failed to connect to WiFi. The ESP32 will be restarted."); + Serial.println("-------------"); + delay(1000); + ESP.restart(); + } + } + + Serial.println(); + Serial.println("WiFi connected"); + Serial.print("Successfully connected to : "); + Serial.println(ssid); + Serial.println("-------------"); + //:::::::::::::::::: + delay(1000); + //---------------------------------------- +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ prepare_and_start_The_Server() +void prepare_and_start_The_Server() { + //----------------------------------------Setting the server. + server.on("/", handleRoot); + server.on("/settings", handleSettings); + delay(500); + //---------------------------------------- + + //----------------------------------------Start server. + server.begin(); + Serial.println(); + Serial.println("HTTP server started"); + delay(500); + //---------------------------------------- + + //----------------------------------------Open the IP address in your browser to open the interface page. + // Make sure that your computer / mobile device and ESP32 are connected to the same WiFi network. + Serial.println(); + Serial.print("IP address : "); + Serial.println(WiFi.localIP()); + Serial.println("Open the IP address in your browser to open the interface page."); + Serial.println("Make sure that your computer / mobile device and"); + Serial.println("ESP32 are connected to the same WiFi network."); + delay(500); + //---------------------------------------- +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ handleRoot() +// This routine is executed when you open ESP32 IP Address in browser. +void handleRoot() { + server.send(200, "text/html", MAIN_page); //--> Send web page. +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ handleSettings(). +// Subroutines for handling handle settings from clients. +void handleSettings() { + String incoming_Settings; + + incoming_Settings = server.arg("key"); + + Serial.println(); + Serial.println("-------------Settings"); + Serial.print("Key : "); + Serial.println(incoming_Settings); + + // Conditions for checking keys. + if (incoming_Settings == key_Txt) { + incoming_Settings = server.arg("sta"); + + // Conditions for setting the Clock and Date. + if (incoming_Settings == "setTimeDate") { + incoming_Settings = server.arg("d_Year"); + d_Year = incoming_Settings.toInt(); + incoming_Settings = server.arg("d_Month"); + d_Month = incoming_Settings.toInt(); + incoming_Settings = server.arg("d_Day"); + d_Day = incoming_Settings.toInt(); + incoming_Settings = server.arg("t_Hour"); + t_Hour = incoming_Settings.toInt(); + incoming_Settings = server.arg("t_Minute"); + t_Minute = incoming_Settings.toInt(); + incoming_Settings = server.arg("t_Second"); + t_Second = incoming_Settings.toInt(); + + char TD[40]; + sprintf(TD, "Date : %d-%d-%d | Time : %d-%d-%d", d_Day, d_Month, d_Year, t_Hour, t_Minute, t_Second); + + Serial.println(); + Serial.println("Set Time and Date."); + Serial.print("DateTime : "); + Serial.println(TD); + + Serial.println("Set Time and Date..."); + rtc.adjust(DateTime(d_Year, d_Month, d_Day, t_Hour, t_Minute, t_Second)); + delay(100); + Serial.println("Setting the Time and Date has been completed."); + } + + // Conditions for setting Display Mode. + if (incoming_Settings == "setDisplayMode") { + incoming_Settings = server.arg("input_Display_Mode"); + input_Display_Mode = incoming_Settings.toInt(); + + Serial.println(); + Serial.println("Set Display Mode."); + Serial.print("Display Mode : "); + Serial.println(input_Display_Mode); + + Serial.println("Set and save Display Mode...."); + + // Disable Timer Interrupts. + display_update_enable(false); + delay(1000); + + //:::::::::::::::::: + // Open Preferences. + preferences.begin("mySettings", false); + delay(500); + + // Save "input_Display_Mode" to flash memory with key name "input_DM". + preferences.putInt("input_DM", input_Display_Mode); + delay(100); + + // Gets the value of "input_Display_Mode" stored in flash memory. + // If the key name "input_DM" is not found, then "input_Display_Mode" is 1 or "input_Display_Mode = 1". + input_Display_Mode = preferences.getInt("input_DM", 1); + delay(100); + + // Close the Preferences. + preferences.end(); + delay(500); + //:::::::::::::::::: + + // Enable Timer Interrupts. + display_update_enable(true); + delay(1000); + + if (input_Display_Mode == 1) { + clock_Color = display.color565(Color_Clock_R, Color_Clock_G, Color_Clock_B); + day_and_date_Text_Color = display.color565(Color_Date_R, Color_Date_G, Color_Date_B); + text_Color = display.color565(Color_Text_R, Color_Text_G, Color_Text_B); + } + + display.clearDisplay(); + + reset_Scrolling_Text = true; + + // After the scrolling text display is reset, + // set "scrolling_text_Display_Order = 0" so that the scrolling text display starts from scrolling the name of the day and date. + scrolling_text_Display_Order = 0; + + Serial.println("Set and save Display Mode is complete."); + } + + // Conditions for setting Brightness. + if (incoming_Settings == "setBrightness") { + incoming_Settings = server.arg("input_Brightness"); + input_Brightness = incoming_Settings.toInt(); + + if (input_Brightness > 255) input_Brightness = 255; + if (input_Brightness < 0) input_Brightness = 0; + + Serial.println(); + Serial.println("Set Brightness."); + Serial.print("Brightness : "); + Serial.println(input_Brightness); + + Serial.println("Set and save Brightness...."); + + // Disable Timer Interrupts. + display_update_enable(false); + delay(1000); + + //:::::::::::::::::: + // Open Preferences. + preferences.begin("mySettings", false); + delay(500); + + // Save "input_Brightness" to flash memory with key name "input_BRT". + preferences.putInt("input_BRT", input_Brightness); + delay(100); + + // Gets the value of "input_Brightness" stored in flash memory. + // If the key name "input_BRT" is not found, then "input_Brightness" is 125 or "input_Brightness = 125". + input_Brightness = preferences.getInt("input_BRT", 125); + delay(100); + + // Close the Preferences. + preferences.end(); + delay(500); + //:::::::::::::::::: + + // Enable Timer Interrupts. + display_update_enable(true); + delay(1000); + + display.setBrightness(input_Brightness); + + Serial.println("Set and save Brightness is complete."); + } + + // Conditions for setting Clock Color. + if (incoming_Settings == "setColorClock") { + // Conditions for checking display mode. + // Setting the clock color can only be done in display mode = 1. + if (input_Display_Mode == 2) { + server.send(200, "text/plane", "+ERR_DM"); //--> Sending replies to the client. + delay(500); + Serial.println("-------------"); + return; + } + + incoming_Settings = server.arg("Color_Clock_R"); + Color_Clock_R = incoming_Settings.toInt(); + incoming_Settings = server.arg("Color_Clock_G"); + Color_Clock_G = incoming_Settings.toInt(); + incoming_Settings = server.arg("Color_Clock_B"); + Color_Clock_B = incoming_Settings.toInt(); + + Serial.println(); + Serial.println("Set Clock Color."); + Serial.print("Clock Color (RGB) : "); + Serial.print(Color_Clock_R);Serial.print(",");Serial.print(Color_Clock_G);Serial.print(",");Serial.println(Color_Clock_B); + + Serial.println("Set and save Clock Color...."); + + // Disable Timer Interrupts. + display_update_enable(false); + delay(1000); + + //:::::::::::::::::: + // Open Preferences. + preferences.begin("mySettings", false); + delay(500); + + // Saves "Color_Clock_R", "Color_Clock_G" and "Color_Clock_B" to flash memory with key names "CC_R", "CC_G" and "CC_B". + preferences.putInt("CC_R", Color_Clock_R); + delay(100); + preferences.putInt("CC_G", Color_Clock_G); + delay(100); + preferences.putInt("CC_B", Color_Clock_B); + delay(100); + + // Gets the values ​​of "Color_Clock_R", "Color_Clock_G" and "Color_Clock_B" stored in flash memory. + // If the key names "Color_Clock_R", "Color_Clock_G" and "Color_Clock_B" are not found, + // then "Color_Clock_R", "Color_Clock_G" and "Color_Clock_B" have a value of 255. + Color_Clock_R = preferences.getInt("CC_R", 255); + delay(100); + Color_Clock_G = preferences.getInt("CC_G", 255); + delay(100); + Color_Clock_B = preferences.getInt("CC_B", 255); + delay(100); + + // Close the Preferences. + preferences.end(); + delay(500); + //:::::::::::::::::: + + // Enable Timer Interrupts. + display_update_enable(true); + delay(1000); + + clock_Color = display.color565(Color_Clock_R, Color_Clock_G, Color_Clock_B); + + Serial.println("Set and save Clock Color is complete."); + } + + // Conditions for setting Date Color. + if (incoming_Settings == "setColorDate") { + // Conditions for checking display mode. + // Setting the date color can only be done in display mode = 1. + if (input_Display_Mode == 2) { + server.send(200, "text/plane", "+ERR_DM"); //--> Sending replies to the client. + delay(500); + Serial.println("-------------"); + return; + } + incoming_Settings = server.arg("Color_Date_R"); + Color_Date_R = incoming_Settings.toInt(); + incoming_Settings = server.arg("Color_Date_G"); + Color_Date_G = incoming_Settings.toInt(); + incoming_Settings = server.arg("Color_Date_B"); + Color_Date_B = incoming_Settings.toInt(); + + Serial.println(); + Serial.println("Set Date Color."); + Serial.print("Date Color (RGB) : "); + Serial.print(Color_Date_R);Serial.print(",");Serial.print(Color_Date_G);Serial.print(",");Serial.println(Color_Date_B); + + Serial.println("Set and save Date Color...."); + + // Disable Timer Interrupts. + display_update_enable(false); + delay(1000); + + //:::::::::::::::::: + // Open Preferences. + preferences.begin("mySettings", false); + delay(500); + + preferences.putInt("DC_R", Color_Date_R); + delay(100); + preferences.putInt("DC_G", Color_Date_G); + delay(100); + preferences.putInt("DC_B", Color_Date_B); + delay(100); + + Color_Date_R = preferences.getInt("DC_R", 255); + delay(100); + Color_Date_G = preferences.getInt("DC_G", 255); + delay(100); + Color_Date_B = preferences.getInt("DC_B", 255); + delay(100); + + // Close the Preferences. + preferences.end(); + delay(500); + //:::::::::::::::::: + + // Enable Timer Interrupts. + display_update_enable(true); + delay(1000); + + display.clearDisplay(); + + reset_Scrolling_Text = true; + + // After the scrolling text display is reset, + // set "scrolling_text_Display_Order = 0" so that the scrolling text display starts from scrolling the name of the day and date. + scrolling_text_Display_Order = 0; + + day_and_date_Text_Color = display.color565(Color_Date_R, Color_Date_G, Color_Date_B); + + Serial.println("Set and save Date Color is complete."); + } + + // Conditions for setting text on Scrolling Text. + if (incoming_Settings == "setScrollingText") { + incoming_Settings = server.arg("input_Scrolling_Text"); + String my_Scrolling_Text = incoming_Settings; + int my_Scrolling_Text_Length = my_Scrolling_Text.length() + 1; + my_Scrolling_Text.toCharArray(input_Scrolling_Text, my_Scrolling_Text_Length); + + Serial.println(); + Serial.println("Set Scrolling Text."); + Serial.print("Text : "); + Serial.println(input_Scrolling_Text); + + Serial.println("Set and save Scrolling Text...."); + + // Disable Timer Interrupts. + display_update_enable(false); + delay(1000); + + //:::::::::::::::::: + // Open Preferences. + preferences.begin("mySettings", false); + delay(500); + + preferences.putString("input_ST", input_Scrolling_Text); + delay(100); + + my_Scrolling_Text = preferences.getString("input_ST", ""); + my_Scrolling_Text_Length = my_Scrolling_Text.length() + 1; + my_Scrolling_Text.toCharArray(input_Scrolling_Text, my_Scrolling_Text_Length); + delay(100); + + // Close the Preferences. + preferences.end(); + delay(500); + //:::::::::::::::::: + + // Enable Timer Interrupts. + display_update_enable(true); + delay(1000); + + display.clearDisplay(); + + reset_Scrolling_Text = true; + + // Once the scrolling text display is reset, + // set "scrolling_text_Display_Order = 1" so that the scrolling text display starts from scrolling "input_Scrolling_Text". + scrolling_text_Display_Order = 1; + + Serial.println("Set and save Scrolling Text is complete."); + } + + // Conditions for setting Text Color. + if (incoming_Settings == "setTextColor") { + // Conditions for checking display mode. + // Setting the text color can only be done in display mode = 1. + if (input_Display_Mode == 2) { + server.send(200, "text/plane", "+ERR_DM"); //--> Sending replies to the client. + delay(500); + Serial.println("-------------"); + return; + } + + incoming_Settings = server.arg("Color_Text_R"); + Color_Text_R = incoming_Settings.toInt(); + incoming_Settings = server.arg("Color_Text_G"); + Color_Text_G = incoming_Settings.toInt(); + incoming_Settings = server.arg("Color_Text_B"); + Color_Text_B = incoming_Settings.toInt(); + + Serial.println(); + Serial.println("Set Text Color."); + Serial.print("Text Color (RGB) : "); + Serial.print(Color_Text_R);Serial.print(",");Serial.print(Color_Text_G);Serial.print(",");Serial.println(Color_Text_B); + + Serial.println("Set and save Text Color...."); + + // Disable Timer Interrupts. + display_update_enable(false); + delay(1000); + + //:::::::::::::::::: + // Open Preferences. + preferences.begin("mySettings", false); + delay(500); + + preferences.putInt("TC_R", Color_Text_R); + delay(100); + preferences.putInt("TC_G", Color_Text_G); + delay(100); + preferences.putInt("TC_B", Color_Text_B); + delay(100); + + Color_Text_R = preferences.getInt("TC_R", 255); + delay(100); + Color_Text_G = preferences.getInt("TC_G", 255); + delay(100); + Color_Text_B = preferences.getInt("TC_B", 255); + delay(100); + + // Close the Preferences. + preferences.end(); + delay(500); + //:::::::::::::::::: + + // Enable Timer Interrupts. + display_update_enable(true); + delay(1000); + + display.clearDisplay(); + + reset_Scrolling_Text = true; + + // Once the scrolling text display is reset, + // set "scrolling_text_Display_Order = 1" so that the scrolling text display starts from scrolling "input_Scrolling_Text". + scrolling_text_Display_Order = 1; + + text_Color = display.color565(Color_Text_R, Color_Text_G, Color_Text_B); + + Serial.println("Set and save Text Color is complete."); + } + + // Conditions for setting Scrolling Speed. + if (incoming_Settings == "setScrollingSpeed") { + incoming_Settings = server.arg("input_Scrolling_Speed"); + input_Scrolling_Speed = incoming_Settings.toInt(); + + Serial.println(); + Serial.println("Set Scrolling Speed."); + Serial.print("Scrolling Speed : "); + Serial.println(input_Scrolling_Speed); + + Serial.println("Set and save Scrolling Speed...."); + + // Disable Timer Interrupts. + display_update_enable(false); + delay(1000); + + //:::::::::::::::::: + // Open Preferences. + preferences.begin("mySettings", false); + delay(500); + + preferences.putInt("input_SS", input_Scrolling_Speed); + delay(100); + + input_Scrolling_Speed = preferences.getInt("input_SS", 35); + delay(100); + + // Close the Preferences. + preferences.end(); + delay(500); + //:::::::::::::::::: + + // Enable Timer Interrupts. + display_update_enable(true); + delay(1000); + + Serial.println("Set and save Scrolling Speed is complete."); + } + + // Sends settings stored in flash memory to the client. + if (incoming_Settings == "getSettings") { + Serial.println(); + Serial.println("Get Settings."); + + // Disable Timer Interrupts. + display_update_enable(false); + delay(1000); + + get_All_Saved_Settings(); + + // Enable Timer Interrupts. + display_update_enable(true); + delay(1000); + + char send_Settings[200]; + sprintf(send_Settings, "%d|%d|%d|%d|%d|%d|%d|%d|%s|%d|%d|%d|%d", input_Display_Mode, input_Brightness, + Color_Clock_R, Color_Clock_G, Color_Clock_B, + Color_Date_R, Color_Date_G, Color_Date_B, + input_Scrolling_Text, + Color_Text_R, Color_Text_G, Color_Text_B, + input_Scrolling_Speed); + + Serial.print("Settings Data :"); + Serial.println(send_Settings); + + server.send(200, "text/plane", send_Settings); //--> Sending replies to the client. + delay(500); + } + Serial.println("-------------"); + + server.send(200, "text/plane", "+OK"); //--> Sending replies to the client. + delay(500); + } else { + Serial.println(); + Serial.println("Wrong Key Text !"); + Serial.println("Please enter the correct Key Text."); + Serial.println("-------------"); + + server.send(200, "text/plane", "+ERR"); //--> Sending replies to the client. + delay(500); + } +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ get_All_Saved_Settings() +void get_All_Saved_Settings() { + // Open Preferences. + preferences.begin("mySettings", false); + delay(500); + + input_Display_Mode = preferences.getInt("input_DM", 1); + input_Brightness = preferences.getInt("input_BRT", 125); + Color_Clock_R = preferences.getInt("CC_R", 255); + Color_Clock_G = preferences.getInt("CC_G", 255); + Color_Clock_B = preferences.getInt("CC_B", 255); + clock_Color = display.color565(Color_Clock_R, Color_Clock_G, Color_Clock_B); + Color_Date_R = preferences.getInt("DC_R", 255); + Color_Date_G = preferences.getInt("DC_G", 255); + Color_Date_B = preferences.getInt("DC_B", 255); + day_and_date_Text_Color = display.color565(Color_Date_R, Color_Date_G, Color_Date_B); + String my_Scrolling_Text = preferences.getString("input_ST", ""); + int my_Scrolling_Text_Length = my_Scrolling_Text.length() + 1; + my_Scrolling_Text.toCharArray(input_Scrolling_Text, my_Scrolling_Text_Length); + Color_Text_R = preferences.getInt("TC_R", 255); + Color_Text_G = preferences.getInt("TC_G", 255); + Color_Text_B = preferences.getInt("TC_B", 255); + text_Color = display.color565(Color_Text_R, Color_Text_G, Color_Text_B); + input_Scrolling_Speed = preferences.getInt("input_SS", 35); + + // Close the Preferences. + preferences.end(); + delay(500); + + Serial.println("-------------"); + Serial.println("All Saved Settings."); + Serial.print("Display Mode : "); + Serial.println(input_Display_Mode); + Serial.print("Brightness : "); + Serial.println(input_Brightness); + Serial.print("Clock Color (RGB) : "); + Serial.print(Color_Clock_R);Serial.print(",");Serial.print(Color_Clock_G);Serial.print(",");Serial.println(Color_Clock_B); + Serial.print("Date Color (RGB) : "); + Serial.print(Color_Date_R);Serial.print(",");Serial.print(Color_Date_G);Serial.print(",");Serial.println(Color_Date_B); + Serial.print("Scrolling Text : "); + Serial.println(input_Scrolling_Text); + Serial.print("Text Color (RGB) : "); + Serial.print(Color_Text_R);Serial.print(",");Serial.print(Color_Text_G);Serial.print(",");Serial.println(Color_Text_B); + Serial.print("Scrolling Speed : "); + Serial.println(input_Scrolling_Speed); + Serial.println("-------------"); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ run_Scrolling_Text() +// Subroutine for scrolling text. +void run_Scrolling_Text(uint8_t st_Y_Pos, byte st_Speed, char * st_Text, uint16_t st_Color) { + if (start_Scroll_Text == true && set_up_Scrolling_Text_Length == true) { + if (strlen(st_Text) > 0) { + text_Length_In_Pixel = getTextWidth(st_Text); + scrolling_X_Pos = matrix_width; + + set_up_Scrolling_Text_Length = false; + } else { + start_Scroll_Text = false; + return; + } + } + + if (reset_Scrolling_Text == true) { + set_up_Scrolling_Text_Length = true; + start_Scroll_Text = false; + reset_Scrolling_Text = false; + + return; + } + + unsigned long currentMillis_Scroll_Text = millis(); + if (currentMillis_Scroll_Text - prevMill_Scroll_Text >= st_Speed) { + prevMill_Scroll_Text = currentMillis_Scroll_Text; + + scrolling_X_Pos--; + if (scrolling_X_Pos < -(matrix_width + text_Length_In_Pixel)) { + set_up_Scrolling_Text_Length = true; + start_Scroll_Text = false; + + return; + } + + scrolling_X_Pos_CT = scrolling_X_Pos + 1; + + display.setTextColor(myBLACK); + display.setCursor(scrolling_X_Pos_CT, st_Y_Pos); + display.print(st_Text); + + display.setTextColor(st_Color); + display.setCursor(scrolling_X_Pos, st_Y_Pos); + display.print(st_Text); + } +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ getTextWidth() +// Subroutine to get the length of text in pixels. +uint16_t getTextWidth(const char* text) { + int16_t x1, y1; + uint16_t w, h; + display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h); + return w; +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ drawColon() +void drawColon(int16_t x, int16_t y, uint16_t colonColor) { + display.drawPixel(x, y, colonColor); + display.drawPixel(x+1, y, colonColor); + display.drawPixel(x, y+1, colonColor); + display.drawPixel(x+1, y+1, colonColor); + + display.drawPixel(x, y+3, colonColor); + display.drawPixel(x+1, y+3, colonColor); + display.drawPixel(x, y+4, colonColor); + display.drawPixel(x+1, y+4, colonColor); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ get_Time() +void get_Time() { + DateTime now = rtc.now(); + + minute_Val = now.minute(); + + sprintf(chr_t_Hour, "%02d", now.hour()); + sprintf(chr_t_Minute, "%02d", now.minute()); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ get_Date() +void get_Date() { + DateTime now = rtc.now(); + + sprintf(day_and_date_Text, "%s, %02d-%02d-%d", daysOfTheWeek[now.dayOfTheWeek()], now.day(), now.month(), now.year()); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ VOID SETUP() +void setup() { + // put your setup code here, to run once: + + delay(1000); + Serial.begin(115200); + Serial.println(); + + get_All_Saved_Settings(); + + //----------------------------------------Starting and setting up the DS3231 RTC module. + Serial.println(); + Serial.println("------------"); + Serial.println("Starting the DS3231 RTC module."); + if (!rtc.begin()) { + Serial.println("Couldn't find RTC"); + while (1); + } + Serial.println("Successfully started the DS3231 RTC module."); + Serial.println("------------"); + //---------------------------------------- + + // Display initialization. + display.begin(8); //--> Value 8 for 1/8 row scan panel. + delay(100); + + // Enable Timer Interrupts. + display_update_enable(true); + delay(100); + + display.clearDisplay(); + delay(1000); + + display.setBrightness(input_Brightness); //--> Range from 0 to 255. + delay(100); + + display.fillScreen(myRED); + delay(1000); + display.fillScreen(myGREEN); + delay(1000); + display.fillScreen(myBLUE); + delay(1000); + display.fillScreen(myWHITE); + delay(1000); + + display.clearDisplay(); + delay(1000); + + display.setTextWrap(false); + display.setTextSize(1); + display.setRotation(0); + delay(100); + + start_Scroll_Text = true; + while(true) {run_Scrolling_Text(4, 35, "Connecting to WiFi.", myBLUE);if (start_Scroll_Text == false) break;} + delay(500); + + start_Scroll_Text = true; + while(true) {run_Scrolling_Text(4, 35, "Please Wait...", myRED);if (start_Scroll_Text == false) break;} + delay(500); + + // Disable Timer Interrupts. + display_update_enable(false); + delay(1000); + + connecting_To_WiFi(); + delay(1000); + + prepare_and_start_The_Server(); + delay(1000); + + // Enable Timer Interrupts. + display_update_enable(true); + delay(1000); + + start_Scroll_Text = true; + while(true) {run_Scrolling_Text(4, 35, "Successfully connected to WiFi.", myGREEN);if (start_Scroll_Text == false) break;} + delay(500); + + char IP_Add[30]; + sprintf(IP_Add, "IP Address : %s", WiFi.localIP().toString()); + start_Scroll_Text = true; + while(true) {run_Scrolling_Text(4, 35, IP_Add, myWHITE);if (start_Scroll_Text == false) break;} + delay(500); +} +//________________________________________________________________________________ + + + + + + +//________________________________________________________________________________ VOID LOOP() +void loop() { + // put your main code here, to run repeatedly: + + // Handle client requests. + server.handleClient(); + + + + + //----------------------------------------input_Display_Mode = 1. + if (input_Display_Mode == 1) { + //::::::::::::::::::Timer/Millis to update clock data. + unsigned long currentMillis_Update_Time = millis(); + if (currentMillis_Update_Time - prevMill_Update_Time >= interval_Update_Time) { + prevMill_Update_Time = currentMillis_Update_Time; + + get_Time(); + blink_Colon = !blink_Colon; + } + //:::::::::::::::::: + + //::::::::::::::::::Timer/Millis to display hours and minutes. + unsigned long currentMillis_Show_Clock = millis(); + if (currentMillis_Show_Clock - prevMill_Show_Clock >= interval_Show_Clock) { + prevMill_Show_Clock = currentMillis_Show_Clock; + + display.setTextSize(1); + + //clock_Color = myRED; + + if (last_minute_Val != minute_Val) display.fillRect(1, 0, 11, 7, myBLACK); + display.setTextColor(clock_Color); + display.setCursor(1, 0); + display.print(chr_t_Hour); + + if (blink_Colon == true) { + drawColon(15, 1, clock_Color); + } else { + drawColon(15, 1, myBLACK); + } + + if (last_minute_Val != minute_Val) display.fillRect(20, 0, 11, 7, myBLACK); + display.setTextColor(clock_Color); + display.setCursor(20, 0); + display.print(chr_t_Minute); + + last_minute_Val = minute_Val; + } + //:::::::::::::::::: + + //::::::::::::::::::Conditions for setting and preparing scrolling text. + // "start_Scroll_Text = false" means scrolling has not been executed. + // After the settings and preparations for scrolling text below are complete, "start_Scroll_Text = true" to start scrolling text. + // "start_Scroll_Text" will return "false" if scrolling the text is complete or the scrolled text is empty. + if (start_Scroll_Text == false) { + scrolling_text_Display_Order++; + if (scrolling_text_Display_Order > 2) scrolling_text_Display_Order = 1; + + // Conditions for scrolling text containing the name of the day and date. + if (scrolling_text_Display_Order == 1) { + get_Date(); + display.setTextSize(1); + scrolling_Y_Pos = 8; //--> Y position settings for scrolling text. + //input_Scrolling_Speed = 45; //--> Speed ​​settings for scrolling text. + //day_and_date_Text_Color = myGREEN; + scrolling_Text_Color = day_and_date_Text_Color; //--> Color settings for scrolling text. You can also use: scrolling_Text_Color = display.color565(255, 0, 0); + strcpy(text_Scrolling_Text, day_and_date_Text); //--> Sets the displayed text on scrolling text. + } + + // Conditions for scrolling the text you want. + if (scrolling_text_Display_Order == 2) { + display.setTextSize(1); + scrolling_Y_Pos = 8; //--> Y position settings for scrolling text. + //input_Scrolling_Speed = 45; //--> Speed ​​settings for scrolling text. + //text_Color = myBLUE; + scrolling_Text_Color = text_Color; //--> Color settings for scrolling text. You can also use: scrolling_Text_Color = display.color565(255, 0, 0); + strcpy(text_Scrolling_Text, input_Scrolling_Text); //--> Sets the displayed text on scrolling text. + } + + start_Scroll_Text = true; + } + //:::::::::::::::::: + } + //---------------------------------------- + + + + + //----------------------------------------input_Display_Mode = 2. + if (input_Display_Mode == 2) { + //:::::::::::::::::: + unsigned long currentMillis_Update_Time = millis(); + if (currentMillis_Update_Time - prevMill_Update_Time >= interval_Update_Time) { + prevMill_Update_Time = currentMillis_Update_Time; + + get_Time(); + blink_Colon = !blink_Colon; + } + //:::::::::::::::::: + + //:::::::::::::::::: + unsigned long currentMillis_Show_Clock = millis(); + if (currentMillis_Show_Clock - prevMill_Show_Clock >= interval_Show_Clock) { + prevMill_Show_Clock = currentMillis_Show_Clock; + + display.setTextSize(1); + + clock_Color = myCOLOR_ARRAY[cnt_Color]; + + if (last_minute_Val != minute_Val) display.fillRect(1, 0, 11, 7, myBLACK); + display.setTextColor(clock_Color); + display.setCursor(1, 0); + display.print(chr_t_Hour); + + if (blink_Colon == true) { + drawColon(15, 1, clock_Color); + } else { + drawColon(15, 1, myBLACK); + } + + if (last_minute_Val != minute_Val) display.fillRect(20, 0, 11, 7, myBLACK); + display.setTextColor(clock_Color); + display.setCursor(20, 0); + display.print(chr_t_Minute); + + last_minute_Val = minute_Val; + } + //:::::::::::::::::: + + //:::::::::::::::::: + if (start_Scroll_Text == false) { + scrolling_text_Display_Order++; + if (scrolling_text_Display_Order > 3) scrolling_text_Display_Order = 1; + + if (scrolling_text_Display_Order == 1) { + get_Date(); + display.setTextSize(1); + scrolling_Y_Pos = 8; //--> Y position settings for scrolling text. + //input_Scrolling_Speed = 45; //--> Speed ​​settings for scrolling text. + + int next_cnt_Color = cnt_Color + 1; + if (next_cnt_Color > (myCOLOR_ARRAY_Length - 1)) next_cnt_Color = cnt_Color - (myCOLOR_ARRAY_Length - 1); + day_and_date_Text_Color = myCOLOR_ARRAY[next_cnt_Color]; + + scrolling_Text_Color = day_and_date_Text_Color; //--> Color settings for scrolling text. You can also use: scrolling_Text_Color = display.color565(255, 0, 0); + strcpy(text_Scrolling_Text, day_and_date_Text); //--> Sets the displayed text on scrolling text. + } + + if (scrolling_text_Display_Order == 2) { + display.setTextSize(1); + scrolling_Y_Pos = 8; //--> Y position settings for scrolling text. + //input_Scrolling_Speed = 45; //--> Speed ​​settings for scrolling text. + + int next_cnt_Color = cnt_Color + 2; + if (next_cnt_Color > (myCOLOR_ARRAY_Length - 1)) next_cnt_Color = cnt_Color - (myCOLOR_ARRAY_Length - 2); + text_Color = myCOLOR_ARRAY[next_cnt_Color]; + + scrolling_Text_Color = text_Color; //--> Color settings for scrolling text. You can also use: scrolling_Text_Color = display.color565(255, 0, 0); + strcpy(text_Scrolling_Text, input_Scrolling_Text); //--> Sets the displayed text on scrolling text. + } + + // Conditions for changing color. + if (scrolling_text_Display_Order == 3) { + cnt_Color++; + if (cnt_Color > (myCOLOR_ARRAY_Length - 1)) cnt_Color = 0; + + strcpy(text_Scrolling_Text, ""); + } + + start_Scroll_Text = true; + } + //:::::::::::::::::: + } + //---------------------------------------- + + + + + if (start_Scroll_Text == true) { + run_Scrolling_Text(scrolling_Y_Pos, input_Scrolling_Speed, text_Scrolling_Text, scrolling_Text_Color); + } +} +//________________________________________________________________________________ +//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + + + + +//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 06_P10_RGB_32x16_Digital_Clock_Web_Server_APM +//----------------------------------------Access Point Declaration and Configuration. +const char* ssid = "ESP32_WS"; //--> access point name +const char* password = "helloesp32WS"; //--> access point password + +IPAddress local_ip(192,168,1,1); +IPAddress gateway(192,168,1,1); +IPAddress subnet(255,255,255,0); +//---------------------------------------- + +//________________________________________________________________________________ set_ESP32_Access_Point() +void set_ESP32_Access_Point() { + //----------------------------------------Set Wifi to AP mode + Serial.println(); + Serial.println("-------------"); + Serial.println("WIFI mode : AP"); + WiFi.mode(WIFI_AP); + Serial.println("-------------"); + delay(1000); + //---------------------------------------- + + //----------------------------------------Setting up ESP32 to be an Access Point. + Serial.println(); + Serial.println("-------------"); + Serial.println("Setting up ESP32 to be an Access Point."); + WiFi.softAP(ssid, password); //--> Creating Access Points + delay(1000); + Serial.println("Setting up ESP32 softAPConfig."); + WiFi.softAPConfig(local_ip, gateway, subnet); + Serial.println("-------------"); + delay(1000); + //---------------------------------------- +} +//________________________________________________________________________________ + +//________________________________________________________________________________ prepare_and_start_The_Server() +void prepare_and_start_The_Server() { + //----------------------------------------Setting the server. + server.on("/", handleRoot); + server.on("/settings", handleSettings); + delay(500); + //---------------------------------------- + + //----------------------------------------Start server. + server.begin(); + Serial.println(); + Serial.println("HTTP server started"); + delay(500); + //---------------------------------------- + + //----------------------------------------Open the IP address in your browser to open the interface page. + // Make sure your computer/mobile device is connected to the ESP32 Access Point. + Serial.println(); + Serial.println(); + Serial.println("------------"); + Serial.print("SSID name : "); + Serial.println(ssid); + Serial.print("IP address : "); + Serial.println(WiFi.softAPIP()); + Serial.println(); + Serial.println("Connect your computer or mobile Wifi to the SSID above."); + Serial.println("Visit the IP Address above in your browser to open the main page."); + Serial.println("------------"); + Serial.println(); + delay(500); + //---------------------------------------- +} +//________________________________________________________________________________ + +while(true) {run_Scrolling_Text(4, 35, "Set up the ESP32 Access Point.", myBLUE);if (start_Scroll_Text == false) break;} + +while(true) {run_Scrolling_Text(4, 35, "Please Wait...", myRED);if (start_Scroll_Text == false) break;} + +set_ESP32_Access_Point(); + +while(true) {run_Scrolling_Text(4, 35, "Set Up the ESP32 Access Point Successfully.", myGREEN);if (start_Scroll_Text == false) break;} + +char IP_Add[30]; +sprintf(IP_Add, "IP Address : %s", WiFi.softAPIP().toString()); +start_Scroll_Text = true; +while(true) {run_Scrolling_Text(4, 35, IP_Add, myWHITE);if (start_Scroll_Text == false) break;} +//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< \ No newline at end of file diff --git a/Guide to using the Web Interface.png b/Guide to using the Web Interface.png new file mode 100644 index 0000000..91c80fc Binary files /dev/null and b/Guide to using the Web Interface.png differ diff --git a/Guide to using the Web Interface.txt b/Guide to using the Web Interface.txt new file mode 100644 index 0000000..8e36a79 --- /dev/null +++ b/Guide to using the Web Interface.txt @@ -0,0 +1,20 @@ +1. Please enter the "Key" that matches the "Key" in the Arduino code. +2. The "Apply Time and Date" button is to set the time and date on the DS3231 RTC module based on the time and date on your device. +3. "Display Mode" is the setting for display mode. + > Display Mode = 1 is a display mode in which the color of the clock, the color of the scrolling text to display the date + (including the name of the day) and the color of the message in + the scrolling text can be set manually. + > Display Mode = 2 is a display mode in which the color of the clock, the color of the scrolling text to display the date + (including the name of the day) and the color of the message in the scrolling text will change sequentially based on the color code + list in the Arduino code. +4. "Brightness" is the setting to adjust the brightness on the P10 RGB 32x16 panel. +5. "Clock Color" is a setting to adjust the color of the clock display (can only be set if display mode = 1). +6. "Date Color" is a setting to set the scrolling text display color to display the name of the day and date + (can only be set if display mode = 1). +7. "Scrolling Text" is a setting to set the message displayed on the scrolling text (after scrolling the text containing the name of + the day and date). +8. "Text Color" is a setting to set the text color for displaying messages in scrolling text (does not include scrolling text for names of days + and dates and can only be set if display mode = 1). +9. "Scrolling Speed" is a setting to set the speed of scrolling text (scrolling text for names of days and dates and scrolling text for + displaying messages). +10. The "Get Settings" button is to get the settings stored in the ESP32 flash memory. \ No newline at end of file diff --git a/Installation.png b/Installation.png new file mode 100644 index 0000000..824bb7b Binary files /dev/null and b/Installation.png differ diff --git a/Lib.txt b/Lib.txt new file mode 100644 index 0000000..f831146 --- /dev/null +++ b/Lib.txt @@ -0,0 +1,4 @@ +- Adafruit BusIO (V1.16.1) by Adafruit : Install via "Manage Libraries" or "Library Manager" in the Arduino IDE with the search keyword "Adafruit BusIO". +- RTClib by Adafruit (V2.1.4) : Install via "Manage Libraries" or "Library Manager" in the Arduino IDE with the search keyword "RTClib". +- Adafruit GFX Library by Adafruit (V1.11.9) : Install via "Manage Libraries" or "Library Manager" in the Arduino IDE with the search keyword "Adafruit GFX Library". +- PxMatrix Library by 2dom (Dominic Buchstaller) (V1.8.2) : https://github.com/2dom/PxMatrix/tree/master \ No newline at end of file diff --git a/PageIndex.txt b/PageIndex.txt new file mode 100644 index 0000000..3fb14c5 --- /dev/null +++ b/PageIndex.txt @@ -0,0 +1,527 @@ +const char MAIN_page[] PROGMEM = R"=====( + + + Digital Clcok & Scrolling Text with ESP32 and P10 RGB 32x16 + + + + +
+

Digital Clcok & Scrolling Text with ESP32 and P10 RGB 32x16

+
+ +
+
+ + + + + +
+ + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Display Mode: + + + +
Brightness: + (0 - 255) + + +
Clock Color: + + + +
Date Color: + + + +
+ +
+ + +
+ + + + + + + + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + +
Text Color: + + + +
Scrolling Speed: + + + +
+ +
+ + +
+
+ + + + +)====="; \ No newline at end of file diff --git a/QUICK_START.md b/QUICK_START.md new file mode 100644 index 0000000..63a4c6b --- /dev/null +++ b/QUICK_START.md @@ -0,0 +1,159 @@ +# Guide de Démarrage Rapide - ESP32 P10 Digital Clock + +## 🚀 Démarrage en 5 minutes + +### Étape 1 : Préparation +1. **Installez PlatformIO** dans VS Code +2. **Ouvrez ce dossier** dans VS Code +3. **Connectez votre ESP32** en USB + +### Étape 2 : Configuration WiFi +Modifiez dans `src/main.cpp` lignes ~100 : +```cpp +const char* ssid = "VOTRE_WIFI"; +const char* password = "VOTRE_MOT_DE_PASSE"; +``` + +### Étape 3 : Câblage (IMPORTANT !) + +#### Panneau P10 → ESP32 +``` +HUB75 → ESP32 +R1 → GPIO2 +G1 → GPIO15 +B1 → GPIO4 +R2 → GPIO16 +G2 → GPIO17 +B2 → GPIO5 +A → GPIO19 +B → GPIO23 +C → GPIO18 +CLK → GPIO14 +STB → GPIO32 +OE → GPIO33 +GND → GND (plusieurs connexions) +``` + +#### RTC DS3231 → ESP32 +``` +VCC → 3.3V +GND → GND +SDA → GPIO21 +SCL → GPIO22 +``` + +### Étape 4 : Test rapide +1. **Test du panneau P10** : + ```bash + pio run -e p10_test --target upload + ``` + +2. **Test du RTC** : + ```bash + pio run -e rtc_test --target upload + ``` + +### Étape 5 : Projet principal +```bash +pio run -e main --target upload +pio device monitor +``` + +## 🌐 Configuration Web + +1. **Trouvez l'IP** dans le moniteur série +2. **Ouvrez votre navigateur** → http://IP_AFFICHEE +3. **Utilisez la clé** : `p10rgbesp32ws` +4. **Configurez** date, heure, couleurs, texte + +## 🔧 Commandes Utiles + +```bash +# Compilation principale +pio run -e main + +# Upload et monitoring +pio run -e main -t upload && pio device monitor + +# Test des composants +pio run -e rtc_test -t upload # Test RTC +pio run -e p10_test -t upload # Test P10 +pio run -e nvs_erase -t upload # Reset mémoire + +# Nettoyage +pio run -t clean +``` + +## ⚡ Commandes VS Code +- **Ctrl+Shift+P** → "Tasks: Run Task" +- Choisissez parmi : + - PlatformIO: Build Main Project + - PlatformIO: Upload Main Project + - PlatformIO: Test RTC Module + - PlatformIO: Test P10 Matrix + - PlatformIO: Monitor Serial + +## 🚨 Problèmes Courants + +### L'affichage ne fonctionne pas +- ✅ Vérifiez l'**alimentation 5V** (crucial !) +- ✅ Vérifiez **toutes les connexions** +- ✅ Testez avec `pio run -e p10_test -t upload` + +### WiFi ne se connecte pas +- ✅ Vérifiez SSID/mot de passe +- ✅ L'ESP32 créera un point d'accès "ESP32_Clock" + +### RTC ne fonctionne pas +- ✅ Vérifiez connexions I2C (SDA/SCL) +- ✅ Testez avec `pio run -e rtc_test -t upload` + +### Paramètres perdus +- ✅ Effacez la mémoire : `pio run -e nvs_erase -t upload` + +## 📱 Interface Web - Fonctionnalités + +- **Date/Heure** : Configuration complète +- **Mode 1** : Couleurs manuelles (RGB) +- **Mode 2** : Changement automatique de couleurs +- **Luminosité** : 0-255 +- **Texte défilant** : Message personnalisé +- **Vitesse** : Réglage du défilement + +## 💡 Configuration Avancée + +### Changement des pins +Modifiez dans `src/main.cpp` : +```cpp +#define P_LAT 5 // Pin Latch +#define P_A 19 // Pin A +#define P_B 23 // Pin B +#define P_C 18 // Pin C +#define P_OE 4 // Pin Output Enable +``` + +### Réduction du bruit d'affichage +```cpp +#define PxMATRIX_SPI_FREQUENCY 8000000 // Réduire si bruit +``` + +## 📋 Checklist de Test + +- [ ] ESP32 se connecte au WiFi +- [ ] Interface web accessible +- [ ] Heure s'affiche correctement +- [ ] Date défile en bas +- [ ] Texte personnalisé fonctionne +- [ ] Changement de couleurs (mode 2) +- [ ] Réglage luminosité +- [ ] Sauvegarde des paramètres + +## 🎯 Prêt à utiliser ! + +Une fois tout testé, votre horloge affichera : +- **Heure** en haut (HH:MM avec : clignotant) +- **Date et texte** défilant en bas +- **Couleurs** selon le mode choisi +- **Configuration** via navigateur web + +Clé d'accès web : **p10rgbesp32ws** diff --git a/README.md b/README.md new file mode 100644 index 0000000..68eff20 --- /dev/null +++ b/README.md @@ -0,0 +1,245 @@ +# ESP32 P10 RGB 32x16 Digital Clock - PlatformIO Version + +## Description + +Horloge numérique utilisant un panneau P10 RGB 32x16 avec ESP32, module RTC DS3231 et interface web de configuration. + +Version adaptée pour PlatformIO à partir du code Arduino IDE original. + +## Matériel Requis + +- **ESP32 DEVKIT V1** +- **Panneau P10 RGB 32x16 HUB75** (Scan 1/8) + - Référence utilisée : P10-2727-8S-32X16-A + - ICs : RUC7258D, DP5125D, 74HC245KA +- **Module RTC DS3231** +- **Alimentation 5V** (importante pour le panneau P10) + +## Brochage + +### Connexions P10 HUB75 +``` +HUB75 Pin | ESP32 Pin +----------|---------- +R1 | GPIO 2 +G1 | GPIO 15 +B1 | GPIO 4 +GND | GND +R2 | GPIO 16 +G2 | GPIO 17 +B2 | GPIO 5 +GND | GND +A | GPIO 19 +B | GPIO 23 +C | GPIO 18 +GND | GND +CLK | GPIO 14 +STB | GPIO 32 +OE | GPIO 33 +GND | GND +``` + +**Note :** Ces connexions peuvent varier selon votre panneau P10. Consultez le code et ajustez si nécessaire. + +### Connexions RTC DS3231 +``` +DS3231 | ESP32 +-------|------- +VCC | 3.3V +GND | GND +SDA | GPIO 21 +SCL | GPIO 22 +``` + +## Installation et Configuration + +### 1. Installation PlatformIO + +Si vous n'avez pas encore PlatformIO : +```bash +# Via VS Code +# Installez l'extension PlatformIO IDE + +# Via ligne de commande +pip install platformio +``` + +### 2. Configuration du projet + +1. **Clonez ou téléchargez** ce projet +2. **Ouvrez le dossier** dans VS Code avec PlatformIO +3. **Modifiez les paramètres WiFi** dans `src/main.cpp` : + +```cpp +// Configuration WiFi - Modifiez selon vos besoins +const char* ssid = "VOTRE_WIFI_SSID"; +const char* password = "VOTRE_MOT_DE_PASSE_WIFI"; +``` + +### 3. Compilation et téléversement + +```bash +# Compilation +pio run + +# Téléversement +pio run --target upload + +# Monitoring série +pio device monitor +``` + +Ou utilisez les boutons PlatformIO dans VS Code. + +## Structure du Projet + +``` +├── platformio.ini # Configuration PlatformIO +├── src/ +│ └── main.cpp # Code principal de l'horloge +├── include/ +│ └── PageIndex.h # Interface web HTML +├── examples/ +│ ├── rtc_test.cpp # Test du module RTC +│ ├── p10_test.cpp # Test du panneau P10 +│ └── nvs_erase.cpp # Effacement mémoire NVS +└── README.md # Ce fichier +``` + +## Utilisation + +### Premier démarrage + +1. **Téléversez le code** sur l'ESP32 +2. **Ouvrez le moniteur série** (115200 baud) +3. L'ESP32 va essayer de se connecter à votre WiFi +4. Si la connexion échoue, il créera un point d'accès WiFi + +### Configuration via interface web + +1. **Connectez-vous au réseau WiFi** : + - Si connecté à votre WiFi : utilisez l'IP affichée dans le moniteur série + - Sinon connectez-vous au point d'accès "ESP32_Clock" (mot de passe : "esp32clock") + +2. **Ouvrez votre navigateur** et allez à l'adresse IP + +3. **Utilisez la clé** : `p10rgbesp32ws` + +4. **Configurez** : + - Date et heure + - Mode d'affichage (1 = couleurs manuelles, 2 = couleurs automatiques) + - Luminosité (0-255) + - Couleurs (en mode 1) + - Texte défilant + - Vitesse de défilement + +### Configuration de l'heure RTC + +Vous pouvez aussi configurer l'heure directement via le moniteur série : +``` +SET,2024,8,1,14,30,0 +``` +Format : `SET,année,mois,jour,heure,minute,seconde` + +## Programmes d'exemple + +### Test du module RTC +```bash +# Modifiez src/main.cpp pour inclure examples/rtc_test.cpp +# Ou créez un nouveau projet avec ce fichier +``` + +### Test du panneau P10 +```bash +# Modifiez src/main.cpp pour inclure examples/p10_test.cpp +# Utile pour vérifier les connexions +``` + +### Effacement mémoire NVS +```bash +# Utilisez examples/nvs_erase.cpp si vous voulez +# réinitialiser toutes les préférences sauvegardées +``` + +## Modes d'affichage + +### Mode 1 - Couleurs manuelles +- Couleurs fixes définissables via l'interface web +- Couleur de l'horloge personnalisable +- Couleur de la date personnalisable +- Couleur du texte personnalisable + +### Mode 2 - Couleurs automatiques +- Changement automatique des couleurs +- Cycle entre : Rouge, Vert, Bleu, Jaune, Cyan, Magenta, Blanc + +## Paramètres configurables + +- **Date et heure** : via interface web ou moniteur série +- **Luminosité** : 0-255 +- **Mode d'affichage** : 1 ou 2 +- **Couleurs RGB** : 0-255 pour chaque composante (mode 1) +- **Texte défilant** : jusqu'à 150 caractères +- **Vitesse de défilement** : 10-100 (plus bas = plus rapide) + +## Dépannage + +### Problèmes d'affichage +- Vérifiez l'alimentation 5V (importante !) +- Vérifiez les connexions HUB75 +- Ajustez `PxMATRIX_SPI_FREQUENCY` si vous voyez du bruit + +### Problèmes WiFi +- Vérifiez le SSID et le mot de passe +- L'ESP32 basculera en mode point d'accès si la connexion échoue + +### Problèmes RTC +- Vérifiez les connexions I2C (SDA/SCL) +- Testez avec le programme `examples/rtc_test.cpp` + +### Réinitialisation +- Utilisez `examples/nvs_erase.cpp` pour effacer toutes les préférences + +## Configuration avancée + +### Modification de la fréquence SPI +```cpp +// Dans src/main.cpp, modifiez si vous avez du bruit sur l'affichage +#define PxMATRIX_SPI_FREQUENCY 10000000 // Valeurs possibles: 20000000, 15000000, 10000000, 8000000 +``` + +### Modification des pins +```cpp +// Modifiez ces valeurs dans src/main.cpp si votre câblage est différent +#define P_LAT 5 +#define P_A 19 +#define P_B 23 +#define P_C 18 +#define P_OE 4 +``` + +## Bibliothèques utilisées + +- **PxMatrix** : Contrôle du panneau P10 RGB +- **RTClib** : Interface avec le module DS3231 +- **Preferences** : Sauvegarde des paramètres dans la flash +- **WiFi** : Connectivité réseau +- **WebServer** : Interface web de configuration + +## Support + +Pour obtenir de l'aide : +1. Vérifiez ce README +2. Consultez les programmes d'exemple +3. Vérifiez les connexions et l'alimentation +4. Consultez la documentation des bibliothèques utilisées + +## Crédit + +Projet original adapté pour PlatformIO. Code source basé sur les exemples et tutoriels de la communauté ESP32/Arduino. + +Bibliothèques utilisées : +- PxMatrix par 2dom (Dominic Buchstaller) +- RTClib par Adafruit +- Adafruit GFX Library +- Adafruit BusIO diff --git a/WIRING.md b/WIRING.md new file mode 100644 index 0000000..5fa06a2 --- /dev/null +++ b/WIRING.md @@ -0,0 +1,214 @@ +# Schémas de Connexion - ESP32 P10 Digital Clock + +## Vue d'ensemble du système + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Alimentation │ │ ESP32 │ │ Panneau P10 │ +│ 5V │ │ DEVKIT V1 │ │ RGB 32x16 │ +├─────────────────┤ ├─────────────────┤ ├─────────────────┤ +│ + ────────────────────│ VIN │ │ │ +│ - ────────────────────│ GND │ │ │ +└─────────────────┘ │ │ │ │ + │ │ │ │ +┌─────────────────┐ │ │ │ │ +│ RTC DS3231 │ │ │ │ │ +├─────────────────┤ │ │ │ │ +│ VCC ──────────────────│ 3.3V │ │ │ +│ GND ──────────────────│ GND │ │ │ +│ SDA ──────────────────│ GPIO21 │ │ │ +│ SCL ──────────────────│ GPIO22 │ │ │ +└─────────────────┘ │ │ │ │ + │ GPIO2 ─────────────────│ R1 │ + │ GPIO15 ─────────────────│ G1 │ + │ GPIO4 ─────────────────│ B1 │ + │ GPIO16 ─────────────────│ R2 │ + │ GPIO17 ─────────────────│ G2 │ + │ GPIO5 ─────────────────│ B2 │ + │ GPIO19 ─────────────────│ A │ + │ GPIO23 ─────────────────│ B │ + │ GPIO18 ─────────────────│ C │ + │ GPIO14 ─────────────────│ CLK │ + │ GPIO32 ─────────────────│ STB (LAT) │ + │ GPIO33 ─────────────────│ OE │ + │ GND ─────────────────│ GND (multiple) │ + └─────────────────┘ └─────────────────┘ +``` + +## Connecteur HUB75 - Vue détaillée + +``` + HUB75 Connector (Vue de face) + ┌─────────────────────────┐ + │ 1 2 3 4 5 6 7 8 │ + │ ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐│ + │ │R││G││B││ ││R││G││B││ ││ + │ │1││1││1││G││2││2││2││G││ + │ └─┘└─┘└─┘│N│└─┘└─┘└─┘│N││ + │ │D│ │D││ + │ └─┘ └─┘│ + ├─────────────────────────┤ + │ 9 10 11 12 13 14 15 16 │ + │ ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐│ + │ │A││B││C││G││C││S││O││G││ + │ │ ││ ││ ││N││L││T││E││N││ + │ │ ││ ││ ││D││K││B││ ││D││ + │ └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘│ + └─────────────────────────┘ + +Pin 1 (R1) → ESP32 GPIO2 Pin 9 (A) → ESP32 GPIO19 +Pin 2 (G1) → ESP32 GPIO15 Pin 10 (B) → ESP32 GPIO23 +Pin 3 (B1) → ESP32 GPIO4 Pin 11 (C) → ESP32 GPIO18 +Pin 4 (GND) → ESP32 GND Pin 12 (GND) → ESP32 GND +Pin 5 (R2) → ESP32 GPIO16 Pin 13 (CLK) → ESP32 GPIO14 +Pin 6 (G2) → ESP32 GPIO17 Pin 14 (STB) → ESP32 GPIO32 +Pin 7 (B2) → ESP32 GPIO5 Pin 15 (OE) → ESP32 GPIO33 +Pin 8 (GND) → ESP32 GND Pin 16 (GND) → ESP32 GND +``` + +## ESP32 DEVKIT V1 - Pinout + +``` + ESP32 DEVKIT V1 + ┌─────────────────────────┐ + │ │ + │ ● ● │ + 3.3V │ [ ] [ ] │ VIN ──── Alimentation 5V+ + GND │ [ ] [ ] │ GND ──── Alimentation 5V- + Touch │ [ ] [ ] │ GPIO13 + Touch │ [ ] [ ] │ GPIO12 + Touch │ [ ] [ ] │ GPIO14 ──── CLK (P10) + Touch │ [ ] [ ] │ GPIO27 + │ [ ] [ ] │ GPIO26 + │ [ ] [ ] │ GPIO25 + │ [ ] [ ] │ GPIO33 ──── OE (P10) + │ [ ] [ ] │ GPIO32 ──── STB (P10) + │ [ ] [ ] │ GPIO35 + │ [ ] [ ] │ GPIO34 + │ [ ] [ ] │ GPIO39 + │ [ ] [ ] │ GPIO36 + EN │ [ ] [ ] │ GPIO23 ──── B (P10) + │ [ ] [ ] │ GPIO22 ──── SCL (RTC) + GPIO2 ──│ [ ] [ ] │ GPIO21 ──── SDA (RTC) + GPIO4 ──│ [ ] [ ] │ GPIO19 ──── A (P10) + GPIO16 ──│ [ ] [ ] │ GPIO18 ──── C (P10) + GPIO17 ──│ [ ] [ ] │ GPIO5 ──── B2 (P10) + GPIO5 ──│ [ ] [ ] │ TX + GPIO15 ──│ [ ] [ ] │ RX + │ │ + │ ┌─────────────┐ │ + │ │ ESP32 │ │ + │ │ WiFi │ │ + │ │ Bluetooth │ │ + │ └─────────────┘ │ + │ │ + │ USB ┌─────────────┐ │ + │ ──── │ │ │ + └──────┴─────────────┴───┘ + +Connexions P10: +GPIO2 → R1 GPIO19 → A +GPIO15 → G1 GPIO23 → B +GPIO4 → B1 GPIO18 → C +GPIO16 → R2 GPIO14 → CLK +GPIO17 → G2 GPIO32 → STB +GPIO5 → B2 GPIO33 → OE + +Connexions RTC: +GPIO21 → SDA 3.3V → VCC +GPIO22 → SCL GND → GND +``` + +## Module RTC DS3231 + +``` + ┌─────────────────┐ + │ RTC DS3231 │ + ├─────────────────┤ + │ VCC ── 3.3V │ ──── ESP32 3.3V + │ GND ── GND │ ──── ESP32 GND + │ SCL ── Clock │ ──── ESP32 GPIO22 + │ SDA ── Data │ ──── ESP32 GPIO21 + └─────────────────┘ + +Note: Certains modules ont aussi: +- 32K (sortie 32kHz) - Non utilisé +- SQW (signal carré) - Non utilisé +- RST (reset) - Non utilisé +``` + +## Alimentation - IMPORTANT ! + +``` + ┌─────────────────┐ ┌─────────────────┐ + │ Alimentation │ │ ESP32 │ + │ 5V/3A │ │ (via USB ou │ + │ │ │ pin VIN) │ + ├─────────────────┤ ├─────────────────┤ + │ +5V ────────────┼─┬───┼── VIN │ + │ GND ────────────┼─┼───┼── GND │ + └─────────────────┘ │ └─────────────────┘ + │ + │ ┌─────────────────┐ + │ │ Panneau P10 │ + │ │ RGB 32x16 │ + │ ├─────────────────┤ + └───┼── +5V │ + │ (via HUB75) │ + └─────────────────┘ + +ATTENTION: +- Le panneau P10 nécessite du 5V avec suffisamment de courant +- Utilisez une alimentation 5V/3A minimum +- L'ESP32 peut être alimenté via USB pour les tests +- Pour un fonctionnement permanent, alimentez l'ESP32 via VIN avec du 5V +``` + +## Câblage recommandé + +``` +Étape 1: Connexions d'alimentation +ESP32 VIN ← 5V+ +ESP32 GND ← 5V- +P10 +5V ← 5V+ (via HUB75) +P10 GND ← 5V- (via HUB75, plusieurs pins) + +Étape 2: Connexions I2C (RTC) +ESP32 GPIO21 ← RTC SDA +ESP32 GPIO22 ← RTC SCL +ESP32 3.3V ← RTC VCC +ESP32 GND ← RTC GND + +Étape 3: Connexions HUB75 (P10) +ESP32 GPIO2 ← P10 R1 +ESP32 GPIO15 ← P10 G1 +ESP32 GPIO4 ← P10 B1 +ESP32 GPIO16 ← P10 R2 +ESP32 GPIO17 ← P10 G2 +ESP32 GPIO5 ← P10 B2 +ESP32 GPIO19 ← P10 A +ESP32 GPIO23 ← P10 B +ESP32 GPIO18 ← P10 C +ESP32 GPIO14 ← P10 CLK +ESP32 GPIO32 ← P10 STB/LAT +ESP32 GPIO33 ← P10 OE +ESP32 GND ← P10 GND (plusieurs connexions) +``` + +## Vérification des connexions + +Utilisez un multimètre pour vérifier : +1. **Continuité** entre ESP32 et P10 pour chaque signal +2. **Absence de court-circuit** entre VCC et GND +3. **Tension 5V** sur les pins d'alimentation du P10 +4. **Tension 3.3V** sur le module RTC + +## Troubleshooting connexions + +| Problème | Vérification | +|----------|-------------| +| Affichage noir | Alimentation 5V, connexion OE | +| Couleurs incorrectes | Connexions R1,G1,B1,R2,G2,B2 | +| Affichage instable | Connexions CLK, STB, GND | +| Position incorrecte | Connexions A, B, C | +| RTC ne fonctionne pas | Connexions SDA, SCL, alimentation 3.3V | diff --git a/examples/cascade_test.cpp b/examples/cascade_test.cpp new file mode 100644 index 0000000..f4fea7c --- /dev/null +++ b/examples/cascade_test.cpp @@ -0,0 +1,293 @@ +/** + * ESP32 P10 RGB Cascade Test + * Test pour vérifier le bon fonctionnement des panneaux P10 en cascade + * + * Ce test affiche : + * - Des bordures pour vérifier l'alignement des panneaux + * - La numérotation de chaque panneau + * - Des tests de couleurs + * - Un texte défilant sur toute la largeur + * + * Compatible avec toutes les configurations de cascade définies dans platformio.ini + */ + +#define PxMATRIX_SPI_FREQUENCY 10000000 + +#include +#include + +// Pins pour la matrice LED +#define P_LAT 5 +#define P_A 19 +#define P_B 23 +#define P_C 18 +#define P_OE 4 + +// Configuration des panneaux - définie par les build flags +#ifndef MATRIX_WIDTH +#define MATRIX_WIDTH 32 +#endif + +#ifndef MATRIX_HEIGHT +#define MATRIX_HEIGHT 16 +#endif + +#ifndef MATRIX_PANELS_X +#define MATRIX_PANELS_X 1 +#endif + +#ifndef MATRIX_PANELS_Y +#define MATRIX_PANELS_Y 1 +#endif + +// Calcul des dimensions totales +#define TOTAL_WIDTH (MATRIX_WIDTH * MATRIX_PANELS_X) +#define TOTAL_HEIGHT (MATRIX_HEIGHT * MATRIX_PANELS_Y) + +// Configuration du timer +hw_timer_t * timer = NULL; +portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; + +// Temps d'affichage ajusté selon le nombre de panneaux +uint8_t display_draw_time = (MATRIX_PANELS_X * MATRIX_PANELS_Y > 4) ? 20 : 30; + +// Objet matrice +PxMATRIX display(TOTAL_WIDTH, TOTAL_HEIGHT, P_LAT, P_OE, P_A, P_B, P_C); + +// Couleurs prédéfinies +uint16_t myRED = display.color565(255, 0, 0); +uint16_t myGREEN = display.color565(0, 255, 0); +uint16_t myBLUE = display.color565(0, 0, 255); +uint16_t myYELLOW = display.color565(255, 255, 0); +uint16_t myCYAN = display.color565(0, 255, 255); +uint16_t myMAGENTA = display.color565(255, 0, 255); +uint16_t myWHITE = display.color565(255, 255, 255); +uint16_t myBLACK = display.color565(0, 0, 0); +uint16_t myORANGE = display.color565(255, 165, 0); + +uint16_t colors[] = {myRED, myGREEN, myBLUE, myYELLOW, myCYAN, myMAGENTA, myWHITE, myORANGE}; +int numColors = sizeof(colors) / sizeof(colors[0]); + +// Variables pour le texte défilant +long scrollX = TOTAL_WIDTH; +unsigned long lastScrollTime = 0; +int scrollSpeed = 50; +const char* scrollText = "=== CASCADE TEST - ESP32 P10 RGB PANELS ==="; + +// Gestionnaire d'interruption pour l'affichage +void IRAM_ATTR display_updater() { + portENTER_CRITICAL_ISR(&timerMux); + display.display(display_draw_time); + portEXIT_CRITICAL_ISR(&timerMux); +} + +// Activation du timer d'affichage +void display_update_enable() { + timer = timerBegin(0, 80, true); + timerAttachInterrupt(timer, &display_updater, true); + timerAlarmWrite(timer, 1500, true); + timerAlarmEnable(timer); +} + +// Test des bordures et alignement des panneaux +void testPanelAlignment() { + Serial.println("Testing panel alignment..."); + + display.clearDisplay(); + + // Bordure extérieure + display.drawRect(0, 0, TOTAL_WIDTH, TOTAL_HEIGHT, myWHITE); + + // Lignes de séparation entre panneaux horizontaux + for (int i = 1; i < MATRIX_PANELS_X; i++) { + int x = i * MATRIX_WIDTH; + display.drawLine(x, 0, x, TOTAL_HEIGHT - 1, myRED); + } + + // Lignes de séparation entre panneaux verticaux + for (int i = 1; i < MATRIX_PANELS_Y; i++) { + int y = i * MATRIX_HEIGHT; + display.drawLine(0, y, TOTAL_WIDTH - 1, y, myGREEN); + } + + delay(3000); +} + +// Test de numérotation des panneaux +void testPanelNumbering() { + Serial.println("Testing panel numbering..."); + + display.clearDisplay(); + display.setTextSize(1); + + for (int py = 0; py < MATRIX_PANELS_Y; py++) { + for (int px = 0; px < MATRIX_PANELS_X; px++) { + int panelNum = py * MATRIX_PANELS_X + px + 1; + uint16_t color = colors[panelNum % numColors]; + + // Position au centre de chaque panneau + int centerX = px * MATRIX_WIDTH + 2; + int centerY = py * MATRIX_HEIGHT + 2; + + // Fond coloré pour le panneau + display.fillRect(px * MATRIX_WIDTH + 1, py * MATRIX_HEIGHT + 1, + MATRIX_WIDTH - 2, MATRIX_HEIGHT - 2, color); + + // Numéro du panneau en noir + display.setTextColor(myBLACK); + display.setCursor(centerX, centerY); + display.print("P"); + display.setCursor(centerX, centerY + 8); + display.print(panelNum); + + delay(800); + } + } + + delay(3000); +} + +// Test des couleurs sur tous les panneaux +void testColors() { + Serial.println("Testing colors..."); + + for (int i = 0; i < numColors; i++) { + display.fillScreen(colors[i]); + delay(800); + } + + display.clearDisplay(); + delay(500); +} + +// Test du texte défilant +void testScrollingText() { + Serial.println("Testing scrolling text..."); + + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(myWHITE); + + // Calculer la largeur approximative du texte + int textWidth = strlen(scrollText) * 6; + + // Faire défiler le texte 2 fois + for (int cycle = 0; cycle < 2; cycle++) { + scrollX = TOTAL_WIDTH; + + while (scrollX > -textWidth) { + unsigned long currentTime = millis(); + if (currentTime - lastScrollTime >= scrollSpeed) { + lastScrollTime = currentTime; + + // Effacer la ligne de texte + display.fillRect(0, 8, TOTAL_WIDTH, 8, myBLACK); + + // Afficher le texte à la nouvelle position + display.setCursor(scrollX, 8); + display.print(scrollText); + + scrollX--; + } + + delay(5); + } + } +} + +void setup() { + Serial.begin(115200); + delay(1000); + Serial.println("\n=== ESP32 P10 RGB CASCADE TEST ==="); + Serial.printf("Configuration: %dx%d panels (%dx%d total resolution)\n", + MATRIX_PANELS_X, MATRIX_PANELS_Y, TOTAL_WIDTH, TOTAL_HEIGHT); + Serial.printf("Draw time: %d\n", display_draw_time); + + // Initialisation de l'affichage + display.begin(8); + display_update_enable(); + display.clearDisplay(); + + // Luminosité adaptée au nombre de panneaux + int brightness = 150; + if (MATRIX_PANELS_X > 2) brightness = 100; + if (MATRIX_PANELS_X > 4) brightness = 80; + if (MATRIX_PANELS_X > 6) brightness = 60; + + display.setBrightness(brightness); + Serial.printf("Brightness set to: %d\n", brightness); + + display.setTextWrap(false); + display.setRotation(0); + + // Message de démarrage + display.setTextSize(1); + display.setTextColor(myWHITE); + + // Calculer position centrée + String startMsg = "CASCADE TEST"; + int msgWidth = startMsg.length() * 6; + int startX = (TOTAL_WIDTH - msgWidth) / 2; + if (startX < 0) startX = 0; + + display.setCursor(startX, 0); + display.print(startMsg); + + if (TOTAL_HEIGHT > 8) { + String configMsg = String(MATRIX_PANELS_X) + "x" + String(MATRIX_PANELS_Y) + " PANELS"; + int configWidth = configMsg.length() * 6; + int configX = (TOTAL_WIDTH - configWidth) / 2; + if (configX < 0) configX = 0; + + display.setCursor(configX, 8); + display.print(configMsg); + } + + delay(3000); + + Serial.println("Starting cascade tests..."); +} + +void loop() { + // Séquence de tests + + Serial.println("\n--- Test Cycle Starting ---"); + + // 1. Test d'alignement des panneaux + testPanelAlignment(); + + // 2. Test de numérotation des panneaux + testPanelNumbering(); + + // 3. Test des couleurs + testColors(); + + // 4. Test du texte défilant + testScrollingText(); + + // Message de fin de cycle + display.clearDisplay(); + display.setTextColor(myGREEN); + + String okMsg = "TESTS OK"; + int okWidth = okMsg.length() * 6; + int okX = (TOTAL_WIDTH - okWidth) / 2; + if (okX < 0) okX = 0; + + display.setCursor(okX, 0); + display.print(okMsg); + + if (TOTAL_HEIGHT > 8) { + String restartMsg = "RESTARTING..."; + int restartWidth = restartMsg.length() * 6; + int restartX = (TOTAL_WIDTH - restartWidth) / 2; + if (restartX < 0) restartX = 0; + + display.setCursor(restartX, 8); + display.print(restartMsg); + } + + Serial.println("--- Test Cycle Completed ---"); + Serial.println("Restarting in 5 seconds...\n"); + delay(5000); +} diff --git a/examples/nvs_erase.cpp b/examples/nvs_erase.cpp new file mode 100644 index 0000000..e89a618 --- /dev/null +++ b/examples/nvs_erase.cpp @@ -0,0 +1,27 @@ +/** + * Effacement et reformatage de la mémoire NVS + * Utilisez ce programme si vous voulez réinitialiser la mémoire de préférences + */ + +#include +#include + +void setup() { + Serial.begin(115200); + Serial.println(); + delay(1000); + + Serial.println("=== NVS Memory Erase Tool ==="); + Serial.println("Erasing the NVS partition..."); + nvs_flash_erase(); // Effacer la partition NVS + + Serial.println("Initializing the NVS partition..."); + nvs_flash_init(); // Initialiser la partition NVS + + Serial.println("NVS Memory erase completed successfully."); + Serial.println("You can now upload your main program."); +} + +void loop() { + delay(10); +} diff --git a/examples/p10_test.cpp b/examples/p10_test.cpp new file mode 100644 index 0000000..96a7780 --- /dev/null +++ b/examples/p10_test.cpp @@ -0,0 +1,156 @@ +/** + * Test de la matrice P10 RGB 32x16 + * Ce programme permet de tester l'affichage sur la matrice P10 + */ + +#include +#include + +// Configuration SPI +#define PxMATRIX_SPI_FREQUENCY 10000000 + +// Pins pour la matrice LED +#define P_LAT 5 +#define P_A 19 +#define P_B 23 +#define P_C 18 +#define P_OE 4 + +// Dimensions de la matrice +#define MATRIX_WIDTH 32 +#define MATRIX_HEIGHT 16 + +// Configuration du timer +hw_timer_t * timer = NULL; +portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; + +// Temps d'affichage +uint8_t display_draw_time = 30; + +// Objet matrice +PxMATRIX display(MATRIX_WIDTH, MATRIX_HEIGHT, P_LAT, P_OE, P_A, P_B, P_C); + +// Couleurs +uint16_t myRED = display.color565(255, 0, 0); +uint16_t myGREEN = display.color565(0, 255, 0); +uint16_t myBLUE = display.color565(0, 0, 255); +uint16_t myYELLOW = display.color565(255, 255, 0); +uint16_t myCYAN = display.color565(0, 255, 255); +uint16_t myFUCHSIA = display.color565(255, 0, 255); +uint16_t myWHITE = display.color565(255, 255, 255); +uint16_t myBLACK = display.color565(0, 0, 0); + +uint16_t myCOLOR_ARRAY[4] = {myRED, myGREEN, myBLUE, myWHITE}; + +// Gestionnaire d'interruption pour l'affichage +void IRAM_ATTR display_updater() { + portENTER_CRITICAL_ISR(&timerMux); + display.display(display_draw_time); + portEXIT_CRITICAL_ISR(&timerMux); +} + +// Activation/désactivation du timer d'affichage +void display_update_enable(bool is_enable) { + if (is_enable) { + timer = timerBegin(0, 80, true); + timerAttachInterrupt(timer, &display_updater, true); + timerAlarmWrite(timer, 1500, true); + timerAlarmEnable(timer); + } else { + timerDetachInterrupt(timer); + timerAlarmDisable(timer); + } +} + +void setup() { + delay(2000); + Serial.begin(115200); + Serial.println(); + Serial.println("=== Test P10 RGB 32x16 Matrix ==="); + + // Initialisation de l'affichage + display.begin(8); // Valeur 8 pour un panneau 1/8 scan + delay(100); + + // Activation des interruptions timer + display_update_enable(true); + delay(100); + + display.clearDisplay(); + delay(1000); + + display.setBrightness(125); // 0-255 + delay(100); + + // Test des couleurs pleines + Serial.println("Testing full screen colors..."); + display.fillScreen(myRED); + delay(1000); + display.fillScreen(myGREEN); + delay(1000); + display.fillScreen(myBLUE); + delay(1000); + display.fillScreen(myWHITE); + delay(1000); + + display.clearDisplay(); + delay(1000); + + display.setTextWrap(false); + display.setTextSize(1); + display.setRotation(0); + delay(100); + + // Test d'affichage de texte + Serial.println("Testing text display..."); + display.fillScreen(myRED); + display.setTextColor(myWHITE); + display.setCursor(0, 0); + display.print("TEST"); + display.setCursor(15, 9); + display.print("P10"); + delay(2500); + + display.clearDisplay(); + delay(1000); + + Serial.println("Setup completed. Starting color loop..."); +} + +void loop() { + int myCOLOR_ARRAY_Length = sizeof(myCOLOR_ARRAY) / sizeof(myCOLOR_ARRAY[0]); + + for (byte i = 0; i < myCOLOR_ARRAY_Length; i++) { + // Test position 1 + display.setTextColor(myCOLOR_ARRAY[i]); + display.setCursor(0, 0); + display.print("1234"); + display.setCursor(0, 9); + display.print("ABCD"); + delay(2500); + + display.clearDisplay(); + delay(1000); + + // Test position 2 + display.setTextColor(myCOLOR_ARRAY[i]); + display.setCursor(4, 0); + display.print("1234"); + display.setCursor(4, 9); + display.print("ABCD"); + delay(2500); + + display.clearDisplay(); + delay(1000); + + // Test position 3 + display.setCursor(9, 0); + display.print("1234"); + display.setCursor(9, 9); + display.print("ABCD"); + delay(2500); + + display.clearDisplay(); + delay(1000); + } +} diff --git a/examples/rtc_test.cpp b/examples/rtc_test.cpp new file mode 100644 index 0000000..2edd447 --- /dev/null +++ b/examples/rtc_test.cpp @@ -0,0 +1,160 @@ +/** + * Test du module RTC DS3231 + * Ce programme permet de tester et configurer le module RTC + */ + +#include +#include + +RTC_DS3231 rtc; + +char daysOfTheWeek[8][10] = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "ERROR"}; + +String inputString = ""; +bool stringComplete = false; + +int d_year; +byte d_month, d_day, daysOfTheWeek_Val; +byte t_hour, t_minute, t_second; + +unsigned long prevMill_Update_DateTime = 0; +const long interval_Update_DateTime = 1000; + +// Fonction pour traiter les données reçues +String getValue(String data, char separator, int index) { + int found = 0; + int strIndex[] = { 0, -1 }; + int maxIndex = data.length() - 1; + + for (int i = 0; i <= maxIndex && found <= index; i++) { + if (data.charAt(i) == separator || i == maxIndex) { + found++; + strIndex[0] = strIndex[1] + 1; + strIndex[1] = (i == maxIndex) ? i+1 : i; + } + } + return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; +} + +// Gestion des événements série +void serialEvent() { + while (Serial.available()) { + char inChar = (char)Serial.read(); + if (inChar == '\n') { + stringComplete = true; + return; + } + inputString += inChar; + } +} + +// Récupération date/heure +void get_DateTime() { + DateTime now = rtc.now(); + + d_year = now.year(); + d_month = now.month(); + d_day = now.day(); + daysOfTheWeek_Val = now.dayOfTheWeek(); + if (daysOfTheWeek_Val > 7 || daysOfTheWeek_Val < 0) daysOfTheWeek_Val = 7; + t_hour = now.hour(); + t_minute = now.minute(); + t_second = now.second(); + + char full_DateTime[60]; + sprintf(full_DateTime, "%s | %02d-%02d-%d | %02d:%02d:%02d", + daysOfTheWeek[daysOfTheWeek_Val], d_day, d_month, d_year, t_hour, t_minute, t_second); + + Serial.print("Date Time : "); + Serial.println(full_DateTime); +} + +void setup() { + delay(2000); + Serial.begin(115200); + inputString.reserve(200); + + Serial.println(); + Serial.println("------------"); + Serial.println("Starting the DS3231 RTC module."); + if (!rtc.begin()) { + Serial.println("Couldn't find RTC"); + while (1); + } + Serial.println("Successfully started the DS3231 RTC module."); + Serial.println("------------"); + Serial.println(); + + Serial.println(); + Serial.println("------------"); + Serial.println("Serial monitor settings :"); + Serial.println("- End Char : Newline"); + Serial.println("- Baud Rate : 115200"); + Serial.println("------------"); + Serial.println(); + + Serial.println(); + Serial.println("------------"); + Serial.println("Example command to set the time and date on the RTC module : "); + Serial.println("SET,2024,8,1,12,30,0"); + Serial.println(); + Serial.println("SET = command to set."); + Serial.println("2024 = Year."); + Serial.println("8 = Month."); + Serial.println("1 = Day."); + Serial.println("12 = Hour."); + Serial.println("30 = Minute."); + Serial.println("0 = Second."); + Serial.println("------------"); + Serial.println(); + + delay(3000); +} + +void loop() { + serialEvent(); + + unsigned long currentMillis_Update_DateTime = millis(); + if (currentMillis_Update_DateTime - prevMill_Update_DateTime >= interval_Update_DateTime) { + prevMill_Update_DateTime = currentMillis_Update_DateTime; + get_DateTime(); + } + + if (stringComplete) { + Serial.print("Input String : "); + Serial.println(inputString); + + String command = getValue(inputString, ',', 0); + + if (command == "SET") { + Serial.println(); + Serial.println("------------"); + Serial.println("Set the Time and Date of the DS3231 RTC Module."); + Serial.println("Incoming settings data : "); + + d_year = getValue(inputString, ',', 1).toInt(); + d_month = getValue(inputString, ',', 2).toInt(); + d_day = getValue(inputString, ',', 3).toInt(); + t_hour = getValue(inputString, ',', 4).toInt(); + t_minute = getValue(inputString, ',',5).toInt(); + t_second = getValue(inputString, ',', 6).toInt(); + + Serial.print("- Year : ");Serial.println(d_year); + Serial.print("- Month : ");Serial.println(d_month); + Serial.print("- Day : ");Serial.println(d_day); + Serial.print("- Hour : ");Serial.println(t_hour); + Serial.print("- Minute : ");Serial.println(t_minute); + Serial.print("- Second : ");Serial.println(t_second); + + Serial.println("Set Time and Date..."); + rtc.adjust(DateTime(d_year, d_month, d_day, t_hour, t_minute, t_second)); + + Serial.println("Setting the Time and Date has been completed."); + Serial.println("------------"); + Serial.println(); + } + + inputString = ""; + stringComplete = false; + } +} diff --git a/include/PageIndex.h b/include/PageIndex.h new file mode 100644 index 0000000..bb1c18e --- /dev/null +++ b/include/PageIndex.h @@ -0,0 +1,522 @@ +#ifndef PAGE_INDEX_H +#define PAGE_INDEX_H + +#include + +const char MAIN_page[] PROGMEM = R"=====( + + + Digital Clcok & Scrolling Text with ESP32 and P10 RGB 32x16 + + + +
+

Digital Clock & Scrolling Text with ESP32 and P10 RGB 32x16

+ +
+
+ +
+
+ +
+
+
+ +
+ +
+
+ +
+ +
+

Set Date & Time

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+ +
+

Display Settings

+ + + + + + + + + + + + + +
+ +
+
+
+ +
+
+
+
+
+ +
+
+
+
+ + + +
+
+ +
+ +
+

Color Settings (Mode 1 Only)

+ + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+ +
+ +
+ + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+ +
+ +
+ + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+ +
+

Scrolling Text

+ + + + + +
+
+
+ +
+
+
+
+ +
+
+ +
+ +
+

System

+ +
+
+ + + + +)====="; + +#endif // PAGE_INDEX_H diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..e8f40e8 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,160 @@ +; Configuration commune +[env] +platform = espressif32 +board = esp32dev +framework = arduino +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder +upload_speed = 921600 +board_build.f_cpu = 240000000L +board_build.f_flash = 80000000L +board_build.partitions = default.csv +build_flags = + -DCORE_DEBUG_LEVEL=0 + -DARDUINO_USB_CDC_ON_BOOT=0 + ; Configuration par défaut pour un seul panneau 32x16 + -DMATRIX_WIDTH=32 + -DMATRIX_HEIGHT=16 + -DMATRIX_PANELS_X=1 + -DMATRIX_PANELS_Y=1 + +; ========================================== +; ENVIRONNEMENT PRINCIPAL - Horloge complète +; ========================================== +[env:main] +src_filter = + +lib_deps = + adafruit/Adafruit BusIO@^1.16.1 + adafruit/Adafruit GFX Library@^1.11.9 + adafruit/RTClib@^2.1.4 + https://github.com/2dom/PxMatrix.git + +; ========================================== +; ENVIRONNEMENTS DE TEST +; ========================================== + +; Test du module RTC DS3231 +[env:rtc_test] +src_filter = +<../examples/rtc_test.cpp> +lib_deps = + adafruit/RTClib@^2.1.4 + +; Test du panneau P10 RGB +[env:p10_test] +src_filter = +<../examples/p10_test.cpp> +lib_deps = + adafruit/Adafruit BusIO@^1.16.1 + adafruit/Adafruit GFX Library@^1.11.9 + https://github.com/2dom/PxMatrix.git + +; Effacement de la mémoire NVS +[env:nvs_erase] +src_filter = +<../examples/nvs_erase.cpp> + +; ========================================== +; ENVIRONNEMENT DE DÉVELOPPEMENT +; ========================================== +[env:debug] +src_filter = + +lib_deps = + adafruit/Adafruit BusIO@^1.16.1 + adafruit/Adafruit GFX Library@^1.11.9 + adafruit/RTClib@^2.1.4 + https://github.com/2dom/PxMatrix.git +build_flags = + ${env.build_flags} + -DCORE_DEBUG_LEVEL=5 + -DDEBUG_ESP_PORT=Serial + +; Configuration pour OTA (optionnel) +; Décommentez et configurez selon vos besoins +;[env:ota] +;extends = env:main +;upload_protocol = espota +;upload_port = 192.168.1.100 +;upload_flags = --auth=your_ota_password + +; ========================================== +; CONFIGURATIONS PANNEAUX MULTIPLES +; ========================================== + +; Configuration 2 panneaux horizontaux (64x16) +[env:cascade_2x1] +extends = env:main +build_flags = + ${env.build_flags} + -DMATRIX_WIDTH=32 + -DMATRIX_HEIGHT=16 + -DMATRIX_PANELS_X=2 + -DMATRIX_PANELS_Y=1 + -DCASCADE_MODE=1 + +; Configuration 3 panneaux horizontaux (96x16) +[env:cascade_3x1] +extends = env:main +build_flags = + ${env.build_flags} + -DMATRIX_WIDTH=32 + -DMATRIX_HEIGHT=16 + -DMATRIX_PANELS_X=3 + -DMATRIX_PANELS_Y=1 + -DCASCADE_MODE=1 + +; Configuration 4 panneaux horizontaux (128x16) +[env:cascade_4x1] +extends = env:main +build_flags = + ${env.build_flags} + -DMATRIX_WIDTH=32 + -DMATRIX_HEIGHT=16 + -DMATRIX_PANELS_X=4 + -DMATRIX_PANELS_Y=1 + -DCASCADE_MODE=1 + +; Configuration 2x2 panneaux (64x32) +[env:cascade_2x2] +extends = env:main +build_flags = + ${env.build_flags} + -DMATRIX_WIDTH=32 + -DMATRIX_HEIGHT=16 + -DMATRIX_PANELS_X=2 + -DMATRIX_PANELS_Y=2 + -DCASCADE_MODE=1 + +; Configuration 6 panneaux horizontaux (192x16) +[env:cascade_6x1] +extends = env:main +build_flags = + ${env.build_flags} + -DMATRIX_WIDTH=32 + -DMATRIX_HEIGHT=16 + -DMATRIX_PANELS_X=6 + -DMATRIX_PANELS_Y=1 + -DCASCADE_MODE=1 + +; Configuration 8 panneaux horizontaux (256x16) +[env:cascade_8x1] +extends = env:main +build_flags = + ${env.build_flags} + -DMATRIX_WIDTH=32 + -DMATRIX_HEIGHT=16 + -DMATRIX_PANELS_X=8 + -DMATRIX_PANELS_Y=1 + -DCASCADE_MODE=1 + +; Test pour panneaux multiples +[env:test_cascade] +src_filter = +<../examples/cascade_test.cpp> +lib_deps = + adafruit/Adafruit BusIO@^1.16.1 + adafruit/Adafruit GFX Library@^1.11.9 + https://github.com/2dom/PxMatrix.git +build_flags = + ${env.build_flags} + -DMATRIX_WIDTH=32 + -DMATRIX_HEIGHT=16 + -DMATRIX_PANELS_X=2 + -DMATRIX_PANELS_Y=1 + -DCASCADE_MODE=1 diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..511a065 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,822 @@ +/** + * ESP32 P10 RGB 32x16 Digital Clock with Web Server + * Compatible with PlatformIO + * + * Hardware Requirements: + * - ESP32 DEVKIT V1 + * - P10 RGB 32x16 HUB75 Panel + * - DS3231 RTC Module + * - 5V Power Supply + * + * Libraries: + * - Adafruit BusIO + * - Adafruit GFX Library + * - PxMatrix Library + * - RTClib + */ + +// Defines pour la fréquence SPI (réduire si du bruit apparaît sur l'affichage) +#define PxMATRIX_SPI_FREQUENCY 10000000 + +// Inclusion des bibliothèques +#include +#include +#include +#include +#include +#include +#include +#include "PageIndex.h" + +// Pins pour la matrice LED +#define P_LAT 5 +#define P_A 19 +#define P_B 23 +#define P_C 18 +#define P_OE 4 + +// Configuration des panneaux - définie par les build flags ou valeurs par défaut +#ifndef MATRIX_WIDTH +#define MATRIX_WIDTH 32 +#endif + +#ifndef MATRIX_HEIGHT +#define MATRIX_HEIGHT 16 +#endif + +#ifndef MATRIX_PANELS_X +#define MATRIX_PANELS_X 1 +#endif + +#ifndef MATRIX_PANELS_Y +#define MATRIX_PANELS_Y 1 +#endif + +// Calcul des dimensions totales +#define TOTAL_WIDTH (MATRIX_WIDTH * MATRIX_PANELS_X) +#define TOTAL_HEIGHT (MATRIX_HEIGHT * MATRIX_PANELS_Y) + +// Configuration du timer +hw_timer_t * timer = NULL; +portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; + +// Temps d'affichage (plus élevé = plus lumineux, mais attention aux crashs) +uint8_t display_draw_time = 30; // 30-70 est généralement correct + +// Objet matrice avec dimensions totales calculées +PxMATRIX display(TOTAL_WIDTH, TOTAL_HEIGHT, P_LAT, P_OE, P_A, P_B, P_C); + +// Couleurs prédéfinies +uint16_t myRED = display.color565(255, 0, 0); +uint16_t myGREEN = display.color565(0, 255, 0); +uint16_t myBLUE = display.color565(0, 0, 255); +uint16_t myYELLOW = display.color565(255, 255, 0); +uint16_t myCYAN = display.color565(0, 255, 255); +uint16_t myFUCHSIA = display.color565(255, 0, 255); +uint16_t myWHITE = display.color565(255, 255, 255); +uint16_t myBLACK = display.color565(0, 0, 0); + +uint16_t myCOLOR_ARRAY[7] = {myRED, myGREEN, myBLUE, myYELLOW, myCYAN, myFUCHSIA, myWHITE}; +int cnt_Color = 0; +int myCOLOR_ARRAY_Length = sizeof(myCOLOR_ARRAY) / sizeof(myCOLOR_ARRAY[0]); + +// Variables pour le texte défilant +unsigned long prevMill_Scroll_Text = 0; +int scrolling_Y_Pos = 0; +long scrolling_X_Pos; +long scrolling_X_Pos_CT; +uint16_t scrolling_Text_Color; +uint16_t text_Color; +char text_Scrolling_Text[151]; +uint16_t text_Length_In_Pixel; +bool set_up_Scrolling_Text_Length = true; +bool start_Scroll_Text = false; +byte scrolling_text_Display_Order = 0; +bool reset_Scrolling_Text = false; + +// Variables de temps +unsigned long prevMill_Update_Time = 0; +const long interval_Update_Time = 1000; +unsigned long prevMill_Show_Clock = 0; +const long interval_Show_Clock = 500; + +// Variables pour la date et l'heure +char daysOfTheWeek[7][10] = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"}; +char chr_t_Minute[3]; +byte minute_Val, last_minute_Val; +char chr_t_Hour[3]; +char day_and_date_Text[25]; +bool blink_Colon = false; +uint16_t clock_Color; +uint16_t day_and_date_Text_Color; + +// Variables de configuration +int d_Year; +byte d_Month, d_Day; +byte t_Hour, t_Minute, t_Second; +byte input_Display_Mode = 1; +byte input_Brightness = 125; +byte input_Scrolling_Speed = 45; +int Color_Clock_R = 255, Color_Clock_G = 0, Color_Clock_B = 0; +int Color_Date_R = 0, Color_Date_G = 255, Color_Date_B = 0; +int Color_Text_R = 0, Color_Text_G = 0, Color_Text_B = 255; +char input_Scrolling_Text[151] = "ESP32 P10 RGB Digital Clock with PlatformIO"; + +// Configuration WiFi - Modifiez selon vos besoins +const char* ssid = "YOUR_WIFI_SSID"; +const char* password = "YOUR_WIFI_PASSWORD"; + +// Configuration Point d'accès (si pas de WiFi) +const char* ap_ssid = "ESP32_Clock"; +const char* ap_password = "esp32clock"; + +// Clé de sécurité pour l'interface web +#define KEY_TXT "p10rgbesp32ws" + +// Mode de fonctionnement WiFi +bool useStationMode = true; // true = se connecter au WiFi, false = créer un point d'accès + +// Objets RTC et Preferences +RTC_DS3231 rtc; +Preferences preferences; + +// Serveur web +WebServer server(80); + +// Gestionnaire d'interruption pour l'affichage +void IRAM_ATTR display_updater() { + portENTER_CRITICAL_ISR(&timerMux); + display.display(display_draw_time); + portEXIT_CRITICAL_ISR(&timerMux); +} + +// Activation/désactivation du timer d'affichage +void display_update_enable(bool is_enable) { + if (is_enable) { + timer = timerBegin(0, 80, true); + timerAttachInterrupt(timer, &display_updater, true); + timerAlarmWrite(timer, 1500, true); + timerAlarmEnable(timer); + } else { + timerDetachInterrupt(timer); + timerAlarmDisable(timer); + } +} + +// Connexion WiFi +void connecting_To_WiFi() { + Serial.println("\n-------------WIFI mode"); + Serial.println("WIFI mode : STA"); + WiFi.mode(WIFI_STA); + Serial.println("-------------"); + delay(1000); + + Serial.println("\n-------------Connection"); + Serial.print("Connecting to "); + Serial.println(ssid); + WiFi.begin(ssid, password); + + int connecting_process_timed_out = 40; // 20 secondes timeout + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); + if(connecting_process_timed_out > 0) connecting_process_timed_out--; + if(connecting_process_timed_out == 0) { + Serial.println("\nFailed to connect to WiFi. Switching to AP mode."); + useStationMode = false; + break; + } + } + + if (WiFi.status() == WL_CONNECTED) { + Serial.println("\nWiFi connected"); + Serial.print("Successfully connected to : "); + Serial.println(ssid); + Serial.print("IP address : "); + Serial.println(WiFi.localIP()); + } + Serial.println("-------------"); +} + +// Configuration du point d'accès +void set_ESP32_Access_Point() { + Serial.println("\n-------------"); + Serial.println("WIFI mode : AP"); + WiFi.mode(WIFI_AP); + Serial.println("-------------"); + delay(1000); + + Serial.println("\n-------------"); + Serial.println("Setting up ESP32 to be an Access Point."); + WiFi.softAP(ap_ssid, ap_password); + delay(1000); + + IPAddress local_ip(192, 168, 1, 1); + IPAddress gateway(192, 168, 1, 1); + IPAddress subnet(255, 255, 255, 0); + + WiFi.softAPConfig(local_ip, gateway, subnet); + Serial.println("-------------"); + Serial.print("SSID name : "); + Serial.println(ap_ssid); + Serial.print("IP address : "); + Serial.println(WiFi.softAPIP()); + delay(1000); +} + +// Fonction pour obtenir la largeur du texte en pixels +uint16_t getTextWidth(const char* text) { + int16_t x1, y1; + uint16_t w, h; + display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h); + return w; +} + +// Fonction pour dessiner les deux points de l'heure +void drawColon(int16_t x, int16_t y, uint16_t colonColor) { + display.drawPixel(x, y, colonColor); + display.drawPixel(x+1, y, colonColor); + display.drawPixel(x, y+1, colonColor); + display.drawPixel(x+1, y+1, colonColor); + + display.drawPixel(x, y+3, colonColor); + display.drawPixel(x+1, y+3, colonColor); + display.drawPixel(x, y+4, colonColor); + display.drawPixel(x+1, y+4, colonColor); +} + +// Fonction de texte défilant adaptée aux panneaux multiples +void run_Scrolling_Text(uint8_t st_Y_Pos, byte st_Speed, char * st_Text, uint16_t st_Color) { + if (start_Scroll_Text == true && set_up_Scrolling_Text_Length == true) { + if (strlen(st_Text) > 0) { + text_Length_In_Pixel = getTextWidth(st_Text); + scrolling_X_Pos = TOTAL_WIDTH; // Utiliser la largeur totale + set_up_Scrolling_Text_Length = false; + } else { + start_Scroll_Text = false; + return; + } + } + + unsigned long currentMillis_Scroll_Text = millis(); + if (currentMillis_Scroll_Text - prevMill_Scroll_Text >= st_Speed) { + prevMill_Scroll_Text = currentMillis_Scroll_Text; + + scrolling_X_Pos--; + if (scrolling_X_Pos < -(TOTAL_WIDTH + text_Length_In_Pixel)) { // Utiliser la largeur totale + set_up_Scrolling_Text_Length = true; + start_Scroll_Text = false; + return; + } + + scrolling_X_Pos_CT = scrolling_X_Pos + 1; + + display.setTextColor(myBLACK); + display.setCursor(scrolling_X_Pos_CT, st_Y_Pos); + display.print(st_Text); + + display.setTextColor(st_Color); + display.setCursor(scrolling_X_Pos, st_Y_Pos); + display.print(st_Text); + } +} + +// Récupération de l'heure +void get_Time() { + DateTime now = rtc.now(); + minute_Val = now.minute(); + sprintf(chr_t_Hour, "%02d", now.hour()); + sprintf(chr_t_Minute, "%02d", now.minute()); +} + +// Récupération de la date +void get_Date() { + DateTime now = rtc.now(); + sprintf(day_and_date_Text, "%s, %02d-%02d-%d", + daysOfTheWeek[now.dayOfTheWeek()], + now.day(), now.month(), now.year()); +} + +// Chargement des paramètres depuis la mémoire flash +void loadSettings() { + preferences.begin("mySettings", true); + + input_Display_Mode = preferences.getInt("input_DM", 1); + input_Brightness = preferences.getInt("input_BRT", 125); + input_Scrolling_Speed = preferences.getInt("input_SS", 45); + Color_Clock_R = preferences.getInt("CC_R", 255); + Color_Clock_G = preferences.getInt("CC_G", 0); + Color_Clock_B = preferences.getInt("CC_B", 0); + Color_Date_R = preferences.getInt("DC_R", 0); + Color_Date_G = preferences.getInt("DC_G", 255); + Color_Date_B = preferences.getInt("DC_B", 0); + Color_Text_R = preferences.getInt("CT_R", 0); + Color_Text_G = preferences.getInt("CT_G", 0); + Color_Text_B = preferences.getInt("CT_B", 255); + + String savedText = preferences.getString("scrollText", "ESP32 P10 RGB Digital Clock with PlatformIO"); + strcpy(input_Scrolling_Text, savedText.c_str()); + + preferences.end(); + + // Application des paramètres + display.setBrightness(input_Brightness); + if (input_Display_Mode == 1) { + clock_Color = display.color565(Color_Clock_R, Color_Clock_G, Color_Clock_B); + day_and_date_Text_Color = display.color565(Color_Date_R, Color_Date_G, Color_Date_B); + text_Color = display.color565(Color_Text_R, Color_Text_G, Color_Text_B); + } +} + +// Gestionnaire de la page principale +void handleRoot() { + server.send(200, "text/html", MAIN_page); +} + +// Gestionnaire des paramètres +void handleSettings() { + String incoming_Settings = server.arg("key"); + + Serial.println("\n-------------Settings"); + Serial.print("Key : "); + Serial.println(incoming_Settings); + + if (incoming_Settings != KEY_TXT) { + server.send(200, "text/plain", "+ERR"); + Serial.println("Wrong key!"); + Serial.println("-------------"); + return; + } + + incoming_Settings = server.arg("sta"); + + // Définir la date et l'heure + if (incoming_Settings == "setTimeDate") { + d_Year = server.arg("d_Year").toInt(); + d_Month = server.arg("d_Month").toInt(); + d_Day = server.arg("d_Day").toInt(); + t_Hour = server.arg("t_Hour").toInt(); + t_Minute = server.arg("t_Minute").toInt(); + t_Second = server.arg("t_Second").toInt(); + + Serial.println("Set Time and Date."); + Serial.printf("DateTime : %02d-%02d-%d %02d:%02d:%02d\n", d_Day, d_Month, d_Year, t_Hour, t_Minute, t_Second); + + rtc.adjust(DateTime(d_Year, d_Month, d_Day, t_Hour, t_Minute, t_Second)); + Serial.println("Setting completed."); + } + + // Définir le mode d'affichage + else if (incoming_Settings == "setDisplayMode") { + input_Display_Mode = server.arg("input_Display_Mode").toInt(); + + Serial.print("Set Display Mode : "); + Serial.println(input_Display_Mode); + + display_update_enable(false); + delay(100); + + preferences.begin("mySettings", false); + preferences.putInt("input_DM", input_Display_Mode); + preferences.end(); + + display_update_enable(true); + + if (input_Display_Mode == 1) { + clock_Color = display.color565(Color_Clock_R, Color_Clock_G, Color_Clock_B); + day_and_date_Text_Color = display.color565(Color_Date_R, Color_Date_G, Color_Date_B); + text_Color = display.color565(Color_Text_R, Color_Text_G, Color_Text_B); + } + + display.clearDisplay(); + reset_Scrolling_Text = true; + scrolling_text_Display_Order = 0; + } + + // Définir la luminosité + else if (incoming_Settings == "setBrightness") { + input_Brightness = server.arg("input_Brightness").toInt(); + if (input_Brightness > 255) input_Brightness = 255; + if (input_Brightness < 0) input_Brightness = 0; + + Serial.print("Set Brightness : "); + Serial.println(input_Brightness); + + display_update_enable(false); + delay(100); + + preferences.begin("mySettings", false); + preferences.putInt("input_BRT", input_Brightness); + preferences.end(); + + display_update_enable(true); + display.setBrightness(input_Brightness); + } + + // Définir la vitesse de défilement + else if (incoming_Settings == "setScrollingSpeed") { + input_Scrolling_Speed = server.arg("input_Scrolling_Speed").toInt(); + if (input_Scrolling_Speed > 100) input_Scrolling_Speed = 100; + if (input_Scrolling_Speed < 10) input_Scrolling_Speed = 10; + + Serial.print("Set Scrolling Speed : "); + Serial.println(input_Scrolling_Speed); + + preferences.begin("mySettings", false); + preferences.putInt("input_SS", input_Scrolling_Speed); + preferences.end(); + } + + // Définir la couleur de l'horloge + else if (incoming_Settings == "setColorClock") { + if (input_Display_Mode == 2) { + server.send(200, "text/plain", "+ERR_DM"); + Serial.println("-------------"); + return; + } + + Color_Clock_R = server.arg("Color_Clock_R").toInt(); + Color_Clock_G = server.arg("Color_Clock_G").toInt(); + Color_Clock_B = server.arg("Color_Clock_B").toInt(); + + Serial.printf("Set Clock Color (RGB) : %d,%d,%d\n", Color_Clock_R, Color_Clock_G, Color_Clock_B); + + display_update_enable(false); + delay(100); + + preferences.begin("mySettings", false); + preferences.putInt("CC_R", Color_Clock_R); + preferences.putInt("CC_G", Color_Clock_G); + preferences.putInt("CC_B", Color_Clock_B); + preferences.end(); + + display_update_enable(true); + clock_Color = display.color565(Color_Clock_R, Color_Clock_G, Color_Clock_B); + } + + // Définir la couleur de la date + else if (incoming_Settings == "setColorDate") { + if (input_Display_Mode == 2) { + server.send(200, "text/plain", "+ERR_DM"); + Serial.println("-------------"); + return; + } + + Color_Date_R = server.arg("Color_Date_R").toInt(); + Color_Date_G = server.arg("Color_Date_G").toInt(); + Color_Date_B = server.arg("Color_Date_B").toInt(); + + Serial.printf("Set Date Color (RGB) : %d,%d,%d\n", Color_Date_R, Color_Date_G, Color_Date_B); + + display_update_enable(false); + delay(100); + + preferences.begin("mySettings", false); + preferences.putInt("DC_R", Color_Date_R); + preferences.putInt("DC_G", Color_Date_G); + preferences.putInt("DC_B", Color_Date_B); + preferences.end(); + + display_update_enable(true); + day_and_date_Text_Color = display.color565(Color_Date_R, Color_Date_G, Color_Date_B); + } + + // Définir la couleur du texte + else if (incoming_Settings == "setColorText") { + if (input_Display_Mode == 2) { + server.send(200, "text/plain", "+ERR_DM"); + Serial.println("-------------"); + return; + } + + Color_Text_R = server.arg("Color_Text_R").toInt(); + Color_Text_G = server.arg("Color_Text_G").toInt(); + Color_Text_B = server.arg("Color_Text_B").toInt(); + + Serial.printf("Set Text Color (RGB) : %d,%d,%d\n", Color_Text_R, Color_Text_G, Color_Text_B); + + display_update_enable(false); + delay(100); + + preferences.begin("mySettings", false); + preferences.putInt("CT_R", Color_Text_R); + preferences.putInt("CT_G", Color_Text_G); + preferences.putInt("CT_B", Color_Text_B); + preferences.end(); + + display_update_enable(true); + text_Color = display.color565(Color_Text_R, Color_Text_G, Color_Text_B); + } + + // Définir le texte défilant + else if (incoming_Settings == "setScrollingText") { + String scrollText = server.arg("input_Scrolling_Text"); + if (scrollText.length() > 150) scrollText = scrollText.substring(0, 150); + strcpy(input_Scrolling_Text, scrollText.c_str()); + + Serial.print("Set Scrolling Text : "); + Serial.println(input_Scrolling_Text); + + preferences.begin("mySettings", false); + preferences.putString("scrollText", scrollText); + preferences.end(); + + reset_Scrolling_Text = true; + scrolling_text_Display_Order = 0; + } + + // Reset du système + else if (incoming_Settings == "resetSystem") { + Serial.println("System Reset requested"); + server.send(200, "text/plain", "+OK"); + delay(1000); + ESP.restart(); + } + + server.send(200, "text/plain", "+OK"); + Serial.println("-------------"); +} + +// Configuration et démarrage du serveur +void prepare_and_start_The_Server() { + server.on("/", handleRoot); + server.on("/settings", handleSettings); + delay(500); + + server.begin(); + Serial.println("\nHTTP server started"); + + if (useStationMode) { + Serial.print("Open http://"); + Serial.print(WiFi.localIP()); + Serial.println(" in your browser"); + } else { + Serial.print("Connect to WiFi network: "); + Serial.println(ap_ssid); + Serial.print("Then open http://"); + Serial.print(WiFi.softAPIP()); + Serial.println(" in your browser"); + } + + Serial.println("Use key: " KEY_TXT); + delay(500); +} + +void setup() { + delay(1000); + Serial.begin(115200); + Serial.println("\n=== ESP32 P10 RGB Digital Clock ==="); + Serial.println("Version: PlatformIO Compatible with Cascade Support"); + + // Affichage de la configuration des panneaux + Serial.println("\n--- Configuration Panneaux ---"); + Serial.printf("Panneaux X: %d\n", MATRIX_PANELS_X); + Serial.printf("Panneaux Y: %d\n", MATRIX_PANELS_Y); + Serial.printf("Taille panneau: %dx%d pixels\n", MATRIX_WIDTH, MATRIX_HEIGHT); + Serial.printf("Taille totale: %dx%d pixels\n", TOTAL_WIDTH, TOTAL_HEIGHT); + Serial.printf("Nombre total panneaux: %d\n", MATRIX_PANELS_X * MATRIX_PANELS_Y); + + // Ajustement automatique de la luminosité selon le nombre de panneaux + int auto_brightness = 125; + if (MATRIX_PANELS_X > 2) auto_brightness = 100; + if (MATRIX_PANELS_X > 4) auto_brightness = 80; + if (MATRIX_PANELS_X > 6) auto_brightness = 60; + input_Brightness = auto_brightness; + + Serial.printf("Luminosité auto-ajustée: %d\n", auto_brightness); + Serial.println("------------------------------"); + + // Initialisation du RTC + Serial.println("\n------------"); + Serial.println("Starting DS3231 RTC module..."); + if (!rtc.begin()) { + Serial.println("Couldn't find RTC"); + while (1) delay(10); + } + Serial.println("DS3231 RTC module started successfully"); + Serial.println("------------"); + + // Initialisation de l'affichage + display.begin(8); // Valeur 8 pour un panneau 1/8 scan + delay(100); + + // Activation des interruptions timer + display_update_enable(true); + delay(100); + + display.clearDisplay(); + delay(500); + + // Chargement des paramètres + loadSettings(); + + // Appliquer la luminosité ajustée si pas de sauvegarde + display.setBrightness(input_Brightness); + + // Test d'affichage des couleurs avec message adapté + Serial.println("Testing display colors..."); + + // Test de bordures pour vérifier l'alignement (panneaux multiples) + if (MATRIX_PANELS_X > 1 || MATRIX_PANELS_Y > 1) { + Serial.println("Testing panel alignment..."); + + // Bordure extérieure + display.drawRect(0, 0, TOTAL_WIDTH, TOTAL_HEIGHT, myWHITE); + delay(1000); + + // Lignes de séparation entre panneaux + for (int i = 1; i < MATRIX_PANELS_X; i++) { + int x = i * MATRIX_WIDTH; + display.drawLine(x, 0, x, TOTAL_HEIGHT - 1, myRED); + } + for (int i = 1; i < MATRIX_PANELS_Y; i++) { + int y = i * MATRIX_HEIGHT; + display.drawLine(0, y, TOTAL_WIDTH - 1, y, myGREEN); + } + delay(2000); + display.clearDisplay(); + } + + // Test des couleurs + display.fillScreen(myRED); + delay(1000); + display.fillScreen(myGREEN); + delay(1000); + display.fillScreen(myBLUE); + delay(1000); + display.fillScreen(myWHITE); + delay(1000); + + display.clearDisplay(); + delay(500); + + display.setTextWrap(false); + display.setTextSize(1); + display.setRotation(0); + + // Affichage du message de démarrage adapté + display.setTextColor(myWHITE); + + // Calculer la position centrée pour le texte + String startMsg = "ESP32 CLOCK"; + if (MATRIX_PANELS_X > 1) { + startMsg = String(MATRIX_PANELS_X) + "x" + String(MATRIX_PANELS_Y) + " P10 CLOCK"; + } + + int textWidth = startMsg.length() * 6; // Approximation + int startX = (TOTAL_WIDTH - textWidth) / 2; + if (startX < 0) startX = 0; + + display.setCursor(startX, 0); + display.print(startMsg); + + if (TOTAL_HEIGHT > 16) { + display.setCursor(startX, 16); + display.print("CASCADE MODE"); + } else { + display.setCursor(startX, 8); + display.print("READY"); + } + + delay(3000); + display.clearDisplay(); + + // Configuration WiFi + if (useStationMode) { + connecting_To_WiFi(); + if (!useStationMode) { + set_ESP32_Access_Point(); + } + } else { + set_ESP32_Access_Point(); + } + + // Démarrage du serveur web + prepare_and_start_The_Server(); + + Serial.println("\nSetup completed. System ready!"); + + // Message de fin adapté à la configuration + if (MATRIX_PANELS_X > 1) { + Serial.printf("Running with %dx%d panels cascade (%dx%d total resolution)\n", + MATRIX_PANELS_X, MATRIX_PANELS_Y, TOTAL_WIDTH, TOTAL_HEIGHT); + } +} + +void loop() { + // Gestion du serveur web + server.handleClient(); + + // Mise à jour de l'heure + unsigned long currentMillis_Update_Time = millis(); + if (currentMillis_Update_Time - prevMill_Update_Time >= interval_Update_Time) { + prevMill_Update_Time = currentMillis_Update_Time; + get_Time(); + blink_Colon = !blink_Colon; + } + + // Affichage de l'horloge + unsigned long currentMillis_Show_Clock = millis(); + if (currentMillis_Show_Clock - prevMill_Show_Clock >= interval_Show_Clock) { + prevMill_Show_Clock = currentMillis_Show_Clock; + + display.setTextSize(1); + + // Couleur selon le mode + if (input_Display_Mode == 1) { + clock_Color = display.color565(Color_Clock_R, Color_Clock_G, Color_Clock_B); + } else { + clock_Color = myCOLOR_ARRAY[cnt_Color]; + } + + // Calcul de la position centrée pour l'horloge (adapté à la largeur totale) + int clock_width = 30; // Approximation pour "HH:MM" + int clock_x = (TOTAL_WIDTH - clock_width) / 2; + if (clock_x < 1) clock_x = 1; + + // Effacer et afficher les heures + if (last_minute_Val != minute_Val) display.fillRect(clock_x, 0, 11, 7, myBLACK); + display.setTextColor(clock_Color); + display.setCursor(clock_x, 0); + display.print(chr_t_Hour); + + // Position des deux points (centrée) + int colon_x = clock_x + 14; + if (blink_Colon) { + drawColon(colon_x, 1, clock_Color); + } else { + drawColon(colon_x, 1, myBLACK); + } + + // Effacer et afficher les minutes + if (last_minute_Val != minute_Val) display.fillRect(clock_x + 19, 0, 11, 7, myBLACK); + display.setTextColor(clock_Color); + display.setCursor(clock_x + 19, 0); + display.print(chr_t_Minute); + + last_minute_Val = minute_Val; + } + + // Gestion du texte défilant + if (reset_Scrolling_Text) { + start_Scroll_Text = false; + set_up_Scrolling_Text_Length = true; + reset_Scrolling_Text = false; + } + + if (start_Scroll_Text == false) { + scrolling_text_Display_Order++; + + if (input_Display_Mode == 1) { + if (scrolling_text_Display_Order > 2) scrolling_text_Display_Order = 1; + } else { + if (scrolling_text_Display_Order > 3) scrolling_text_Display_Order = 1; + } + + // Affichage de la date + if (scrolling_text_Display_Order == 1) { + get_Date(); + display.setTextSize(1); + scrolling_Y_Pos = 8; + + if (input_Display_Mode == 1) { + scrolling_Text_Color = display.color565(Color_Date_R, Color_Date_G, Color_Date_B); + } else { + int next_cnt_Color = (cnt_Color + 1) % myCOLOR_ARRAY_Length; + scrolling_Text_Color = myCOLOR_ARRAY[next_cnt_Color]; + } + + strcpy(text_Scrolling_Text, day_and_date_Text); + } + + // Affichage du texte personnalisé + if (scrolling_text_Display_Order == 2) { + display.setTextSize(1); + scrolling_Y_Pos = 8; + + if (input_Display_Mode == 1) { + scrolling_Text_Color = display.color565(Color_Text_R, Color_Text_G, Color_Text_B); + } else { + int next_cnt_Color = (cnt_Color + 2) % myCOLOR_ARRAY_Length; + scrolling_Text_Color = myCOLOR_ARRAY[next_cnt_Color]; + } + + strcpy(text_Scrolling_Text, input_Scrolling_Text); + } + + // Changement de couleur (mode 2 seulement) + if (scrolling_text_Display_Order == 3 && input_Display_Mode == 2) { + cnt_Color = (cnt_Color + 1) % myCOLOR_ARRAY_Length; + strcpy(text_Scrolling_Text, ""); + } + + start_Scroll_Text = true; + } + + if (start_Scroll_Text) { + run_Scrolling_Text(scrolling_Y_Pos, input_Scrolling_Speed, text_Scrolling_Text, scrolling_Text_Color); + } + + // Petit délai pour éviter la surcharge du processeur + delay(1); +}