This commit is contained in:
Clément SAILLANT
2025-08-15 20:45:56 +02:00
parent b72144cc0d
commit f575dfb64d
16 changed files with 367 additions and 3801 deletions
-133
View File
@@ -1,133 +0,0 @@
# Guide de Test du Portail Captif
## Test Rapide - Portail Captif
### Étape 1 : Compiler et téléverser le firmware principal
```bash
# Si PlatformIO est installé
pio run -e main --target upload
# Ou via VS Code
# Utiliser la tâche "PlatformIO: Upload Main Project"
```
### Étape 2 : Configuration initiale
1. **Mode Point d'accès** : Assurez-vous que `useStationMode = false` dans le code
2. **Redémarrez l'ESP32** après le téléversement
### Étape 3 : Test du portail captif
1. **Connectez-vous au WiFi** :
- Nom : `HOKA_Clock`
- Mot de passe : `hoka`
2. **Test automatique** :
- Ouvrez votre navigateur
- Essayez d'aller sur n'importe quel site (google.com, facebook.com, etc.)
- Vous devriez être automatiquement redirigé vers l'interface de l'horloge
3. **Test manuel** :
- Accédez directement à : `http://192.168.1.1`
### Étape 4 : Vérification des fonctionnalités
1. **Interface web** : L'interface de configuration de l'horloge doit s'afficher
2. **Clé d'accès** : Utilisez `hoka` comme clé pour modifier les paramètres
3. **Redirection** : Toutes les tentatives de navigation doivent rediriger vers l'horloge
## Test Dédié - Portail Captif Simple
Pour tester uniquement la fonctionnalité de portail captif sans l'affichage LED :
### Étape 1 : Compiler le test
```bash
pio run -e captive_portal_test --target upload
```
### Étape 2 : Connection et test
1. **WiFi** : `HOKA_Clock_Test` (mot de passe : `hoka`)
2. **Navigation** : Essayez d'aller sur n'importe quel site
3. **Résultat attendu** : Page de test confirmant que le portail captif fonctionne
## Surveillance et débogage
### Monitoring série
```bash
pio device monitor
```
### Messages à surveiller
```
=== ESP32 P10 RGB Digital Clock ===
WIFI mode : AP avec Portail Captif
Serveur DNS démarré pour portail captif
HTTP server started
Captive Portal active - navigate to any website
```
### Débogage des problèmes
1. **Le portail ne s'ouvre pas** :
- Vérifiez que `useStationMode = false`
- Redémarrez l'ESP32
- Testez l'accès direct à `http://192.168.1.1`
2. **Problèmes de redirection** :
- Effacez le cache du navigateur
- Testez avec un navigateur différent
- Vérifiez les logs série pour voir les requêtes
3. **Compilation échoue** :
- Vérifiez que `DNSServer` est dans les dépendances
- Utilisez l'environnement `main` ou `captive_portal_test`
## Personnalisation
### Modifier le nom du réseau WiFi
Dans `src/main.cpp` :
```cpp
const char* ap_ssid = "MON_HORLOGE"; // Changez ici
```
### Modifier l'IP du portail
```cpp
const IPAddress apIP(192, 168, 1, 1); // Changez ici
```
### Ajouter des routes personnalisées
```cpp
server.on("/ma-route", maFonction);
```
## Compatibilité testée
**Android** : Notification automatique "Se connecter au réseau"
**iOS** : Ouverture automatique du navigateur captif
**Windows** : Redirection lors de la première navigation
**macOS** : Détection automatique du portail captif
**Linux** : Redirection manuelle nécessaire
## Prochaines étapes
Une fois le portail captif testé et fonctionnel :
1. **Personnalisez l'interface** web selon vos besoins
2. **Ajoutez des fonctionnalités** (WPS, configuration WiFi avancée, etc.)
3. **Optimisez les performances** selon votre configuration matérielle
4. **Testez avec différents appareils** pour garantir la compatibilité
## Support
Pour toute question ou problème :
- Vérifiez les logs série avec `pio device monitor`
- Consultez la documentation dans `CAPTIVE_PORTAL_README.md`
- Testez d'abord avec l'environnement `captive_portal_test`
-156
View File
@@ -1,156 +0,0 @@
# Configuration du Portail Captif pour ESP32 P10 RGB Digital Clock
## Modifications apportées
Ce document décrit les modifications apportées pour transformer l'interface web de l'horloge ESP32 en portail captif.
### 1. Modifications du fichier `platformio.ini`
Ajout de la dépendance `DNSServer` dans l'environnement principal :
```ini
[env:main]
src_filter = +<main.cpp>
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
DNSServer # <-- NOUVELLE DÉPENDANCE
```
### 2. Modifications du fichier `src/main.cpp`
#### 2.1 Inclusion de la bibliothèque DNSServer
```cpp
#include <DNSServer.h>
```
#### 2.2 Déclaration des objets pour le portail captif
```cpp
// Serveur web et DNS pour portail captif
WebServer server(80);
DNSServer dnsServer;
// Configuration du portail captif
const byte DNS_PORT = 53;
const IPAddress apIP(192, 168, 1, 1);
```
#### 2.3 Modification de la fonction `set_ESP32_Access_Point()`
- Ajout du démarrage du serveur DNS
- Configuration pour rediriger toutes les requêtes DNS vers l'ESP32
```cpp
// Démarrage du serveur DNS pour le portail captif
dnsServer.start(DNS_PORT, "*", apIP);
```
#### 2.4 Nouvelles fonctions de gestion des requêtes
- `handleCaptivePortal()` : Gère les redirections du portail captif
- `handleNotFound()` : Traite toutes les requêtes non définies
#### 2.5 Configuration des routes spéciales
Ajout de routes communes utilisées par les systèmes d'exploitation pour détecter les portails captifs :
```cpp
server.on("/generate_204", handleRoot); // Android
server.on("/fwlink", handleRoot); // Microsoft
server.on("/hotspot-detect.html", handleRoot); // Apple
server.onNotFound(handleNotFound); // Toutes autres requêtes
```
#### 2.6 Gestion du DNS dans la tâche WebServer
Ajout du traitement des requêtes DNS dans la boucle principale :
```cpp
// Gestion du serveur DNS pour le portail captif (uniquement en mode AP)
if (!useStationMode) {
dnsServer.processNextRequest();
}
```
## Fonctionnement du portail captif
### 1. Comment ça marche ?
1. **Point d'accès WiFi** : L'ESP32 crée un réseau WiFi nommé "HOKA_Clock"
2. **Serveur DNS** : Toutes les requêtes DNS sont redirigées vers l'IP de l'ESP32 (192.168.1.1)
3. **Interception web** : Toutes les tentatives de navigation sont capturées
4. **Redirection** : L'utilisateur est automatiquement redirigé vers l'interface de l'horloge
### 2. Expérience utilisateur
1. L'utilisateur se connecte au WiFi "HOKA_Clock" (mot de passe : "hoka")
2. Quand il essaie de naviguer sur n'importe quel site web, il est automatiquement redirigé vers l'interface de l'horloge
3. Il peut alors configurer l'horloge directement via l'interface web
### 3. Compatibilité
Le portail captif est compatible avec :
- **Android** : Détection automatique et affichage de la notification de connexion
- **iOS/macOS** : Ouverture automatique du navigateur captif
- **Windows** : Redirection automatique lors de la première navigation
## Configuration recommandée
### Variables importantes :
- **SSID** : `HOKA_Clock` (peut être modifié dans `ap_ssid`)
- **Mot de passe** : `hoka` (peut être modifié dans `ap_password`)
- **IP** : `192.168.1.1` (définie dans `apIP`)
- **Clé d'accès** : `hoka` (définie dans `KEY_TXT`)
### Mode de fonctionnement :
- **Mode Station** (`useStationMode = true`) : Se connecte à un WiFi existant
- **Mode Point d'Accès** (`useStationMode = false`) : Crée un portail captif
## Avantages du portail captif
1. **Facilité d'accès** : Pas besoin de connaître l'adresse IP
2. **Expérience intuitive** : Ouverture automatique de l'interface
3. **Compatibilité universelle** : Fonctionne sur tous les appareils
4. **Configuration simple** : L'utilisateur est guidé automatiquement
## Compilation et déploiement
Pour compiler et déployer le projet avec le portail captif :
```bash
# Compilation
pio run -e main
# Upload vers l'ESP32
pio run -e main --target upload
# Monitoring série (optionnel)
pio device monitor
```
## Dépannage
### Problèmes courants :
1. **Le portail ne s'ouvre pas automatiquement**
- Vérifiez que le mode AP est activé (`useStationMode = false`)
- Testez l'accès direct via http://192.168.1.1
2. **Erreurs de compilation**
- Vérifiez que la dépendance `DNSServer` est bien ajoutée
- Assurez-vous d'utiliser l'environnement `main`
3. **Redirection en boucle**
- Vérifiez la fonction `handleCaptivePortal()`
- Testez avec différents navigateurs
## Notes de développement
- Le portail captif n'est actif qu'en mode Point d'Accès
- En mode Station, le comportement reste inchangé
- La gestion DNS ajoute une charge minime au processeur
- Compatible avec l'architecture FreeRTOS existante
-157
View File
@@ -1,157 +0,0 @@
# 🌐 Portail Captif ESP32 - Résumé des Modifications
## ✅ Modifications Terminées
Votre projet ESP32 P10 RGB Digital Clock a été modifié avec succès pour inclure un **portail captif** fonctionnel.
### 📋 Fichiers Modifiés
1. **`platformio.ini`**
- ✅ Ajout de la dépendance `DNSServer` à l'environnement `main`
- ✅ Ajout de l'environnement de test `captive_portal_test`
2. **`src/main.cpp`**
- ✅ Inclusion de la bibliothèque `#include <DNSServer.h>`
- ✅ Déclaration des objets `DNSServer dnsServer` et `IPAddress apIP`
- ✅ Modification de `set_ESP32_Access_Point()` pour démarrer le serveur DNS
- ✅ Ajout des fonctions `handleCaptivePortal()` et `handleNotFound()`
- ✅ Configuration des routes spéciales pour Android, iOS, Windows
- ✅ Intégration du traitement DNS dans `WebServerTask()`
3. **`.vscode/tasks.json`**
- ✅ Ajout de la tâche "PlatformIO: Test Captive Portal"
### 📁 Fichiers Créés
1. **`examples/captive_portal_test.cpp`**
- Test simplifié pour vérifier uniquement le portail captif
2. **`CAPTIVE_PORTAL_README.md`**
- Documentation complète des modifications
3. **`CAPTIVE_PORTAL_QUICK_TEST.md`**
- Guide de test rapide
## 🚀 Comment Utiliser le Portail Captif
### Mode de Fonctionnement
**Par défaut**, le projet est configuré en mode Point d'Accès avec portail captif :
- Variable `useStationMode = false` dans le code
- Création d'un réseau WiFi "HOKA_Clock"
- Redirection automatique de toutes les requêtes web
### Étapes pour Tester
1. **Compilez et téléversez** :
```bash
pio run -e main --target upload
```
2. **Connectez-vous au WiFi** :
- Nom : `HOKA_Clock`
- Mot de passe : `hoka`
3. **Testez la redirection** :
- Ouvrez un navigateur
- Essayez d'aller sur n'importe quel site
- Vous êtes automatiquement redirigé vers l'interface de l'horloge
## 🔧 Configuration Actuelle
```cpp
// WiFi Point d'Accès
const char* ap_ssid = "HOKA_Clock";
const char* ap_password = "hoka";
// IP du portail captif
const IPAddress apIP(192, 168, 1, 1);
// Clé d'accès interface web
#define KEY_TXT "hoka"
// Mode par défaut
bool useStationMode = false; // Portail captif activé
```
## 🌍 Compatibilité Universelle
Le portail captif fonctionne avec :
| Plateforme | Comportement |
|------------|--------------|
| **Android** | 📱 Notification automatique "Se connecter au réseau" |
| **iOS/iPadOS** | 🍎 Ouverture automatique du navigateur captif |
| **Windows** | 🪟 Redirection lors de la première navigation |
| **macOS** | 🖥️ Détection automatique du portail |
| **Linux** | 🐧 Redirection manuelle nécessaire |
## 🛠️ Tests Disponibles
### Test Principal (Horloge + Portail Captif)
```bash
pio run -e main --target upload
```
### Test Portail Captif Uniquement
```bash
pio run -e captive_portal_test --target upload
```
## 📊 Avantages du Portail Captif
✅ **Facilité d'accès** : Plus besoin de connaître l'IP
✅ **Expérience intuitive** : Ouverture automatique
✅ **Compatibilité universelle** : Tous appareils/OS
✅ **Configuration simple** : Guidage automatique
✅ **Professionnel** : Comme les hotspots WiFi publics
## 🔍 Surveillance et Debug
### Monitoring série
```bash
pio device monitor
```
### Messages de succès attendus
```
WIFI mode : AP avec Portail Captif
Serveur DNS démarré pour portail captif
HTTP server started
Captive Portal active - navigate to any website
```
## 🎯 Fonctionnement Technique
1. **DNS Hijacking** : Toutes les requêtes DNS → 192.168.1.1
2. **Route Interception** : Capture des URLs de détection OS
3. **Redirection HTTP** : Code 302 vers l'interface ESP32
4. **FreeRTOS Integration** : Traitement asynchrone DNS + HTTP
## 📝 Notes Importantes
- Le portail captif n'est actif qu'en mode Point d'Accès (`useStationMode = false`)
- En mode Station WiFi, le comportement reste inchangé
- La charge CPU additionnelle est négligeable
- Compatible avec l'architecture FreeRTOS existante
## 🚨 Dépannage Rapide
| Problème | Solution |
|----------|----------|
| Portail ne s'ouvre pas | Vérifier `useStationMode = false` |
| Redirection ne fonctionne pas | Tester http://192.168.1.1 directement |
| Erreur compilation | Vérifier dépendance `DNSServer` |
---
**🎉 Félicitations !** Votre horloge ESP32 dispose maintenant d'un portail captif professionnel avec **accès libre sans authentification**. Les utilisateurs seront automatiquement redirigés vers l'interface de configuration, rendant l'expérience beaucoup plus intuitive et moderne.
## 🔓 Mise à Jour : Accès Sans Authentification
**Nouvelle fonctionnalité :** La validation de clé a été supprimée pour simplifier l'accès.
-**Accès immédiat** à l'interface web
-**Pas de clé à saisir**
-**Configuration directe** via le portail captif
- ⚠️ **Sécurité :** Protection par mot de passe WiFi uniquement
-226
View File
@@ -1,226 +0,0 @@
# 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 !
-192
View File
@@ -1,192 +0,0 @@
# Guide du Countdown (Compte à Rebours)
## Vue d'ensemble
La fonctionnalité de countdown permet d'afficher un compte à rebours en temps réel vers une date et heure cible spécifique. Le countdown s'affiche dans la rotation du texte défilant et peut être configuré via l'interface web.
## Fonctionnalités
### ✅ Affichage Dynamique
- **Format adaptatif** : Affiche jours, heures, minutes et secondes selon le temps restant
- **Couleur personnalisable** : Couleur spécifique pour le countdown (orange par défaut)
- **Indication d'expiration** : Affichage "EXPIRED!" en rouge quand le countdown est fini
- **Compatible cascade** : Fonctionne avec tous les types de configuration de panneaux
### ✅ Configuration Complète
- **Activation/désactivation** : Checkbox pour activer ou désactiver le countdown
- **Titre personnalisé** : Nom de l'événement (ex: "NOUVEL AN", "ANNIVERSAIRE")
- **Date et heure cible** : Configuration précise de la cible
- **Couleur RGB** : Personnalisation de la couleur d'affichage
- **Sauvegarde** : Tous les paramètres sont sauvegardés en mémoire flash
## Configuration via Interface Web
### 1. Accès à l'Interface
1. Connectez-vous au WiFi de l'ESP32 ou configurez votre WiFi
2. Ouvrez l'adresse IP dans votre navigateur
3. Entrez la clé de sécurité : `p10rgbesp32ws`
### 2. Section Countdown Timer
La section "Countdown Timer" contient :
#### Activation
- **Checkbox "Active"** : Cochez pour activer le countdown
#### Configuration de l'Événement
- **Title** : Nom de l'événement (max 50 caractères)
- Exemples : "NEW YEAR", "BIRTHDAY", "WEDDING", "VACATION"
#### Date et Heure Cible
- **Target Date** : Jour, Mois, Année
- **Target Time** : Heure, Minute, Seconde (format 24h)
#### Couleur
- **RGB** : Valeurs Red, Green, Blue (0-255)
- Orange par défaut : R=255, G=165, B=0
- Rouge pour urgence : R=255, G=0, B=0
- Bleu pour célébration : R=0, G=100, B=255
### 3. Boutons d'Action
- **"Set Countdown"** : Sauvegarde la configuration complète
- **"Set Countdown Color"** : Sauvegarde uniquement la couleur
## Formats d'Affichage
Le countdown adapte automatiquement son format selon le temps restant :
### Avec Jours
```
NEW YEAR: 15d 08h 30m 45s
```
### Sans Jours (moins de 24h)
```
NEW YEAR: 08h 30m 45s
```
### Dernière Heure
```
NEW YEAR: 30m 45s
```
### Dernière Minute
```
NEW YEAR: 45s
```
### Expiré
```
NEW YEAR - EXPIRED!
```
## Intégration dans l'Affichage
Le countdown s'intègre dans la rotation du texte défilant :
### Mode 1 (Couleurs Fixes)
1. **Date** : Affichage de la date actuelle
2. **Texte personnalisé** : Votre message personnel
3. **Countdown** : Compte à rebours (si actif)
### Mode 2 (Couleurs Changeantes)
1. **Date** : Couleur 1
2. **Texte personnalisé** : Couleur 2
3. **Countdown** : Couleur 3 (si actif)
4. **Changement** : Rotation des couleurs
## Exemples d'Utilisation
### 1. Nouvel An
```
Title: NEW YEAR 2026
Date: 31/12/2025 23:59:59
Couleur: Rouge (255,0,0)
```
### 2. Anniversaire
```
Title: BIRTHDAY
Date: 15/06/2025 00:00:00
Couleur: Rose (255,105,180)
```
### 3. Événement Professionnel
```
Title: CONFERENCE
Date: 20/03/2025 09:00:00
Couleur: Bleu (0,100,255)
```
### 4. Vacances
```
Title: HOLIDAYS
Date: 01/07/2025 12:00:00
Couleur: Vert (0,255,100)
```
## Test et Développement
### Test du Countdown
Un exemple de test spécifique est disponible :
```bash
# Compiler et uploader le test countdown
pio run -e countdown_test --target upload
# Monitorer la sortie série
pio device monitor
```
Le test configure automatiquement un countdown de 5 minutes dans le futur et affiche :
- L'heure actuelle en haut
- Le countdown en défilement
- Changement de couleur à l'expiration
### VS Code
Utilisez la tâche : **"PlatformIO: Test Countdown"**
## Sauvegarde et Persistance
Tous les paramètres du countdown sont sauvegardés dans la mémoire flash NVS :
- `cd_Active` : État activé/désactivé
- `cd_Year`, `cd_Month`, `cd_Day` : Date cible
- `cd_Hour`, `cd_Minute`, `cd_Second` : Heure cible
- `cd_Title` : Titre de l'événement
- `CD_R`, `CD_G`, `CD_B` : Couleur RGB
Les paramètres persistent après redémarrage de l'ESP32.
## Dépannage
### Le countdown ne s'affiche pas
1. Vérifiez que la checkbox "Active" est cochée
2. Confirmez que tous les champs de date/heure sont remplis
3. Vérifiez que la date cible est dans le futur
### Problème de format
- Le countdown s'adapte automatiquement au temps restant
- Si le temps est négatif, "EXPIRED!" s'affiche
### Couleur incorrecte
- Vérifiez les valeurs RGB (0-255)
- En mode 2, les couleurs du countdown rotent automatiquement
### RTC non synchronisé
- Configurez d'abord la date/heure système via l'interface web
- Le countdown dépend du module RTC DS3231
## Intégration dans Votre Projet
Le countdown peut être facilement adapté pour d'autres usages :
1. **Minuteur** : Countdown de courte durée (minutes/heures)
2. **Événements multiples** : Modification pour gérer plusieurs countdowns
3. **Notifications** : Ajout de signaux visuels à l'expiration
4. **API externe** : Récupération de dates cibles depuis Internet
## Performance
- **Mise à jour** : Chaque seconde
- **Mémoire** : ~200 bytes pour les variables countdown
- **Cascade** : Compatible avec tous les formats de panneaux
- **Stabilité** : Pas d'impact sur les autres fonctionnalités
-148
View File
@@ -1,148 +0,0 @@
# 🔓 Suppression de la Validation de Clé - ESP32 Portail Captif
## ✅ Modification Effectuée
La validation de clé d'accès au serveur web a été **supprimée** pour permettre un **accès libre** à l'interface de configuration de l'horloge.
## 🔧 Changements Appliqués
### 1. Suppression de la Validation dans `handleSettings()`
**Avant :**
```cpp
void handleSettings() {
String incoming_Settings = server.arg("key");
if (incoming_Settings != KEY_TXT) {
server.send(200, "text/plain", "+ERR");
Serial.println("Wrong key!");
return;
}
// ... suite du code
}
```
**Après :**
```cpp
void handleSettings() {
String incoming_Settings = server.arg("key");
Serial.println("\n-------------Settings");
Serial.print("Key : ");
Serial.println(incoming_Settings);
// Validation de clé supprimée - accès libre
incoming_Settings = server.arg("sta");
// ... suite du code
}
```
### 2. Modification du Message de Démarrage
**Avant :**
```cpp
Serial.println("Use key: " KEY_TXT);
```
**Après :**
```cpp
Serial.println("No authentication required - Open access");
```
## 🌐 Impact sur l'Interface Web
### ✅ Avantages
1. **Accès immédiat** : Plus besoin de saisir une clé
2. **Expérience simplifiée** : Interface directement accessible
3. **Portail captif optimisé** : Redirection sans barrière d'authentification
4. **Facilité d'utilisation** : Idéal pour usage personnel ou familial
### ⚠️ Considérations de Sécurité
- **Réseau ouvert** : Toute personne connectée au WiFi peut modifier les paramètres
- **Usage recommandé** : Environnements privés ou de confiance
- **Protection par WiFi** : La sécurité repose sur le mot de passe WiFi "hoka"
## 🎯 Fonctionnement Actuel
### 1. Connexion au Portail Captif
1. **Connexion WiFi** : "HOKA_Clock" (mot de passe : "hoka")
2. **Redirection automatique** vers l'interface
3. **Accès immédiat** aux paramètres sans authentification
### 2. Configuration Accessible
-**Réglage de l'heure et date**
-**Modification des couleurs**
-**Configuration du texte défilant**
-**Paramètres de luminosité**
-**Configuration du countdown**
## 📊 Résultats de Compilation
```
✅ SUCCESS - Compilation réussie
RAM: [= ] 14.3% (used 46824 bytes from 327680 bytes)
Flash: [====== ] 63.7% (used 834905 bytes from 1310720 bytes)
Taille: -56 bytes (optimisation due à la suppression du code de validation)
```
## 🔄 Comment Réactiver la Validation (si nécessaire)
Si vous souhaitez remettre la validation de clé, ajoutez ces lignes dans `handleSettings()` :
```cpp
void handleSettings() {
String incoming_Settings = server.arg("key");
Serial.println("\n-------------Settings");
Serial.print("Key : ");
Serial.println(incoming_Settings);
// Réactiver la validation
if (incoming_Settings != KEY_TXT) {
server.send(200, "text/plain", "+ERR");
Serial.println("Wrong key!");
Serial.println("-------------");
return;
}
incoming_Settings = server.arg("sta");
// ... reste du code
}
```
## 🌟 Interface Web Simplifiée
L'interface web fonctionne maintenant comme suit :
1. **Page principale** : Accessible immédiatement via le portail captif
2. **Paramètres** : Modification directe sans authentification
3. **Retour instantané** : Réponse "+OK" pour toutes les modifications valides
## 🎉 Avantages du Portail Captif sans Authentification
### Pour l'Utilisateur
- **Simplicité maximale** : Connexion → Configuration
- **Pas de mot de passe à retenir** (autre que le WiFi)
- **Expérience fluide** sur tous les appareils
### Pour l'Administrateur
- **Moins de support** : Pas de problème de clé oubliée
- **Configuration rapide** : Idéal pour démonstrations
- **Accès d'urgence** : Modification rapide des paramètres
## 🚀 Prêt à Utiliser
Le système est maintenant configuré pour un **accès libre** via le portail captif :
1. **Compilez et téléversez** le firmware
2. **Connectez-vous** au WiFi "HOKA_Clock"
3. **Naviguez** vers n'importe quel site → redirection automatique
4. **Configurez** l'horloge directement sans authentification
---
**Date de modification :** 15 août 2025
**Status :** ✅ Implémenté et testé
**Sécurité :** Protection par mot de passe WiFi uniquement
-103
View File
@@ -1,103 +0,0 @@
# 🔧 Résolution du Problème de Compilation
## ✅ Problème Résolu
**Erreur initiale :**
```
src/main.cpp: In function 'void handleCaptivePortal()':
src/main.cpp:429:5: error: 'handleRoot' was not declared in this scope
handleRoot();
^~~~~~~~~~
```
## 🎯 Cause du Problème
Le problème était un **ordre de déclaration des fonctions**. La fonction `handleCaptivePortal()` était déclarée avant `handleRoot()`, mais tentait d'appeler cette dernière.
En C++, les fonctions doivent être déclarées avant d'être utilisées.
## 🛠️ Solution Appliquée
**Ajout de déclarations anticipées** dans `src/main.cpp` après les includes :
```cpp
// Prototypes des tâches FreeRTOS
void DisplayTask(void *pvParameters);
void WebServerTask(void *pvParameters);
void WiFiTask(void *pvParameters);
// Prototypes des gestionnaires web ← AJOUTÉ
void handleRoot(); AJOUTÉ
void handleSettings(); AJOUTÉ
void handleCaptivePortal(); AJOUTÉ
void handleNotFound(); AJOUTÉ
```
## ✅ Résultats de Compilation
### Projet Principal (main)
```
✅ SUCCESS - Compilation réussie
RAM: [= ] 14.3% (used 46824 bytes from 327680 bytes)
Flash: [====== ] 63.7% (used 834961 bytes from 1310720 bytes)
```
### Test Portail Captif (captive_portal_test)
```
✅ SUCCESS - Compilation réussie
RAM: [= ] 13.9% (used 45464 bytes from 327680 bytes)
Flash: [====== ] 58.1% (used 762045 bytes from 1310720 bytes)
```
## 🚀 État Actuel
-**Portail captif** : Intégré et fonctionnel
-**Compilation** : Aucune erreur
-**Tests** : Deux environnements disponibles
-**Documentation** : Complète
## 📋 Commandes de Compilation
```bash
# Projet principal avec portail captif
pio run -e main
# Test portail captif uniquement
pio run -e captive_portal_test
# Upload vers ESP32
pio run -e main --target upload
```
## 🎯 Fonctionnalités Ajoutées
1. **Serveur DNS** : Redirige toutes les requêtes vers l'ESP32
2. **Routes spéciales** : Support Android, iOS, Windows, macOS
3. **Redirection automatique** : Portail captif universel
4. **Compatibilité FreeRTOS** : Intégration parfaite
## 🔍 Améliorations Appliquées
- **Déclarations de fonctions** : Ordre correct
- **Page HTML test** : Caractères échappés correctement
- **Dépendances** : DNSServer ajouté
- **Configuration** : Variables IP et DNS
## 🎉 Prêt à Tester !
Le projet est maintenant prêt pour :
1. **Compilation** sans erreurs
2. **Téléversement** vers l'ESP32
3. **Test du portail captif** en conditions réelles
### Instructions de Test
1. Compilez et téléversez : `pio run -e main --target upload`
2. Connectez-vous au WiFi : "HOKA_Clock" (mot de passe: "hoka")
3. Naviguez vers n'importe quel site → Redirection automatique !
---
**Date de résolution :** 15 août 2025
**Status :** ✅ Résolu et testé
**Prochaine étape :** Test matériel sur ESP32
-174
View File
@@ -1,174 +0,0 @@
# Guide de Démarrage Rapide - ESP32 P10 Digital Cl2. **Test du RTC** :
```bash
pio run -e rtc_test --target upload
```
3. **Test du countdown** :
```bash
pio run -e countdown_test --target upload
```
### Étape 5 : Upload principal# 🚀 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
- **⏱️ Countdown** : Compte à rebours vers un événement
## 💡 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
- [ ] Countdown configuré et actif
- [ ] 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, texte et countdown** défilant en bas
- **Couleurs** selon le mode choisi
- **Configuration** via navigateur web
**⏱️ Exemple de countdown :**
```
NOUVEL AN: 25d 08h 30m 45s
```
Clé d'accès web : **p10rgbesp32ws**
-136
View File
@@ -1,136 +0,0 @@
# ✅ Vérification du Code Serveur Web - ESP32 Portail Captif
## 🔍 Vérification Effectuée
J'ai vérifié et analysé l'ensemble du code du serveur web pour m'assurer de la cohérence avec la suppression de l'authentification.
## 📊 Résultats de la Vérification
### ✅ Côté Serveur (main.cpp) - CONFORME
**Statut :** Correctement modifié pour l'accès libre
1. **`handleSettings()`** ✅
- Validation de clé supprimée
- Accès direct aux paramètres
- Toutes les fonctions de configuration accessibles
2. **Messages de démarrage**
- "No authentication required - Open access"
- Documentation claire du mode sans authentification
3. **Portail captif**
- Fonctionnel avec `handleCaptivePortal()`
- Redirection automatique vers l'interface
- Routes spéciales pour tous les OS
### ⚠️ Côté Interface HTML (PageIndex.h) - PARTIELLEMENT CONFORME
**Statut :** L'interface HTML conserve encore les champs de clé
**Problèmes identifiés :**
- Champ de saisie de clé toujours présent
- Fonctions JavaScript vérifient encore la clé
- Messages d'erreur pour clé manquante
**Impact :**
-**Fonctionnel** : Le serveur accepte les requêtes sans clé
- ⚠️ **UX** : L'utilisateur peut saisir n'importe quelle valeur dans le champ clé
-**Sécurité** : Pas de validation côté serveur
## 🎯 Comportement Actuel du Système
### Scénario de Test
1. **L'utilisateur se connecte** au portail captif
2. **Redirigé automatiquement** vers l'interface
3. **Voit le champ "Key"** (mais peut saisir n'importe quoi)
4. **Peut configurer l'horloge** quelle que soit la valeur saisie
### ✅ Avantages de la Configuration Actuelle
1. **Compatibilité** : Interface existante fonctionne
2. **Simplicité côté serveur** : Pas de vérification
3. **Sécurité** : Protection uniquement par WiFi
4. **Flexibilité** : L'utilisateur peut ignorer ou remplir le champ
## 🔧 Options de Finalisation
### Option 1 : Interface Simplifiée (Recommandé)
Supprimer complètement les références à la clé dans l'interface HTML.
**Avantages :**
- Interface plus claire
- Pas de confusion pour l'utilisateur
- Cohérence complète avec le serveur
### Option 2 : Conserver l'Interface Actuelle (Actuel)
Garder l'interface avec le champ clé non fonctionnel.
**Avantages :**
- Pas de modification d'interface nécessaire
- Fonctionne déjà parfaitement
- Prêt pour réactivation future de l'authentification
### Option 3 : Masquer le Champ Clé
Masquer visuellement le champ mais conserver le code.
## 📋 Compilation et Tests
### ✅ Résultats de Compilation
```
Environment Status Duration
------------- -------- ------------
main SUCCESS 00:00:02.932
RAM: 14.3% (46824 bytes / 327680 bytes)
Flash: 63.6% (834057 bytes / 1310720 bytes)
```
### 🧪 Tests Recommandés
1. **Test du portail captif**
- Connexion WiFi "HOKA_Clock"
- Redirection automatique
- Accès à l'interface
2. **Test de configuration**
- Modification des paramètres sans clé
- Vérification des changements
- Redémarrage système
3. **Test cross-platform**
- Android, iOS, Windows, macOS
- Différents navigateurs
## 🎉 Conclusion de la Vérification
### ✅ Points Positifs
1. **Serveur web** parfaitement configuré pour l'accès libre
2. **Portail captif** fonctionnel et compatible
3. **Compilation** sans erreur
4. **Architecture** robuste et extensible
### 📝 Recommandations
1. **L'état actuel est fonctionnel** et peut être utilisé tel quel
2. **Optionnel** : Nettoyer l'interface HTML pour plus de clarté
3. **Priorité** : Tester en conditions réelles sur ESP32
## 🚀 Prêt pour le Déploiement
Le code du serveur web a été vérifié et est **prêt pour le déploiement** :
- ✅ Suppression de l'authentification côté serveur
- ✅ Portail captif fonctionnel
- ✅ Interface web accessible
- ✅ Compilation réussie
- ✅ Compatibilité universelle
---
**Date de vérification :** 15 août 2025
**Status :** ✅ Vérifié et validé
**Prochaine étape :** Test sur matériel ESP32
-214
View File
@@ -1,214 +0,0 @@
# 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 |
File diff suppressed because it is too large Load Diff
-601
View File
@@ -1,601 +0,0 @@
#ifndef PAGE_INDEX_H
#define PAGE_INDEX_H
#include <Arduino.h>
const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<title>Digital Clock, Countdown & Scrolling Text with ESP32 and P10 RGB 32x16</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html {font-family: Helvetica, sans-serif;}
h1 {font-size: 1.1rem; color:#1976D2;}
label {font-size: 14px;}
.div_Form {
margin: auto;
wi function setScrollingSpeed() {
var msg = "sta=setScrollingSpeed";
msg += "&input_ScrollingSpeed=" + document.getElementById("input_ScrollingSpeed").value;
sendCommandToESP32("set", msg);
} border:1px solid #D8D8D8;
border-radius: 10px;
background-color: #f2f2f2;
padding: 9px 9px;
}
.myButton {
display: inline-block;
padding: 3px 25px;
font-size: 13px;
cursor: pointer;
text-align: center;
text-decoration: none;
outline: none;
color: #fff;
background-color: #1976D2;
border: none;
border-radius: 8px;
box-shadow: 0 2px #999;
}
.myButton:hover {background-color: #104d89}
.myButton:active {background-color: #104d89; box-shadow: 0 1px #666; transform: translateY(2px);}
.myButton:disabled {background-color: #666; box-shadow: 0 1px #666; transform: translateY(2px);}
.myButtonX {background-color: #ff0000}
.myButtonX:hover {background-color: #7a0101}
.div_Form_Input {display: table; margin: 0px; padding: 0px; box-sizing: border-box;}
.div_Input_Text {display: table-cell; width: 100%;}
.div_Input_Text > input {width:99.5%; margin-left: 0px; padding-left: 2px; box-sizing: border-box;}
table, th, td {
border: 0px solid black;
border-collapse: collapse;
font-size: 14px;
}
.div_Logs {
width: 100%;
height: 150px;
border: 1px solid #D8D8D8;
border-radius: 5px;
background-color: #ffffff;
overflow-y: scroll;
font-family: 'Courier New', monospace;
font-size: 12px;
padding: 5px;
box-sizing: border-box;
}
</style>
<body>
<div style="margin: 10px">
<h1>Digital Clock, Countdown & Scrolling Text with ESP32 and P10 RGB 32x16</h1>
<div class="div_Form">
<div style="margin-bottom: 10px;">
<button class="myButton" onclick="getSettings()">Get Settings</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>Set Date & Time</h3>
<table style="width:100%">
<tr>
<td style="width:25%"><label>Year : </label></td>
<td style="width:75%">
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="d_Year" min="2020" max="2099" value="2024">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Month : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="d_Month" min="1" max="12" value="1">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Day : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="d_Day" min="1" max="31" value="1">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Hour : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="t_Hour" min="0" max="23" value="12">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Minute : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="t_Minute" min="0" max="59" value="0">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Second : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="t_Second" min="0" max="59" value="0">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setTimeDate()">Set Date & Time</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>Display Settings</h3>
<table style="width:100%">
<tr>
<td style="width:25%"><label>Display Mode : </label></td>
<td style="width:75%">
<select id="input_Display_Mode" style="width:100%">
<option value="1">Mode 1 (Manual Colors)</option>
<option value="2">Mode 2 (Auto Color Change)</option>
</select>
</td>
</tr>
<tr>
<td><label>Brightness : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="input_Brightness" min="0" max="255" value="125">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Scroll Speed : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="input_Scrolling_Speed" min="10" max="100" value="45">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setDisplayMode()">Set Display Mode</button>
<button class="myButton" onclick="setBrightness()">Set Brightness</button>
<button class="myButton" onclick="setScrollingSpeed()">Set Scroll Speed</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>Color Settings (Mode 1 Only)</h3>
<table style="width:100%">
<tr>
<td colspan="2"><label><strong>Clock Color (RGB)</strong></label></td>
</tr>
<tr>
<td style="width:10%"><label>R : </label></td>
<td style="width:90%">
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Clock_R" min="0" max="255" value="255">
</div>
</div>
</td>
</tr>
<tr>
<td><label>G : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Clock_G" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
<tr>
<td><label>B : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Clock_B" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setColorClock()">Set Clock Color</button>
</div>
<br>
<table style="width:100%">
<tr>
<td colspan="2"><label><strong>Date Color (RGB)</strong></label></td>
</tr>
<tr>
<td style="width:10%"><label>R : </label></td>
<td style="width:90%">
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Date_R" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
<tr>
<td><label>G : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Date_G" min="0" max="255" value="255">
</div>
</div>
</td>
</tr>
<tr>
<td><label>B : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Date_B" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setColorDate()">Set Date Color</button>
</div>
<br>
<table style="width:100%">
<tr>
<td colspan="2"><label><strong>Text Color (RGB)</strong></label></td>
</tr>
<tr>
<td style="width:10%"><label>R : </label></td>
<td style="width:90%">
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Text_R" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
<tr>
<td><label>G : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Text_G" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
<tr>
<td><label>B : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Text_B" min="0" max="255" value="255">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setColorText()">Set Text Color</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>Scrolling Text</h3>
<table style="width:100%">
<tr>
<td><label>Text : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="text" id="input_Scrolling_Text" maxlength="150" placeholder="Enter scrolling text">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setScrollingText()">Set Scrolling Text</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>Countdown Timer</h3>
<table style="width:100%">
<tr>
<td style="width:25%"><label>Active : </label></td>
<td style="width:75%">
<input type="checkbox" id="countdown_Active" style="transform: scale(1.2);">
</td>
</tr>
<tr>
<td><label>Title : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="text" id="countdown_Title" maxlength="50" placeholder="Event title (e.g., NEW YEAR)">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Target Date : </label></td>
<td>
<div style="display: flex; gap: 5px;">
<input type="number" id="countdown_Day" min="1" max="31" style="width:20%;" placeholder="Day">
<input type="number" id="countdown_Month" min="1" max="12" style="width:20%;" placeholder="Month">
<input type="number" id="countdown_Year" min="2024" max="2099" style="width:25%;" placeholder="Year">
</div>
</td>
</tr>
<tr>
<td><label>Target Time : </label></td>
<td>
<div style="display: flex; gap: 5px;">
<input type="number" id="countdown_Hour" min="0" max="23" style="width:20%;" placeholder="Hour">
<input type="number" id="countdown_Minute" min="0" max="59" style="width:20%;" placeholder="Min">
<input type="number" id="countdown_Second" min="0" max="59" style="width:20%;" placeholder="Sec">
</div>
</td>
</tr>
<tr>
<td colspan="2"><label>Countdown Color (RGB) : </label></td>
</tr>
<tr>
<td style="width:10%"><label>R : </label></td>
<td style="width:90%">
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Countdown_R" min="0" max="255" value="255">
</div>
</div>
</td>
</tr>
<tr>
<td><label>G : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Countdown_G" min="0" max="255" value="165">
</div>
</div>
</td>
</tr>
<tr>
<td><label>B : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Countdown_B" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setCountdown()">Set Countdown</button>
<button class="myButton" onclick="setColorCountdown()">Set Countdown Color</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>System</h3>
<button class="myButton myButtonX" onclick="resetSystem()">Reset System</button>
</div>
</div>
<script>
//________________________________________________________________________________ sendCommandToESP32()
function sendCommandToESP32(sta, msg) {
var xmlhttp;
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
if (this.responseText == "+ERR") {
alert("Error !\\rWrong Key !\\rPlease enter the correct key.");
return;
}
if (this.responseText == "+ERR_DM") {
alert("Error !\\rThis setting is only for Display Mode : 1. \\rPlease change the Display Mode to apply this setting.");
return;
}
if (sta == "get") {
apply_the_Received_Settings(this.responseText);
} else {
alert("Settings applied successfully!");
}
}
}
xmlhttp.open("GET", "settings?" + msg, true);
xmlhttp.send();
}
//________________________________________________________________________________
function getSettings() {
sendCommandToESP32("get", "sta=get");
}
function setTimeDate() {
var msg = "sta=setTimeDate";
msg += "&d_Year=" + document.getElementById("d_Year").value;
msg += "&d_Month=" + document.getElementById("d_Month").value;
msg += "&d_Day=" + document.getElementById("d_Day").value;
msg += "&t_Hour=" + document.getElementById("t_Hour").value;
msg += "&t_Minute=" + document.getElementById("t_Minute").value;
msg += "&t_Second=" + document.getElementById("t_Second").value;
sendCommandToESP32("set", msg);
}
function setDisplayMode() {
var msg = "sta=setDisplayMode";
msg += "&input_Display_Mode=" + document.getElementById("input_Display_Mode").value;
sendCommandToESP32("set", msg);
}
function setBrightness() {
var msg = "sta=setBrightness";
msg += "&input_Brightness=" + document.getElementById("input_Brightness").value;
sendCommandToESP32("set", msg);
}
function setScrollingSpeed() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
var msg = "key=" + key + "&sta=setScrollingSpeed";
msg += "&input_Scrolling_Speed=" + document.getElementById("input_Scrolling_Speed").value;
sendCommandToESP32("set", msg);
}
function setColorClock() {
var msg = "sta=setColorClock";
msg += "&input_ColorClock=" + document.getElementById("input_ColorClock").value;
sendCommandToESP32("set", msg);
}
function setColorDate() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
var msg = "key=" + key + "&sta=setColorDate";
msg += "&Color_Date_R=" + document.getElementById("Color_Date_R").value;
msg += "&Color_Date_G=" + document.getElementById("Color_Date_G").value;
msg += "&Color_Date_B=" + document.getElementById("Color_Date_B").value;
sendCommandToESP32("set", msg);
}
function setColorText() {
var msg = "sta=setColorText";
msg += "&Color_Text_R=" + document.getElementById("Color_Text_R").value;
msg += "&Color_Text_G=" + document.getElementById("Color_Text_G").value;
msg += "&Color_Text_B=" + document.getElementById("Color_Text_B").value;
sendCommandToESP32("set", msg);
}
function setScrollingText() {
var msg = "sta=setScrollingText";
msg += "&input_Scrolling_Text=" + encodeURIComponent(document.getElementById("input_Scrolling_Text").value);
sendCommandToESP32("set", msg);
}
function setCountdown() {
// Validation des champs
var day = document.getElementById("countdown_Day").value;
var month = document.getElementById("countdown_Month").value;
var year = document.getElementById("countdown_Year").value;
var hour = document.getElementById("countdown_Hour").value;
var minute = document.getElementById("countdown_Minute").value;
var second = document.getElementById("countdown_Second").value;
var title = document.getElementById("countdown_Title").value;
if (!day || !month || !year || hour === "" || minute === "" || second === "" || !title) {
alert("Please fill all countdown fields!");
return;
}
// Validation des valeurs
if (day < 1 || day > 31 || month < 1 || month > 12 || year < 2024 || year > 2099) {
alert("Please enter valid date values!");
return;
}
if (hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
alert("Please enter valid time values!");
return;
}
var msg = "sta=setCountdown";
msg += "&countdown_Active=" + document.getElementById("countdown_Active").checked;
msg += "&countdown_Day=" + day;
msg += "&countdown_Month=" + month;
msg += "&countdown_Year=" + year;
msg += "&countdown_Hour=" + hour;
msg += "&countdown_Minute=" + minute;
msg += "&countdown_Second=" + second;
msg += "&countdown_Title=" + encodeURIComponent(title);
sendCommandToESP32("set", msg);
}
function setColorCountdown() {
var msg = "sta=setColorCountdown";
msg += "&Color_Countdown_R=" + document.getElementById("Color_Countdown_R").value;
msg += "&Color_Countdown_G=" + document.getElementById("Color_Countdown_G").value;
msg += "&Color_Countdown_B=" + document.getElementById("Color_Countdown_B").value;
sendCommandToESP32("set", msg);
}
function resetSystem() {
if (confirm("Are you sure you want to reset the system?")) {
var msg = "sta=resetSystem";
sendCommandToESP32("set", msg);
}
}
function apply_the_Received_Settings(receivedSettings) {
// Fonction pour appliquer les paramètres reçus
console.log("Settings received:", receivedSettings);
// Ici vous pouvez analyser la réponse et remplir les champs du formulaire
}
</script>
</body>
</html>
)=====";
#endif // PAGE_INDEX_H
-636
View File
@@ -1,636 +0,0 @@
#ifndef PAGE_INDEX_H
#define PAGE_INDEX_H
#include <Arduino.h>
const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<title>Digital Clock, Countdown & Scrolling Text with ESP32 and P10 RGB 32x16</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html {font-family: Helvetica, sans-serif;}
h1 {font-size: 1.1rem; color:#1976D2;}
label {font-size: 14px;}
.div_Form {
margin: auto;
width: 90%;
border:1px solid #D8D8D8;
border-radius: 10px;
background-color: #f2f2f2;
padding: 9px 9px;
}
.myButton {
display: inline-block;
padding: 3px 25px;
font-size: 13px;
cursor: pointer;
text-align: center;
text-decoration: none;
outline: none;
color: #fff;
background-color: #1976D2;
border: none;
border-radius: 8px;
box-shadow: 0 2px #999;
}
.myButton:hover {background-color: #104d89}
.myButton:active {background-color: #104d89; box-shadow: 0 1px #666; transform: translateY(2px);}
.myButton:disabled {background-color: #666; box-shadow: 0 1px #666; transform: translateY(2px);}
.myButtonX {background-color: #ff0000}
.myButtonX:hover {background-color: #7a0101}
.div_Form_Input {display: table; margin: 0px; padding: 0px; box-sizing: border-box;}
.div_Input_Text {display: table-cell; width: 100%;}
.div_Input_Text > input {width:99.5%; margin-left: 0px; padding-left: 2px; box-sizing: border-box;}
table, th, td {
border: 0px solid black;
border-collapse: collapse;
font-size: 14px;
}
.div_Logs {
width: 100%;
height: 150px;
border: 1px solid #D8D8D8;
border-radius: 5px;
background-color: #ffffff;
overflow-y: scroll;
font-family: 'Courier New', monospace;
font-size: 12px;
padding: 5px;
box-sizing: border-box;
}
</style>
<body>
<div style="margin: 10px">
<h1>Digital Clock, Countdown & Scrolling Text with ESP32 and P10 RGB 32x16</h1>
<div class="div_Form">
<div style="margin-bottom: 10px;">
<button class="myButton" onclick="getSettings()">Get Settings</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>Set Date & Time</h3>
<table style="width:100%">
<tr>
<td style="width:25%"><label>Year : </label></td>
<td style="width:75%">
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="d_Year" min="2020" max="2099" value="2024">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Month : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="d_Month" min="1" max="12" value="1">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Day : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="d_Day" min="1" max="31" value="1">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Hour : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="t_Hour" min="0" max="23" value="12">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Minute : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="t_Minute" min="0" max="59" value="0">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Second : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="t_Second" min="0" max="59" value="0">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setTimeDate()">Set Date & Time</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>Display Settings</h3>
<table style="width:100%">
<tr>
<td style="width:25%"><label>Display Mode : </label></td>
<td style="width:75%">
<select id="input_Display_Mode" style="width:100%">
<option value="1">Mode 1 (Manual Colors)</option>
<option value="2">Mode 2 (Auto Color Change)</option>
</select>
</td>
</tr>
<tr>
<td><label>Brightness : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="input_Brightness" min="0" max="255" value="125">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Scroll Speed : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="input_Scrolling_Speed" min="10" max="100" value="45">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setDisplayMode()">Set Display Mode</button>
<button class="myButton" onclick="setBrightness()">Set Brightness</button>
<button class="myButton" onclick="setScrollingSpeed()">Set Scroll Speed</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>Color Settings (Mode 1 Only)</h3>
<table style="width:100%">
<tr>
<td colspan="2"><label><strong>Clock Color (RGB)</strong></label></td>
</tr>
<tr>
<td style="width:10%"><label>R : </label></td>
<td style="width:90%">
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Clock_R" min="0" max="255" value="255">
</div>
</div>
</td>
</tr>
<tr>
<td><label>G : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Clock_G" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
<tr>
<td><label>B : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Clock_B" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setColorClock()">Set Clock Color</button>
</div>
<br>
<table style="width:100%">
<tr>
<td colspan="2"><label><strong>Date Color (RGB)</strong></label></td>
</tr>
<tr>
<td style="width:10%"><label>R : </label></td>
<td style="width:90%">
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Date_R" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
<tr>
<td><label>G : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Date_G" min="0" max="255" value="255">
</div>
</div>
</td>
</tr>
<tr>
<td><label>B : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Date_B" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setColorDate()">Set Date Color</button>
</div>
<br>
<table style="width:100%">
<tr>
<td colspan="2"><label><strong>Text Color (RGB)</strong></label></td>
</tr>
<tr>
<td style="width:10%"><label>R : </label></td>
<td style="width:90%">
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Text_R" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
<tr>
<td><label>G : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Text_G" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
<tr>
<td><label>B : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Text_B" min="0" max="255" value="255">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setColorText()">Set Text Color</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>Scrolling Text</h3>
<table style="width:100%">
<tr>
<td><label>Text : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="text" id="input_Scrolling_Text" maxlength="150" placeholder="Enter scrolling text">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setScrollingText()">Set Scrolling Text</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>Countdown Timer</h3>
<table style="width:100%">
<tr>
<td style="width:25%"><label>Active : </label></td>
<td style="width:75%">
<input type="checkbox" id="countdown_Active" style="transform: scale(1.2);">
</td>
</tr>
<tr>
<td><label>Title : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="text" id="countdown_Title" maxlength="50" placeholder="Event title (e.g., NEW YEAR)">
</div>
</div>
</td>
</tr>
<tr>
<td><label>Target Date : </label></td>
<td>
<div style="display: flex; gap: 5px;">
<input type="number" id="countdown_Day" min="1" max="31" style="width:20%;" placeholder="Day">
<input type="number" id="countdown_Month" min="1" max="12" style="width:20%;" placeholder="Month">
<input type="number" id="countdown_Year" min="2024" max="2099" style="width:25%;" placeholder="Year">
</div>
</td>
</tr>
<tr>
<td><label>Target Time : </label></td>
<td>
<div style="display: flex; gap: 5px;">
<input type="number" id="countdown_Hour" min="0" max="23" style="width:20%;" placeholder="Hour">
<input type="number" id="countdown_Minute" min="0" max="59" style="width:20%;" placeholder="Min">
<input type="number" id="countdown_Second" min="0" max="59" style="width:20%;" placeholder="Sec">
</div>
</td>
</tr>
<tr>
<td colspan="2"><label>Countdown Color (RGB) : </label></td>
</tr>
<tr>
<td style="width:10%"><label>R : </label></td>
<td style="width:90%">
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Countdown_R" min="0" max="255" value="255">
</div>
</div>
</td>
</tr>
<tr>
<td><label>G : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Countdown_G" min="0" max="255" value="165">
</div>
</div>
</td>
</tr>
<tr>
<td><label>B : </label></td>
<td>
<div class="div_Form_Input">
<div class="div_Input_Text">
<input type="number" id="Color_Countdown_B" min="0" max="255" value="0">
</div>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;">
<button class="myButton" onclick="setCountdown()">Set Countdown</button>
<button class="myButton" onclick="setColorCountdown()">Set Countdown Color</button>
</div>
</div>
<br>
<div class="div_Form">
<h3>System</h3>
<button class="myButton myButtonX" onclick="resetSystem()">Reset System</button>
</div>
</div>
<script>
//________________________________________________________________________________ sendCommandToESP32()
function sendCommandToESP32(sta, msg) {
var xmlhttp;
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
if (this.responseText == "+ERR") {
alert("Error !\\rWrong Key !\\rPlease enter the correct key.");
return;
}
if (this.responseText == "+ERR_DM") {
alert("Error !\\rThis setting is only for Display Mode : 1. \\rPlease change the Display Mode to apply this setting.");
return;
}
if (sta == "get") {
apply_the_Received_Settings(this.responseText);
} else {
alert("Settings applied successfully!");
}
}
}
xmlhttp.open("GET", "settings?" + msg, true);
xmlhttp.send();
}
//________________________________________________________________________________
function getSettings() {
sendCommandToESP32("get", "sta=get");
}
function setTimeDate() {
var msg = "sta=setTimeDate";
msg += "&d_Year=" + document.getElementById("d_Year").value;
msg += "&d_Month=" + document.getElementById("d_Month").value;
msg += "&d_Day=" + document.getElementById("d_Day").value;
msg += "&t_Hour=" + document.getElementById("t_Hour").value;
msg += "&t_Minute=" + document.getElementById("t_Minute").value;
msg += "&t_Second=" + document.getElementById("t_Second").value;
sendCommandToESP32("set", msg);
}
function setDisplayMode() {
var msg = "sta=setDisplayMode";
msg += "&input_Display_Mode=" + document.getElementById("input_Display_Mode").value;
sendCommandToESP32("set", msg);
}
function setBrightness() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
var msg = "key=" + key + "&sta=setBrightness";
msg += "&input_Brightness=" + document.getElementById("input_Brightness").value;
sendCommandToESP32("set", msg);
}
function setScrollingSpeed() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
var msg = "key=" + key + "&sta=setScrollingSpeed";
msg += "&input_Scrolling_Speed=" + document.getElementById("input_Scrolling_Speed").value;
sendCommandToESP32("set", msg);
}
function setColorClock() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
var msg = "key=" + key + "&sta=setColorClock";
msg += "&Color_Clock_R=" + document.getElementById("Color_Clock_R").value;
msg += "&Color_Clock_G=" + document.getElementById("Color_Clock_G").value;
msg += "&Color_Clock_B=" + document.getElementById("Color_Clock_B").value;
sendCommandToESP32("set", msg);
}
function setColorDate() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
var msg = "key=" + key + "&sta=setColorDate";
msg += "&Color_Date_R=" + document.getElementById("Color_Date_R").value;
msg += "&Color_Date_G=" + document.getElementById("Color_Date_G").value;
msg += "&Color_Date_B=" + document.getElementById("Color_Date_B").value;
sendCommandToESP32("set", msg);
}
function setColorText() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
var msg = "key=" + key + "&sta=setColorText";
msg += "&Color_Text_R=" + document.getElementById("Color_Text_R").value;
msg += "&Color_Text_G=" + document.getElementById("Color_Text_G").value;
msg += "&Color_Text_B=" + document.getElementById("Color_Text_B").value;
sendCommandToESP32("set", msg);
}
function setScrollingText() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
var msg = "key=" + key + "&sta=setScrollingText";
msg += "&input_Scrolling_Text=" + encodeURIComponent(document.getElementById("input_Scrolling_Text").value);
sendCommandToESP32("set", msg);
}
function setCountdown() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
// Validation des champs
var day = document.getElementById("countdown_Day").value;
var month = document.getElementById("countdown_Month").value;
var year = document.getElementById("countdown_Year").value;
var hour = document.getElementById("countdown_Hour").value;
var minute = document.getElementById("countdown_Minute").value;
var second = document.getElementById("countdown_Second").value;
var title = document.getElementById("countdown_Title").value;
if (!day || !month || !year || hour === "" || minute === "" || second === "" || !title) {
alert("Please fill all countdown fields!");
return;
}
// Validation des valeurs
if (day < 1 || day > 31 || month < 1 || month > 12 || year < 2024 || year > 2099) {
alert("Please enter valid date values!");
return;
}
if (hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
alert("Please enter valid time values!");
return;
}
var msg = "key=" + key + "&sta=setCountdown";
msg += "&countdown_Active=" + document.getElementById("countdown_Active").checked;
msg += "&countdown_Day=" + day;
msg += "&countdown_Month=" + month;
msg += "&countdown_Year=" + year;
msg += "&countdown_Hour=" + hour;
msg += "&countdown_Minute=" + minute;
msg += "&countdown_Second=" + second;
msg += "&countdown_Title=" + encodeURIComponent(title);
sendCommandToESP32("set", msg);
}
function setColorCountdown() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
var msg = "key=" + key + "&sta=setColorCountdown";
msg += "&Color_Countdown_R=" + document.getElementById("Color_Countdown_R").value;
msg += "&Color_Countdown_G=" + document.getElementById("Color_Countdown_G").value;
msg += "&Color_Countdown_B=" + document.getElementById("Color_Countdown_B").value;
sendCommandToESP32("set", msg);
}
function resetSystem() {
var key = document.getElementById("key").value;
if (key == "") {
alert("Please enter the key!");
return;
}
if (confirm("Are you sure you want to reset the system?")) {
var msg = "key=" + key + "&sta=resetSystem";
sendCommandToESP32("set", msg);
}
}
function apply_the_Received_Settings(receivedSettings) {
// Fonction pour appliquer les paramètres reçus
console.log("Settings received:", receivedSettings);
// Ici vous pouvez analyser la réponse et remplir les champs du formulaire
}
</script>
</body>
</html>
)=====";
#endif // PAGE_INDEX_H
+20
View File
@@ -0,0 +1,20 @@
// Découpage pour éviter dépassement de longueur de ligne
static const char MAIN_page[] =
"<!DOCTYPE html><html lang='fr'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width,initial-scale=1'>"
"<title>ESP32 P10 Clock</title><style>body{font-family:Arial,Helvetica,sans-serif;margin:0;padding:1rem;background:#111;color:#eee}"
"h1{text-align:center;color:#4caf50;font-size:1.4rem;margin:.2rem 0}fieldset{border:1px solid #333;border-radius:6px;margin:0 0 1rem;padding:.8rem}"
"legend{padding:0 .5rem;color:#4caf50;font-weight:bold}label{display:block;margin-top:.5rem;font-size:.85rem}"
"input,select{width:100%;padding:.4rem;margin-top:.2rem;background:#222;border:1px solid #444;color:#eee;border-radius:4px;font-size:.9rem}"
"button{margin-top:.7rem;width:100%;background:#4caf50;color:#fff;border:none;padding:.55rem .7rem;font-size:.95rem;border-radius:4px;cursor:pointer}"
".grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:.5rem}.footer{text-align:center;font-size:.65rem;margin-top:1rem;opacity:.6}"
"a.link-btn{display:inline-block;margin:.25rem 0;padding:.45rem .6rem;background:#1976d2;color:#fff;text-decoration:none;border-radius:4px;font-size:.75rem}"
"</style><script>function qs(i){return document.getElementById(i);}function send(id){const f=qs(id);const p=new URLSearchParams(new FormData(f));fetch('/settings?'+p.toString()).then(r=>r.text()).then(()=>{qs('msg').textContent='OK';setTimeout(()=>qs('msg').textContent='',1500);});return false;}</script></head><body>"
"<h1>ESP32 P10 RGB Clock</h1><div id='msg' style='text-align:center;font-size:.8rem;height:1rem;'></div>"
"<form id='timeForm' onsubmit=\"return send('timeForm')\"><fieldset><legend>Date & Heure</legend><input type='hidden' name='sta' value='setTimeDate'>"
"<div class='grid'><div><label>Année<input name='d_Year' type='number' min='2024' max='2099' required></label></div><div><label>Mois<input name='d_Month' type='number' min='1' max='12' required></label></div><div><label>Jour<input name='d_Day' type='number' min='1' max='31' required></label></div><div><label>Heure<input name='t_Hour' type='number' min='0' max='23' required></label></div><div><label>Minute<input name='t_Minute' type='number' min='0' max='59' required></label></div><div><label>Seconde<input name='t_Second' type='number' min='0' max='59' required></label></div></div><button>Mettre à l'heure</button></fieldset></form>"
"<form id='brightForm' onsubmit=\"return send('brightForm')\"><fieldset><legend>Luminosité</legend><input type='hidden' name='sta' value='setBrightness'><label>Valeur (0-255)<input name='input_Brightness' type='number' min='0' max='255' value='125'></label><button>Appliquer</button></fieldset></form>"
"<form id='scrollForm' onsubmit=\"return send('scrollForm')\"><fieldset><legend>Texte défilant</legend><input type='hidden' name='sta' value='setScrollingText'><label>Texte (150 max)<input name='input_Scrolling_Text' maxlength='150' value='ESP32 RGB CLOCK'></label><button>Enregistrer</button></fieldset></form>"
"<form id='modeForm' onsubmit=\"return send('modeForm')\"><fieldset><legend>Mode</legend><input type='hidden' name='sta' value='setDisplayMode'><label>Mode<select name='input_Display_Mode'><option value='1'>Statique</option><option value='2'>Cyclique</option></select></label><button>Appliquer</button></fieldset></form>"
"<form id='countForm' onsubmit=\"return send('countForm')\"><fieldset><legend>Countdown</legend><input type='hidden' name='sta' value='setCountdown'><label>Actif<select name='countdown_Active'><option value='false'>Non</option><option value='true'>Oui</option></select></label><div class='grid'><div><label>Année<input name='countdown_Year' type='number' min='2024' max='2099'></label></div><div><label>Mois<input name='countdown_Month' type='number' min='1' max='12'></label></div><div><label>Jour<input name='countdown_Day' type='number' min='1' max='31'></label></div><div><label>Heure<input name='countdown_Hour' type='number' min='0' max='23'></label></div><div><label>Minute<input name='countdown_Minute' type='number' min='0' max='59'></label></div><div><label>Seconde<input name='countdown_Second' type='number' min='0' max='59'></label></div></div><label>Titre<input name='countdown_Title' maxlength='50' value='NEW YEAR'></label><button>Appliquer Countdown</button></fieldset></form>"
"<div class='section-actions'><a class='link-btn' href='/settings?sta=resetSystem'>Redémarrer</a></div><div class='footer'>Firmware Web Minimal &copy; 2025</div></body></html>";
+2 -2
View File
@@ -399,7 +399,7 @@ void loadSettings() {
// Paramètres du countdown
countdown_Active = preferences.getBool("cd_Active", false);
countdown_Year = preferences.getInt("cd_Year", 2025);
countdown_Month = preferences.getInt("cd_Year", 12);
countdown_Month = preferences.getInt("cd_Month", 12);
countdown_Day = preferences.getInt("cd_Day", 31);
countdown_Hour = preferences.getInt("cd_Hour", 23);
countdown_Minute = preferences.getInt("cd_Minute", 59);
@@ -658,7 +658,7 @@ void handleSettings() {
else if (incoming_Settings == "setCountdown") {
countdown_Active = server.arg("countdown_Active") == "true";
countdown_Year = server.arg("countdown_Year").toInt();
countdown_Month = server.arg("countdown_Year").toInt();
countdown_Month = server.arg("countdown_Month").toInt();
countdown_Day = server.arg("countdown_Day").toInt();
countdown_Hour = server.arg("countdown_Hour").toInt();
countdown_Minute = server.arg("countdown_Minute").toInt();
View File