Ajouter main.cpp
This commit is contained in:
354
main.cpp
Normal file
354
main.cpp
Normal file
@@ -0,0 +1,354 @@
|
||||
#include <Arduino.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiManager.h>
|
||||
#include <EEPROM.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <Bounce2.h>
|
||||
#include <NTPClient.h>
|
||||
#include <time.h>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
// Définition des broches
|
||||
#define RELAY_PIN 12
|
||||
#define BUTTON_PIN 0
|
||||
#define LED_PIN 13
|
||||
|
||||
// EEPROM
|
||||
#define EEPROM_SIZE 8 // Taille nécessaire pour stocker 4 octets pour la durée et 4 octets pour l'heure d'allumage
|
||||
|
||||
// Configuration WiFi
|
||||
const char* ssid = "WifiHome2";
|
||||
const char* password = "louca2212";
|
||||
|
||||
// Variables globales
|
||||
Bounce buttonDebouncer;
|
||||
ESP8266WebServer server(80); // Serveur Web sur le port 80
|
||||
WiFiUDP ntpUDP;
|
||||
NTPClient timeClient(ntpUDP, "pool.ntp.org", 3600); // Serveur NTP avec décalage UTC+1
|
||||
bool relayState = false;
|
||||
unsigned long relayTimer = 0;
|
||||
unsigned long relayDuration = 60000; // 60 secondes par défaut
|
||||
bool saveSuccess = false; // Indique si l'EEPROM a été sauvegardée
|
||||
int relayStartHour = 0; // Heure d'allumage (par défaut 00)
|
||||
int relayStartMinute = 0; // Minute d'allumage (par défaut 00)
|
||||
unsigned long lastNTPUpdate = 0; // Temps de la dernière mise à jour NTP (en ms)
|
||||
|
||||
|
||||
// Fonction pour mettre à jour le client NTP toutes les 30 secondes
|
||||
void updateNTP() {
|
||||
unsigned long currentMillis = millis();
|
||||
if (currentMillis - lastNTPUpdate >= 30000 || lastNTPUpdate == 0) {
|
||||
timeClient.update();
|
||||
lastNTPUpdate = currentMillis;
|
||||
unsigned long rawTime = timeClient.getEpochTime();
|
||||
Serial.println("Mise à jour NTP effectuée. Temps brut reçu : " + String(rawTime));
|
||||
Serial.println("Temps formaté (UTC) : " + String(rawTime % 86400 / 3600) + ":" + String(rawTime % 3600 / 60));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Fonction pour basculer l'état du relais
|
||||
void toggleRelay() {
|
||||
relayState = !relayState;
|
||||
digitalWrite(RELAY_PIN, relayState);
|
||||
if (relayState) {
|
||||
relayTimer = millis();
|
||||
Serial.println("Relais activé");
|
||||
} else {
|
||||
Serial.println("Relais désactivé");
|
||||
}
|
||||
}
|
||||
|
||||
// Fonction pour sauvegarder les paramètres dans l'EEPROM
|
||||
void saveSettings() {
|
||||
EEPROM.write(0, relayDuration / 60000); // Sauvegarde la durée en minutes
|
||||
EEPROM.write(1, relayStartHour); // Sauvegarde l'heure
|
||||
EEPROM.write(2, relayStartMinute); // Sauvegarde les minutes
|
||||
EEPROM.commit();
|
||||
Serial.println("Paramètres sauvegardés dans l'EEPROM");
|
||||
}
|
||||
|
||||
// Fonction pour charger les paramètres depuis l'EEPROM
|
||||
void loadSettings() {
|
||||
relayDuration = EEPROM.read(0) * 60000; // Chargement de la durée en ms
|
||||
relayStartHour = EEPROM.read(1); // Chargement de l'heure
|
||||
relayStartMinute = EEPROM.read(2); // Chargement des minutes
|
||||
|
||||
// Vérifier les valeurs invalides et appliquer des valeurs par défaut
|
||||
if (relayDuration == 0 || relayDuration > 10800000) relayDuration = 60000; // Valeur par défaut 60 secondes
|
||||
if (relayStartHour < 0 || relayStartHour >= 24) relayStartHour = 0; // Heure par défaut 00
|
||||
if (relayStartMinute < 0 || relayStartMinute >= 60) relayStartMinute = 0; // Minute par défaut 00
|
||||
|
||||
Serial.println("Paramètres chargés :");
|
||||
Serial.println("Durée du relais : " + String(relayDuration / 60000) + " minutes");
|
||||
Serial.println("Heure d'allumage : " + String(relayStartHour) + ":" + String(relayStartMinute));
|
||||
}
|
||||
|
||||
// Fonction pour mettre à jour la LED en fonction de l'état
|
||||
void updateLED() {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
digitalWrite(LED_PIN, LOW); // LED éteinte si déconnecté
|
||||
} else if (relayState) {
|
||||
digitalWrite(LED_PIN, LOW); // LED allumée si relais activé
|
||||
} else {
|
||||
digitalWrite(LED_PIN, HIGH); // LED éteinte si relais désactivé
|
||||
}
|
||||
}
|
||||
|
||||
// Gestion des clics du bouton
|
||||
void handleButton() {
|
||||
if (buttonDebouncer.fell()) {
|
||||
Serial.println("Bouton pressé");
|
||||
toggleRelay(); // Bascule le relais
|
||||
}
|
||||
}
|
||||
|
||||
// Fonction pour obtenir l'heure au format HH:MM
|
||||
String getFormattedTime() {
|
||||
unsigned long rawTime = timeClient.getEpochTime();
|
||||
unsigned long adjustedTime = rawTime ;
|
||||
int hours = (adjustedTime % 86400L) / 3600; // Heures
|
||||
int minutes = (adjustedTime % 3600) / 60; // Minutes
|
||||
|
||||
char buffer[6];
|
||||
snprintf(buffer, sizeof(buffer), "%02d:%02d", hours, minutes);
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
// Calculer le délai en minutes avant le prochain allumage
|
||||
int calculateMinutesUntilNextStart() {
|
||||
unsigned long currentTime = timeClient.getEpochTime();
|
||||
int currentHour = (currentTime % 86400L) / 3600;
|
||||
int currentMinute = (currentTime % 3600) / 60;
|
||||
|
||||
// Convertir l'heure actuelle et l'heure de démarrage en minutes depuis minuit
|
||||
int currentTotalMinutes = currentHour * 60 + currentMinute;
|
||||
int startTotalMinutes = relayStartHour * 60 + relayStartMinute;
|
||||
|
||||
// Calculer la différence
|
||||
int delay = startTotalMinutes - currentTotalMinutes;
|
||||
if (delay < 0) {
|
||||
delay += 1440; // Ajouter 24 heures si le délai est négatif (allumage le lendemain)
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
int calculateMinutesUntilNextStop() {
|
||||
int delayUntilStart = calculateMinutesUntilNextStart();
|
||||
if (relayState) {
|
||||
// Si le relais est déjà activé, calcule le temps restant jusqu'à son extinction
|
||||
unsigned long elapsedMillis = millis() - relayTimer;
|
||||
return max(0L, (long)((relayDuration - elapsedMillis) / 60000));
|
||||
} else {
|
||||
// Si le relais est désactivé, ajoute la durée d'activation au délai jusqu'au prochain allumage
|
||||
return delayUntilStart + (relayDuration / 60000);
|
||||
}
|
||||
}
|
||||
|
||||
// Page principale
|
||||
void handleMainPage() {
|
||||
updateNTP(); // Mettre à jour le client NTP si nécessaire
|
||||
String currentTime = getFormattedTime();
|
||||
int nextStart = calculateMinutesUntilNextStart();
|
||||
int nextStop = calculateMinutesUntilNextStop();
|
||||
|
||||
String relayStateColor = relayState ? "green" : "red"; // Détermine la couleur du texte
|
||||
String relayStateText = relayState ? "ACTIVÉ" : "DÉSACTIVÉ";
|
||||
|
||||
String html = R"rawliteral(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Relais Sonoff</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }
|
||||
button { padding: 10px 20px; font-size: 16px; margin: 20px; cursor: pointer; }
|
||||
#relayState { font-weight: bold; color: RELAY_COLOR; }
|
||||
</style>
|
||||
<script>
|
||||
setInterval(() => {
|
||||
location.reload(); // Rafraîchit la page toutes les secondes
|
||||
}, 10000);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Relais Sonoff</h1>
|
||||
<p>Heure : <span id="currentTime">TIME</span></p>
|
||||
<p><strong>État du relais :</strong> <span id="relayState">RELAY_STATE</span></p>
|
||||
<p>Délai avant prochain allumage du relais : <span id="nextStart">NEXT_START</span> minutes</p>
|
||||
<p>Délai avant prochaine extinction du relais : <span id="nextStop">NEXT_STOP</span> minutes</p>
|
||||
<p><button onclick="location.href='/settings'">Paramètres</button></p>
|
||||
</body>
|
||||
</html>
|
||||
)rawliteral";
|
||||
|
||||
html.replace("TIME", currentTime);
|
||||
html.replace("RELAY_STATE", relayStateText);
|
||||
html.replace("RELAY_COLOR", relayStateColor);
|
||||
html.replace("NEXT_START", String(nextStart));
|
||||
html.replace("NEXT_STOP", String(nextStop));
|
||||
server.send(200, "text/html", html);
|
||||
}
|
||||
|
||||
// Page des paramètres
|
||||
void handleSettingsPage() {
|
||||
// Charger les paramètres depuis l'EEPROM
|
||||
loadSettings();
|
||||
|
||||
// Générer la page HTML
|
||||
String html = R"rawliteral(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Paramètres Relais</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }
|
||||
button { padding: 10px 20px; font-size: 16px; margin: 20px; cursor: pointer; }
|
||||
</style>
|
||||
<script>
|
||||
function saveSettings() {
|
||||
const duration = parseInt(document.getElementById('duration').value);
|
||||
const startHour = parseInt(document.getElementById('startHour').value);
|
||||
const startMinute = parseInt(document.getElementById('startMinute').value);
|
||||
|
||||
if (isNaN(duration) || duration < 0 || duration > 180) {
|
||||
alert('Erreur : Durée invalide (entre 0 et 180 minutes).');
|
||||
return;
|
||||
}
|
||||
if (isNaN(startHour) || startHour < 0 || startHour > 23) {
|
||||
alert('Erreur : Heure invalide (entre 0 et 23).');
|
||||
return;
|
||||
}
|
||||
if (isNaN(startMinute) || startMinute < 0 || startMinute > 59) {
|
||||
alert('Erreur : Minute invalide (entre 0 et 59).');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/save', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
relayDuration: duration,
|
||||
relayStartHour: startHour,
|
||||
relayStartMinute: startMinute
|
||||
})
|
||||
}).then(() => {
|
||||
location.href = '/';
|
||||
});
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
location.href = '/';
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Paramètres Relais</h1>
|
||||
<p>Durée (minutes) : <input type="text" id="duration" value="DURATION"></p>
|
||||
<p>Heure d'allumage : <input type="text" id="startHour" value="HOUR" size="2"> : <input type="text" id="startMinute" value="MINUTE" size="2"></p>
|
||||
<p><button onclick="saveSettings()">Enregistrer</button></p>
|
||||
<p><button onclick="goBack()">Retour</button></p>
|
||||
</body>
|
||||
</html>
|
||||
)rawliteral";
|
||||
|
||||
html.replace("DURATION", String(relayDuration / 60000));
|
||||
html.replace("HOUR", String(relayStartHour));
|
||||
html.replace("MINUTE", String(relayStartMinute));
|
||||
server.send(200, "text/html", html);
|
||||
}
|
||||
|
||||
// Sauvegarde des paramètres
|
||||
void handleSaveSettings() {
|
||||
JsonDocument doc;
|
||||
DeserializationError error = deserializeJson(doc, server.arg("plain"));
|
||||
if (error) {
|
||||
server.send(400, "text/plain", "Erreur JSON");
|
||||
return;
|
||||
}
|
||||
|
||||
relayDuration = doc["relayDuration"].as<unsigned long>() * 60000;
|
||||
relayStartHour = doc["relayStartHour"].as<int>();
|
||||
relayStartMinute = doc["relayStartMinute"].as<int>();
|
||||
|
||||
saveSettings();
|
||||
server.send(200, "text/plain", "Paramètres sauvegardés.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Initialisation
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Démarrage du programme...");
|
||||
|
||||
// Initialisation des broches
|
||||
pinMode(RELAY_PIN, OUTPUT);
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP);
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
digitalWrite(RELAY_PIN, LOW);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
Serial.println("Broches configurées");
|
||||
|
||||
// Configuration du bouton avec Bounce2
|
||||
buttonDebouncer.attach(BUTTON_PIN);
|
||||
buttonDebouncer.interval(25);
|
||||
Serial.println("Bouton configuré");
|
||||
|
||||
// Connexion WiFi avec WiFiManager
|
||||
Serial.println("Connexion au WiFi...");
|
||||
WiFiManager wifiManager;
|
||||
wifiManager.autoConnect("SonoffRelay", "password");
|
||||
Serial.println("Connecté au WiFi : " + String(WiFi.SSID()) + " - IP : " + WiFi.localIP().toString());
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
loadSettings();
|
||||
|
||||
|
||||
// Initialisation du client NTP
|
||||
timeClient.begin();
|
||||
updateNTP();
|
||||
|
||||
server.on("/", handleMainPage);
|
||||
server.on("/settings", handleSettingsPage);
|
||||
server.on("/save", HTTP_POST, handleSaveSettings);
|
||||
|
||||
server.begin();
|
||||
Serial.println("Serveur web démarré");
|
||||
}
|
||||
|
||||
// Boucle principale
|
||||
void loop() {
|
||||
buttonDebouncer.update();
|
||||
handleButton();
|
||||
|
||||
// Mise à jour de l'heure NTP
|
||||
timeClient.update();
|
||||
|
||||
// Gère les requêtes HTTP des clients
|
||||
server.handleClient();
|
||||
|
||||
// Obtenir l'heure actuelle
|
||||
unsigned long rawTime = timeClient.getEpochTime();
|
||||
int currentHour = (rawTime % 86400L) / 3600; // Heures actuelles
|
||||
int currentMinute = (rawTime % 3600) / 60; // Minutes actuelles
|
||||
|
||||
// Vérifier si l'heure actuelle correspond à l'heure d'allumage
|
||||
if (!relayState && currentHour == relayStartHour && currentMinute == relayStartMinute) {
|
||||
Serial.println("Allumage automatique du relais à l'heure programmée");
|
||||
toggleRelay(); // Allume le relais
|
||||
}
|
||||
|
||||
// Gestion du relais (arrêt automatique après la durée spécifiée)
|
||||
if (relayState && millis() - relayTimer >= relayDuration) {
|
||||
Serial.println("Extinction automatique du relais après la durée configurée");
|
||||
toggleRelay(); // Éteint le relais
|
||||
}
|
||||
|
||||
// Mise à jour de la LED
|
||||
updateLED();
|
||||
}
|
||||
Reference in New Issue
Block a user