#include <Wire.h>
// Sonde de Temperature
#include <OneWire.h>
//typedef uint8_t DeviceAddress[8]; // pas besoin deja defini dans la lib DAllas
#include <DallasTemperature.h>
// Ecran OLED
//#define SSD1306_NO_SPLASH // dans la lib
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSerif9pt7b.h>
#include <Fonts/FreeSerif18pt7b.h>
// EEPROM ESP32
#include <Preferences.h>
Preferences pref; // on cree un Alias ??
// Include the AccelStepper Library
#include <AccelStepper.h>
// SD Card
#include "FS.h"
#include "SD.h"
#include "SPI.h"
// Wifi et NTP (mise a jour heure reseau)
#include <WiFi.h>
#include "time.h"
//#include "sntp.h" // Warning compilation "sntp.h in IDF's lwip port folder is deprecated
#include "esp_sntp.h"
//WebServer
//#include <ESPAsyncWebServer.h>
#include <ESPAsyncWebSrv.h> // DEBUG WOKWI
#include <AsyncTCP.h>
// PID
#include <PID_v1.h>
// JSON lib
#include <ArduinoJson.h>
// ************************
// ******** GPIO *********
// ************************
// Definition GPIO PWM commande vitesse ventilateur
#define OUT_PWM 25 // PWM Pin OUT
// Definition GPIO Compteur RPM
#define IN_RPM 33 // Compteur RPM pin. lecture vitesse moteur
// Definition GPIO Sonde Temperature
#define ONE_WIRE_BUS 4 // Pin 4
// Definition GPIO Encodeur
#define ENC_A 34 // CLK // Rotary encoder gpio pin - 34
#define ENC_B 35 // DT // Rotary encoder gpio pin - 35
#define ENC_SW 32 // SW // Rotary encoder button gpio pin - 32
//Definition GPIO ecran OLED
//#define SDA 21 // SDA // oled data pin - 21
//#define SCL 22 // SCL // oled clock pin - 22
// Wire.begin(SDA, SCL);
//Definition GPIO SD CARD
#define SD_CS 5 // CS // SD card CS pin - 5
#define SD_MOSI 23 // MOSI // SD card MOSI pin - 23
#define SD_CLK 18 // CLK / SCK // SD card CLK pin - 18
#define SD_MISO 19 // MISO // SD card MISO pin - 19
// SPI pour carte SD
SPIClass spi = SPIClass(VSPI);
//Definition GPIO Moteur Pas a Pas : DRV8825 Motor Driver Pins
#define dirPin 26 // Pin pour la direction sens horraire ou anti-horraire
#define stepPin 27 // Pin pour le nombre de step
#define enablePin 16 // Pin pour activer / desactiver le driver, lorque le moteur est inactif
//Definition GPIO Limite switch moteur pas a pas
#define LSW_HOME 15 // LSW_HOME // Limit switch 1 fin de course LSW_HOME gpio pin - 14
#define LSW_MAXTRAVEL 14 // LSW_MAXTRAVEL // Limit switch 2 fin de course LSW_MAXTRAVEL gpio pin - 15
// 17 GPIO utilisées
// GPIO encore Libre
/*
12 libre gpio pin - 12 // VDD_FLASH // probleme de BOOT Failed si pulled UP probleme
13 libre gpio pin - 13 // ok
17 libre gpio pin - 17
0 libre gpio pin - 0 // BOOT Input pulled UP, PWM Output during boot doit etre à LOW to enter flashing mode
2 libre gpio pin - 2 // ok // LOW ou Floating to enter flashing mode
*/
/*
Strapping Pins
The ESP32 chip has the following strapping pins:
GPIO 0 (must be LOW to enter boot mode)
GPIO 2 (must be floating or LOW during boot)
GPIO 4
GPIO 5 (must be HIGH during boot)
GPIO 12 (must be LOW during boot)
GPIO 15 (must be HIGH during boot)
Pins HIGH at Boot
Some GPIOs change their state to HIGH or Output PWM signals at boot or reset.
This means that if you have Outputs connected to these GPIOs you may get unexpected results when the ESP32 resets or boots.
GPIO 1
GPIO 3
GPIO 5
GPIO 6 to GPIO 11 (connected to the ESP32 integrated SPI flash memory – not recommended to use).
GPIO 14
GPIO 15
*/
// pour Preference mode lecture ecriture
#define RO_MODE true // lecture seulement
#define RW_MODE false // lecture et ecriture
// ecran OLED
#define Largeur 128 // Taille de l'écran OLED, en pixel, au niveau de sa largeur
#define Hauteur 64 // Taille de l'écran OLED, en pixel, au niveau de sa hauteur
#define ResetOLED -1 // Reset de l'OLED partagé avec l'Arduino (d'où la valeur à -1, et non un numéro de pin)
#define adrI2COLED 0x3C // Adresse de "mon" écran OLED sur le bus i2c (généralement égal à 0x3C ou 0x3D)
// Init Ecran OLED bus I2C
//Adafruit_SSD1306 ecranOLED(Largeur, Hauteur, &Wire, ResetOLED);
Adafruit_SSD1306 ecranOLED(Largeur, Hauteur, &Wire, ResetOLED, 400000, 100000); // Vitesse bus I2C a 400 KHz en marche et 100 KHz a l'arret (BUG a 800 KHz si perturbation exterieure Tel GSM)
//Adafruit_SSD1306::Adafruit_SSD1306(w, h, TwoWire *twi, rst_pin, clkDuring, clkAfter)
//Adafruit_SSD1306 ecranOLED(Largeur, Hauteur, &Wire, ResetOLED, 800000, 400000); // Ajout Vitesse bus I2C a 800 KHz en marche et 400 KHz a l'arret
// Init Bus Onewire Sonde Temperature
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
// DRV8825 formule courant : Current Limit = Vref × 2
// Create a new instance of the AccelStepper class: DRV8825
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);
// define step constant Half Step
#define STEP_PER_REVOLUTION 13664 // this value is from datasheet HALF STEP -> 48 par tour X 2 (HalfStep) X rotation demultiplication 1:120 -> 48 x 2 x 120 -> 11 520 steps (pour 1 tour)
// Debut PID
//Define Variables we'll be connecting to
double InputPID, OutputPID, SetpointPID, OldSetpointPID; //, lastOutputPID;
//Define the aggressive and conservative Tuning Parameters
//double ultKp=200, ultKi=10, ultKd=50; // x 2.00 (si consigne sup de 5°C) // 200 %
double ultKp=240, ultKi=12, ultKd=60; // x 2.40 (si consigne sup de 5°C) // 240 %
//double aggKp=175, aggKi=8.75, aggKd=43.75; // x 1.75 (si consigne sup a 2°C et inf a 7°C // delta 2 -5 -> 3°C) // Ancien 175 %
//double aggKp=180, aggKi=9, aggKd=45; // 180 %
double aggKp=200, aggKi=10, aggKd=50; // 200 %
//double intKp=150, intKi=7.5, intKd=37.5; // x 1.50 (si consigne sup de 0.5°C et inf a 2°C // delta 0.5 -2 -> 1.5°C) // Ancien 150 %
//double intKp=160, intKi=8, intKd=40; // 160 %
double intKp=180, intKi=9, intKd=45; // 180 %
//double consKp=100, consKi=5, consKd=25; // x 1.00 (si consigne inf a 0.5°C // delta -> 0.5°C) // Ancien 100 % BASE
//double consKp=140, consKi=7, consKd=35; // 140 %
double consKp=160, consKi=8, consKd=40; // 160 %
// Setpoint -> consigne de reglage temperature moteur pour distribution air chaud dans les pieces
int16_t Temp_min_ConsignePID_allowed = 150; // 25°C -> mini ************************************************** AVOIR TEST SILENCIEUX
int16_t Temp_max_ConsignePID_allowed = 600; // 60°C -> maxi (Temp maxi ventillateur)
int16_t ConsignePID = 535; // 53.5°C Temperature de consigne Sonde moteur -> choix (Base) // SAUVE MEM ok
//Temperature d'arret auto PID si trop froid au moteur (et demarrage)
int16_t Temp_min_coupure_allowed = 150; // 25°C -> mini ************************************************** AVOIR TEST SILENCIEUX
int16_t Temp_max_coupure_allowed = 450; // 45°C -> maxi
int16_t ConsignePID_coupure = 370; // 37°C Pid temperature de coupure (Donc 32°C a la bouche) // SAUVE MEM AVOIR
int16_t ConsignePID_demarrage; // Pid temperature de demarrage (ConsignePID - 50 --> 500 -50 -> 450 --> 45°C)
// Seuil Temperature demarrage arret ventilateur X 10
// Temp OFF moteur (Maxi) (Sonde Moteur)
int16_t Temp_min_moteur_allowed = 150; // 25 °C -> mini ************************************************** AVOIR TEST SILENCIEUX
int16_t Temp_max_moteur_allowed = 600; // 60 °C -> maxi
int16_t Temp_OFF_moteur = 550; // 55 °C -> choix (Base) // SAUVE MEM ok
// Temp ON moteur (Mini) (Sonde Chaud)
int16_t Temp_min_chaud_allowed = 150; // 25 °C -> mini ************************************************** AVOIR TEST SILENCIEUX
int16_t Temp_max_chaud_allowed = 800; // 80 °C -> maxi
int16_t Temp_ON_moteur = 435; // 43.5 °C -> choix (Base) // SAUVE MEM ok
// Hysteresis 1er demarrage Temp ON moteur (Sonde Chaud)
int16_t Temp_min_Hyst_allowed = 0; // 0 °C -> mini
int16_t Temp_max_Hyst_allowed = 100; // 10 °C -> maxi
int16_t Hyst_Temp_ON_moteur = 65; // 6,5 °C Hysteresis temperature moteur ON (Chaud) -> choix (Base) // SAUVE MEM ok
int16_t Hyst_moteur = Hyst_Temp_ON_moteur; // prends la valeur 0 apres demarrage moteur, revient a la valeur par defaut apres arret moteur
float coef_temp = 0.1; // on divise par 10 pour avoir les degres °C
//double SetpointPID = ConsignePID * coef_temp; // Temperature de consigne Sonde moteur
String PidMod = " "; // Variable pour le mode PID Tuning (Conservateur, Intermediare, Agressif, Ultra agressif) //Reserve 4 caracteres
bool Flag_init_PID_temp_mini_moteur = false; // FLAG Init Temperature mini Smoteur demarrage regulation PID IRIS
//Delais Arret recuperateur chaleur 60 sec, si mode Boost actif et temp consigne inferieure à ConsignePID
unsigned long timermodeventiloarret = 0;
//Specify the links and initial tuning parameters
PID myPID(&InputPID, &OutputPID, &SetpointPID, consKp, consKi, consKd, P_ON_M, DIRECT);
//PID myPID(&InputPID, &OutputPID, &SetpointPID, Kp, Ki, Kd, DIRECT);
/*
PID myPID(&InputPID, &OutputPID, &SetpointPID, consKp, consKi, consKd, P_ON_M, DIRECT); //P_ON_M specifies that Proportional on Measurement be used
//P_ON_E (Proportional on Error) is the default behavior
*/
// FIN PID
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create a WebSocket object
AsyncWebSocket ws("/ws"); // AVOIR WEB
/*
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* ntpServer = "pool.ntp.org";
//*/
///*
// WIFI
//Wifi : Variables to save values from HTML form
String ssidnew = " "; //Reserve 70 caracteres
String passnew = " "; //Reserve 70 caracteres
// Wifi mode AP
IPAddress local_ip_ap(10,0,0,1);
IPAddress gateway_ap(10,0,0,1);
IPAddress subnet_ap(255,255,255,0);
bool WifiStaMode = false; // Mode STA -> true , Mode AP -> false
// SSID de l'EPS32 en mode AccessPoint en mode reseau ouvert (sans Password)
const char* SSID_AP = "ESP-WIFI-AP";
// Serveur NTP (Network Time Protocol) mise a jour Heure ici Freebox
String ntpServer = " ";
//const char* ntpServer = "192.168.0.1"; // DEPLACER DANS WIFI CALLBACK
// TimeZone rule for Europe/Paris including avec changement heure hivers heure été
const char* time_zone = "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00";
// Sonde DS18B20 (Dallas, Onewire)
// Resolution du capteur fixe a 12 bit (valeur possible 9 10 11 12 bit) Sonde Temperature resolution
//#define TEMPERATURE_PRECISION 12 // Deja Forcé a 12 bit
// Timer variables Sonde Temperature
unsigned long lastTimeRequestTemp = 0;
unsigned long lastTimeDemandeTemp = 0; // Temporaire pour demande en sequence
unsigned long lastTimeReadTemp = 0; // Temporaire pour lecture en sequence
// Temps pour la demande de Temperature toutes les (4.25 + .75) sec
// Delay avant de pouvoir avoir la reponse de la sonde en fonction de sa resolution en bit si asynchrone
unsigned long intervalConversionSonde = 750;
//unsigned long intervalConversionSonde = 750 / (1 << (12 - TEMPERATURE_PRECISION));
unsigned long intervalRequestTemp = 4250; // 5 sec
int8_t countSondeDemande = 0; // compteur temporaire pour les 4 sondes demande de Temperature
int8_t countSondeRead = 0; // compteur temporaire pour les 4 sondes lecture de Temperature
bool flag_auth_request_Temp = false; // Flag pour le Time toutes les 4.250 sec
bool flag_request_Temp_done = false; // Flag pour dire que toutes les demandes de Temperature faite
bool flag_auth_lecture_Temp = false; // Flag pour le Time de conversion 0.750 sec apres le Time de demande
bool flag_auth_traitmnt_Temp = false; // Flag pour dire que toutes les sondes de Temperature ont été lu
// Nombre de sonde de Temperature ICI 4
const uint8_t nbreSondes = 4;
// Sonde comptee apres INIT pour voir si on en a bien 4
uint8_t numberOfDevicesFound;
// Variable Sonde Temperature
const String SondeNom[] = {"Smoteur", "Schaud", "Sfroid", "Sext", "SFlag"}; // Nom des Sondes + Flag sonde existe ok
float SondeTempC[nbreSondes]; //Temperature en Celsius (°C)
/* Exemple :
SondeTempC[4] = { 25.23, 25.25, 25.26, -25.24 };
*/
bool SondeEnVie[nbreSondes]; // si sonde temp ok existe, reponds, donc pas deconnectée
/* Exemple :
SondeEnVie[4] = { true, true, true, true };
*/
uint16_t SondeErr[nbreSondes]; // compteur Total d'erreur par sonde
/* Exemple :
SondeErr[4] = { 0, 0, 0, 0 };
*/
uint8_t SondeErrTemp[nbreSondes]; // compteur erreur temporaire sonde (10 Erreurs de suite) -> Sonde morte TRUE
/* Exemple :
SondeErrTemp[4] = { 0, 0, 0, 0 };
*/
DeviceAddress memSondesAddr[nbreSondes]; // on créé un tableau de de 4 lignes de 8 byte pour stocker les adresses des sondes
/* Exemple :
memSondesAddr[4] = { {0x28, 0xFF, 0x64, 0x1E, 0xF7, 0xC7, 0x55, 0xA2},
{0x28, 0xFF, 0x64, 0x1E, 0x19, 0x23, 0x19, 0x3A},
{0x28, 0xFF, 0x64, 0x1E, 0x19, 0x2B, 0x54, 0xF7},
{0x28, 0xFF, 0x64, 0x1E, 0x19, 0x7E, 0xA4, 0x0B} }; // old exterieure (1m)
{0x28, 0x61, 0x64, 0x0A, 0xBF, 0x27, 0xDF, 0xA5} }; // new exterieure (10m)
*/
uint8_t indexSondeRemp = 0;
// SERIAL DEBUG
const bool serialDebug = 0; // DEBUG 1 ON, 0 OFF (Log Serial) -> MENU
const bool serialDebug_Init = 0; // DEBUG 1 ON, 0 OFF (Log Serial) -> INIT
const bool serialDebug_websocket = 0; // DEBUG 1 ON, 0 OFF (Log Serial) -> WEBSOCKET
const bool serialDebug_webserver = 0; // DEBUG 1 ON, 0 OFF (Log Serial) -> WEBSERVER
const bool serialDebug_wifi = 0; // DEBUG 1 ON, 0 OFF (Log Serial) -> WIFI
const bool serialDebug_PID = 0; // DEBUG 1 ON, 0 OFF (Log Serial) -> PID
const bool serialDebug_IRIS = 0; // DEBUG 1 ON, 0 OFF (Log Serial) -> IRIS
const bool serialDebug_sondes = 0; // DEBUG 1 ON, 0 OFF (Log Serial) -> SONDES TEMPERATURE
const bool serialDebug_ram = 0; // DEBUG 1 ON, 0 OFF (Log Serial) -> MEMOIRE RAM DISPO
// MENU
const int16_t menuTimeout = 600; // menu inactivity timeout (seconds)
const bool menuLargeText = 0; // Permet de voir le menu selectionné dans le TITRE si 1
const int8_t maxmenuItems = 13; // max number of items used in any of the menus (keep as low as possible to save memory)
const int8_t topLine = 18; // y position of lower area of the display (18 with two colour displays)
const byte lineSpace1 = 9; // line spacing for textsize 1 (small text)
const int8_t displayMaxLines = 5; // Nombre de ligne de menu en textsize1 (5 on larger oLeds 64)
// MENU
// modes that the menu system can be in
enum menuModes {
off_menu, // display is off
menu, // a menu is active
value, // 'enter a value' none blocking is active
message, // displaying a message
blocking // a blocking procedure is in progress (see enter value)
};
menuModes menuMode = off_menu; // default mode at startup is off
struct oledMenus {
// menu
String menuTitle = " "; // the title of active mode //Reserve 45 caracteres
int8_t noOfmenuItems = 0; // number if menu items in the active menu
int8_t selectedMenuItem = 0; // when a menu item is selected it is flagged here until actioned and cleared
int8_t highlightedMenuItem = 1; // which item is curently highlighted in the menu // Initialisation a la 1ere ligne
String menuItems[maxmenuItems+1]; // store for the menu item titles
uint32_t lastMenuActivity = 0; // time the menu last saw any activity (used for timeout)
// 'enter a value'
int32_t mValueEntered = 0; // store for number entered by value entry menu
int32_t mValueLow = 0; // lowest allowed value
int32_t mValueHigh = 0; // highest allowed value
int16_t mValueStep = 1; // step size when encoder is turned
};
oledMenus oledMenu;
// Variable pour SOUS SOUS-MENU DATE MENU -->> CONFIG DATE / HEURE
int16_t contenuDateNum[6] = {-1,-1,-1,-1,-1,-1};
//Coordonnées X et Y pour les differents champs Années, Mois, Jours, Heures, Minutes et Secondes
int8_t CoordXDate[8] = {48, 78, 96, 48, 66, 84, 0, 85 }; // position X pour les champs date/heure
int8_t CoordYDate[8] = {25, 25, 25, 40, 40, 40, 55, 55 }; // position Y pour les champs date/heure
String contenuDateStringVide[8] = {"----", "--", "--", "--", "--", "--", "Valider", "Annuler"}; // Valeur des champs pour l'initialisation
// days in each month: {jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec};
// Nbre jours du mois 0 1 2 3 4 5 6 7 8 9 10 11
int8_t NbreJourmonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // de Janvier(0) a Decembre(11)
int8_t countDateCligno = 0; // compteur pour inversion Flag FlagDateCligno apres 1 sec
bool FlagDateCligno = true; // Flag pour faire clignoter le champ date a modifier
int8_t leapYear = 0; // si c'est une annee bissextile
bool Flag_configchampDate = false; // Verif que tous les champs dates sont rempli
bool Flag_Manual_Date = false; // Flag pour prise en compte date manu
bool Flag_Y2038 = false; // Flag si timestamp negatif Rollover 2038
int8_t offsetDateY2038 = 0; // Offset de 56 ans -> retour en 1982 si Flag_Y2038 = TRUE
// NTP Flag SD card synchro heure NTP reçu
bool Flag_firstTimeUpdateNTP = false;
unsigned long previousWrite = 0; // Time pour eviter d'ecrire plusieurs fois les données
// Heure pour l'affichage d'accueil OLED
bool Flag_HeureAccueil = false; // FLAG Heure accueil pret
char HeureAccueil[3]; // Heure de l'accueil -> 23:xx [2]+1
char MinutAccueil[3]; // Minute de l'accueil -> xx:59 [2]+1
//char YearAccueil[5]; //BUG AVOIR demarrage affiche 1970
// FIN Variable pour SOUS SOUS-MENU DATE MENU -->> CONFIG DATE / HEURE
//Variable encodeur
// Encodeur Rotatif ENC_A (CLK) et ENC_B (DT)
volatile int32_t encoder0Pos = 0;
// Bouton ENC_SW
//stores if the switch was high before at all (PULLUP RESISTANCE)
volatile bool ENC_SW_state = HIGH;
//storing the button state for short press mode
volatile bool ENC_SW_state_short = LOW;
//storing the button state for long press mode
volatile bool ENC_SW_state_long = LOW;
//stores the time each button went high or low
volatile unsigned long current_Appu_ENC_SW;
volatile unsigned long last_Appu_ENC_SW;
volatile unsigned long current_Rela_ENC_SW;
// Compteur RPM IN_RPM pour interruption
volatile uint64_t last_RPM_interupt = 0; // Time 64 µSec // derniere interruption pour calcul periode
const uint8_t Nbre_echanti_RPM = 16; // Nombre d'echantillon pour affichage vitesse RPM
volatile uint64_t periode_RPM[Nbre_echanti_RPM] = {}; // tableau de 16 echantillon de periode pour RPM
volatile uint8_t count_Nbre_periode_RPM = 0; // compteur des 16 echantillions
volatile bool FlagFirstImpulsion_RPM = false; // Flag pour 1ere impulsion
volatile bool FlagAllImpulsionsPeriode_RPM = false; // Flag pour les 16 echantillions
bool FlagErrorMoteur_RPM = false; // Flag si le moteur (Ventilo) ne tourne pas en erreur bloqué ou autre
uint64_t timer_first_start_RPM = 0; // Timer 1er demarrage moteur apres etre OFF (MENU ou arret normal) fonctionne avec [FlagErrorMoteur_RPM]
// STEPER MOTOR : IRIS Interrupt
//stores if the switch was high before at all (PULLUP RESISTANCE)
volatile int8_t LSW_HOME_state = LOW;
volatile int8_t LSW_MAXTRAVEL_state = LOW;
//stores the time each button went high or low
volatile unsigned long current_Appu_LSW_HOME;
volatile unsigned long last_Appu_LSW_HOME;
volatile unsigned long current_Rela_LSW_HOME;
volatile bool FlagApp_LSW_HOME = false;
volatile unsigned long current_Appu_LSW_MAXTRAVEL;
volatile unsigned long last_Appu_LSW_MAXTRAVEL;
volatile unsigned long current_Rela_LSW_MAXTRAVEL;
volatile bool FlagApp_LSW_MAXTRAVEL = false;
bool flag_maxtravel = false; // Init valeur position maxtravel
bool flag_home = false; // Init valeur position home
bool flag_initIris = false; // Init position IRIS apres Init maxtravel et Init home
// STEPPER MOTEUR : IRIS
int16_t home = -STEP_PER_REVOLUTION;
int16_t maxtravel = STEP_PER_REVOLUTION;
// Diametre de l'IRIS de Diam 200 mm (Maxi) a Diam 85 mm (Mini)
uint8_t DiamIrisMaxi = 200;
uint8_t DiamIrisMini = 85; // A mesurer pour valeur reelle AVOIR
uint8_t NbreStepIris = DiamIrisMaxi - DiamIrisMini; // 200 - 85 -> 115 steps
float PasStepIris = 0; // maxtravel / NbreStepIris (nbre de pas pour 1mm IRIS)
// Flag deplacement STEPPER MOTEUR : IRIS
bool flag_auth_deplacement = false;
bool flag_PID_ON_OFF_IRIS = false; // Flag verouillage PID jusqu'a fin deplacement stepper si reinitialisation PID, stepper sup ou inf a HOME / MAXTRAVEL
bool flag_limite_maxtravel_depacement = false;
bool flag_limite_home_depacement = false;
// Flag Iris mode Manu (TRUE)/ Auto (FALSE) mode Auto (FALSE) au demarrage
bool flag_iris_manu_on_off = false;
// Marge haute et basse entre (limit switch HOME et [position home + marge]) et (limit switch MAXTRAVEL et [position maxtravel - marge])
int16_t INIT_MARGE = 144; // -> 1mm -> 100 +/- ( 3 * 48) -> 144 (3.5 * 48) -> 168
//Marge Flottante compensation jeux cremaillere IRIS
int16_t MARGE_FLOTTANTE = 864; // -> (16 * 48) -> 768, (17.5 * 48) -> 840, (18 * 48) -> 864
int8_t sensRotation = 1; // valeur 1 sens horraire, valeur -1 sens anti-horraire
int8_t prevSensRotation = 1; // valeur precedente pour savoir si le sens de rotation a change
int16_t oldStepperPosition = 0; // ancienne valeur pour ajour Marge Flottante
int16_t Steppercurrent = 0; // dans le menu
bool flag_sens_rotation_diff = false; // Flag changement direction
// Pourcentage Erreur toléré pour Erreur POSITION IRIS RE-INITIALISATION
int8_t POURC_ERR_IRIS = 5;
// Position de l'IRIS STEPPER MOTOR vers ou on va
int16_t PosIris = 0; // variable de commande du deplacement de l'IRIS
int16_t TempPosIris = 0; // valeur temporaire sortie PID
int16_t old_deplacement; // reference de l'ancien deplacement de l'IRIS permet de determiner si c'est une nouvelle valeur
// variable pour refresh OLED
unsigned long previousRefreshOled = 0;
unsigned long intervalRefreshOled = 500L; // toutes les 0.5 sec
// Variable des repertoires et nom fichier pour log data carte SD
char Repertoire[6] = "/data"; // 5 +1
char lastfile[19] = "/data/lastfile.txt"; // 18 +1
char Year[19]; // /data/2023 -> 10 +1
char YearMonth[31]; // /data/2023/08 -> 13 +1
char YearMonthDayFile[47]; // /data/2023/08/06.txt -> 20 +1
char DateHour[73]; // 2021-05-20T22:30:00 -> 19 +1
// PWM
int8_t pwmChannel = 0; // Choisit le canal 0
uint16_t frequence = 4000; // Fréquence PWM de 4 KHz (4000 Hz)
uint8_t resolution = 11; // Résolution de 8 bits -> 0 - 255 -> (256) valeurs possibles
// 9 bits -> 0 - 511 -> (512) valeurs possibles
// 10 bits -> 0 - 1023 -> (1024) valeurs possibles
// 11 bits -> 0 - 2047 -> (2048) valeurs possibles
// 12 bits -> 0 - 4095 -> (4096) valeurs possibles
uint16_t Vmaxpwm = 2047; // en fonction de la resolution pwm 10 bits -> 1023 etc..
// PWM tableau valeur des vitesses
const uint8_t Nbrevitesse = 21; // Nbre de vitesse pour le ventilateur MAX 20 [0 -> 19] (Affichage OLED) -> 21 pour Mode DEBUG [0 -> Vmaxpwm]
uint16_t VitesseVentil[Nbrevitesse] = {0, // Moteur ventilateur OFF nuit (0) -> NUIT (actuel)
811, //791, // 799, // Moteur ventilateur 900 tr/min (1)
//838, //823, // 832, // Moteur ventilateur 950 tr/min
867, //854, // 862, // Moteur ventilateur 1000 tr/min (2)
//898, //885, // 890, // Moteur ventilateur 1050 tr/min
929, //917, // 922, // Moteur ventilateur 1100 tr/min (3)
//959, //947, // 952, // Moteur ventilateur 1150 tr/min (Normalement TROP BAS 1163 tr/min)
987, //974, // 981, // Moteur ventilateur 1200 tr/min (4)
//1018, //1003, // 1013, // Moteur ventilateur 1250 tr/min -> 4.766 V
1045, //1032, // 1042, // Moteur ventilateur 1300 tr/min (5)
1075, //1059, // 1073, // Moteur ventilateur 1350 tr/min -> 5.06 V (6) (17.7 W)
1103, //1087, // 1102, // Moteur ventilateur 1400 tr/min (7)
1131, //1115, // 1130, // Moteur ventilateur 1450 tr/min jour -> 5.263 V (8) (20 W) -> JOUR (actuel)
1159, //1145, // 1158, // Moteur ventilateur 1500 tr/min -> 5.477 V (9) (19.9 W)
1187, //1174, // 1187, // Moteur ventilateur 1550 tr/min (10) (21.6 W)
1215, //1214, //1201, // 1219, // Moteur ventilateur 1600 tr/min-> 5.772 V (11) (24.1 W)
1243, //1226, // 1248, // Moteur ventilateur 1650 tr/min (12) (25.1 W)
1271, //1255, // 1277, // Moteur ventilateur 1700 tr/min -> 6.06 V (13) (27.1 W)
1299, //1283, // 1304, // Moteur ventilateur 1750 tr/min -> 6.355 V (14) (29.3 W)
1331, //1312, // 1332, // Moteur ventilateur 1800 tr/min -> 6.632 V (15) (31.5 W)
1360, //1341, // 1362, // Moteur ventilateur 1850 tr/min -> 6.91 V (16) (34 W)
1385, //1366, // Moteur ventilateur 1900 tr/min (17) (36.5 W)
1416, //1397, // Moteur ventilateur 1950 tr/min boost (18) (39.2 W) -> BOOST (actuel)
1442, //1424, // Moteur ventilateur 2000 tr/min (19) (43 W)
Vmaxpwm // Moteur ventilateur 2945 tr min MAX -> 10.038 V (20) (132W)
};
// choix des vitesses pour le mode Jour, Nuit et Boost
uint8_t Vit_nuit = 0; // SAUVE MEM ok
uint8_t Vit_jour = 8; // 7 + 1 // SAUVE MEM ok
uint8_t Vit_boost = 18; // SAUVE MEM ok
// Variable Vitesse dynamique du ventilateur
//Temperature
int16_t Temp_Vbase = 120; // Seuil Temperature de Base de 50 a 250 (5 a 25°C) INITIALE 12,0 °C
int8_t Temp_Vinte = 0; // Seuil Temp. Inter. de -50 a 50 (-5 a 5°C) INITIALE 0,0 °C
int16_t Temp_Vmini = -120; // Seuil Temp. Mini de -250 a -50 (-25 a -5°C) INITIALE -12,0 °C
int8_t Temp_offset = 0; // Offset de Temperature de -25 a 25 (-2,5 a 2,5°C) agit sur Temp_Vbase, Temp_Vinte et Temp_Vmini INITIALE 0,5 °C
float seuilTempB; // seuil debut augmentation vitesse 12°C + offset temperature
float seuilTempI; // seuil intermediaire augmentation vitesse 0°C + offset temperature
float seuilTempMi; // seuil fin augmentation vitesse -12°C + offset temperature
//Vitesse ventilateur
int8_t Vit_Tbase = 8; // Numero de la vitesse de Base de 6 a 9 INITIALE 7 + 1
int8_t Vit_Tinte = 12; // Numero de la vitesse Intermediaire de 9 a 14 INITIALE 12
int8_t Vit_Tmaxi = 14; // Numero de la vitesse Maximum de 13 a 16 INITIALE 14
int8_t Vit_offset = 0; // PWM Brut offset de 0 a 30 (valeur entre 2 vitesses) agit sur Vit_Tinte et Vit_Tmaxi INITIALE 15
int16_t seuilVitesseB; //1115; -> 1450 tr/min // Vitesse de base mode normale vers 12°C + offset vitesse
int16_t seuilVitesseI; //1226; -> 1650 tr/min // Vitesse intermediaire vers 0°C + offset vitesse
int16_t seuilVitesseMa; //1283; -> 1750 tr/min // Vitesse par grand froid vers -12°C + offset vitesse
int16_t vitesseDynamique = 0; // augmentation dynamique de la vitesse du ventilateur
int16_t prevvitesseDynamique = 0; // valeur precedente de la vitesseDynamique
int8_t NumDynVit = 0; // Variable pour recherche numero de vitesse dans tableau Affichage accueil (Mode dynamique)
bool Flag_vitesseDynamique_ON = false;
// Fin Variable Vitesse dynamique du ventilateur
bool flag_Debug_PWM_Ventilo = false; // Flag pour debug PWM de la vitesse du ventilo (VitesseVentil[Nbrevitesse-1]) si FALSE INACTIF, TRUE ACTIF
bool flag_Nbrevitesse_exist = false; // Flag si valeur trouve dans tableau si TRUE num vitesse si FALSE PWM BRUTE
/*
Moteur ventilateur 1 -> 0 -> 0 tr min (OFF)
Moteur ventilateur 1 -> 968 -> 1163 tr min 4.5V (TROP BAS)
Moteur ventilateur 1 -> 1075 -> 1344 tr min 5V
Moteur ventilateur 2 -> 1179 -> 1501 tr min 5.5V
Moteur ventilateur 3 -> 1278 -> 1681 tr min 6V (Nuit)
Moteur ventilateur 4 -> 1377 -> 1885 tr min 6.5 V
Moteur ventilateur 5 -> 1476 -> 2066 tr min 7v (Jour)
Moteur ventilateur 6 -> 1526 -> 2159 tr min 7.252V (Jour Initial TROP HAUT)
Moteur ventilateur 7 -> 1574 -> 2252 tr min 7.5v
Moteur ventilateur 8 -> 1673 -> 2439 tr min 8V (Boost)
Moteur ventilateur 9 -> 1771 -> 2625 tr min 8.5V
Moteur ventilateur 10 -> 1869 -> 2814 tr min 9V
Moteur ventilateur 11 -> 1966 -> 3000 tr min 9.5V
Moteur ventilateur 12 -> 2047 -> 3017 tr min 10.038V (Max)
*/
// Compteur RPM et PWM
uint16_t pwm = VitesseVentil[0]; // valeur pour vitesse moteur (0-2047 pour 11 bits) INIT à ZERO moteur ARRET
uint32_t rpm = 0; // vitesse moteur tr/min
// Ancien pwm
uint16_t prevpwm = 0;
int8_t prevCorrectionPwm = 0; // ancienne correction pwm
int8_t correctionPwm = 0; // correction pwm si RPM sup ou inf a RPM Reference
uint16_t oldrpm = 0; // ancien rpm
// Compteur pour refresh valeur RPM et PWM (LOOP)
uint64_t last_RPM_refresh = 0; // Time 64 µSec // dernier temps du run (Toutes les secondes)
// modes du ventilateur
enum modeVentilateur {
off_ventilo, // ventilo -> mode OFF
nuit, // ventilo -> mode Nuit (Heure -> 23:30)
jour, // ventilo -> mode Jour (Heure -> 07:00)
boost, // ventilo -> mode Boost (Temps enmode Boost -> 2:00 heures)
manu // ventilo -> mode Manuel
};
modeVentilateur modeVentilo = off_ventilo; // default mode at startup is off
String etatVentilo = " "; // Pour fichier Log (Statut du mode du ventilateur) // Reserve 6 caractere
// Flag ventilo etat ON au demarrage
bool flag_ventilo_on_off = true;
// Flag ventilo mode Boost OFF au demarrage
bool flag_ventilo_boost_on_off = false;
// Flag ventilo mode Manu (TRUE)/ Auto (FALSE) mode auto (FALSE) au demarrage
bool flag_ventilo_manu_on_off = false;
// Timer mode Boost ventilateur
unsigned long timerModeBoost = 0;
// mode Jour / Nuit ventilateur et Boost
#define HMS(h,m,s) ((long)(h)*60L*60L + (long)(m)*60 + (long)(s))
long START_MODE_JOUR = HMS(7,45,0); // SAUVE MEM ok
long START_MODE_NUIT = HMS(0,00,0); // SAUVE MEM ok
long TIMER_MODE_BOOST = HMS(1,00,0); // SAUVE MEM ok
// Ecran accueil OLED
int8_t countErrorswitch = 0; // compteur pour inversion Flag FlagErrorswitc apres 2 sec
bool FlagErrorswitch = true; // Flag pour commuter les erreurs moteur ou sondes temperature
// Restart ESP32 Menu
unsigned long timerRestartESP = 0; // Timer delais (10 sec)
bool flag_restart_esp = false; // Flag autorisation Restart
// Time pour durée du SETUP et de la LOOP
unsigned long timesetup = 0;
unsigned long timeloop = 0;
// Ram
//uint32_t MiniFreeHeap; // AVOIR
size_t MiniFreeHeap;
unsigned long lastTimeRequestRamStatus = 0;
// Variable ESP32 UP (Temps démarré)
String Uptime = " "; //Reserve 30 caracteres
// WEBSERVER
// Search for parameter in HTTP POST request
const char* PARAM_IN_SSID = "ssid";
const char* PARAM_IN_PASS = "pass";
const char* headerlight = "<!DOCTYPE html>"
"<html>"
"<head>"
"<meta charset=\"UTF-8\">"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
"<link rel=\"icon\" href=\"data:,\">"
"<title id=\"title\">ESP32 Interface Web</title>"
"</head>"
"<body>";
const char* headerDeb = "<!DOCTYPE html>"
"<html>"
"<head>"
"<meta charset=\"UTF-8\">"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
//"<link rel=\"shortcut icon\" href=\"#\" />"
//"<link rel=\"icon\" href=\"data:;base64,iVBORw0KGgo=\" />"
"<link rel=\"icon\" href=\"data:,\">"
//"<link rel=\"icon\" href=\"#\" />"
"<style>";
const char* headerFin = "</style>"
"<title id=\"title\">ESP32 Interface Web</title>"
"</head>"
"<body>";
const char* styleMenu = "nav{"
" margin: auto auto auto -40px;" // margin: 0px auto 40px auto;"
" background-color: white;"
" position: static;" // position: sticky;
//" top: 0px;" // AVOIR SERT A RIEN
"}"
"nav ul{"
" list-style-type: none;"
"}"
"nav li{"
" font-size: 2rem;"
" font-weight: bolder;"
" float: left;"
" width: 25%;"
" text-align: center;"
" height: 55px;"
"}"
"nav ul::after{"
//" content: \"\";"
" display: table;"
" clear: both;"
"}"
"nav a{"
" display: block;"
" text-decoration: none;"
" color: black;"
" border-bottom: 2px solid transparent;"
" padding: 0 0 10px 0;"
"}"
"nav a:hover{"
" color: #fe5815;"
" border-bottom: 2px solid orange;"
" padding: 0 0 10px 0;"
"}"
"h1 {"
//" border-bottom: 2px solid #6a6a6a;"
" margin-bottom: 10px;"
//" padding-bottom: 10px;"
" white-space: nowrap;"
" display: list-item;"
" margin-left: 1em;"
"}";
const char* styledata = "table {"
" border-collapse: collapse;"
" font-size: 1.2rem;"
//" display: table;"
" table-layout: fixed;"
" width: 450px;"
"}"
"th {"
" cursor: pointer;"
//" width: 100%;"
"}"
"td.detailsColumn {"
//" padding-left: 2em;"
" text-align: center;"
" white-space: nowrap;"
"}"
"a.icon {"
" padding-left: 1.5em;"
" text-decoration: none;"
"}"
"a.icon:hover {"
" text-decoration: underline;"
"}"
"a.file {"
" background : url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC \") left center no-repeat;"
"}"
"a.dir {"
" background : url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= \") left center no-repeat;"
"}"
"a.up {"
" background : url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU0toU0EUPfPysx/tTxuDH9SCWhUDooIbd7oRUUTMouqi2iIoCO6lceHWhegy4EJFinWjrlQUpVm0IIoFpVDEIthm0dpikpf3ZuZ6Z94nrXhhMjM3c8895977BBHB2PznK8WPtDgyWH5q77cPH8PpdXuhpQT4ifR9u5sfJb1bmw6VivahATDrxcRZ2njfoaMv+2j7mLDn93MPiNRMvGbL18L9IpF8h9/TN+EYkMffSiOXJ5+hkD+PdqcLpICWHOHc2CC+LEyA/K+cKQMnlQHJX8wqYG3MAJy88Wa4OLDvEqAEOpJd0LxHIMdHBziowSwVlF8D6QaicK01krw/JynwcKoEwZczewroTvZirlKJs5CqQ5CG8pb57FnJUA0LYCXMX5fibd+p8LWDDemcPZbzQyjvH+Ki1TlIciElA7ghwLKV4kRZstt2sANWRjYTAGzuP2hXZFpJ/GsxgGJ0ox1aoFWsDXyyxqCs26+ydmagFN/rRjymJ1898bzGzmQE0HCZpmk5A0RFIv8Pn0WYPsiu6t/Rsj6PauVTwffTSzGAGZhUG2F06hEc9ibS7OPMNp6ErYFlKavo7MkhmTqCxZ/jwzGA9Hx82H2BZSw1NTN9Gx8ycHkajU/7M+jInsDC7DiaEmo1bNl1AMr9ASFgqVu9MCTIzoGUimXVAnnaN0PdBBDCCYbEtMk6wkpQwIG0sn0PQIUF4GsTwLSIFKNqF6DVrQq+IWVrQDxAYQC/1SsYOI4pOxKZrfifiUSbDUisif7XlpGIPufXd/uvdvZm760M0no1FZcnrzUdjw7au3vu/BVgAFLXeuTxhTXVAAAAAElFTkSuQmCC \") left center no-repeat;"
"}"
"html[dir=rtl] a {"
" background-position-x: right;"
"}"
"#parentDirLinkBox {"
" margin-bottom: 10px;"
" padding-bottom: 10px;"
" font-size: 1.2rem;"
" font-weight: bold;"
"}"
"#listingParsingErrorBox {"
" border: 1px solid black;"
" background: #fae691;"
" padding: 10px;"
" display: none;"
"}"
"button, input, input::file-selector-button {"
" font-size: 1.0rem;"
"}"
"button, input::file-selector-button {"
" border-radius: 5px;"
"}"
"input::file-selector-button:hover, button:hover{"
" background-color: #fe5815;"
"}";
const char* stylewifi = ".card {"
" padding-left: 15px;"
"}"
"input[type=submit] {"
" padding-top: 1px;"
" padding-bottom: 5px;"
" text-align: center;"
" text-decoration: none;"
" display: inline-block;"
" font-size: 1rem;"
" width: 90px;"
" border-radius: 4px;"
" transition-duration: 0.4s;"
"}"
"input[type=submit]:hover {"
" background-color: #fe5815;"
"}"
"input[type=text], input[type=number], select {"
" width: 50%;"
" padding: 12px 20px;"
" margin: 10px;"
" border: 1px solid #ccc;"
" border-radius: 4px;"
"}"
"input[type=text]:focus-visible {"
" border: 2px solid #fe5815;"
" outline: none;"
"}"
"label {"
" font-size: 1.2rem; "
" width: 75px;"
" display: inline-block;"
"}";
const char* styleetat = ".topnav{"
" margin-top: 21px;"
" margin-bottom: 11px;"
"}"
".topnav h1{"
" display: inline list-item;"
" margin-left: 0;"
"}"
".topnav span {"
" margin-left: 50px;"
" font-size: 1.2rem;"
" font-weight: bold;"
"}"
"#uptime {"
" margin-left: 0px;"
" color: #034078;"
"}"
"span.timer {"
" display: none;"
" left: 50px;"
" position: relative;"
" font-size: 1.2rem;"
" font-weight: bold;"
"}"
"#timerb {"
" color: #034078;"
" margin-left: 5px;"
"}"
".content {"
" padding: 0 20px 0 20px;"
" max-width: 2616px;"
"}"
".card2-grid-h2 {"
" text-align: left;"
" margin-top: -5px;"
" margin-bottom: 10px;"
"}"
".card2-grid {"
" max-width: 2616px;"
" margin: 0 auto 30px auto;"
" display: grid;"
" grid-gap: 12px;"
" grid-template-columns: repeat(auto-fit, minmax(250px, 280px));"
" text-align: center;"
"}"
".card2 {"
" background-color: white;"
" box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);"
" position: relative;"
" height: 125px;"
"}"
".card2-title {"
" font-size: 1.2rem;"
" font-weight: bold;"
" color: #034078;"
" width: 100%;"
" height: 45px;"
" display: table;"
" margin-top: 10px;"
"}"
".card2-title span {"
" vertical-align: middle;"
" display: table-cell;"
" padding: 0 10px;"
"}"
".reading {"
" font-size: 1.4rem;"
" color: limegreen;"
" position: absolute;"
" bottom: 17px;"
" width: 100%;"
//" color: #1282A2;" //Couleur Bleu origine
"}"
//slider choix
".cursor {"
" display: flex;"
" justify-content: center;"
" margin-bottom: 8px;"
" position: absolute;"
" bottom: 0px;"
" width: 100%;"
"}"
"#manuIris, #manuVenti {"
" display: none;"
"}"
"#manuIrisN, #manuVentiN {"
" display:none;"
" top:40px;"
"}"
".btcursor {"
" width: 26px;"
" height: 26px;"
//" text-align: center;"
" border-radius: 50%;"
" font-weight: bold;"
" font-size: 1.0rem;"
" padding-bottom: 22px;"
"}"
".valcursor {"
" margin-left: 20px;"
" border-radius: 20%;"
" font-weight: bold;"
"}"
"input[type=button]:hover {"
" background-color: #fe5815;"
"}"
"input[type=range] {"
" accent-color: orange;"
"}"
//Fin slider choix
".boost{"
" margin-left: 50px;"
"}"
//Fin Temperature
//Debut Bouton ON / OFF
".switch input{"
" display: none;"
"}"
".switch {"
" display: inline-block;"
" width: 120px;"
" height: 30px;"
" position: relative;"
" text-align: center;"
" left: 30px;"
" top: 6px;"
"}"
".slider {"
" position: absolute;"
" top: 0;"
" bottom: 0;"
" left: 0;"
" right: 0;"
" border-radius: 30px;"
" box-shadow: 0 0 0 2px red, 0 0 8px red;"
" border: 4px solid transparent;"
" transition: 0.2s;"
"}"
".slider:before {"
" position: absolute;"
" content: attr(data-off);"
" width: 70px;"
" background-color: red;"
" border-radius: 30px;"
" transition: 0.2s;"
" color: white;"
" left: 0px;"
"}"
"input:checked + .slider:before {"
" content: attr(data-on);"
" transform: translateX(42px);" //translateX(w-h)
" background-color: limeGreen;"
"}"
"input:checked + .slider"
"{"
" box-shadow: 0 0 0 2px limeGreen, 0 0 8px limeGreen;"
"}"
"label {"
" font-size: 1.2rem; "
"}"
// SVG
".content3 {"
" max-width: 950px;"
"}"
".card3-grid {"
" margin: -10px auto 30px auto;"
" display: grid;"
" text-align: center;"
"}"
".card3 {"
" background-color: white;"
" box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);"
" position: relative;"
" height: 325px;"
" width: 950px;"
"}"
".card3-title {"
" font-size: 1.2rem;"
" font-weight: bold;"
" color: #034078;"
" height: 10px;"
" margin-top: 0px;"
" padding-right: 40px;"
"}"
".cursor3 {"
" display: flex;"
" margin-bottom: 8px;"
"}"
".titre3 {"
" height: 0px;"
" position: relative;"
" margin-top: 0px;"
" margin-bottom: 0;"
" font-weight: bold;"
" color: #034078;"
" left: 25px;"
" text-align: left;"
"}"
".val3 {"
" height: 0px;"
" padding-right: 80px;"
" font-weight: bold;"
" color: limegreen;"
" display: block;"
" text-align: right;"
"}"
".table3 {"
" position: absolute;"
" bottom: 0px;"
" margin-left: 350px;"
" border-collapse: separate;"
" border-spacing: 23px 5px;"
"}"
".svg {"
" position: absolute;"
" bottom: 0px;"
" width: 350px;"
" height: 200px;"
"}"
".svg2 {"
" position: absolute;"
" bottom: 10px;"
" left: 10px;"
" width: 350px;"
" height: 200px;"
"}"
".cadre {"
" fill: white;"
" stroke: #034078;"
" stroke-width: 2px;"
"}"
".axe {"
" fill: none;"
" stroke: black;"
" stroke-width: 1px;"
"}"
".valaxe {"
" dominant-baseline: middle;"
" text-anchor: middle;"
"}"
".valaxe1 {"
" dominant-baseline: middle;"
" text-anchor: middle;"
" font-size: 1.0rem;"
" font-weight: bold;"
" fill: #034078;"
"}"
".courbe {"
" fill: none;"
" stroke: red;"
" stroke-width: 1px;"
"}";
const char* styleconf = ".conteneur{"
" margin: 0px 20px;"
" height: 1500px;"
"}";
const char* stylemedia = "@media only screen and (max-width: 721px) {"
"h1 {"
" font-size: 1.4rem;"
" margin-bottom: 10px;"
" white-space: nowrap;"
"}"
"h2 {"
" font-size: 1.2rem;"
"}"
".card2-grid {"
" grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));"
//" justify-content: center;" //AVOIR
"}"
".switch {"
" margin-block: 2px;"
" top: 8px;"
" left: 15px;"
"}"
"nav li{"
" font-size: 1.5rem;"
" font-weight: bolder;"
" float: left;"
" width: 25%;"
" text-align: center;"
" height: 45px;"
"}"
".topnav{"
" margin-top: 0;"
" margin-bottom: 0;"
"}"
" .topnav h1{"
" display: list-item;"
" margin-left: 1em;"
"}"
" .topnav span {"
" margin-left: 10px;"
" font-size: .9rem;"
"}"
"}"
"@media only screen and (max-width: 361px) {"
".boost {"
" margin-left: 0px;"
"}"
"}";
const char* menuhtml = "<nav>"
"<ul>"
"<li><a href='/etat'>Etat</a></li>"
"<li><a href='/data'>SDCard</a></li>"
"<li><a href='/wifi'>Wifi</a></li>"
"<li><a href='/config'>Config</a></li>"
"</ul>"
"</nav>"
"<hr>";
const char* wifipage = "<div class=\"topnav\">"
"<h1 id=\"header\">ESP Wi-Fi Manager</h1>"
"</div>"
"<hr>"
"<div class=\"card\">"
"<form action='/wifi' method='POST'>"
"<p>"
"<label for=\"ssid\">SSID</label>"
"<input type=\"text\" id =\"ssid\" name=\"ssid\"><br>"
"<label for=\"pass\">Clé Wifi</label>"
"<input type=\"text\" id =\"pass\" name=\"pass\"><br>"
"<input type =\"submit\" value =\"Enregistrer\">"
"</p>"
"</form>"
"</div>";
const char* footer = "<hr>"
"</body>"
"</html>";
const char* script = "<script>function sortTable(l){var e=document.getElementById('theader'),n=e.cells[l].dataset.order||'1',s=0-(n=parseInt(n,10));e.cells[l].dataset.order=s;var t,a=document.getElementById('tbody'),r=a.rows,d=[];for(t=0;t<r.length;t++)d.push(r[t]);for(d.sort(function(e,t){var a=e.cells[l].dataset.value,r=t.cells[l].dataset.value;return l?(a=parseInt(a,10),(r=parseInt(r,10))<a?s:a<r?n:0):r<a?s:a<r?n:0}),t=0;t<d.length;t++)a.appendChild(d[t])}</script>";
const char* scriptEtat = "<script>var websocket,gateway=`ws://${window.location.hostname}/ws`;window.addEventListener('load',onload);var Vit=[0,811,867,929,987,1045,1075,1103,1131,1159,1187,1215,1243,1271,1299,1331,1360,1385,1416,1442,2047];function onload(e){initWebSocket()}function initWebSocket(){console.log('Trying to open a WebSocket connection…'),(websocket=new WebSocket(gateway)).onopen=onOpen,websocket.onclose=onClose,websocket.onmessage=onMessage}function onOpen(e){console.log('Connection opened'),getReadings()}function getReadings(){websocket.send(JSON.stringify({getReadings:!0}))}function onClose(e){console.log('Connection closed'),setTimeout(initWebSocket,2e3)}function onMessage(e){console.log(e.data+' ,taille : '+e.data.length);for(var t=JSON.parse(e.data),n=Object.keys(t),l=0;l<n.length;l++){var m=n[l];if('onoff'==m||'Vboost'==m)document.getElementById(m+'_slid').style.boxShadow='',1==parseInt(t[m])?(document.getElementById(m).checked=!0,'Vboost'==m&&(document.getElementsByClassName('timer')[0].style.display='inline-block',document.getElementsByClassName('timer')[1].style.display='inline-block')):(document.getElementById(m).checked=!1,'Vboost'==m&&(document.getElementsByClassName('timer')[0].style.display='none',document.getElementsByClassName('timer')[1].style.display='none'));else if('Vmanuauto'==m||'Imanuauto'==m)document.getElementById(m+'_slid').style.boxShadow='',1==parseInt(t[m])?(document.getElementById(m).checked=!1,'Imanuauto'==m?(document.getElementById('manuIris').style.display='flex',document.getElementById('manuIrisT').style.marginTop='-5px',document.getElementById('manuIrisO').style.top='10px',document.getElementById('manuIrisN').style.display='inherit'):(document.getElementById('manuVenti').style.display='flex',document.getElementById('manuVentiT').style.marginTop='-5px',document.getElementById('manuVentiO').style.top='10px',document.getElementById('manuVentiN').style.display='inherit')):(document.getElementById(m).checked=!0,'Imanuauto'==m?(document.getElementById('manuIris').style.display='none',document.getElementById('manuIrisT').style.marginTop='',document.getElementById('manuIrisO').style.top='',document.getElementById('manuIrisN').style.display='none'):(document.getElementById('manuVenti').style.display='none',document.getElementById('manuVentiT').style.marginTop='',document.getElementById('manuVentiO').style.top='',document.getElementById('manuVentiN').style.display='none'));else if('uptime'==m||'timerb'==m)document.getElementById(m).innerHTML=Tup(parseInt(t[m]));else if('Smoteur'==m||'Schaud'==m||'Sfroid'==m||'Sext'==m)document.getElementById(m).style.color='red',-127==parseFloat(t[m])?document.getElementById(m).innerHTML='Err.-127':-85==parseFloat(t[m])?document.getElementById(m).innerHTML='Err. +85':(document.getElementById(m).style.color='',document.getElementById(m).innerHTML=parseFloat(t[m]).toFixed(2).replace('.',',')+' °C');else if('SetpointPID'==m)document.getElementById(m).innerHTML=parseFloat(t[m]).toFixed(2).replace('.',',')+' °C';else if('ConsignePID'==m||'ConsignePID_coupure'==m||'Temp_ON_moteur'==m||'Hyst_Temp_ON_moteur'==m||'Temp_OFF_moteur'==m)document.getElementById(m).value=parseFloat(t[m]).toFixed(2),document.getElementById('va_'+m).innerHTML=parseFloat(t[m]).toFixed(2).replace('.',',')+' °C',document.getElementById('va_'+m).style.color='';else if('Vit_jour'==m||'Vit_nuit'==m||'Vit_boost'==m||'VitManu'==m)document.getElementById(m).value=parseInt(t[m]),document.getElementById('va_'+m).innerHTML=parseInt(t[m]),document.getElementById('va_'+m).style.color='';else if('PosManu'==m)document.getElementById(m).value=parseInt(t[m]),document.getElementById('va_'+m).innerHTML='⌀ '+parseInt(t[m])+' mm',document.getElementById('va_'+m).style.color='';else if('Temp_Vbase'==m||'Temp_Vinte'==m||'Temp_Vmini'==m||'Temp_offset'==m){if(document.getElementById(m).value=parseFloat(t[m]).toFixed(2),'Temp_offset'==m){var i=parseFloat(t[m]),y=parseFloat(document.getElementById('Temp_Vbase').value)+i,a=parseFloat(document.getElementById('Temp_Vinte').value)+i,d=parseFloat(document.getElementById('Temp_Vmini').value)+i;document.getElementById('gr_'+m).innerHTML=i.toFixed(2).replace('.',',')+' °C',document.getElementById('gr_Temp_Vbase').innerHTML=y.toFixed(2).replace('.',','),document.getElementById('gr_Temp_Vinte').innerHTML=a.toFixed(2).replace('.',','),document.getElementById('gr_Temp_Vmini').innerHTML=d.toFixed(2).replace('.',',')}else{var r=parseFloat(document.getElementById('Temp_offset').value)+parseFloat(t[m]);document.getElementById('gr_'+m).innerHTML=r.toFixed(2).replace('.',',')}document.getElementById('va_'+m).innerHTML=parseFloat(t[m]).toFixed(2).replace('.',',')+' °C',document.getElementById('va_'+m).style.color='',cordxy(Xval(),Yval())}else if('Vit_Tbase'==m||'Vit_Tinte'==m||'Vit_Tmaxi'==m||'Vit_offset'==m){if(document.getElementById(m).value=parseInt(t[m]),'Vit_offset'==m){var s=parseInt(t[m]),g=parseInt(document.getElementById('Vit_Tbase').value),o=parseInt(document.getElementById('Vit_Tinte').value),I=parseInt(document.getElementById('Vit_Tmaxi').value);document.getElementById('gr_'+m).innerHTML=s+' %',document.getElementById('gr_Vit_Tbase').innerHTML=pwmTotrmin(Vit[g]+offsetNormalisation(g,s)),document.getElementById('gr_Vit_Tinte').innerHTML=pwmTotrmin(Vit[o]+offsetNormalisation(o,s)),document.getElementById('gr_Vit_Tmaxi').innerHTML=pwmTotrmin(Vit[I]+offsetNormalisation(I,s)),document.getElementById('va_'+m).innerHTML=s+' %'}else{s=parseInt(t[m]);var E=parseInt(document.getElementById('Vit_offset').value);document.getElementById('gr_'+m).innerHTML=pwmTotrmin(Vit[s]+offsetNormalisation(s,E)),document.getElementById('va_'+m).innerHTML=s}document.getElementById('va_'+m).style.color='',cordxy(Xval(),Yval())}else if('TMB'==m||'HMJ'==m||'HMN'==m){document.getElementById(m).value=parseInt(t[m]);var B=parseInt(t[m])/3600,T=parseInt(t[m])%3600/60;document.getElementById('va_'+m).innerHTML=T<10?parseInt(B)+':0'+parseInt(T):parseInt(B)+':'+parseInt(T),document.getElementById('va_'+m).style.color=''}else'pwm'==m||'CorrPwm'==m||('rpm'==m?Number.isInteger(parseInt(t[m]))?(document.getElementById(m).style.color='',document.getElementById(m).innerHTML=t[m]+' Tr/min'):(document.getElementById(m).style.color='red',document.getElementById(m).innerHTML='Err. Moteur'):document.getElementById(m).innerHTML=t[m])}}function updateSlider(e){var t=e.id;inSlider(t,parseFloat(document.getElementById(t).value),parseFloat(document.getElementById(t).step))}function updownSlider(e){var t=e.id.slice(3),n=parseFloat(document.getElementById(t).value),o=parseFloat(document.getElementById(t).min),i=parseFloat(document.getElementById(t).max),m=parseFloat(document.getElementById(t).step);e.id=='mo_'+t?(n-=m)<o&&(n=o):e.id=='pl_'+t&&(n+=m)>i&&(n=i),document.getElementById(t).value=n,inSlider(t,n,m)}function inSlider(e,t,n){if(n<1)if('Temp_Vbase'==e||'Temp_Vinte'==e||'Temp_Vmini'==e||'Temp_offset'==e){if('Temp_offset'==e){var m=parseFloat(document.getElementById('Temp_Vbase').value)+t,i=parseFloat(document.getElementById('Temp_Vinte').value)+t,a=parseFloat(document.getElementById('Temp_Vmini').value)+t;document.getElementById('gr_'+e).innerHTML=t.toFixed(2).replace('.',',')+' °C',document.getElementById('gr_Temp_Vbase').innerHTML=m.toFixed(2).replace('.',','),document.getElementById('gr_Temp_Vinte').innerHTML=i.toFixed(2).replace('.',','),document.getElementById('gr_Temp_Vmini').innerHTML=a.toFixed(2).replace('.',',')}else{var r=parseFloat(document.getElementById('Temp_offset').value)+t;document.getElementById('gr_'+e).innerHTML=r.toFixed(2).replace('.',',')}document.getElementById('va_'+e).innerHTML=t.toFixed(2).replace('.',',')+' °C',cordxy(Xval(),Yval())}else document.getElementById('va_'+e).innerHTML=t.toFixed(2).replace('.',',')+' °C';else if('TMB'==e||'HMJ'==e||'HMN'==e){var d=t/3600,o=t%3600/60;document.getElementById('va_'+e).innerHTML=o<10?parseInt(d)+':0'+parseInt(o):parseInt(d)+':'+parseInt(o)}else if('PosManu'==e)document.getElementById('va_'+e).innerHTML='⌀ '+parseInt(t)+' mm';else if('Vit_Tbase'==e||'Vit_Tinte'==e||'Vit_Tmaxi'==e||'Vit_offset'==e){var l=parseInt(t);if('Vit_offset'==e){var s=parseInt(document.getElementById('Vit_Tbase').value),T=parseInt(document.getElementById('Vit_Tinte').value),_=parseInt(document.getElementById('Vit_Tmaxi').value);document.getElementById('gr_'+e).innerHTML=l+' %',document.getElementById('gr_Vit_Tbase').innerHTML=pwmTotrmin(Vit[s]+offsetNormalisation(s,l)),document.getElementById('gr_Vit_Tinte').innerHTML=pwmTotrmin(Vit[T]+offsetNormalisation(T,l)),document.getElementById('gr_Vit_Tmaxi').innerHTML=pwmTotrmin(Vit[_]+offsetNormalisation(_,l)),document.getElementById('va_'+e).innerHTML=l+' %'}else{var p=parseInt(document.getElementById('Vit_offset').value);document.getElementById('gr_'+e).innerHTML=pwmTotrmin(Vit[l]+offsetNormalisation(l,p)),document.getElementById('va_'+e).innerHTML=l}cordxy(Xval(),Yval())}else document.getElementById('va_'+e).innerHTML=parseInt(t);document.getElementById('va_'+e).style.color='#005bff'}function validSlider(e){var t={},n=e.id.slice(3);t['ws'+n]='ConsignePID'==n||'ConsignePID_coupure'==n||'Temp_ON_moteur'==n||'Hyst_Temp_ON_moteur'==n||'Temp_OFF_moteur'==n||'Temp_Vbase'==n||'Temp_Vinte'==n||'Temp_Vmini'==n||'Temp_offset'==n?parseFloat(document.getElementById(n).value):parseInt(document.getElementById(n).value),document.getElementById('va_'+n).style.color='red',console.log(JSON.stringify(t)+' ,taille : '+JSON.stringify(t).length),websocket.send(JSON.stringify(t))}function handleClick(e){var t={},n=e.id;t['ws'+n]='Vmanuauto'==n||'Imanuauto'==n?!e.checked:e.checked,document.getElementById(n+'_slid').style.boxShadow='0 0 0 2px #005bff, 0 0 8px #005bff',console.log(JSON.stringify(t)+' ,taille : '+JSON.stringify(t).length),websocket.send(JSON.stringify(t))}function pwmTotrmin(e){if(e<Vit[1]);else{if(e>=Vit[1]&&e<Vit[2])return Math.round(1.7857*e-548.21);if(e>=Vit[2]&&e<Vit[3])return Math.round(1.6129*e-398.39);if(e>=Vit[3]&&e<Vit[5])return Math.round(1.7241*e-501.72);if(e>=Vit[5]&&e<Vit[6])return Math.round(1.6666*e-441.67);if(e>=Vit[6]&&e<Vit[14])return Math.round(1.7857*e-569.64);if(e>=Vit[14]&&e<Vit[15])return Math.round(1.5625*e-279.69);if(e>=Vit[15]&&e<Vit[16])return Math.round(1.7241*e-494.83);if(e>=Vit[16]&&e<Vit[17])return 2*e-870;if(e>=Vit[17]&&e<Vit[18])return Math.round(1.6129*e-333.87);if(e>=Vit[18]&&e<=Vit[19])return Math.round(1.9231*e-773.08)}return 0}function offsetNormalisation(e,t){return 0==t?0:t>0?Math.round((Vit[e+1]-Vit[e])*t/100):Math.round((Vit[e]-Vit[e-1])*t/100)}function Xval(){var e=parseFloat(document.getElementById('Temp_Vbase').value),t=parseFloat(document.getElementById('Temp_Vinte').value),n=parseFloat(document.getElementById('Temp_Vmini').value),o=e-n;return 60+Math.round(235/o*(o-(t-n)))}function Yval(){var e=parseInt(document.getElementById('Vit_Tbase').value),t=parseInt(document.getElementById('Vit_Tinte').value),n=parseInt(document.getElementById('Vit_Tmaxi').value);return 30+Math.round(126-126*(Vit[t]-Vit[e])/(Vit[n]-Vit[e]))}function cordxy(e,t){var n=document.getElementById('polygraph');n.points[1].x=e,n.points[1].y=t;var o=document.getElementById('CoAxeX');o.setAttribute('x1',e),o.setAttribute('x2',e);var i=document.getElementById('CoAxeY');i.setAttribute('y1',t),i.setAttribute('y2',t),document.getElementById('gr_Temp_Vinte').setAttribute('x',e),document.getElementById('gr_Vit_Tinte').setAttribute('y',t)}function Tup(e){let d=Math.floor(e/86400),h=Math.floor(e%86400/3600),m=Math.floor(e%3600/60);if(e>0&&d===0&&h===0&&m===0){return\"Moins d'une minute\"}else{return(d>0?d+' Jour'+(1===d?'':'s')+(h>0||m>0?', ':''):'')+(h>0?h+' Heure'+(1===h?'':'s')+(m>0?', ':''):'')+(m>0?m+' Minute'+(1===m?'':'s'):'')}}</script>";
String uploadPath = " "; //Reserve 50 caracteres
// "/data/2024/03/31.txt" // ici 20 caracteres
// *************************************
// ******* FONCTION INTERRUPTION *******
// *************************************
// Encodeur ENC_A et ENC_B INTERRUPTION
void IRAM_ATTR read_encoder() {
// Encoder interrupt routine for both pins. Updates encoder0Pos
// if they are valid and have rotated a full indent
static uint8_t old_AB = 3; // Lookup table index
static int8_t encval = 0; // Encoder value
static const int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; // Lookup table
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
old_AB <<=2; // Remember previous state
if (digitalRead(ENC_A)) old_AB |= 0x02; // Add current state of pin A
if (digitalRead(ENC_B)) old_AB |= 0x01; // Add current state of pin B
encval += enc_states[( old_AB & 0x0f )];
// Update encoder0Pos if encoder has rotated a full indent, that is at least 4 steps
if( encval > 3 ) { // Four steps forward
if (interruptTime - lastInterruptTime > 40) { // Greater than 40 milliseconds
encoder0Pos ++; // Increase by 1
} else if (interruptTime - lastInterruptTime > 20){ // Greater than 20 milliseconds
encoder0Pos += 3; // Increase by 3
} else { // Faster than 20 milliseconds
encoder0Pos += 10; // Increase by 10
}
encval = 0;
lastInterruptTime = millis(); // Remember time
}
else if( encval < -3 ) { // Four steps backwards
if (interruptTime - lastInterruptTime > 40) { // Greater than 40 milliseconds
encoder0Pos --; // Increase by 1
} else if (interruptTime - lastInterruptTime > 20){ // Greater than 20 milliseconds
encoder0Pos -= 3; // Increase by 3
} else { // Faster than 20 milliseconds
encoder0Pos -= 10; // Increase by 10
}
encval = 0;
lastInterruptTime = millis(); // Remember time
}
}
// Bouton ENC_SW INTERRUPTION
//is called when the Interrupt Pin is pressed or released (CHANGE Mode)
void IRAM_ATTR read_button() {
//if this is true the button was just pressed down (HIGH quand non appuyé)
if ((digitalRead(ENC_SW) == LOW) && ENC_SW_state == HIGH) {
//note the time the button was pressed
current_Appu_ENC_SW = millis();
if((current_Appu_ENC_SW - last_Appu_ENC_SW) > 10 ) { // si sup à 25ms
last_Appu_ENC_SW = current_Appu_ENC_SW;
ENC_SW_state = LOW;
//ets_printf("APPUYER ENC_SW\n");
}
}
//if no button is high one had to be released.
//The millis function will increase while a button is hold down the loop function will be cycled (no change, so no interrupt is active)
if ((digitalRead(ENC_SW) == HIGH) && ENC_SW_state == LOW) {
current_Rela_ENC_SW = millis();
if((current_Rela_ENC_SW - current_Appu_ENC_SW) > 10 && (current_Rela_ENC_SW - current_Appu_ENC_SW) < 500) { // entre 10ms et 500ms (0.5sec)
last_Appu_ENC_SW = current_Rela_ENC_SW;
ENC_SW_state_short = HIGH;
ENC_SW_state = HIGH;
//ets_printf("RELACHE COURT ENC_SW\n");
}
else if((current_Rela_ENC_SW - current_Appu_ENC_SW) >= 500) { // si superierieur a 0.5 sec
last_Appu_ENC_SW = current_Rela_ENC_SW;
ENC_SW_state_long = HIGH;
ENC_SW_state = HIGH;
//ets_printf("RELACHE LONG ENC_SW\n");
}
}
}
// Compteur RPM IN_RPM
//is called when the Interrupt Pin Changing
void IRAM_ATTR read_RPM() {
// impulsion suivantes :
if (FlagFirstImpulsion_RPM == true && esp_timer_get_time() - last_RPM_interupt > 4000 && esp_timer_get_time() - last_RPM_interupt < 75000) { // entre 250 tr/min (60000µsec) et 3100 tr/min (4838µsec) [ICI entre 200 tr/min (75000µsec) et 3750 tr/min (4000µsec)]
periode_RPM[count_Nbre_periode_RPM] = esp_timer_get_time() - last_RPM_interupt; // 16 echantillons -> entre 0,96sec (250tr/min) et 0,078sec (3100tr/min)
last_RPM_interupt = esp_timer_get_time();
count_Nbre_periode_RPM++; // compteur des 16 echantillions
if (count_Nbre_periode_RPM == Nbre_echanti_RPM) { // 16 echantillions, puis reinitialisation a 0
count_Nbre_periode_RPM = 0;
FlagAllImpulsionsPeriode_RPM = true; // Flag TRUE on a bien les 16 echantillions
}
//ets_printf("autre\n");
}
// 1er impulsion INIT
else if (FlagFirstImpulsion_RPM == false && esp_timer_get_time() - last_RPM_interupt > 4000 && esp_timer_get_time() - last_RPM_interupt < 75000) { // entre 250 tr/min (60000µsec) et 3100 tr/min (4838µsec) [ICI entre 200 tr/min (75000µsec) et 3750 tr/min (4000µsec)]
last_RPM_interupt = esp_timer_get_time();
//ets_printf("1er\n");
count_Nbre_periode_RPM = 0;
FlagFirstImpulsion_RPM = true;
}
}
// Limit Switch LSW_HOME INTERRUPTION
//is called when the Interrupt Pin is pressed or released (CHANGE Mode)
void IRAM_ATTR read_limite_switch_Home() {
//if this is true the button was just pressed down (LOW quand non appuyé)
if ((digitalRead(LSW_HOME) == HIGH) && LSW_HOME_state == LOW && FlagApp_LSW_HOME == false) {
//if (LSW_HOME_state == LOW && FlagApp_LSW_HOME == false) {
//note the time the button was pressed
current_Appu_LSW_HOME = millis();
if ((current_Appu_LSW_HOME - last_Appu_LSW_HOME) > 10 ) { // si sup à 10ms
last_Appu_LSW_HOME = current_Appu_LSW_HOME;
LSW_HOME_state = HIGH;
FlagApp_LSW_HOME = true;
//ets_printf("APPUYER LSW_HOME\n");
}
}
//if no button is high one had to be released.
//The millis function will increase while a button is hold down the loop function will be cycled (no change, so no interrupt is active)
if ((digitalRead(LSW_HOME) == LOW) && LSW_HOME_state == HIGH) {
//if (LSW_HOME_state == HIGH) {
current_Rela_LSW_HOME = millis();
if((current_Rela_LSW_HOME - current_Appu_LSW_HOME) > 10 ) { // si sup à 10ms
last_Appu_LSW_HOME = current_Rela_LSW_HOME;
LSW_HOME_state = LOW;
FlagApp_LSW_HOME = false;
//ets_printf("RELACHE LSW_HOME\n");
}
}
}
// Limit Switch LSW_MAXTRAVEL INTERRUPTION
//is called when the Interrupt Pin is pressed or released (CHANGE Mode)
void IRAM_ATTR read_limite_switch_MaxTravel() {
//if this is true the button was just pressed down (LOW quand non appuyé)
if ((digitalRead(LSW_MAXTRAVEL) == HIGH) && LSW_MAXTRAVEL_state == LOW && FlagApp_LSW_MAXTRAVEL == false) {
//if (LSW_MAXTRAVEL_state == LOW && FlagApp_LSW_MAXTRAVEL == false) {
//note the time the button was pressed
current_Appu_LSW_MAXTRAVEL = millis();
if ((current_Appu_LSW_MAXTRAVEL - last_Appu_LSW_MAXTRAVEL) > 10 ) { // si sup à 10ms
last_Appu_LSW_MAXTRAVEL = current_Appu_LSW_MAXTRAVEL;
LSW_MAXTRAVEL_state = HIGH;
FlagApp_LSW_MAXTRAVEL = true;
//ets_printf("APPUYER LSW_MAXTRAVEL\n");
}
}
//if no button is high one had to be released.
//The millis function will increase while a button is hold down the loop function will be cycled (no change, so no interrupt is active)
if ((digitalRead(LSW_MAXTRAVEL) == LOW) && LSW_MAXTRAVEL_state == HIGH) {
//if (LSW_MAXTRAVEL_state == HIGH) {
current_Rela_LSW_MAXTRAVEL = millis();
if ((current_Rela_LSW_MAXTRAVEL - current_Appu_LSW_MAXTRAVEL) > 10 ) { // si sup à 10ms
last_Appu_LSW_MAXTRAVEL = current_Rela_LSW_MAXTRAVEL;
LSW_MAXTRAVEL_state = LOW;
FlagApp_LSW_MAXTRAVEL = false;
//ets_printf("RELACHE LSW_MAXTRAVEL\n");
}
}
}
// ************************
// ******* FONCTION *******
// ************************
// ****************************
// *** DEBUT INITIALISATION ***
// ****************************
// Initialisation Serial
void InitSerial() {
Serial.begin(115200);
while(!Serial); // Wait for serial to start
if (serialDebug_Init) Serial.println("INIT SERIAL : OK");
}
// Initialisation de l'écran OLED
void InitOLED() {
//if(!ecranOLED.begin(SSD1306_EXTERNALVCC, adrI2COLED)) { // AVOIR
if(!ecranOLED.begin(SSD1306_SWITCHCAPVCC, adrI2COLED)) {
if (serialDebug_Init) Serial.println("INIT OLED : Erreur");
while(1); // Arrêt du programme (boucle infinie)
}
else {
if (serialDebug_Init) Serial.println("INIT OLED : OK");
// Fonction : Efface l'ecran OLED
oledClearDisplay();
displayMessage("DEMARRAGE", "Initialisation ...");
}
}
// Initialisation PWM
void InitPWM() {
// Configuration du canal 0 avec la fréquence et la résolution choisie
ledcSetup(pwmChannel, frequence, resolution);
// Assigne le canal PWM au pin 25
ledcAttachPin(OUT_PWM, pwmChannel);
// Initialise Vitesse ventilateur à l'arret au demarrage
ledcWrite(pwmChannel, pwm); // 0 -> OFF, Max -> A FOND
}
// Initialisation Time Zone "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00"
void InitTimeZone(const char* time_zone) {
//Serial.print("Setting Timezone to");
//Serial.println(time_zone);
setenv("TZ",time_zone,1); // Now adjust the TZ. Clock settings are adjusted to show the new local time
tzset(); // le 1 c'est pour appliquer le parametre (override)
if (serialDebug_Init) Serial.println("INIT TIMEZONE : OK");
}
// Initialisation NTP Serveur
void InitNTPServer() {
// set notification call-back function
esp_sntp_set_time_sync_notification_cb(timeavailable); // Mise a jour auto date/heure fonction CALL - BACK
// Interval update Time
esp_sntp_set_sync_interval(3600000); // toutes les heures en milliseconde (ex pour une heure : 1*60*60*1000)
//Serial.print("Interval update Time : ");Serial.println(sntp_get_sync_interval()); // 3600 000 ms
/** DEPLACER DANS WIFI CALLBACK
* A more convenient approach to handle TimeZones with daylightOffset
* would be to specify a environmnet variable with TimeZone definition including daylight adjustmnet rules.
* A list of rules for your zone could be obtained from https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h
*/
//configTzTime(time_zone, ntpServer);
}
// INIT PID en mode MANU donc OFF
void InitPid() {
//initialize the variables we're linked to
//InputPID = SondeTempC[0]; // sonde temperature moteur (SondeTempC[0]) , sonde froid (SondeTempC[2])
SetpointPID = ConsignePID * coef_temp; // Temperature de consigne Sonde moteur
OldSetpointPID = SetpointPID; // Ancienne temperature de consigne Sonde moteur
//tell the PID to range between 0 and the full window size
myPID.SetOutputLimits(home, maxtravel);
// Time pour myPID.Compute(); // intervalRequestTemp (4250ms) + intervalConversionSonde (750 ms) -> 5000 ms
myPID.SetSampleTime(intervalRequestTemp + intervalConversionSonde); // en ms -> donc toutes mes 5 sec
//PID off au demarrage (voir FLAG flag_iris_manu_on_off (true) -> mode Manu (TRUE))
// AVOIR NEW BUG IRIS
UpdateOutputPID(); // dit au PID ou est l'IRIS avant de passer en mode AUTOMATIC (AVOIR juste pour MAJ affichage OLED)
// FIN AVOIR NEW BUG IRIS
myPID.SetMode(MANUAL);
//turn the PID on (voir FLAG flag_iris_manu_on_off (false) -> mode Auto (FALSE))
//OutputPID = stepper.currentPosition(); // dit au PID ou est l'IRIS avant de passer en mode AUTOMATIC
//myPID.SetMode(AUTOMATIC);
}
// INIT IRIS Moteur pas a Pas
void InitIris() {
stepper.setEnablePin(enablePin); // Permet d'activer le driver du moteur pas a pas (Pin 16)
//https://forum.arduino.cc/t/using-accelstepper-library-w-stepper-driver-step-direction-and-enable-pins/639451/6
stepper.setPinsInverted(false, false, true); // Permet d'inverser le niveau de la PIN
//stepper.setPinsInverted(bool directionInvert=false, bool stepInvert=false, bool enableInvert=false)
// [in] directionInvert True for inverted direction pin, false for non-inverted
// [in] stepInvert True for inverted step pin, false for non-inverted
// [in] enableInvert True for inverted enable pin, false (default) for non-inverted
stepper.setMaxSpeed(640.0); // 100 // set the maximum speed //SPEED = Steps / second // -> 320 --> ICI X 2 -> 640 car HalfStep
stepper.setAcceleration(200.0); // 50 // set acceleration //ACCELERATION = Steps /(second)^2 (100 ,puis 200 ,puis 300, puis 320) // -> 100 --> ICI X 2 -> 200 car HalfStep
stepper.setCurrentPosition(0); // set position
stepper.moveTo(home); // set target position: max dans sans anti-horraire jusqu'a Limit switch home
stepper.enableOutputs(); // Activation des PIN du moteur
if (serialDebug_Init) Serial.println("INIT IRIS : Limit Switch DEBUT");
while (flag_initIris == false) { // code BLOQUANT boucle WHILE
// INIT Limite switch moteur pas a pas
// Si HOME interupt HIGH (sens anti-horraire -1)
if (digitalRead(LSW_HOME) == HIGH && stepper.distanceToGo() < 0 && digitalRead(LSW_MAXTRAVEL) == LOW) { //LSW_HOME_state == HIGH || // FIN course HOME BUG Ajout digitalRead(LSW_HOME) si deja en butée a l'initialisation STEPPER FIGE BUG, ajout LSW_MAXTRAVEL_state == LOW BUG Parasite reseau electrique
// Init home:
if (flag_home == false) {
stepper.setCurrentPosition(0); // position mise à 0 // Position réelle -> HOME - INIT_MARGE(-104) - MARGE_FLOTTANTE(-750)
stepper.moveTo(maxtravel); // 1er run -> on va a fond ( STEP_PER_REVOLUTION )
flag_home = true;
if (serialDebug_Init) Serial.println("INIT IRIS : Limit Switch HOME OK");
}
} // Fin HOME interupt HIGH
// Si MAXTRAVEL interupt HIGH (sens horraire +1)
if (digitalRead(LSW_MAXTRAVEL) == HIGH && stepper.distanceToGo() > 0 && digitalRead(LSW_HOME) == LOW && flag_home == true) { //LSW_MAXTRAVEL_state == HIGH || // FIN course MAXTRAVEL BUG Ajout digitalRead(LSW_MAXTRAVEL) si deja en butée a l'initialisation STEPPER FIGE BUG, ajout LSW_HOME_state == LOW BUG Parasite reseau electrique
// Init maxtravel:
if (flag_maxtravel == false) {
maxtravel = abs(stepper.currentPosition()) - (2 * INIT_MARGE) - MARGE_FLOTTANTE; // save maxtravel (nombre de step entre home et maxtravel en valeur absolue) - 2 x INIT_MARGE // Position réelle (maxtravel - (2 x INIT_MARGE(-2 x 104)) - MARGE_FLOTTANTE(-750))
home = 0; // initialise home à 0
while (maxtravel % 2 != 0) { // verifie que la division par 2 donne Zero (Halfstep) si maxtravel impaire on enleve 1
maxtravel--;
}
// Determine le pas d'un step (PasStepIris)
PasStepIris = maxtravel / (float)NbreStepIris; // 11600 / 115 step -> 100.87
stepper.setCurrentPosition(maxtravel + INIT_MARGE + MARGE_FLOTTANTE); // position mise à maxtravel // position reelle -> MAXTRAVEL + INIT_MARGE(+104) + MARGE_FLOTTANTE(+750)
stepper.moveTo(maxtravel); // on retourne a maxtravel
flag_maxtravel = true;
if (serialDebug_Init) Serial.println("INIT IRIS : Limit Switch MAXTRAVEL OK");
}
} // Fin MAXTRAVEL interupt HIGH
if (flag_home == true && flag_maxtravel == true) {
if (stepper.distanceToGo() == 0 && stepper.currentPosition() == maxtravel) {
if (maxtravel >= 11560) { // Si INIT IRIS OK (maxtravel env -> 11604, 11606, 11612 maintenant 11624) // DEBUG WOKWI
maxtravel = 12020; // DEBUG WOKWI
stepper.setCurrentPosition(maxtravel); // DEBUG WOKWI
PasStepIris = maxtravel / (float)NbreStepIris; // DEBUG WOKWI
home=0; // DEBUG WOKWI
if (serialDebug_Init) {
Serial.println();
Serial.println("INIT IRIS : OK");
Serial.print("Current Position : ");
Serial.print(stepper.currentPosition());
Serial.print(" ,maxtravel : ");
Serial.print(maxtravel);
Serial.print(" ,home : ");
Serial.print(home);
Serial.print(", PasStepIris : ");
Serial.println(PasStepIris);
Serial.println();
}
stepper.disableOutputs(); // Desactivation des PIN du moteur
sensRotation = -1; // Direction -1 (anti-horraire) vers HOME
prevSensRotation = -1; // Prev Direction -1 (anti-horraire) vers HOME
PosIris = maxtravel; // Initialisation a la position courante de l'IRIS
Steppercurrent = maxtravel; // Initialisation a la position courante de l'IRIS (Affichage)
old_deplacement = maxtravel; // ancienne position de l'IRIS pour comparer lors d'un nouveau deplacement
flag_initIris = true;
}
else { // Si INIT IRIS PAS BON
//assistant: < line 1 > < line 2 > < line 3 > < line 4 >
displayMessage("INIT. ERR.", "INIT IRIS : -ERREUR-\n MAXTRAVEL: " + String(maxtravel) + "\n VERIFIER IRIS !!!\nAppui Long\nPour Recommencer");
while (ENC_SW_state_long == LOW) { // code Bloquant si pas d'appui sur bouton reste bloque ICI
}
displayMessage("DEMARRAGE", "Initialisation ...\n\n INIT IRIS :\n\n En cours !!!");
stepper.setCurrentPosition(0); // set position
flag_home = false; // Reset Flag
flag_maxtravel = false; // Reset Flag
home = -STEP_PER_REVOLUTION; // Reset home
maxtravel = STEP_PER_REVOLUTION; // Reset maxtravel
stepper.moveTo(home);
//Reset Bouton Encodeur:
ENC_SW_state_short = LOW;
ENC_SW_state_long = LOW;
}
}
}
stepper.run(); // MUST be called in loop() function
} // Fin WHILE
//Reset Bouton Encodeur:
ENC_SW_state_short = LOW;
ENC_SW_state_long = LOW;
} // Fin InitIris
// initialisation des 4 sondes au demarrage
void InitSondes(DeviceAddress memSondesAddr[], uint8_t nbreSondes) {
pref.begin("Sondes", RO_MODE); // open (or create) the namespace
if (!pref.isKey("SFlag")) { // si SFlag existe pas on ecrit les adresses des sondes en memoire
pref.end(); // Ferme le namespace "Sonde" en lecture
pref.begin("Sondes", RW_MODE); // Reouvre le namespace "Sonde en ecriture
if (serialDebug_Init) Serial.println("INIT : Enregistrement des sondes en memoire : DEBUT");
uint8_t foundCount = 0; // compteur du nombre de sonde trouvée init a 0 avant boucle FOR
for (uint8_t index = 0; index < nbreSondes; index++) { // on crée une boucle de 4 executions
ENC_SW_state_long = LOW; // Reset appui Long status avant boucle WHILE PAS NECESSAIRE AVOIR
//Fonction : Affiche inserer sonde
oledAfficheInitSonde(index);
while (ENC_SW_state_long == LOW) { // Attends l'appui Long sur le bouton BLOQUANT
// if (ENC_SW_state_short == HIGH) { // Permet de casser la boucle AVOIR
// break;
// }
}
ENC_SW_state_long = LOW; // Reset appui Long status pour la prochaine sonde
if (serialDebug_Init) Serial.println("Bouton Long OK");
if (findNewSensor(memSondesAddr, foundCount)) { // si findNewSensor, return true ok, sinon else avec boucle while infinie
foundCount++;
// String(SondeNom[index]).c_str() -> converti une String en char
pref.putBytes(SondeNom[index].c_str(), memSondesAddr[index], sizeof(memSondesAddr[index]) ); // ENREGISTRE EN MEMOIRE
if (serialDebug_Init) {
Serial.print("Sonde trouvé : Address : ");
printAddress(memSondesAddr[index]);
Serial.println();
}
}
else {
if (serialDebug_Init) Serial.println("Pas de sonde trouvé, Verif cablage puis redémarrer");
while (1) {
}
}
}
// Fin Enregistrement ok creation FLAG Sonde SFlag
//pref.putBool(String(SondeNom[4]).c_str(), true); // SondeNom[4] -> SFlag
pref.putBool("SFlag", true); // SondeNom[4] -> SFlag
if (serialDebug_Init) Serial.println("INIT : Enregistrement des sondes en memoire : FIN");
pref.end(); // Ferme preferences Read Write mode
// Fonction : Efface l'ecran OLED
oledClearDisplay();
// Affiche toutes les address des 4 sondes de memSondesAddr[index] avec le nom de la sonde SondeNom[index]
if (serialDebug_Init) {
Serial.println();
Serial.println("Toutes les sondes trouvées:");
for (uint8_t index = 0; index < nbreSondes; index++) {
Serial.print("Sonde #");
Serial.print(index+1);
Serial.print(" (");
Serial.print(SondeNom[index]);
Serial.print(") : ");
printAddress(memSondesAddr[index]);
Serial.println();
}
}
// FIN ENREGISTREMENT
} // Fin Boucle IF
else { // si SFlag existe on lit les adresses des sondes depuis la memoire
if (serialDebug_Init) Serial.println("INIT : Lecture des sondes en memoire : DEBUT");
for (uint8_t index = 0; index < nbreSondes; index++) {
//String(SondeNom[index]).c_str()
pref.getBytes(SondeNom[index].c_str(), memSondesAddr[index], pref.getBytesLength(SondeNom[index].c_str()));
}
if (serialDebug_Init) Serial.println("INIT : Lecture des sondes en memoire : FIN");
//Serial.print("INIT : Lecture du FLAG en memoire : SFlag (true) -> ");
//Serial.println(pref.getBool("SFlag")); // SondeNom[3] -> SFlag
pref.end(); // Ferme preferences Read Only mode
// Affiche toutes les address des 3 sondes de memSondesAddr[index] avec le nom de la sonde SondeNom[index]
if (serialDebug_Init) {
Serial.println();
Serial.println("Toutes les sondes chargées:");
for (uint8_t index = 0; index < nbreSondes; index++) {
Serial.print("Sonde #");
Serial.print(index+1);
Serial.print(" (");
Serial.print(SondeNom[index]);
Serial.print(") : ");
printAddress(memSondesAddr[index]);
// Ajout verif sonde EN VIE ICI
Serial.println();
}
}
} // Fin boucle ELSE
//Reset Bouton Encodeur:
ENC_SW_state_short = LOW;
ENC_SW_state_long = LOW;
}
// Fin Fonction InitSondes
// Init :Start up the DS18B20 library (Dallas Temperature sensor)
void InitDallas() {
sensors.begin();
// Pour passer en mode assynchrone Sonde Temperature
sensors.setWaitForConversion(false);
// Pour compter le nombre de sonde :
numberOfDevicesFound = sensors.getDeviceCount();
if (numberOfDevicesFound == nbreSondes) {
// Boucle pour imprimer la resolution de chaque sonde:
for (uint8_t index = 0; index < nbreSondes; index++) {
SondeEnVie[index] = true; // Initialisation des sondes si en vie a UP (true) A voir ou il faut le mettre
if (serialDebug_Init) {
Serial.print("Sonde #");
Serial.print(index+1);
Serial.print(" (");
Serial.print(SondeNom[index]);
Serial.print(") : ");
printAddress(memSondesAddr[index]);
Serial.print(", Resolution : ");
Serial.println(sensors.getResolution(memSondesAddr[index]));
}
}
}
else {
if (serialDebug_Init) {
Serial.print("ERREUR -> Nombre de capteur : ");
Serial.println(numberOfDevicesFound);
}
}
}
// Fin Fonction InitDallas
// Initialisation du Server Web
void InitServerWeb() {
// Serve files in directory "/www/" when request url starts with "/"
// Request to the root or none existing files will try to server the default
// file name "index.htm" if exists
server.serveStatic("/data/", SD, "/data/"); // Permet de chercher les fichiers physique sur la carte SD dans le repertoire /data/ a telecharger si ils existent
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { // Redirection page demarrage
request->redirect("/etat");
});
server.on("/etat", HTTP_GET, handleEtat); // Page Etat
server.on("/data", HTTP_GET, handleSDCard); // Page Carte SD
server.on("/wifi", HTTP_GET, handlewifi); // Page Wifi GET
server.on("/wifi", HTTP_POST, handlewifiPost); // Page Wifi POST (SSID, WIFI KEY)
server.on("/doWifi", doWifi); // Page Wifi GET Validation (SSID, WIFI KEY)
server.on("/config", HTTP_GET, handleconfig); // Page Config AVOIR si il faut faire en POST
// run handleFileUpload function when any file is uploaded
server.on("/fupload", HTTP_POST, [](AsyncWebServerRequest *request) {
request->send(200);
}, handleFileUpload);
server.on("/deleteConfirm", deleteConfirm); // Confirmation pour la suppression de fichier ou de repertoire sur carte SD
server.on("/doDelete", doDelete); // Suppression fichier ou repertoire sur carte SD
server.on("/mkdir", doMkdir); // Creation repertoire sur carte SD
server.onFileUpload(handleFileUpload);
//server.onNotFound(handleSDCard);
server.onNotFound(handleNotFound);
server.begin();
if (serialDebug_Init) Serial.println("INIT HTTP : WEB SERVER OK");
}
// Initialisation Seuil Vitesse et Temperature (Vitesse Dynamique)
void InitSeuilVitDyn() {
//Vitesse
seuilVitesseB = VitesseVentil[Vit_Tbase] + offsetNormalisation(Vit_Tbase, Vit_offset);
seuilVitesseI = VitesseVentil[Vit_Tinte] + offsetNormalisation(Vit_Tinte, Vit_offset);
seuilVitesseMa = VitesseVentil[Vit_Tmaxi] + offsetNormalisation(Vit_Tmaxi, Vit_offset);
//Temperature
seuilTempB = (Temp_Vbase + Temp_offset) * coef_temp;
seuilTempI = (Temp_Vinte + Temp_offset) * coef_temp;
seuilTempMi = (Temp_Vmini + Temp_offset) * coef_temp;
}
// **************************
// *** FIN INITIALISATION ***
// **************************
// **********************************
// *** DEBUT PREFERENCE (MEMOIRE) ***
// **********************************
// Permet de charger la config des variables depuis la memoire
void chargeConfig(bool init) { // init -> true (SETUP 1er Run), init -> false (appel fonction depuis menu)
pref.begin("Config", RO_MODE); // open (or create) the namespace
if (pref.isKey("CFlag")) { // si CFlag existe (Flag config) on charge la config
//Int
ConsignePID = pref.getInt("CoPID"); // Temperature de consigne Sonde moteur PID
ConsignePID_coupure = pref.getInt("CoCPID"); // Temperature de Coupure PID (Si trop froid au moteur)
//Int
Temp_ON_moteur = pref.getInt("TonMo"); // Temperature de consigne mini ON Moteur (Temperature chaud)
Temp_OFF_moteur = pref.getInt("ToffMo"); // Temperature de consigne maxi OFF Moteur (Temperature moteur)
Hyst_Temp_ON_moteur = pref.getInt("HyMo"); // Hysteresis temperature moteur ON (Chaud 1er demarrage)
//Long
START_MODE_JOUR = pref.getLong("HMJ"); // Heure de demarage planification mode JOUR
START_MODE_NUIT = pref.getLong("HMN"); // Heure de demarage planification mode NUIT
TIMER_MODE_BOOST = pref.getLong("TMB"); // Duree pour le mode BOOST
//Int
Vit_nuit = pref.getInt("Vj"); // Vitesse mode Jour
Vit_jour = pref.getInt("Vn"); // Vitesse mode Nuit
Vit_boost = pref.getInt("Vb"); // Vitesse mode Boost
//Int
Temp_Vbase = pref.getInt("Tvb"); // Seuil Temperature de Base (Vitesse Dynamique)
Temp_Vinte = pref.getInt("Tvi"); // Seuil Temp. Inter. (Vitesse Dynamique)
Temp_Vmini = pref.getInt("Tvmi"); // Seuil Temp. Mini (Vitesse Dynamique)
Temp_offset = pref.getInt("Tvos"); // Offset de Temperature (Vitesse Dynamique)
Vit_Tbase = pref.getInt("Vtb"); // Seuil Vitesse de Base (Vitesse Dynamique)
Vit_Tinte = pref.getInt("Vti"); // Seuil Vitesse Inter. (Vitesse Dynamique)
Vit_Tmaxi = pref.getInt("Vtma"); // Seuil Vitesse Maxi (Vitesse Dynamique)
Vit_offset = pref.getInt("Vtos"); // Offset de Vitesse (Vitesse Dynamique)
if (init) {
if (serialDebug_Init) Serial.println("INIT CONFIG : OK"); // Init
}
else {
InitSeuilVitDyn();
displayMessage("Charger1", "\nChargement\nconfig OK\n"); // Menu
}
}
else { // si CFlag existe pas (Flag config)
if (init) {
if (serialDebug_Init) Serial.println("INIT CONFIG : Pas de Config"); // Init
}
else {
displayMessage("Charger1", "\nPas de config\na charger.\n"); // Menu
}
}
pref.end(); // Ferme le namespace "Config" en lecture
}
// Permet d'enregistrer la config des variables dans la memoire
void enregisConfig() {
pref.begin("Config", RW_MODE); // Ouvre le namespace "Config" en ecriture
if (pref.isKey("CFlag")) { // si CFlag existe deja (Flag config) [ON remplace seulement les valeurs modifiees]
//Int
if (ConsignePID != pref.getInt("CoPID")) { // Temperature de consigne Sonde moteur PID
pref.putInt("CoPID", ConsignePID);
}
if (ConsignePID_coupure != pref.getInt("CoCPID")) { // Temperature de coupure PID
pref.putInt("CoCPID", ConsignePID_coupure);
}
//Int
if (Temp_ON_moteur != pref.getInt("TonMo")) { // Temperature de consigne mini ON Moteur (Temperature chaud)
pref.putInt("TonMo", Temp_ON_moteur);
}
if (Temp_OFF_moteur != pref.getInt("ToffMo")) { // Temperature de consigne maxi OFF Moteur (Temperature moteur)
pref.putInt("ToffMo", Temp_OFF_moteur);
}
if (Hyst_Temp_ON_moteur != pref.getInt("HyMo")) { // Hysteresis temperature moteur ON (Chaud 1er demarrage)
pref.putInt("HyMo", Hyst_Temp_ON_moteur);
}
//Long
if (START_MODE_JOUR != pref.getLong("HMJ")) { // Heure de demarage planification mode JOUR
pref.putLong("HMJ", START_MODE_JOUR);
}
if (START_MODE_NUIT != pref.getLong("HMN")) { // Heure de demarage planification mode NUIT
pref.putLong("HMN", START_MODE_NUIT);
}
if (TIMER_MODE_BOOST != pref.getLong("TMB")) { // Heure de demarage planification mode NUIT
pref.putLong("TMB", TIMER_MODE_BOOST);
}
//Int
if (Vit_jour != pref.getInt("Vj")) { // Vitesse mode Jour
pref.putInt("Vj", Vit_jour);
}
if (Vit_nuit != pref.getInt("Vn")) { // Vitesse mode Nuit
pref.putInt("Vn", Vit_nuit);
}
if (Vit_boost != pref.getInt("Vb")) { // Vitesse mode Boost
pref.putInt("Vb", Vit_boost);
}
//Int
if (Temp_Vbase != pref.getInt("Tvb")) { // Seuil Temperature de Base (Vitesse Dynamique)
pref.putInt("Tvb", Temp_Vbase);
}
if (Temp_Vinte != pref.getInt("Tvi")) { // Seuil Temp. Inter. (Vitesse Dynamique)
pref.putInt("Tvi", Temp_Vinte);
}
if (Temp_Vmini != pref.getInt("Tvmi")) { // Seuil Temp. Mini (Vitesse Dynamique)
pref.putInt("Tvmi", Temp_Vmini);
}
if (Temp_offset != pref.getInt("Tvos")) { // Offset de Temperature (Vitesse Dynamique)
pref.putInt("Tvos", Temp_offset);
}
if (Vit_Tbase != pref.getInt("Vtb")) { // Seuil Vitesse de Base (Vitesse Dynamique)
pref.putInt("Vtb", Vit_Tbase);
}
if (Vit_Tinte != pref.getInt("Vti")) { // Seuil Vitesse Inter. (Vitesse Dynamique)
pref.putInt("Vti", Vit_Tinte);
}
if (Vit_Tmaxi != pref.getInt("Vtma")) { // Seuil Vitesse Maxi (Vitesse Dynamique)
pref.putInt("Vtma", Vit_Tmaxi);
}
if (Vit_offset != pref.getInt("Vtos")) { // Offset de Vitesse (Vitesse Dynamique)
pref.putInt("Vtos", Vit_offset);
}
}
else { // si CFlag existe pas (Flag config 1er RUN)
//Int
pref.putInt("CoPID", ConsignePID); // Temperature de consigne Sonde moteur PID
pref.putInt("CoCPID", ConsignePID_coupure); // Temperature de coupure PID
//Int
pref.putInt("TonMo", Temp_ON_moteur); // Temperature de consigne mini ON Moteur (Temperature chaud)
pref.putInt("ToffMo", Temp_OFF_moteur); // Temperature de consigne maxi OFF Moteur (Temperature moteur)
pref.putInt("HyMo", Hyst_Temp_ON_moteur); // Hysteresis temperature moteur ON (Chaud 1er demarrage)
//Long
pref.putLong("HMJ", START_MODE_JOUR); // Heure de demarage planification mode JOUR
pref.putLong("HMN", START_MODE_NUIT); // Heure de demarage planification mode NUIT
pref.putLong("TMB", TIMER_MODE_BOOST); // Duree pour le mode BOOST
//Int
pref.putInt("Vj", Vit_jour); // Vitesse mode Jour
pref.putInt("Vn", Vit_nuit); // Vitesse mode Nuit
pref.putInt("Vb", Vit_boost); // Vitesse mode Boost
//Int
pref.putInt("Tvb", Temp_Vbase); // Seuil Temperature de Base (Vitesse Dynamique)
pref.putInt("Tvi", Temp_Vinte); // Seuil Temp. Inter. (Vitesse Dynamique)
pref.putInt("Tvmi", Temp_Vmini); // Seuil Temp. Mini (Vitesse Dynamique)
pref.putInt("Tvos", Temp_offset); // Offset de Temperature (Vitesse Dynamique)
pref.putInt("Vtb", Vit_Tbase); // Seuil Vitesse de Base (Vitesse Dynamique)
pref.putInt("Vti", Vit_Tinte); // Seuil Vitesse Inter. (Vitesse Dynamique)
pref.putInt("Vtma", Vit_Tmaxi); // Seuil Vitesse Maxi (Vitesse Dynamique)
pref.putInt("Vtos", Vit_offset); // Offset de Vitesse (Vitesse Dynamique)
pref.putBool("CFlag", true); // Si config ok on cree le Flag de la config
}
pref.end(); // Ferme le namespace "Config" en ecriture
displayMessage("Enregistrer1", "\nEnregistrement\nconfig OK\n");
}
// ********************************
// *** FIN PREFERENCE (MEMOIRE) ***
// ********************************
// ******************
// *** DEBUT OLED ***
// ******************
// Efface l'ecran OLED
void oledClearDisplay() {
ecranOLED.clearDisplay(); // clear display
ecranOLED.display(); // display on OLED
}
// Ecran OLED : Ecran REMPLACEMENT des sondes de Temperature
void oledAfficheRempSonde(uint8_t index) {
ecranOLED.setFont(&FreeSerif9pt7b);
if (SondeEnVie[indexSondeRemp] == false) { // si sonde morte
ecranOLED.setCursor(0, 31); // mini y=31
ecranOLED.print("Connect Sonde ");
ecranOLED.print(index+1);
ecranOLED.setCursor(0, 45); // mini y=45
ecranOLED.print(" -> (");
ecranOLED.print(SondeNom[index]);
ecranOLED.print(")");
ecranOLED.setCursor(0, 59); // maxi y=59
ecranOLED.print(" Appui Long");
}
else { // Sonde DEJA OK
ecranOLED.setCursor(0, 31); // mini y=31
ecranOLED.print("Sonde ");
ecranOLED.print(index+1);
ecranOLED.setCursor(0, 45); // mini y=45
ecranOLED.print(" -> (");
ecranOLED.print(SondeNom[index]);
ecranOLED.print(")");
ecranOLED.setCursor(0, 59); // maxi y=59
ecranOLED.print(" Deja OK");
}
ecranOLED.setFont();
ecranOLED.display(); // display on OLED
}
// Ecran OLED : Ecran INITIALISATION des sondes de Temperature
void oledAfficheInitSonde(uint8_t index) {
ecranOLED.clearDisplay(); // clear display
ecranOLED.setFont(&FreeSerif9pt7b);
//ecranOLED.setTextSize(1); // set text size
ecranOLED.setTextColor(SSD1306_WHITE); // set text color
ecranOLED.setCursor(2, 11); // mini y=11
ecranOLED.print("Init Sonde Temp");
ecranOLED.setCursor(0, 31); // mini y=31
ecranOLED.print("Connect Sonde ");
ecranOLED.print(index+1);
ecranOLED.setCursor(0, 45); // mini y=45
ecranOLED.print(" -> (");
ecranOLED.print(SondeNom[index]);
ecranOLED.print(")");
ecranOLED.setCursor(0, 59); // maxi y=59
ecranOLED.print(" Appui Long");
ecranOLED.drawLine(0, topLine-1, ecranOLED.width(), topLine-1, SSD1306_WHITE); // draw horizontal line under title
ecranOLED.display(); // display on OLED
}
// Fonction pour modifier les seuils de DEMARRAGE et d'ARRET du Moteur en fonction de la temperature
void oledAfficheTempSeuil(float mini, float maxi, float temp ) {
temp = temp * coef_temp;
mini = mini * coef_temp;
maxi = maxi * coef_temp;
// message Temperature
ecranOLED.setFont(&FreeSerif18pt7b);
//Fonction pour centrer la Temperature, position y
oledCentreFloatTemperature(temp,48); // y = 48 sur 64 reste 16 pixel en bas de libre
// 54 max en y
drawProgressbar(0,54,128,10, mini, maxi, temp); // (int x, int y, int width, int height,valeur min, valeur max, valeur )
ecranOLED.setFont();
ecranOLED.display();
}
// Fonction pour modifier l'etat MARCHE / ARRET (Menu OFF / ON)
void oledAfficheONOFF(bool etat_ventilo) {
ecranOLED.setFont(&FreeSerif18pt7b);
if (etat_ventilo) {
oledCentreString("ON", 0, 54, 128);
}
else {
oledCentreString("OFF", 0, 54, 128);
}
ecranOLED.setFont();
ecranOLED.display();
}
// Fonction pour modifier l'etat AUTO / MANU (Auto OFF / Manu ON)
void oledAfficheManuAuto(bool manu) {
ecranOLED.setFont(&FreeSerif18pt7b);
if (manu) {
oledCentreString("Manu", 0, 54, 128);
}
else {
oledCentreString("Auto", 0, 54, 128);
}
ecranOLED.setFont();
ecranOLED.display();
}
// Fonction pour afficher l'heure
void oledAfficheTime(long time) {
int8_t h;
int8_t m;
String heure;
h = time / 3600;
m = (time % 3600)/60;
heure = h;
if (m < 10) { // Pour ajouter un zero devant les minutes en dessous de 10 min
heure += ":0";
}
else {
heure += ":";
}
heure += m;
if (serialDebug) {
Serial.print("Time : ");
Serial.print(time);
Serial.print(" -> heure : ");
Serial.println(heure);
}
ecranOLED.setFont(&FreeSerif18pt7b);
oledCentreString(heure, 0, 54, 128);
ecranOLED.setFont();
ecranOLED.display();
}
//Fonction Affiche ecran temperature combine 3 Fonctions
// -oledCentreString(text a afficher, debut x, debut y, taille zone affichage texte) -> TITRE, POSITION VERTICALE
// -oledCentreFloatTemperature(float temp,int y) -> TEMPERATURE, POSITION VERTICALE max 64
// -ftoS(float temp,int nbre decimale, bool virgule ou pas) -> Arrondi + transforme FLOAT to SRING et remplacement point par virgule
void oledAfficheTemp(String titre, float temp) {
ecranOLED.clearDisplay();
ecranOLED.setTextColor(SSD1306_WHITE);
ecranOLED.setFont(&FreeSerif9pt7b);
// title
oledCentreString(titre, 0, 13, 128); // y=13 sur 16 pixel pour le Jaune
ecranOLED.drawLine(0, topLine-1, ecranOLED.width(), topLine-1, SSD1306_WHITE); // draw horizontal line under title
// message
ecranOLED.setFont(&FreeSerif18pt7b);
if (temp == -127) { // Erreur
//Serial.println("CAS Erreur -127");
ecranOLED.setCursor(1,48); // y = 48 sur 64 reste 16 pixel en bas de libre
ecranOLED.print("Err. -127");
//ecranOLED.println(temp,0);
}
else if (temp == -85) { // Erreur
//Serial.println("CAS Erreur -127");
ecranOLED.setCursor(1,48); // y = 48 sur 64 reste 16 pixel en bas de libre
ecranOLED.print("Err. +85");
//ecranOLED.println(temp,0);
}
else {
//Fonction pour centrer la Temperature, position y
oledCentreFloatTemperature(temp,48); // y = 48 sur 64 reste 16 pixel en bas de libre
}
ecranOLED.display();
}
//Fonction pour centrer la Temperature
void oledCentreFloatTemperature(float temp, int16_t y) { // X en 0 pour toute la ligne, y 48 en vertical
int16_t x1, y1;
uint16_t width, height;
//Passage de float a string et remplacement du point par une virgule
String out = ftoS(temp,1,true);
out +=" C";
ecranOLED.getTextBounds(out, 0, y, &x1, &y1, &width, &height);
ecranOLED.setCursor((ecranOLED.width() - width) / 2, y);
ecranOLED.print(out);
ecranOLED.drawCircle(((ecranOLED.width() - width) / 2)+width-26, y-20, 3, SSD1306_WHITE); //(y=48-20) Affiche le ° degres
}
// Fonction Oled Affiche RPM et PWM Ventilateur
void oledAfficheRPM(int32_t rpm, int32_t pwm, int32_t maxpwm) {
// RPM et PWM si probleme moteur
if (pwm != 0 && rpm == 0 && FlagErrorMoteur_RPM == true) { // Si le moteur ne tourne pas et qu'il est en ERREUR alors que PWM est different de zero
//Fonction pour mettre a doite le PWM (124 - width), position y->50 (4)
oledAlligneDroiteInt(pwm, 50, 123);
ecranOLED.setFont(&FreeSerif18pt7b);
ecranOLED.setCursor(0, 46);
ecranOLED.print("ErMot");
}
else { // Si le moteur tourne ou que pwm = 0
//Fonction pour centrer tr/min (entre 65 et 96), position y->48 (3)
ecranOLED.setCursor(75, 32);
ecranOLED.print("tr/min");
//Fonction pour mettre a doite le PWM (124 - width), position y->50 (4)
oledAlligneDroiteInt(pwm, 50, 123);
ecranOLED.setFont(&FreeSerif18pt7b);
//Fonction pour centrer le RPM (entre 0 et 64), position y->48 (2)
oledAlligneDroiteInt(rpm, 48, 70);
}
//Affichage mode Auto / Manu
//drawRoundRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t radius, uint16_t color);
ecranOLED.drawRoundRect(0, 52, 18, 12, 3, SSD1306_WHITE); // vignette
ecranOLED.setFont(&FreeSerif9pt7b);
if (flag_ventilo_manu_on_off == true) { // Mode MANU -> TRUE
ecranOLED.setCursor(2, 61);
ecranOLED.print("m");
}
else { // Mode AUTO -> FALSE
ecranOLED.setCursor(5, 61);
ecranOLED.print("a");
}
// 54 max en y
drawProgressbar(20,54,108,10, 0, maxpwm, pwm ); // (int x, int y, int width, int height,valeur min, valeur max, valeur )
ecranOLED.display();
}
//Fonction pour centrer
//oledCentreString(text a afficher, debut x, debut y, taille zone affichage texte, police FONTS)
void oledCentreString(String text, int16_t x, int16_t y, int16_t taille) {
int16_t x1, y1;
uint16_t width,height;
ecranOLED.setTextWrap(false); //Permet de couper le text a droite
ecranOLED.getTextBounds(text, x, y, &x1, &y1, &width, &height);
while (width > taille) { // 128 // Si plus large que taille on supprime le dernier caractere du text
//Serial.println("width :");
//Serial.println(width);
text = text.substring(0, text.length() - 1);
ecranOLED.getTextBounds(text, x, y, &x1, &y1, &width, &height);
}
ecranOLED.setCursor((taille - width + x) / 2, y);
ecranOLED.print(text);
ecranOLED.setTextWrap(true); // Permet de continuer le text a la ligne suivante
}
//Fonction pour mettre a doite Float
void oledAlligneDroiteFloat(float temp, int16_t y, int16_t fin) {
int16_t x1, y1;
uint16_t width, height;
//Passage de float a string et remplacement du point par une virgule
String out = ftoS(temp,1,true);
ecranOLED.getTextBounds(out, 0, y, &x1, &y1, &width, &height);
ecranOLED.setCursor((fin - width), y);
ecranOLED.print(out);
}
//Fonction pour alligner a doite Int
void oledAlligneDroiteInt(int32_t nbre, int16_t y, int16_t fin) { // X en 0 pour toute la ligne, y 13 position text verticale
String out = String(nbre);
int16_t x1, y1;
uint16_t width, height;
ecranOLED.getTextBounds(out, 0, y, &x1, &y1, &width, &height);
ecranOLED.setCursor((fin - width), y);
ecranOLED.print(out);
}
// Fonction pour modifier le numero de la vitesse du Ventilo pour le Mode Jour, Nuit et Boost
void oledAfficheInt(uint8_t mini, uint8_t maxi, uint8_t num, int16_t y) {
int16_t x1, y1;
uint16_t width, height;
String out = String(num);
// message Temperature
ecranOLED.setFont(&FreeSerif18pt7b);
//Fonction pour centrer le num, position y = 48
ecranOLED.getTextBounds(out, 0, y, &x1, &y1, &width, &height);
ecranOLED.setCursor((ecranOLED.width() - width) / 2, y);
ecranOLED.print(out);
// 54 max en y
drawProgressbar(0,54,128,10, mini, maxi, num); // (int x, int y, int width, int height,valeur min, valeur max, valeur )
ecranOLED.setFont();
ecranOLED.display();
}
// Fonction pour afficher l'offset (vitesse dynamique)
void oledAfficheIntToFloat(int8_t mini, int8_t maxi, int8_t num, int16_t y) {
int16_t x1, y1;
uint16_t width, height;
String out = ftoS(num/100.00, 2, true);
// message Temperature
ecranOLED.setFont(&FreeSerif18pt7b);
//Fonction pour centrer le num, position y = 48
ecranOLED.getTextBounds(out, 0, y, &x1, &y1, &width, &height);
ecranOLED.setCursor((ecranOLED.width() - width) / 2, y);
ecranOLED.print(out);
// 54 max en y
drawProgressbar(0,54,128,10, mini, maxi, num); // (int x, int y, int width, int height,valeur min, valeur max, valeur )
ecranOLED.setFont();
ecranOLED.display();
}
// Fonction OLED pour IRIS
void oledAfficheIRIS(int16_t currentPos, int16_t desiredPos) {
//Fonction pour centrer mm (entre 65 et 96), position y->48 (3)
ecranOLED.setCursor(77, 32);
ecranOLED.print("mm");
//Fonction pour mettre a doite le Position encodeur (124 - width), position y->50 (4)
//oledAlligneDroiteInt(desiredPos, 50, 123); // Mode debug
oledAlligneDroiteInt(map2(desiredPos, home, maxtravel, DiamIrisMaxi, DiamIrisMini), 50, 123);
ecranOLED.setFont(&FreeSerif18pt7b);
//Fonction pour centrer le position Iris (entre 0 et 64), position y->48 (2)
oledAlligneDroiteInt(map2(currentPos, home, maxtravel, DiamIrisMaxi, DiamIrisMini), 48, 70);
// Symbole Diametre
ecranOLED.setCursor(0, 44);
ecranOLED.print("o");
ecranOLED.setCursor(4, 48);
ecranOLED.print("/");
//Affichage mode Iris Auto / Manu
//drawRoundRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t radius, uint16_t color);
ecranOLED.drawRoundRect(0, 52, 18, 12, 3, SSD1306_WHITE); // vignette
ecranOLED.setFont(&FreeSerif9pt7b);
if (flag_iris_manu_on_off == true) { // Mode MANU -> TRUE
ecranOLED.setCursor(2, 61);
ecranOLED.print("m");
}
else { // Mode AUTO -> FALSE
ecranOLED.setCursor(5, 61);
ecranOLED.print("a");
}
// 54 max en y
//drawProgressbar(20,54,108,10, home, maxtravel, desiredPos); // (int x, int y, int width, int height,valeur min, valeur max, valeur )
drawProgressbar(20,54,108,10, -maxtravel, home, -desiredPos); // (int x, int y, int width, int height,valeur min, valeur max, valeur )
ecranOLED.display();
}
// Fonction OLED pour Sondes Erreurs de Temperature
void oledAfficheErrSonde() {
ecranOLED.setFont();
// Erreur Sonde Temperature Exterieure
ecranOLED.setCursor(5,23); // y = 23 sur 63 reste 40 pixel en bas de libre
ecranOLED.print(SondeNom[3]);
ecranOLED.setCursor(57,23); // y = 23 sur 63 reste 40 pixel en bas de libre
ecranOLED.print(":");
ecranOLED.setCursor(67,23); // y = 23 sur 63 reste 40 pixel en bas de libre
ecranOLED.print(SondeErr[3]);
// Erreur Sonde Temperature Moteur
ecranOLED.setCursor(5,33); // y = 33 sur 63 reste 30 pixel en bas de libre
ecranOLED.print(SondeNom[0]);
ecranOLED.setCursor(57,33); // y = 33 sur 63 reste 30 pixel en bas de libre
ecranOLED.print(":");
ecranOLED.setCursor(67,33); // y = 33 sur 63 reste 30 pixel en bas de libre
ecranOLED.print(SondeErr[0]);
// Erreur Sonde Temperature Chaud (Hotte)
ecranOLED.setCursor(5,43); // y = 43 sur 63 reste 20 pixel en bas de libre
ecranOLED.print(SondeNom[1]);
ecranOLED.setCursor(57,43); // y = 43 sur 63 reste 20 pixel en bas de libre
ecranOLED.print(":");
ecranOLED.setCursor(67,43); // y = 43 sur 63 reste 20 pixel en bas de libre
ecranOLED.print(SondeErr[1]);
// Erreur Sonde Temperature Froid (by-pass)
ecranOLED.setCursor(5,53); // y = 53 sur 63 reste 10 pixel en bas de libre
ecranOLED.print(SondeNom[2]);
ecranOLED.setCursor(57,53); // y = 53 sur 63 reste 10 pixel en bas de libre
ecranOLED.print(":");
ecranOLED.setCursor(67,53); // y = 53 sur 63 reste 10 pixel en bas de libre
ecranOLED.print(SondeErr[2]);
ecranOLED.display();
}
// Progress Bar OLED
void drawProgressbar(int16_t x,int16_t y, int16_t width, int16_t height, float Vmini, float Vmaxi, float progress) {
progress = progress > Vmaxi ? Vmaxi : progress; // set the progress value to 100
progress = progress < Vmini ? Vmini :progress; // start the counting to 0-100
float bar = ((float)(width-4) / (Vmaxi-Vmini)) * (progress-Vmini);
ecranOLED.drawRect(x, y, width, height, SSD1306_WHITE);
ecranOLED.fillRect(x+2, y+2, bar , height-4, SSD1306_WHITE); // initailize the graphics fillRect(int x, int y, int width, int height)
}
// ****************
// *** FIN OLED ***
// ****************
// ********************************
// *** DEBUT SONDES TEMPERATURE ***
// ********************************
// Recherche adresse Nouvelle sonde
bool findNewSensor(DeviceAddress currentAddressSondes[], uint8_t currentCount) {
DeviceAddress TempAddressSondes;
bool alreadyFound;
oneWire.reset_search();
while (oneWire.search(TempAddressSondes)) {
if (validAddress(TempAddressSondes)) { // verif CRC
alreadyFound = false;
if (validFamily(TempAddressSondes)) { // verif bien une DS18B20
for (uint8_t index = 0; index < currentCount; index++) { // verifie pour chaque adresse de currentAddressSondes[0], puis [1], puis [2] si TempAddressSondes existe deja
if (addressMatch(TempAddressSondes, currentAddressSondes[index])) { // si true -> on passe a la suivante, break
alreadyFound = true;
break;
}
}
if (!alreadyFound) { // si pas trouvé -> on copie l'adress de la sonde de TempAddressSondes dans currentAddressSondes[currentCount] : (memcpy(Destination, Source, sizeof(DeviceAddress));)
memcpy(currentAddressSondes[currentCount], TempAddressSondes, sizeof(DeviceAddress));
return true;
}
}
}
}
return false;
}
// Recherche adresse Nouvelle sonde pour remplacement sonde defectueuse
bool rempOldSensor(DeviceAddress currentAddressSondes[], uint8_t nbreSondes, uint8_t indexExt) {
DeviceAddress TempAddressSondes;
bool alreadyFound;
oneWire.reset_search();
while (oneWire.search(TempAddressSondes)) {
if (validAddress(TempAddressSondes)) { // verif CRC
alreadyFound = false;
if (validFamily(TempAddressSondes)) { // verif bien une DS18B20
for (uint8_t index = 0; index < nbreSondes; index++) { // verifie pour chaque adresse de currentAddressSondes[0], puis [1], puis [2], puis [3] si TempAddressSondes existe deja
if (addressMatch(TempAddressSondes, currentAddressSondes[index])) { // si true -> on passe a la suivante, break
//if (serialDebug_sondes) {Serial.print("index : ");Serial.println(index);}
alreadyFound = true;
break;
}
}
if (!alreadyFound) { // si pas trouvé -> on copie l'adress de la sonde de TempAddressSondes dans currentAddressSondes[currentCount] : (memcpy(Destination, Source, sizeof(DeviceAddress));)
memcpy(currentAddressSondes[indexExt], TempAddressSondes, sizeof(DeviceAddress));
return true;
}
}
}
}
return false;
}
// Imprime l'address de la sonde
void printAddress(DeviceAddress SondeAddress) {
for (uint8_t i = 0; i < 8; i++) {
// zero pad the address if necessary
if (SondeAddress[i] < 16) {
Serial.print("0");
}
Serial.print(SondeAddress[i], HEX);
}
}
// Verifie le CRC de la sonde
bool validAddress(const uint8_t* SondeAddress) {
return (oneWire.crc8(SondeAddress, 7) == SondeAddress[7]);
}
// Verifie que la sonde est bien une DS18B20
bool validFamily(const uint8_t* SondeAddress) {
if (SondeAddress[0] == 0x28) {
return true;
}
return false;
}
// Verifie que l'adresse est identique entre addr1 et addr2 (Sonde Temp)
bool addressMatch(DeviceAddress addr1, DeviceAddress addr2) {
for (uint8_t index = 0; index < sizeof(DeviceAddress); index++) {
if (addr1[index] != addr2[index]) {
return false;
}
}
return true;
}
// Recupere la valeur de la sonde de Temperature, A faire apres le GET TEMPERATURE
float readDSTemperatureC(DeviceAddress SondeAddress, uint8_t index) {
// Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus
//sensors.requestTemperatures();
// commande pour afficher la temperature une seconde apres par adresse
//float tempC = sensors.getTempC(tempDeviceAddress);
// commande pour afficher la temperature une seconde apres par index
//float tempC = sensors.getTempC(SondeAddress);
float tempC = 50.2639; // DEBUG WOKWI
static int8_t tt = 0;
if (tt <=2) {
tempC = 85;
tt++;
}
else {
tempC = 50.2639; // DEBUG WOKWI
}
if (tt == 4) {
tt=0;
}
//} // DEBUG WOKWI
if (tempC == -127) { // Erreur -127
SondeErr[index]++; // Compteur erreur sonde incrementation
SondeErrTemp[index]++; // Compteur erreur temporaire sonde (10 Erreurs de suite)
if (SondeErrTemp[index] == 1) { // Erreur -127 "Faux positif" on ignore le -127 la 1ere fois (lampe couloir telerupteur)
tempC = SondeTempC[index]; // on garde l'ancienne valeur de la sonde
}
}
else if (tempC == 85) { // Erreur +85
if (abs(SondeTempC[index] - tempC) >= 5) { // si difference de temperature superieure a 5 °C en 5 sec --> Erreur
SondeErr[index]++; // Compteur erreur sonde incrementation
SondeErrTemp[index]++; // Compteur erreur temporaire sonde (10 Erreurs de suite)
if (SondeErrTemp[index] == 1) { // Erreur +85 "Faux positif" on ignore le +85 la 1ere fois (lampe couloir telerupteur)
tempC = SondeTempC[index]; // on garde l'ancienne valeur de la sonde
}
else {
tempC = -85.0f; // Force -85 (pour Err.+85)
}
}
}
else {
SondeErrTemp[index] = 0; // Reinitialise compteur erreur temporaire sonde (10 Erreurs de suite)
}
if (SondeErrTemp[index] >= 10) { // si erreur sup à 10 -> sonde morte
SondeEnVie[index] = false; // Passage sonde a DOWN (false) si morte
// Si sonde morte print nombre erreur
if (serialDebug_sondes) {
Serial.print("ERREUR : Sonde #");
Serial.print(index+1);
Serial.print(" MORTE (");
Serial.print(SondeNom[index]);
Serial.print(") Address : ");
printAddress(SondeAddress);
Serial.print(" , SondeErr : ");
Serial.print(SondeErr[index]);
Serial.print(" , SondeErrTemp : ");
Serial.println(SondeErrTemp[index]);
}
}
return float(tempC);
}
// Recherche adresse Nouvelle sonde de REMPLACEMENT
void RemplacerSondes(DeviceAddress memSondesAddr[], uint8_t nbreSondes, uint8_t index) {
//uint8_t foundCount = 0; // compteur du nombre de sonde trouvée init a 0 avant boucle FOR
for (index = 0; index < nbreSondes; index++) { // on crée une boucle de 3 executions
if (SondeEnVie[index] == false) { // si sonde morte
// A VOIR si il faut vider ou nom l'adresse avant
DeviceAddress VideAddr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
//(memcpy(Destination, Source, sizeof(DeviceAddress))
memcpy(memSondesAddr[index], VideAddr, sizeof(DeviceAddress));
//Fonction : Affiche inserer sonde
oledAfficheInitSonde(index);
ENC_SW_state_long = LOW; // Reset appui Long status avant boucle WHILE
ENC_SW_state_short = LOW; // Reset appui Court status
while (ENC_SW_state_long == LOW) { // Attends l'appui Long sur le bouton BLOQUANT
//Serial.println("BOUCLE");
if (ENC_SW_state_short == HIGH) {
break;
}
}
ENC_SW_state_long = LOW; // Reset appui Long status pour la prochaine sonde
ENC_SW_state_short = LOW; // Reset appui Court status
if (serialDebug_sondes) Serial.println("Bouton Long OK");
if (rempOldSensor(memSondesAddr, nbreSondes, index)) { // si rempOldSensor, return true ok, sinon else avec boucle while infinie
if (!addressMatch(VideAddr, memSondesAddr[index])) { // si false -> on enregistre l'adresse de la sonde en memoire -> namespace -> nomSonde
pref.begin("Sondes", RW_MODE); // Ouvre le namespace "Sonde en ecriture
// String(SondeNom[index]).c_str() -> converti une String en char
pref.putBytes(SondeNom[index].c_str(), memSondesAddr[index], sizeof(memSondesAddr[index]) ); // ENREGISTRE EN MEMOIRE
pref.end(); // Ferme preferences Read Write mode
if (serialDebug_sondes) Serial.println("Sauvegarde mémoire sonde OK");
}
else {
if (serialDebug_sondes) {
Serial.print("Erreur : Adresse Sonde Vide :");
printAddress(memSondesAddr[index]);
Serial.println();
}
}
SondeEnVie[index] = true; // Reinitialise sonde en vie a UP (true)
SondeErr[index] = 0; // Reinitialise compteur erreur sonde
SondeErrTemp[index] = 0; // Reinitialise compteur erreur temporaire sonde (10 Erreurs de suite)
if (serialDebug_sondes) {
Serial.print("Sonde #");
Serial.print(index+1);
Serial.print(" (");
Serial.print(SondeNom[index]);
Serial.print(") remplacée : Address : ");
printAddress(memSondesAddr[index]);
Serial.println();
}
}
else {
if (serialDebug_sondes) Serial.println("Pas de sonde trouvé, Verif cablage puis recommencer");
}
}
}
}
// ******************************
// *** FIN SONDES TEMPERATURE ***
// ******************************
// **********************
// *** DEBUT CARTE SD ***
// **********************
//Initialisation SD CARD
void InitSDCard() {
spi.begin(SD_CLK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS,spi,80000000)) {
if (serialDebug_Init) Serial.println("Card Mount Failed");
return;
}
else { // Si SD Card Mount OK, on continue
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
if (serialDebug_Init) Serial.println("No SD card attached");
return;
}
else { // Si SD Card attached OK, on continue
if (serialDebug_Init) {
Serial.print("SD Card Type: ");
if(cardType == CARD_MMC) {
Serial.println("MMC");
}
else if(cardType == CARD_SD) {
Serial.println("SDSC");
}
else if(cardType == CARD_SDHC) {
Serial.println("SDHC");
}
else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %llu Mo\n", cardSize);
Serial.println("INIT SD CARD : OK");
}
}
}
}
// cloture le fichier precedent J-1 ou J-10, et met a jour le fichier /data/lastfile.txt avec le nom du fichier du jour
void closelastfile() {
//String closeMessage;
String prevFile;
if (SD.exists(lastfile)) {
prevFile = readlastFile(SD, lastfile); // lit le nom du dernier fichier (/data/lastfile.txt)
if (prevFile != YearMonthDayFile){ // si different de la date du jour
if (SD.exists(prevFile.c_str())) {
//closeMessage = "\r\n]";
appendFile(SD, prevFile.c_str(), (char*)"\r\n]"); // on cloture le fichier du jour precedent J-1 ou J-10
//appendFile(SD, prevFile.c_str(), closeMessage.c_str()); // on cloture le fichier du jour precedent J-1 ou J-10
}
}
}
writeFile(SD, lastfile, YearMonthDayFile); // remplace le fichier lastFile avec date du jour (creer un nouveau fichier a chaque fois)
}
// Lecture last file SD CARD:
String readlastFile(fs::FS &fs, const char * path) {
if (serialDebug) Serial.printf("Reading lastFile: %s\n", path);
File file = fs.open(path);
String value;
char fileData[21]; // /data/2023/08/06.txt -> 20 +1
int8_t index = 0;
while (file.available()) { // If the file is present execute loop until done.
fileData[index] = file.read();
value += fileData[index];
index++;
}
if (serialDebug) {
Serial.print("Read from lastFile: ");
Serial.println(value);
}
file.close();
return String(value);
}
// Creation repertoire SD CARD:
void createDir(fs::FS &fs, const char * path) {
if (serialDebug) Serial.printf("Creating Dir: %s\n", path);
if(fs.mkdir(path)) {
if (serialDebug) Serial.println("Dir created");
}
else {
if (serialDebug) Serial.println("mkdir failed");
}
}
// Lecture fichier SD CARD:
void readFile(fs::FS &fs, const char * path) {
if (serialDebug) Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file) {
if (serialDebug) Serial.println("Failed to open file for reading");
return;
}
if (serialDebug) Serial.println("Read from file: ");
while(file.available()) {
Serial.write(file.read());
}
file.close();
}
// Ecriture fichier SD CARD: (Ecrase contenu fichier si existe ecriture NOUVEAU FICHIER)
void writeFile(fs::FS &fs, const char * path, const char * message) {
if (serialDebug) Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
if (serialDebug) Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)) {
if (serialDebug) Serial.println("File written");
}
else {
if (serialDebug) Serial.println("Write failed");
}
file.close();
}
// Ecriture a la suite du fichier SD CARD: (ajoute contenu fichier existant)
void appendFile(fs::FS &fs, const char * path, const char * message) {
if (serialDebug) Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
if (serialDebug) Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)){
if (serialDebug) Serial.println("Message appended");
}
else {
if (serialDebug) Serial.println("Append failed");
}
file.close();
}
//Passage de Float to String et remplacement point par virgule
String ftoS(float in, int8_t nbre, bool virgule) {
String out = String(in,nbre);
if (virgule){
out.replace(".", ",");
}
return out;
}
//Ecriture des données sur la carte SD (creation repertoire fichier et fermeture fichier J-1)
void createfileSD() {
// Message a ecrire dans le fichier du jour carte SD
String dataMessage;
String appendMessage;
String headerMessage;
//String closeMessage;
String modeIris;
String etatPID;
String modeVentiloStatus;
// Si IRIS MODE AUTO (FALSE)
if (flag_iris_manu_on_off == false) {
modeIris ="Auto";
if (myPID.GetMode() == AUTOMATIC) {
etatPID = "Actif";
}
else {
etatPID = "Inactif";
PidMod = "";
}
}
else {
modeIris = "Manu";
etatPID = "Inactif";
PidMod = "";
}
// Si VENTILO MODE AUTO (FALSE)
if (flag_ventilo_manu_on_off == false) {
modeVentiloStatus ="Auto";
}
else {
modeVentiloStatus = "Manu";
}
dataMessage = "{ 'Date': '"; // Ouverture dataMessage
dataMessage += DateHour;
dataMessage += "', 'SONDES': {";
dataMessage += " '";
dataMessage += SondeNom[3];
dataMessage += "': ";
dataMessage += ftoS(SondeTempC[3], 2, true); // Sonde Exterieure
dataMessage += ", '";
dataMessage += SondeNom[0];
dataMessage += "': ";
dataMessage += ftoS(SondeTempC[0], 2, true); // Sonde Moteur
dataMessage += ", '";
dataMessage += SondeNom[1];
dataMessage += "': ";
dataMessage += ftoS(SondeTempC[1], 2, true); // Sonde Chaud
dataMessage += ", '";
dataMessage += SondeNom[2];
dataMessage += "': ";
dataMessage += ftoS(SondeTempC[2], 2, true); // Sonde Froid
dataMessage += "}";
dataMessage += ", 'IRIS': {";
dataMessage += " 'Mode': '";
dataMessage += modeIris;
dataMessage += "'";
dataMessage += ", 'Position': ";
dataMessage += map2(Steppercurrent, home, maxtravel, DiamIrisMaxi, DiamIrisMini);
dataMessage += "}";
dataMessage += ", 'VENTILATEUR': {";
dataMessage += " 'Mode': '";
dataMessage += modeVentiloStatus;
dataMessage += "'";
dataMessage += ", 'Etat': '";
dataMessage += etatVentilo;
dataMessage += "'";
dataMessage += ", 'RPM': ";
dataMessage += rpm;
dataMessage += ", 'PWM': ";
dataMessage += pwm;
dataMessage += ", 'CorrPWM': ";
dataMessage += correctionPwm;
dataMessage += ", 'Temp_ON_Min': ";
dataMessage += ftoS((Temp_ON_moteur + Hyst_moteur) * coef_temp, 1, true);
dataMessage += ", 'Temp_OFF_Max': ";
dataMessage += ftoS(Temp_OFF_moteur * coef_temp, 1, true);
dataMessage += " }";
dataMessage += ", 'PID': {";
dataMessage += " 'Etat': '";
dataMessage += etatPID;
dataMessage += "'";
dataMessage += ", 'Mode': '";
dataMessage += PidMod;
dataMessage += "'";
dataMessage += ", 'Consigne': ";
dataMessage += ftoS(SetpointPID, 1, true);
dataMessage += " }";
dataMessage += " }"; // Fermeture dataMessage
//headerMessage = "data = [\r\n";
//headerMessage += dataMessage;
//appendMessage = ",\r\n"; //retour a la ligne avant message
//appendMessage += dataMessage;
//closeMessage = "\r\n]";
/*
{ 'Date': '2023-12-09T00:30:00',
'SONDES': { 'Sext': -22,00, 'Smoteur': 22,00, 'Schaud': 19,44, 'Sfroid': 22,06},
'IRIS': { 'Mode': 'Auto', 'Position': 125},
'VENTILATEUR': { 'Mode': 'Auto', 'Etat': 'Arret', 'RPM': 0, 'PWM': 0, 'Temp_ON_Min': 25,0, 'Temp_OFF_Max': 55,0 },
'PID': { 'Etat': 'Inactif', 'Mode': '', 'Consigne': 30,0 }
}
*/
if (SD.exists(YearMonthDayFile)) { // Si le fichier du jour existe deja on continu a ecrire a la suite
appendMessage = ",\r\n"; //retour a la ligne avant message
appendMessage += dataMessage;
appendFile(SD, YearMonthDayFile, appendMessage.c_str());
}
else { // Le fichier du jour existe pas
headerMessage = "data = [\r\n";
headerMessage += dataMessage;
if (SD.exists(Repertoire)) { // si data existe
if (SD.exists(Year)) { // Si l'annee existe
if(SD.exists(YearMonth)) { // Si le mois existe
writeFile(SD, YearMonthDayFile, headerMessage.c_str()); // On cree le fichier du jour
closelastfile(); // on cloture le fichier du jour precedent
}
else { // Sinon on cree mois + fichier du jour
createDir(SD, YearMonth);
writeFile(SD, YearMonthDayFile, headerMessage.c_str());
closelastfile(); // on cloture celui du jour precedent
}
}
else { // Sinon on cree annee + mois + fichier du jour
createDir(SD, Year);
createDir(SD, YearMonth);
writeFile(SD, YearMonthDayFile, headerMessage.c_str());
closelastfile(); // on cloture celui du jour precedent
}
}
else {
createDir(SD, Repertoire);
createDir(SD, Year);
createDir(SD, YearMonth);
writeFile(SD, YearMonthDayFile, headerMessage.c_str());
closelastfile(); // on cloture celui du jour precedent
}
}
///*if (serialDebug) */Serial.println(dataMessage); // Affiche la ligne que l'on vient d'enregistrer dans le fichier
}
// ********************
// *** FIN CARTE SD ***
// ********************
// ************************
// ***** DEBUT MENU *****
// ************************
// -------------------------------------------------------------------------------------------------
// menus below here
// -------------------------------------------------------------------------------------------------
// Start the default menu
void defaultMenu() {
mainMenu();
}
// -----------------------------------------------
// **************
// MENU PRINCIPAL
// **************
// 0: main menu
void mainMenu() {
resetMenu(); // clear any previous menu
menuMode = menu; // enable menu mode
oledMenu.noOfmenuItems = 11; // set the number of items in this menu
oledMenu.menuTitle = "Menu Principal"; // menus title (used to identify it)
oledMenu.menuItems[1] = "OFF / ON"; // ON/OFF General
oledMenu.menuItems[2] = "Sondes";
oledMenu.menuItems[3] = "Ventilateur";
oledMenu.menuItems[4] = "IRIS";
oledMenu.menuItems[5] = "Courbe Ventilo";
oledMenu.menuItems[6] = "Wifi";
oledMenu.menuItems[7] = "Date / Heure";
oledMenu.menuItems[8] = "Config";
oledMenu.menuItems[9] = "Redemarrage";
oledMenu.menuItems[10] = "Menus Off";
oledMenu.menuItems[11] = "Accueil";
} // mainMenu
// *********
// SOUS MENU
// *********
// 1 : OFF / ON
// 2: Sondes menu
void SondesMenu() {
resetMenu(); // clear any previous menu
menuMode = menu; // enable menu mode
oledMenu.noOfmenuItems = 7; // set the number of items in this menu
oledMenu.menuTitle = "Sondes Temp"; // menus title (used to identify it)
oledMenu.menuItems[1] = "Sonde Exterieure"; // set the menu items
oledMenu.menuItems[2] = "Sonde Moteur";
oledMenu.menuItems[3] = "Sonde Chaud";
oledMenu.menuItems[4] = "Sonde Froid";
oledMenu.menuItems[5] = "Sondes Erreurs";
oledMenu.menuItems[6] = "Sondes Rempla.";
oledMenu.menuItems[7] = "Retour";
} // SondesMenu
// 3: Ventilateur menu
void VentilMenu() {
resetMenu(); // clear any previous menu
menuMode = menu; // enable menu mode
oledMenu.noOfmenuItems = 13; // set the number of items in this menu
oledMenu.menuTitle = "Menu Ventilateur"; // menus title (used to identify it)
oledMenu.menuItems[1] = "Ven Auto / Manu";
oledMenu.menuItems[2] = "RPM Ventilateur";
oledMenu.menuItems[3] = "Temp. ON";
oledMenu.menuItems[4] = "Hyst Temp. ON";
oledMenu.menuItems[5] = "Temp. OFF";
oledMenu.menuItems[6] = "Heure Deb Jour";
oledMenu.menuItems[7] = "Vitesse Jour";
oledMenu.menuItems[8] = "Heure Deb Nuit";
oledMenu.menuItems[9] = "Vitesse Nuit";
oledMenu.menuItems[10] = "Mode Boost ON";
oledMenu.menuItems[11] = "Vitesse Boost";
oledMenu.menuItems[12] = "Duree Boost";
oledMenu.menuItems[13] = "Retour";
} // VentilMenu
// 4: IRIS menu (Moteur Pas a Pas)
void IrisMenu() {
resetMenu(); // clear any previous menu
menuMode = menu; // enable menu mode
oledMenu.noOfmenuItems = 5; // set the number of items in this menu
oledMenu.menuTitle = "Menu IRIS"; // menus title (used to identify it)
oledMenu.menuItems[1] = "Iri Auto / Manu"; // set the menu items
oledMenu.menuItems[2] = "IRIS Position";
oledMenu.menuItems[3] = "IRIS Consigne";
oledMenu.menuItems[4] = "IRIS Tmin Arret"; // Temperature coupure PID
oledMenu.menuItems[5] = "Retour";
} // IrisMenu
// 5: Courbe Ventilation menu (Vitesse dynamique)
void CourbeMenu() {
resetMenu(); // clear any previous menu
menuMode = menu; // enable menu mode
oledMenu.noOfmenuItems = 10; // set the number of items in this menu
oledMenu.menuTitle = "M Courbe Ventilo"; // menus title (used to identify it)
oledMenu.menuItems[1] = "Courbe Ventilation"; // set the menu items
oledMenu.menuItems[2] = "Vitesse Base";
oledMenu.menuItems[3] = "Vitesse Inter.";
oledMenu.menuItems[4] = "Vitesse Maxi";
oledMenu.menuItems[5] = "Vitesse Offset";
oledMenu.menuItems[6] = "Temp. Base";
oledMenu.menuItems[7] = "Temp. Inter.";
oledMenu.menuItems[8] = "Temp. Mini";
oledMenu.menuItems[9] = "Temp. Offset";
oledMenu.menuItems[10] = "Retour";
} // CourbeMenu
// 6: WIFI menu
void WifiMenu() {
resetMenu(); // clear any previous menu
menuMode = menu; // enable menu mode
oledMenu.noOfmenuItems = 3; // set the number of items in this menu
oledMenu.menuTitle = "Menu WIFI"; // menus title (used to identify it)
oledMenu.menuItems[1] = "Statut Wifi"; // set the menu items
oledMenu.menuItems[2] = "Reset Wifi";
oledMenu.menuItems[3] = "Retour";
} // WifiMenu
// 7: Date / Heure menu
void DateMenu() {
resetMenu(); // clear any previous menu
menuMode = menu; // enable menu mode
oledMenu.noOfmenuItems = 3; // set the number of items in this menu
oledMenu.menuTitle = "Menu Date/Heure"; // menus title (used to identify it)
oledMenu.menuItems[1] = "Statut Date/Heure"; // set the menu items
oledMenu.menuItems[2] = "Config Date/Heure";
oledMenu.menuItems[3] = "Retour";
} // DateMenu
// 8: Config menu
void ConfigMenu() {
resetMenu(); // clear any previous menu
menuMode = menu; // enable menu mode
oledMenu.noOfmenuItems = 4; // set the number of items in this menu
oledMenu.menuTitle = "Menu Config"; // menus title (used to identify it)
oledMenu.menuItems[1] = "Charger"; // set the menu items
oledMenu.menuItems[2] = "Enregistrer";
oledMenu.menuItems[3] = "Debug PWM Ventilo";
oledMenu.menuItems[4] = "Retour";
} // ConfigMenu
/*
Message
->
*/
// actions for menu selections are put in here // Go to SOUS MENU
void menuActions() {
// ******************
// 0: MENU PRINCIPAL
// ******************
// actions when an item is selected in "Menu_Princ"
if (oledMenu.menuTitle == "Menu Principal") {
// 1: OFF / ON Recuperateur de chaleur
if (oledMenu.selectedMenuItem == 1) {
if (serialDebug) Serial.println("Menu_Princ: Recuperateur de chaleur: OFF / ON");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "OFF / ON";
oledMenu.mValueLow = 0;
oledMenu.mValueHigh = 1;
oledMenu.mValueStep = 1;
oledMenu.mValueEntered = flag_ventilo_on_off; // starting value
}
// 2: Sous menu Sonde de Temperature
if (oledMenu.selectedMenuItem == 2) {
if (serialDebug) Serial.println("Menu_Princ: Go to Sondes_Temp MENU");
SondesMenu(); // Va vers Sous menu
}
// 3: Sous menu Ventilateur
if (oledMenu.selectedMenuItem == 3) {
if (serialDebug) Serial.println("Menu_Princ: Go to Ventilateur MENU");
VentilMenu(); // Va vers Sous menu
}
// 4: Sous menu IRIS
if (oledMenu.selectedMenuItem == 4) {
if (serialDebug) Serial.println("Menu_Princ: Go to IRIS MENU");
IrisMenu(); // Va vers Sous menu
}
// 5: Sous menu COURBE VENTILO
if (oledMenu.selectedMenuItem == 5) {
if (serialDebug) Serial.println("Menu_Princ: Go to COURBE VENTILO MENU");
CourbeMenu(); // Va vers Sous menu
}
// 6: Sous menu WIFI
if (oledMenu.selectedMenuItem == 6) {
if (serialDebug) Serial.println("Menu_Princ: Go to WIFI MENU");
WifiMenu(); // Va vers Sous menu
}
// 7: Sous menu DATE
if (oledMenu.selectedMenuItem == 7) {
if (serialDebug) Serial.println("Menu_Princ: Go to Date MENU");
DateMenu(); // Va vers Sous menu
}
// 8: Sous menu CONFIG
if (oledMenu.selectedMenuItem == 8) {
if (serialDebug) Serial.println("Menu_Princ: Go to Config MENU");
ConfigMenu(); // Va vers Sous menu
}
// 9: Redemarrage ESP32
if (oledMenu.selectedMenuItem == 9) {
if (serialDebug) Serial.println("Menu_Princ: Redemarrage");
resetMenu();
displayMessage("Redemarrage", "\nRedemarrage\nESP32 ?\n"); // 21 chars per line, "\n" = next line
}
// 10: turn menu/OLED OFF
else if (oledMenu.selectedMenuItem == 10) {
if (serialDebug) Serial.println("Menu_Princ: menu off");
resetMenu(); // turn menus off
}
// 11: retour page d'Accueil
if (oledMenu.selectedMenuItem == 11) {
if (serialDebug) Serial.println("Menu_Princ: back to Accueil");
resetMenu();
AccueilMenu();
}
oledMenu.selectedMenuItem = 0; // clear menu item selected flag
}
// ***************
// ** SOUS MENU **
// ***************
// 1: SousMenu : OFF / ON
// 2: SousMenu : SONDES MENU
// actions when an item is selected in the Sondes_Temp menu
if (oledMenu.menuTitle == "Sondes Temp") {
// Statut sonde exterieure
if (oledMenu.selectedMenuItem == 1) {
if (serialDebug) Serial.println("Sondes_Temp: Sonde exterieure");
resetMenu();
menuMode = message;
oledMenu.menuTitle = "Sonde Exterieure"; // title (used to identify which number was entered)
}
// Statut sonde moteur
if (oledMenu.selectedMenuItem == 2) {
if (serialDebug) Serial.println("Sondes_Temp: Sonde moteur");
resetMenu();
menuMode = message;
oledMenu.menuTitle = "Sonde Moteur"; // title (used to identify which number was entered)
}
// Statut sonde chaud
if (oledMenu.selectedMenuItem == 3) {
if (serialDebug) Serial.println("Sondes_Temp: Sonde chaud");
resetMenu();
menuMode = message;
oledMenu.menuTitle = "Sonde Chaud"; // title (used to identify which number was entered)
}
// Statut sonde froid
if (oledMenu.selectedMenuItem == 4) {
if (serialDebug) Serial.println("Sondes_Temp: Sonde froid");
resetMenu();
menuMode = message;
oledMenu.menuTitle = "Sonde Froid"; // title (used to identify which number was entered)
}
// Erreur Sondes
if (oledMenu.selectedMenuItem == 5) {
if (serialDebug) Serial.println("Sondes_Temp: Sondes Erreur");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Sondes Erreurs"; // title (used to identify which number was entered)
}
// Remplacement sondes
if (oledMenu.selectedMenuItem == 6) {
if (serialDebug) Serial.println("Sondes_Temp: Sondes Rempla.");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Sondes Rempla."; // title (used to identify which number was entered)
}
// back to main menu
if (oledMenu.selectedMenuItem == 7) {
if (serialDebug) Serial.println("Sondes_Temp: back to main menu");
defaultMenu();
}
oledMenu.selectedMenuItem = 0; // clear menu item selected flag
}
// 3: SousMenu : VENTILATEUR MENU
// actions when an item is selected in the Ventilateur menu
if (oledMenu.menuTitle == "Menu Ventilateur") {
// Ventilateur: Mode Auto OFF / Manu ON
if (oledMenu.selectedMenuItem == 1) {
if (serialDebug) Serial.println("Ventilateur: Mode Auto / Manu");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Ven Auto / Manu"; // title (used to identify which number was entered)
oledMenu.mValueLow = 0; // minimum value allowed 0
oledMenu.mValueHigh = 1; // maximum value allowed 1
oledMenu.mValueStep = 1; // step size 1
oledMenu.mValueEntered = flag_ventilo_manu_on_off; // starting value
}
// Ventilateur: Vitesse Statut RPM et modif
if (oledMenu.selectedMenuItem == 2) {
if (serialDebug) Serial.println("Ventilateur: RPM Ventilateur");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "RPM Ventilateur"; // title (used to identify which number was entered)
oledMenu.mValueLow = 0; // minimum value allowed
oledMenu.mValueStep = 1; // step size
if (flag_Debug_PWM_Ventilo == false) { // si flag_Debug_PWM_Ventilo -> FALSE -> PWM avec Numero de la vitesse du tableau VitesseVentil[Nbrevitesse-2]
// PWM avec 19 Vitesses
oledMenu.mValueHigh = Nbrevitesse-2; // maximum value allowed (Nbrevitesse-2 [ici 21 -2 -> 19])
if (Flag_vitesseDynamique_ON == true) { // Gestion dynamique vitesse ventilo Mode Dynamique Actif (ON) TRUE
oledMenu.mValueEntered = RechercheNumVitesseDyn(); // starting value
}
else { // Mode Dynamique Inactif (OFF) FALSE
for (uint8_t i = 0; i < Nbrevitesse-1; i++) {
if (VitesseVentil[i] == pwm) { // recherche vitesse actuelle dans Tableau
oledMenu.mValueEntered = i; // starting value
break;
}
}
}
if (serialDebug) {
Serial.print("pwm : ");
Serial.print(pwm);
Serial.print(", VitesseVentil[");
Serial.print(oledMenu.mValueEntered);
Serial.print("] : ");
Serial.println(VitesseVentil[oledMenu.mValueEntered]);
}
}
else { // si flag_Debug_PWM_Ventilo -> TRUE -> PWM avec vitesse de 0 à Vmaxpwm PWM (Mode Debug)
// PWM de 0 à Vmaxpwm (2047)
oledMenu.mValueHigh = VitesseVentil[Nbrevitesse-1]; // maximum value allowed (Nbrevitesse-1 [ici 21 -1 -> 20])
oledMenu.mValueEntered = pwm; // starting value
}
} // Fin
// Ventilateur: Seuil Temp moteur ON (Valeur sonde chaud) Demarrage TEMP MIN. HOTTE
if (oledMenu.selectedMenuItem == 3) {
if (serialDebug) Serial.println("Ventilateur: Seuil Temp moteur ON (Valeur sonde chaud)");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Temp. ON"; // title (used to identify which number was entered)
oledMenu.mValueLow = Temp_min_chaud_allowed; // minimum value allowed 25,0 °C (250 x10)
oledMenu.mValueHigh = Temp_max_chaud_allowed; // maximum value allowed 80,0 °C (800 x10)
oledMenu.mValueStep = 5; // step size 0,5°C
oledMenu.mValueEntered = Temp_ON_moteur; // starting value
}
// Ventilateur: Seuil Hysteresis Temp moteur ON (Valeur sonde chaud) Demarrage TEMP MIN. HOTTE + HYSTERESIS
if (oledMenu.selectedMenuItem == 4) {
if (serialDebug) Serial.println("Ventilateur: Seuil Hysteresis Temp moteur ON (Valeur sonde chaud)");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Hyst Temp. ON"; // title (used to identify which number was entered)
oledMenu.mValueLow = Temp_min_Hyst_allowed; // minimum value allowed 0 °C (0 x10)
oledMenu.mValueHigh = Temp_max_Hyst_allowed; // maximum value allowed 5,0 °C (50 x10)
oledMenu.mValueStep = 5; // step size 0,5°C
oledMenu.mValueEntered = Hyst_Temp_ON_moteur; // starting value
}
// Ventilateur: Seuil Temp moteur OFF (Valeur sonde moteur) Arret depassement TEMP MAX. MOTEUR
if (oledMenu.selectedMenuItem == 5) {
if (serialDebug) Serial.println("Ventilateur: Seuil Temp moteur OFF (Valeur sonde moteur)");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Temp. OFF"; // title (used to identify which number was entered)
oledMenu.mValueLow = Temp_min_moteur_allowed; // minimum value allowed 25,0 °C (250 x10)
oledMenu.mValueHigh = Temp_max_moteur_allowed; // maximum value allowed 60,0 °C (600 x10)
oledMenu.mValueStep = 5; // step size 0,5°C
oledMenu.mValueEntered = Temp_OFF_moteur; // starting value
}
// Ventilateur: Mode Jour / Nuit (Heure Deb Jour)
if (oledMenu.selectedMenuItem == 6) {
if (serialDebug) Serial.println("Ventilateur: Mode Jour / Nuit (Heure Deb Jour)");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Heure Deb Jour"; // title (used to identify which number was entered)
oledMenu.mValueLow = 0; // minimum value allowed 0
oledMenu.mValueHigh = 86100L; // maximum value allowed 24 x 60 x 60 -300 (-5min)
oledMenu.mValueStep = 300; // step size 5 x 60 -> 300 (5min)
oledMenu.mValueEntered = START_MODE_JOUR; // starting value
}
// Ventilateur: Vitesse moteur pour le mode Jour
if (oledMenu.selectedMenuItem == 7) {
if (serialDebug) Serial.println("Ventilateur: Vitesse moteur pour le mode Jour)");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Vitesse Jour"; // title (used to identify which number was entered)
oledMenu.mValueLow = 0; // minimum value allowed 0
oledMenu.mValueHigh = Nbrevitesse-2; // maximum value allowed (Nbrevitesse-2 [ici 21 -2 -> 19])
oledMenu.mValueStep = 1; // step size
oledMenu.mValueEntered = Vit_jour; // starting value
}
// Ventilateur: Mode Jour / Nuit (Heure Deb Nuit)
if (oledMenu.selectedMenuItem == 8) {
if (serialDebug) Serial.println("Ventilateur: Mode Jour / Nuit (Heure Deb Nuit)");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Heure Deb Nuit"; // title (used to identify which number was entered)
oledMenu.mValueLow = 0; // minimum value allowed 0
oledMenu.mValueHigh = 86100L; // maximum value allowed 24 x 60 x 60 -300 (-5min)
oledMenu.mValueStep = 300; // step size 5 x 60 -> 300 (5min)
oledMenu.mValueEntered = START_MODE_NUIT; // starting value
}
// Ventilateur: Vitesse moteur pour le mode Nuit
if (oledMenu.selectedMenuItem == 9) {
if (serialDebug) Serial.println("Ventilateur: Vitesse moteur pour le mode Nuit)");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Vitesse Nuit"; // title (used to identify which number was entered)
oledMenu.mValueLow = 0; // minimum value allowed 0
oledMenu.mValueHigh = Nbrevitesse-2; // maximum value allowed (Nbrevitesse-2 [ici 21 -2 -> 19])
oledMenu.mValueStep = 1; // step size
oledMenu.mValueEntered = Vit_nuit; // starting value
}
// Ventilateur: Mode Boost ON
if (oledMenu.selectedMenuItem == 10) {
if (serialDebug) Serial.println("Ventilateur: Mode Boost ON");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Mode Boost ON"; // title (used to identify which number was entered)
oledMenu.mValueLow = 0; // minimum value allowed 0
oledMenu.mValueHigh = 1; // maximum value allowed 1
oledMenu.mValueStep = 1; // step size 1
oledMenu.mValueEntered = flag_ventilo_boost_on_off; // starting value
}
// Ventilateur: Vitesse moteur pour le mode Boost
if (oledMenu.selectedMenuItem == 11) {
if (serialDebug) Serial.println("Ventilateur: Vitesse moteur pour le mode Boost)");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Vitesse Boost"; // title (used to identify which number was entered)
oledMenu.mValueLow = 0; // minimum value allowed 0
oledMenu.mValueHigh = Nbrevitesse-2; // maximum value allowed (Nbrevitesse-2 [ici 21 -2 -> 19])
oledMenu.mValueStep = 1; // step size
oledMenu.mValueEntered = Vit_boost; // starting value
}
// Ventilateur: Duree Boost
if (oledMenu.selectedMenuItem == 12) {
if (serialDebug) Serial.println("Ventilateur: Duree Boost");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Duree Boost"; // title (used to identify which number was entered)
oledMenu.mValueLow = 300; // minimum value allowed 300 (5min)
oledMenu.mValueHigh = 18000L; // maximum value allowed 5 x 60 x 60 (5H00)
oledMenu.mValueStep = 300; // step size 5 x 60 -> 300 (5min)
oledMenu.mValueEntered = TIMER_MODE_BOOST; // starting value
}
// back to main menu
if (oledMenu.selectedMenuItem == 13) {
if (serialDebug) Serial.println("Ventilateur: back to main menu");
defaultMenu();
}
oledMenu.selectedMenuItem = 0; // clear menu item selected flag
}
// 4: SousMenu : IRIS MENU
// actions when an item is selected in the Iris menu
if (oledMenu.menuTitle == "Menu IRIS") {
// Iris_Menu: Mode Auto OFF / Manu ON
if (oledMenu.selectedMenuItem == 1) {
if (serialDebug) Serial.println("Iris_Menu: Iri Auto / Manu");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Iri Auto / Manu"; // title (used to identify which number was entered)
oledMenu.mValueLow = 0; // minimum value allowed 0
oledMenu.mValueHigh = 1; // maximum value allowed 1
oledMenu.mValueStep = 1; // step size 1
oledMenu.mValueEntered = flag_iris_manu_on_off; // starting value
}
// Iris_Menu: Position Statut
if (oledMenu.selectedMenuItem == 2) {
if (serialDebug) Serial.println("Iris_Menu: Position Statut");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "IRIS Position"; // title (used to identify which number was entered)
oledMenu.mValueLow = home; // minimum value allowed -> 0
oledMenu.mValueHigh = NbreStepIris; // maximum value allowed -> 115
oledMenu.mValueStep = -1; // step size (Inversion sens) -1
if (stepper.distanceToGo() != 0 && flag_iris_manu_on_off == true ) { // Permet de conserver la valeur precedement entrée (si sort et re-rentre dans le menu) si mode manu et IRIS toujours en train de se deplacer vers l'ancienne position
oledMenu.mValueEntered = round(TempPosIris / (float)PasStepIris); // starting value (recupere l'ancienne demande de mouvement)
// valeur entre 0 et 115
}
else {
//oledMenu.mValueEntered = round(stepper.currentPosition() / (float)PasStepIris); // starting value (recupere la position actuel du moteur pas a pas)
oledMenu.mValueEntered = round(Steppercurrent / (float)PasStepIris); // starting value (recupere la position actuel du moteur pas a pas)
// valeur entre 0 et 115
}
}
// Iris_Menu: IRIS Temperature de Consigne
if (oledMenu.selectedMenuItem == 3) {
if (serialDebug) Serial.println("Iris_Menu: IRIS Temperature de Consigne");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "IRIS Consigne"; // title (used to identify which number was entered)
oledMenu.mValueLow = Temp_min_ConsignePID_allowed; // minimum value allowed 25 °C
oledMenu.mValueHigh = Temp_max_ConsignePID_allowed; // maximum value allowed 55 °C
oledMenu.mValueStep = 5; // step size 0,5 °C
oledMenu.mValueEntered = ConsignePID; // starting value
}
// Iris_Menu: IRIS Temperature mini Arret PID (Niveau Temperature Smoteur)
if (oledMenu.selectedMenuItem == 4) {
if (serialDebug) Serial.println("Iris_Menu: IRIS Temperature mini Arret PID");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "IRIS Tmin Arret"; // title (used to identify which number was entered)
oledMenu.mValueLow = Temp_min_coupure_allowed; // minimum value allowed 25 °C
oledMenu.mValueHigh = Temp_max_coupure_allowed; // maximum value allowed 45 °C
oledMenu.mValueStep = 5; // step size 0,5 °C
oledMenu.mValueEntered = ConsignePID_coupure; // starting value 37 °C
}
// back to main menu
if (oledMenu.selectedMenuItem == 5) {
if (serialDebug) Serial.println("Iris_Menu: back to main menu");
defaultMenu();
}
oledMenu.selectedMenuItem = 0; // clear menu item selected flag
}
// 5: SousMenu : COURBE VENTILO MENU
// actions when an item is selected in the Courbe Ventilo menu
if (oledMenu.menuTitle == "M Courbe Ventilo") {
// CourbeVentilo_Menu: Courbe Ventilo
if (oledMenu.selectedMenuItem == 1) {
if (serialDebug) Serial.println("CourbeVentilo_Menu: Courbe Ventilation");
resetMenu();
menuMode = message;
oledMenu.menuTitle = "Courbe Ventilation";
CourbeVentilation();
}
// CourbeVentilo_Menu: Vitesse Base
if (oledMenu.selectedMenuItem == 2) {
if (serialDebug) Serial.println("CourbeVentilo_Menu: Vitesse Base");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Vitesse Base"; // title (used to identify which number was entered)
oledMenu.mValueLow = 6; // minimum value allowed vitesse 6 1350 tr/min
oledMenu.mValueHigh = 9; // maximum value allowed vitesse 9 1500 tr/min
oledMenu.mValueStep = 1; // step size
oledMenu.mValueEntered = Vit_Tbase; // starting value vitesse 8
}
// CourbeVentilo_Menu: Vitesse Inter.
if (oledMenu.selectedMenuItem == 3) {
if (serialDebug) Serial.println("CourbeVentilo_Menu: Vitesse Inter.");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Vitesse Inter."; // title (used to identify which number was entered)
oledMenu.mValueLow = 9; // minimum value allowed vitesse 9 1500 tr/min
oledMenu.mValueHigh = 14; // maximum value allowed vitesse 13 +1 -> 14 1750 tr/min
oledMenu.mValueStep = 1; // step size
oledMenu.mValueEntered = Vit_Tinte; // starting value vitesse 12
}
// CourbeVentilo_Menu: Vitesse Maxi
if (oledMenu.selectedMenuItem == 4) {
if (serialDebug) Serial.println("CourbeVentilo_Menu: Vitesse Maxi");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Vitesse Maxi"; // title (used to identify which number was entered)
oledMenu.mValueLow = 13; // minimum value allowed vitesse 13 1700 tr/min
oledMenu.mValueHigh = 16; // maximum value allowed vitesse 16 1850 tr/min
oledMenu.mValueStep = 1; // step size
oledMenu.mValueEntered = Vit_Tmaxi; // starting value vitesse 14
}
// CourbeVentilo_Menu: Vitesse Offset (PWM Brut)
if (oledMenu.selectedMenuItem == 5) {
if (serialDebug) Serial.println("CourbeVentilo_Menu: Vitesse Offset");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Vitesse Offset"; // title (used to identify which number was entered)
oledMenu.mValueLow = -50; // minimum value allowed -50 % de la vitesse en cours
oledMenu.mValueHigh = 50; // maximum value allowed +50 % de la vitesse en cours
oledMenu.mValueStep = 1; // step size
oledMenu.mValueEntered = Vit_offset; // starting value PWM 15
}
// CourbeVentilo_Menu: Temp. Base
if (oledMenu.selectedMenuItem == 6) {
if (serialDebug) Serial.println("CourbeVentilo_Menu: Temp. Base");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Temp. Base"; // title (used to identify which number was entered)
oledMenu.mValueLow = 50; // minimum value allowed 5,0 °C (50 x 0.1)
oledMenu.mValueHigh = 250; // maximum value allowed 25,0 °C (250 x 0.1)
oledMenu.mValueStep = 1; // step size 0,1°C
oledMenu.mValueEntered = Temp_Vbase; // starting value 12,0°C
}
// CourbeVentilo_Menu: Temp. Inter.
if (oledMenu.selectedMenuItem == 7) {
if (serialDebug) Serial.println("CourbeVentilo_Menu: Temp. Inter.");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Temp. Inter."; // title (used to identify which number was entered)
oledMenu.mValueLow = -50; // minimum value allowed -5,0 °C (-50 x 0.1)
oledMenu.mValueHigh = 50; // maximum value allowed 5,0 °C (50 x 0.1)
oledMenu.mValueStep = 1; // step size 0,1°C
oledMenu.mValueEntered = Temp_Vinte; // starting value 0,0°C
}
// CourbeVentilo_Menu: Temp. Mini
if (oledMenu.selectedMenuItem == 8) {
if (serialDebug) Serial.println("CourbeVentilo_Menu: Temp. Mini");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Temp. Mini"; // title (used to identify which number was entered)
oledMenu.mValueLow = -250; // minimum value allowed -25,0 °C (-250 x 0.1)
oledMenu.mValueHigh = -50; // maximum value allowed -5,0 °C (-50 x 0.1)
oledMenu.mValueStep = 1; // step size 0,1°C
oledMenu.mValueEntered = Temp_Vmini; // starting value -12,0°C
}
// CourbeVentilo_Menu: Temp. Offset
if (oledMenu.selectedMenuItem == 9) {
if (serialDebug) Serial.println("CourbeVentilo_Menu: Temp. Offset");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Temp. Offset"; // title (used to identify which number was entered)
oledMenu.mValueLow = -25; // minimum value allowed -2,5 °C (-25 x 0.1)
oledMenu.mValueHigh = 25; // maximum value allowed 2,5 °C (25 x 0.1)
oledMenu.mValueStep = 1; // step size 0,1°C
oledMenu.mValueEntered = Temp_offset; // starting value 0,5°C
}
// back to main menu
if (oledMenu.selectedMenuItem == 10) {
if (serialDebug) Serial.println("CourbeVentilo_Menu: back to main menu");
defaultMenu();
}
oledMenu.selectedMenuItem = 0; // clear menu item selected flag
}
// 6: SousMenu : WIFI MENU // AVOIR AFAIRE
// actions when an item is selected in the Wifi menu
if (oledMenu.menuTitle == "Menu WIFI") {
// Wifi_Menu: Statut Wifi
if (oledMenu.selectedMenuItem == 1) {
if (serialDebug) Serial.println("Wifi_Menu: Statut Wifi");
resetMenu();
menuMode = message;
oledMenu.menuTitle = "Statut Wifi"; // title (used to identify which number was entered)
}
// Wifi_Menu: Reset Wifi
if (oledMenu.selectedMenuItem == 2) {
if (serialDebug) Serial.println("Wifi_Menu: Reset Wifi");
resetMenu();
//assistant: < line 1 > < line 2 > < line 3 > < line 4 >
displayMessage("Reset Wifi", "\nReset Wifi en\nMODE ACCES POINT ???\nSSID : ESP-WIFI-AP\nIP : 10.0.0.1\n"); // Menu
}
// back to main menu
if (oledMenu.selectedMenuItem == 3) {
if (serialDebug) Serial.println("Wifi_Menu: back to main menu");
defaultMenu();
}
oledMenu.selectedMenuItem = 0; // clear menu item selected flag
}
//******************* ///////////////////// *********************** DEBUT MENU CONFIG DATE / HEURE
// 7: SousMenu : DATE MENU
// actions when an item is selected in the Date Menu
if (oledMenu.menuTitle == "Menu Date/Heure") {
// Date_Menu: Heure actuelle Statut
if (oledMenu.selectedMenuItem == 1) {
if (serialDebug) Serial.println("Date_Menu: Statut Date/Heure");
resetMenu();
menuMode = message;
oledMenu.menuTitle = "Statut Date/Heure"; // title (used to identify which number was entered)
}
// Date_Menu: Config manu date heure
if (oledMenu.selectedMenuItem == 2) {
if (serialDebug) Serial.println("Date_Menu: Config Date/Heure"); // -->> CONFIG DATE / HEURE
resetMenu();
menuMode = menu;
oledMenu.menuTitle = "Config Date/Heure"; // title (used to identify which number was entered) // VOIR 7.2 plus bas -->> CONFIG DATE / HEURE
}
// back to main menu
if (oledMenu.selectedMenuItem == 3) {
if (serialDebug) Serial.println("Date_Menu: back to main menu");
defaultMenu();
}
oledMenu.selectedMenuItem = 0; // clear menu item selected flag
}
// 7.2: SousMenu : SOUS SOUS-MENU DATE MENU -->> CONFIG DATE / HEURE
// actions when an item is selected in the SOUS SOUS-MENU : Config Date/Heure
if (oledMenu.menuTitle == "Config Date/Heure") {
// Annees
if (oledMenu.selectedMenuItem == 1) {
//if (serialDebug) Serial.println("Config Date/Heure: Annees");
menuMode = value;
oledMenu.menuTitle = "Config Date/Heure"; //1
oledMenu.mValueLow = 2024; // Min annee 2024
oledMenu.mValueHigh = 2093; // Max annee 2094 (mardi 19 janvier 2094 04:14:07) [2038+56]
oledMenu.mValueStep = 1;
if (contenuDateNum[0] != -1) {
oledMenu.mValueEntered = contenuDateNum[0]; // starting value // Valeur depart si contenuDateNum[0] pas vide
}
else {
oledMenu.mValueEntered = oledMenu.mValueLow; // starting value
}
}
// Mois
if (oledMenu.selectedMenuItem == 2) {
//if (serialDebug) Serial.println("Config Date/Heure: Mois");
menuMode = value;
oledMenu.menuTitle = "Config Date/Heure"; //1
oledMenu.mValueLow = 1;
oledMenu.mValueHigh = 12;
oledMenu.mValueStep = 1;
if (contenuDateNum[1] != -1) {
oledMenu.mValueEntered = contenuDateNum[1]; // starting value // Valeur depart si contenuDateNum[1] pas vide
}
else {
oledMenu.mValueEntered = oledMenu.mValueLow; // starting value
}
}
// Jours
if (oledMenu.selectedMenuItem == 3) {
//if (serialDebug) Serial.println("Config Date/Heure: Jours");
menuMode = value;
oledMenu.menuTitle = "Config Date/Heure"; //1
oledMenu.mValueLow = 1;
if (contenuDateNum[1] != -1) { // Mois
if (contenuDateNum[1] == 2 && contenuDateNum[0] != -1) { // february + Annee
oledMenu.mValueHigh = NbreJourmonth[contenuDateNum[1]-1] + is_leap_year(contenuDateNum[0]); // MAX (si annnée Bissextile [29 FEV])
}
else {
oledMenu.mValueHigh = NbreJourmonth[contenuDateNum[1]-1]; // MAX (Nbre jour en fonction du Mois)
}
}
else {
oledMenu.mValueHigh = 31; // MAX (default 31 jours si mois vide)
}
oledMenu.mValueStep = 1;
if (contenuDateNum[2] != -1) {
oledMenu.mValueEntered = contenuDateNum[2]; // starting value // Valeur depart si contenuDateNum[2] pas vide
}
else {
oledMenu.mValueEntered = oledMenu.mValueLow; // starting value
}
}
// Heures
if (oledMenu.selectedMenuItem == 4) {
//if (serialDebug) Serial.println("Config Date/Heure: Heures");
menuMode = value;
oledMenu.menuTitle = "Config Date/Heure"; //1
oledMenu.mValueLow = 0;
oledMenu.mValueHigh = 23;
oledMenu.mValueStep = 1;
if (contenuDateNum[3] != -1) {
oledMenu.mValueEntered = contenuDateNum[3]; // starting value // Valeur depart si contenuDateNum[3] pas vide
}
else {
oledMenu.mValueEntered = oledMenu.mValueLow; // starting value
}
}
// Minutes
if (oledMenu.selectedMenuItem == 5) {
//if (serialDebug) Serial.println("Config Date/Heure: Minutes");
menuMode = value;
oledMenu.menuTitle = "Config Date/Heure"; //1
oledMenu.mValueLow = 0;
oledMenu.mValueHigh = 59;
oledMenu.mValueStep = 1;
if (contenuDateNum[4] != -1) {
oledMenu.mValueEntered = contenuDateNum[4]; // starting value // Valeur depart si contenuDateNum[4] pas vide
}
else {
oledMenu.mValueEntered = oledMenu.mValueLow; // starting value
}
}
// Secondes
if (oledMenu.selectedMenuItem == 6) {
//if (serialDebug) Serial.println("Config Date/Heure: Secondes");
menuMode = value;
oledMenu.menuTitle = "Config Date/Heure"; //1
oledMenu.mValueLow = 0;
oledMenu.mValueHigh = 59;
oledMenu.mValueStep = 1;
if (contenuDateNum[5] != -1) {
oledMenu.mValueEntered = contenuDateNum[5]; // starting value // Valeur depart si contenuDateNum[5] pas vide
}
else {
oledMenu.mValueEntered = oledMenu.mValueLow; // starting value
}
}
// Valider
if (oledMenu.selectedMenuItem == 7) { // MAJ DATE
//if (serialDebug) Serial.println("Config Date/Heure: Valider");
ValideChampDate();
}
// Annuler // Retour DateMenu()
if (oledMenu.selectedMenuItem == 8) {
//if (serialDebug) Serial.println("Config Date/Heure: Annuler");
for (int8_t i=0; i < 6; i++) { // Reset contenuDateNum
contenuDateNum[i] = -1;
}
DateMenu();
}
oledMenu.selectedMenuItem = 0; // clear menu item selected flag as it has been actioned
}
//******************* ///////////////////// *********************** FIN MENU CONFIG DATE / HEURE
// 8: SousMenu : CONFIG MENU
// actions when an item is selected in the Date Menu
if (oledMenu.menuTitle == "Menu Config") {
// Config_Menu: Charger Config
if (oledMenu.selectedMenuItem == 1) {
if (serialDebug) Serial.println("Config_Menu: Charger Config");
resetMenu();
displayMessage("Charger", "\nCharger\nla config ?\n");
}
// Config_Menu: Enregistrer Config
if (oledMenu.selectedMenuItem == 2) {
if (serialDebug) Serial.println("Config_Menu: Enregistrer Config");
resetMenu();
displayMessage("Enregistrer", "\nEnregistrer\nla config ?\n");
}
// Config_Menu: Inactif OFF / Actif ON
if (oledMenu.selectedMenuItem == 3) {
if (serialDebug) Serial.println("Config_Menu: Debug PWM Ventilo");
resetMenu();
menuMode = value;
oledMenu.menuTitle = "Debug PWM Ventilo"; // title (used to identify which number was entered)
oledMenu.mValueLow = 0; // minimum value allowed 0
oledMenu.mValueHigh = 1; // maximum value allowed 1
oledMenu.mValueStep = 1; // step size 1
oledMenu.mValueEntered = flag_Debug_PWM_Ventilo; // starting value
}
// back to main menu
if (oledMenu.selectedMenuItem == 4) {
if (serialDebug) Serial.println("Config_Menu: back to main menu");
defaultMenu();
}
oledMenu.selectedMenuItem = 0; // clear menu item selected flag
}
} // FIN menuActions
// -----------------------------------------------
// actions for value entered put in here
void menuValues() {
// ******************
// DEBUT DES ACTIONS
// ******************
// *****************************
// 1. ** SOUS MENU : OFF / ON **
// *****************************
// action for "OFF / ON" du Recuperateur de chaleur
if (oledMenu.menuTitle == "OFF / ON") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (flag_ventilo_on_off != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
flag_ventilo_on_off = oledMenu.mValueEntered;
//Envoie la valeur de VENTILO on/off -> WEBSOCKET (flag_ventilo_on_off) // AVOIR WEBSOCKET
notifyClients((char*)"wsonoff");
if (serialDebug) {
Serial.print("OFF / ON : selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
defaultMenu();
}
}
// ********************************
// 2. ** SOUS MENU : SONDES MENU **
// ********************************
// action for Sondes Temp "Sondes Erreurs" Visu + Remise a Zero
if (oledMenu.menuTitle == "Sondes Erreurs") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
for (uint8_t index = 0; index < nbreSondes; index++) {
//for (uint8_t index = 0; index < sizeof(SondeEnVie); index++) { // nbreSondes
SondeErrTemp[index] = 0; // Reset compteur erreur temporaire sonde (10 Erreurs de suite)
SondeErr[index] = 0; // Reset compteur erreur sonde Temperature
if (!SondeEnVie[index]) {
SondeEnVie[index] = true; // Passage sonde a UP (true) si en vie
}
}
if (serialDebug) Serial.println("Sondes Temp: Sondes Erreurs selection was RESET");
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
SondesMenu();
}
}
// action for Sondes Temp "Sondes Rempla." Remplacement sonde
if (oledMenu.menuTitle == "Sondes Rempla.") {
//Serial.print("indexSondeRemp : ");Serial.println(indexSondeRemp);
if (SondeEnVie[indexSondeRemp] == false) { // si sonde morte
if (ENC_SW_state_long == HIGH) { // valide la valeur
DeviceAddress VideAddr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
if (rempOldSensor(memSondesAddr, nbreSondes, indexSondeRemp)) { // si rempOldSensor, return true ok, sinon else avec boucle while infinie
if (!addressMatch(VideAddr, memSondesAddr[indexSondeRemp])) { // si false -> on enregistre l'adresse de la sonde en memoire -> namespace -> Sondes
pref.begin("Sondes", RW_MODE); // Ouvre le namespace "Sonde en ecriture
// String(SondeNom[indexSondeRemp]).c_str() -> converti une String en char
pref.putBytes(SondeNom[indexSondeRemp].c_str(), memSondesAddr[indexSondeRemp], sizeof(memSondesAddr[indexSondeRemp]) ); // ENREGISTRE EN MEMOIRE
pref.end(); // Ferme preferences Read Write mode
if (serialDebug_sondes) Serial.println("Sauvegarde mémoire sonde OK");
}
else {
if (serialDebug_sondes) {
Serial.print("Erreur : Adresse Sonde Vide :");
printAddress(memSondesAddr[indexSondeRemp]);
Serial.println();
}
}
SondeEnVie[indexSondeRemp] = true; // Reinitialise sonde en vie a UP (true)
SondeErr[indexSondeRemp] = 0; // Reinitialise compteur erreur sonde
SondeErrTemp[indexSondeRemp] = 0; // Reinitialise compteur erreur temporaire sonde (10 Erreurs de suite)
if (serialDebug_sondes) {
Serial.print("Sonde #");
Serial.print(indexSondeRemp+1);
Serial.print(" (");
Serial.print(SondeNom[indexSondeRemp]);
Serial.print(") remplacée : Address : ");
printAddress(memSondesAddr[indexSondeRemp]);
Serial.println();
}
}
if (serialDebug_sondes) Serial.println("Sondes Temp: Sondes Rempla. selection was Remplacement");
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
if (serialDebug_sondes) Serial.println("Sondes Temp: Sondes Rempla. selection was By-Pass");
indexSondeRemp++; // incremente le numero de sonde a remplacer
if (indexSondeRemp == nbreSondes) { // retour menu sondes (4 Sondes)
indexSondeRemp = 0; // Pour menu remplacement sondes Temp (Smoteur, Schaud, Sfroid, Sext) [RESET]
SondesMenu();
}
}
}
// *************************************
// 3. ** SOUS MENU : VENTILATEUR MENU **
// *************************************
// action for Ventilateur "Mode Auto (false) / Manu (true)"
if (oledMenu.menuTitle == "Ven Auto / Manu") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (flag_ventilo_manu_on_off != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
flag_ventilo_manu_on_off = oledMenu.mValueEntered;
if (flag_ventilo_manu_on_off == true) { // passage mode manu TRUE
if (flag_ventilo_boost_on_off == true ) {
flag_ventilo_boost_on_off = false; // reset FLAG mode Boost OFF
notifyClients((char*)"wsVboost");
UpdateSetpointPID(); // MAJ Temperature de consigne // AVOIR
}
}
else { // passage mode auto FALSE
flag_Debug_PWM_Ventilo = false; // force FLAG Debug PWM Ventilo a OFF si ventilo en mode auto
}
//Envoie la valeur de VENTILO manu/auto -> WEBSOCKET (flag_ventilo_manu_on_off) //AVOIR WEBSOCKET NEW
notifyClients((char*)"wsVmanuauto");
if (serialDebug) {
Serial.print("Ventilateur: Mode Auto / Manu selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "RPM Ventilateur"
if (oledMenu.menuTitle == "RPM Ventilateur") {
if (ENC_SW_state_long == HIGH && flag_ventilo_manu_on_off == true && flag_ventilo_on_off == true) { // valide la valeur si appui long ET mode MANU ET Ventilo etat ON
if (flag_Debug_PWM_Ventilo == false) { // Si mode Debug PWM, Numero de la vitesse si FALSE
pwm = VitesseVentil[oledMenu.mValueEntered];
}
else { // Si mode Debug PWM, PWM Brute de la vitesse si TRUE
pwm = oledMenu.mValueEntered;
}
if (serialDebug) {
Serial.print("Ventilateur: RPM Ventilateur PWM selection was ");
Serial.println(pwm);
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "Temp. ON" Temperature Min chaud (Hotte DEMARRAGE)
if (oledMenu.menuTitle == "Temp. ON") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Temp_ON_moteur != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
Temp_ON_moteur = oledMenu.mValueEntered;
notifyClients((char*)"wsTemp_ON_moteur");
if (serialDebug) {
Serial.print("Ventilateur: Temp. ON selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "Hyst Temp. ON" Hysteresis Temperature Min chaud (Hotte DEMARRAGE) apres zero
if (oledMenu.menuTitle == "Hyst Temp. ON") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Hyst_Temp_ON_moteur != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
Hyst_Temp_ON_moteur = oledMenu.mValueEntered;
notifyClients((char*)"wsHyst_Temp_ON_moteur");
if (serialDebug) {
Serial.print("Ventilateur: Hyst Temp. ON selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "Temp. OFF" Temperature Max moteur (ARRET)
if (oledMenu.menuTitle == "Temp. OFF") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Temp_OFF_moteur != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
Temp_OFF_moteur = oledMenu.mValueEntered;
notifyClients((char*)"wsTemp_OFF_moteur");
if (serialDebug) {
Serial.println("Ventilateur: Temp. OFF selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "Heure Deb Jour" Heure Debut mode Jour (Mode jour / Nuit)
if (oledMenu.menuTitle == "Heure Deb Jour") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (START_MODE_JOUR != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
START_MODE_JOUR = oledMenu.mValueEntered;
notifyClients((char*)"wsHMJ");
if (serialDebug) {
Serial.print("Ventilateur: Heure Deb Jour selection was ");
Serial.print((int8_t)(oledMenu.mValueEntered / 3600L));
Serial.print(":");
Serial.println((int8_t)((oledMenu.mValueEntered % 3600L)/60L)) ;
} // + String(oledMenu.mValueEntered));
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "Vitesse Jour" Vitesse pour le mode Jour (mode AUTO)
if (oledMenu.menuTitle == "Vitesse Jour") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Vit_jour != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
Vit_jour = oledMenu.mValueEntered;
notifyClients((char*)"wsVit_jour");
if (serialDebug) {
Serial.print("Ventilateur: Vitesse mode Jour selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "Heure Deb Nuit" Heure Fin mode Jour (Mode jour / Nuit)
if (oledMenu.menuTitle == "Heure Deb Nuit") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (START_MODE_NUIT != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
START_MODE_NUIT = oledMenu.mValueEntered;
notifyClients((char*)"wsHMN");
if (serialDebug) {
Serial.print("Ventilateur: Heure Deb Nuit selection was ");
Serial.print((int8_t)(oledMenu.mValueEntered / 3600L));
Serial.print(":");
Serial.println((int8_t)((oledMenu.mValueEntered % 3600L)/60L));
} // + String(oledMenu.mValueEntered));
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "Vitesse Nuit" Vitesse pour le mode Nuit (mode AUTO)
if (oledMenu.menuTitle == "Vitesse Nuit") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Vit_nuit != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
Vit_nuit = oledMenu.mValueEntered;
notifyClients((char*)"wsVit_nuit");
if (serialDebug) {
Serial.print("Ventilateur: Vitesse mode Nuit selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "Mode Boost ON"
if (oledMenu.menuTitle == "Mode Boost ON") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (flag_ventilo_boost_on_off != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
flag_ventilo_boost_on_off = oledMenu.mValueEntered;
if (flag_ventilo_boost_on_off == true) { // passage mode BOOST ON
timerModeBoost = millis(); // Save time declenchement mode BOOST
if (flag_ventilo_manu_on_off == true) {
flag_ventilo_manu_on_off = false; // reset FLAG mode manu OFF (ICI Donc MODE AUTO(FALSE))
//Envoie la valeur de VENTILO manu/auto -> WEBSOCKET (flag_ventilo_manu_on_off) //AVOIR WEBSOCKET NEW
notifyClients((char*)"wsVmanuauto");
}
}
UpdateSetpointPID(); // MAJ Temperature de consigne
notifyClients((char*)"wsVboost"); // AVOIR
if (serialDebug) {
Serial.print("Ventilateur: Mode Boost ON selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "Vitesse Boost" Vitesse pour le mode Boost
if (oledMenu.menuTitle == "Vitesse Boost") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Vit_boost != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
Vit_boost = oledMenu.mValueEntered;
notifyClients((char*)"wsVit_boost");
if (serialDebug) {
Serial.print("Ventilateur: Vitesse mode Boost selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// action for Ventilateur "Duree Boost" Temps Boost ON
if (oledMenu.menuTitle == "Duree Boost") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (TIMER_MODE_BOOST != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
TIMER_MODE_BOOST = oledMenu.mValueEntered;
notifyClients((char*)"wsTMB");
if (serialDebug) {
Serial.print("Ventilateur: Duree Boost selection was ");
Serial.print((int8_t)(oledMenu.mValueEntered / 3600L));
Serial.print(":");
Serial.println((int8_t)((oledMenu.mValueEntered % 3600L)/60L));
} // + String(oledMenu.mValueEntered));
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
VentilMenu();
}
}
// ******************************
// 4. ** SOUS MENU : IRIS MENU **
// ******************************
// action for IRIS "Iri Manu (true) / Auto (false)"
if (oledMenu.menuTitle == "Iri Auto / Manu") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (flag_iris_manu_on_off != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
flag_iris_manu_on_off = oledMenu.mValueEntered;
// Deplace dans la (loop()) on garde juste la MAJ de OutputPID pour l'affichage
if (flag_iris_manu_on_off == false) { // passage IRIS mode Auto FALSE
if (myPID.GetMode() == MANUAL) { // si PID mode MANUAL
// AVOIR NEW BUG IRIS
UpdateOutputPID(); // dit au PID ou est l'IRIS avant de passer en mode AUTOMATIC (Pour Affichage Ecran OLED)
// FIN AVOIR NEW BUG IRIS
//myPID.SetMode(AUTOMATIC); // Deplace dans la (loop())
}
}
//Envoie la valeur de IRIS manu/auto -> WEBSOCKET (flag_iris_manu_on_off)
notifyClients((char*)"wsImanuauto");
if (serialDebug) {
Serial.print("Iris_Menu: Iri Auto / Manu selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
IrisMenu();
}
}
// action for IRIS "IRIS Position"
if (oledMenu.menuTitle == "IRIS Position") { // BUG MODE MANU SI SORT DU MENU LE STEPPER S'ARRETE AVOIR
if (ENC_SW_state_long == HIGH && flag_iris_manu_on_off == true && flag_ventilo_on_off == true) { // valide la valeur Mode MANU -> TRUE ET Ventilo etat ON
//PosIris (valeur entre 0 et 12000)
//oledMenu.mValueEntered (valeur entre 0 et 115)
PosIris = round(oledMenu.mValueEntered * (float)PasStepIris);
PosIris = verifStepIris(PosIris); // verifie que la division par 2 donne Zero (Halfstep) et qu'on n'est pas superieur (home et maxtravel)
//TempPosIris = PosIris; // AVOIR IRIS NEWS
//notifyClients((char*)"wsPosManu"); // AVOIR ICI
//if (stepper.currentPosition() != PosIris) { // AVOIR NEW
if (Steppercurrent != PosIris) { // AVOIR NEW
flag_auth_deplacement = true;
}
notifyClients((char*)"wsPosManu"); // DEPLACE ICI AVOIR
if (serialDebug) {
Serial.print("Iris_Menu: IRIS Position selection was ");
Serial.println(PosIris);
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
IrisMenu();
}
}
// action for IRIS "IRIS Consigne" Temperature consigne regulation PID (SMoteur)
if (oledMenu.menuTitle == "IRIS Consigne") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (ConsignePID != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
ConsignePID = oledMenu.mValueEntered;
//Refresh SetpointPID affichage AccueilMenu
UpdateSetpointPID(); // MAJ Temperature de consigne
notifyClients((char*)"wsConsignePID");
if (serialDebug) {
Serial.print("Iris_Menu: IRIS Consigne Temperature selection was ConsignePID : ");
Serial.println(ConsignePID);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
IrisMenu();
}
}
// action for IRIS "IRIS Tmin Arret" Temperature mini Arret PID (Niveau Temperature Smoteur)
if (oledMenu.menuTitle == "IRIS Tmin Arret") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (ConsignePID_coupure != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
ConsignePID_coupure = oledMenu.mValueEntered;
notifyClients((char*)"wsConsignePID_coupure");
if (serialDebug) {
Serial.print("Iris_Menu: IRIS Temperature mini Arret PID selection was ConsignePID_coupure : ");
Serial.println(ConsignePID_coupure);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
IrisMenu();
}
}
// ********************************************
// 5. ** SOUS MENU : COURBE VENTILATION MENU **
// ********************************************
// action for COURBE VENTILATION "Vitesse Base" Vitesse Base pour vitesse dynamique
if (oledMenu.menuTitle == "Vitesse Base") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Vit_Tbase != oledMenu.mValueEntered) { // si DIFF -> UPDATE
Vit_Tbase = oledMenu.mValueEntered;
seuilVitesseB = VitesseVentil[Vit_Tbase] + offsetNormalisation(Vit_Tbase, Vit_offset);
notifyClients((char*)"wsVit_Tbase");
if (serialDebug) {
Serial.print("Courbe_Ventilation: Vitesse Base selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
CourbeMenu();
}
}
// action for COURBE VENTILATION "Vitesse Inter." Vitesse Inter. pour vitesse dynamique
if (oledMenu.menuTitle == "Vitesse Inter.") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Vit_Tinte != oledMenu.mValueEntered) { // si DIFF -> UPDATE
Vit_Tinte = oledMenu.mValueEntered;
seuilVitesseI = VitesseVentil[Vit_Tinte] + offsetNormalisation(Vit_Tinte, Vit_offset);
notifyClients((char*)"wsVit_Tinte");
if (serialDebug) {
Serial.print("Courbe_Ventilation: Vitesse Inter. selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
CourbeMenu();
}
}
// action for COURBE VENTILATION "Vitesse Maxi" Vitesse Maxi pour vitesse dynamique
if (oledMenu.menuTitle == "Vitesse Maxi") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Vit_Tmaxi != oledMenu.mValueEntered) { // si DIFF -> UPDATE
Vit_Tmaxi = oledMenu.mValueEntered;
seuilVitesseMa = VitesseVentil[Vit_Tmaxi] + offsetNormalisation(Vit_Tmaxi, Vit_offset);
notifyClients((char*)"wsVit_Tmaxi");
if (serialDebug) {
Serial.print("Courbe_Ventilation: Vitesse Maxi selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
CourbeMenu();
}
}
// action for COURBE VENTILATION "Vitesse Offset" Vitesse Offset pour vitesse dynamique (Pour vitesse Intermediare et vitesse Maximum)
if (oledMenu.menuTitle == "Vitesse Offset") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Vit_offset != oledMenu.mValueEntered) { // si DIFF -> UPDATE
Vit_offset = oledMenu.mValueEntered;
seuilVitesseB = VitesseVentil[Vit_Tbase] + offsetNormalisation(Vit_Tbase, Vit_offset);
seuilVitesseI = VitesseVentil[Vit_Tinte] + offsetNormalisation(Vit_Tinte, Vit_offset);
seuilVitesseMa = VitesseVentil[Vit_Tmaxi] + offsetNormalisation(Vit_Tmaxi, Vit_offset);
notifyClients((char*)"wsVit_offset"); // AFAIRE
if (serialDebug) {
Serial.print("Courbe_Ventilation: Vitesse Offset selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
CourbeMenu();
}
}
// action for COURBE VENTILATION "Temp. Base" Temp. Base pour vitesse dynamique
if (oledMenu.menuTitle == "Temp. Base") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Temp_Vbase != oledMenu.mValueEntered) { // si DIFF -> UPDATE
Temp_Vbase = oledMenu.mValueEntered;
seuilTempB = (Temp_Vbase + Temp_offset) * coef_temp;
notifyClients((char*)"wsTemp_Vbase");
if (serialDebug) {
Serial.print("Courbe_Ventilation: Temp. Base selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
CourbeMenu();
}
}
// action for COURBE VENTILATION "Temp. Inter." Temp. Inter. pour vitesse dynamique
if (oledMenu.menuTitle == "Temp. Inter.") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Temp_Vinte != oledMenu.mValueEntered) { // si DIFF -> UPDATE
Temp_Vinte = oledMenu.mValueEntered;
seuilTempI = (Temp_Vinte + Temp_offset) * coef_temp;
notifyClients((char*)"wsTemp_Vinte");
if (serialDebug) {
Serial.print("Courbe_Ventilation: Temp. Inter. selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
CourbeMenu();
}
}
// action for COURBE VENTILATION "Temp. Mini" Temp. Mini pour vitesse dynamique
if (oledMenu.menuTitle == "Temp. Mini") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Temp_Vmini != oledMenu.mValueEntered) { // si DIFF -> UPDATE
Temp_Vmini = oledMenu.mValueEntered;
seuilTempMi = (Temp_Vmini + Temp_offset) * coef_temp;
notifyClients((char*)"wsTemp_Vmini");
if (serialDebug) {
Serial.print("Courbe_Ventilation: Temperature Minimum selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
CourbeMenu();
}
}
// action for COURBE VENTILATION "Temp. Offset" Temp. Offset pour vitesse dynamique
if (oledMenu.menuTitle == "Temp. Offset") {
if (ENC_SW_state_long == HIGH) { // valide la valeur
if (Temp_offset != oledMenu.mValueEntered) { // si DIFF -> UPDATE
Temp_offset = oledMenu.mValueEntered;
seuilTempB = (Temp_Vbase + Temp_offset) * coef_temp;
seuilTempI = (Temp_Vinte + Temp_offset) * coef_temp;
seuilTempMi = (Temp_Vmini + Temp_offset) * coef_temp;
notifyClients((char*)"wsTemp_offset");
if (serialDebug) {
Serial.print("Courbe_Ventilation: Temp. Offset selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
CourbeMenu();
}
}
// ***********************************************
// 7.2. ** SOUS SOUS-MENU : CONFIG DATE / HEURE ** (MenuMode = value) Modification des Valeurs -->> CONFIG DATE / HEURE
// ***********************************************
// action for CONFIG DATE / HEURE
if (oledMenu.menuTitle == "Config Date/Heure") {
if (ENC_SW_state_short == HIGH) { // retour menu precedent + Validation
if (0 <= oledMenu.highlightedMenuItem-1 && oledMenu.highlightedMenuItem-1 < 6) { // si entre 0 et 5 pour contenuDateNum[] = (Annees, Mois, Jours, Heures, Minutes, Secondes)
contenuDateNum[oledMenu.highlightedMenuItem-1] = oledMenu.mValueEntered; // <-- Enregistre la valeur
// Gestion Nbre MAX de Jours en fonction de l'année pour FEVRIER (bissextile) --> (Modif Années + Retour)
// Annees && Mois == FEV && Jours > Nbre jour dans Mois FEV
if (oledMenu.highlightedMenuItem-1 == 0 && contenuDateNum[1] == 2 ) { // Si oledMenu.mValueEntered concerne Année
leapYear = is_leap_year(oledMenu.mValueEntered);
if (contenuDateNum[2] > NbreJourmonth[1] + leapYear) {
contenuDateNum[2] = NbreJourmonth[1] + leapYear; // Jour Max si FEV et Bissextile
}
}
// Gestion Nbre MAx de Jours en fonction du mois (+gestion Annees bissextile) --> (Modif Mois + Retour)
if (oledMenu.highlightedMenuItem-1 == 1) { // Si oledMenu.mValueEntered concerne Mois value (1->12)
if (contenuDateNum[0] != -1) { // Si Année existe
if (contenuDateNum[1] == 2) { // Si Mois FEV
leapYear = is_leap_year(contenuDateNum[0]);
if (contenuDateNum[2] > NbreJourmonth[oledMenu.mValueEntered-1] + leapYear) { // Jour Max si FEV et Bissextile
contenuDateNum[2] = NbreJourmonth[oledMenu.mValueEntered-1] + leapYear;
}
}
else { // Tous les autres Mois (SAUF FEVRIER)
if (contenuDateNum[2] > NbreJourmonth[oledMenu.mValueEntered-1]) { // Jour Max
contenuDateNum[2] = NbreJourmonth[oledMenu.mValueEntered-1];
}
}
}
else { // Si Année existe pas
if (contenuDateNum[2] > NbreJourmonth[oledMenu.mValueEntered-1]) { // Jour Max
contenuDateNum[2] = NbreJourmonth[oledMenu.mValueEntered-1];
}
}
}
} //Fin si entre 0 et 5 pour contenuDateNum[]
// Retour vers le Menu [MenuConfigDateHeure()] -->> CONFIG DATE / HEURE
menuMode = menu;
oledMenu.menuTitle = "Config Date/Heure";
// Remet le status du bouton a low
ENC_SW_state_short = LOW;
ENC_SW_state_long = LOW;
}
}
// ********************************
// 8. ** SOUS MENU : CONFIG MENU **
// ********************************
// action for Config_Menu "Debug PWM Ventilo" (Inactif OFF / Actif ON)
if (oledMenu.menuTitle == "Debug PWM Ventilo") {
if (ENC_SW_state_long == HIGH && flag_ventilo_manu_on_off == true) { // valide la valeur
if (flag_Debug_PWM_Ventilo != oledMenu.mValueEntered) { // AVOIR si DIFF -> UPDATE
flag_Debug_PWM_Ventilo = oledMenu.mValueEntered;
//if (flag_ventilo_manu_on_off == false) { // si Ventilo en mode auto FALSE
// flag_Debug_PWM_Ventilo = false; // force FLAG Debug PWM Ventilo a OFF si ventilo en mode auto
//}
if (serialDebug) {
Serial.print("Config_Menu: Debug PWM Ventilo selection was ");
Serial.println(oledMenu.mValueEntered);
}
}
}
if (ENC_SW_state_short == HIGH) { // retour menu precedent
ConfigMenu();
}
}
// Remet le status du bouton a low
ENC_SW_state_long = LOW;
ENC_SW_state_short = LOW;
}
// Refresh ecran OLED for messages
void refreshMessages() {
if( millis() - previousRefreshOled >= intervalRefreshOled) { // Timer pour le refresh ecran oled (2 fois par secondes)
previousRefreshOled = millis();
// refresh ecran OLED for "Accueil"
if (oledMenu.menuTitle == "Accueil") {
AccueilMenu(); // Affiche l'ecran d'Accueil
}
// refresh ecran OLED for "Sonde Moteur"
if (oledMenu.menuTitle == "Sonde Moteur") {
oledAfficheTemp(oledMenu.menuTitle ,float(SondeTempC[0])); // Affiche la Temperature de la sonde
}
// refresh ecran OLED for "Sonde Chaud"
if (oledMenu.menuTitle == "Sonde Chaud") {
oledAfficheTemp(oledMenu.menuTitle ,float(SondeTempC[1])); // Affiche la Temperature de la sonde
}
// refresh ecran OLED for "Sonde Froid"
if (oledMenu.menuTitle == "Sonde Froid") {
oledAfficheTemp(oledMenu.menuTitle ,float(SondeTempC[2])); // Affiche la Temperature de la sonde
}
// refresh ecran OLED for "Sonde Exterieure"
if (oledMenu.menuTitle == "Sonde Exterieure") {
oledAfficheTemp(oledMenu.menuTitle ,float(SondeTempC[3])); // Affiche la Temperature de la sonde
}
// refresh ecran OLED for "Statut Wifi"
if (oledMenu.menuTitle == "Statut Wifi" || oledMenu.menuTitle == "Wifi Mode STA") { // || oledMenu.menuTitle == "Wifi Mode AP" // AVOIR SI NECESSAIRE
//oledStatutWifi(); // Affiche le statut du Wifi
if (WifiStaMode == true) {
if (WiFi.status() == WL_CONNECTED) { // Si connection WIFI ok
// WiFi.macAddress() // MAC STA IP : 192.168.0.17
// WiFi.softAPmacAddress(); // MAC AP SSID : ESP-WIFI-AP RSSI : -77 dB IP : 10.0.0.1 MAC: 24:0A:C4:00:01:10
//assistant: < line 1 > < line 2 > < line 3 > < line 4 >
displayMessage("Wifi Mode STA", "\nSSID : " + WiFi.SSID() + "\nRSSI : " + String(WiFi.RSSI()) + " dB\nIP : " + WiFi.localIP().toString() + "\nMAC:" + WiFi.macAddress() + "\n");
}
else { // Si pas de connection WIFI
// WiFi.softAPmacAddress(); // MAC AP SSID : ESP-WIFI-AP RSSI : -77 dB IP : 10.0.0.1 MAC: 24:0A:C4:00:01:10
//assistant: < line 1 > < line 2 > < line 3 > < line 4 >
displayMessage("Wifi Mode STA", "\nSSID : " + ssidnew + "\nEtat: " + EtatWifi() + "\nIP : " + WiFi.localIP().toString() + "\nMAC:" + WiFi.macAddress() + "\n");
}
}
else {
displayMessage("Wifi Mode AP", "\nSSID : " + WiFi.softAPSSID() + "\nIP : " + WiFi.softAPIP().toString() + "\nMAC:" + WiFi.macAddress() + "\n");
}
}
// refresh ecran OLED for "Statut Date/Heure"
if (oledMenu.menuTitle == "Statut Date/Heure") {
MenuStatutDateHeure();
}
}
}
// -------------------------------------------------------------------------------------------------
// menus above here
// -------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------
// -update the active menu
// ----------------------------------------------------------------
void menuUpdate() {
// if no recent activity then turn oled off
if ( (unsigned long)(millis() - oledMenu.lastMenuActivity) > (menuTimeout * 1000) ) {
resetMenu();
return;
}
switch(menuMode) {
case off_menu:
if (ENC_SW_state_long == HIGH) {
oledMenu.lastMenuActivity = millis(); // log time AVOIR BUG
defaultMenu(); // if button long push has been pressed return to default menu
break; //AVOIR
}
if (ENC_SW_state_short == HIGH) {
oledMenu.lastMenuActivity = millis(); // log time AVOIR BUG
AccueilMenu(); // if button short push has been pressed return to Accueil
break;
}
break; //Si pas de break, erreur lors du retour
// if there is an active menu
case menu:
if (oledMenu.menuTitle == "Config Date/Heure") { // ************* 7. MENU CONFIG DATE / HEURE ************* -->> CONFIG DATE / HEURE
MenuConfigDateHeure();
}
else {
serviceMenu();
}
menuActions(); // Go to SOUS MENU
break;
// if there is an active none blocking 'enter value'
case value:
serviceValue(0);
if (ENC_SW_state_short == HIGH || ENC_SW_state_long == HIGH) { // if the button has been pressed
oledMenu.lastMenuActivity = millis(); // log time AVOIR BUG
menuValues(); // a value has been entered so action it
break;
}
break; // BUG AVOIR
// if a message is being displayed
case message:
refreshMessages(); // refresh OLED valeur si change
if (ENC_SW_state_short == HIGH && oledMenu.menuTitle != "Accueil" && oledMenu.menuTitle != "Redemarrage1") { // AVOIR
oledMenu.lastMenuActivity = millis(); // log time AVOIR BUG
if (oledMenu.menuTitle == "STARTED") {
AccueilMenu();
break;
}
else if (oledMenu.menuTitle == "Sonde Moteur" || oledMenu.menuTitle == "Sonde Chaud" || oledMenu.menuTitle == "Sonde Froid" || oledMenu.menuTitle == "Sonde Exterieure") {
SondesMenu(); // if button has been pressed return to SondesMenu
break;
}
else if (oledMenu.menuTitle == "Courbe Ventilation") {
CourbeMenu(); // if button has been pressed return to CourbeMenu
break;
}
else if (oledMenu.menuTitle == "Charger" || oledMenu.menuTitle == "Enregistrer" || oledMenu.menuTitle == "Charger1" || oledMenu.menuTitle == "Enregistrer1") {
ConfigMenu(); // if button has been pressed return to ConfigMenu
break;
}
else if (oledMenu.menuTitle == "Reset Wifi" || oledMenu.menuTitle == "Reset Wifi1" || oledMenu.menuTitle == "Wifi Mode STA" || oledMenu.menuTitle == "Wifi Mode AP") {
WifiMenu(); // if button has been pressed return to WifiMenu
break;
}
else if (oledMenu.menuTitle == "Statut Date/Heure" ) {
DateMenu(); // if button has been pressed return to DateMenu
break;
}
else if (oledMenu.menuTitle == "Config Date/HeureErr" ) {
// Retour vers le Menu [MenuConfigDateHeure()] -->> CONFIG DATE / HEURE
menuMode = menu;
oledMenu.menuTitle = "Config Date/Heure"; // if button has been pressed return to DateMenu
break;
}
else {
defaultMenu(); // if button has been pressed return to default menu
break;
}
}
if (ENC_SW_state_long == HIGH) { // if the button long has been pressed
oledMenu.lastMenuActivity = millis(); // log time AVOIR BUG
if (oledMenu.menuTitle == "Accueil") {
defaultMenu(); // if button has been pressed return to defaultMenu
break;
}
else if (oledMenu.menuTitle == "Charger") {
chargeConfig(false); // if button has been pressed charge la config
break;
}
else if (oledMenu.menuTitle == "Enregistrer") {
enregisConfig(); // if button has been pressed enregistre la config
break;
}
else if (oledMenu.menuTitle == "Reset Wifi") {
InitWifi_AP(); // if button has been pressed passage Wifi en Mode AP
CheckWifiStatus();
if (WifiStaMode == false) {
// WiFi.macAddress() // MAC STA IP : 192.168.0.17
// WiFi.softAPmacAddress(); // MAC AP SSID : ESP-WIFI-AP IP : 10.0.0.1 MAC: 24:0A:C4:00:01:10
//assistant: < line 1 > < line 2 > < line 3 > < line 4 >
displayMessage("Reset Wifi1", "\nWifi en Mode AP OK\nSSID : " + WiFi.softAPSSID() + "\nIP : " + WiFi.softAPIP().toString() + "\nMAC:" + WiFi.macAddress() + "\n");
}
else {
displayMessage("Reset Wifi1", "\nReset Wifi NOK\nVerifier Statut !!!\n");
}
break;
}
else if (oledMenu.menuTitle == "Redemarrage") {
flag_restart_esp = true; // Autorisation redemarrage
timerRestartESP = millis(); // Enregistre le time pour le delais de 10 secondes
displayMessage("Redemarrage1", "\nRedemarrage ESP32\ndans 10 secondes...\n");
break;
}
}
break; // BUG AVOIR
case blocking: // BUG Warning compilation
break;
}
}
// ----------------------------------------------------------------
// -service active menu
// ----------------------------------------------------------------
void serviceMenu() { // Gestion menu, sous menu, encoder menu et affichage menu
if (encoder0Pos > 0) { // ici on incremente ++ menu
if (serialDebug) {
Serial.print("encoder0Pos Menu ++ : ");
Serial.println(encoder0Pos);
}
oledMenu.highlightedMenuItem--; // -1 STEP a la fois
encoder0Pos = 0;
oledMenu.lastMenuActivity = millis(); // log time
}
if (encoder0Pos < 0) { // ici on decremente -- menu
if (serialDebug) {
Serial.print("encoder0Pos Menu -- : ");
Serial.println(encoder0Pos);
}
oledMenu.highlightedMenuItem++; // +1 STEP a la fois
encoder0Pos = 0;
oledMenu.lastMenuActivity = millis(); // log time
}
if (ENC_SW_state_short == HIGH) {
oledMenu.selectedMenuItem = oledMenu.highlightedMenuItem; // flag that the item has been selected
oledMenu.lastMenuActivity = millis(); // log time
if (serialDebug) {
Serial.print("menu '");
Serial.print(oledMenu.menuTitle);
Serial.print("' item '");
Serial.print(oledMenu.menuItems[oledMenu.highlightedMenuItem]);
Serial.println("' selected");
}
}
const int8_t _centreLine = displayMaxLines / 2 + 1; // mid list point (5/2 +1 -> 3)
ecranOLED.clearDisplay();
ecranOLED.setTextColor(SSD1306_WHITE);
ecranOLED.setFont(&FreeSerif9pt7b);
// verify valid highlighted item (limite MIN MAX) Modification une fois en dessous de bas (bas-1 -> HAUT) une fois au dessus de haut (haut+1 -> BAS)
if (oledMenu.highlightedMenuItem > oledMenu.noOfmenuItems) { // TEST ligne MAX
oledMenu.highlightedMenuItem = 1; // on revient a la premiere ligne
}
if (oledMenu.highlightedMenuItem < 1) { // TEST ligne MIN
oledMenu.highlightedMenuItem = oledMenu.noOfmenuItems; // on revient a la derniere ligne
}
// title
if (menuLargeText) { // mets le nom du menu selectionné en TITRE
oledCentreString(oledMenu.menuItems[oledMenu.highlightedMenuItem], 0, 13, 128); // y=13 sur 16 pixel pour le Jaune (Garde les 16 premiers caracteres)
}
else {
oledCentreString(oledMenu.menuTitle, 0, 13, 128); // y=13 sur 16 pixel pour le Jaune (Garde les 16 premiers caracteres)
}
ecranOLED.drawLine(0, topLine-1, ecranOLED.width(), topLine-1, SSD1306_WHITE); // draw horizontal line under title
// menu
ecranOLED.setFont();// Revient a la police par defaut
ecranOLED.setTextSize(1);
ecranOLED.setCursor(0, topLine+2);
for (int8_t i=1; i <= displayMaxLines; i++) {
int8_t item = oledMenu.highlightedMenuItem - _centreLine + i; // centre le surlignage sur la 3eme lignes
if (item == oledMenu.highlightedMenuItem) {
ecranOLED.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
}
else {
ecranOLED.setTextColor(SSD1306_WHITE);
}
if (item > 0 && item <= oledMenu.noOfmenuItems) {
ecranOLED.println(oledMenu.menuItems[item]);
}
else {
ecranOLED.println(" ");
}
}
//// how to display some updating info. on the menu screen
// ecranOLED.setCursor(80, 25);
// ecranOLED.println(millis());
ecranOLED.display();
}
// ----------------------------------------------------------------
// -service value entry AFFICHAGE
// ----------------------------------------------------------------
// if _blocking set to 1 then all other tasks are stopped until a value is entered
int32_t serviceValue(bool _blocking) {
const int8_t _valueSpacingX = 30; // spacing for the displayed value x position
const int8_t _valueSpacingY = 5; // spacing for the displayed value y position
if (_blocking) {
menuMode = blocking;
oledMenu.lastMenuActivity = millis(); // log time of last activity (for timeout)
}
uint32_t tTime;
do {
// rotary encoder
if (encoder0Pos > 0) { // ici on incremente ++ pas encoder variable
if (serialDebug) {
Serial.print("encoder0Pos Valeur ++ : ");
Serial.println(encoder0Pos);
}
oledMenu.mValueEntered += encoder0Pos * oledMenu.mValueStep; // vitesse variable (encoder0Pos positif toujours) [oledMenu.mValueStep -> coef de multiplication du step encoder]
encoder0Pos = 0;
oledMenu.lastMenuActivity = millis(); // log time
}
if (encoder0Pos < 0) { // ici on decremente -- pas encoder variable
if (serialDebug) {
Serial.print("encoder0Pos Valeur -- : ");
Serial.println(encoder0Pos);
}
oledMenu.mValueEntered += encoder0Pos * oledMenu.mValueStep; // vitesse variable (encoder0Pos negatif toujours) [oledMenu.mValueStep -> coef de multiplication du step encoder]
encoder0Pos = 0;
oledMenu.lastMenuActivity = millis(); // log time
}
if (oledMenu.mValueEntered < oledMenu.mValueLow) { // Fixe valeur minimum
oledMenu.mValueEntered = oledMenu.mValueLow;
oledMenu.lastMenuActivity = millis(); // log time
}
if (oledMenu.mValueEntered > oledMenu.mValueHigh) { // Fixe valeur maximum
oledMenu.mValueEntered = oledMenu.mValueHigh;
oledMenu.lastMenuActivity = millis(); // log time
}
if( millis() - previousRefreshOled >= intervalRefreshOled) { // Timer pour le refresh ecran oled (2 fois par secondes)
previousRefreshOled = millis();
// Affichage
ecranOLED.clearDisplay();
ecranOLED.setTextColor(SSD1306_WHITE);
ecranOLED.setFont(&FreeSerif9pt7b);
// title
oledCentreString(oledMenu.menuTitle, 0, 13, 128); // y=13 sur 16 pixel pour le Jaune (Garde les 16 premiers caracteres)
ecranOLED.drawLine(0, topLine-1, ecranOLED.width(), topLine-1, SSD1306_WHITE); // draw horizontal line under title
// CORPS du message
// value selected specifique
// ************* OFF / ON *************
if (oledMenu.menuTitle == "OFF / ON") {
//if (serialDebug) Serial.println("ON /OFF Ventilateur : oledAfficheONOFF()");
oledAfficheONOFF(oledMenu.mValueEntered); // Affiche l'etat du ventilo MARCHE / ARRET
}
// SONDES TEMPERATURES *************
else if (oledMenu.menuTitle == "Sondes Erreurs") {
//if (serialDebug) Serial.println("Sondes Erreurs : oledAfficheErrSonde()");
oledAfficheErrSonde(); // Affiche les erreurs des Sondes de Temperature sur l'ecran OLED
}
else if (oledMenu.menuTitle == "Sondes Rempla.") {
//if (serialDebug) Serial.println("Sondes Rempla. : oledAfficheRempSonde()");
oledAfficheRempSonde(indexSondeRemp); // Affiche ecran de REMPLACEMENT des Sondes de Temperature
}
// ************* VENTILATEUR *************
else if (oledMenu.menuTitle == "Ven Auto / Manu") {
//if (serialDebug) Serial.println("Mode Auto / Manu Ventilateur : oledAfficheManuAuto()");
oledAfficheManuAuto(oledMenu.mValueEntered); // Affiche l'etat du Mode Auto / Manu pour le ventilateur
}
else if (oledMenu.menuTitle == "RPM Ventilateur") {
if (flag_ventilo_manu_on_off == true) { // si Mode Manu
if (flag_Debug_PWM_Ventilo == false) {
// Ajout check numero vitesse existe pas AVOIR AVOIR AFFICHAGE
oledAfficheRPM(rpm, oledMenu.mValueEntered, Nbrevitesse-2); // Affiche les RPM et le numero de la vitesse pour le PWM du moteur
}
else {
oledAfficheRPM(rpm, oledMenu.mValueEntered, VitesseVentil[Nbrevitesse-1]); // Affiche les RPM et le PWM du moteur Mode DEBUG
}
}
else { // si Mode Auto
if (Flag_vitesseDynamique_ON == true) { // Gestion dynamique vitesse ventilo Mode Dynamique Actif (ON) TRUE
oledAfficheRPM(rpm, RechercheNumVitesseDyn(), Nbrevitesse-2);
}
else { // Mode Dynamique Inactif (OFF) FALSE
for (uint8_t i = 0; i < Nbrevitesse-1; i++) {
if (VitesseVentil[i] == pwm) { // recherche vitesse actuelle dans Tableau
oledAfficheRPM(rpm, i, Nbrevitesse-2); // Affiche les RPM et le PWM du moteur
break;
}
}
}
}
//if (serialDebug) Serial.println("RPM Ventilateur : oledAfficheRPM()");
}
else if (oledMenu.menuTitle == "Temp. ON") {
oledAfficheTempSeuil(float(oledMenu.mValueLow), float(oledMenu.mValueHigh), float(oledMenu.mValueEntered)); // Affiche la Temperature Min chaud (Hotte DEMARRAGE)
}
else if (oledMenu.menuTitle == "Hyst Temp. ON") {
oledAfficheTempSeuil(float(oledMenu.mValueLow), float(oledMenu.mValueHigh), float(oledMenu.mValueEntered)); // Affiche l'Hysteresis de le temperature Min chaud (Hotte DEMARRAGE)
}
else if (oledMenu.menuTitle == "Temp. OFF") {
oledAfficheTempSeuil(float(oledMenu.mValueLow), float(oledMenu.mValueHigh), float(oledMenu.mValueEntered)); // Affiche la Temperature Max moteur ARRET
}
else if (oledMenu.menuTitle == "Heure Deb Jour") {
oledAfficheTime(oledMenu.mValueEntered); // Affiche la Temps Heure Deb Jour (Mode Jour / Nuit)
}
else if (oledMenu.menuTitle == "Vitesse Jour") {
oledAfficheInt(oledMenu.mValueLow, oledMenu.mValueHigh, oledMenu.mValueEntered, 48); // Affiche le numero de la vitesse choisi pour le mode Jour
}
else if (oledMenu.menuTitle == "Heure Deb Nuit") {
oledAfficheTime(oledMenu.mValueEntered); // Affiche la Temps Heure Deb Nuit (Mode Jour / Nuit)
}
else if (oledMenu.menuTitle == "Vitesse Nuit") {
oledAfficheInt(oledMenu.mValueLow, oledMenu.mValueHigh, oledMenu.mValueEntered, 48); // Affiche le numero de la vitesse choisi pour le mode Nuit
}
else if (oledMenu.menuTitle == "Mode Boost ON") {
//if (serialDebug) Serial.println("Mode Boost ON Ventilateur : oledAfficheONOFF()");
oledAfficheONOFF(oledMenu.mValueEntered); // Affiche l'etat du Mode Boost ON pour le ventilateur
}
else if (oledMenu.menuTitle == "Vitesse Boost") {
oledAfficheInt(oledMenu.mValueLow, oledMenu.mValueHigh, oledMenu.mValueEntered, 48); // Affiche le numero de la vitesse choisi pour le mode Boost
}
else if (oledMenu.menuTitle == "Duree Boost") {
oledAfficheTime(oledMenu.mValueEntered); // Affiche le Temps Mode BOOST
}
// ************* IRIS *************
else if (oledMenu.menuTitle == "Iri Auto / Manu") {
//if (serialDebug) Serial.println("Iri Auto / Manu IRIS : oledAfficheManuAuto()");
oledAfficheManuAuto(oledMenu.mValueEntered); // Affiche l'etat du Iris Auto / Manu
}
else if (oledMenu.menuTitle == "IRIS Position") {
// oledMenu.mValueEntered; // (valeur entre 0 et 115)
// PosIris // (valeur entre 0 et 12000)
// TempPosIris // (valeur entre 0 et 12000)
if (flag_iris_manu_on_off == true) { // si Mode Manu
TempPosIris = round(oledMenu.mValueEntered * (float)PasStepIris); // Rafraichi en temps reel
TempPosIris = verifStepIris(TempPosIris); // verifie que la division par 2 donne Zero (Halfstep) et qu'on n'est pas superieur (home et maxtravel)
// oledAfficheIRIS(int16_t currentPos[au centre], int16_t desiredPos [en bas a droite])
oledAfficheIRIS(Steppercurrent, TempPosIris); // Rafraichi la position de l'IRIS sur l'ecran OLED
}
else { // si Mode Auto
oledAfficheIRIS(Steppercurrent, PosIris); // Rafraichi la position de l'IRIS sur l'ecran OLED PID [OutputPID + correction]
}
//if (serialDebug) Serial.println("IRIS Position : oledAfficheIRIS()");
}
else if (oledMenu.menuTitle == "IRIS Consigne") {
oledAfficheTempSeuil(float(oledMenu.mValueLow), float(oledMenu.mValueHigh), float(oledMenu.mValueEntered)); // Affiche la Temperature consigne regulation PID (SMoteur)
}
else if (oledMenu.menuTitle == "IRIS Tmin Arret") {
oledAfficheTempSeuil(float(oledMenu.mValueLow), float(oledMenu.mValueHigh), float(oledMenu.mValueEntered)); // Affiche la Temperature coupure / Arret regulation PID (Si trop froid Niveau Temperature Smoteur)
}
// ************* COURBE VENTILATION *************
else if (oledMenu.menuTitle == "Vitesse Base") {
oledAfficheInt(oledMenu.mValueLow, oledMenu.mValueHigh, oledMenu.mValueEntered, 48); // Affiche le numero de la vitesse de Base (Vitesse Dynamique)
}
else if (oledMenu.menuTitle == "Vitesse Inter.") {
oledAfficheInt(oledMenu.mValueLow, oledMenu.mValueHigh, oledMenu.mValueEntered, 48); // Affiche le numero de la vitesse Intermadiaire (Vitesse Dynamique)
}
else if (oledMenu.menuTitle == "Vitesse Maxi") {
oledAfficheInt(oledMenu.mValueLow, oledMenu.mValueHigh, oledMenu.mValueEntered, 48); // Affiche le numero de la vitesse Maximum (Vitesse Dynamique)
}
else if (oledMenu.menuTitle == "Vitesse Offset") {
oledAfficheIntToFloat(oledMenu.mValueLow, oledMenu.mValueHigh, oledMenu.mValueEntered, 48); // Affiche le numero de la vitesse d'Offset (Vitesse Dynamique)
}
else if (oledMenu.menuTitle == "Temp. Base") {
oledAfficheTempSeuil(float(oledMenu.mValueLow), float(oledMenu.mValueHigh), float(oledMenu.mValueEntered)); // Affiche la Temperature de Base (Vitesse Dynamique)
}
else if (oledMenu.menuTitle == "Temp. Inter.") {
oledAfficheTempSeuil(float(oledMenu.mValueLow), float(oledMenu.mValueHigh), float(oledMenu.mValueEntered)); // Affiche la Temperature Intermadiaire (Vitesse Dynamique)
}
else if (oledMenu.menuTitle == "Temp. Mini") {
oledAfficheTempSeuil(float(oledMenu.mValueLow), float(oledMenu.mValueHigh), float(oledMenu.mValueEntered)); // Affiche la Temp. Mini (Vitesse Dynamique)
}
else if (oledMenu.menuTitle == "Temp. Offset") {
oledAfficheTempSeuil(float(oledMenu.mValueLow), float(oledMenu.mValueHigh), float(oledMenu.mValueEntered)); // Affiche la Temperature d'Offset (Vitesse Dynamique)
}
// ************* CONFIG *************
else if (oledMenu.menuTitle == "Debug PWM Ventilo") {
//if (serialDebug) Serial.println("Config_Menu: Debug PWM Ventilo : oledAfficheONOFF()");
oledAfficheONOFF(oledMenu.mValueEntered); // Affiche Debug PWM Ventilo
}
// ************* CONFIG DATE HEURE ************* AFFICHAGE -->> CONFIG DATE / HEURE
else if (oledMenu.menuTitle == "Config Date/Heure") {
//if (serialDebug) Serial.println("Afichage Config Date/Heure: Config Date/Heure");
oledAfficheConfigDateHeure(oledMenu.mValueEntered,oledMenu.highlightedMenuItem); // Affiche Config Date/Heure
}
else { // value selected BASE
ecranOLED.setFont();// Revient a la police par defaut
ecranOLED.setCursor(_valueSpacingX, topLine + _valueSpacingY);
ecranOLED.setTextSize(3);
ecranOLED.println(oledMenu.mValueEntered);
// range
ecranOLED.setCursor(0, ecranOLED.height() - lineSpace1 - 1 ); // bottom of display
ecranOLED.setTextSize(1);
ecranOLED.print(oledMenu.mValueLow);
ecranOLED.print(" to ");
ecranOLED.println(oledMenu.mValueHigh);
// bar
int16_t Tlinelength = map(oledMenu.mValueEntered, oledMenu.mValueLow, oledMenu.mValueHigh, 0 , ecranOLED.width());
ecranOLED.drawLine(0, ecranOLED.height()-1, Tlinelength, ecranOLED.height()-1, SSD1306_WHITE);
ecranOLED.display();
}
// Fin Affichage
} // Fin Timer
tTime = (unsigned long)(millis() - oledMenu.lastMenuActivity); // time since last activity
} while (_blocking && ENC_SW_state_short == LOW && tTime < (menuTimeout * 1000)); // if in blocking mode repeat until button is pressed or timeout
if (_blocking) menuMode = off_menu;
return oledMenu.mValueEntered; // used when in blocking mode
}
// ----------------------------------------------------------------
// -message display
// ----------------------------------------------------------------
// 21 characters per line, use "\n" for next line
// assistant: < line 1 >< line 2 >< line 3 >< line 4 >
void displayMessage(String _title, String _message) {
//resetMenu(); // BUG Flash dans ecran status WIFI
menuMode = message;
oledMenu.menuTitle = _title; //AVOIR
if (_title.endsWith("1")) { // permet d'enlever le 1 a la fin du titre (supprime le dernier caractere) pour Charger1, Enregistrer1 et Redemarrage1
_title = _title.substring(0, _title.length() - 1);
}
ecranOLED.clearDisplay();
ecranOLED.setTextColor(SSD1306_WHITE);
ecranOLED.setFont(&FreeSerif9pt7b);
// title
oledCentreString(_title, 0, 13, 128); // y=13 sur 16 pixel pour le Jaune
ecranOLED.drawLine(0, topLine-1, ecranOLED.width(), topLine-1, SSD1306_WHITE); // draw horizontal line under title
// message
ecranOLED.setFont(); // Revient a la police par defaut
ecranOLED.setTextSize(1);
ecranOLED.setCursor(0, topLine+2); // debut du text sous le titre du message
ecranOLED.println(_message);
ecranOLED.display();
}
// ----------------------------------------------------------------
// -Coube de Ventilation
// ----------------------------------------------------------------
// Courbe vitesse ventilation en fonction de la temperature exterieure (Vitesse dynamique)
// - Contient Fonction uint8_t Xval(float inValTemp); -> Fonction Courbe Ventilation coordonnée point X (Vitesse dynamique CourbeVentilation())
// - Contient Fonction uint8_t Yval(int16_t inValPwm); -> Fonction Courbe Ventilation coordonnée point Y (Vitesse dynamique CourbeVentilation())
void CourbeVentilation() {
ecranOLED.clearDisplay(); // clear display
ecranOLED.setTextColor(SSD1306_WHITE);
ecranOLED.setTextSize(1);
int8_t xInt = Xval(seuilTempI) + 29; // 76;
if (serialDebug) {
Serial.print("xInt : ");
Serial.println(xInt);
}
int8_t yInt = Yval(seuilVitesseI); // 17;
if (serialDebug) {
Serial.print("yInt : ");
Serial.println(yInt);
}
// valeur verticale texte valeur (Tr/min)
ecranOLED.setCursor(0,0);
ecranOLED.print(pwmTotrmin(seuilVitesseMa)); //valeur PWM
ecranOLED.setCursor(27,0);
ecranOLED.print("tr/min");
ecranOLED.setCursor(0,yInt-3); // moitier caratere -3
ecranOLED.print(pwmTotrmin(seuilVitesseI));
ecranOLED.setCursor(0,47); // 63-6-10 (6-> hauteur caractere)
ecranOLED.print(pwmTotrmin(seuilVitesseB));
// valeur horizontale: text valeur (Temperature °C)
ecranOLED.setCursor(15,56); // 56 -> 63-6-1 (6-> hauteur caractere, 1 virgule)
ecranOLED.print(ftoS(seuilTempB, 1, true)); // valeur Temperature
ecranOLED.setCursor(xInt-8,56);
ecranOLED.print(ftoS(seuilTempI, 1, true));
ecranOLED.setCursor(98,56);
ecranOLED.print(ftoS(seuilTempMi, 1, true));
ecranOLED.setCursor(43,56);
ecranOLED.print("C");
ecranOLED.drawCircle(40, 57, 1, SSD1306_WHITE); // Affiche le ° degres
/*
ecranOLED.setCursor(122,45);
ecranOLED.print("C");
ecranOLED.drawCircle(119, 46, 1, SSD1306_WHITE); // Affiche le ° degres
*/
//cadre ligne verticale et point Base Inter Min
ecranOLED.drawFastVLine(25, 0, 54, SSD1306_WHITE); //-10
ecranOLED.drawPixel(24,0, SSD1306_WHITE); // Point max y
ecranOLED.drawPixel(24,yInt, SSD1306_WHITE); // Point mid y
ecranOLED.drawPixel(24,53, SSD1306_WHITE); // Point min y
//cadre ligne horizontale et point Base Inter Max
ecranOLED.drawFastHLine(25, 53, 103, SSD1306_WHITE);
ecranOLED.drawPixel(29,54, SSD1306_WHITE); // Point min x
ecranOLED.drawPixel(xInt,54, SSD1306_WHITE); // Point mid x
ecranOLED.drawPixel(123,54, SSD1306_WHITE); // Point max x
// Graph //x -> 25 --> 127 y -> 0 --> 53
ecranOLED.drawLine(29,53, xInt,yInt, SSD1306_WHITE); // x:(25+4->29) marge 4 sur x
ecranOLED.drawLine(xInt,yInt, 123,0, SSD1306_WHITE); // x:(127-4->123) marge 4 sur x
ecranOLED.display(); // display on OLED
}
// ----------------------------------------------------------------
// -Accueil menu
// ----------------------------------------------------------------
// Fonction pour afficher l'ecran d'accueil
void AccueilMenu() {
//resetMenu(); // Ecran Flash BUG
menuMode = message;
oledMenu.menuTitle = "Accueil";
ecranOLED.clearDisplay();
//drawLine(x1, y1, x2, y2, couleur)
ecranOLED.drawPixel(26,3, SSD1306_WHITE); // Point separation heure Wifi
ecranOLED.drawLine(65, 0, 65, 7, SSD1306_WHITE); // 1ere ligne du haut vertical // 8 (a la place du 7) AVOIR
ecranOLED.drawLine(51, 29, 51, 63, SSD1306_WHITE); // 2eme ligne du bas vertical
ecranOLED.drawLine(0, 8, 64, 8, SSD1306_WHITE); // 1ere ligne horizontal // 65 (a la place du 64) AVOIR
ecranOLED.drawLine(0, 29, 127, 29, SSD1306_WHITE); // 2eme ligne horizontal
ecranOLED.drawLine(0, 54, 127, 54, SSD1306_WHITE); // 3eme ligne horizontal
ecranOLED.setTextColor(SSD1306_WHITE);
ecranOLED.setTextSize(1);
// Positionnement des lignes donc y
int16_t y1 = 0;
int16_t y2 = y1+10;
int16_t y3 = y2+23;
int16_t y4 = y3+23;
// HEURE
ecranOLED.setCursor(0, y1); // (de 0 a 64)
if (Flag_HeureAccueil == true) {
ecranOLED.print(HeureAccueil);
ecranOLED.setCursor(10, y1);
ecranOLED.print(":");
ecranOLED.setCursor(14, y1);
ecranOLED.print(MinutAccueil);
}
else {
ecranOLED.print("--");
ecranOLED.setCursor(10, y1);
ecranOLED.print(":");
ecranOLED.setCursor(14, y1);
ecranOLED.print("--");
}
// WIFI
ecranOLED.setCursor(28, y1); // (de 65 a 128) New(de 32 a 67)
ecranOLED.print("W");
ecranOLED.setCursor(33, y1); // (de 65 a 128) New(de 32 a 67)
ecranOLED.print("i");
ecranOLED.setCursor(36, y1); // (de 65 a 128) New(de 32 a 67)
ecranOLED.print("f");
ecranOLED.setCursor(41, y1); // (de 65 a 128) New(de 32 a 67)
ecranOLED.print("i");
if (WifiStaMode == true) { // Si wifi en mode STA
if (WiFi.status() == WL_CONNECTED) {
//ecranOLED.print("Wifi CON");
ecranOLED.setCursor(47, y1); // (de 47 a 65)
ecranOLED.write(0x02); // (0x02) -> Smilet content, (0x01) -> Smilet pas content
// Signal Wifi
int8_t bars;
int16_t RSSI = WiFi.RSSI();
// Nombe de barre en fonction des dBm de WiFi.RSSI()
if (RSSI >= -30) {
bars = 5;
} else if (RSSI < -30 && RSSI >= -60) {
bars = 4;
} else if (RSSI < -60 && RSSI >= -70) {
bars = 3;
} else if (RSSI < -70 && RSSI >= -80) {
bars = 2;
} else if (RSSI < -80 && RSSI >= -90) {
bars = 1;
} else {
bars = 0;
}
//Serial.print("bars : ");Serial.print(bars);Serial.print(", RSSI : ");Serial.println(RSSI);
// Permet d'afficher les barres de la force du signal Wifi.
for (int8_t b=0; b <= bars; b++) {
ecranOLED.fillRect(52 + (b*2), 6 - b, 1, b, SSD1306_WHITE);
}
}
else {
//ecranOLED.print("Wifi DECON");
ecranOLED.setCursor(46, y1); // (de 28 a 65)
ecranOLED.print("DEC");
}
}
else { // Si wifi en mode AP
ecranOLED.setCursor(52, y1); // (de 28 a 65)
ecranOLED.print("AP");
}
// TEMPERATURE ET CONSIGNE
// Temperature Exterieure
ecranOLED.setCursor(69, y1); // (de 65 a 128)
ecranOLED.print("Te:");
if (SondeTempC[3] == -127) { // CAS Erreur -127
ecranOLED.setCursor(86,y1);
ecranOLED.print("Er.-127");
//ecranOLED.println(SondeTempC[3],0);
}
else if (SondeTempC[3] == -85) { // CAS Erreur +85
ecranOLED.setCursor(86,y1);
ecranOLED.print("Er.+ 85");
//ecranOLED.println(SondeTempC[3],0);
}
else {
oledAlligneDroiteFloat(SondeTempC[3], y1, 117);
ecranOLED.setCursor(122, y1);
ecranOLED.drawCircle(119, y1+1, 1, SSD1306_WHITE); // Affiche le ° degres
ecranOLED.print("C");
}
// Temperature Chaud
ecranOLED.setCursor(0, y2); // (de 0 a 64)
ecranOLED.print("Tc:");
if (SondeTempC[1] == -127) { // CAS Erreur -127
ecranOLED.setCursor(17,y2);
ecranOLED.print("Er.-127");
//ecranOLED.println(SondeTempC[1],0);
}
else if (SondeTempC[1] == -85) { // CAS Erreur +85
ecranOLED.setCursor(17,y2);
ecranOLED.print("Er.+ 85");
//ecranOLED.println(SondeTempC[1],0);
}
else {
oledAlligneDroiteFloat(SondeTempC[1], y2, 48);
ecranOLED.setCursor(53, y2);
ecranOLED.drawCircle(50, y2+1, 1, SSD1306_WHITE); // Affiche le ° degres
ecranOLED.print("C");
}
// Temperature Moteur
ecranOLED.setCursor(69, y2); // (de 65 a 128)
ecranOLED.print("Tm:");
if (SondeTempC[0] == -127) { // CAS Erreur -127
ecranOLED.setCursor(86,y2);
ecranOLED.print("Er.-127");
//ecranOLED.println(SondeTempC[0],0);
}
else if (SondeTempC[0] == -85) { // CAS Erreur +85
ecranOLED.setCursor(86,y2);
ecranOLED.print("Er.+ 85");
//ecranOLED.println(SondeTempC[0],0);
}
else {
oledAlligneDroiteFloat(SondeTempC[0], y2, 117);
ecranOLED.setCursor(122, y2);
ecranOLED.drawCircle(119, y2+1, 1, SSD1306_WHITE); // Affiche le ° degres
ecranOLED.print("C");
}
// Temperature Froid
ecranOLED.setCursor(0, y2+10); // (de 0 a 64)
ecranOLED.print("Tf:");
if (SondeTempC[2] == -127) { // CAS Erreur -127
ecranOLED.setCursor(17,y2+10);
ecranOLED.print("Er.-127");
//ecranOLED.println(SondeTempC[2],0);
}
else if (SondeTempC[2] == -85) { // CAS Erreur +85
ecranOLED.setCursor(17,y2+10);
ecranOLED.print("Er.+ 85");
//ecranOLED.println(SondeTempC[2],0);
}
else {
oledAlligneDroiteFloat(SondeTempC[2], y2+10, 48);
ecranOLED.setCursor(53, y2+10);
ecranOLED.drawCircle(50, y2+11, 1, SSD1306_WHITE); // Affiche le ° degres
ecranOLED.print("C");
}
//Consigne
ecranOLED.setCursor(69, y2+10); // (de 65 a 128)
ecranOLED.print("Co:");
oledAlligneDroiteFloat(SetpointPID, y2+10, 117); // BUG affichage si ConsignePID modifié et PID pas encore UP // AVOIR
ecranOLED.setCursor(122, y2+10);
ecranOLED.drawCircle(119, y2+11, 1, SSD1306_WHITE); // Affiche le ° degres
ecranOLED.print("C");
// IRIS (de 0 a 64)
// IRIS mode, position
ecranOLED.setCursor(0, y3);
ecranOLED.print("I");
ecranOLED.setCursor(5, y3);
ecranOLED.print("R");
ecranOLED.setCursor(10, y3);
ecranOLED.print("I");
ecranOLED.setCursor(15, y3);
ecranOLED.print("S");
// Symbole Diametre
ecranOLED.setFont(&FreeSerif9pt7b);
ecranOLED.setCursor(1, y3+17);
ecranOLED.print("o");
ecranOLED.setCursor(3, y3+19);
ecranOLED.print("/");
ecranOLED.setFont();
oledAlligneDroiteInt(map2(Steppercurrent, home, maxtravel, DiamIrisMaxi, DiamIrisMini), y3+11, 33);
ecranOLED.setCursor(36, y3+11); // x=39
ecranOLED.print("mm");
//drawRoundRect(uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t radius, uint16_t color);
ecranOLED.drawRoundRect(36, y3-2, 11, 11, 3, SSD1306_WHITE); // vignette "encadrement"
if (flag_iris_manu_on_off == true) { // Mode Manu IRIS
ecranOLED.setCursor(39, y3);
ecranOLED.print("M"); // text to display pour Manu
}
else { // Mode Auto IRIS
ecranOLED.setCursor(39, y3);
ecranOLED.print("A"); // text to display pour Auto
}
// VENTILO (de 65 a 128)
// Ventilo mode, vitesse RPM
ecranOLED.setCursor(54, y3);
ecranOLED.print("VENT");
ecranOLED.setCursor(77, y3);
ecranOLED.print("I");
// RPM VENTILO
if (pwm != 0 && rpm == 0 && FlagErrorMoteur_RPM == true) { // Si le moteur ne tourne pas et qu'il est en ERREUR alors que PWM est different de zero
ecranOLED.setCursor(54, y3+11);
ecranOLED.print("Err. moteur");
}
else { // Si le moteur tourne ou que pwm = 0
oledAlligneDroiteInt(rpm, y3+11, 79);
ecranOLED.setCursor(82, y3+11);
ecranOLED.print("tr/min");
}
// Mode Ventilo
if (modeVentilo != off_ventilo) { // Si le ventilo n'est pas eteint
ecranOLED.drawRoundRect(84, y3-2, 11, 11, 3, SSD1306_WHITE); // Pour mode Auto, Manu, Boost vignette "encadrement"
if (modeVentilo == jour || modeVentilo == nuit) { // si mode AUTO
ecranOLED.setCursor(87, y3);
ecranOLED.print("A");
ecranOLED.drawRoundRect(97, y3-2, 11, 11, 3, SSD1306_WHITE); // Pour mode Jour, Nuit
if (modeVentilo == jour) { // si mode JOUR
ecranOLED.setCursor(100, y3);
ecranOLED.print("J");
}
else { // si mode NUIT
ecranOLED.setCursor(100, y3);
ecranOLED.print("N");
}
}
else if (modeVentilo == boost) { // si mode BOOST
ecranOLED.setCursor(87, y3);
ecranOLED.print("B");
}
else if (modeVentilo == manu) { // si mode MANU
ecranOLED.setCursor(87, y3);
ecranOLED.print("M");
}
}
else { // si mode OFF
ecranOLED.drawRoundRect(84, y3-2, 11, 11, 3, SSD1306_WHITE); // Pour mode Auto, Manu vignette "encadrement"
ecranOLED.setCursor(87, y3);
if (flag_ventilo_manu_on_off == false) { // si Mode Auto
ecranOLED.print("A");
}
else { // si Mode Manu
ecranOLED.print("M");
}
}
// Numero de la vitesse du ventilo selectionne ou PWM brute
if (flag_ventilo_manu_on_off == true && flag_Debug_PWM_Ventilo == true) {
ecranOLED.drawRoundRect(97, y3-2, 30, 11, 3, SSD1306_WHITE); // vignette "encadrement" pwm vitesse 4 digits max 1023, 2047, 4095 etc...
oledAlligneDroiteInt(pwm, y3, 125); // AFFICHE PWM valeur de 0 a maxPWM
}
else {
// Numero de la vitesse du ventilo selectionne
if (Flag_vitesseDynamique_ON == true) { // Gestion dynamique vitesse ventilo
NumDynVit = RechercheNumVitesseDyn();
flag_Nbrevitesse_exist = true; // On force le flag a TRUE car la RechercheNumVitesseDyn renvoie toujours un nombre (Normalement !!!!)
}
else {
for (uint8_t i = 0; i < Nbrevitesse-1; i++) {
if (VitesseVentil[i] == pwm) { // recherche vitesse actuelle dans Tableau
NumDynVit = i;
flag_Nbrevitesse_exist = true; // si on trouve le numero de la vitesse dans VitesseVentil[Nbrevitesse-2] (0 - 19) --> flag -> TRUE
break;
}
}
}
if (flag_Nbrevitesse_exist == true) {
if (serialDebug) {
Serial.print("ACCUEIL : pwm : ");
Serial.print(pwm);
Serial.print(", VitesseVentil[");
Serial.print(NumDynVit);
Serial.print("] : ");
Serial.println(VitesseVentil[NumDynVit]);
}
ecranOLED.drawRoundRect(110, y3-2, 17, 11, 3, SSD1306_WHITE); // vignette "encadrement" Numero vitesse 2 digits max 19 -> 20 choix
if (NumDynVit < 10) { // si vitesse Ventilo inf à 10 on centre le Digit (de 0 a 9)
ecranOLED.setCursor(116, y3);
}
else { // si vitesse Ventilo sup à 10 deux Digits (de 10 a 19)
ecranOLED.setCursor(113, y3);
}
ecranOLED.print(NumDynVit); // text to display pour numero de vitesse ventilo
}
// si numero de la vitesse n'existe pas dans le tableau des vitesses VitesseVentil[Nbrevitesse-2] affiche la valeur PWM BRUTE
if (flag_Nbrevitesse_exist == false && flag_ventilo_manu_on_off == true && flag_Debug_PWM_Ventilo == false) {
ecranOLED.drawRoundRect(97, y3-2, 30, 11, 3, SSD1306_WHITE); // vignette "encadrement" pwm vitesse 4 digits max 1023, 2047, 4095 etc...
oledAlligneDroiteInt(pwm, y3, 125);
}
flag_Nbrevitesse_exist = false; // Reset Flag pour le prochain check
}
// OFF / ON VENTILO
if (flag_ventilo_on_off == true) {
oledCentreString("MARCHE", 0, y4, 51);
// Etat ventilo si en marche AVOIR
ecranOLED.setCursor(54, y4);
//SondeNom[] = {"Smoteur", "Schaud", "Sfroid", "Sext", "SFlag"};
if ((SondeTempC[0] != -127 && SondeTempC[1] != -127 && SondeTempC[2] != -127 && SondeTempC[3] != -127 && SondeTempC[0] != -85 && SondeTempC[1] != -85 && SondeTempC[2] != -85 && SondeTempC[3] != -85) && (FlagErrorMoteur_RPM == false)) { // Si sondes temp ok et moteur (ventilo) ok
// Sonde Chaud < Temp Hotte mini
if (SondeTempC[1] < ((Temp_ON_moteur + Hyst_moteur) * coef_temp)) { // Si PAS assez chaud -> Temperature chaud (Hotte)
ecranOLED.print("Tc < ");
oledAlligneDroiteFloat(((Temp_ON_moteur + Hyst_moteur) * coef_temp), y4, 117);
ecranOLED.setCursor(122, y4);
ecranOLED.drawCircle(119, y4+1, 1, SSD1306_WHITE); // Affiche le ° degres
ecranOLED.print("C");
}
// Sonde Moteur >= Temp Moteur Maxi
else if (SondeTempC[0] >= (Temp_OFF_moteur * coef_temp)) { // Si TROP chaud -> Temperature moteur
ecranOLED.print("Tm > ");
oledAlligneDroiteFloat((Temp_OFF_moteur * coef_temp), y4, 117);
ecranOLED.setCursor(122, y4);
ecranOLED.drawCircle(119, y4+1, 1, SSD1306_WHITE); // Affiche le ° degres
ecranOLED.print("C");
}
else {
if (modeVentilo != off_ventilo) {
ecranOLED.print("Tout est OK"); // AVOIR Ajout si different de mode OFF (modeVentilo != off_ventilo)
}
else {
ecranOLED.print("VentiModeOFF");
//ecranOLED.print("ABCDEFGHIJKL"); // Nombre max de caractere affichable dans la Zone
}
}
}
else { // Si ERREUR sondes temp OU ERREUR moteur (ventilo) OU LES DEUX
if ((SondeTempC[0] == -127 || SondeTempC[1] == -127 || SondeTempC[2] == -127 || SondeTempC[3] == -127 || SondeTempC[0] == -85 || SondeTempC[1] == -85 || SondeTempC[2] == -85 || SondeTempC[3] == -85) && (FlagErrorMoteur_RPM == true)) { // si Erreur sondes ET Erreur Ventilo
if (countErrorswitch == 4) { // Toutes les 2 sec (4 x 0.5 sec) on change de message
FlagErrorswitch = !FlagErrorswitch;
countErrorswitch = 0;
}
if (FlagErrorswitch) {
ecranOLED.print("Err. Moteur");
}
else {
ecranOLED.print("Err. Sondes");
}
countErrorswitch++;
}
else if ((SondeTempC[0] != -127 || SondeTempC[1] != -127 || SondeTempC[2] != -127 || SondeTempC[3] != -127 || SondeTempC[0] != -85 || SondeTempC[1] != -85 || SondeTempC[2] != -85 || SondeTempC[3] != -85) && FlagErrorMoteur_RPM == true) { // si Erreur Ventilo
ecranOLED.print("Err. Moteur");
}
else { // Si Erreur sondes
ecranOLED.print("Err. Sondes");
}
}
}
else {
oledCentreString("ARRET", 0, y4, 51);
}
ecranOLED.display();
}
// ----------------------------------------------------------------
// -reset menu system
// ----------------------------------------------------------------
void resetMenu() {
// reset all menu variables / flags
menuMode = off_menu;
oledMenu.selectedMenuItem = 0;
encoder0Pos = 0;
oledMenu.noOfmenuItems = 0;
oledMenu.menuTitle = "";
oledMenu.highlightedMenuItem = 1; // Se positionne a la 1ere ligne du menu
oledMenu.mValueEntered = 0;
oledMenu.mValueStep = 1; // A voir coef de multiplication du step encoder
ENC_SW_state_short = LOW;
ENC_SW_state_long = LOW;
oledMenu.lastMenuActivity = millis(); // log time
// clear oled display
oledClearDisplay();
}
// ************************
// ****** FIN MENU ******
// ************************
// ******************************************
// *** DEBUT Fonction CONFIG DATE / HEURE ***
// ******************************************
// NTP Callback function (get's called when time adjusts via NTP) mise a jour date et heure retour fonction AUTO toutes les heures
void timeavailable(struct timeval *tv) {
if (serialDebug) {
Serial.print("Got time adjustment from NTP! TimeStamp : ");
Serial.println(tv->tv_sec);// TimeStamp : 1691338965 -> 2023-08-06T18:22:45
}
//Serial.println(ctime(&tv->tv_sec)); // Date : Sun Aug 6 18:22:45 2023
//Serial.println(tv->tv_sec);
//Serial.println(tv->tv_sec,HEX); // Nombre de seconde en Hexa
//TEST RollOver
//tv->tv_sec = 2147483646UL; // Une seconde avant Rollover
//tv->tv_sec += 2; // Une Seconde apres Rollover -> -2147483648
//settimeofday(tv, nullptr); // MAJ DATE
// Mode normal entre [0 -> (jeudi 1 janvier 1970 00:00:00) ET 2147483647 (Max int32_t) -> (mardi 19 janvier 2038 04:14:07)]
if ( 0 <= tv->tv_sec && tv->tv_sec <= 2147483647UL) { // UL -> unsigned long int uint32_t format
Flag_Y2038 = false;
offsetDateY2038 = 0;
}
// Mode apres ROLLOVER 2147483647 +1 donc de -2147483648 (mardi 19 janvier 2038 04:14:08) A -1 (mardi 19 janvier 2094 04:14:07)] SI SUPPERIEUR A 2094 RESET a (mardi 19 janvier 2038 04:14:08)
if (tv->tv_sec < 0) {
tv->tv_sec += 2527741696UL; // 2147483648UL (revient a 0) + 380258048UL (revient 56 ans avant date Jour (2 x 28 ans))
settimeofday(tv, nullptr); // Update date
Flag_Y2038 = true;
offsetDateY2038 = 56;
}
if (!Flag_firstTimeUpdateNTP) { // 1er Run connexion NTP serveur ok
if (serialDebug_Init) Serial.println("INIT NTP Server : OK");
Flag_firstTimeUpdateNTP = true; // Flag pour recetion mise a jour date / heure ok du serveur NTP 1er Run pour synchronisation millis heure
}
if (Flag_Manual_Date == true) { // Si update DATE/HEURE en MODE MANU
Flag_Manual_Date = false; // Reset Flag Mise a jour manuel heure et date
Flag_HeureAccueil = false; // Reset Flag update heure menu en immediat
for (int8_t i=0; i < 6; i++) { // Reset contenuDateNum Config manuel de la date
contenuDateNum[i] = -1;
}
}
}
// creation variable repertoire et nom fichier avec parametre serveur NTP
void printLocalTime(struct tm * timeinfo) {
//Format "%d/%m/%Y - %H:%M:%S" (-> 19/01/2024 - 04:15:00 (21+1 char))
//char dateTime[22];
//snprintf(dateTime, 22, "%02d/%02d/%04d - %02d:%02d:%02d", timeinfo->tm_mday, timeinfo->tm_mon + 1, timeinfo->tm_year + 1900 + offsetDateY2038, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
//Serial.println(dateTime);
// Format "%Y-%m-%dT%H:%M:%S" // Date + heure dans fichier (-> 2024-01-19T04:15:00)
snprintf(DateHour, 73, "%04d-%02d-%02dT%02d:%02d:%02d", timeinfo->tm_year + 1900 + offsetDateY2038, timeinfo->tm_mon + 1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
//Serial.println(DateHour);
// Format "/data/%Y/%m/%d.txt" // Repertoire Année + Mois + nom fichier jour.txt (-> /data/2024/01/19.txt)
snprintf(YearMonthDayFile, 47, "/data/%04d/%02d/%02d.txt", timeinfo->tm_year + 1900 + offsetDateY2038, timeinfo->tm_mon + 1, timeinfo->tm_mday);
//Serial.println(YearMonthDayFile);
// Format "/data/%Y/%m" // Repertoire Année + Mois (-> /data/2024/01)
snprintf(YearMonth, 31, "/data/%04d/%02d", timeinfo->tm_year + 1900 + offsetDateY2038, timeinfo->tm_mon + 1);
//Serial.println(YearMonth);
// Format "/data/%Y" // Repertoire Année (-> /data/2024)
snprintf(Year, 19, "/data/%04d", timeinfo->tm_year + 1900 + offsetDateY2038);
//Serial.println(Year);
}
// Display Date et Heure et etat serveur NTP -> Menu Affichage DATE/HEURE
void MenuStatutDateHeure() {
if (Flag_firstTimeUpdateNTP == true || Flag_Manual_Date == true) {
time_t now = time(nullptr);
struct tm * timeinfo;
timeinfo = localtime(&now);
AjoutOffsetY2038(timeinfo); // BUG 2038 ajout offset pour 2038
char Date[45]; // Date : 19/01/2024 -> (18+1 char) Jours / Mois / Annees
char Hour[17]; // Heure : 04:15:06 -> (16+1 char)
// Format "Date : %d/%m/%Y" // Date : Jours / Mois / Années (-> Date : 19/01/2024)
snprintf(Date, 45, "Date : %02d/%02d/%04d", timeinfo->tm_mday, timeinfo->tm_mon + 1, timeinfo->tm_year + 1900 + offsetDateY2038);
//Serial.println(Date);
// Format "Heure : %H:%M:%S" // Heure : Heures : Minutes : Secondes (-> Heure : 04:15:06)
snprintf(Hour, 17, "Heure : %02d:%02d:%02d", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
//Serial.println(Hour);
if (Flag_Manual_Date == true) {
displayMessage("Statut Date/Heure", "\n" + (String)Date + "\n" + (String)Hour + "\nServeur NTP : KO\nDate Mode Manu : OK"); // REGLAGE MANU DATE ET HEURE -> MODE MANUEL
}
else {
//assistant: < line 1 > < line 2 > < line 3 > < line 4 >
displayMessage("Statut Date/Heure", "\n" + (String)Date + "\n" + (String)Hour + "\nServeur NTP : OK"); // SERVEUR NTP OK -> MODE AUTOMATIQUE
}
}
else {
displayMessage("Statut Date/Heure", "\nDate : --/--/----\nHeure : --:--:--\nServeur NTP : Erreur\nVerifier WIFI"); // SERVEUR NTP KO et pas de REGLAGE MANU DATE ET HEURE
}
}
// Format emplacement des Champs Dates et Heures partie static de l'affichage -> Menu Affichage DATE/HEURE
void FormatChampDateHeure() {
ecranOLED.setFont();// Revient a la police par defaut
ecranOLED.setTextSize(1);
ecranOLED.setCursor(0, 25); // Titre 25 en y (1ere ligne) DATE (Format Date : AAAA/MM/JJ)
ecranOLED.print("Date :");
ecranOLED.setCursor(72, 25);
ecranOLED.print("/");
ecranOLED.setCursor(90, 25);
ecranOLED.print("/");
ecranOLED.setCursor(0,40); // Titre 40 en y (2eme ligne) HEURE (Format Heure : HH:MM:SS)
ecranOLED.print("Heure :");
ecranOLED.setCursor(60,40);
ecranOLED.print(":");
ecranOLED.setCursor(78,40);
ecranOLED.print(":");
}
// Fonction OLED pour Configurer la date et l'heure -> Menu Affichage DATE/HEURE
void MenuConfigDateHeure() {
//Gestion encoder rotatif
if (encoder0Pos < 0) { // ici on incremente ++ Item
oledMenu.highlightedMenuItem--; // -1 STEP a la fois
encoder0Pos = 0;
oledMenu.lastMenuActivity = millis(); // log time
}
if (encoder0Pos > 0) { // ici on decremente -- Item
oledMenu.highlightedMenuItem++; // +1 STEP a la fois
encoder0Pos = 0;
oledMenu.lastMenuActivity = millis(); // log time
}
// verify valid highlighted item (limite MIN MAX) Modification une fois en dessous de bas (bas-1 -> HAUT) une fois au dessus de haut (haut+1 -> BAS)
if (oledMenu.highlightedMenuItem > 8) { // TEST ligne MAX
oledMenu.highlightedMenuItem = 1; // on revient a la premiere ligne
}
if (oledMenu.highlightedMenuItem < 1) { // TEST ligne MIN
oledMenu.highlightedMenuItem = 8; // on revient a la derniere ligne
}
ecranOLED.clearDisplay();
ecranOLED.setTextColor(SSD1306_WHITE);
ecranOLED.setFont(&FreeSerif9pt7b);
// title
if (menuLargeText) { // mets le nom du menu selectionné en TITRE
oledCentreString(oledMenu.menuItems[oledMenu.highlightedMenuItem], 0, 13, 128); // y=13 sur 16 pixel pour le Jaune (Garde les 16 premiers caracteres)
}
else {
oledCentreString(oledMenu.menuTitle, 0, 13, 128); // y=13 sur 16 pixel pour le Jaune (Garde les 16 premiers caracteres)
}
ecranOLED.drawLine(0, topLine-1, ecranOLED.width(), topLine-1, SSD1306_WHITE); // draw horizontal line under title
// Structure Statique champ DATE HEURE
FormatChampDateHeure();
for (int8_t i = 0; i < 8; i++) {
ecranOLED.setCursor(CoordXDate[i], CoordYDate[i]); // position X et Y des variables
if (i == oledMenu.highlightedMenuItem-1) {
ecranOLED.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
}
else {
ecranOLED.setTextColor(SSD1306_WHITE);
}
if (0 <= i && i < 6) { // entre 0 et 5 Année a Secondes -> on exclut Valider(6) et Annuler(7)
if (contenuDateNum[i] != -1) {
if (contenuDateNum[i] < 10) { // si inferieur a 10 on ajoute un 0
ecranOLED.print("0");
}
ecranOLED.print(contenuDateNum[i]);
}
else {
ecranOLED.print(contenuDateStringVide[i]);
}
}
else {
ecranOLED.print(contenuDateStringVide[i]);
}
} // Fin FOR
// de 1 a 6 -> appui COURT
if (ENC_SW_state_short == HIGH && 1 <= oledMenu.highlightedMenuItem && oledMenu.highlightedMenuItem <= 6) { // permet d'aller dans le Sous Menu pour les Valeurs appui COURT
oledMenu.selectedMenuItem = oledMenu.highlightedMenuItem; // flag that the item has been selected
oledMenu.lastMenuActivity = millis(); // log time
}
// de 7 a 8 -> appui LONG
if (ENC_SW_state_long == HIGH && 7 <= oledMenu.highlightedMenuItem && oledMenu.highlightedMenuItem <= 8) { // permet d'aller dans Valider ou Annuler appui LONG
oledMenu.selectedMenuItem = oledMenu.highlightedMenuItem; // flag that the item has been selected
oledMenu.lastMenuActivity = millis(); // log time
}
// Remet le status du bouton a low
ENC_SW_state_long = LOW;
ENC_SW_state_short = LOW;
ecranOLED.display();
}
// Fonction Affiche OLED pour Configurer la date et l'heure -> Menu Affichage DATE/HEURE
void oledAfficheConfigDateHeure(int16_t value, int8_t numeroSelected) { // value -> annees (max int16_t),mois, jours, heures, minutes et secondes , numeroSelected numero du menu max 0->7 int8_t
if (countDateCligno == 2) { // Toutes les 1 sec (2 x 0.5 sec) on change de message
FlagDateCligno = !FlagDateCligno;
countDateCligno = 0;
}
// Structure Statique champ DATE HEURE
FormatChampDateHeure();
for (int8_t i = 0; i < 8; i++) {
ecranOLED.setCursor(CoordXDate[i], CoordYDate[i]); // position X et Y des variables
if (i == numeroSelected-1) { // Champ date modif en cours
if (FlagDateCligno) { //Permet de faire clignoter le champ date en cours de modification (inversion couleur Texte)
ecranOLED.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
}
else {
ecranOLED.setTextColor(SSD1306_WHITE);
}
if (0 <= i && i < 6) {
if (value < 10) {
ecranOLED.print("0");
}
ecranOLED.print(value); // Champ date Valeur en cours
}
else {
ecranOLED.print(contenuDateStringVide[i]); // Champ Valider et Annuler
}
}
else { // Champ date valeur depuis contenuDateNum[]
ecranOLED.setTextColor(SSD1306_WHITE);
if (0 <= i && i < 6) {
if (contenuDateNum[i] != -1) {
if (contenuDateNum[i] < 10) {
ecranOLED.print("0");
}
ecranOLED.print(contenuDateNum[i]); // Si une valeur existe dans contenuDateNum[]
}
else {
ecranOLED.print(contenuDateStringVide[i]); // Sinon champ vide
}
}
else {
ecranOLED.print(contenuDateStringVide[i]); // Champ Valider et Annuler
}
}
} // Fin FOR
countDateCligno++; // Incrementation compteur pour faire clignoter le champ date en cours de modification
ecranOLED.display();
}
//Fonction pour Valider que tous les champs dates sont remplis -> Menu Affichage DATE/HEURE
void ValideChampDate() {
for (int8_t i = 0; i < 6; i++) { // Affiche sur serial le contenu de contenuDateNum
//Serial.print("contenuDateNum[");
//Serial.print(i+1);
//Serial.print("] -> ");
//Serial.println(contenuDateNum[i]);
if (contenuDateNum[i] == -1) {
Flag_configchampDate = false; // Si il manque un champ date on ne valide pas (champ NULL)
break;
}
Flag_configchampDate = true; // Si tous les champs dates sont remplis ok on valide
}
if (Flag_configchampDate) {
//Serial.println("Date OK");
// Année , Mois , Jours , Heures , Minutes , Secondes, , DST (changement Heure ete / hivers)
setDateTimeManu(contenuDateNum[0], contenuDateNum[1], contenuDateNum[2], contenuDateNum[3], contenuDateNum[4], contenuDateNum[5], -1); // MAJ DATE / HEURE
DateMenu();
}
else {
displayMessage("Config Date/HeureErr", "\n Erreur saisie Date\n\n Un champ est vide \n Verifier !!!");
//Serial.println("Erreur date");
// Retour vers le Menu [MenuConfigDateHeure()] si appui court -->> CONFIG DATE / HEURE
}
}
// Fonction pour determiner si c'est une Année Bissextile ou pas
uint8_t is_leap_year(int16_t y) {
return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); // return 0 ou 1
}
//Permet de verifier que la MAJ de la date / heure est faite copie de la fonction getLocalTime avec ajout Flag_Y2038 pour le Rollover
bool getLocalTime2(struct tm *info, uint32_t ms) { // 5000 -> timeout en ms de 5 sec (valeur par default)
uint32_t start = millis();
time_t now;
while ((millis() - start) <= ms) {
time(&now);
localtime_r(&now, info);
if (Flag_Y2038 == true) { // si flag 2038 RollOver retour en 1982 (-56 ans)
if (info->tm_year > (1981 - 1900)) {
return true;
}
}
else {
if (info->tm_year > (2023 - 1900)) {
return true;
}
}
//delay(10);
}
return false;
}
// Permet de definir un timestamp a partir de la date
void setDateTimeManu(int16_t yr, int8_t month, int8_t mday, int8_t hr, int8_t minute, int8_t sec, int8_t isDst) {
if (yr >= 2038) { // Si on depasse 2038 Rollover
Flag_Y2038 = true;
offsetDateY2038= 56; // 2038 (+56) (28ans x 2) ok de DEBUT:2038-> [1982(+56)], FIN:2094-> [2038(+56)]
}
else {
Flag_Y2038 = false;
offsetDateY2038= 0; // DEBUT:1970, FIN:2038
}
struct tm manu;
manu.tm_year = yr - 1900 - offsetDateY2038;
manu.tm_mon = month-1;
manu.tm_mday = mday;
manu.tm_hour = hr;
manu.tm_min = minute;
manu.tm_sec = sec;
manu.tm_isdst = isDst; // (1 or 0) ou -1 pour auto (Heure été/hivers)
time_t t = mktime(&manu); // Genere un timestamp a partir de la strurcture tm manu
//Serial.print("Creation timestamp: ");
//Serial.println(t);
struct timeval now = { .tv_sec = t, .tv_usec = 0 }; // MAJ tv_sec de timeval avec le timestamp de mktime()
settimeofday(&now, nullptr); // MAJ DATE HEURE
//Serial.println("Manuel Time ok");
Flag_Manual_Date = true;
Flag_HeureAccueil = false; // Reset Flag update heure menu en immediat
//Flag_firstTimeUpdateNTP = false; // Reset Flag pour recetion mise a jour date / heure ok du serveur NTP
}
//Fonction BUG 2038 ajout offset pour 2038
void AjoutOffsetY2038(struct tm * timeinfo) {
time_t t = mktime(timeinfo); // Extrait le timestamp de la structur tm timeinfo
//Serial.print("Get timestamp: ");
//Serial.println(t);
if (t < 0) { // Pour MAJ Manuel date/heure menu et si Rollover entre 2 requete NTP (Si Timestamp NEGATIF)
t += 2527741696UL; // 2147483648UL (revient a 0) + 380258048UL (revient 56 ans avant date Jour (2 x 28 ans))
//Serial.print("Setting timestamp: ");
//Serial.println(t);
struct timeval tvnow = { .tv_sec = t, .tv_usec = 0 };
settimeofday(&tvnow, nullptr); // MAJ DATE HEURE
time_t now = time(nullptr);
timeinfo = localtime(&now);
Flag_Y2038 = true;
}
if (Flag_Y2038) {
offsetDateY2038 = 56; // offset de -56 ans
}
else {
offsetDateY2038 = 0; // Reset offset
}
}
// ****************************************
// *** FIN Fonction CONFIG DATE / HEURE ***
// ****************************************
// **************************
// *** DEBUT VENTILATEUR ***
// **************************
// Echantillonage compte tour ventillateur si PWM different de zero donc ventilo ON (Mode Auto/Manu , Jour/Nuit, Boost)
void echantillonageRPM() {
// Compteur RPM ------------------ DEBUT
if (esp_timer_get_time() - last_RPM_refresh >= 1000000L) { // toutes les secondes
last_RPM_refresh = esp_timer_get_time();
if (pwm != 0) { // si ventilo ON
if (FlagAllImpulsionsPeriode_RPM == false) { // si le moteur ne tourne pas (Pas d'echantillion)
if (esp_timer_get_time() - last_RPM_interupt >= 75000L) { // toutes les 0.06 secondes (250 tr/min) si pas d'interruption (0.075 seconde pour 200 tr/min)
if (serialDebug) {
Serial.print("ARRET MOTEUR : Time periode_RPM : ");
Serial.print(esp_timer_get_time() - last_RPM_interupt);
Serial.println(" en µs");
}
last_RPM_interupt = esp_timer_get_time();
rpm = 0;
correctionPwm = 0; // Reset pour fonction correctionRPM()
oldrpm = 0; // Reset pour fonction correctionRPM()
FlagFirstImpulsion_RPM = false; // Reinitialise 1ere interuption apres arret moteur
if (esp_timer_get_time() - timer_first_start_RPM >= 3000000L) { // Timer 1er demarrage moteur apres etre OFF (MENU ou arret normal)
FlagErrorMoteur_RPM = true; // Flag pour dire que le moteur ne tourne pas Erreur bloqué ou autre
}
// AVOIR AJOUT COMPTEUR ERREUR MOTEUR ICI
}
}
else if (FlagAllImpulsionsPeriode_RPM == true) { // si le moteur tourne on determine sa vitesse (on a les 16 echantillions)
FlagErrorMoteur_RPM = false; // Reinitialise Flag pour dire que le moteur ne tourne pas (Ventilo OK il tourne aucun probleme)
//if (serialDebug) {Serial.print("Time periode_RPM : ");Serial.print(periode_RPM);Serial.println(" en µs");}
//**********************************
// DEBUT : Traitement des 16 echantillions pour vitesse moteur
//**********************************
uint64_t tot_periode_RPM = 0;
uint64_t avg_tot_periode_RPM = 0;
uint64_t avg_min_periode_RPM = 0;
uint64_t avg_max_periode_RPM = 0;
uint8_t countAVGPer = 0;
for (uint8_t i = 0; i < Nbre_echanti_RPM; i++) { // fait la somme des 16 periodes
//if (serialDebug) {Serial.print("periode_RPM[");Serial.print(i);Serial.print("] : ");Serial.println(periode_RPM[i]);}
tot_periode_RPM += periode_RPM[i];
}
avg_tot_periode_RPM = tot_periode_RPM / Nbre_echanti_RPM; // fait la moyenne des 16 periodes
//avg_max_periode_RPM = avg_tot_periode_RPM * 0.9; // 90 % de la periode
//avg_min_periode_RPM = avg_tot_periode_RPM * 1.1; // 110 % de la periode
avg_max_periode_RPM = (uint32_t) 15000000 / (((uint32_t) 15000000 / avg_tot_periode_RPM) - 50); // -50 tr/min
avg_min_periode_RPM = (uint32_t) 15000000 / (((uint32_t) 15000000 / avg_tot_periode_RPM) + 50); // +50 tr/min
if (serialDebug) {
Serial.print("tot_periode_RPM / Nbre_echanti_RPM : ");
Serial.println(avg_tot_periode_RPM);
}
for (uint8_t i = 0; i < Nbre_echanti_RPM; i++) {
//if (avg_min_periode_RPM < periode_RPM[i] && periode_RPM[i] < avg_max_periode_RPM) { // si entre 0.9 < periode_RPM[i] < 1.1
if (avg_min_periode_RPM < periode_RPM[i] && periode_RPM[i] < avg_max_periode_RPM) { // si entre (rpm -50tr/min) < periode_RPM[i] < (rpm +50tr/min)
//if (serialDebug) {Serial.print("GARDE : periode_RPM[");Serial.print(i);Serial.print("] : ");Serial.println(periode_RPM[i]);}
countAVGPer++;
}
else { // on ne garde pas
countAVGPer = 0; // Reset compteur
break; // on sort de la boucle FOR si mauvaise valeur
}
}
if (countAVGPer == Nbre_echanti_RPM) { // si on a bien les 16 echantillions
rpm = round(((uint32_t) 15000000 / avg_tot_periode_RPM)); // Front montant et descandant (on divise par 4 [4 impulsions par tour]-> 60 / 2 / 2 -> 15)
countAVGPer = 0; // reinitailise le compteur
correctionRPM(); // Correction PWM en fonction RPM actuel par rapport au RPM de reference
}
//**********************************
// FIN : Traitement des 16 echantillions pour vitesse moteur
//**********************************
if (serialDebug) {
Serial.print("RPM : ");
Serial.print(rpm);
Serial.println(" tr/min");
}
FlagAllImpulsionsPeriode_RPM = false; // on remet a FALSE le flag pour la recuperation des echantillions
} //Fin ELSE IF
} // FIN IF PWM
else {
FlagErrorMoteur_RPM = false; // Reinitialise Flag pour dire que le moteur ne tourne pas (Ventilo OK il tourne aucun probleme) AVOIR
rpm = 0; // Ventilo OFF MENU, ou arret temperature insuffisante
correctionPwm = 0; // Reset pour fonction correctionRPM()
oldrpm = 0; // Reset pour fonction correctionRPM()
timer_first_start_RPM = esp_timer_get_time(); // Reinitialise timer 1er demarrage RPM moteur (3 sec) pour eviter message d'erreur au 1er demarrage du moteur [FlagErrorMoteur_RPM]
if (serialDebug) Serial.println("ARRET MOTEUR : Time periode_RPM Choix menu ou off");
}
notifyClients((char*)"wsrpm");
} // Fin Timer
}
// Correction PWM si vitesse superieur ou inferieur a vitesse voulue
void correctionRPM() {
if (pwm == 0 ) { // si moteur arrete on sort
correctionPwm = 0; // int16_t Reset
oldrpm = 0; // int16_t Reset
return;
}
if (VitesseVentil[1] <= pwm && pwm <= VitesseVentil[19]) { // si pwm dans la plage de correction entre 900 et 2000 tr/min
int16_t RpmRef = pwmTotrmin(pwm); // Recuperation tr/min de reference a partir PWM
if (rpm != RpmRef) {
if (abs((int32_t)rpm - oldrpm) <= 2 ) { // Rpm +/- 2 tr/min par rapport a oldrpm vitesse stabilisee (Fin montee ou descente en regime)
int16_t DeltaRpm = RpmRef - rpm;
if (abs(DeltaRpm) > 2) { // on diminue la correction (vitesse superieure) OU on augmente la correction (vitesse inferieure) [sup a +/-3 tr/min]
if (abs(DeltaRpm) > 3) { // on diminue la correction (vitesse superieure) OU on augmente la correction (vitesse inferieure) [sup a +/-4 tr/min]
correctionPwm += pwm - trminTopwm(rpm); // on va plus vite
//correctionPwm = pwm - trminTopwm(rpm); // on va plus vite AVOIR ICI [suppression '+=' -> remplacement '='] MARCHE PAS
}
else { // sinon on augmente ou on diminue de seulement +/- 1 [egal a +/-3 tr/min]
if (DeltaRpm > 0) {
correctionPwm++; // on augmente la correction (vitesse inferieure)
}
else {
correctionPwm--; // on diminue la correction (vitesse superieure)
}
} // Fin ELSE
//Min - Max +/- 150 tr/min
if (correctionPwm > 42) { // Max correction +75 tr/min (old +35 PWM) [+/- 56 PWM pour 100 tr/min AVOIR]
correctionPwm = 42;
}
if (correctionPwm < -42) { // Min correction -75 tr/min (old -35 PWM)
correctionPwm = -42;
}
} // Fin if (abs(DeltaRpm) > 2)
} // Fin if (abs(rpm - oldrpm) <= 2 )
oldrpm = rpm;
} // if (rpm != RpmRef)
}
else {
correctionPwm = 0; // int16_t Reset
oldrpm = 0; // int16_t Reset
}
} // Fin Fonction correctionRPM
// Permet de convertir les tr/min en PWM (CorrectionPwm))
int16_t trminTopwm(int16_t rpm) {
//if (rpm <= 0) {
// return 0;
//}
if (rpm >= 800 && rpm < 1000) { // 900 - 100 AVOIR --> 800 tr/min
return round( rpm / 1.7857f + 307 ); // (PWM 811-867)
}
else if (rpm >= 1000 && rpm < 1100) {
return round( rpm / 1.6129f + 247 ); // (PWM 867-929)
}
else if (rpm >= 1100 && rpm < 1300) {
return round( rpm / 1.7241f + 291 ); // (PWM 929-1045)
}
else if (rpm >= 1300 && rpm < 1350) {
return round( rpm / 1.6666f + 265 ); // (PWM 1045-1075)
}
else if (rpm >= 1350 && rpm < 1750) {
return round( rpm / 1.7857f + 319 ); // (PWM 1075-1299)
}
else if (rpm >= 1750 && rpm < 1800) {
return round( rpm / 1.5625f + 179 ); // (PWM 1299-1331)
}
else if (rpm >= 1800 && rpm < 1850) {
return round( rpm / 1.7241f + 287 ); // (PWM 1331-1360)
}
else if (rpm >= 1850 && rpm < 1900) {
return round( rpm / 2 + 435 ); // (PWM 1360-1385)
}
else if (rpm >= 1900 && rpm < 1950) {
return round( rpm / 1.6129f + 207 ); // (PWM 1385-1416)
}
else if (rpm >= 1950 && rpm <= 2100) { // 2000 + 100 AVOIR --> 2100 tr/min
return round( rpm / 1.9231f + 402 ); // (PWM 1416-1442) ==> MAX 2047
}
return pwm; // AVOIR si supperieur 2100 tr/min ou inferieur a 800 tr/min AVOIR
}
// Mise a jour PWM du ventilateur (Mode)
void ventiloUpdate() {
switch (modeVentilo) {
// ventilo -> mode OFF
case off_ventilo:
pwm = VitesseVentil[0]; // Tableau des vitesses OFF
Flag_vitesseDynamique_ON = false;
etatVentilo = "Arret"; // 5 caracteres
//flag_ventilo_manu_on_off = false;
//flag_ventilo_boost_on_off = false;
break;
// ventilo -> mode Nuit [VITESSE FIXE] AVOIR BRUIT
case nuit:
//if (Vit_nuit != 0 && SondeTempC[3] != -127 && SondeTempC[3] != -85) { // si vitesse differente de 0 ET sonde exterieur OK
// vitesseDynamique = vitesseDyn(seuilVitesseB, seuilVitesseI, seuilVitesseMa, VitesseVentil[Vit_nuit], seuilTempB, seuilTempI, seuilTempMi, SondeTempC[3]); // SondeTempC[3] -> Sonde Exterieure
// pwm = VitesseVentil[Vit_nuit] + vitesseDynamique; // VITESSE dynamique en fonction Temperature exterieure
// Flag_vitesseDynamique_ON = true;
//}
//else {
pwm = VitesseVentil[Vit_nuit]; // Tableau des vitesses Nuit (Heure -> 24:00)
//vitesseDynamique = 0;
Flag_vitesseDynamique_ON = false;
//}
etatVentilo = "Nuit"; // 4 caracteres
//flag_ventilo_manu_on_off = false;
//flag_ventilo_boost_on_off = false;
break;
// ventilo -> mode Jour [VITESSE DYNAMIQUE]
case jour:
if (Vit_jour != 0 && SondeTempC[3] != -127 && SondeTempC[3] != -85) { // si vitesse differente de 0 ET sonde exterieur OK
vitesseDynamique = vitesseDyn(seuilVitesseB, seuilVitesseI, seuilVitesseMa, VitesseVentil[Vit_jour], seuilTempB, seuilTempI, seuilTempMi, SondeTempC[3]); // SondeTempC[3] -> Sonde Exterieure
pwm = VitesseVentil[Vit_jour] + vitesseDynamique; // VITESSE dynamique en fonction Temperature exterieure
Flag_vitesseDynamique_ON = true;
etatVentilo = "JourDy"; // 6 caracteres [Mode vitesse Dynamique]
}
else {
pwm = VitesseVentil[Vit_jour]; // Tableau des vitesses Jour (Heure -> 07:45)
//vitesseDynamique = 0;
Flag_vitesseDynamique_ON = false;
etatVentilo = "JourFi"; // 6 caracteres [Mode vitesse Fixe]
}
//etatVentilo = "Jour"; // 4 caracteres
//flag_ventilo_manu_on_off = false;
//flag_ventilo_boost_on_off = false;
break;
// ventilo -> mode Boost
case boost:
pwm = VitesseVentil[Vit_boost]; // Tableau des vitesses Boost (Temps enmode Boost -> 2:00 heures)
Flag_vitesseDynamique_ON = false;
etatVentilo = "Boost"; // 5 caracteres
//flag_ventilo_manu_on_off = false;
break;
// ventilo -> mode Manu
case manu:
Flag_vitesseDynamique_ON = false;
etatVentilo = "Manuel"; // 6 caracteres
//pwm = VitesseVentil[6]; // Tableau des vitesses selection dans RPM Ventilateur
//flag_ventilo_boost_on_off = false;
break;
}
if (pwm != prevpwm || correctionPwm != prevCorrectionPwm) {
ledcWrite(pwmChannel, pwm + correctionPwm); // Nouvelle vitesse en PWM passé au ventilateur
/*
if (prevvitesseDynamique != vitesseDynamique) { // Notification websocket
prevvitesseDynamique = vitesseDynamique;
notifyClients((char*)"wsVitDyn");
}
*/
if (serialDebug) {
Serial.print("Old PWM -> ");
Serial.print(prevpwm);
Serial.print(" ,Old Correction -> ");
Serial.print(prevCorrectionPwm);
Serial.print(" ,New PWM -> ");
Serial.print(pwm);
Serial.print(" ,New Correction -> ");
Serial.println(correctionPwm);
}
prevpwm = pwm;
prevCorrectionPwm = correctionPwm;
}
}
// *************************
// *** FIN VENTILATEUR ***
// *************************
// ********************
// *** DEBUT IRIS ***
// ********************
// Deplacement moteur à une position entre HOME et MAXTRAVEL
void moteurDeplacementVers(int16_t deplacement) { // (int16_t) -32768 to 32767
if (flag_initIris == true && flag_auth_deplacement == true) {
if (old_deplacement != deplacement) { // old_deplacement (int16_t) -32768 to 32767 // Si la position est differente de la position actuelle
if (serialDebug_IRIS) Serial.println("NEW DEPLACEMENT"); // AVOIR NEW
old_deplacement = deplacement;
stepper.moveTo(deplacement); // instruction deplacement vers target
// Marge Flottante
if (stepper.distanceToGo() > 0) { // Si distanceToGo() positif sens horraire(+1), si distanceToGo() negatif sens anti-horraire(-1)
sensRotation = 1; // sens horraire
}
else {
sensRotation = -1; // sens anti-horraire
}
if (sensRotation != prevSensRotation) { // si sens de rotation different du precedent
prevSensRotation = sensRotation;
flag_sens_rotation_diff = true;
oldStepperPosition = stepper.currentPosition(); // enregistre la position actuelle
// 6846 - -1 * 750
stepper.setCurrentPosition(oldStepperPosition - (sensRotation * MARGE_FLOTTANTE)); // Remplace la position courante en ajoutant (sens anti-horraire -- ) / soustraillant (sens horraire ++ ) la MARGE_FLOTTANTE
stepper.moveTo(deplacement); // Il faut de nouveau indiquer le deplacement
if (serialDebug_IRIS) {
if (sensRotation == 1) {
Serial.println("IRIS sens Rotation Different ++ MARGE_FLOTTANTE");
}
else {
Serial.println("IRIS sens Rotation Different -- MARGE_FLOTTANTE");
}
Serial.print("Old stepper.currentPosition() : ");
Serial.print(oldStepperPosition);
Serial.print(", New stepper.currentPosition() : ");
Serial.print(stepper.currentPosition()); // sensRotation = 1 (horraire) ou sensRotation = -1 (anti-horraire)
Serial.print(", stepper.distanceToGo() : ");
Serial.println(stepper.distanceToGo());
} // Fin serialDebug
}
// Fin Marge Flottante
stepper.enableOutputs(); // Activation des PIN du moteur
//if (serialDebug_IRIS) Serial.println("Activation PIN Moteur OK");
}
else { // RUN MOTEUR ********************
stepper.run(); // MUST be called in loop() function (DEPLACE LE MOTEUR D' 1 STEP)
// Marge Flottante IRIS
if (((sensRotation == 1 && oldStepperPosition >= stepper.currentPosition()) || (sensRotation == -1 && oldStepperPosition <= stepper.currentPosition())) && flag_sens_rotation_diff == true) { // pour le sens inverse
Steppercurrent = oldStepperPosition;
}
else { // si on va dans le meme sens ou que la Marge Flottante est deja faite dans le sens inverse
flag_sens_rotation_diff = false;
Steppercurrent = stepper.currentPosition();
}
// Fin Marge Flottante
// Verif FIN de course HOME et MAXTRAVEL
moteurVerifLimitSwitchDeplacement();
if (stepper.isRunning() == false) { // Fini le deplacement
// Gestion Flag fin de boucle + Desactivation Pin Moteur
FlagmoteurDeplacement();
if (serialDebug_IRIS) Serial.println("DISABLE OUTPUT et FLAG AUTH DEPLACEMENT"); // AVOIR NEW
}
}
}
}
// Gestion Flag fin de deplacement
void FlagmoteurDeplacement() {
if (flag_PID_ON_OFF_IRIS == true) { // Flag verouillage PID jusqu'a fin deplacement stepper
flag_PID_ON_OFF_IRIS = false; // Reset FLAG
myPID.SetMode(AUTOMATIC); // Passage PID auto, si deja auto avant deplacement
}
stepper.disableOutputs(); // Desactivation des PIN du moteur
if (flag_limite_maxtravel_depacement == true) {
// AVOIR Ajout test si toujours en butée MAXTRAVEL
flag_limite_maxtravel_depacement = false;
}
if (flag_limite_home_depacement == true) {
// AVOIR Ajout test si toujours en butée HOME
flag_limite_home_depacement = false;
}
flag_auth_deplacement = false;
notifyClients((char*)"wsSteppercurrent");
}
// Verif FIN de course HOME et MAXTRAVEL
void moteurVerifLimitSwitchDeplacement() {
// Si MAXTRAVEL interupt HIGH (sens horraire +1)
//if (LSW_MAXTRAVEL_state == HIGH && digitalRead(LSW_MAXTRAVEL) == HIGH && LSW_HOME_state == LOW) { // FIN course MAXTRAVEL (LIMIT SWITCH) BUG parasite reseau electrique ajout LSW_HOME_state == LOW
if (digitalRead(LSW_MAXTRAVEL) == HIGH && stepper.distanceToGo() > 0 && digitalRead(LSW_HOME) == LOW) {
if (flag_limite_maxtravel_depacement == false) {
if (serialDebug_IRIS) Serial.println("LIMIT MAXTRAVEL ATTEINTE");
flag_limite_maxtravel_depacement = true;
int16_t temp_maxtravel = stepper.currentPosition(); // on recupere la position actuelle pour le pourcentage d'erreur
sensRotation = -1; // sens anti-horraire -> RETOUR vers HOME
prevSensRotation = sensRotation;
flag_sens_rotation_diff = true;
oldStepperPosition = maxtravel;
stepper.setCurrentPosition(maxtravel + INIT_MARGE + MARGE_FLOTTANTE); // on fixe la position courante de MAXTRAVEL + INIT_MARGE AVOIR (+ MARGE_FLOTTANTE)
old_deplacement = maxtravel; // force l'ancienne valeur a maxtravel pour determiner si nouveau deplacement AVOIR NEW
stepper.moveTo(maxtravel); // Retour a MAXTRAVEL
// RE-INIT MAXTRAVEL
if (flag_iris_manu_on_off == true) { // Si mode Manu, Init Position encodeur a la position moteur MAXTRAVEL (AFFICHAGE Normalement)
TempPosIris = maxtravel;
}
else {
if (OutputPID != maxtravel) {
if (myPID.GetMode() == AUTOMATIC) { // si PID mode AUTOMATIC on le passe a OFF -> mode MANUAL
myPID.SetMode(MANUAL);
flag_PID_ON_OFF_IRIS = true; // Flag verouillage PID jusqu'a fin deplacement stepper
}
OutputPID = maxtravel; // Init OutputPID a la position moteur MAXTRAVEL
//myPID.SetMode(AUTOMATIC); // ACTIVATION PID Deplacé dans FlagmoteurDeplacement() // FLAG flag_PID_ON_OFF_IRIS = TRUE (Apres fin deplacement stepper)
}
}
if (serialDebug_IRIS) {
Serial.println("LIMIT MAXTRAVEL ATTEINTE");
float pourcent = (float)temp_maxtravel * 100 / maxtravel; // pourcentage d'erreur
//Serial.print("Current Position : ");
//Serial.print(stepper.currentPosition());
//Serial.print(" ,maxtravel : ");
//Serial.print(maxtravel);
//Serial.print(" ,home : ");
//Serial.println(home);
if (pourcent > (100 - POURC_ERR_IRIS)) { // si marge sup 95% -> Erreur inferieur a 5% donc OK
Serial.print("INIT IRIS MAXTRAVEL Erreur inf 5% : ");
Serial.print(100 - pourcent,1);
Serial.println(" % OK");
}
else {
Serial.print("PROBLEME IRIS MAXTRAVEL Erreur sup 5% : ");
Serial.print(100 - pourcent,1);
Serial.println(" %");
}
} // Fin SerialDebug
}
} // Fin MAXTRAVEL limit switch
// Si HOME interupt HIGH (sens anti-horraire -1)
//if (LSW_HOME_state == HIGH && digitalRead(LSW_HOME) == HIGH && LSW_MAXTRAVEL_state == LOW) { // FIN course HOME (LIMIT SWITCH) BUG parasite reseau electrique ajout LSW_MAXTRAVEL_state == LOW
if (digitalRead(LSW_HOME) == HIGH && stepper.distanceToGo() < 0 && digitalRead(LSW_MAXTRAVEL) == LOW) {
if (flag_limite_home_depacement == false) {
if (serialDebug_IRIS) Serial.println("LIMIT HOME ATTEINTE");
flag_limite_home_depacement = true;
int16_t temp_home = stepper.currentPosition(); // on recupere la position actuelle pour le pourcentage d'erreur
sensRotation = 1; // sens horraire -> RETOUR vers MAXTRAVEL
prevSensRotation = sensRotation;
flag_sens_rotation_diff = true;
oldStepperPosition = home;
stepper.setCurrentPosition(home - INIT_MARGE - MARGE_FLOTTANTE); // on fixe la position courante de HOME - INIT_MARGE AVOIR (- MARGE_FLOTTANTE)
old_deplacement = home; // force l'ancienne valeur a home pour determiner si nouveau deplacement AVOIR NEW
stepper.moveTo(home); // Retour a HOME
// RE-INIT HOME
if (flag_iris_manu_on_off == true) { // Si mode Manu, Init Position encodeur a la position moteur HOME (AFFICHAGE Normalement)
TempPosIris = home;
}
else {
if (OutputPID != home) {
if (myPID.GetMode() == AUTOMATIC) { // si PID mode AUTOMATIC on le passe a OFF -> mode MANUAL
myPID.SetMode(MANUAL);
flag_PID_ON_OFF_IRIS = true; // Flag verouillage PID jusqu'a fin deplacement stepper
}
OutputPID = home; // Init OutputPID a la position moteur HOME
//myPID.SetMode(AUTOMATIC); // ACTIVATION PID Deplacé dans FlagmoteurDeplacement() // FLAG flag_PID_ON_OFF_IRIS = TRUE (Apres fin deplacement stepper)
}
}
if (serialDebug_IRIS) {
Serial.println("LIMIT HOME ATTEINTE");
float pourcent = (float)temp_home * 100 / maxtravel; // pourcentage d'erreur
//Serial.print("Current Position : ");
//Serial.print(stepper.currentPosition());
//Serial.print(" ,maxtravel : ");
//Serial.print(maxtravel);
//Serial.print(" ,home : ");
//Serial.println(home);
if (pourcent < POURC_ERR_IRIS) { // si marge inf 5% -> Erreur inferieur a 5% donc OK
Serial.print("INIT IRIS HOME Erreur inf 5% : ");
Serial.print(pourcent,1);
Serial.println(" % OK");
}
else {
Serial.print("PROBLEME IRIS HOME Erreur sup 5% : ");
Serial.print(pourcent,1);
Serial.println(" %");
}
} // Fin SerialDebug
}
} // Fin HOME limit switch
}
// IRIS : verifie que la division par 2 donne Zero (Halfstep) et qu'on n'est pas superieur (home et maxtravel)
int16_t verifStepIris(int16_t desiredPosition) {
while (desiredPosition % 2 != 0) { // verifie que la division par 2 donne Zero (Halfstep)
desiredPosition++;
}
if (desiredPosition > maxtravel) { // si PosIris trop grand on force maxtravel
desiredPosition = maxtravel;
}
if (desiredPosition < home) { // si PosIris trop petit on force home
desiredPosition = home;
}
return desiredPosition;
}
//Correction position IRIS map fonctionne pas
long map2(long x, long in_min, long in_max, long out_min, long out_max) {
return round(((x - in_min) * (out_max - out_min)) / (float)(in_max - in_min) + out_min);
}
// ******************
// *** FIN IRIS ***
// ******************
// *********************************************
// *** DEBUT GESTION VENTILATEUR ET PID IRIS ***
// *********************************************
// Permet de passer la vitesse du ventillateur entre le mode jour et le mode nuit
void mode_journuit() {
time_t now = time(nullptr);
struct tm * timeinfo;
timeinfo = localtime(&now);
long daysec = HMS(timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
//if (serialDebug) {Serial.print("Heure :");Serial.print(timeinfo->tm_hour);Serial.print(":");Serial.print(timeinfo->tm_min);Serial.print(",");Serial.println(timeinfo->tm_sec);}
long jourdeb = 0;
long jourfin = 0;
//if (serialDebug) {Serial.println("(START_MODE_NUIT <= START_MODE_JOUR)");Serial.print("(");Serial.print(START_MODE_NUIT);Serial.print(" < ");Serial.print(START_MODE_JOUR);Serial.println(")");}
// Gestion J+1 si (START_MODE_NUIT = START_MODE_JOUR) -> Tout le temps en mode Jour
if (START_MODE_NUIT <= START_MODE_JOUR) {
if (daysec <= START_MODE_NUIT) {
//if (serialDebug) {Serial.println("(daysec <= START_MODE_NUIT)");Serial.print("(");Serial.print(daysec);Serial.print(" <= ");Serial.print(START_MODE_NUIT);Serial.println(")");}
jourdeb = 86400L; // + 24H 24 x 60 x 60
}
if (daysec >= START_MODE_JOUR) {
//if (serialDebug) {Serial.println("(daysec >= START_MODE_JOUR)");Serial.print("(");Serial.print(daysec);Serial.print(" >= ");Serial.print(START_MODE_JOUR);Serial.println(")");}
jourfin = 86400L; // + 24H
}
}
//if (serialDebug) {Serial.print("jourdeb : ");Serial.print(jourdeb);Serial.print(", jourfin : ");Serial.println(jourfin);Serial.println("((daysec + jourdeb) >= START_MODE_JOUR && daysec < (START_MODE_NUIT + jourfin))");Serial.print("((");Serial.print(daysec);Serial.print(" + ");Serial.print(jourdeb);Serial.print(") >= ");Serial.print(START_MODE_JOUR);Serial.print(" && ");Serial.print(daysec);Serial.print(" < (");Serial.print(START_MODE_NUIT);Serial.print(" + ");Serial.print(jourfin);Serial.println("))");}
if ((daysec + jourdeb) >= START_MODE_JOUR && daysec < (START_MODE_NUIT + jourfin)) { // gestion mode Jour / Nuit (avec J+1)
if (serialDebug) {
Serial.print("VENTILATEUR : Mode Jour ON ,Heure : ");
Serial.print(timeinfo->tm_hour);
Serial.print(":");
Serial.print(timeinfo->tm_min);
Serial.print(",");
Serial.println(timeinfo->tm_sec);
}
modeVentilo = jour;
}
else {
if (serialDebug) {
Serial.print("VENTILATEUR : Mode Nuit ON ,Heure : ");
Serial.print(timeinfo->tm_hour);
Serial.print(":");
Serial.print(timeinfo->tm_min);
Serial.print(",");
Serial.println(timeinfo->tm_sec);
}
modeVentilo = nuit;
}
}
// Update Temperature de consigne Sonde moteur
void UpdateSetpointPID() {
// Temperature de consigne Sonde moteur
SetpointPID = ConsignePID * coef_temp; //Refresh SetpointPID affichage AccueilMenu
// Limite la temperature max de consigne a la temperature de coupure moteur -1.5 °C
if (SetpointPID >= ((Temp_OFF_moteur * coef_temp) - 1.5f) || flag_ventilo_boost_on_off == true) {
SetpointPID = (Temp_OFF_moteur * coef_temp) - 1.5f;
}
// Pour interface web client websocket refresh valeur SetpointPID
if (OldSetpointPID != SetpointPID) {
OldSetpointPID = SetpointPID;
notifyClients((char*)"wsSetpointPID");
}
}
// Update OutputPID avec position IRIS et Maxi Mini // dit au PID ou est l'IRIS
void UpdateOutputPID() {
//if (stepper.currentPosition() >= maxtravel) {
if (Steppercurrent >= maxtravel) {
OutputPID = maxtravel;
}
//else if (stepper.currentPosition() <= home) {
else if (Steppercurrent <= home) {
OutputPID = home;
}
else {
//OutputPID = stepper.currentPosition(); // dit au PID ou est l'IRIS
OutputPID = Steppercurrent; // dit au PID ou est l'IRIS
}
}
// Vitesse dynamique du ventilateur V4
int16_t vitesseDyn(int16_t seuilVitesseB, int16_t seuilVitesseI, int16_t seuilVitesseMa, int16_t seuilVitesseActu, float seuilTempB, float seuilTempI, float seuilTempMi, float sondeExt) {
int16_t deltaVitesseB = seuilVitesseI - seuilVitesseB; // 111 incrementations -> 200 tr/min
float deltaTempB = seuilTempB - seuilTempI; // -> 12 °C
int16_t deltaVitesseI = seuilVitesseMa - seuilVitesseI; // 57 incrementations -> 100 tr/min
float deltaTempI = seuilTempI - seuilTempMi; // -> 12 °C
int16_t VF = 0;
if (seuilVitesseActu == 0) { // si vitesse actuelle est egale a 0 on sort
return 0;
}
else {
if (sondeExt < seuilTempB && sondeExt >= seuilTempI) { // si temperature entre 12°C et 0°C (precision 12/111 -> 0,11°C)
VF = vitesseFlottante(deltaVitesseB, deltaTempB, seuilTempB, sondeExt);
if (seuilVitesseActu >= seuilVitesseI || seuilVitesseActu >= VF + seuilVitesseB) { // si la vitesse actuelle est deja au dessus on retourne 0
return 0;
}
else {
return VF + seuilVitesseB - seuilVitesseActu;
}
}
else if (sondeExt < seuilTempI) { // si temperature en dessous de 0 vers -12 ... -20 - etc (precision 12/57 -> 0,21°C)
VF = vitesseFlottante(deltaVitesseI, deltaTempI, seuilTempI, sondeExt);
if (seuilVitesseActu >= seuilVitesseMa || seuilVitesseActu >= VF + seuilVitesseI) { // si la vitesse actuelle est deja au dessus on retourne 0
return 0;
}
else {
return VF + seuilVitesseI - seuilVitesseActu;
}
}
else { // si temperature superieure a 12°C
return 0;
}
}
}
// Pente de la courbe du ventilo, retourne la vitesse flottante
int16_t vitesseFlottante(int16_t deltaVitesse, float deltaTemp, float seuilTempBase, float sondeExt) {
float coefPente = (float)(deltaVitesse / deltaTemp); // -> (111/12 -> 9.25), (57/12 -> 4.75)
int16_t vitesseFlo = round((float)(coefPente * (seuilTempBase - sondeExt)));
if (vitesseFlo >= deltaVitesse ) {
vitesseFlo = deltaVitesse;
}
if (vitesseFlo <= 0 ) {
vitesseFlo = 0;
}
return vitesseFlo;
}
// Recherche vitesse actuelle dans Tableau Mode dynamique
int8_t RechercheNumVitesseDyn() {
if (pwm <= VitesseVentil[0]) {
return 0;
}
else if (pwm >= VitesseVentil[Nbrevitesse-1]) {
return Nbrevitesse-1;
}
else {
for (uint8_t i = 0; i < Nbrevitesse-1; i++) {
if (VitesseVentil[i] <= pwm && VitesseVentil[i+1] > pwm ) {
if (VitesseVentil[i] == pwm) {
return i;
}
else {
if (pwm - VitesseVentil[i] >= VitesseVentil[i+1] -pwm) {
//Serial.print("pwm = max- : ");
//Serial.println(VitesseVentil[i+1]);
return i+1;
}
else {
//Serial.print("pwm = min+ : ");
//Serial.println(VitesseVentil[i]);
return i;
}
}
} // Fin If
} // Fin For
}
return 0; // AVOIR BUG Warning compilateur
}
// Permet de convertir les PWM en tr/min (Vitesse dynamique CourbeVentilation())
int16_t pwmTotrmin(int16_t pwm) {
if (pwm < VitesseVentil[1]) {
return 0;
}
else if (pwm >= VitesseVentil[1] && pwm < VitesseVentil[2]) {
return round( 1.7857f * pwm - 548.21f ); // (900-1000 tr/min)
}
else if (pwm >= VitesseVentil[2] && pwm < VitesseVentil[3]) {
return round( 1.6129f * pwm - 398.39f ); // (1000-1100 tr/min)
}
else if (pwm >= VitesseVentil[3] && pwm < VitesseVentil[5]) {
return round( 1.7241f * pwm - 501.72f ); // (1100-1300 tr/min)
}
else if (pwm >= VitesseVentil[5] && pwm < VitesseVentil[6]) {
return round( 1.6666f * pwm - 441.67f ); // (1300-1350 tr/min)
}
else if (pwm >= VitesseVentil[6] && pwm < VitesseVentil[14]) {
return round( 1.7857f * pwm - 569.64f ); // (1350-1750 tr/min)
}
else if (pwm >= VitesseVentil[14] && pwm < VitesseVentil[15]) {
return round( 1.5625f * pwm - 279.69f ); // (1750-1800 tr/min)
}
else if (pwm >= VitesseVentil[15] && pwm < VitesseVentil[16]) {
return round( 1.7241f * pwm - 494.83f ); // (1800-1850 tr/min)
}
else if (pwm >= VitesseVentil[16] && pwm < VitesseVentil[17]) {
return 2 * pwm - 870; // (1850-1900 tr/min)
}
else if (pwm >= VitesseVentil[17] && pwm < VitesseVentil[18]) {
return round( 1.6129f * pwm - 333.87f ); // (1900-1950 tr/min)
}
else if (pwm >= VitesseVentil[18] && pwm <= VitesseVentil[19]) {
return round( 1.9231f * pwm - 773.08f ); // (1950-2000 tr/min)
}
return 0; // AVOIR si supperieur vitesse 19
}
// Fonction pour trouver l'offset en fonction de la dif vitesse courante ET [vitesse inf OU vitesse sup]
int8_t offsetNormalisation(int8_t Vit_courante, int8_t Vit_offset) {
if (Vit_offset == 0) {
return 0;
}
else if (Vit_offset > 0) {
return round(( VitesseVentil[Vit_courante + 1] - VitesseVentil[Vit_courante] ) * Vit_offset / 100.0);
}
else {
return round(( VitesseVentil[Vit_courante] - VitesseVentil[Vit_courante -1] ) * Vit_offset / 100.0);
}
}
//Fonction Courbe Ventilation coordonnée point X (Vitesse dynamique CourbeVentilation())
uint8_t Xval(float inValTemp) {
//( (seuilTempB +1 - (seuilTempMi -1)) - (valeur - (seuilTempMi -1)) ) * ((127-25-8) / (seuilTempB +1 -(seuilTempMi -1)) )
float plageTemp = (seuilTempB - seuilTempMi); // + 2 * marge; //-> 26
uint8_t plageX = (127-33); //-> 94 //uint8_t (0 a 255) int8_t (-127 a +127)
return round( (plageTemp - (inValTemp - seuilTempMi)) * (plageX / plageTemp) );
}
//Fonction Courbe Ventilation coordonnée point Y (Vitesse dynamique CourbeVentilation())
uint8_t Yval(int16_t inValPwm) {
uint8_t plageY = (63-10); //-> 53
return round( plageY - ( ((inValPwm - seuilVitesseB) * plageY) / (seuilVitesseMa - seuilVitesseB)) ) ;
}
// Gestion PID et Ventilateur
void gestionVentiloEtPid() {
// Debut VENTILATEUR ON (Choix par le MENU) Si temperature OK
// Sonde Chaud >= Temp Hotte mini && Sonde Moteur < Temp Moteur Maxi && Sonde Moteur OK && Flag Moteur ON si TRUE (OFF si FALSE)
if (SondeTempC[1] >= ((Temp_ON_moteur + Hyst_moteur) * coef_temp) && SondeTempC[0] < (Temp_OFF_moteur * coef_temp) && SondeTempC[0] != -127 && SondeTempC[0] != -85 && flag_ventilo_on_off == true) {
Hyst_moteur = 0; // Reset Hyst_moteur apres le 1er demarrage
// Gestion VENTILATEUR
// Si Flag Mode Boost -> ON si TRUE
if (flag_ventilo_boost_on_off == true && flag_ventilo_manu_on_off == false) {
modeVentilo = boost;
if (serialDebug) Serial.println("VENTILATEUR : Mode Boost ON");
}
// Si Flag Mode Ven Auto / Manu -> ON si TRUE (Mode Manu)
else if (flag_ventilo_manu_on_off == true && flag_ventilo_boost_on_off == false) {
modeVentilo = manu;
if (serialDebug) Serial.println("VENTILATEUR : Mode Manu ON");
}
// Mode Auto en Jour / Nuit
else {
if (flag_ventilo_manu_on_off == true) {
flag_ventilo_manu_on_off = false;
//Envoie la valeur de VENTILO manu/auto -> WEBSOCKET (flag_ventilo_manu_on_off) //AVOIR WEBSOCKET NEW
notifyClients((char*)"wsVmanuauto");
}
if (flag_ventilo_boost_on_off == true) {
flag_ventilo_boost_on_off = false;
notifyClients((char*)"wsVboost"); // AVOIR
}
mode_journuit(); // change le mode du ventilo entre jour et nuit
if (serialDebug) Serial.println("VENTILATEUR : Mode Auto ON");
}
// Fin Gestion VENTILATEUR
// Gestion PID IRIS : Mode Auto (False) / Manu (True)
// Debut IRIS Mode AUTO (FALSE) MENU && FlagErrorMoteur_RPM -> FALSE (Ventilo ok pas d'erreur)
if (flag_iris_manu_on_off == false && FlagErrorMoteur_RPM == false) { // AVOIR
// Une fois toutes les 4 sondes lu on traite le PID (1)
if (flag_auth_traitmnt_Temp == true) { // NEW AVOIR SONDE
// DEMARRAGE regulation PID IRIS : Consigne Temperature mini Smoteur
ConsignePID_demarrage = ConsignePID_coupure + 50; // 370 + 50 -> 420 --> 42°C
if (ConsignePID_demarrage > ConsignePID) { // 370 + 50 -> 420°C [ donc ici, si 420 > 500, donc consigne 420 --> 42°C ok sinon consigne 500 --> 50°C] // Pour eviter le yoyo (stop / start en boucle)
ConsignePID_demarrage = ConsignePID; // 500 --> 50°C
}
// DEMARRAGE regulation PID IRIS : Init Temperature mini Smoteur
if (SondeTempC[0] >= (ConsignePID_demarrage * coef_temp) && Flag_init_PID_temp_mini_moteur == false) { // Si Temp Sonde Moteur sup à Setpoint - 5°C AVOIR
Flag_init_PID_temp_mini_moteur = true;
}
// ARRET regulation PID IRIS : Init Temperature (insuffisante) arret Smoteur ET ARRET du VENTILATEUR // BUG NE S'ARRETE PAS SI TEMPERATURE SONDE CHAUD TOUJOURS SUPPERIEUR A 40°C // AVOIR AVOIR AVOIR
//if (SondeTempC[0] < (ConsignePID_coupure * coef_temp) && Flag_init_PID_temp_mini_moteur == true && stepper.currentPosition() >= maxtravel && myPID.GetMode() == AUTOMATIC) { // Si Temp Sonde Moteur inf à ConsignePID_coupure (37°C) BUG arret / demarrage
if (SondeTempC[0] < (ConsignePID_coupure * coef_temp) && Flag_init_PID_temp_mini_moteur == true && Steppercurrent >= maxtravel && myPID.GetMode() == AUTOMATIC) { // Si Temp Sonde Moteur inf à ConsignePID_coupure (37°C) BUG arret / demarrage
if (flag_ventilo_boost_on_off == true) { // Si en Mode Boost
flag_ventilo_boost_on_off = false; // On coupe le mode Boost
notifyClients((char*)"wsVboost");
//UpdateSetpointPID(); // AVOIR BoostPID // reset BOOST temperature PID (SetpointPID) // AVOIR MODIF SetpointPID PAS BESOIN
timermodeventiloarret = millis(); // on enregistre le temps a l'arret du mode BOOST
}
else {
if ((millis() - timermodeventiloarret) >= 60000L) { // Delais de 60 secondes avant arret recuperateur chaleur si mode BOOST été activé
modeVentilo = off_ventilo; // Passage du VENTILATEUR a OFF (Gestion PWM)
myPID.SetMode(MANUAL); // on desactive le PID -> passage en mode MANUAL (OFF)
Flag_init_PID_temp_mini_moteur = false; // reset FLAG init temp mini sonde moteur
Hyst_moteur = Hyst_Temp_ON_moteur; // reset Hysteresis
// on reinitialise la position de l'IRIS a maxtravel [TEMP SONDE MOTEUR INSUFISANTE]
/*
//if (stepper.currentPosition() < maxtravel) { // AVOIR NEW --> Normalement on ne va jamais dans cette boucle donc en commentaire
if (Steppercurrent < maxtravel) { // AVOIR NEW --> Normalement on ne va jamais dans cette boucle donc en commentaire
OutputPID = maxtravel; // Position Initiale de l'IRIS Demarrage
PosIris = maxtravel;
flag_auth_deplacement = true;
}
*/
if (serialDebug) Serial.println("VENTILATEUR : Mode OFF (Temperature insuffisante)"); // Temperature Smoteur insuffisante
} // Fin Timer
}
} // Fin ARRET Regul
// Passage PID Mode automatique
if (myPID.GetMode() == MANUAL && Flag_init_PID_temp_mini_moteur == true) { // si PID mode MANUAL on le passe a ON -> mode AUTOMATIC
// AVOIR NEW BUG IRIS
UpdateOutputPID(); // dit au PID ou est l'IRIS avant de passer en mode AUTOMATIC
// FIN AVOIR NEW BUG IRIS
myPID.SetMode(AUTOMATIC);
}
// Debut PID en mode AUTOMATIC
if (myPID.GetMode() == AUTOMATIC) {
InputPID = SondeTempC[0]; // sonde temperature moteur (SondeTempC[0]) , sonde froid (SondeTempC[2])
// Temperature de consigne Sonde moteur
UpdateSetpointPID();
// Debut gestion Tuning PID si mode AUTOMATIC
//float gap = abs(SetpointPID - InputPID); //distance away from SetpointPID
float gap = SetpointPID - InputPID; //distance away from SetpointPID
if (gap >= 0) { // Temperature inferieure a la Consigne
if (gap < 0.5) // delta 0.5 -1 -> 0.5°C (Si inf a 0.5°C)
{ //we're close to SetpointPID, use conservative tuning parameters
myPID.SetTunings(intKp, intKi, intKd);
PidMod = "int"; // 3 caracteres
}
else if (gap >= 0.5 && gap < 1) // delta 0.5 -1 -> 0.5°C (Si inf a 1°C)
{ //we're middle far from SetpointPID, use intermediaire tuning parameters
myPID.SetTunings(aggKp, aggKi, aggKd);
PidMod = "agg"; // 3 caracteres
}
else // (Si sup a 1°C)
{ //we're far far from SetpointPID, use ultra-aggressive tuning parameters
myPID.SetTunings(ultKp, ultKi, ultKd);
PidMod = "ult"; // 3 caracteres
}
}
else { // (gap < 0) // Temperature superieure a la Consigne (PID PLUS AGGRESSIF)
if (gap > -0.5 ) // delta 0 -0.5 -> .5°C (Si inf a 0.5°C)
{ //we're far from SetpointPID, use aggressive tuning parameters
myPID.SetTunings(aggKp, aggKi, aggKd);
PidMod = "agg"; // 3 caracteres
}
else // (Si sup a 0.5°C)
{ //we're far far from SetpointPID, use ultra-aggressive tuning parameters
myPID.SetTunings(ultKp, ultKi, ultKd);
PidMod = "ult"; // 3 caracteres
}
}
// Fin gestion Tuning PID si mode AUTOMATIC
} // Fin PID en mode AUTOMATIC
} // Fin flag_auth_traitmnt_Temp == true PID (1) // NEW AVOIR SONDE
} // Fin IRIS Mode AUTO (FALSE) MENU
// Debut IRIS Mode MANU(TRUE)
else {
// Debut Gestion PID IRIS
if (myPID.GetMode() == AUTOMATIC) { // si PID mode AUTOMATIC (ON), on desactive le PID -> passage en mode MANUAL (OFF)
myPID.SetMode(MANUAL);
}
Flag_init_PID_temp_mini_moteur = false; // reset FLAG init temp mini sonde moteur
// Fin Gestion PID IRIS
} // Fin IRIS Mode MANU(TRUE)
} // Fin VENTILATEUR ON (Choix par le MENU) Si temperature OK
// Debut VENTILATEUR OFF (Choix par le MENU)
else {
modeVentilo = off_ventilo; // Passage du VENTILATEUR a OFF (Gestion PWM)
// Gestion PID IRIS
if (flag_iris_manu_on_off == false) { // IRIS Mode AUTO (FALSE) MENU
if (myPID.GetMode() == AUTOMATIC) { // si PID mode AUTOMATIC (ON), on desactive le PID -> passage en mode MANUAL (OFF)
myPID.SetMode(MANUAL);
if (SondeTempC[0] >= (Temp_OFF_moteur * coef_temp) - 1.0f) { // Si Temp Moteur trop chaud (Temp max moteur -1°C)
//if (stepper.currentPosition() > home) { // AVOIR NEW
if (Steppercurrent > home) { // AVOIR NEW
OutputPID = home; // Position de l'IRIS sur home si surchauffe
PosIris = home;
flag_auth_deplacement = true;
}
}
else {
//if (stepper.currentPosition() < maxtravel) { // AVOIR NEW
if (Steppercurrent < maxtravel) { // AVOIR NEW
OutputPID = maxtravel; // Position Initiale de l'IRIS (reinitialise la position de l'IRIS a maxtravel) AVOIR BUG OU PAS
PosIris = maxtravel;
flag_auth_deplacement = true;
}
}
}
}
Flag_init_PID_temp_mini_moteur = false; // reset FLAG init temp mini sonde moteur
// Fin Gestion PID IRIS
if (flag_ventilo_boost_on_off == true) {
flag_ventilo_boost_on_off = false; // On coupe le mode Boost
notifyClients((char*)"wsVboost");
UpdateSetpointPID(); // AVOIR BoostPID // // reset BOOST temperature PID (SetpointPID)
}
Hyst_moteur = Hyst_Temp_ON_moteur; // reset Hysteresis
if (serialDebug) Serial.println("VENTILATEUR : Mode OFF (Choix MENU)");
} // Fin VENTILATEUR OFF (Choix par le MENU)
flag_auth_traitmnt_Temp = false; // Reset Flag authorisation traitement valeur sonde de Temperature // NEW AVOIR SONDE
} // FIN Gestion PID et Ventilateur
// *******************************************
// *** FIN GESTION VENTILATEUR ET PID IRIS ***
// *******************************************
// ******************
// *** DEBUT WIFI ***
// ******************
//Init Wifi:
void InitWifi() {
pref.begin("WifiCred", RO_MODE); // open (or create) the namespace "WifiCred" en lecture
if (!pref.isKey("WFlag")) { // si WFlag existe (Flag Wifi) on charge la config // DEBUG WOKWI
ssidnew = "Wokwi-GUEST"; // DEBUG WOKWI
passnew = "";
InitWifi_STA(); // Demarre le WIFI en mode STATION
}
else {
InitWifi_AP(); // Demarre le WIFI en mode ACCESS POINT
if (serialDebug_Init) Serial.println("INIT WIFI : AP OK");
}
pref.end(); // Ferme preferences Read Write mode
CheckWifiStatus(); // Verif si wifi en mode AP ou en mode STA
}
// Save la config wifi en memoire
void SaveWifiCred() {
pref.begin("WifiCred", RW_MODE); // Ouvre le namespace "WifiCred" en ecriture
if (pref.isKey("WFlag")) { // si WFlag existe (Flag Wifi) on charge la config
if (ssidnew != pref.getString("ssid")) { // SSID
pref.putString("ssid", ssidnew);
}
if (passnew != pref.getString("pass")) { // Password Cle WIFI
pref.putString("pass", passnew);
}
}
else {
pref.putString("ssid", ssidnew); // SSID
pref.putString("pass", passnew); // Password Cle WIFI
pref.putBool("WFlag", true); // Si config ok on cree le Flag de la config WIFI
}
pref.end(); // Ferme preferences Read Write mode
}
//Statut du WIFI mode STA ou AP
void CheckWifiStatus() {
if (WiFi.getMode() == 1) { // WiFi.mode(WIFI_STA)
WifiStaMode = true;
}
else if (WiFi.getMode() == 2) { // WiFi.mode(WIFI_AP)
WifiStaMode = false;
}
}
//Verif Wifi Credential: AVOIR
bool VerifWifiCred() {
pref.begin("WifiCred", RO_MODE); // open (or create) the namespace "WifiCred" en lecture
if (pref.isKey("WFlag")) { // si WFlag existe (Flag Wifi) on verifie que le ssid et le pass sont differents
if (ssidnew != pref.getString("ssid") || passnew != pref.getString("pass")) {
return true;
}
else {
return false;
}
pref.end(); // Ferme preferences Read Write mode
}
else {
return true;
}
}
//Initialisation connection WIFI en mode STATION
void InitWifi_STA() {
// delete old config
WiFi.disconnect(true);
// BUG l'ESP32 Reboot
//WiFi.softAPdisconnect(false);
//while (WiFi.softAPgetStationNum() > 0) {
// if (serialDebug_wifi) {Serial.print("Nbre de station toujours connecté : ");Serial.println(WiFi.softAPgetStationNum());}
//}
WiFi.mode(WIFI_STA);
if (serialDebug_Init) Serial.printf("INIT WIFI : Connexion au SSID : %s \n", ssidnew.c_str());
WiFi.onEvent(WiFiStationConnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_CONNECTED); // Connecte au Wifi
WiFi.onEvent(WiFiGotIP, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP); // recu IP du Wifi
WiFi.onEvent(WiFiStationDisconnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED); // Deconnecte du Wifi
/* Remove WiFi event
Serial.print("WiFi Event ID: ");
Serial.println(eventID);
WiFi.removeEvent(eventID);*/
//WiFi.begin(ssid, password);
WiFi.begin(ssidnew.c_str(), passnew.c_str());
if (serialDebug_wifi) Serial.println("En attente du WiFi... ");
}
//Initialisation connection WIFI en mode ACCES POINT
void InitWifi_AP() {
// delete old config
//WiFi.disconnect(true); // Provoque les erreurs en dessous BUG
// E (61467) wifi:wifi deinit internal: wifi not stop
// E (61469) wifi_init: Failed to deinit Wi-Fi driver (0x3003)
WiFi.disconnect(false, true);
while (WiFi.isConnected()) {
if (serialDebug_wifi) {
Serial.print("Toujours connecté : ");
Serial.println(WiFi.isConnected());
}
}
WiFi.mode(WIFI_AP); // Mode AccessPoint
WiFi.softAP(SSID_AP, NULL); // Wifi sans Password
if (serialDebug_wifi) {
Serial.print("ESP32 AccessPoint SSID -> ");
Serial.println(WiFi.softAPSSID());
}
WiFi.softAPConfig(local_ip_ap, gateway_ap, subnet_ap);
if (serialDebug_wifi) {
Serial.print("Accessoint IP address: ");
Serial.println(WiFi.softAPIP());
}
}
// Connection au Wifi
void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info) {
if (serialDebug_wifi) Serial.println("Connected to AP successfully!");
}
// Verifie qu'on a bien une adresse IP (Wifi)
void WiFiGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
//ntpServer = WiFi.gatewayIP().toString();
ntpServer = "pool.ntp.org"; // DEBUG WOKWI
String IPaddr = WiFi.localIP().toString();
if (serialDebug_wifi) {
Serial.print("ntpServer -> ");
Serial.println(ntpServer);
}
/**
* A more convenient approach to handle TimeZones with daylightOffset
* would be to specify a environmnet variable with TimeZone definition including daylight adjustmnet rules.
* A list of rules for your zone could be obtained from https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h
*/
configTzTime(time_zone, ntpServer.c_str());
if (serialDebug_wifi) {
Serial.print("WiFi connected to : ");
Serial.print(WiFi.SSID());
Serial.print(" (");
Serial.print(WiFi.RSSI());
Serial.println(" dB)");
//Serial.print(" dB) [");
//byte encryption = WiFi.encryptionType();
//Serial.println(encryption,HEX);
//Serial.println("]");
Serial.print("IP address : ");
Serial.print(IPaddr);
Serial.print(", Gateway IP : ");
//Serial.println(WiFi.gatewayIP());
Serial.println(ntpServer);
}
if (serialDebug_Init) {
Serial.print("INIT WIFI : STA OK (IP : ");
Serial.print(IPaddr);
Serial.println(")");
}
}
// Reconnection apres perte de connection Wifi
void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
if (serialDebug_wifi) {
Serial.println("Disconnected from WiFi access point");
Serial.print("WiFi lost connection. Reason: ");
Serial.println(info.wifi_sta_disconnected.reason);
Serial.println("Trying to Reconnect");
}
//WiFi.begin(ssid, password);
WiFi.begin(ssidnew.c_str(), passnew.c_str());
}
// Etat du Wifi si deconnecte pour menu Satus WIFI
String EtatWifi() {
wl_status_t status = WiFi.status();
if (status == 0) {
return "IDLE_STATUS"; // WL_IDLE_STATUS = 0,
}
else if (status == 1) {
return "NO_SSID_AVAIL"; // WL_NO_SSID_AVAIL = 1,
}
else if (status == 2) {
return "SCAN_COMPLETED"; // WL_SCAN_COMPLETED = 2,
}
else if (status == 3) {
return "CONNECTED"; // WL_CONNECTED = 3,
}
else if (status == 4) {
return "CONNECT_FAILED"; // WL_CONNECT_FAILED = 4,
}
else if (status == 5) {
return "CONNECTION_LOST"; // WL_CONNECTION_LOST = 5,
}
/*
else if (status == 6) {
return "WRONG_PASSWORD"; // WL_WRONG_PASSWORD = 6,
}
*/
else if (status == 6) {
return "DISCONNECTED"; // WL_DISCONNECTED = 6
}
else if (status == 254) {
return "STOPPED"; // WL_STOPPED = 254,
}
else if (status == 255) {
return "NO_SHIELD"; // WL_NO_SHIELD = 255,
}
else {
return (String)status; //"UNKNOWN";
}
}
/*
typedef enum {
WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library
WL_STOPPED = 254,
WL_IDLE_STATUS = 0,
WL_NO_SSID_AVAIL = 1,
WL_SCAN_COMPLETED = 2,
WL_CONNECTED = 3,
WL_CONNECT_FAILED = 4,
WL_CONNECTION_LOST = 5,
WL_DISCONNECTED = 6
} wl_status_t;
*/
// ****************
// *** FIN WIFI ***
// ****************
// ************************
// *** DEBUT SERVER WEB ***
// ************************
// Page carte SD methode GET
void handleSDCard(AsyncWebServerRequest * request) {
String directory = urldecode(request->url());
if (serialDebug_webserver) {
Serial.print("request->url() -> ");
Serial.println(request->url());
Serial.print("directory -> ");
Serial.println(directory);
}
uploadPath = directory;
File dir = SD.open(directory);
String entryName = "";
String tree = "";
while (true) {
File entry = dir.openNextFile();
//if (serialDebug_webserver) {Serial.print("entry -> ");Serial.println(entry);} // return 1 ou 0
entryName = entry.name();
if (serialDebug_webserver) {
Serial.print("entryName -> ");
Serial.println(entryName);
}
entryName.replace(directory + "/", "");
//if (serialDebug_webserver) {Serial.print("entryName2 -> ");Serial.println(entryName);} // aucune difference
if (! entry) {
// no more files
break;
}
if (entry.isDirectory()) { // Si c'est un repertoire
if (strcmp(entry.name(), "System Volume Information") != 0) { // if it's NOT "System Volume Information"
tree += "<tr>";
tree += "<td data-value=\"";
tree += entryName;
tree += "/\"><a class=\"icon dir\" href=\"";
tree += entry.path();
tree += "\">";
tree += entryName;
tree += "/</a></td>";
tree += "<td class=\"detailsColumn\" data-value=\"0\">-</td>";
tree += "<td class=\"detailsColumn\" data-value=\"0\">";
tree += "<button class='buttons' onclick=\"location.href='/deleteConfirm?folder=";
tree += entry.path();
tree += "';\">Supprimer</button></td>";
tree += "</tr>";
}
}
else { // Si c'est un fichier
if (strcmp(entry.name(), "WPSettings.dat") != 0 && strcmp(entry.name(), "IndexerVolumeGuid") != 0) { // if it's NOT "WPSettings.dat" ET "IndexerVolumeGuid"
tree += "<tr>";
tree += "<td data-value=\"";
tree += entry.name();
tree += "\"><a class=\"icon file\" draggable=\"true\" href=\"";
tree += entry.path();
tree += "\" download>";
tree += entryName;
tree += "</a></td>";
tree += "<td class=\"detailsColumn\" data-value=\")";
tree += file_size(entry.size());
tree += "\">";
tree += file_size(entry.size());
tree += "</td>";
tree += "<td class=\"detailsColumn\" data-value=\"0\">";
tree += "<button class='buttons' onclick=\"location.href='/deleteConfirm?file=";
tree += entry.path();
tree += "';\">Supprimer</button></td>";
tree += "</tr>";
}
}
entry.close();
}
String path = directory;
path.remove(0, 1); // supprime le / en debut de path
path += "/"; // ajoute un / en fin de path
if (serialDebug_webserver) {
Serial.print("path -> ");
Serial.println(path);
}
/*
if (serialDebug_webserver) Serial.print("directory:");
if (serialDebug_webserver) Serial.println(directory);
if (serialDebug_webserver) Serial.print("path:");
if (serialDebug_webserver) Serial.println(path);
*/
//Construction de la page WEB
String webpage = "";
webpage += headerDeb; // AJOUT HEADER debut
webpage += styleMenu; // style Menu
webpage += styledata; // style Data
webpage += stylemedia; // style @media
webpage += headerFin; // AJOUT HEADER Fin
webpage += menuhtml; // AJOUT MENU
webpage += "<div class=\"topnav\">";
webpage += "<h1 id=\"header\">Index of "; // Titre Indef of DIRECTORY (juste en dessous)
webpage += directory;
webpage += "</h1>";
webpage += "</div>";
webpage += "<hr>";
if (directory != "/" && directory != "/data") { // si on est pas a la racine, on cree le lien Parent Directory
webpage += "<div id=\"parentDirLinkBox\" style=\"display:block;\">";
webpage += "<a id=\"parentDirLink\" class=\"icon up\" href=\"";
while (!directory.endsWith("/")) {
directory = directory.substring(0, directory.length() - 1);
}
if (directory.length() > 1) {
directory = directory.substring(0, directory.length() - 1);
}
webpage += directory;
webpage += "\">";
webpage += "<span id=\"parentDirText\">[Parent directory]</span>"; // Text de [Parent directory] lien repertoire precedent
webpage += "</a>";
webpage += "</div>";
}
webpage += script; // AJOUT SCRIPT (Java)
webpage += "<table>";
webpage += "<thead>";
webpage += "<tr class=\"header\" id=\"theader\">";
webpage += "<th onclick=\"sortTable(0);\">Nom</th>"; // Nom de la colonne (Name)
webpage += "<th class=\"detailsColumn\" onclick=\"sortTable(1);\">Taille</th>"; // Taille de la colonne (Size)
webpage += "<th></th>";
webpage += "</tr>";
webpage += "</thead>";
webpage += "<tbody id=\"tbody\">";
webpage += tree; // Ajoute le nom du fichier ou du repertoire
webpage += "</tbody>";
webpage += "</table>";
webpage += "<hr>";
// Pour le telechargemnt d'un fichier [PC -> CARTE SD]
webpage += "<FORM action='/fupload' method='post' enctype='multipart/form-data'>";
webpage += "<input class='buttons' type='file' name='fupload' id = 'fupload' value=''>";
webpage += "<button class='buttons' type='submit'>Upload</button></form><br>";
// Creation d'un repertoire
webpage += "<FORM action='/mkdir' method='post' enctype='multipart/form-data'>";
webpage += "<input type='hidden' id='path' name='path' value='";
webpage += uploadPath; // uploadPath == directory (Repertoire courant)
webpage += "'>";
webpage += "<input class='buttons' name='dirName' id ='dirName' value='NewFolder'>"; // Nom du nouveau repertoire (force NewFolder par defaut)
webpage += "<button class='buttons' type='submit'>MkDir</button></form>";
webpage += footer; // AJOUT FOOTER
if (tree == "") { // Upload fichier ou Telechargement de fichier
String dlPath = urldecode(request->url());
//if (serialDebug_webserver) {Serial.print("server.uri() dlPath -> ");Serial.println(server.uri());}
//AVOIR MODIF
if (!SD.exists(dlPath)) { // si le fichier existe pas -> NOT FOUND
handleNotFound(request); // Page not Found
}
/* //AVOIR ORIGINAL **
if (SD.exists(dlPath)) { // Si fichier existe sur la carte SD
File entry = SD.open(dlPath); // on ouvre le fichier
if (!entry.isDirectory()) { // si ce n'est pas un repertoire
if (serialDebug_webserver) {Serial.print("dlPath -> ");Serial.println(dlPath);}
//handleFileRead(request, dlPath);
}
}
else { // si le fichier existe pas -> NOT FOUND
handleNotFound(request); // AVOIR
}
*/
}
request->send(200, "text/html", webpage);
}
// Fichier non trouve
void handleNotFound(AsyncWebServerRequest * request) {
String webpage = "";
webpage += headerlight;
webpage += "<hr>Fichier introuvable<br>";
webpage += "<br>URI:";
webpage += request->url();
webpage += "<br>Method: ";
webpage += (request->method() == HTTP_GET) ? "GET" : "POST"; // si method = GET -> GET sinon POST
webpage += "<br>Arguments: ";
webpage += request->params();
webpage += "<br>";
int8_t args = request->args();
for(int8_t i =0 ; i < args; i++ ) {
if (serialDebug_webserver) Serial.printf("ARG[%s]: %s\n", request->argName(i).c_str(), request->arg(i).c_str());
webpage += request->argName(i);
webpage += ": ";
webpage += request->arg(i);
webpage += "<br>";
}
webpage += "<br><button class='buttons' onclick=\"location.href='/';\">OK</button>";
webpage += footer;
request->send(404, "text/html", webpage);
}
// Creation d'un repertoire
void doMkdir(AsyncWebServerRequest * request) {
String webpage = "";
String path = "";
String pathi = "";
String dirName = "";
webpage += headerlight;
int8_t args = request->args();
for(int8_t i =0 ; i < args; i++ ) {
if (request->argName(i) == "dirName") { // Nom du repertoire a creer
if (serialDebug_webserver) Serial.printf("Dir Name: %s\n", request->arg(i).c_str());
dirName = request->arg(i);
}
if (request->argName(i) == "path") { // Emplacement du repertoire
if (serialDebug_webserver) Serial.printf("Path: %s\n", request->arg(i).c_str());
path = request->arg(i);
}
}
if (dirName != "" && path != "") { // si pas vide
pathi = path; // permet le retour au repertoir courant
webpage += "<hr>Creating Dir: <br>";
if (path == "/") { // si on est a la racine on cree le repertoire
path += dirName;
}
else { // si on est dans un repertoire on ajoute "/" et on cree le repertoire
path += "/";
path += dirName;
}
webpage += path;
if (serialDebug_webserver) {
Serial.print("Creating Dir: ");
Serial.println(path);
}
// Ajout verif repertoire existe deja AVOIR
if (!SD.exists(path)) { // Le fichier existe pas on créer le repertoire
if (SD.mkdir(path)) { // creation ok
webpage += "<br>Creation repertoire OK<br>";
}
else {
if (serialDebug_webserver) Serial.println("mkdir failed");
webpage += "<br>Erreur creation repertoire (SD.mkdir)<br>";
}
}
else { // Le fichier existe on verifie si c'est un repertoire
File file = SD.open(path);
if (file.isDirectory()) { // Le repertoire existe DEJA on arrete
if (serialDebug_webserver) Serial.println("mkdir already exist !");
webpage += "<br>Le repertoire existe DEJA (SD.mkdir)<br>";
}
else { // Le repertoire existe PAS on creer le repertoire
if (SD.mkdir(path)) { // creation ok
webpage += "<br>Creation repertoire OK<br>";
}
else {
if (serialDebug_webserver) Serial.println("mkdir failed");
webpage += "<br>Erreur creation repertoire (SD.mkdir)<br>";
}
}
file.close(); //on ferme le fichier
}
}
else {
webpage += "<br>Path or Name empty!";
}
webpage += "<br><button class='buttons' onclick=\"location.href='";
webpage += pathi;
webpage += "';\">OK</button>";
webpage += footer;
request->send(200, "text/html", webpage);
}
// Suppression de fichier
void doDelete(AsyncWebServerRequest * request) {
String webpage = "";
String pathi = "";
webpage += headerlight;
int8_t args = request->args();
for(int8_t i=0;i<args;i++){
if (request->argName(i) == "file") { // si c'est un fichier
if (serialDebug_webserver) {
Serial.print("Deleting file: ");
Serial.println(request->arg(i));
}
pathi = request->arg(i);
webpage += "<hr>Suppression fichier : <br>";
webpage += request->arg(i);
if (SD.remove(request->arg(i))) {
webpage += "<br>Fichier supprimé OK<br>";
}
else {
webpage += "<br>Erreur suppression fichier<br>";
}
}
if (request->argName(i) == "folder") { // si c'est un repertoire
if (serialDebug_webserver) {
Serial.print("Removing Dir: ");
Serial.println(request->arg(i));
}
pathi = request->arg(i);
webpage += "<hr>Suppression repertoire: <br>";
webpage += request->arg(i);
if (SD.rmdir(request->arg(i))) {
webpage += "<br>Repertoire supprimé OK<br>";
}
else {
webpage += "<br>Erreur suppression repertoire (SD.rmdir)<br>";
}
}
}
pathi = suplast(pathi); // defini le nom du path en supprimant le nom du fichier ou du repertoire supprime
webpage += "<br><button class='buttons' onclick=\"location.href='";
webpage += pathi;
webpage += "';\">OK</button>";
webpage += footer;
request->send(200, "text/html", webpage);
}
//Supprime les derniers caracteres d'une string jusqu'au "/" [ entree (pathi in: /data/2023/08/11.txt) -> sortie (pathi out : /data/2023/08)]
String suplast(String string) {
for (int16_t i = string.length(); i > 0; i--) {
if (!string.endsWith("/")) {
string = string.substring(0, string.length() - 1);
//if (serialDebug_webserver) Serial.println(string);
}
}
if (string.endsWith("/") && string != "/") {
string = string.substring(0, string.length() - 1); // supprime le / a la fin
//if (serialDebug_webserver) Serial.println(string);
}
return string;
}
// Confirmation avant suppression fichier ou repertoire
void deleteConfirm(AsyncWebServerRequest * request) {
String webpage = "";
webpage += headerlight;
int8_t args = request->args();
for(int8_t i=0;i<args;i++){
if (request->argName(i) == "file") { // Si fichier
webpage += "<hr>Voulez vous supprimer le fichier :<br>";
webpage += request->arg(i);
webpage += "<br><br><button class='buttons' onclick=\"location.href='/doDelete?file=";
webpage += request->arg(i);
webpage += "';\">OUI</button>";
}
if (request->argName(i) == "folder") { // Si repertoire
webpage += "<hr>Voulez vous supprimer le repertoire :<br>";
webpage += request->arg(i);
webpage += "<br><br><button class='buttons' onclick=\"location.href='/doDelete?folder=";
webpage += request->arg(i);
webpage += "';\">OUI</button>";
}
}
webpage += "<button class='buttons' onclick='window.history.back();'>NON</button>";
webpage += footer;
request->send(200, "text/html", webpage);
}
// Ajout fichier depuis PC vers carte SD [PC -> SDCARD]
void handleFileUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
if (serialDebug_webserver) {
Serial.print("Client: ");
Serial.print(request->client()->remoteIP());
Serial.print(" ");
Serial.print(request->url());
}
String filepath;
//Nom du fichier + path
if (!filename.startsWith("/") && !uploadPath.endsWith("/")) {
filepath = uploadPath;
filepath += "/";
filepath += filename;
}
else {
filepath = uploadPath;
filepath += filename;
}
/*
if (serialDebug_webserver) {
Serial.print("filename -> ");
Serial.println(filepath);
}
*/
if (!index) {
SD.remove(filepath); // Remove a previous version, otherwise data is appended the file again
// open the file on first call and store the file handle in the request object
request->_tempFile = SD.open(filepath, FILE_WRITE); // Open the file for writing in SPIFFS (create it, if doesn't exist)
if (serialDebug_webserver) {
Serial.print("Upload Start: ");
Serial.println(filepath);
}
}
if (len) {
request->_tempFile.write(data, len);
if (serialDebug_webserver) {
Serial.print("Writing file: ");
Serial.print(filepath);
Serial.print(" index=");
Serial.print(index);
Serial.print(" len=");
Serial.println(len);
}
}
if (final) {
// close the file handle as the upload is now done
request->_tempFile.close();
if (serialDebug_webserver) {
Serial.print("Upload Complete: ");
Serial.print(filepath);
Serial.print(",size: ");
Serial.print(index + len);
}
String webpage = "";
webpage += headerlight;
webpage += "<hr>File was successfully uploaded<br>";
webpage += "Uploaded File Name: ";
webpage += filepath;
webpage += "<br>";
webpage += "File Size: ";
webpage += file_size((index + len));
webpage += "<br>";
webpage += "<button class='buttons' onclick=\"location.href='";
webpage += uploadPath;
webpage += "';\">OK</button>";
webpage += footer;
request->send(200, "text/html", webpage); // AVOIR
//request->redirect("/");
}
/*
// AVOIR si ERREUR pendand le chargement du fichier ??
else {
//delay(1000);
String webpage = "";
webpage += header;
webpage += "<hr>Could Not Create Uploaded File (write-protected?)<br>";
webpage += "<button class='buttons' onclick=\"location.href='";
webpage += uploadPath;
webpage += "';\">OK</button>";
webpage += footer;
request->send(200, "text/html", webpage); // AVOIR
}
*/
}
// Taille des fichiers en lecture humaine o (octets) Ko (Kilo octets) etc ...
String file_size(int32_t bytes) {
String fsize = "";
if (bytes < 1024) {
fsize = String(bytes);
fsize += " o";
}
else if (bytes < (1024 * 1024)) {
fsize = String(bytes / 1024.0, 2); // , 2 -> pour deux chiffre apres la virgule (initial 3 chiffres)
fsize += " Ko";
}
else if (bytes < (1024 * 1024 * 1024)) {
fsize = String(bytes / 1024.0 / 1024.0, 2);
fsize += " Mo";
}
else {
fsize = String(bytes / 1024.0 / 1024.0 / 1024.0, 2);
fsize += " Go";
}
fsize.replace(".", ",");// remplace point par virgule
return fsize;
}
// Fonction pour decoder l'url
String urldecode(String str) {
String encodedString = "";
char c;
char code0;
char code1;
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (c == '+') {
encodedString += ' ';
}
else if (c == '%') {
i++;
code0 = str.charAt(i);
i++;
code1 = str.charAt(i);
c = (h2int(code0) << 4) | h2int(code1);
encodedString += c;
}
else {
encodedString += c;
}
//yield();
}
return encodedString;
}
// fonction pour encoder l'url
String urlencode(String str) {
String encodedString = "";
char c;
char code0;
char code1;
//char code2;
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (c == ' ') {
encodedString += '+';
}
else if (isalnum(c)) {
encodedString += c;
}
else {
code1 = (c & 0xf) + '0';
if ((c & 0xf) > 9) {
code1 = (c & 0xf) - 10 + 'A';
}
c = (c >> 4) & 0xf;
code0 = c + '0';
if (c > 9) {
code0 = c - 10 + 'A';
}
//code2 = '\0';
encodedString += '%';
encodedString += code0;
encodedString += code1;
//encodedString+=code2;
}
//yield();
}
return encodedString;
}
//Hexa to Int ??
unsigned char h2int(char c)
{
if (c >= '0' && c <= '9') {
return ((unsigned char)c - '0');
}
if (c >= 'a' && c <= 'f') {
return ((unsigned char)c - 'a' + 10);
}
if (c >= 'A' && c <= 'F') {
return ((unsigned char)c - 'A' + 10);
}
return (0);
}
// Config page
void handleconfig(AsyncWebServerRequest * request) {
String webpage = "";
webpage += headerDeb; // AJOUT HEADER debut
webpage += styleMenu; // style Menu
webpage += styleconf; // style Config
webpage += stylemedia; // style @media
webpage += headerFin; // AJOUT HEADER Fin
webpage += menuhtml;
webpage += "<div class=\"conteneur\">";
webpage += "<p>Du contenu sous le menu Config</p>";
webpage += "</div>";
webpage += footer;
request->send(200, "text/html", webpage);
}
// Wifi page GET
void handlewifi(AsyncWebServerRequest * request) {
String webpage = "";
webpage += headerDeb; // AJOUT HEADER debut
webpage += styleMenu; // style Menu
webpage += stylewifi; // style Wifi
webpage += stylemedia; // style @media
webpage += headerFin; // AJOUT HEADER Fin
webpage += menuhtml;
webpage += wifipage;
webpage += footer;
request->send(200, "text/html", webpage);
}
// Wifi page POST
void handlewifiPost(AsyncWebServerRequest * request) {
String webpage = "";
webpage += headerlight;
webpage += "<hr>Vérification SSID et Clé Wifi :<br>";
int8_t params = request->params();
for(int8_t i=0;i<params;i++) {
AsyncWebParameter* p = request->getParam(i);
if(p->isPost()) {
// HTTP POST ssid value
if (p->name() == PARAM_IN_SSID) {
if (p->value() != nullptr) { // si le SSID n'est pas vide
//ssidnew = p->value().c_str(); // c_str() -> converti une String en char AVOIR
ssidnew = p->value();
webpage += "<hr>Le SSID est : ";
webpage += p->value();
webpage += "<br>";
if (serialDebug_webserver) {
Serial.print("SSID set to: ");
Serial.println(ssidnew);
}
}
else {
ssidnew = ""; // force le SSID a Empty [VIDE]
webpage += "<hr>Le SSID est vide !!!<br>";
if (serialDebug_webserver) Serial.println("SSID set to: Empty");
}
}
// HTTP POST pass value
if (p->name() == PARAM_IN_PASS) {
if (p->value() != nullptr) { // si le Password n'est pas vide
//passnew = p->value().c_str(); // c_str() -> converti une String en char AVOIR
passnew = p->value();
webpage += "La Clé Wifi est : ";
webpage += p->value();
if (serialDebug_webserver) {
Serial.print("WifiKey set to: ");
Serial.println(passnew);
}
}
else {
passnew = ""; // force le Password a Empty [VIDE]
webpage += "Le Clé Wifi est vide !!!";
if (serialDebug_webserver) Serial.println("WifiKey set to: Empty");
}
}
//if (serialDebug_webserver) Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
}
}
if (ssidnew != nullptr && passnew != nullptr ) { // SI SSID ou Clé WIFI [NON VIDE] OK
webpage += "<br><br><button class='buttons' onclick=\"location.href='/doWifi';\">OUI</button>";
webpage += "<button class='buttons' onclick=\"location.href='/wifi';\">NON</button>";
}
else { // SI SSID ou Clé WIFI [VIDE] NOK
webpage += "<br><br><button class='buttons' onclick=\"location.href='/wifi';\">Recommencer</button>";
}
webpage += footer;
request->send(200, "text/html", webpage);
}
// Maj Wifi ok
void doWifi(AsyncWebServerRequest * request) {
SaveWifiCred();
String webpage = "";
webpage += headerlight;
webpage += "<hr>Config Wifi Mise à jour OK <br>";
webpage += "<br><button class='buttons' onclick=\"location.href='/wifi';\">OK</button>";
webpage += footer;
request->send(200, "text/html", webpage);
// AVOIR Ajout MAJ Connexion Wifi // AVOIR VERIF SI PAS LE MEME WIFI DEJA CONNECTE !!!!
InitWifi(); // Init du WIFI
}
// Page Etat
void handleEtat(AsyncWebServerRequest * request) {
String webpage = "";
webpage += headerDeb; // AJOUT HEADER debut
webpage += styleMenu; // style Menu
webpage += styleetat; // style Etat
webpage += stylemedia; // style @media
webpage += headerFin; // AJOUT HEADER Fin
webpage += menuhtml;
// Titre
webpage += "<div class=\"topnav\">";
webpage += "<h1>Etat du Récuperateur de chaleur</h1>";
webpage += "<span>Démarré depuis : </span>";
webpage += "<span id=\"uptime\"></span>";
webpage += "</div>";
webpage += "<hr>"; // Trait delimitation
//ON /OFF
webpage += "<div class=\"content\">";
webpage += "<div class=\"card2-grid-h2\">";
webpage += "<h2>Arrêter / Démarrer :";
webpage += "<label class=\"switch\">";
//"<!--<input id=\"onoff\" type=\"checkbox\" %ONOFF%>-->"
webpage += "<input id=\"onoff\" type=\"checkbox\" onclick=\"handleClick(this);\" ";
//webpage += processor("ONOFF"); // VENTILO on/off
webpage += flag_ventilo_on_off ? "checked" : ""; // VENTILO on/off
webpage += ">";
webpage += "<span class=\"slider\" id=\"onoff_slid\" data-on=\"ON\" data-off=\"OFF\"></span>";
webpage += "</label>";
webpage += "</h2>";
webpage += "</div>";
webpage += "</div>";
webpage += "<hr>"; // Trait delimitation
webpage += "<div class=\"content\">";
webpage += "<div class=\"card2-grid-h2\">";
webpage += "<h2>Sondes Température :</h2>";
webpage += "</div>";
//Sondes de Temperature
webpage += "<div class=\"card2-grid\">";
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Température Sonde Extérieure</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"Sext\"></span></p>"; // °C (mis dans le Javascript)
webpage += "</div>";
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Température Sonde Moteur</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"Smoteur\"></span></p>"; // °C (mis dans le Javascript)
webpage += "</div>";
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Température Sonde Chaud</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"Schaud\"></span></p>"; // °C (mis dans le Javascript)
webpage += "</div>";
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Température Sonde Froid</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"Sfroid\"></span></p>"; // °C (mis dans le Javascript)
webpage += "</div>";
//PID TEMPERATURE
//Temperature de consigne -> SetpointPID
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Température SetpointPID</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"SetpointPID\"></span></p>"; // °C (mis dans le Javascript)
webpage += "</div>";
//Temperature de consigne -> ConsignePID
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Température Consigne</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_ConsignePID\"></span></p>"; // °C (mis dans le Javascript)
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_ConsignePID\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"ConsignePID\" min=\"";
webpage += Temp_min_ConsignePID_allowed * coef_temp; // Temperature mini
webpage += "\" max=\"";
webpage += Temp_max_ConsignePID_allowed * coef_temp; // Temperature maxi
//webpage += "\" value=\""; //NEW
//webpage += ConsignePID * coef_temp; //NEW // AVOIR
webpage += "\" step=\"0.5\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_ConsignePID\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_ConsignePID\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
//Temperature de consigne -> Temp_ON_moteur
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Température Min(Démarrage) Ventilo</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_Temp_ON_moteur\"></span></p>"; // °C (mis dans le Javascript)
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Temp_ON_moteur\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Temp_ON_moteur\" min=\"";
webpage += Temp_min_chaud_allowed * coef_temp; // Temperature mini
webpage += "\" max=\"";
webpage += Temp_max_chaud_allowed * coef_temp; // Temperature maxi
//webpage += "\" value=\""; //NEW
//webpage += Temp_ON_moteur * coef_temp; //NEW // AVOIR
webpage += "\" step=\"0.5\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Temp_ON_moteur\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Temp_ON_moteur\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
webpage += "</div>"; //Fin DIV
webpage += "</div>";
webpage += "<hr>"; // Trait delimitation
//VENTILATEUR
webpage += "<div class=\"content\">";
webpage += "<div class=\"card2-grid-h2\">";
webpage += "<h2><span> VENTILATEUR :</span>";
webpage += "<label class=\"switch\">";
//"<!--<input id=\"Vmanuauto\" type=\"checkbox\" %VMANUAUTO%>-->"
webpage += "<input id=\"Vmanuauto\" type=\"checkbox\" onclick=\"handleClick(this);\" ";
//webpage += processor("VMANUAUTO"); // VENTILO manu/auto INVERSE
webpage += flag_ventilo_manu_on_off ? "" : "checked"; // VENTILO manu/auto INVERSE
webpage += ">";
webpage += "<span class=\"slider\" id=\"Vmanuauto_slid\" data-on=\"AUTO\" data-off=\"MANU\"></span>";
webpage += "</label>";
//Mode Boost
webpage += "<span class=\"boost\">Mode BOOST :</span>";
webpage += "<label class=\"switch\">";
//"<!--<input id=\"Vboost\" type=\"checkbox\" %VBOOST%>-->"
webpage += "<input id=\"Vboost\" type=\"checkbox\" onclick=\"handleClick(this);\" ";
//webpage += processor("VBOOST"); // VENTILO BOOST on/off
webpage += flag_ventilo_boost_on_off ? "checked" : ""; // VENTILO BOOST on/off
webpage += ">";
webpage += "<span class=\"slider\" id=\"Vboost_slid\" data-on=\"ON\" data-off=\"OFF\"></span>";
webpage += "</label>";
webpage += "<span class=\"timer\">Durée restante : </span>"; //Duree Mode BOOST
webpage += "<span class=\"timer\" id=\"timerb\"></span>"; //Duree Mode BOOST
//Fin Mode Boost
webpage += "</h2>";
webpage += "</div>";
webpage += "<div class=\"card2-grid\">";
//Vitesse Ventilo
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\" id=\"manuVentiT\"><span>VENTILO Vitesse</span></p>";
webpage += "<p class=\"reading\" id=\"manuVentiO\"><span id=\"rpm\"></span></p>"; // Tr/min (mis dans le Javascript)
//Vitesse Ventilo (Modification possible si MODE MANU Menu cache)
webpage += "<p class=\"reading\" id=\"manuVentiN\"><span id=\"va_VitManu\"></span></p>"; // Numero de la vitesse en MODE MANU
webpage += "<p class=\"cursor\" id=\"manuVenti\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_VitManu\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"VitManu\" min=\"";
webpage += 0; // Vitesse mini
webpage += "\" max=\"";
webpage += Nbrevitesse-2; // Vitesse maxi AVOIR VMAX
webpage += "\" step=\"1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_VitManu\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_VitManu\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
//VENTILATEUR VITESSE
// Vitesse Mode Jour -> Vit_jour
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Vitesse Mode Jour</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_Vit_jour\"></span></p>";
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Vit_jour\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Vit_jour\" min=\"";
webpage += 0; // Vitesse mini
webpage += "\" max=\"";
webpage += Nbrevitesse-2; // Vitesse maxi
//webpage += "\" value=\""; //NEW
//webpage += Vit_jour; //NEW // AVOIR
webpage += "\" step=\"1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Vit_jour\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Vit_jour\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
//Heure Debut Mode Jour -> START_MODE_JOUR (HMJ)
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Heure Début Mode Jour</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_HMJ\"></span></p>";
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_HMJ\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"HMJ\" min=\"";
webpage += 0; // Time mini (0h00)
webpage += "\" max=\"";
webpage += 86100; // Time maxi (23h55)
//webpage += "\" value=\""; //NEW
//webpage += START_MODE_JOUR; //NEW
webpage += "\" step=\"300\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_HMJ\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_HMJ\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
// Vitesse Mode Nuit -> Vit_nuit
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Vitesse Mode Nuit</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_Vit_nuit\"></span></p>";
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Vit_nuit\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Vit_nuit\" min=\"";
webpage += 0; // Vitesse mini
webpage += "\" max=\"";
webpage += Nbrevitesse-2; // Vitesse maxi
//webpage += "\" value=\""; //NEW
//webpage += Vit_nuit; //NEW // AVOIR
webpage += "\" step=\"1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Vit_nuit\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Vit_nuit\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
//Heure Debut Mode Nuit -> START_MODE_NUIT (HMN)
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Heure Début Mode Nuit</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_HMN\"></span></p>";
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_HMN\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"HMN\" min=\"";
webpage += 0; // Time mini (0h00)
webpage += "\" max=\"";
webpage += 86100; // Time maxi (23h55)
//webpage += "\" value=\""; //NEW
//webpage += START_MODE_NUIT; //NEW
webpage += "\" step=\"300\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_HMN\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_HMN\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
// Vitesse Mode Boost -> Vit_boost
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Vitesse Mode Boost</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_Vit_boost\"></span></p>";
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Vit_boost\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Vit_boost\" min=\"";
webpage += 0; // Vitesse mini
webpage += "\" max=\"";
webpage += Nbrevitesse-2; // Vitesse maxi
//webpage += "\" value=\""; //NEW
//webpage += Vit_boost; //NEW // AVOIR
webpage += "\" step=\"1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Vit_boost\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Vit_boost\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
//Timer Mode BOOST -> TIMER_MODE_BOOST (TMB)
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Durée Mode Boost</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_TMB\"></span></p>";
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_TMB\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"TMB\" min=\"";
webpage += 300; // Time mini (5min)
webpage += "\" max=\"";
webpage += 18000; // Time maxi (5h00)
//webpage += "\" value=\""; //NEW
//webpage += TIMER_MODE_BOOST; //NEW
webpage += "\" step=\"300\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_TMB\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_TMB\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
webpage += "</div>"; // Fin DIV
//DEBUT Courbe Vitesse Mode Jour SVG
webpage += "<div class=\"content3\">";
webpage += "<div class=\"card3-grid\">";
webpage += "<div class=\"card3\">";
webpage += "<p class=\"card2-title\"><span>Courbe Vitesse Mode Jour</span></p>";
webpage += "<div class=\"svg\">";
//SVG Debut
webpage += "<svg class=\"svg2\">";
webpage += "<rect class=\"cadre\" x=\"0\" y=\"0\" width=\"350px\" height=\"200px\"/>"; // cadre SVG
// +50 sur X
// +30 sur Y
webpage += "<polyline class=\"axe\" points=\"50,30 50,156 304,156\" />"; // Axes SVG
// axe vertical
webpage += "<text class=\"valaxe\" x=\"50\" y=\"16\">Tr/min</text>"; // unite axe vertical SVG
webpage += "<line class=\"axe\" x1=\"47\" y1=\"30\" x2=\"50\" y2=\"30\" />";
webpage += "<text class=\"valaxe1\" id=\"gr_Vit_Tmaxi\" x=\"30\" y=\"36\" ></text>"; // Point haut y:+6, x:-3 (1800)
webpage += "<line class=\"axe\" id=\"CoAxeY\" x1=\"47\" y1=\"73\" x2=\"50\" y2=\"73\" />";
webpage += "<text class=\"valaxe1\" id=\"gr_Vit_Tinte\" x=\"30\" y=\"73\" ></text>"; // Point milieu x:-3 (1650) //variable y:73 (43+30)
webpage += "<line class=\"axe\" x1=\"47\" y1=\"156\" x2=\"50\" y2=\"156\" />";
webpage += "<text class=\"valaxe1\" id=\"gr_Vit_Tbase\" x=\"30\" y=\"153\" ></text>"; // Point bas y:-3, x:-3 (1400)
// axe horizontal
webpage += "<text class=\"valaxe\" x=\"320\" y=\"158\">°C</text>"; // unite axe horizontal SVG
webpage += "<line class=\"axe\" x1=\"60\" y1=\"156\" x2=\"60\" y2=\"159\" />";
webpage += "<text class=\"valaxe1\" id=\"gr_Temp_Vbase\" x=\"60\" y=\"168\" ></text>"; // Point gauche y:+10 (12,0)
webpage += "<line class=\"axe\" id=\"CoAxeX\" x1=\"177\" y1=\"156\" x2=\"177\" y2=\"159\" />";
webpage += "<text class=\"valaxe1\" id=\"gr_Temp_Vinte\" x=\"177\" y=\"168\" ></text>"; //Point milieu y:+10 (0,0) //variable x:177 (127+50)
webpage += "<line class=\"axe\" x1=\"295\" y1=\"156\" x2=\"295\" y2=\"159\" />";
webpage += "<text class=\"valaxe1\" id=\"gr_Temp_Vmini\" x=\"295\" y=\"168\" ></text>"; // Point doite y:+10 (-12,0)
//Offset
webpage += "<text class=\"valaxe\" x=\"50\" y=\"190\" >Offset Vit.: </text>"; // Offset Vitesse
webpage += "<text class=\"valaxe1\" id=\"gr_Vit_offset\" x=\"110\" y=\"190\" ></text>"; //Valeur Vitesse
webpage += "<text class=\"valaxe\" x=\"200\" y=\"190\" >Offset Temp.: </text>"; // Offset Temperature
webpage += "<text class=\"valaxe1\" id=\"gr_Temp_offset\" x=\"280\" y=\"190\" ></text>"; //Valeur Temp
//courbe
webpage += "<polyline class=\"courbe\" id=\"polygraph\" points=\"60,156 177,73 294,30\" />";
webpage += "</svg>";
//Fin SVG
//Curseur / Slider
webpage += "<table class=\"table3\">";
webpage += "<tbody>";
//Titre
webpage += "<tr>";
webpage += "<td>";
webpage += "<p class=\"card3-title\"><span>Vitesses</span></p>";
webpage += "</td>";
webpage += "<td>";
webpage += "<p class=\"card3-title\"><span>Températures</span></p>";
webpage += "</td>";
webpage += "</tr>";
//Base
webpage += "<tr>";
webpage += "<td>";
webpage += "<p class=\"titre3\">Vitesse Base : </p>";
webpage += "<span class=\"val3\" id=\"va_Vit_Tbase\"></span>";
webpage += "<p class=\"cursor3\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Vit_Tbase\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Vit_Tbase\" min=\"";
webpage += 6; // Vitesse mini
webpage += "\" max=\"";
webpage += 9; // Vitesse maxi
//webpage += "\" value=\""; //NEW
//webpage += Vit_Tbase; //NEW
webpage += "\" step=\"1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Vit_Tbase\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Vit_Tbase\" value=\"OK\" >";
webpage += "</p>";
webpage += "</td>";
webpage += "<td>";
webpage += "<p class=\"titre3\">Temp. Base : </p>";
webpage += "<span class=\"val3\" id=\"va_Temp_Vbase\"></span>";
webpage += "<p class=\"cursor3\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Temp_Vbase\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Temp_Vbase\" min=\"";
webpage += 5; // Temperature mini
webpage += "\" max=\"";
webpage += 25; // Temperature maxi
//webpage += "\" value=\""; //NEW
//webpage += Temp_Vbase * coef_temp; //NEW
webpage += "\" step=\"0.1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Temp_Vbase\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Temp_Vbase\" value=\"OK\" >";
webpage += "</p>";
webpage += "</td>";
webpage += "</tr>";
//Intermediaire
webpage += "<tr>";
webpage += "<td>";
webpage += "<p class=\"titre3\">Vitesse Int : </p>";
webpage += "<span class=\"val3\" id=\"va_Vit_Tinte\"></span>";
webpage += "<p class=\"cursor3\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Vit_Tinte\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Vit_Tinte\" min=\"";
webpage += 9; // Vitesse mini
webpage += "\" max=\"";
webpage += 14; // Vitesse maxi
//webpage += "\" value=\""; //NEW
//webpage += Vit_Tinte; //NEW
webpage += "\" step=\"1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Vit_Tinte\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Vit_Tinte\" value=\"OK\" >";
webpage += "</p>";
webpage += "</td>";
webpage += "<td>";
webpage += "<p class=\"titre3\">Temp. Int : </p>";
webpage += "<span class=\"val3\" id=\"va_Temp_Vinte\"></span>";
webpage += "<p class=\"cursor3\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Temp_Vinte\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Temp_Vinte\" min=\"";
webpage += -5; // Temperature mini
webpage += "\" max=\"";
webpage += 5; // Temperature maxi
//webpage += "\" value=\""; //NEW
//webpage += Temp_Vinte * coef_temp; //NEW
webpage += "\" step=\"0.1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Temp_Vinte\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Temp_Vinte\" value=\"OK\" >";
webpage += "</p>";
webpage += "</td>";
webpage += "</tr>";
//Max / min
webpage += "<tr>";
webpage += "<td>";
webpage += "<p class=\"titre3\">Vitesse Max : </p>";
webpage += "<span class=\"val3\" id=\"va_Vit_Tmaxi\"></span>";
webpage += "<p class=\"cursor3\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Vit_Tmaxi\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Vit_Tmaxi\" min=\"";
webpage += 13; // Vitesse mini
webpage += "\" max=\"";
webpage += 16; // Vitesse maxi
//webpage += "\" value=\""; //NEW
//webpage += Vit_Tmaxi; //NEW
webpage += "\" step=\"1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Vit_Tmaxi\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Vit_Tmaxi\" value=\"OK\" >";
webpage += "</p>";
webpage += "</td>";
webpage += "<td>";
webpage += "<p class=\"titre3\">Temp. Mini : </p>";
webpage += "<span class=\"val3\" id=\"va_Temp_Vmini\"></span>";
webpage += "<p class=\"cursor3\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Temp_Vmini\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Temp_Vmini\" min=\"";
webpage += -25; // Temperature mini
webpage += "\" max=\"";
webpage += -5; // Temperature maxi
//webpage += "\" value=\""; //NEW
//webpage += Temp_Vmini * coef_temp; //NEW
webpage += "\" step=\"0.1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Temp_Vmini\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Temp_Vmini\" value=\"OK\" >";
webpage += "</p>";
webpage += "</td>";
webpage += "</tr>";
//Offset
webpage += "<tr>";
webpage += "<td>";
webpage += "<p class=\"titre3\">Vitesse Offset : </p>";
webpage += "<span class=\"val3\" id=\"va_Vit_offset\"></span>";
webpage += "<p class=\"cursor3\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Vit_offset\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Vit_offset\" min=\"";
webpage += -50; // Poucentage Vitesse mini
webpage += "\" max=\"";
webpage += 50; // Poucentage Vitesse maxi
//webpage += "\" value=\""; //NEW
//webpage += Vit_offset; //NEW
webpage += "\" step=\"1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Vit_offset\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Vit_offset\" value=\"OK\" >";
webpage += "</p>";
webpage += "</td>";
webpage += "<td>";
webpage += "<p class=\"titre3\">Temp. Offset : </p>";
webpage += "<span class=\"val3\" id=\"va_Temp_offset\"></span>";
webpage += "<p class=\"cursor3\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Temp_offset\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Temp_offset\" min=\"";
webpage += -2.5; // Temperature mini
webpage += "\" max=\"";
webpage += 2.5; // Temperature maxi
//webpage += "\" value=\""; //NEW
//webpage += Temp_offset * coef_temp; //NEW
webpage += "\" step=\"0.1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Temp_offset\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Temp_offset\" value=\"OK\" >";
webpage += "</p>";
webpage += "</td>";
webpage += "</tr>";
webpage += "</tbody>";
webpage += "</table>";
webpage += "</div>"; // Fin DIV SVG
webpage += "</div>"; // Fin DIV card3
webpage += "</div>"; // Fin DIV card3-grid
webpage += "</div>"; // Fin DIV content3
//FIN Courbe Vitesse Mode Jour
webpage += "</div>";
webpage += "<hr>"; // Trait delimitation
//IRIS
webpage += "<div class=\"content\">";
webpage += "<div class=\"card2-grid-h2\">";
webpage += "<h2>IRIS :";
webpage += "<label class=\"switch\">";
//"<!--<input id=\"Imanuauto\" type=\"checkbox\" %IMANUAUTO%>-->"
webpage += "<input id=\"Imanuauto\" type=\"checkbox\" onclick=\"handleClick(this);\" ";
//webpage += processor("IMANUAUTO"); // IRIS manu/auto INVERSE
webpage += flag_iris_manu_on_off ? "" : "checked"; // IRIS manu/auto INVERSE
webpage += ">";
webpage += "<span class=\"slider\" id=\"Imanuauto_slid\" data-on=\"AUTO\" data-off=\"MANU\"></span>";
webpage += "</label>";
webpage += "</h2>";
webpage += "</div>";
webpage += "<div class=\"card2-grid\">";
//Position IRIS
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\" id=\"manuIrisT\"><span>IRIS Position</span></p>";
webpage += "<p class=\"reading\" id=\"manuIrisO\">⌀ <span id=\"Steppercurrent\"></span> mm</p>";
//Position IRIS (Modification possible si MODE MANU Menu cache)
webpage += "<p class=\"reading\" id=\"manuIrisN\"><span id=\"va_PosManu\"></span></p>"; // Position choisi si MODE MANU
webpage += "<p class=\"cursor\" id=\"manuIris\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_PosManu\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"PosManu\" min=\"";
webpage += DiamIrisMini; // IRIS position mini 85 mm
webpage += "\" max=\"";
webpage += DiamIrisMaxi; // IRIS position maxi 200 mm
webpage += "\" step=\"1\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_PosManu\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_PosManu\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
//VENTILATEUR TEMPERATURE
//Temperature de consigne -> Hyst_Temp_ON_moteur
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Hystérésis Température Min(Démarrage)</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_Hyst_Temp_ON_moteur\"></span></p>"; // °C (mis dans le Javascript)
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Hyst_Temp_ON_moteur\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Hyst_Temp_ON_moteur\" min=\"";
webpage += Temp_min_Hyst_allowed * coef_temp; // Temperature mini
webpage += "\" max=\"";
webpage += Temp_max_Hyst_allowed * coef_temp; // Temperature maxi
//webpage += "\" value=\""; //NEW
//webpage += Hyst_Temp_ON_moteur * coef_temp; //NEW // AVOIR
webpage += "\" step=\"0.5\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Hyst_Temp_ON_moteur\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Hyst_Temp_ON_moteur\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
//Temperature de consigne -> Temp_OFF_moteur
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Température Max(Arrêt) Ventilo</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_Temp_OFF_moteur\"></span></p>"; // °C (mis dans le Javascript)
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_Temp_OFF_moteur\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"Temp_OFF_moteur\" min=\"";
webpage += Temp_min_moteur_allowed * coef_temp; // Temperature mini
webpage += "\" max=\"";
webpage += Temp_max_moteur_allowed * coef_temp; // Temperature maxi
//webpage += "\" value=\""; //NEW
//webpage += Temp_OFF_moteur * coef_temp; //NEW // AVOIR
webpage += "\" step=\"0.5\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_Temp_OFF_moteur\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_Temp_OFF_moteur\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
//Temperature de consigne -> ConsignePID_coupure
webpage += "<div class=\"card2\">";
webpage += "<p class=\"card2-title\"><span>Température Min(Arrêt) PID</span></p>";
webpage += "<p class=\"reading\">";
webpage += "<span id=\"va_ConsignePID_coupure\"></span></p>"; // °C (mis dans le Javascript)
webpage += "<p class=\"cursor\">";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"mo_ConsignePID_coupure\" value=\"-\" >";
webpage += "<input type=\"range\" onchange=\"updateSlider(this);\" id=\"ConsignePID_coupure\" min=\"";
webpage += Temp_min_coupure_allowed * coef_temp; // Temperature mini
webpage += "\" max=\"";
webpage += Temp_max_coupure_allowed * coef_temp; // Temperature maxi
//webpage += "\" value=\""; //NEW
//webpage += ConsignePID_coupure * coef_temp; //NEW // AVOIR
webpage += "\" step=\"0.5\" >";
webpage += "<input class=\"btcursor\" type=\"button\" onclick=\"updownSlider(this);\" id=\"pl_ConsignePID_coupure\" value=\"+\" >";
webpage += "<input class=\"valcursor\" type=\"button\" onclick=\"validSlider(this);\" id=\"bt_ConsignePID_coupure\" value=\"OK\" >";
webpage += "</p>";
webpage += "</div>";
webpage += "</div>"; // Fin DIV
webpage += "</div>"; // Fin DIV
webpage += scriptEtat;
webpage += footer;
request->send(200, "text/html", webpage); //, processor
}
/*
// Fonction pour remplacer les variables dans la page web etat a l'ouverture etat on/off, ventilo manu/auto, iris manu/auto
String processor(const String& var) {
if(var == "ONOFF") { // VENTILO on/off
return flag_ventilo_on_off ? "checked" : "";
}
if(var == "VMANUAUTO") { // VENTILO manu/auto
return flag_ventilo_manu_on_off ? "" : "checked"; // Inverse
}
if(var == "IMANUAUTO") { // IRIS manu/auto
return flag_iris_manu_on_off ? "" : "checked"; // Inverse
}
if(var == "VBOOST") { // VENTILO BOOST on/off
return flag_ventilo_boost_on_off ? "checked" : "";
}
return String();
}
*/
// **********************
// *** FIN SERVER WEB ***
// **********************
// ***********************
// *** DEBUT WEBSOCKET ***
// ***********************
// Envoie le message a tous les client via websocket
void notifyClients(char * nomMessage) {
if (ws.count() == 0) { // Si pas de client connected on sort
return;
}
//const uint8_t size = JSON_OBJECT_SIZE(1);
//StaticJsonDocument<size> json;
//StaticJsonDocument<640> json; // Version 6 existe plus dans version 7
JsonDocument json;
if (strcmp((char*)nomMessage, "getReadings") == 0) {
json["Sext"] = serialized(ftoS(SondeTempC[3], 2, false)); // serialized() permet de considerer le String comme un Float sans les "-10.25" -> -10.25
json["Smoteur"] = serialized(ftoS(SondeTempC[0], 2, false));
json["Schaud"] = serialized(ftoS(SondeTempC[1], 2, false));
json["Sfroid"] = serialized(ftoS(SondeTempC[2], 2, false));
json["SetpointPID"] = serialized(ftoS(SetpointPID, 1, false));
json["ConsignePID"] = serialized(ftoS(ConsignePID * coef_temp, 1, false));
json["ConsignePID_coupure"] = serialized(ftoS(ConsignePID_coupure * coef_temp, 1, false));
if (pwm != 0 && rpm == 0 && FlagErrorMoteur_RPM == true) { // Si le moteur ne tourne pas et qu'il est en ERREUR alors que PWM est different de zero
json["rpm"] = "Err.";
}
else {
json["rpm"] = rpm; // Vitesse moteur tr/min uint32_t
json["pwm"] = pwm; // Valeur PWM commande moteur uint16_t
json["CorrPwm"] = correctionPwm; // Correction valeur PWM int8_t
}
json["Vit_jour"] = Vit_jour;
json["Vit_nuit"] = Vit_nuit;
json["Vit_boost"] = Vit_boost;
//json["VitDyn"] = vitesseDynamique;
json["Temp_ON_moteur"] = serialized(ftoS(Temp_ON_moteur * coef_temp, 1, false));
json["Hyst_Temp_ON_moteur"] = serialized(ftoS(Hyst_Temp_ON_moteur * coef_temp, 1, false));
json["Temp_OFF_moteur"] = serialized(ftoS(Temp_OFF_moteur * coef_temp, 1, false));
json["Steppercurrent"] = map2(Steppercurrent, home, maxtravel, DiamIrisMaxi, DiamIrisMini);
json["onoff"] = flag_ventilo_on_off ? 1 : 0;
json["Vmanuauto"] = flag_ventilo_manu_on_off ? 1 : 0;
json["Imanuauto"] = flag_iris_manu_on_off ? 1 : 0;
if ( flag_iris_manu_on_off == true && flag_ventilo_on_off == true && (stepper.distanceToGo() != 0 || flag_auth_deplacement == true) ) { // si IRIS mode Manu ET (si deja en train de bouger OU on va commencer a bouger)
json["PosManu"] = map2(TempPosIris, home, maxtravel, DiamIrisMaxi, DiamIrisMini); // recupere la position vers laquel on va moteur pas a pas (deja en train de bouger)
// valeur entre 0 et 115
}
else { // si IRIS mode Auto
json["PosManu"] = json["Steppercurrent"]; // recupere la position actuel du moteur pas a pas [AU CAS OU] on passe en mode Manu
// valeur entre 0 et 115
}
json["Vboost"] = flag_ventilo_boost_on_off ? 1 : 0;
json["TMB"] = TIMER_MODE_BOOST;
json["HMJ"] = START_MODE_JOUR;
json["HMN"] = START_MODE_NUIT;
// Vitesse Dynamique
//Temperature
json["Temp_Vbase"] = serialized(ftoS(Temp_Vbase * coef_temp, 1, false));
json["Temp_Vinte"] = serialized(ftoS(Temp_Vinte * coef_temp, 1, false));
json["Temp_Vmini"] = serialized(ftoS(Temp_Vmini * coef_temp, 1, false));
json["Temp_offset"] = serialized(ftoS(Temp_offset * coef_temp, 1, false));
//Vitesse
json["Vit_Tbase"] = Vit_Tbase;
json["Vit_Tinte"] = Vit_Tinte;
json["Vit_Tmaxi"] = Vit_Tmaxi;
json["Vit_offset"] = Vit_offset;
json["uptime"] = serialized(Uptime);
if (flag_ventilo_boost_on_off == true) {
json["timerb"] = round( ((TIMER_MODE_BOOST * 1000L) - (millis() - timerModeBoost)) / 1000L ); // Duree du mode BOOST (en seconde)
}
}
//PID TEMPERATURE
if (strcmp((char*)nomMessage, "wsConsignePID") == 0) { // Temperature de consigne Sonde moteur PID (float 53°C) + SetpointPID (double)
json["ConsignePID"] = serialized(ftoS(ConsignePID * coef_temp, 1, false));
}
if (strcmp((char*)nomMessage, "wsSetpointPID") == 0) { // Temperature de consigne PID SetpointPID (double)
json["SetpointPID"] = serialized(ftoS(SetpointPID, 1, false));
}
if (strcmp((char*)nomMessage, "wsConsignePID_coupure") == 0) { // Temperature de coupure PID (float 37°C)
json["ConsignePID_coupure"] = serialized(ftoS(ConsignePID_coupure * coef_temp, 1, false));
}
//VENTILATEUR TEMPERATURE
if (strcmp((char*)nomMessage, "wsTemp_ON_moteur") == 0) { // Temperature de consigne mini ON Moteur (Temperature chaud) (float 400.0 -> 40°C)
json["Temp_ON_moteur"] = serialized(ftoS(Temp_ON_moteur * coef_temp, 1, false));
}
if (strcmp((char*)nomMessage, "wsTemp_OFF_moteur") == 0) { // Temperature de consigne maxi OFF Moteur (Temperature moteur) (float 550.0 -> 55°C)
json["Temp_OFF_moteur"] = serialized(ftoS(Temp_OFF_moteur * coef_temp, 1, false));
}
if (strcmp((char*)nomMessage, "wsHyst_Temp_ON_moteur") == 0) { // Hysteresis temperature moteur ON (Chaud 1er demarrage) (float 50.0 -> 5°C)
json["Hyst_Temp_ON_moteur"] = serialized(ftoS(Hyst_Temp_ON_moteur * coef_temp, 1, false));
}
//VENTILATEUR VITESSE
if (strcmp((char*)nomMessage, "wsVit_jour") == 0) { // Vitesse Mode Jour (uint8_t -> 12)
json["Vit_jour"] = Vit_jour;
}
if (strcmp((char*)nomMessage, "wsVit_nuit") == 0) { // Vitesse Mode Nuit (uint8_t -> 0)
json["Vit_nuit"] = Vit_nuit;
}
if (strcmp((char*)nomMessage, "wsVit_boost") == 0) { // Vitesse Mode Boost (uint8_t -> 16)
json["Vit_boost"] = Vit_boost;
}
if (strcmp((char*)nomMessage, "wsVitDyn") == 0) { // Vitesse Dynamique en mode auto Jour / nuit (uint16_t -> 0 - 168)
json["VitDyn"] = vitesseDynamique;
}
// Vitesse Dynamique
//Temperature
if (strcmp((char*)nomMessage, "wsTemp_Vbase") == 0) { // Seuil Temperature de Base 50 a 250 (int16_t 5 a 25°C)
json["Temp_Vbase"] = serialized(ftoS(Temp_Vbase * coef_temp, 1, false));
}
if (strcmp((char*)nomMessage, "wsTemp_Vinte") == 0) { // Seuil Temp. Inter. de -50 a 50 (int8_t -5 a 5°C)
json["Temp_Vinte"] = serialized(ftoS(Temp_Vinte * coef_temp, 1, false));
}
if (strcmp((char*)nomMessage, "wsTemp_Vmini") == 0) { // Seuil Temp. Mini de -250 a -50 (int16_t -25 a -5°C)
json["Temp_Vmini"] = serialized(ftoS(Temp_Vmini * coef_temp, 1, false));
}
if (strcmp((char*)nomMessage, "wsTemp_offset") == 0) { // Offset de Temperature de -25 a 25 (int8_t -2,5 a 2,5°C)
json["Temp_offset"] = serialized(ftoS(Temp_offset * coef_temp, 1, false));
}
//Vitesse
if (strcmp((char*)nomMessage, "wsVit_Tbase") == 0) { // Numero de la vitesse de Base de 5 a 9 INITIALE 6 int8_t
json["Vit_Tbase"] = Vit_Tbase;
}
if (strcmp((char*)nomMessage, "wsVit_Tinte") == 0) { // Numero de la vitesse Intermediaire de 9 a 13 INITIALE 12 int8_t
json["Vit_Tinte"] = Vit_Tinte;
}
if (strcmp((char*)nomMessage, "wsVit_Tmaxi") == 0) { // Numero de la vitesse Maximum de 13 a 16 INITIALE 14 int8_t
json["Vit_Tmaxi"] = Vit_Tmaxi;
}
if (strcmp((char*)nomMessage, "wsVit_offset") == 0) { // PWM Brut offset de -50 % a +50 % (valeur entre 2 vitesses) int8_t
json["Vit_offset"] = Vit_offset;
}
if (strcmp((char*)nomMessage, "wsrpm") == 0) { // Vitesse moteur tr/min (uint32_t -> 0 - 3000 tr/min)
if (pwm != 0 && rpm == 0 && FlagErrorMoteur_RPM == true) { // Si le moteur ne tourne pas et qu'il est en ERREUR alors que PWM est different de zero
json["rpm"] = "Err.";
}
else {
json["rpm"] = rpm; // Vitesse moteur tr/min uint32_t
json["pwm"] = pwm; // Valeur PWM commande moteur uint16_t
json["CorrPwm"] = correctionPwm; // Correction valeur PWM int8_t
}
if (stepper.isRunning() && stepper.distanceToGo() != 0) {
json["Steppercurrent"] = map2(Steppercurrent, home, maxtravel, DiamIrisMaxi, DiamIrisMini); // Position IRIS (int16_t -> 85 - 200 mm)
if (flag_iris_manu_on_off == false) { // si IRIS mode Auto
json["PosManu"] = json["Steppercurrent"]; // recupere la position vers laquel on va moteur pas a pas [AU CAS OU] on passe en mode Manu
}
}
}
//IRIS Position auto
if (strcmp((char*)nomMessage, "wsSteppercurrent") == 0) { // Position IRIS (int16_t -> 85 - 200 mm)
json["Steppercurrent"] = map2(Steppercurrent, home, maxtravel, DiamIrisMaxi, DiamIrisMini);
if (flag_iris_manu_on_off == false) { // si IRIS mode Auto
json["PosManu"] = json["Steppercurrent"]; // recupere la position vers laquel on va moteur pas a pas [AU CAS OU] on passe en mode Manu
}
}
// map2(value , fromLow, fromHigh , toLow , toHigh) ->[ home = 0 (Diam 200)] -> [maxtravel = 12000 (Diam 85)]
//IRIS Position Manu
if (strcmp((char*)nomMessage, "wsPosManu") == 0) { // Position IRIS Mode Manu(int16_t -> 85 - 200 mm)
json["PosManu"] = map2(TempPosIris, home, maxtravel, DiamIrisMaxi, DiamIrisMini); // recupere la position vers laquel on va moteur pas a pas
// valeur entre 200 et 85
}
//Timer Mode BOOST, Heure Debut Mode Jour, Heure Debut Mode Nuit
if (strcmp((char*)nomMessage, "wsTMB") == 0) { // Timer Mode Boost (long)
json["TMB"] = TIMER_MODE_BOOST;
if (flag_ventilo_boost_on_off == true) {
json["timerb"] = round( ((TIMER_MODE_BOOST * 1000L) - (millis() - timerModeBoost)) / 1000L ); // Duree du mode BOOST (en seconde)
}
}
if (strcmp((char*)nomMessage, "wsHMJ") == 0) { // Heure Debut Mode Jour (long)
json["HMJ"] = START_MODE_JOUR;
}
if (strcmp((char*)nomMessage, "wsHMN") == 0) { // Heure Debut Mode Nuit (long)
json["HMN"] = START_MODE_NUIT;
}
//Sondes de Temperature
if (strcmp((char*)nomMessage, "wssondes") == 0) { // Sondes Temperatures (float -127°C a +125°C)
json["Sext"] = serialized(ftoS(SondeTempC[3], 2, false));
json["Smoteur"] = serialized(ftoS(SondeTempC[0], 2, false));
json["Schaud"] = serialized(ftoS(SondeTempC[1], 2, false));
json["Sfroid"] = serialized(ftoS(SondeTempC[2], 2, false));
}
// Marche / Arret Ventilo (ON / OFF)
if (strcmp((char*)nomMessage, "wsonoff") == 0) {
json["onoff"] = flag_ventilo_on_off ? 1 : 0; // VENTILO on/off (Si flag_ventilo_on_off true ou false) bool
}
if (strcmp((char*)nomMessage, "wsVmanuauto") == 0) {
json["Vmanuauto"] = flag_ventilo_manu_on_off ? 1 : 0; // VENTILO manu/auto (Si flag_ventilo_manu_on_off true ou false) bool
}
if (strcmp((char*)nomMessage, "wsImanuauto") == 0) {
json["Imanuauto"] = flag_iris_manu_on_off ? 1 : 0; // IRIS manu/auto (Si flag_iris_manu_on_off true ou false) bool
if (flag_iris_manu_on_off == true) { // si IRIS mode Manu
json["PosManu"] = map2(Steppercurrent, home, maxtravel, DiamIrisMaxi, DiamIrisMini); // recupere la position actuel du moteur pas a pas ON VIENT D'ACTIVER LE MODE MANU
// valeur entre 0 et 115
}
}
if (strcmp((char*)nomMessage, "wsVboost") == 0) {
json["Vboost"] = flag_ventilo_boost_on_off ? 1 : 0; // VENTILO mode boost (Si flag_ventilo_boost_on_off true ou false) bool
if (flag_ventilo_boost_on_off == true) {
json["timerb"] = round( ((TIMER_MODE_BOOST * 1000L) - (millis() - timerModeBoost)) / 1000L ); // Duree du mode BOOST (en seconde)
}
}
/*
if (strcmp((char*)nomMessage, "wstimerb") == 0) {
if (flag_ventilo_boost_on_off == true) {
json["timerb"] = round( ((TIMER_MODE_BOOST * 1000L) - (millis() - timerModeBoost)) / 1000L ); // Duree du mode BOOST (en seconde)
}
}
*/
if (strcmp((char*)nomMessage, "wsuptime") == 0) {
json["uptime"] = serialized(Uptime);
if (flag_ventilo_boost_on_off == true) {
json["timerb"] = round( ((TIMER_MODE_BOOST * 1000L) - (millis() - timerModeBoost)) / 1000L ); // Duree du mode BOOST (en seconde)
}
}
char data[640];
size_t len = serializeJson(json, data);
if (serialDebug_websocket) { // visuel message + taille
Serial.print("data : ");
Serial.println(data);
Serial.print("len : ");
Serial.println(len);
}
ws.textAll(data, len);
}
// Reception des messages depuis le client (interface WEB)
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
AwsFrameInfo *info = (AwsFrameInfo*)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
if (serialDebug_websocket) {
data[len] = 0; // facultatif AVOIR mode DEBUG
String message = (char*)data; // facultatif AVOIR mode DEBUG
Serial.print("message : ");
Serial.println(message); // facultatif AVOIR mode DEBUG
}
//const uint8_t size = JSON_OBJECT_SIZE(1);
//StaticJsonDocument<size> json;
//StaticJsonDocument<640> json;
JsonDocument json;
DeserializationError err = deserializeJson(json, data);
if (err) {
Serial.print("deserializeJson() failed with code ");
Serial.println(err.c_str());
return;
}
if (json.containsKey("getReadings")) { // Lecture de toute les variables Initialisation de la page
const bool getReadings = json["getReadings"];
if (serialDebug_websocket) {
Serial.print("getReadings : ");
Serial.println(getReadings);
}
notifyClients((char*)"getReadings");
return;
}
// DEBUG A VOIR
if (json.containsKey("getReadings2")) { // Lecture de toute les variables Initialisation de la page
const bool getReadings2 = json["getReadings2"];
if (serialDebug_websocket) {
Serial.print("getReadings2 : ");
Serial.println(getReadings2);
}
notifyClients((char*)"getReadings2");
return;
}
if (json.containsKey("wsonoff")) { // ON / OFF du ventilateur
const bool wsonoff = json["wsonoff"];
if (serialDebug_websocket) {
Serial.print("wsonoff : ");
Serial.println(wsonoff);
}
if (flag_ventilo_on_off != wsonoff) { // AVOIR si DIFF -> UPDATE
flag_ventilo_on_off = wsonoff;
}
notifyClients((char*)"wsonoff");
return;
}
if (json.containsKey("wsVmanuauto")) { // Mode Auto / Manu du Ventilateur
const bool wsVmanuauto = json["wsVmanuauto"];
if (serialDebug_websocket) {
Serial.print("wsVmanuauto : ");
Serial.println(wsVmanuauto);
}
if (flag_ventilo_manu_on_off != wsVmanuauto) { // AVOIR si DIFF -> UPDATE
flag_ventilo_manu_on_off = wsVmanuauto;
if (flag_ventilo_manu_on_off == true) { // passage mode manu TRUE
if (flag_ventilo_boost_on_off == true ) {
flag_ventilo_boost_on_off = false; // reset FLAG mode Boost OFF
notifyClients((char*)"wsVboost");
UpdateSetpointPID(); // MAJ Temperature de consigne // AVOIR
}
}
else { // passage mode auto FALSE
flag_Debug_PWM_Ventilo = false; // force FLAG Debug PWM Ventilo a OFF si ventilo en mode auto
}
}
notifyClients((char*)"wsVmanuauto");
return;
}
// IRIS Manu / Auto
if (json.containsKey("wsImanuauto")) { // Mode Auto / Manu de l'IRIS
const bool wsImanuauto = json["wsImanuauto"];
if (serialDebug_websocket) {
Serial.print("wsImanuauto : ");
Serial.println(wsImanuauto);
}
if (flag_iris_manu_on_off != wsImanuauto) { // AVOIR si DIFF -> UPDATE
flag_iris_manu_on_off = wsImanuauto;
if (flag_iris_manu_on_off == false) { // passage IRIS mode Auto FALSE
if (myPID.GetMode() == MANUAL) { // si PID mode MANUAL
UpdateOutputPID(); // dit au PID ou est l'IRIS avant de passer en mode AUTOMATIC (Pour Affichage Ecran OLED)
//myPID.SetMode(AUTOMATIC); // Deplace dans la (loop())
}
}
}
notifyClients((char*)"wsImanuauto");
return;
}
// IRIS Position MANU
if (json.containsKey("wsPosManu")) { // Deplacement Mode Manu de l'IRIS (Position manuel valeur {"wsPosManu":85(->12000) - 200(->0)})
const int16_t wsPosManu = json["wsPosManu"];
if (serialDebug_websocket) {
Serial.print("wsPosManu : ");
Serial.println(wsPosManu);
}
if (flag_iris_manu_on_off == true && flag_ventilo_on_off == true) { // valide la valeur Mode MANU -> TRUE ET Ventilo etat ON // && flag_auth_deplacement == false // AVOIR
//PosIris (valeur entre 0 et 12000)
//TempPosIris (valeur entre 0 et 12000)
//wsPosManu (valeur entre 85 et 200) [inverse des valeurs voulues]
// map2(value, fromLow, fromHigh, toLow, toHigh) ->[ home = 0 (Diam 200)] -> [maxtravel = 12000 (Diam 85)]
PosIris = round(map2(wsPosManu, DiamIrisMini, DiamIrisMaxi, NbreStepIris, home) * (float)PasStepIris); // ici entree 85(0) et 200(115) sortie -> ajout map2-> 85(115) et 200(0) donne (valeur entre 12000 et 0) -> Normalement OK
PosIris = verifStepIris(PosIris); // verifie que la division par 2 donne Zero (Halfstep) et qu'on n'est pas superieur (home et maxtravel)
TempPosIris = PosIris; // Pour l'AFFICHAGE si rentre dans le menu "IRIS Position"
if (oledMenu.menuTitle == "IRIS Position") { // AVOIR CAS OU ON EST DEJA DANS LE MENU
oledMenu.mValueEntered = round(TempPosIris / (float)PasStepIris); // starting value (recupere l'ancienne demande de mouvement)
}
//if ( stepper.currentPosition() != PosIris ) { // AVOIR si DIFF -> UPDATE
if ( Steppercurrent != PosIris ) { // AVOIR si DIFF -> UPDATE
flag_auth_deplacement = true;
}
}
notifyClients((char*)"wsPosManu");
return;
}
// MODE BOOST
if (json.containsKey("wsVboost")) { // Mode Boost ON / OFF du ventilateur
const bool wsVboost = json["wsVboost"];
if (serialDebug_websocket) {
Serial.print("wsVboost : ");
Serial.println(wsVboost);
}
if (flag_ventilo_boost_on_off != wsVboost) { // AVOIR si DIFF -> UPDATE
flag_ventilo_boost_on_off = wsVboost;
if (flag_ventilo_boost_on_off == true) { // passage mode BOOST ON
timerModeBoost = millis(); // Save time declenchement mode BOOST
if (flag_ventilo_manu_on_off == true) {
flag_ventilo_manu_on_off = false; // reset FLAG mode manu OFF (ICI Donc MODE AUTO(FALSE))
//Envoie la valeur de VENTILO manu/auto -> WEBSOCKET (flag_ventilo_manu_on_off) //AVOIR WEBSOCKET NEW
notifyClients((char*)"wsVmanuauto");
}
}
UpdateSetpointPID();
}
notifyClients((char*)"wsVboost");
return;
}
//PID TEMPERATURE
if (json.containsKey("wsConsignePID")) { // Temperature de consigne Sonde moteur PID (int16_t 535 -> 53.5°C)
const float wsConsignePID = json["wsConsignePID"];
if (serialDebug_websocket) {
Serial.print("wsConsignePID : ");
Serial.println(wsConsignePID);
}
if (ConsignePID != wsConsignePID * 10) { // AVOIR si DIFF -> UPDATE
ConsignePID = wsConsignePID * 10; // Temperature de consigne Sonde moteur PID (int16_t 535 -> 53.5°C)
UpdateSetpointPID();
}
notifyClients((char*)"wsConsignePID");
return;
}
if (json.containsKey("wsConsignePID_coupure")) { // Temperature de coupure PID (int16_t 370 -> 37°C)
const float wsConsignePID_coupure = json["wsConsignePID_coupure"];
if (serialDebug_websocket) {
Serial.print("wsConsignePID_coupure : ");
Serial.println(wsConsignePID_coupure);
}
if (ConsignePID_coupure != wsConsignePID_coupure * 10) { // AVOIR si DIFF -> UPDATE
ConsignePID_coupure = wsConsignePID_coupure * 10; // Temperature de coupure PID (int16_t 370 -> 37°C)
}
notifyClients((char*)"wsConsignePID_coupure");
return;
}
//VENTILATEUR TEMPERATURE
if (json.containsKey("wsTemp_ON_moteur")) { // Temperature de consigne mini ON Moteur (Temperature chaud) (int16_t 410 -> 40°C)
const float wsTemp_ON_moteur = json["wsTemp_ON_moteur"];
if (serialDebug_websocket) {
Serial.print("wsTemp_ON_moteur : ");
Serial.println(wsTemp_ON_moteur);
}
if (Temp_ON_moteur != wsTemp_ON_moteur * 10) { // AVOIR si DIFF -> UPDATE
Temp_ON_moteur = wsTemp_ON_moteur * 10; // Temperature de consigne mini ON Moteur (Temperature chaud) (int16_t 410 -> 40°C)
}
notifyClients((char*)"wsTemp_ON_moteur");
return;
}
if (json.containsKey("wsTemp_OFF_moteur")) { // Temperature de consigne maxi OFF Moteur (Temperature moteur) (int16_t 550 -> 55°C)
const float wsTemp_OFF_moteur = json["wsTemp_OFF_moteur"];
if (serialDebug_websocket) {
Serial.print("wsTemp_OFF_moteur : ");
Serial.println(wsTemp_OFF_moteur);
}
if (Temp_OFF_moteur != wsTemp_OFF_moteur * 10) { // AVOIR si DIFF -> UPDATE
Temp_OFF_moteur = wsTemp_OFF_moteur * 10; // Temperature de consigne maxi OFF Moteur (Temperature moteur) (int16_t 550 -> 55°C)
}
notifyClients((char*)"wsTemp_OFF_moteur");
return;
}
if (json.containsKey("wsHyst_Temp_ON_moteur")) { // Hysteresis temperature moteur ON (Chaud 1er demarrage) (int16_t 50 -> 5°C)
const float wsHyst_Temp_ON_moteur = json["wsHyst_Temp_ON_moteur"];
if (serialDebug_websocket) {
Serial.print("wsHyst_Temp_ON_moteur : ");
Serial.println(wsHyst_Temp_ON_moteur);
}
if (Hyst_Temp_ON_moteur != wsHyst_Temp_ON_moteur * 10) { // AVOIR si DIFF -> UPDATE
Hyst_Temp_ON_moteur = wsHyst_Temp_ON_moteur * 10; // Hysteresis temperature moteur ON (Chaud 1er demarrage) (int16_t 50 -> 5°C)
}
notifyClients((char*)"wsHyst_Temp_ON_moteur");
return;
}
//VENTILATEUR VITESSE
if (json.containsKey("wsVit_jour")) { // Vitesse Mode Jour (uint8_t -> 12)
const uint8_t wsVit_jour = json["wsVit_jour"];
if (serialDebug_websocket) {
Serial.print("wsVit_jour : ");
Serial.println(wsVit_jour);
}
if (Vit_jour != wsVit_jour) { // AVOIR si DIFF -> UPDATE
Vit_jour = wsVit_jour; // Vitesse Mode Jour (uint8_t -> 12)
}
notifyClients((char*)"wsVit_jour");
return;
}
if (json.containsKey("wsVit_nuit")) { // Vitesse Mode Nuit (uint8_t -> 0)
const uint8_t wsVit_nuit = json["wsVit_nuit"];
if (serialDebug_websocket) {
Serial.print("wsVit_nuit : ");
Serial.println(wsVit_nuit);
}
if (Vit_nuit != wsVit_nuit) { // AVOIR si DIFF -> UPDATE
Vit_nuit = wsVit_nuit; // Vitesse Mode Nuit (uint8_t -> 0)
}
notifyClients((char*)"wsVit_nuit");
return;
}
if (json.containsKey("wsVit_boost")) { // Vitesse Mode Boost (uint8_t -> 16)
const uint8_t wsVit_boost = json["wsVit_boost"];
if (serialDebug_websocket) {
Serial.print("wsVit_boost : ");
Serial.println(wsVit_boost);
}
if (Vit_boost != wsVit_boost) { // AVOIR si DIFF -> UPDATE
Vit_boost = wsVit_boost; // Vitesse Mode Boost (uint8_t -> 16)
}
notifyClients((char*)"wsVit_boost");
return;
}
//TIME Mode VENTILATEUR (Boost, Jour Nuit)
if (json.containsKey("wsTMB")) { // Timer Mode Boost (long) [TIMER_MODE_BOOST]
const long wsTMB = json["wsTMB"];
if (serialDebug_websocket) {
Serial.print("wsTMB [TIMER_MODE_BOOST] : ");
Serial.println(wsTMB);
}
if (TIMER_MODE_BOOST != wsTMB) { // AVOIR si DIFF -> UPDATE
TIMER_MODE_BOOST = wsTMB; // Timer Mode Boost (long)
}
notifyClients((char*)"wsTMB");
return;
}
if (json.containsKey("wsHMJ")) { // Heure Debut Mode Jour (long) [START_MODE_JOUR]
const long wsHMJ = json["wsHMJ"];
if (serialDebug_websocket) {
Serial.print("wsHMJ [START_MODE_JOUR] : ");
Serial.println(wsHMJ);
}
if (START_MODE_JOUR != wsHMJ) { // AVOIR si DIFF -> UPDATE
START_MODE_JOUR = wsHMJ; // Heure Debut Mode Jour (long)
}
notifyClients((char*)"wsHMJ");
return;
}
if (json.containsKey("wsHMN")) { // Heure Debut Mode Nuit (long) [START_MODE_NUIT]
const long wsHMN = json["wsHMN"];
if (serialDebug_websocket) {
Serial.print("wsHMN [START_MODE_NUIT] : ");
Serial.println(wsHMN);
}
if (START_MODE_NUIT != wsHMN) { // AVOIR si DIFF -> UPDATE
START_MODE_NUIT = wsHMN; // Heure Debut Mode Nuit (long)
}
notifyClients((char*)"wsHMN");
return;
}
//VITESSE DYNAMIQUE
if (json.containsKey("wsVit_Tbase")) { // Numero de la vitesse de Base de 5 a 9 INITIALE 6 (int8_t)
const int8_t wsVit_Tbase = json["wsVit_Tbase"];
if (serialDebug_websocket) {
Serial.print("wsVit_Tbase : ");
Serial.println(wsVit_Tbase);
}
if (Vit_Tbase != wsVit_Tbase) { // AVOIR si DIFF -> UPDATE
Vit_Tbase = wsVit_Tbase; // Numero de la vitesse de Base de 5 a 9 (int8_t -> 6)
seuilVitesseB = VitesseVentil[Vit_Tbase] + offsetNormalisation(Vit_Tbase, Vit_offset);
}
notifyClients((char*)"wsVit_Tbase");
return;
}
if (json.containsKey("wsVit_Tinte")) { // Numero de la vitesse Intermediaire de 9 a 13 INITIALE 12 (int8_t)
const int8_t wsVit_Tinte = json["wsVit_Tinte"];
if (serialDebug_websocket) {
Serial.print("wsVit_Tinte : ");
Serial.println(wsVit_Tinte);
}
if (Vit_Tinte != wsVit_Tinte) { // AVOIR si DIFF -> UPDATE
Vit_Tinte = wsVit_Tinte; // Numero de la vitesse Intermediaire de 9 a 13 (int8_t -> 12)
seuilVitesseI = VitesseVentil[Vit_Tinte] + offsetNormalisation(Vit_Tinte, Vit_offset);
}
notifyClients((char*)"wsVit_Tinte");
return;
}
if (json.containsKey("wsVit_Tmaxi")) { // Numero de la vitesse Maximum de 13 a 16 INITIALE 14 (int8_t)
const int8_t wsVit_Tmaxi = json["wsVit_Tmaxi"];
if (serialDebug_websocket) {
Serial.print("wsVit_Tmaxi : ");
Serial.println(wsVit_Tmaxi);
}
if (Vit_Tmaxi != wsVit_Tmaxi) { // AVOIR si DIFF -> UPDATE
Vit_Tmaxi = wsVit_Tmaxi; // Numero de la vitesse Maximum de 13 a 16 (int8_t -> 14)
seuilVitesseMa = VitesseVentil[Vit_Tmaxi] + offsetNormalisation(Vit_Tmaxi, Vit_offset);
}
notifyClients((char*)"wsVit_Tmaxi");
return;
}
if (json.containsKey("wsVit_offset")) { // PWM Brut offset de -50 % a +50 % (valeur entre 2 vitesses) INITIALE 0 % (int8_t)
const int8_t wsVit_offset = json["wsVit_offset"];
if (serialDebug_websocket) {
Serial.print("wsVit_offset : ");
Serial.println(wsVit_offset);
}
if (Vit_offset != wsVit_offset) { // AVOIR si DIFF -> UPDATE
Vit_offset = wsVit_offset; // PWM Brut offset de -50 % a +50 % (valeur entre 2 vitesses) (int8_t -> 0 %)
seuilVitesseB = VitesseVentil[Vit_Tbase] + offsetNormalisation(Vit_Tbase, Vit_offset);
seuilVitesseI = VitesseVentil[Vit_Tinte] + offsetNormalisation(Vit_Tinte, Vit_offset);
seuilVitesseMa = VitesseVentil[Vit_Tmaxi] + offsetNormalisation(Vit_Tmaxi, Vit_offset);
}
notifyClients((char*)"wsVit_offset");
return;
}
//TEMPERATURE DYNAMIQUE
if (json.containsKey("wsTemp_Vbase")) { // Seuil Temperature de Base 50 a 250 (int16_t 5 a 25°C)
const float wsTemp_Vbase = json["wsTemp_Vbase"];
if (serialDebug_websocket) {
Serial.print("wsTemp_Vbase : ");
Serial.println(wsTemp_Vbase);
}
if (Temp_Vbase != wsTemp_Vbase * 10) { // AVOIR si DIFF -> UPDATE
Temp_Vbase = wsTemp_Vbase * 10; // Seuil Temperature de Base 50 a 250 (int16_t 5 a 25°C)
seuilTempB = (Temp_Vbase + Temp_offset) * coef_temp;
}
notifyClients((char*)"wsTemp_Vbase");
return;
}
if (json.containsKey("wsTemp_Vinte")) { // Seuil Temp. Inter. de -50 a 50 (int8_t -5 a 5°C)
const float wsTemp_Vinte = json["wsTemp_Vinte"];
if (serialDebug_websocket) {
Serial.print("wsTemp_Vinte : ");
Serial.println(wsTemp_Vinte);
}
if (Temp_Vinte != wsTemp_Vinte * 10) { // AVOIR si DIFF -> UPDATE
Temp_Vinte = wsTemp_Vinte * 10; // Seuil Temp. Inter. de -50 a 50 (int8_t -5 a 5°C)
seuilTempI = (Temp_Vinte + Temp_offset) * coef_temp;
}
notifyClients((char*)"wsTemp_Vinte");
return;
}
if (json.containsKey("wsTemp_Vmini")) { // Seuil Temp. Mini de -250 a -50 (int16_t -25 a -5°C)
const float wsTemp_Vmini = json["wsTemp_Vmini"];
if (serialDebug_websocket) {
Serial.print("wsTemp_Vmini : ");
Serial.println(wsTemp_Vmini);
}
if (Temp_Vmini != wsTemp_Vmini * 10) { // AVOIR si DIFF -> UPDATE
Temp_Vmini = wsTemp_Vmini * 10; // Seuil Temp. Mini de -250 a -50 (int16_t -25 a -5°C)
seuilTempMi = (Temp_Vmini + Temp_offset) * coef_temp;
}
notifyClients((char*)"wsTemp_Vmini");
return;
}
if (json.containsKey("wsTemp_offset")) { // Offset de Temperature de -25 a 25 (int8_t -2,5 a 2,5°C)
const float wsTemp_offset = json["wsTemp_offset"];
if (serialDebug_websocket) {
Serial.print("wsTemp_offset : ");
Serial.println(wsTemp_offset);
}
if (Temp_offset != wsTemp_offset * 10) { // AVOIR si DIFF -> UPDATE
Temp_offset = wsTemp_offset * 10; // Offset de Temperature de -25 a 25 (int8_t -2,5 a 2,5°C)
seuilTempB = (Temp_Vbase + Temp_offset) * coef_temp;
seuilTempI = (Temp_Vinte + Temp_offset) * coef_temp;
seuilTempMi = (Temp_Vmini + Temp_offset) * coef_temp;
}
notifyClients((char*)"wsTemp_offset");
return;
}
}
}
// Gestion des evenements du websocket
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
switch (type) {
case WS_EVT_CONNECT:
//if (serialDebug_websocket) Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); //AVOIR LOG client CONNECT
break;
case WS_EVT_DISCONNECT:
//if (serialDebug_websocket) Serial.printf("WebSocket client #%u disconnected\n", client->id()); //AVOIR LOG client DISCONNECT
break;
case WS_EVT_DATA:
handleWebSocketMessage(arg, data, len);
break;
case WS_EVT_PONG:
//if (serialDebug_websocket) Serial.printf("Pong:\n\tClient id:%u\n", client->id());
break;
case WS_EVT_ERROR:
//if (serialDebug_websocket) Serial.printf("Error:\n\tClient id:%u\n", client->id());
break;
}
}
// Initialise le websocket
void InitWebSocket() {
ws.onEvent(onEvent);
server.addHandler(&ws);
}
// *********************
// *** FIN WEBSOCKET ***
// *********************
//Fonction Temps demarrage ESP32
String fuptime() {
String uptime = String(esp_timer_get_time());
//Serial.print("uptime1 : ");
//Serial.println(uptime);
uptime = uptime.substring(0, uptime.length() - 6); // supprime les 6 derniers caractere (div par 1000, div par 1000)
if (uptime != nullptr) {
//Serial.print("uptime2 : ");
//Serial.println(uptime);
return String(uptime);
}
else {
//Serial.println("uptime3 : 0");
return "0";
}
}
// Fonction pour redemarrer l'ESP32
void RestartESP() {
if ((millis() - timerRestartESP) >= 10000 && flag_restart_esp == true) { // delais de 10 secondes avant Redemarrage
oledClearDisplay();
ESP.restart();
}
}
// ************************
// ******** SETUP *********
// ************************
void setup() {
timesetup = millis();
if (serialDebug_ram) {
MiniFreeHeap = ESP.getHeapSize();
}
Uptime = "0";
// Initialisation Serial
InitSerial();
//Fin INIT SERIAL
// Initialisation de l'écran OLED
InitOLED();
//FIN INIT OLED
// Initialisation PWM
InitPWM();
// FIN INIT PWM
//Initialisation SD CARD
InitSDCard();
// FIN INIT SD CARD
// DEBUT : ENCODEUR
// Set encoder pins and attach interrupts
pinMode(ENC_A, INPUT); //CLK
pinMode(ENC_B, INPUT); // DT
pinMode(ENC_SW, INPUT); // SW (bouton)
attachInterrupt(digitalPinToInterrupt(ENC_A), read_encoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENC_B), read_encoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENC_SW), read_button, CHANGE);
// FIN : ENCODEUR
// INIT DEBUT RPM
// Set Compteur RPM pins
pinMode(IN_RPM, INPUT); // Compteur RPM
// Compteur RPM IN_RPM
attachInterrupt(digitalPinToInterrupt(IN_RPM), read_RPM, CHANGE); // Front montant et descandant
// FIN RPM
// STEPPER MOTOR
// Limit switch Pin
pinMode(LSW_HOME, INPUT_PULLUP); // LSW_HOME pin 14 -> Passage a PULLUP externe (initial INPUT_PULLUP interne) BUG Parasite reseau electrique avec PULLUP interne
pinMode(LSW_MAXTRAVEL, INPUT_PULLUP); // LSW_MAXTRAVEL pin 15 -> Passage a PULLUP externe (initial INPUT_PULLUP interne) BUG Parasite reseau electrique avec PULLUP interne
// Limit switch Interrupt
attachInterrupt(digitalPinToInterrupt(LSW_HOME), read_limite_switch_Home, CHANGE);
attachInterrupt(digitalPinToInterrupt(LSW_MAXTRAVEL), read_limite_switch_MaxTravel, CHANGE);
//Initialisation TimeZone
InitTimeZone(time_zone);
//FIN INIT TimeZone
// Initialisation NTP Serveur
InitNTPServer();
//Fin NTP Serveur
//Initialisation connection WIFI
InitWifi();
//FIN INIT WIFI
// Initialisation WEBSOCKET
InitWebSocket();
//FIN INIT WEBSOCKET
// Initialisation WEBSERVER
InitServerWeb();
//FIN INIT WEBSERVER
// INITIALISATION SONDE TEMPERATURE
//InitSondes(memSondesAddr, nbreSondes); // DEBUG WOKWI
// FIN Init Sonde Temperature
// INIT DS18B20 library (Dallas Temperature sensor)
//InitDallas(); // DEBUG WOKWI
// FIN Init DS18B20 library (Dallas Temperature sensor)
// INIT STEPPER MOTOR
InitIris(); // DEBUG WOKWI
// FIN Init STEPPER MOTOR
// Initialisation de la config
chargeConfig(true);
// Fin INIT Config
// Initialisation Seuil Vitesse et Temperature (Vitesse Dynamique)
InitSeuilVitDyn();
// Fin INIT Seuil Vitesse et Temperature (Vitesse Dynamique)
// INIT PID
// [A Faire apres InitIris() et apres InitSondes() et apres sensors.begin()]
InitPid();
// FIN Init PID
// *****************************************
// AJOUT concatenation des INITS A FAIRE
// *****************************************
// En fin de setup
//Reset Bouton Encodeur:
ENC_SW_state_short = LOW;
ENC_SW_state_long = LOW;
// display greeting message - pressing button will start menu
displayMessage("STARTED", "INIT OK");
// Mesure temps du SETUP A SUPPRIMER
Serial.print("Temps SETUP FIN : ");
Serial.print(millis() - timesetup);
Serial.println(" ms");
}
// *****************
// *** FIN SETUP ***
// *****************
// ************************
// ******** LOOP **********
// ************************
void loop() {
//timeloop = millis();
// Redemarrage ESP32 si choix Menu
RestartESP();
// Menu (Ecran OLED)
menuUpdate(); // update or action the oled menu
//RESET Mode BOOST
// VENTILATEUR : DESACTIVATION Mode BOOST repasse a OFF apres 1H (TIMER_MODE_BOOST * 1000L)
if ((millis() - timerModeBoost) >= (TIMER_MODE_BOOST * 1000L) && flag_ventilo_boost_on_off == true) { // Toutes les 1 heures
//timerModeBoost = millis();
flag_ventilo_boost_on_off = false; // reset FLAG mode BOOST apres 1 heures
UpdateSetpointPID();
notifyClients((char*)"wsVboost");
}
// **************************************
// *** GESTION SONDES DE TEMPERATURES ***
// **************************************
// 1. DEMANDE
// Flag Demande la Temperature des 4 Sondes avec Timer
if ((millis() - lastTimeRequestTemp) >= intervalRequestTemp && flag_auth_request_Temp == false) { // toutes les 4.250 secondes
lastTimeRequestTemp = millis();
flag_auth_request_Temp = true; // Flag pour authorisation de requete aux sondes
}
// Demande la Temperature des 4 Sondes
if (flag_auth_request_Temp == true) {
if ((millis() - lastTimeDemandeTemp) >= 50) { // toutes les 0.050 secondes
lastTimeDemandeTemp = millis();
if (serialDebug_sondes) {
Serial.print("Request (");
Serial.print(countSondeDemande);
Serial.print(") : ");
printAddress(memSondesAddr[countSondeDemande]);
Serial.println();
}
sensors.requestTemperaturesByAddress(memSondesAddr[countSondeDemande]);
countSondeDemande++;
if (countSondeDemande == nbreSondes) {
countSondeDemande = 0; // Reset compteur nbre de sondes pour requete de temperature
flag_auth_request_Temp = false; // Reset Flag autorisation request Temperature
flag_request_Temp_done = true; // Passage a TRUE Flag des 4 requete de temperature faite (maintenant wait for conversion des sondes)
}
}
}
// 2. LECTURE
// Flag Lecture de la temperature avec Timer
if (((millis() - lastTimeRequestTemp) >= intervalConversionSonde) && flag_request_Temp_done == true) { // 0.750 seconde apres la Demande de temperature (resolution 12 bits)
lastTimeRequestTemp = millis(); // AVOIR on reset encore une fois lastTimeRequestTemp pour avoir 5 sec entre 2 demandes (4.250 secondes + 0.750 seconde)
flag_auth_lecture_Temp = true;
}
// Lecture de la temperature apres le temps de conversion (en fonction de la resolution)
if (flag_auth_lecture_Temp == true) {
if ((millis() - lastTimeReadTemp) >= 50) { // toutes les 0.050 secondes
lastTimeReadTemp = millis();
if (serialDebug_sondes) {
Serial.print("Lecture (");
Serial.print(countSondeRead);
Serial.print(") : ");
printAddress(memSondesAddr[countSondeRead]);
Serial.print(", Valeur : ");
Serial.println(SondeTempC[countSondeRead]);
}
SondeTempC[countSondeRead] = readDSTemperatureC(memSondesAddr[countSondeRead], countSondeRead); // Lit la valeur de la sonde apres avoir fait la demande
countSondeRead++;
if (countSondeRead == nbreSondes) {
countSondeRead = 0; // Reset compteur nbre de sondes pour requete de temperature
flag_request_Temp_done = false; // Reset flag requete temperature faite
flag_auth_lecture_Temp = false; // Reset flag authorisation lecture Sonde (Temps de conversion)
flag_auth_traitmnt_Temp = true; // Flag authorisation traitement Lecture Sonde ok
}
}
}
// 3. TRAITEMENT (Toutes les valeurs de temperature des sondes sont a jour)
// Une fois toutes les 4 sondes lu on traite le PID
if (flag_auth_traitmnt_Temp == true) {
//SondeNom[] = {"Smoteur", "Schaud", "Sfroid", "Sext", "SFlag"};
static int8_t pp = 0; // DEBUG WOKWI
if ( 0 <= pp && pp <= 3 ) { // DEBUG WOKWI
SondeTempC[pp] = -85;
pp++;
if (pp == 4) {
pp=0;
}
} // DEBUG WOKWI
if (serialDebug_sondes) {
String TestSonde = "'SONDES': { '";
TestSonde += SondeNom[3];
TestSonde += "': ";
TestSonde += ftoS(SondeTempC[3], 2, true); // Sonde Extérieure
TestSonde += ", '";
TestSonde += SondeNom[0];
TestSonde += "': ";
TestSonde += ftoS(SondeTempC[0], 2, true); // Sonde Moteur
TestSonde += ", '";
TestSonde += SondeNom[1];
TestSonde += "': ";
TestSonde += ftoS(SondeTempC[1], 2, true); // Sonde Chaud
TestSonde += ", '";
TestSonde += SondeNom[2];
TestSonde += "': ";
TestSonde += ftoS(SondeTempC[2], 2, true); // Sonde Froid
TestSonde += "}";
Serial.println(TestSonde);
}
//Envoie les valeurs sondes (Toutes les 5 sec) WEBSOCKET
notifyClients((char*)"wssondes");
//Deplacement dans gestionVentiloEtPid() (A la Fin)
//flag_auth_traitmnt_Temp = false; // Reset Flag authorisation traitement valeur sonde de Temperature // NEW AVOIR SONDE
}
// ******************************************
// *** FIN GESTION SONDES DE TEMPERATURES ***
// ******************************************
// ***************************************
// *** GESTION VENTILATEUR ET PID IRIS ***
// ***************************************
// 4. TRAITEMENT PID (valeur sondes) sauf durant lecture des sondes
if (flag_auth_lecture_Temp == false) { // si pas en train de lire les sondes de temperature
// Gestion PID et Mode ventilateur : Si sonde chaud sup à 40°C et sonde moteur inf 55°C allume moteur
gestionVentiloEtPid(); //commande PWM ventilo-> tout le temp, PID -> toutes les 5 sec
// Gestion PWM ventilateur (update valeur PWM) : Mode du ventilateur ON/OFF, JOUR/NUIT, BOOST, MANU
ventiloUpdate();
}
/*
if (flag_auth_traitmnt_Temp == true) {
flag_auth_traitmnt_Temp = false; // Reset Flag authorisation traitement valeur sonde de Temperature // NEW AVOIR SONDE
}
*/
// Gestion PID IRIS
myPID.Compute(); // tourne a chaque boucle si PID Mode AUTOMATIC fait quelque chose sinon (Mode MANUAL) ne fait rien
//UPDATE PosIris --> OutputPID : SI PID mode AUTO (commande IRIS)
if (flag_iris_manu_on_off == false && myPID.GetMode() == AUTOMATIC && Flag_init_PID_temp_mini_moteur == true && stepper.distanceToGo() == 0) { // Si IRIS (FLAG Mode AUTO -> FALSE) et (PID Mode AUTOMATIC) et (FLAG init temp mini sonde moteur -> TRUE et le moteur de l'iris ne bouge pas deja)
//if (serialDebug_PID) {
//static double lastOutputPID = stepper.currentPosition(); // Erreur compilation si dans boucle IF
static double lastOutputPID = Steppercurrent; // Erreur compilation si dans boucle IF
//}
int8_t OutputPIDPosIris = round(OutputPID / (float)PasStepIris); // (valeur entre 0 et 115)
// -> 111.389
//int8_t CurrentPosIris = round(stepper.currentPosition() / (float)PasStepIris); // (valeur entre 0 et 115)
int8_t CurrentPosIris = round(Steppercurrent / (float)PasStepIris); // (valeur entre 0 et 115)
// -> 115
// si nouvelle position IRIS
if (OutputPIDPosIris != CurrentPosIris) { // (valeur entre 0 et 115)
PosIris = round(OutputPIDPosIris * (float)PasStepIris); // (valeur entre 0 et 12000)
PosIris = verifStepIris(PosIris); // verifie que la division par 2 donne Zero (Halfstep) et qu'on n'est pas superieur (home et maxtravel)
flag_auth_deplacement = true; // Autorise le deplacement de l'IRIS
if (serialDebug_PID) {
Serial.println();
Serial.print("OutputPID : ");
Serial.println(OutputPID); // (valeur entre 0 et 12 000)
Serial.print("OutputPIDPosIris : ");
Serial.println(OutputPIDPosIris); // (valeur entre 0 et 115) [OutputPID]
Serial.print("CurrentPosIris : ");
Serial.println(CurrentPosIris); // (valeur entre 0 et 115)
Serial.print("PosIris : ");
Serial.println(PosIris); // (valeur entre 0 et 12 000)
Serial.println();
}
if (serialDebug_PID) {
Serial.print("SetpointPID:");
Serial.print(SetpointPID); // *100
Serial.print(",");
Serial.print("InputPID:");
Serial.print(InputPID); // *100
Serial.print(",");
Serial.print("OutputPID:");
Serial.print((double)((OutputPID*100)/maxtravel)); // Normalisation (0 -> 100%)
Serial.print(" , Nbre pas :");
Serial.print((int)(OutputPID - lastOutputPID));
Serial.print(" , PID Mode :");
Serial.print(PidMod);
Serial.print(" , PosIris :");
Serial.println(PosIris);
lastOutputPID = OutputPID;
}
}
}
// Fin Gestion PID IRIS
// Gestion deplacement IRIS entre home et maxtravel (Mode Auto et Manu)
moteurDeplacementVers(PosIris);
//Serial.print("stepper.distanceToGo() -> ");
//Serial.println(stepper.distanceToGo());
// Echantillonage Compteur RPM (Tourne toutes les secondes)
echantillonageRPM();
// *******************************************
// *** FIN GESTION VENTILATEUR ET PID IRIS ***
// *******************************************
// Mise a Jour heure (synchro) et log fichier data date du jour (SD CARD)
time_t now = time(nullptr);
struct tm * timeinfo;
timeinfo = localtime(&now);
AjoutOffsetY2038(timeinfo); // BUG 2038 ajout offset pour 2038
if (Flag_HeureAccueil == false && (Flag_firstTimeUpdateNTP == true || Flag_Manual_Date == true) && getLocalTime2(timeinfo, 0)) {
// Format "%H"
snprintf(HeureAccueil, 3, "%02d", timeinfo->tm_hour); // heure accueil 1er RUN
// Format "%M"
snprintf(MinutAccueil, 3, "%02d", timeinfo->tm_min); // minute accueil 1er RUN
//snprintf(YearAccueil, 5, "%04d", timeinfo->tm_year + 1900 + offsetDateY2038); // si 1970 BUG pas eu le temps de rafraichir
Uptime = fuptime();
notifyClients((char*)"wsuptime");
Flag_HeureAccueil = true;
}
if (((timeinfo->tm_min % 1) == 0) && timeinfo->tm_sec == 0 && (Flag_firstTimeUpdateNTP == true || Flag_Manual_Date == true) && getLocalTime2(timeinfo, 0) && (millis() - previousWrite >= 2000)) { // toutes les 1 min (timeinfo->tm_min % 1) == 0) + Timout 2sec (previousWrite)
previousWrite = millis();
// Format "%H"
snprintf(HeureAccueil, 3, "%02d", timeinfo->tm_hour); // heure accueil
// Format "%M"
snprintf(MinutAccueil, 3, "%02d", timeinfo->tm_min); // minute accueil
Uptime = fuptime();
notifyClients((char*)"wsuptime");
if ((timeinfo->tm_min % 5) == 0) { // toutes les 5 min (timeinfo->tm_min % 5) == 0) -> Enregistrement carte SD
printLocalTime(timeinfo);
createfileSD(); // créé met a jour le fichier du jour et de la veille repertoire etc...(creation fichier sur carte SD )
//readFile(SD, YearMonthDayFile); // lit le fichier du jour Temporaire
//Serial.println();
}
/*
if ((timeinfo->tm_wday == 0 && timeinfo->tm_hour == 1 && timeinfo->tm_min == 1)) { // Tous les dimanches (tm_wday 0-6 -> 0 Dimanche) a 1h01 Restart ESP32
RestartESP();
}
*/
}
// FIN Mise a Jour heure (synchro) et log fichier data date du jour
// Affiche la RAM disponible
//static unsigned long lastTimeRequestRamStatus = 0;
if (serialDebug_ram) {
if ((millis() - lastTimeRequestRamStatus) >= 1000) { // toutes les 1 secondes
lastTimeRequestRamStatus = millis();
if (ESP.getMinFreeHeap() < MiniFreeHeap) {
MiniFreeHeap = ESP.getMinFreeHeap();
//const size_t capacity = ESP.getMaxAllocHeap(); // ESP32
//uint32_t getMinFreeHeap(); //lowest level of free heap since boot
Serial.println("");
Serial.printf("Total Heap Size: %d\n", ESP.getHeapSize());
Serial.printf("Available Heap: %d\n", ESP.getFreeHeap());
Serial.printf("Used heap: %d\n", (ESP.getHeapSize() - ESP.getFreeHeap()));
//Serial.printf("Lowest level of heap since boot: %d\n",ESP.getMinFreeHeap());
Serial.printf("Lowest level of heap since boot: %d\n",MiniFreeHeap);
Serial.printf("Largest block of heap that can be allocated at once: %d\n",ESP.getMaxAllocHeap());
//Serial.printf("Total PSRAM: %d\n", ESP.getPsramSize());
//Serial.printf("Free PSRAM: %d\n", ESP.getFreePsram());
Serial.println("");
}
}
}
/*
if (digitalRead(LSW_MAXTRAVEL) == LOW) {
Serial.println("LSW_MAXTRAVEL");
}
if (digitalRead(LSW_HOME) == LOW) {
Serial.println("LSW_HOME");
}
*/
ws.cleanupClients(); // Deconnect les client WEBSOCKET
//Serial.print("Temps LOOP FIN :");Serial.print(millis() - timeloop);Serial.println(" ms");
}
// ****************
// *** FIN LOOP ***
// ****************
/*
-Si (temp chaud sup 40°C) ET (temp moteur inf 55°C) ET (ventilo ON)
-> demarre ventilateur PWM
-Boost
-Manu
-Auto :
-jour
-nuit
--Si PID Menu Mode Auto
--Si mode Boost
-> Boost = 10°C
--Sinon
-> Boost = 0
Consigne = Consigne + Boost + Marge Flottante
---Si [temp moteur sup à (consigne - 5°C)] ET (init flag == false) --> (INIT demarrage PID)
-> init flag -> true
---Si [temp moteur inf à (consigne -5°C)] ET (init flag == true) ET (IRIS a maxtravel) ET (PID UP) --> (INIT arret PID et Moteur)
-> Reset init flag -> false --> OK
-> Arret ventilo --> OK
-> Arret PID --> OK
-> Reset Boost --> OK
-> Reset Mode Boost --> OK
-> Reset Marge Flottante --> OK
-> Reset Init IRIS Position
---Si init flag == true
-> demarrage PID
---Si PID UP
Max consigne inf temp max moteur - 1°C
Hysteresys consigne +/- 0,5°C
-> Gestion PID en fonction Temp
-Tuning PID variable
--Sinon PID Menu Mode Manu
-> arret PID --> OK
-> Reset Boost --> OK
-> Reset Marge Flottante --> OK
-> Reset Init flag -> false --> OK
-Sinon (ventilo OFF) ou (temp chaud inf 40°C) ou (temp moteur sup 55°C)
-> arret ventilo --> OK
--Si PID UP
-> arret PID --> OK
-> Reset Init IRIS Position --> OK
-> Reset Boost --> OK
-> Reset Mode Boost --> OK
-> Reset Marge Flottante --> OK
-> Reset Init flag -> false --> OK
*/
Loading
ssd1306
ssd1306