hello,
I don't know which topic is it sorry for confusing
I used fastled for a project but it says an error
#include <WiFi.h>
#include <WebServer.h>
#include <FastLED.h>
#include <DNSServer.h>
#include <Preferences.h> // Pour la persistence des paramètres
#include "site final.html"
// ==== CONFIG =====
#define LED_PIN 12
#define NUM_LEDS 30
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
const char* ap_ssid = "ESP32-LED";
const char* ap_password = "12345678";
WebServer server(80);
DNSServer dnsServer;
Preferences preferences; // Objet pour le stockage persistant
// ==== VARIABLES ====
CRGB selectedColor = CRGB::Red;
int brightness = 128;
String currentEffect = "off";
unsigned long speed = 150;
// Variables d'animation
unsigned long previousMillis = 0;
uint16_t rainbowPosition = 0;
uint8_t serpentPosition = 0;
// ==== HTML PAGE ====
const char MAIN_page[] PROGMEM = "site final.html";
// ==== FONCTIONS DE STOCKAGE ====
void saveSettings() {
preferences.begin("ledctrl", true);
// Convertir CRGB en uint32_t (0xRRGGBB)
uint32_t rgbColor = (selectedColor.r << 16) | (selectedColor.g << 8) | selectedColor.b;
preferences.putUInt("color", rgbColor);
preferences.putUInt("brightness", brightness);
preferences.putString("effect", currentEffect.c_str());
preferences.putULong("speed", speed);
preferences.end();
}
void loadSettings() {
preferences.begin("ledctrl", true);
uint32_t rgbColor = preferences.getUInt("color", 0xFF0000); // Rouge par défaut
selectedColor = CRGB((rgbColor >> 16) & 0xFF, (rgbColor >> 8) & 0xFF, rgbColor & 0xFF);
brightness = preferences.getUInt("brightness", 128);
currentEffect = preferences.getString("effect", "off");
speed = preferences.getULong("speed", 150);
if (currentEffect == "rainbowAll" && preferences.getString("effect", "") == "rainbow") {
currentEffect = "rainbow";
}
preferences.end();
}
// ==== HANDLERS ====
void handleRoot() {
server.send(200, "text/html", MAIN_page);
}
void handleSetColor() {
if (server.hasArg("color")) {
String hex = server.arg("color");
hex.remove(0, 1); // Retire le #
long rgb = strtol(hex.c_str(), NULL, 16);
selectedColor = CRGB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF);
if (currentEffect == "all") allOn();
saveSettings();
server.send(200, "text/plain", "OK");
}
}
void handleSetBrightness() {
if (server.hasArg("brightness")) {
brightness = server.arg("brightness").toInt();
FastLED.setBrightness(brightness);
FastLED.show();
saveSettings(); // Sauvegarde après modification
server.send(200, "text/plain", "OK");
}
}
void handleSetSpeed() {
if (server.hasArg("speed")) {
speed = map(server.arg("speed").toInt(), 5, 1000, 1000, 5);
saveSettings(); // Sauvegarde après modification
server.send(200, "text/plain", "OK");
}
}
void handleSetEffect() {
if (server.hasArg("effect")) {
String newEffect = server.arg("effect");
// Gestion spéciale pour le mode Rainbow
if (currentEffect == "rainbow" && newEffect == "rainbowAll") {
currentEffect = "rainbowAll";
}
else if (currentEffect == "rainbowAll" && newEffect == "rainbow") {
currentEffect = "rainbow";
}
else {
currentEffect = newEffect;
}
// Applique l'effet
if (currentEffect == "off") allOff();
else if (currentEffect == "all") allOn();
saveSettings();
server.send(200, "text/plain", "OK");
}
}
void handleGetSettings() {
String json = "{";
json += "\"color\":\"" + String(selectedColor.r) + "," + String(selectedColor.g) + "," + String(selectedColor.b) + "\",";
json += "\"brightness\":" + String(brightness) + ",";
json += "\"effect\":\"" + currentEffect + "\",";
json += "\"speed\":" + String(speed);
json += "}";
server.send(200, "application/json", json);
}
void handleNotFound() {
server.sendHeader("Location", String("http://") + server.client().localIP().toString(), true);
server.send(302, "text/plain", "");
}
// ==== LED EFFECTS ====
// (Vos fonctions d'effets restent inchangées)
void allOn() {
fill_solid(leds, NUM_LEDS, selectedColor);
FastLED.show();
}
void allOff() {
fill_solid(leds, NUM_LEDS, CRGB::Black);
FastLED.show();
}
void serpentAnimation() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= speed) {
previousMillis = currentMillis;
fill_solid(leds, NUM_LEDS, CRGB::Black);
for (uint8_t i = 0; i < NUM_LEDS; i++) {
if ((i + serpentPosition) % 6 < 3) {
leds[i] = selectedColor;
}
}
FastLED.show();
serpentPosition = (serpentPosition + 1) % 6;
}
}
void rainbowAnimation() {
unsigned long currentMillis = millis();
// Multiply speed by 10 only for rainbow effect
if (currentMillis - previousMillis >= (speed / 20)) {
previousMillis = currentMillis;
for (uint8_t i = 0; i < NUM_LEDS; i++) {
leds[i] = Wheel(((i * 256 / NUM_LEDS) + rainbowPosition) & 255);
}
FastLED.show();
rainbowPosition = (rainbowPosition + 1) % 256;
}
}
CRGB Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return CRGB(255 - WheelPos * 3, 0, WheelPos * 3);
} else if(WheelPos < 170) {
WheelPos -= 85;
return CRGB(0, WheelPos * 3, 255 - WheelPos * 3);
} else {
WheelPos -= 170;
return CRGB(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
void rainbowAll() {
static unsigned long lastUpdate = 0;
static uint16_t hue = 0; // Using 16-bit for smoother transitions
// Calculate time since last update (non-blocking)
unsigned long currentMillis = millis();
if (currentMillis - lastUpdate >= 30) { // Fixed refresh rate for smoothness
lastUpdate = currentMillis;
// Increment hue with speed adjustment (16-bit for precision)
uint8_t hueIncrement = map(speed, 5, 1000, 1, 120);
hue += hueIncrement;
// Apply to all LEDs
fill_solid(leds, NUM_LEDS, CHSV(hue >> 8, 255, 255)); // Use upper 8 bits
FastLED.show();
EVERY_N_MILLISECONDS(5) {}
}
}
// ==== SETUP / LOOP ====
void setup() {
Serial.begin(115200);
// Initialize FastLED FIRST
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(brightness);
// Then load settings
loadSettings();
// Appliquer l'effet au démarrage
if (currentEffect == "off") allOff();
else if (currentEffect == "all") allOn();
WiFi.softAP(ap_ssid, ap_password);
dnsServer.start(53, "*", WiFi.softAPIP());
server.on("/", handleRoot);
server.on("/setColor", handleSetColor);
server.on("/setBrightness", handleSetBrightness);
server.on("/setSpeed", handleSetSpeed);
server.on("/setEffect", handleSetEffect);
server.on("/getSettings", handleGetSettings);
server.onNotFound(handleNotFound);
server.begin();
}
void loop() {
dnsServer.processNextRequest();
server.handleClient();
if (currentEffect == "serpent") serpentAnimation();
else if (currentEffect == "rainbow") rainbowAnimation();
else if (currentEffect == "rainbowAll") rainbowAll();
}`
here the html
R"rawliteral(
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LED Controller</title>
<style>
:root {
--active-color: #1e88e5;
}
body {
font-family: 'Calibri';
background: #121212;
color: white;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
margin: 0;
padding: 20px;
}
.slider-container {
width: 80%;
max-width: 400px;
margin: 20px 0;
}
.slider-label {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
font-weight: bold;
}
input[type="range"].styled-slider {
-webkit-appearance: none;
width: 100%;
height: 10px;
background: #ddd;
border-radius: 5px;
outline: none;
}
input[type="range"].styled-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
background: #333;
border-radius: 50%;
cursor: pointer;
transition: background 0.2s ease;
}
input[type="range"].styled-slider:hover::-webkit-slider-thumb {
background: #555;
}
.effects-panel {
display: flex;
gap: 15px;
margin-top: 40px;
flex-wrap: wrap;
justify-content: center;
}
.effect-btn {
background: #333;
color: white;
border: none;
padding: 12px 25px;
border-radius: 30px;
font-size: 16px;
cursor: pointer;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: bold;
transition: all 0.3s;
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
min-width: 120px;
text-align: center;
}
.effect-btn.active {
background: var(--active-color);
box-shadow: 0 0 15px rgba(30, 136, 229, 0.5);
}
.color-preview {
width: 80px;
height: 80px;
border-radius: 50%;
border: 3px solid #444;
background-color: #ff0000;
box-shadow: 0 0 15px rgba(0,0,0,0.5);
margin: 20px auto;
}
.rainbow-slider {
width: 80%;
max-width: 300px;
margin: 0 auto;
}
.rainbow-slider input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 15px;
border-radius: 10px;
background: linear-gradient(to right,
#ff0000, #ff8000, #ffff00, #80ff00,
#00ff00, #00ff80, #00ffff, #0080ff,
#0000ff, #8000ff, #ff00ff, #ff0080, #ff0000);
outline: none;
margin: 15px 0;
}
.rainbow-slider input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 25px;
height: 25px;
border-radius: 50%;
background: white;
border: 3px solid #121212;
cursor: pointer;
box-shadow: 0 0 5px rgba(0,0,0,0.5);
}
#rainbowBtn.active[data-mode="rainbowAll"] {
background: linear-gradient(90deg,
#ff0000, #ff8000, #ffff00, #80ff00,
#00ff00, #00ff80, #00ffff, #0080ff,
#0000ff, #8000ff, #ff00ff, #ff0080);
}
#rainbowBtn.active[data-mode="rainbow"] {
background: linear-gradient(90deg,
#ff0000, #ffff00, #00ff00, #00ffff,
#0000ff, #ff00ff);
}
</style>
</head>
<body>
<h1>CONTROL PANEL</h1>
<div id="connectionStatus" style="position: fixed; top: 10px; right: 10px; background: #4CAF50; color: white; padding: 5px 10px; border-radius: 20px; display: none;">
Connecté
<div class="rainbow-slider">
<div class="color-preview" id="colorPreview"></div>
<input type="range" id="hueSlider" min="0" max="360" value="0">
<div class="slider-label">
<span>COULEUR</span>
</div>
</div>
<div class="slider-container">
<div class="slider-label">
<span>LUMINOSITÉ</span>
<span id="brightnessValue">50%</span>
</div>
<input type="range" class="styled-slider" id="brightnessSlider" min="0" max="255" value="128">
</div>
<div class="slider-container">
<div class="slider-label">
<span>VITESSE</span>
</div>
<input type="range" class="styled-slider" id="speedSlider" min="5" max="1000" value="150">
</div>
<div class="effects-panel">
<button class="effect-btn" id="serpentBtn">SERPENT</button>
<button class="effect-btn" id="rainbowBtn" data-mode="rainbowAll">RAINBOW</button>
<button class="effect-btn" id="allBtn">ON</button>
<button class="effect-btn" id="offBtn">OFF</button>
</div>
<script>
// Éléments DOM
const hueSlider = document.getElementById('hueSlider');
const brightnessSlider = document.getElementById('brightnessSlider');
const speedSlider = document.getElementById('speedSlider');
const colorPreview = document.getElementById('colorPreview');
const brightnessValue = document.getElementById('brightnessValue');
const connectionStatus = document.getElementById('connectionStatus');
// Conversion RGB vers Teinte (HSV)
function rgbToHue(r, g, b) {
r /= 255, g /= 255, b /= 255;
const max = Math.max(r, g, b), min = Math.min(r, g, b);
let h = 0;
if (max === min) h = 0;
else if (max === r) h = (60 * ((g - b) / (max - min)) + 360) % 360;
else if (max === g) h = (60 * ((b - r) / (max - min)) + 120) % 360;
else h = (60 * ((r - g) / (max - min)) + 240) % 360;
return Math.round(h);
}
// Remplacez la gestion du bouton Rainbow par ceci :
document.getElementById('rainbowBtn').addEventListener('click', function() {
const isActive = this.classList.contains('active');
const currentEffect = isActive ? 'off' :
(this.dataset.mode === 'rainbow' ? 'rainbowAll' : 'rainbow');
// Bascule le mode pour le prochain clic
this.dataset.mode = (this.dataset.mode === 'rainbow' ? 'rainbowAll' : 'rainbow');
setEffect(currentEffect);
});
// Modifiez setEffect() pour gérer le mode
function setEffect(effect) {
fetch('/setEffect?effect=' + effect)
.then(() => {
const rainbowBtn = document.getElementById('rainbowBtn');
// Réinitialise tous les boutons
document.querySelectorAll('.effect-btn').forEach(btn => {
btn.classList.remove('active');
});
// Met à jour l'état actif
if (effect === 'rainbow' || effect === 'rainbowAll') {
rainbowBtn.classList.add('active');
rainbowBtn.dataset.mode = (effect === 'rainbow' ? 'rainbowAll' : 'rainbow');
} else {
document.getElementById(effect + 'Btn').classList.add('active');
}
});
}
// Charger les paramètres depuis l'ESP32
function loadSettings() {
fetch('/getSettings')
.then(response => response.json())
.then(settings => {
const [r, g, b] = settings.color.split(',').map(Number);
const hue = rgbToHue(r, g, b);
hueSlider.value = hue;
brightnessSlider.value = settings.brightness;
speedSlider.value = settings.speed;
updateColor();
updateSliderValues();
document.querySelectorAll('.effect-btn').forEach(btn => {
btn.classList.remove('active');
if (btn.id === settings.effect + 'Btn') btn.classList.add('active');
});
showConnectionStatus();
});
}
function showConnectionStatus() {
connectionStatus.style.display = 'block';
setTimeout(() => connectionStatus.style.display = 'none', 2000);
}
// Éléments DOM
const hueSlider = document.getElementById('hueSlider');
const brightnessSlider = document.getElementById('brightnessSlider');
const speedSlider = document.getElementById('speedSlider');
const colorPreview = document.getElementById('colorPreview');
const brightnessValue = document.getElementById('brightnessValue');
// Conversion en pourcentage
function toPercent(value, min, max) {
return Math.round(((value - min) / (max - min)) * 100);
}
// Mise à jour des valeurs en %
function updateSliderValues() {
brightnessValue.textContent = toPercent(brightnessSlider.value, 0, 255) + '%';
}
// Conversion teinte vers RGB
function hueToRgb(h) {
h /= 60;
const c = 255;
const x = (1 - Math.abs(h % 2 - 1)) * 255;
let r, g, b;
if (h >= 0 && h < 1) { [r,g,b] = [c,x,0]; }
else if (h < 2) { [r,g,b] = [x,c,0]; }
else if (h < 3) { [r,g,b] = [0,c,x]; }
else if (h < 4) { [r,g,b] = [0,x,c]; }
else if (h < 5) { [r,g,b] = [x,0,c]; }
else { [r,g,b] = [c,0,x]; }
return {r: Math.round(r), g: Math.round(g), b: Math.round(b)};
}
// Mise à jour couleur
function updateColor() {
const hue = hueSlider.value;
const color = hueToRgb(hue);
const hex = `#${color.r.toString(16).padStart(2,'0')}${color.g.toString(16).padStart(2,'0')}${color.b.toString(16).padStart(2,'0')}`;
colorPreview.style.backgroundColor = `rgb(${color.r}, ${color.g}, ${color.b})`;
colorPreview.style.boxShadow = `0 0 20px rgba(${color.r}, ${color.g}, ${color.b}, 0.7)`;
fetch('/setColor?color=' + encodeURIComponent(hex));
updateSliderValues();
}
// Écouteurs d'événements
hueSlider.addEventListener('input', updateColor);
brightnessSlider.addEventListener('input', () => {
updateSliderValues();
fetch('/setBrightness?brightness=' + brightnessSlider.value);
});
speedSlider.addEventListener('input', () => {
updateSliderValues();
fetch('/setSpeed?speed=' + speedSlider.value);
});
// Gestion des effets
function setEffect(effect) {
fetch('/setEffect?effect=' + effect)
.then(() => {
document.querySelectorAll('.effect-btn').forEach(btn => {
btn.classList.remove('active');
if (btn.id === effect + 'Btn') btn.classList.add('active');
});
});
}
// Assignation des événements aux boutons
document.getElementById('serpentBtn').addEventListener('click', () => setEffect('serpent'));
document.getElementById('rainbowBtn').addEventListener('click', () => setEffect('rainbow'));
document.getElementById('rainbowAllBtn').addEventListener('click', () => setEffect('rainbowAll'));
document.getElementById('allBtn').addEventListener('click', () => setEffect('all'));
document.getElementById('offBtn').addEventListener('click', () => setEffect('off'));
// Initialisation
updateColor();
updateSliderValues();
setEffect('off');
document.addEventListener('DOMContentLoaded', loadSettings);
</script>
</body>
</html>
)rawliteral"
thank you for your help