+ an interface to program the controler

+ an interface to program the controler

--- relais_serre_LCDi2c_V.3.ino
+++ relais_serre_LCDi2c_V.3.ino
@@ -1,193 +1,197 @@
-//--------------LCD 20x4--------------------
+#include <EEPROM.h>
+#include <avr/pgmspace.h>
+//---------------------LCD-------------------
 #include <Wire.h>
 #include <LCD.h>
 #include <LiquidCrystal_I2C.h>

-#define I2C_ADDR    0x22  // Define I2C Address where the PCF8574A is
+#define I2C_ADDR    0x22              // Define I2C Address where the PCF8574A is
 #define BACKLIGHT_PIN     3
+
 LiquidCrystal_I2C  lcd(I2C_ADDR,2,1,0,4,5,6,7);
-/* En_pin  2, Rw_pin  1, Rs_pin  0, D4_pin  4, D5_pin  5, D6_pin  6, D7_pin  7
- */
-//-------------------------Horloge-----------------
+//---------------------RTC--------------------
 #include <DS3231.h>
 DS3231  rtc(SDA, SCL);                // Init the DS3231 using the hardware interface
-Time  t;                        // Init a Time-data structure
-//--------------DHT11--------------------
+Time  t;
+
 #include <DHT.h>
-#define DHTPIN A1
-#define DHTTYPE           DHT11         // Uncomment the type of sensor in use:
+#define DHTPIN            A1          // Pin which is connected to the DHT sensor.
+#define DHTTYPE           DHT11       // Uncomment the type of sensor in use:
 DHT dht(DHTPIN, DHTTYPE);
+int yr; byte mt; byte dy; byte hr; byte mn; byte sc;
+
+//--------------------LCD Menu----------------
+//menuPin
+boolean menuPinState = 1;
+boolean lastMenuPinState = 1;
+//curseur
+byte currentMenuItem = 1;
+//buttonstate
+byte state = 0;
+byte laststate = 0;
+//menu
+int menu = 0;
+//#items/menu
+byte Nbitems = 6;
+char* menuitems[10];
 //--------------Relais--------------------
 //Sorties
-const int ROLLUP1_POWER = 12;//relais on/off - moteur1
-const int ROLLUP1_DIRECTION = 11; //relais gauche/droite - moteur1
-const int ROLLUP2_POWER = 10; //relais on/off - moteur2
-const int ROLLUP2_DIRECTION = 9; //relais gauche/droite - moteur2
-const int FAN = 8; //relais ventilation forcée
-const int CHAUFFAGE1 = 7; //relais fournaise1
-const int CHAUFFAGE2 = 6; // relais fournaise2
-
+#define ROLLUP1_POWER  12//relais on/off - moteur1
+#define ROLLUP1_DIRECTION  11 //relais gauche/droite - moteur1
+#define ROLLUP2_POWER  10//relais on/off - moteur2
+#define ROLLUP2_DIRECTION  9 //relais gauche/droite - moteur2
+#define FAN  8 //relais ventilation forcée
+#define CHAUFFAGE1 7 //relais fournaise1
+#define CHAUFFAGE2 6 // relais fournaise2
+#define menuPin 3
 //vocabulaire
 const int CLOSE = HIGH;
 const int OPEN = LOW;
 const int ON = LOW;
 const int OFF = HIGH;

+//----------------------Program-----------------
+//**********PROGRAMMATION PAR DÉFAUT*************
+//Programmes de températures
+byte HP1 = 7;                   //Heure d'exécution du premier programme
+byte MP1 = 30;                  //Minutes d'exécution du premier programme
+byte TEMP_CIBLEP1 = 20;         //Température cible du program 1
+byte HP2 = 11;                  //Heure d'exécution du deuxième programme
+byte MP2 = 0;                   //Minutes d'exécution du deuxième programme
+byte TEMP_CIBLEP2 = 24;         //Température cible du program2
+byte HP3 = 19;                  //Heure d'exécution du deuxième programme
+byte MP3 = 30;                  //Minutes d'exécution du deuxième programme
+byte TEMP_CIBLEP3 = 22;         //Température cible du programme 3
+//Sorties:
+byte HYST_ROLLUP = 2;           //hysteresis rollup
+byte HYST_VENT = 2;             //hysteresis ventilation
+byte HYST_FOURNAISE1 = 2;       //hysteresis fournaise 1
+byte HYST_FOURNAISE2 = 2;       //hysteresis fournaise 2
+//Modificateurs
+byte rmodE = 11;                //Modificateur relais (Mod.réel = rmodE-11, donc 11 équivaut à un modificateur de 0C, 13 de 2C, 9 de -2C, etc.
+byte vmodE = 13;                //Modificateur ventilation
+byte f1modE = 9;                //Modificateur fournaise1
+byte f2modE = 9;                //Modificateur fournaise2
+//temps de rotation et pauses
+byte rotation = 4;
+byte pause = 2;
+//***********************************************
+
 //consignes initiales
-int opened = 0;
-boolean heating1 = false; //fournaise 1 éteinte par défaut
-boolean heating2 = false; //fournaise 2 éteinte par défaut
-boolean fan = false;//ventilation forcée éteinte par défaut
-float greenhouseTemperature = 20.0; //température par défaut : 20C (ajusté après un cycle)
-float TEMP_CIBLE = 20.0;              //température cible par défaut : 20C (ajusté après un cycle))
-float TEMP_ROLLUP = 20;
-float TEMP_VENT = 22.0;
-float TEMP_CHAUFFAGE1 = 18.0;
-float TEMP_CHAUFFAGE2 = 15.0;
-int PROGRAMME = 1;
-
-//**********BLOC PROGRAMMABLE*************
-//Programmes de températures
-const int HP1 = 7;                  //Heure d'exécution du premier programme
-const int MP1 = 30;                   //Minutes d'exécution du premier programme
-const float TEMP_CIBLEP1 = 20.0;            //Température cible du premier programme
-const float TEMP_ROLLUPP1 = (TEMP_CIBLEP1);
-const float TEMP_VENTP1 = (TEMP_CIBLEP1 + 2.0);
-const float TEMP_CHAUFFAGE1P1 = (TEMP_CIBLEP1 - 2.0);
-const float TEMP_CHAUFFAGE2P1 = (TEMP_CIBLEP1 - 5.0);
-
-const int HP2 = 11;                   //Heure d'exécution du deuxième programme
-const int MP2 = 0;                  //Minutes d'exécution du deuxième programme
-const float TEMP_CIBLEP2 = 24.0;            //Température cible du deuxième programme
-const float TEMP_ROLLUPP2 = (TEMP_CIBLEP2);
-const float TEMP_VENTP2 = (TEMP_CIBLEP2 + 2.0);
-const float TEMP_CHAUFFAGE1P2 = (TEMP_CIBLEP2 - 2.0);
-const float TEMP_CHAUFFAGE2P2 = (TEMP_CIBLEP2 - 5.0);
-
-const int HP3 = 16;                   //Heure d'exécution du troisième programme
-const int MP3 = 9;                  //Minutes d'exécution du troisième programme
-const float TEMP_CIBLEP3 = 18.0;           //Température cible du troisième programme
-const float TEMP_ROLLUPP3 = (TEMP_CIBLEP3);
-const float TEMP_VENTP3 = (TEMP_CIBLEP3 + 2.0);
-const float TEMP_CHAUFFAGE1P3 = (TEMP_CIBLEP3 - 2.0);
-const float TEMP_CHAUFFAGE2P3 = (TEMP_CIBLEP3 - 5.0);
-
-//Rollup:
-//Températures critiques et hysteresis
-//Rollup:
-const int HYST_ROLLUP = 2;
-
-//Ventilation:
-const int HYST_VENT = 2;
-
-//Chauffage:
-const int HYST_CHAUFFAGE1 = 2;//
-const int HYST_CHAUFFAGE2 = 2;
+byte opened = 0;
+byte last_opened = 0;
+boolean heating1 = false;                     //fournaise 1 éteinte par défaut
+boolean last_heating1 = false;
+boolean heating2 = false;                     //fournaise 2 éteinte par défaut
+boolean last_heating2 = false;
+boolean fan = false;                          //VENTilation forcée éteinte par défaut
+boolean last_fan = false;
+float greenhouseTemperature = 20.0;               //température par défaut : 20C (ajusté après un cycle)
+float last_greenhouseTemperature = 20.0;
+float greenhouseHumidity;
+float last_greenhouseHumidity = 40.0;
+int rmod = (rmodE-11);                        //modificateur relais
+int vmod = (vmodE-11);                        //modificateur VENTilation
+int f1mod = (f1modE-11);                      //modificateur fournaise1
+int f2mod = (f2modE-11);                      //modificateur fournaise2
+int TEMP_CIBLE = 20;                          //température cible par défaut : 20C (ajustée après un cycle))
+int TEMP_ROLLUP = TEMP_CIBLE + rmod;
+int TEMP_VENTILATION = TEMP_CIBLE + vmod;
+int TEMP_FOURNAISE1 = TEMP_CIBLE + f1mod;
+int TEMP_FOURNAISE2 = TEMP_CIBLE + f2mod;
+byte PROGRAMME = 1;                           //Programme horaire par défaut
+long ROTATION_TIME = (rotation*1000);         //temps de rotation des moteurs(en mili-secondes)
+long PAUSE_TIME = (pause*1000);               //temps d'arrêt entre chaque ouverture/fermeture(en mili-secondes)

 //incréments d'ouverture(nombre d'incréments d'ouverture = PCT_OPEN/NB_OF_STEPS_IN_ANIMATION = 25/5 = 5 incréments d'ouverture)
 const int PCT_OPEN = 25;
 const int NB_OF_STEPS_IN_ANIMATION = 5; //doit être un divisible de PCT_OPEN
-
-//temps de rotation et pauses
-const int ROTATION_TIME = 4000; //temps de rotation des moteurs(en mili-secondes)
-const int PAUSE_TIME = 2000; //temps d'arrêt entre chaque ouverture/fermeture(en mili-secondes)
+//Autres variables
 const int SLEEPTIME = 1000; //temps de pause entre chaque exécution du programme(en mili-secondes)

-//*************FIN DU BLOC PROGRAMMABLE**********
-
-
-//********INITIALISATION DU PROGRAMME**********
-void setup() {
-  Serial.begin(9600);   // démarre la communication sérielle
-  Serial.println("");
-  Serial.println("Starting");
-  Serial.println("-----------------------");
-//--------------LCD 20x4--------------------
-  lcd.begin (20,4); //démarre l'affichage LCD
-  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
-  lcd.setBacklight(HIGH); //allume le rétro-éclairage
-  lcd.home ();
-  lcd.setCursor(0, 0);
-  lcd.print("Resetting");
-
-  lcd.setCursor(0, 2);
-  lcd.print("FAN:");
-  lcd.setCursor(16,2);
-  lcd.print("OFF");
-
-  lcd.setCursor(0, 3);
-  lcd.print("HEATING: ");
-  lcd.setCursor(16,3);
-  lcd.print("OFF");
-//--------------Horloge--------------------
-  rtc.begin();                      //Démarre la communication avec l'horloge
-//--------------DHT11--------------------
-  dht.begin();
-//--------------General setup-------------------
-//Définition et initalisation des sorties
+
+void setup(){
+ Serial.begin(9600);
+ rtc.begin();
+ dht.begin();
+ lcd.begin(20, 4);
+ lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
+ lcd.setBacklight(HIGH);
+ //newDefaultSettings();
+ loadPreviousSettings();
+ clearPrintTitle();
+
+ //Définition et initalisation des sorties
+  pinMode(menuPin, INPUT_PULLUP);
   pinMode(ROLLUP1_POWER, OUTPUT);
   digitalWrite(ROLLUP1_POWER, HIGH);
-
   pinMode(ROLLUP2_POWER, OUTPUT);
   digitalWrite(ROLLUP2_POWER, HIGH);
-
   pinMode(ROLLUP1_DIRECTION, OUTPUT);
   digitalWrite(ROLLUP1_DIRECTION, HIGH);
-
   pinMode(ROLLUP2_DIRECTION, OUTPUT);
   digitalWrite(ROLLUP2_DIRECTION, HIGH);
-
   pinMode(CHAUFFAGE1, OUTPUT);
   digitalWrite(CHAUFFAGE1, HIGH);
-
   pinMode(CHAUFFAGE2, OUTPUT);
   digitalWrite(CHAUFFAGE2, HIGH);
-
   pinMode(FAN, OUTPUT);
   digitalWrite(FAN, HIGH);
-
+
 //Remise à niveau des rollup
-  Serial.println("Resetting position");
+  Serial.println(F("Resetting position"));
   opened = 100;
   for (int i=0; i<5; i++){
     closeSides();
-    delay(PAUSE_TIME);
-  }
-  Serial.println("Resetting done");
-}
-
-void loop() {
-//-----------------Horloge-----------------
+    delay(PAUSE_TIME);}
+  Serial.println(F("Resetting done"));
+
+  displayTempHRStatus();
+  displayRollupStatus();
+  displayFanHeaterStatus();
+ }
+
+void loop(){
+if (digitalRead(menuPin) == LOW){
+    menuPinState = 0;
+    if (menuPinState != lastMenuPinState){
+      displayMenu(menu);}
+    Menu(menu);
+    lastMenuPinState = menuPinState;
+    delay(50);}
+
+else if (digitalRead(menuPin) == HIGH){
+    menuPinState = 1;
+    if (menuPinState != lastMenuPinState){
+      displayTempHRStatus();
+      displayRollupStatus();
+      displayFanHeaterStatus();
+      }
+    Controle();
+    lastMenuPinState = menuPinState;
+    delay(SLEEPTIME);}
+}
+//*******************************************CONTROLE**********************************
+void Controle(){
+  //-----------------Horloge-----------------
   t = rtc.getTime();
   int heure = t.hour;
   int minutes = t.min;
  if (((heure >= HP1)  && (heure < HP2))  && (minutes >= MP1)){
     TEMP_CIBLE = TEMP_CIBLEP1;
-    TEMP_ROLLUP = TEMP_ROLLUPP1;
-    TEMP_VENT = TEMP_VENTP1;
-    TEMP_CHAUFFAGE1 = TEMP_CHAUFFAGE1P1;
-    TEMP_CHAUFFAGE2 = TEMP_CHAUFFAGE2P1;;
     PROGRAMME = 1;
   }
   else if(((heure >= HP2)  && (heure < HP3))  && (minutes >= MP2)){
     TEMP_CIBLE = TEMP_CIBLEP2;
-    TEMP_ROLLUP = TEMP_ROLLUPP2;
-    TEMP_VENT = TEMP_VENTP2;
-    TEMP_CHAUFFAGE1 = TEMP_CHAUFFAGE1P2;
-    TEMP_CHAUFFAGE2 = TEMP_CHAUFFAGE2P2;
     PROGRAMME = 2;
   }
   else if((heure >= HP3)  && (minutes >= MP3)){
     TEMP_CIBLE = TEMP_CIBLEP3;
-    TEMP_ROLLUP = TEMP_ROLLUPP3;
-    TEMP_VENT = TEMP_VENTP3;
-    TEMP_CHAUFFAGE1 = TEMP_CHAUFFAGE1P3;
-    TEMP_CHAUFFAGE2 = TEMP_CHAUFFAGE2P3;;
     PROGRAMME = 3;
   }
   //--------------DHT11--------------------
-  float greenhouseTemperature = dht.readTemperature();
-  float greenhouseHumidity = dht.readHumidity();
+  greenhouseTemperature = dht.readTemperature();
+  greenhouseHumidity = dht.readHumidity();
 //--------------Relais--------------------
 //Programme d'ouverture/fermeture des rollups
   if(greenhouseTemperature < TEMP_ROLLUP-(HYST_ROLLUP/2)){
@@ -196,100 +200,86 @@
     openSides();
   }
 //Programme fournaise1
-  if (greenhouseTemperature < (TEMP_CHAUFFAGE1-(HYST_CHAUFFAGE1/2))){
+  if (greenhouseTemperature < (TEMP_FOURNAISE1-(HYST_FOURNAISE1/2))){
     setHeater1(ON);
     digitalWrite(CHAUFFAGE1, ON);
-  }else if(greenhouseTemperature > (TEMP_CHAUFFAGE1+(HYST_CHAUFFAGE1/2))){
+  }else if(greenhouseTemperature > (TEMP_FOURNAISE1+(HYST_FOURNAISE1/2))){
     setHeater1(OFF);
     digitalWrite(CHAUFFAGE1, OFF);
   }
 //Programme fournaise2
-  if (greenhouseTemperature < (TEMP_CHAUFFAGE2-(HYST_CHAUFFAGE2/2))){
+  if (greenhouseTemperature < (TEMP_FOURNAISE2-(HYST_FOURNAISE2/2))){
     setHeater2(ON);
     digitalWrite(CHAUFFAGE2, ON);
-  }else if(greenhouseTemperature > (TEMP_CHAUFFAGE2+(HYST_CHAUFFAGE2/2))){
+  }else if(greenhouseTemperature > (TEMP_FOURNAISE2+(HYST_FOURNAISE2/2))){
     setHeater2(OFF);
     digitalWrite(CHAUFFAGE2, OFF);
   }
 //Programme ventilation forcée
-   if (greenhouseTemperature > (TEMP_VENT - (HYST_VENT/2))){
+   if (greenhouseTemperature > (TEMP_VENTILATION - (HYST_VENT/2))){
     setFan(ON);
     digitalWrite(FAN, ON);
-  }else if(greenhouseTemperature < (TEMP_VENT + (HYST_VENT/2))){
+  }else if(greenhouseTemperature < (TEMP_VENTILATION + (HYST_VENT/2))){
     setFan(OFF);
     digitalWrite(FAN, OFF);
   }
 //--------------Affichage sériel--------------------
-    Serial.println("");
-    Serial.println("-----------------------");
+    Serial.println(F(""));
+    Serial.println(F("-----------------------"));
     Serial.print(rtc.getDOWStr());
-    Serial.print(",  ");
+    Serial.print(F(",  "));
     // Send date
     Serial.print(rtc.getDateStr());
-    Serial.print(" - ");
+    Serial.print(F(" - "));
     // Send time
     Serial.println(rtc.getTimeStr());
-    Serial.print("PROGRAMME : ");
+    Serial.print(F("PROGRAMME : "));
     Serial.println(PROGRAMME);

-    Serial.println("-----------------------");
-    Serial.print("Temperature cible :");
+    Serial.println(F("-----------------------"));
+    Serial.print(F("Temperature cible :"));
     Serial.print(TEMP_CIBLE);
-    Serial.println(" C");
-
-    Serial.print("Temperature actuelle: ");
+    Serial.println(F(" C"));
+
+    Serial.print(F("Temperature actuelle: "));
     Serial.print(greenhouseTemperature);
     Serial.println(" C");
-    Serial.print("Humidite: ");
+    Serial.print(F("Humidite: "));
     Serial.print(greenhouseHumidity);
-    Serial.println("%");
-    Serial.println("-----------------------");
+    Serial.println(F("%"));
+    Serial.println(F("-----------------------"));
     if(fan == false){
-    Serial.println("FAN: OFF");}
+    Serial.println(F("FAN: OFF"));}
     else if(fan == true){
-    Serial.println("FAN: ON");}
+    Serial.println(F("FAN: ON"));}
     if(heating1 == false){
-    Serial.println("HEATING1: OFF");}
+    Serial.println(F("HEATING1: OFF"));}
     else if(heating1 == true){
-    Serial.println("HEATING1: ON");}
+    Serial.println(F("HEATING1: ON"));}
     if(heating2 == false){
-    Serial.println("HEATING2 : OFF");}
+    Serial.println(F("HEATING2 : OFF"));}
     else if(heating2 == true){
-    Serial.println("HEATING2 : ON");}
+    Serial.println(F("HEATING2 : ON"));}
 //--------------Affichage LCD--------------------
   lcd.setCursor(0, 0);
-  lcd.print("T: ");
-  lcd.print(greenhouseTemperature);
-  lcd.print("C  ");
-  lcd.setCursor(10,0);
-  lcd.print("HR: ");
-  lcd.print(greenhouseHumidity);
-  lcd.print("%");
-  if(fan == false){
-      lcd.setCursor(0, 2);
-      lcd.print("FAN:");
-      lcd.setCursor(16,2);
-      lcd.print("OFF");}
-  else if(fan == true){
-      lcd.setCursor(0,2);
-      lcd.print("FAN:");
-      lcd.setCursor(16,2);
-      lcd.print("ON ");}
-  if(heating1 == false){
-      lcd.setCursor(0, 3);
-      lcd.print("HEATING:");
-      lcd.setCursor(16,3);
-      lcd.print("OFF");}
-  else if(heating1 == true){
-      lcd.setCursor(0,3);
-      lcd.print("HEATING: ");
-      lcd.setCursor(16,3);
-      lcd.print("ON ");}
-//--------------fin du cycle--------------------
-  delay(SLEEPTIME);
-}
-
-//--------------SOUS-PROGRAMMES--------------------
+  if((greenhouseTemperature!= last_greenhouseTemperature)||(greenhouseHumidity != last_greenhouseHumidity)){
+  displayTempHRStatus();
+  }
+  if(opened != last_opened){
+  displayRollupStatus();
+  }
+  if((fan != last_fan)||(heating1 != last_heating1)){
+  displayFanHeaterStatus();
+  }
+
+last_greenhouseTemperature = greenhouseTemperature;
+last_greenhouseHumidity = greenhouseHumidity;
+last_opened = opened;
+last_fan = fan;
+last_heating1 = heating1;
+last_heating2 = heating2;
+}
+
 //Affichage du % d'ouverture des rollup
 void setOpenedStatus(int pctIncrease){
   opened += pctIncrease;
@@ -298,11 +288,11 @@
   }else if (opened > 100){
     opened = 100;
   }
-  Serial.print("    ");
+  Serial.print(F("    "));
   Serial.println(opened);
   lcd.setCursor(16, 1);
   lcd.print(opened);
-  lcd.print("% ");
+  lcd.print(F("% "));
 }

 //Exécution de la séquence d'ouverture/fermeture
@@ -316,10 +306,10 @@
 //Programme d'ouverture des rollup
 void openSides(){
   if(opened < 100){
-    Serial.println("");
-    Serial.println("  Opening");
+    Serial.println(F(""));
+    Serial.println(F("  Opening"));
     lcd.setCursor(0, 1);
-    lcd.print("OUVERTURE... ");
+    lcd.print(F("OUVERTURE... "));
     digitalWrite(ROLLUP1_POWER,ON);
     digitalWrite(ROLLUP1_DIRECTION, OPEN);
     digitalWrite(ROLLUP2_POWER,ON);
@@ -327,9 +317,9 @@
     animate(1);
     digitalWrite(ROLLUP1_POWER,OFF);
     digitalWrite(ROLLUP2_POWER,OFF);
-    Serial.println("  Done opening");
+    Serial.println(F("  Done opening"));
     lcd.setCursor(0, 1);
-    lcd.print("ROLLUPS:     ");
+    lcd.print(F("ROLLUPS:     "));
     delay(PAUSE_TIME);
   }
 }
@@ -337,10 +327,10 @@
 //Programme de fermeture des rollups
 void closeSides(){
   if (opened > 0){
-    Serial.println("");
-    Serial.println("  Closing");
+    Serial.println(F(""));
+    Serial.println(F("  Closing"));
     lcd.setCursor(0, 1);
-    lcd.print("FERMETURE... ");
+    lcd.print(F("FERMETURE... "));
     digitalWrite(ROLLUP1_POWER,ON);
     digitalWrite(ROLLUP1_DIRECTION, CLOSE);
     digitalWrite(ROLLUP2_POWER,ON);
@@ -348,22 +338,23 @@
     animate(-1);
     digitalWrite(ROLLUP1_POWER, OFF);
     digitalWrite(ROLLUP2_POWER, OFF);
-    Serial.println("  Done closing");
+    Serial.println(F("  Done closing"));
     lcd.setCursor(0, 1);
-    lcd.print("ROLLUPS:     ");
+    lcd.print(F("ROLLUPS:     "));
     delay(PAUSE_TIME);
   }
 }
+

 //État de la première fournaise
 void setHeater1(int heaterCommand1){
   if ((heaterCommand1 == ON) && (heating1 == false)){
-    Serial.println("");
-    Serial.println("  Start heating1");
+    Serial.println(F(""));
+    Serial.println(F("  Start heating1"));
     heating1 = true;
   }else if ((heaterCommand1 == OFF) && (heating1 == true)){
-    Serial.println("");
-    Serial.println("  Stop heating1");
+    Serial.println(F(""));
+    Serial.println(F("  Stop heating1"));
     heating1 = false;
     }
   }
@@ -371,12 +362,12 @@
 //État de la deuxième fournaise
 void setHeater2(int heaterCommand2){
   if ((heaterCommand2 == ON) && (heating2 == false)){
-    Serial.println("");
-    Serial.println("  Start heating2");
+    Serial.println(F(""));
+    Serial.println(F("  Start heating2"));
     heating2 = true;
   }else if ((heaterCommand2 == OFF) && (heating2 == true)){
-    Serial.println("");
-    Serial.println("  Stop heating2");
+    Serial.println(F(""));
+    Serial.println(F("  Stop heating2"));
     heating2 = false;
     }
   }
@@ -384,17 +375,606 @@
 //État de la ventilation
 void setFan(int fanCommand){
   if ((fanCommand == ON) && (fan == false)){
-    Serial.println("");
-    Serial.println("  Start fan");
+    Serial.println(F(""));
+    Serial.println(F("  Start fan"));

     fan = true;
   }else if ((fanCommand == OFF) && (fan == true)){
-    Serial.println("");
-    Serial.println("  Stop fan");
+    Serial.println(F(""));
+    Serial.println(F("  Stop fan"));
     fan = false;
   }
 }
-
-
-
-
+void displayTempHRStatus(){
+  lcd.setCursor(0,0);
+  lcd.print(F("                    "));
+  lcd.setCursor(0,0);
+  lcd.print(F("T: "));
+  lcd.print(greenhouseTemperature);
+  lcd.print(F("C  "));
+  lcd.setCursor(10,0);
+  lcd.print(F("HR: "));
+  lcd.print(greenhouseHumidity);
+  lcd.print("%");
+}
+void displayRollupStatus(){
+  lcd.setCursor(0,1);
+  lcd.print(F("                    "));
+  lcd.setCursor(0, 1);
+  lcd.print(F("ROLLUPS:     "));
+  lcd.setCursor(16, 1);
+  lcd.print(opened);
+  lcd.print(F("% "));
+}
+void displayFanHeaterStatus(){
+  lcd.setCursor(0,2);
+  lcd.print(F("                    "));
+  lcd.setCursor(0,3);
+  lcd.print(F("                    "));
+  if(fan == false){
+      lcd.setCursor(0, 2);
+      lcd.print(F("FAN:"));
+      lcd.setCursor(16,2);
+      lcd.print(F("OFF"));}
+  else if(fan == true){
+      lcd.setCursor(0,2);
+      lcd.print(F("FAN:"));
+      lcd.setCursor(16,2);
+      lcd.print(F("ON "));}
+  if(heating1 == false){
+      lcd.setCursor(0, 3);
+      lcd.print(F("HEATING:"));
+      lcd.setCursor(16,3);
+      lcd.print(F("OFF"));}
+  else if(heating1 == true){
+      lcd.setCursor(0,3);
+      lcd.print(F("HEATING: "));
+      lcd.setCursor(16,3);
+      lcd.print(F("ON "));}
+}
+//*******************************************EEPROM***********************************************
+void newDefaultSettings(){
+ EEPROM.write(0,HYST_ROLLUP);
+ EEPROM.write(1,HYST_VENT);
+ EEPROM.write(2,HYST_FOURNAISE1);
+ EEPROM.write(3,HYST_FOURNAISE2);
+ EEPROM.write(4,HP1);
+ EEPROM.write(5,MP1);
+ EEPROM.write(6,TEMP_CIBLEP1);
+ EEPROM.write(7,HP2);
+ EEPROM.write(8,MP2);
+ EEPROM.write(9,TEMP_CIBLEP2);
+ EEPROM.write(10,HP3);
+ EEPROM.write(11,MP3);
+ EEPROM.write(12,TEMP_CIBLEP3);
+ EEPROM.write(13,rotation);
+ EEPROM.write(14,pause);
+ EEPROM.write(15,rmodE);
+ EEPROM.write(16,vmodE);
+ EEPROM.write(17, f1modE);
+ EEPROM.write(18, f2modE);
+}
+
+void loadPreviousSettings(){
+ HYST_ROLLUP = EEPROM.read(0);
+ HYST_VENT = EEPROM.read(1);
+ HYST_FOURNAISE1 = EEPROM.read(2);
+ HYST_FOURNAISE2 = EEPROM.read(3);
+ HP1 = EEPROM.read(4);
+ MP1 = EEPROM.read(5);
+ TEMP_CIBLEP1 = EEPROM.read(6);
+ HP2 = EEPROM.read(7);
+ MP2 = EEPROM.read(8);
+ TEMP_CIBLEP2 = EEPROM.read(9);
+ HP3 = EEPROM.read(10);
+ MP3 = EEPROM.read(11);
+ TEMP_CIBLEP3 = EEPROM.read(12);
+ rotation = EEPROM.read(13);
+ pause = EEPROM.read(14);
+ rmodE = EEPROM.read(15);
+ vmodE = EEPROM.read(16);
+ f1modE = EEPROM.read(17);
+ f2modE = EEPROM.read(18);
+ }
+
+
+
+//**************************************MENU****************************************************
+void Menu(int x){
+  int a = analogRead(0);
+  buttonState(a);
+
+  if ((state == 1) && (state != laststate)){
+      currentMenuItem = currentMenuItem + 1;
+      real_currentMenuItem(Nbitems);
+      displayMenu(x);
+  } else if ((state == 2) && (state != laststate)){
+      currentMenuItem = currentMenuItem - 1;
+      real_currentMenuItem(Nbitems);
+      displayMenu(x);
+  } else if ((state == 3) && (state != laststate)){
+      real_currentMenuItem(Nbitems);
+      selectMenu(x, currentMenuItem);
+  }
+  laststate = state;
+}
+
+void buttonState(int x){
+  if(x < 800){state = 0;}
+  else if(x < 900){state = 1;}
+  else if (x < 950){state = 2;}
+  else if (x < 1000){state = 3;}
+}
+
+void real_currentMenuItem(int x){
+  if(currentMenuItem < 1){
+  currentMenuItem = 1;
+  }
+  else if(currentMenuItem > x){
+  currentMenuItem = x;
+  }
+}
+
+void Scrollingmenu (int x, const char a[20] PROGMEM, const char b[20] PROGMEM, const char c[20] PROGMEM, const char d[20] PROGMEM, const char e[20] PROGMEM, const char f[20] PROGMEM, const char g[20] PROGMEM, const char h[20] PROGMEM, const char i[20] PROGMEM, const char j[20] PROGMEM, int y){
+  const int numLcdRows = 3;
+  byte scrollPos = 0;
+  Nbitems = x;
+  const char* menuitems[] PROGMEM = {a,b,c,d,e,f,g,h,i,j};
+
+        if (y > numLcdRows){scrollPos = y - numLcdRows;
+      } else {scrollPos = 0;
+      }
+      clearPrintTitle();
+      for (int i=0; i < numLcdRows; ++i) {
+            lcd.setCursor(0, i+1);
+            lcd.print(menuitems[i + scrollPos]);
+            }
+      lcd.setCursor(19, (y - scrollPos));
+      lcd.blink();
+}
+
+void Scrollingnumbers(int x, int y, int z, int a){
+  const int numLcdRows = 3;
+  int scrollPos = 0;
+  Nbitems = x;
+
+      if (y > numLcdRows){scrollPos = y - numLcdRows;
+      } else {scrollPos = 0;
+      }
+      clearPrintTitle();
+      for (int i=0; i < numLcdRows; ++i) {
+            lcd.setCursor(0, i+1);
+            if(y < 4){
+            lcd.print((z-a)+(i*a)+(a));}
+            else if(y < x){
+            lcd.print((z-a)+(i*a)+((y-2)*a));}
+            else if (y == x){
+            lcd.print("back");}
+            else{}
+            }
+      lcd.setCursor(19, (y - scrollPos));
+      lcd.blink();
+}
+void clearPrintTitle(){
+  lcd.noBlink();
+  lcd.clear();
+  lcd.setCursor(0,0);
+  lcd.print("**ROBOT-SERRE**V.1**");
+}
+//***********************************DISPLAY****************************************************
+//Scrollingmenu(Nbitems, Item1, item2, item3, item4, item5, Item6, item7, item8, item9, item10, currentMenuItem); //leave variable "Itemx" blank if it doesnt exist
+//Scrollingnumbers(Nbitems, currentMenuItem, starting number, multiplicator);
+
+void displayMenu(int x){
+  switch (x){
+  case 0: Scrollingmenu(6, "Temperature/humidex","Date/time","Rollups","Ventilation","Chauffage","Programmes","","","","", currentMenuItem);break;
+  case 1: Scrollingmenu(6, "Date","Time", "SetDOW", "Set date","Set time","back","","","","", currentMenuItem);break;
+  case 11: Scrollingmenu(8, "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday", "back","","", currentMenuItem);break;
+  case 12:Scrollingnumbers(11, currentMenuItem, 2016, 1);  break;
+  case 121: Scrollingnumbers(13, currentMenuItem, 1 ,1);  break;
+  case 1211: Scrollingnumbers(32, currentMenuItem, 1, 1); break;
+  case 13: Scrollingnumbers(25, currentMenuItem, 1, 1);break;
+  case 131: Scrollingnumbers(62, currentMenuItem, 0 , 1); break;
+  case 1311: Scrollingnumbers(62, currentMenuItem, 0, 1);break;
+  case 2: Scrollingmenu(6, "Etat", "Programme", "Set hysteresis", "Set rotation time(s)", "Set pause time(s)", "back","","","","", currentMenuItem);break;
+  case 21: Scrollingnumbers(6, currentMenuItem, 2, 2);break;
+  case 22: Scrollingnumbers(21, currentMenuItem, 1, 1);break;
+  case 23: Scrollingmenu(10, "5", "15", "20", "30", "45", "60", "75", "90", "120", "back", currentMenuItem);break;
+  case 3: Scrollingmenu(3, "Etat", "Set hysteresis", "back", "", "", "", "", "", "", "", currentMenuItem);break;
+  case 31: Scrollingnumbers(6, currentMenuItem, 2, 2);break;
+  case 4: Scrollingmenu(5, "(F1)Etat", "(F2)Etat","(F1)Set hysteresis", "(F2)Set hysteresis", "back", "", "", "", "", "", currentMenuItem);break;
+  case 41: Scrollingnumbers(6, currentMenuItem, 2, 2);break;
+  case 42: Scrollingnumbers(6, currentMenuItem, 2, 2);break;
+  case 5: Scrollingmenu(9, "Programme 1", "Programme 2", "Programme 3", "Modificateurs", "Set Programme 1", "Set Programme 2", "Set Programme 3", "Set Modificateurs", "back","",currentMenuItem);break;
+  case 51:Scrollingmenu(3, "Set Heure", "Set Temp. cible", "back","","","","","","","", currentMenuItem);break;
+  case 511: Scrollingnumbers(25, currentMenuItem, 1 , 1); break;
+  case 5111: Scrollingnumbers(62, currentMenuItem, 0, 1);break;
+  case 512: Scrollingnumbers(51, currentMenuItem, 0 , 1); break;
+  case 52: Scrollingmenu(3, "Set Heure", "Set Temp. cible", "back","","","","","","","", currentMenuItem);break;
+  case 521: Scrollingnumbers(25, currentMenuItem, 1, 1); break;
+  case 5211: Scrollingnumbers(62, currentMenuItem, 0, 1);break;
+  case 522: Scrollingnumbers(51, currentMenuItem, 0, 1); break;
+  case 53: Scrollingmenu(3, "Set Heure", "Set Temp. cible", "back","","","","","","","", currentMenuItem);break;
+  case 531: Scrollingnumbers(25, currentMenuItem, 1 , 1); break;
+  case 5311: Scrollingnumbers(62, currentMenuItem, 0, 1);break;
+  case 532: Scrollingnumbers(51, currentMenuItem, 0, 1); break;
+  case 54: Scrollingmenu(3, "Mod. rollups", "Mod. ventilation", "Mod. fournaise1", "Mod. fournaise2", "back","","","","","", currentMenuItem);break;
+  case 541: Scrollingnumbers(22, currentMenuItem, -10, 1);break;
+  case 542: Scrollingnumbers(22, currentMenuItem, -10, 1);break;
+  case 543: Scrollingnumbers(22, currentMenuItem, -10, 1);break;
+  case 544: Scrollingnumbers(22, currentMenuItem, -10, 1);break;
+  }
+}
+//*****************************************SELECT**********************************************
+
+void switchmenu(int x){
+  delay(1000);
+  menu = x;
+  currentMenuItem = 1;
+  Nbitems = 3;
+  displayMenu(menu);
+}
+
+void selectMenu(int x, int y){
+  switch (x){
+  //------------------------------SelectrootMenu-------------------------------------
+  //"Temperature/humidex","Date/time","Rollups","Ventilation","Chauffage"
+  case 0:
+    switch (y){
+    case 1:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(F("Temperature : "));lcd.print(dht.readTemperature());lcd.print(F("C"));
+         lcd.setCursor(0,2);lcd.print(F("HR : "));lcd.print(dht.readHumidity());lcd.print(F("%"));
+    break;
+    case 2:switchmenu(1);break;
+    case 3:switchmenu(2);break;
+    case 4:switchmenu(3);break;
+    case 5:switchmenu(4);break;
+    case 6:switchmenu(5);break;
+     }
+  break;
+  //-------------------------------SelectMenu1-----------------------------------------
+  //"Date","Time","Set DOW" "Set date", "Set time","back"
+  case 1 :
+    switch (y){
+    case 1:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(rtc.getDOWStr());
+         lcd.setCursor(0,2);lcd.print(F("Date : "));lcd.print(rtc.getDateStr());
+    break;
+    case 2:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(F("Time : "));lcd.print(rtc.getTimeStr());
+    break;
+    case 3:switchmenu(11);break;
+    case 4:switchmenu(12);break;
+    case 5:switchmenu(13);break;
+    case 6:switchmenu(0);break;
+    }
+  break;
+  //-------------------------------SelectMenu12-----------------------------------------
+  //SET DAY OF THE WEEK
+  case 11 :
+    switch(y){
+    case 1:rtc.setDOW(MONDAY);switchmenu(1);break;
+    case 2:rtc.setDOW(TUESDAY);switchmenu(1);break;
+    case 3:rtc.setDOW(WEDNESDAY);switchmenu(1);break;
+    case 4:rtc.setDOW(THURSDAY);switchmenu(1);break;
+    case 5:rtc.setDOW(FRIDAY);switchmenu(1);break;
+    case 6:rtc.setDOW(SATURDAY);switchmenu(1);break;
+    case 7:rtc.setDOW(SUNDAY);switchmenu(1);break;
+    case 8:switchmenu(1);break;
+    }
+  break;
+  //-------------------------------SelectMenu12-----------------------------------------
+  //SET YEAR
+  case 12 :
+    if(y<Nbitems){yr = (2015+y);switchmenu(121);}
+    else{switchmenu(1);}
+  break;
+  //-------------------------------SelectMenu131-----------------------------------------
+  //SET MONTH
+  case 121 :
+    if(y<Nbitems){mt = y;switchmenu(1211);}
+    else{switchmenu(1);}
+  break;
+  //-------------------------------SelectMenu1311-----------------------------------------
+  //SET DAY
+  case 1211 :
+    if(y<Nbitems){dy = y;rtc.setDate(dy,mt,yr);switchmenu(1);}
+    else{switchmenu(1);}
+  break;
+  //-------------------------------SelectMenu14-----------------------------------------
+  //SET HOUR
+  case 13 :
+    if(y<Nbitems){hr = y;switchmenu(131);}
+    else{switchmenu(1);}
+  break;
+  //-------------------------------SelectMenu141-----------------------------------------
+  //SET MINUTES
+  case 131 :
+    if(y<Nbitems){mn = y;switchmenu(1311);}
+    else{switchmenu(1);}
+  break;
+  //-------------------------------SelectMenu1411-----------------------------------------
+  //SET SECONDS
+  case 1311 :
+    if(y<Nbitems){sc = y;rtc.setTime(hr,mn,sc);switchmenu(1);}
+    else{switchmenu(1);}
+  break;
+  //-------------------------------SelectMenu2-----------------------------------------
+  //"Etat", "Programme", "Set hysteresis", "Set rotation time(s)", "Set pause time(m)", "back"
+  case 2 :
+    switch (y){
+    case 1:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(F("Ouverture : "));lcd.print(opened);lcd.print(F("%"));
+         lcd.setCursor(0,2);lcd.print(F("TP : "));lcd.print(pause);lcd.print(F("s | TR :"));lcd.print(rotation);lcd.print(F("s"));
+         lcd.setCursor(0,3);lcd.print(F("Hysteresis : "));lcd.print(HYST_ROLLUP);lcd.print(F("C"));
+    break;
+    case 2:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(F("Programme : "));lcd.print(PROGRAMME);
+         lcd.setCursor(0,2);lcd.print(F("Temp. cible : "));lcd.print(TEMP_CIBLE);lcd.print(F("C"));
+         lcd.setCursor(0,3);lcd.print(F("Temp. rollup : "));lcd.print(TEMP_ROLLUP);lcd.print(F("C"));
+    break;
+    case 3:switchmenu(21);break;
+    case 4:switchmenu(22);break;
+    case 5:switchmenu(23);break;
+    case 6:switchmenu(0);break;
+    }
+  break;
+  //-------------------------------SelectMenu21-----------------------------------------
+  //SET HYSTERESIS
+  case 21 :
+    if(y<Nbitems){HYST_ROLLUP = (y*2);switchmenu(2);EEPROM.write(0,HYST_ROLLUP);}
+    else{switchmenu(2);}
+  break;
+  //-------------------------------SelectMenu22-----------------------------------------
+  //SET ROTATION TIME
+  case 22 :
+    if(y<Nbitems){rotation = y;switchmenu(2);EEPROM.write(13, rotation);}
+    else{switchmenu(2);}
+  break;
+  //-------------------------------SelectMenu23-----------------------------------------
+  //"5", "15", "20", "30", "45", "60", "75", "90", "120", "back"
+  case 23 :
+  switch(y){
+    case 1:pause = 5;switchmenu(2);EEPROM.write(14, pause);break;
+    case 2:pause = 15;switchmenu(2);EEPROM.write(14, pause);break;
+    case 3:pause = 20;switchmenu(2);EEPROM.write(14, pause);break;
+    case 4:pause = 30;switchmenu(2);EEPROM.write(14, pause);break;
+    case 5:pause = 45;switchmenu(2);EEPROM.write(14, pause);break;
+    case 6:pause = 60;switchmenu(2);EEPROM.write(14, pause);break;
+    case 7:pause = 75;switchmenu(2);EEPROM.write(14, pause);break;
+    case 8:pause = 90;switchmenu(2);EEPROM.write(14, pause);break;
+    case 9:pause = 120;switchmenu(2);EEPROM.write(14, pause);break;
+    case 10:switchmenu(2);break;
+  }
+  break;
+
+  //-------------------------------SelectMenu3-----------------------------------------
+  case 3 :
+    switch (y){
+    case 1:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(F("FAN : "));
+             if(fan == false){ lcd.print(F("OFF"));}
+             else {lcd.print(F("ON"));}
+         lcd.setCursor(0,2);lcd.print(F("Temp. cible : "));lcd.print(TEMP_VENTILATION);lcd.print(F("C"));
+         lcd.setCursor(0,3);lcd.print(F("Hysteresis : "));lcd.print(HYST_VENT);lcd.print(F("C"));
+    break;
+    case 2:switchmenu(31);break;
+    case 3:switchmenu(0);break;
+    }
+  break;
+  //-------------------------------SelectMenu31-----------------------------------------
+  //SET HYSTERESIS
+  case 31 :
+    if(y<Nbitems){HYST_VENT = (y*2);switchmenu(3); EEPROM.write(1, HYST_VENT);}
+    else{switchmenu(3);}
+  break;
+  //-------------------------------SelectMenu4-----------------------------------------
+  case 4 :
+    switch (y){
+    case 1:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(F("FOURNAISE(1) : "));
+             if(heating1 == false){lcd.print(F("OFF"));}
+             else {lcd.print(F("ON"));}
+         lcd.setCursor(0,2);lcd.print(F("Temp. cible : "));lcd.print(TEMP_FOURNAISE1);lcd.print(F("C"));
+         lcd.setCursor(0,3);lcd.print(F("Hysteresis : "));lcd.print(HYST_FOURNAISE1);lcd.print(F("C"));
+    break;
+    case 2:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(F("FOURNAISE(2) : "));
+             if(heating1 == false){lcd.print(F("OFF"));}
+             else {lcd.print(F("ON"));}
+         lcd.setCursor(0,2);lcd.print(F("Temp. cible : "));lcd.print(TEMP_FOURNAISE2);lcd.print(F("C"));
+         lcd.setCursor(0,3);lcd.print(F("Hysteresis : "));lcd.print(HYST_FOURNAISE2);lcd.print(F("C"));
+    break;
+    case 3:switchmenu(41);break;
+    case 4:switchmenu(42);break;
+    case 5:switchmenu(0);break;
+    }
+  break;
+  //-------------------------------SelectMenu41-----------------------------------------
+  //SET HYSTERESIS
+  case 41 :
+    if(y<Nbitems){HYST_FOURNAISE1 = (y*2);switchmenu(4);EEPROM.write(2, HYST_FOURNAISE1);}
+    else{switchmenu(4);}
+  break;
+  //-------------------------------SelectMenu42-----------------------------------------
+  //SET HYSTERESIS
+  case 42 :
+    if(y<Nbitems){HYST_FOURNAISE2 = (y*2);switchmenu(4);EEPROM.write(3,HYST_FOURNAISE2);}
+    else{switchmenu(4);}
+  break;
+  //-------------------------------SelectMenu5-----------------------------------------
+  //"Programme 1", "Programme 2", "Programme 3", "Modificateurs" "Set Programme 1", "Set Programme 2", "Set Programme 3", "Set Modificateurs", "back"
+  case 5 :
+    switch (y){
+    case 1:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(F("HD: "));lcd.print(HP1);lcd.print(F(":"));lcd.print(MP1);lcd.print(F(" | HF: "));lcd.print(HP2);lcd.print(F(":"));lcd.print(MP2);
+         lcd.setCursor(0,2);lcd.print(F("TEMP.CIBLE : "));lcd.print(TEMP_CIBLEP1);lcd.print(F("C"));
+    break;
+    case 2:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(F("HD: "));lcd.print(HP2);lcd.print(F(":"));lcd.print(MP2);lcd.print(F(" | HF: "));lcd.print(HP3);lcd.print(F(":"));lcd.print(MP3);
+         lcd.setCursor(0,2);lcd.print(F("TEMP.CIBLE : "));lcd.print(TEMP_CIBLEP2);lcd.print(F("C"));
+    break;
+    case 3:
+         lcd.noBlink();
+         clearPrintTitle();
+         lcd.setCursor(0,1);lcd.print(F("HD: "));lcd.print(HP3);lcd.print(F(":"));lcd.print(MP3);lcd.print(F(" | HF: "));lcd.print(HP1);lcd.print(F(":"));lcd.print(MP1);
+         lcd.setCursor(0,2);lcd.print(F("TEMP.CIBLE : "));lcd.print(TEMP_CIBLEP3);lcd.print(F("C"));
+    break;
+    case 4:
+          lcd.noBlink();
+          clearPrintTitle();
+          lcd.setCursor(0,1);lcd.print(F("TEMP.CIBLE : "));lcd.print(TEMP_CIBLE);
+          lcd.setCursor(0,2);lcd.print(F("RMod:"));lcd.print(rmod);
+          lcd.setCursor(8,2);lcd.print(F("| f1mod:"));lcd.print(f1mod);
+          lcd.setCursor(0,3);lcd.print(F("VMod:"));lcd.print(vmod);
+          lcd.setCursor(8,3);lcd.print(F("| f2mod:"));lcd.print(f2mod);
+    break;
+    case 5:switchmenu(51);break;
+    case 6:switchmenu(52);break;
+    case 7:switchmenu(53);break;
+    case 8:switchmenu(54);break;
+    case 9:switchmenu(0);break;
+    }
+  break;
+  //-------------------------------SelectMenu51-----------------------------------------
+  case 51:
+  switch(y){
+    case 1:switchmenu(511);break;
+    case 2:switchmenu(512);break;
+    case 3:switchmenu(5);break;
+  }
+  break;
+  //-------------------------------SelectMenu511-----------------------------------------
+  //SET HOUR
+  case 511 :
+    if(y<Nbitems){HP1 = y;switchmenu(5111);EEPROM.write(4,HP1);}
+    else{switchmenu(51);}
+  break;
+  //-------------------------------SelectMenu5111-----------------------------------------
+  //SET MINUTES
+  case 5111 :
+    if(y<Nbitems){MP1 = (y-1);switchmenu(51);EEPROM.write(5,MP1);}
+    else{switchmenu(51);}
+  break;
+  //-------------------------------SelectMenu512-----------------------------------------
+  //SET TEMP_CIBLE
+  case 512 :
+    if(y<Nbitems){TEMP_CIBLEP1 = y;switchmenu(51);EEPROM.write(6,TEMP_CIBLEP1);}
+    else{switchmenu(51);}
+  break;
+  //-------------------------------SelectMenu52-----------------------------------------
+  case 52:
+  switch(y){
+    case 1: switchmenu(521);break;
+    case 2:switchmenu(522);break;
+    case 3:switchmenu(5);break;
+  }
+  break;
+  //-------------------------------SelectMenu521-----------------------------------------
+  //SET HOUR
+  case 521 :
+    if(y<Nbitems){HP2 = y;switchmenu(5211);EEPROM.write(7,HP2);}
+    else{switchmenu(51);}
+  break;
+  //-------------------------------SelectMenu5211-----------------------------------------
+  //SET MINUTES
+  case 5211 :
+    if(y<Nbitems){MP2 = (y-1);switchmenu(51);EEPROM.write(8,MP2);}
+    else{switchmenu(51);}
+  break;
+  //-------------------------------SelectMenu522-----------------------------------------
+  //SET TEMP_CIBLE
+  case 522 :
+    if(y<Nbitems){TEMP_CIBLEP2 = y;switchmenu(52);EEPROM.write(9,TEMP_CIBLEP2);}
+    else{switchmenu(51);}
+  break;
+  //-------------------------------SelectMenu53-----------------------------------------
+  //"Heure", "Tempcible", "back"
+  case 53:
+  switch(y){
+    case 1: switchmenu(531);break;
+    case 2:switchmenu(532);break;
+    case 3:switchmenu(5);break;
+  }
+  break;
+  //-------------------------------SelectMenu531-----------------------------------------
+  //SET HOUR
+  case 531 :
+    if(y<25){HP3 = y;switchmenu(5311);EEPROM.write(10,HP3);}
+    else{switchmenu(51);}
+  break;
+  //-------------------------------SelectMenu5311-----------------------------------------
+  //SET MINUTES
+  case 5311 :
+    if(y<61){MP3 = (y-1);switchmenu(51);EEPROM.write(11,MP3);}
+    else{switchmenu(51);}
+  break;
+  //-------------------------------SelectMenu532-----------------------------------------
+  //SET TEMP_CIBLE
+  case 532 :
+    if(y<51){TEMP_CIBLEP3 = y;switchmenu(53);EEPROM.write(12,TEMP_CIBLEP3);}
+    else{switchmenu(53);}
+  break;
+  //-------------------------------SelectMenu54-----------------------------------------
+  //"Heure", "Tempcible", "back"
+  case 54:
+  switch(y){
+    case 1:switchmenu(541);break;
+    case 2:switchmenu(542);break;
+    case 3:switchmenu(543);break;
+    case 4:switchmenu(544);break;
+    case 5:switchmenu(5);break;
+  }
+  break;
+  //-------------------------------SelectMenu541-----------------------------------------
+  //SET MOD
+  case 541 :
+    if(y<Nbitems){rmodE = y;switchmenu(54);EEPROM.write(15,rmodE);}
+    else{switchmenu(54);}
+  break;
+  //-------------------------------SelectMenu541-----------------------------------------
+  //SET MOD
+  case 542 :
+    if(y<Nbitems){vmodE = y;switchmenu(54);EEPROM.write(16,vmodE);}
+    else{switchmenu(54);}
+  break;
+  //-------------------------------SelectMenu541-----------------------------------------
+  //SET MOD
+  case 543 :
+    if(y<Nbitems){f1modE = y;switchmenu(54);EEPROM.write(17,f1modE);}
+    else{switchmenu(54);}
+  break;
+  //-------------------------------SelectMenu541-----------------------------------------
+  //SET MOD
+  case 544 :
+    if(y<Nbitems){f2modE = y;switchmenu(54);EEPROM.write(18,f2modE);}
+    else{switchmenu(54);}
+  break;
+  }
+}
+
+
+
+
+
+


Add a link to available wav files for SDWavPlayer example

--- examples/02-Utility/SDWavPlayer/SDWavPlayer.ino
+++ examples/02-Utility/SDWavPlayer/SDWavPlayer.ino
@@ -5,6 +5,8 @@
  * Based On: WaveFilePlayer from Paul Stoffregen, PJRC, Teensy
  *
  * Play back a WAV file through the Typman.
+ *
+ * For access to WAV files, please visit https://www.pjrc.com/teensy/td_libs_AudioDataFiles.html.
  *
  */


added USP lib as option, output message fixes

--- uArm.ino
+++ uArm.ino
@@ -88,7 +88,9 @@
 	uView.begin();
 	uView.clear(PAGE);
 	uView.display();
-
+}
+
+void setupMicroViewSliders(void) {
 	widgetL = new MicroViewSlider(0, 0, 0, 180);
 	widgetR = new MicroViewSlider(0, 10, 0, 180);
 	widgetRot = new MicroViewSlider(0, 20, 0, 180);
@@ -123,12 +125,33 @@
 extern int chlID;

 void setup_ESP8266(void) {
+	uView.setCursor(0,0);
+	uView.print("wifi begin");
+	uView.display();
 	while (!wifi.begin());
-	while (!wifi.Initialize(STA, SSID, PASSWORD));
+	uView.setCursor(0,10);
+	uView.print("wifi init");
+	uView.display();
+	while (!wifi.Initialize(AP_STA, SSID, PASSWORD));
+	delay(2000);
+	String ipstring = wifi.showIP();
+	uView.setCursor(0,20);
+	uView.print(ipstring.substring(8));
+	uView.display();
+	uView.setCursor(0,30);
+	delay(1000);
+	uView.print("mux 1");
+	uView.display();
 	wifi.confMux(1);
+	delay(100);
+	uView.setCursor(0,40);
+	uView.print("server 23");
+	uView.display();
 	wifi.confServer(1, 23);
-}
-
+	delay(8000);
+	uView.clear(PAGE);
+	uView.display();
+}
 #endif

 void sendMsg(String msg) {
@@ -143,12 +166,18 @@
 	String msg;

 	// setup serial port
-	Serial.begin(115200);
+	Serial.begin(9600);

 	// setup MicroView
 	setupMicroView();

+#ifdef USE_ESP8266_LIB
+	// ESP8266
+	setup_ESP8266();
+#endif
+
 	// setup servos
+	setupMicroViewSliders();
 	attachServos();

 	// place servo in positions
@@ -158,12 +187,9 @@
 	moveServoHRot(defaultServoPos, servoSpeed, false, false);
 	moveServoH(defaultServoPos, servoSpeed, true, true);

-#ifdef USE_ESP8266_LIB
-	// ESP8266
-	setup_ESP8266();
-#endif
-	msg = String(F("READY\n"));
-	sendMsg(msg);
+	delay(4000);
+
+	sendMsg(F("READY\n"));
 }

 /*
@@ -179,7 +205,8 @@
 **	XXX = 100; reset
 **	XXX = 101; print free memory
 **	XXX = 102; report current servo desination positions
-**	XXX = 112; emergency stop
+**	XXX = 112; emergency stop (detach servo timers)
+**	XXX = 113; reattach servo timers
 */

 bool parseCommandGServo(char **buf, bool speedControl, bool wait) {
@@ -262,7 +289,7 @@
 		case 'G': case 'g':
 			code = strtoul(&buf[1], &endptr, 10);
 			if (endptr == &buf[1]) {
-				sendMsg(F("ERROR: missing G command code"));
+				sendMsg(F("ERROR: missing G command code\n"));
 				return false;
 			}
 			if (code == 0) {
@@ -294,7 +321,7 @@
 						return false;
 					}
 				} else {
-					sendMsg(F("ERROR: invalid G command wait flag (missing value)"));
+					sendMsg(F("ERROR: invalid G command wait flag (missing value)\n"));
 					return false;
 				}
 			}
@@ -310,18 +337,20 @@
 					(i == servoMoveCount - 1 ? false : wait), (i == servoMoveCount - 1 ? true : false));
 			}
 			if (i != 0) {
-				sendMsg(F("OK"));
-			}
+				sendMsg(F("OK\n"));
+				return true;
+			}
+			return false;
 			break;
 		case 'F': case 'f':
 			code = strtoul(&buf[1], &endptr, 10);
 			if (endptr == &buf[1]) {
-				sendMsg(F("ERROR: missing F speed parameter"));
+				sendMsg(F("ERROR: missing F speed parameter\n"));
 				return false;
 			}
 			if (code >= 0 && code <= 255) {
 				servoSpeed = code;
-				sendMsg(F("OK"));
+				sendMsg(F("OK\n"));
 				return true;
 			} else {
 				String msg = String(F("ERROR: invalid F speed parameter: ")) + String(code, DEC) + String("\n");
@@ -332,12 +361,12 @@
 		case 'M': case 'm':
 			code = strtoul(&buf[1], &endptr, 10);
 			if (endptr == &buf[1]) {
-				sendMsg(F("ERROR: missing M address parameter"));
+				sendMsg(F("ERROR: missing M address parameter\n"));
 				return false;
 			}
 			switch (code) {
 				case 100:
-					sendMsg(F("OK"));
+					sendMsg(F("OK\n"));
 					softwareReset();
 					break;
 				case 101:
@@ -353,31 +382,46 @@
 					break; }
 				case 112:
 					detachServos();
-					sendMsg(F("OK"));
+					sendMsg(F("OK\n"));
 					break;
 				case 113:
 					attachServos();
-					sendMsg(F("OK"));
+					sendMsg(F("OK\n"));
 					break;

 				default:
 					sendMsg(String(F("ERROR: invalid M address parameter: ")) + String(code, DEC) + String("\n"));
 					return false;
 			};
+			return true;
 			break;
 		default:
 			sendMsg(String(F("ERROR: invalid command: ")) + String(buf[0]) + String("\n"));
 			return false;
 	};
+	sendMsg(String(F("ERROR: Unhandled exception in processCommand\n")));
+	return false;
 }

 // main loop
 const uint8_t MAX_CMD_LEN = 128;
 char buf[MAX_CMD_LEN + 1], c;
+#ifndef USE_ESP8266_LIB
 bool suspendStore = false;
-uint8_t len = 0, cidx = 0;
+uint8_t cidx = 0;
+#endif
+uint8_t len = 0;

 void loop() {
+#ifdef USE_ESP8266_LIB
+        len = wifi.ReceiveMessage(buf);
+        if (len > 0) {
+uView.setCursor(0,0);
+uView.print(buf);
+uView.display();
+                processCommand(buf);
+        }
+#else
 	// read to newline
 	// ignore any line that has over 32 characters
 	if (Serial.available() > 0) {
@@ -395,9 +439,10 @@
 				buf[cidx] = c;
 				++cidx;
 			} else {
-				Serial.println(F("ERROR: command line too long"));
+				sendMsg(F("ERROR: command line too long\n"));
 				suspendStore = true;
 			}
 		}
 	}
-}
+#endif
+}


Add data-sending functions

Add data-sending functions

--- src/arduino/touchy.ino
+++ src/arduino/touchy.ino
@@ -5,11 +5,76 @@
 #define CHK(x,y) (x & (1<<y))     // |
 #define TOG(x,y) (x^=(1<<y))      // +

-#define N 160  // Number of frequencies
-
 int   num_freqs = 160;
 float results[num_freqs];
 float freq[num_freqs];
+
+// Note: x/y arguments reversed from original code (was y then x)
+void send(int cmd, unsigned int x, unsigned int y) {
+  byte x_msb    = 0,
+       x_lsb    = 0,
+       y_msb    = 0,
+       y_lsb    = 0,
+       z        = 128, // zero-byte (10000000)
+       checksum = 0;
+
+  x_lsb = lowByte(x);
+  x_msb = highByte(x);
+  y_lsb = lowByte(y);
+  y_msb = highByte(y);
+
+  // Set bit 1 high
+  if(x_lsb == 0) {
+    x_lsb = 1;
+    z    += 1;
+  }
+
+  // Set bit 2 high
+  if(x_msb == 0) {
+    x_msb = 1;
+    z    += 2;
+  }
+
+  // Set bit 3 high
+  if(y_lsb == 0) {
+    y_lsb = 1;
+    z    += 4;
+  }
+
+  // Set bit 4 high
+  if(y_msb == 0) {
+    y_msb = 1;
+    z    += 8;
+  }
+
+  // Get remainder of sum of all bytes divided by 255
+  checksum = (cmd + x_msb + x_lsb + y_msb + y_lsb + z) % 255;
+
+  if(checksum !=0 ) {
+   Serial.write(byte(0));   // Start byte
+   Serial.write(byte(cmd)); // Command byte
+
+   Serial.write(byte(x_msb));
+   Serial.write(byte(x_lsb));
+   Serial.write(byte(y_msb));
+   Serial.write(byte(y_lsb));
+
+   Serial.write(byte(z));        // Which values have a zero value
+   Serial.write(byte(checksum));
+  }
+}
+
+void send_all(unsigned int cmd, float arr1[], arr2[]) {
+  // Tell computer data is about to be sent
+  send(cmd + 1, 1, 1);
+  delay(1);
+
+  for(int ndx = 0; ndx < num_freqs; ndx++) {
+    send(cmd, round(arr1[ndx]), round(arr2[ndx]));
+  }
+
+  send(cmd + 2, 1, 1);
+}

 void setup() {
   TCCR1A = 0b10000010; // Set up frequency generator
@@ -50,7 +115,7 @@
     freq[d] = d;
   }

-  PlottArray(1,freq,results);
+  send_all(1, freq, results);

   TOG(PORTB,0); // Toggle pin 8 after each sweep (good for scope)
 }


Update Power Monitor

Update Power Monitor

It now talks to a Phant server instead of thingspeak, plus many other tweaks.

--- basicPowerMonitor.ino
+++ basicPowerMonitor.ino
@@ -1,22 +1,75 @@
-  #include "ThingSpeak.h"
+  /**
+   * Power Monitor sketch, this monitors the energy usage on analog ports using
+   * the emonlib. It updates a phant server roughly every 4s with the data. It also monitors errors
+   * and in conjunction with a watchdog timer, will attempt a reset if the amount of errors that occur
+   * exceed a certain value. This is VERY useful. The energy monitor will try to keep itself running without
+   * locking up, and if it does, the watchdog will take care of that.
+   *
+   * If you are using the standard ethernet controller, include the correct library, I am using the w5200.
+   * The code includes a 'hack' way of resetting the ethernet controller, with the reset pin attached to A5.
+   *
+   * Author: Jadin Andrews
+   * jadinandrews@gmail.com
+   */
+
+  #include <Phant.h>
   #include <SPI.h>
   #include <EthernetV2_0.h>
   #include "EmonLib.h"
+  #include <avr/wdt.h>

   EnergyMonitor circuit_1;
   EnergyMonitor circuit_2;
   EnergyMonitor circuit_3;

   EthernetClient client;
+
+  // The following variables need to be set.
+  IPAddress ip(192, 168, 0, 5);
   byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
-  unsigned long myChannelNumber = xxxxx;
-  const char * myWriteAPIKey = "xxxxxxxxxxxx";
+  const char * publicKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
+  const char * privateKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
+  const char server[] = "phant.io";
+
+  //Construct the Phant object.
+  Phant data(server, publicKey, privateKey);
+
+  // keeps track of current errors.
+  int errors;
+  int locked_up = 0;
+  int max_errors = 8;

 void setup() {
-  //Serial.begin(9600);
-  //Serial.println("Energy Monitor Initializing");
-  Ethernet.begin(mac);
-  ThingSpeak.begin(client);
+  locked_up = 0;
+  erorrs = 0;
+
+  /**
+   * setup the watchdog timer, it runs every 8s and checks that there aren't too many errors.
+   * if too many errors occur, initialize a soft reset.
+   */
+  setupWDT();
+
+  //Disable the SD card:
+  pinMode(4,OUTPUT);
+  digitalWrite(4,HIGH);
+
+  //reset ethernet at power on to avoid lock up.
+  resetEthernet(A5);
+  delay(500);
+
+  Serial.begin(9600);
+  Serial.println("Energy Monitor Initializing");
+
+  // start the Ethernet connection:
+  if (Ethernet.begin(mac) == 0) {
+    //Serial.println("Failed to configure Ethernet using DHCP");
+    // try to congifure using IP address instead of DHCP:
+    Ethernet.begin(mac, ip);
+  }
+  // give the Ethernet shield a second to initialize:
+  delay(1000);
+
+  //Construct energy monitor objects
   circuit_1.current(1, 30);
   circuit_2.current(2, 30);
   circuit_3.current(3, 30);
@@ -24,19 +77,122 @@
 }

 void loop() {
-  float circuit_1_Irms = circuit_1.calcIrms(1480) * 230 / 1000;
-  float circuit_2_Irms = circuit_2.calcIrms(1480) * 230 / 1000;
-  float circuit_3_Irms = circuit_3.calcIrms(1480) * 230 / 1000;
-  ThingSpeak.setField(1, circuit_1_Irms);
-  ThingSpeak.setField(2, circuit_2_Irms);
-  ThingSpeak.setField(3, circuit_3_Irms);
-  ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
-  //Serial.print("Power on circuit_1 : ");
-  //Serial.println(circuit_1_Irms);
-  //Serial.print("Power on circuit_2 : ");
-  //Serial.println(circuit_2_Irms);
-  //Serial.print("Power on circuit_3 : ");
-  //Serial.println(circuit_3_Irms);
-  //Serial.println();
-  delay(20000);
+  // Set to zero to indicate to the WDT that the program has not locked up.
+  locked_up = 0;
+
+  Serial.print("Errors: ");
+  Serial.println(errors);
+
+  // Get readings and convert to kW.
+  float circuit_1_Irms = circuit_1.calcIrms(2000) * 230 / 1000;
+  float circuit_2_Irms = circuit_2.calcIrms(2000) * 230 / 1000;
+  float circuit_3_Irms = circuit_3.calcIrms(2000) * 230 / 1000;
+
+  // Add readings to POST field constructor and filter out unwanted noise range.
+  data.add("kw1", rejectLowValues(circuit_1_Irms, 0.03));
+  data.add("kw2", rejectLowValues(circuit_2_Irms, 0.03));
+  data.add("kw3", rejectLowValues(circuit_3_Irms, 0.03));
+
+    if (client.connect(server, 8080)) {
+      // Make a HTTP request:
+      client.println(data.post());
+
+      // Wait for response
+      int count = 0;
+      while (!client.available()){
+        delay(10);
+        count++;
+        if (count >= 500){
+          //Response took too long
+          errors++;
+          break;
+        }
+      }
+      //Serial.print("Response took: ");
+      //Serial.print(count*10);
+      //Serial.println(" milliseconds");
+
+      // Read in response, need to add in a response parser to check server response.
+      while (client.available()) {
+      break; // Actually don't need the response just yet, break out for now.
+      //char c = client.read();
+      //Serial.print(c);
+    }
+  }
+  else
+  {
+    // if you didn't get a connection to the server:
+    errors++;
+  }
+
+  client.stop();
+  delay(4000);
 }
+
+/**
+ * resetEthernet reset the ethernet controller.
+ * @param pin is to be directly connected to the reset pin on the ethernet shield.
+ */
+void resetEthernet(int pin) {
+  pinMode(pin, OUTPUT);
+  digitalWrite(pin, LOW);
+  delay(500);
+  digitalWrite(pin, HIGH);
+}
+
+/**
+ * rejectLowValues is one serious hack to remove unwanted noise.
+ * @param value is the value to 'clean'
+ * @param cutOff is the value of the filter
+ * @returns a float that is superficially cleaner.
+ */
+float rejectLowValues(float value, float cutOff) {
+  if (value > cutOff)
+  {
+    return value;
+  }
+  else
+  {
+    return 0.0;
+  }
+}
+
+/**
+ * resetFunc is a software reset function. It does not properly reset, it just returns the cpu to the beginning of the
+ * program. ie: goto 0.
+ */
+void(* resetFunc)(void) = 0;
+
+/**
+ * setupWDT sets up the watchdog timer bits and scaler to execute every 8s.
+ */
+void setupWDT()
+{
+  // Clear the reset flag.
+  MCUSR &= ~(1<<WDRF);
+
+  // In order to change WDE or the prescaler, we need to
+  // set WDCE (This will allow updates for 4 clock cycles).
+  WDTCSR |= (1<<WDCE) | (1<<WDE);
+
+  // Set new watchdog timeout prescaler value
+  // 8.0 seconds
+  WDTCSR = 1<<WDP0 | 1<<WDP3;
+
+  // Enable the WD interrupt.
+  WDTCSR |= _BV(WDIE);
+}
+
+/**
+  * The WDT_vect routine is called by the WDT interrupt.
+  * The Arduino will be reset once a day in case of lock ups.
+  *
+  */
+ISR(WDT_vect)
+{
+  locked_up++;
+   if (errors >= max_errors || locked_up >= max_errors)
+   {
+     resetFunc();
+   }
+}


Delete airsolarcontroller.ino

Delete airsolarcontroller.ino

--- airsolarcontroller.ino
+++ airsolarcontroller.ino
@@ -1,874 +0,0 @@
-/*
-   Arduino Solar Controller - ASC-Kit v1.3
-
-   by karldm, Dec 2016
-
-
-   The MIT License (MIT)
-
-   Copyright (c) 2016 www.renergia.fr
-
-   Permission is hereby granted, free of charge, to any person obtaining a copy
-   of this software and associated documentation files (the "Software"), to deal
-   in the Software without restriction, including without limitation the rights
-   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-   copies of the Software, and to permit persons to whom the Software is
-   furnished to do so, subject to the following conditions:
-
-   The above copyright notice and this permission notice shall be included in all
-   copies or substantial portions of the Software.
-
-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-   SOFTWARE.
-*/
-
-//-------1---------2---------3---------4---------5---------6---------7---------8
-#define VERSION "asc.0.0i"        // Software version
-#define TAG10   "ASCKit...."      // Tag for EEPROM data structure check -- unused
-
-//
-// SOLAR HEATER STATES
-// modes  : OFF - HEAT
-// states : OFF - ON
-//
-// MAIN HEATER
-// modes  : OFF - HEAT - ECO - FP
-// states : ON - OFF
-
-#define OFF     0                  // OFF mode or state
-#define ON      1                  // ON state
-#define HEAT    1                  // main heater & solar heater HEAT mode
-#define ECO     2                  // Main heater ECO mode
-#define FP      3                  // Main heater freeze protection
-
-//
-// CONTROLLER
-// states : STOP - RUN - INIT - FAIL1 - FAIL2
-//
-#define STOP      0                // Controller STOP state or mode
-#define RUN       1                // Controller RUN state or mode
-#define INIT      2                // Controller INIT state -- power onP
-#define FAIL1     3                // Controller FAIL1 -- solar heater OFF due to TCOL measurement error
-#define FAIL2     4                // Controller FAIL2 state -- sh and mh OFF due to TAMB measurements error
-
-// Hardware configuration
-#define PINDHT    2                // DHT sensor bus
-#define PINLED1   3                // White LED status pin number
-#define PINOW1    4                // OW1 Bus pin number (single sensor TCOL)
-#define PINOW2    5                // OW2 Bus pin number (single sensor TEXT)
-#define PINOW3    6                // OW1 Bus pin number (single sensor TUSR1)
-#define PINOW4    7                // OW2 Bus pin number (single sensor TUSR2)
-#define PINSWMH   8                // SWMH pin number
-#define PINSWSH   9                // SWSH pin number
-#define PINSWUSR 12                // SWUSR pin number
-
-// sensors
-// masks for the ERRSENSOR parameter (use for error diagnostic)
-#define MASKTAMB   0b00000001
-#define MASKHAMB   0b00000010
-#define MASKTCOL   0b00000100
-#define MASKTEXT   0b00001000
-#define MASKTUSR1  0b00010000
-#define MASKTUSR2  0b00100000
-
-#define TEMPERATURE_RESOLUTION 12  // nb bits for DS18B20 sensors
-
-//=== DHT SENSOR MODEL ===
-#define DHTTYPE DHT22            // DHT 22  == AM2302 == AM2321
-
-// includes
-#include <avr/pgmspace.h>
-
-#include <Console.h>
-#include <Bridge.h>
-
-#include <DHT.h>
-#include <OneWire.h>
-#include <DallasTemperature.h>
-
-#include "ascutil.h"
-#include "ascdata.h"
-
-//-------1---------2---------3---------4---------5---------6---------7---------8
-// Ascdata objet - global access -- needed?
-Ascdata ascdata;
-
-/************************************************************/
-/***    PARAMETERS TYPE DECLARATION AND DEFAULT VALUES    ***/
-/************************************************************/
-
-// available types are :
-//   byte
-//   int            => TEMP
-//   unsigned long  => ULONG
-
-/*
- * Sensors
- */
-TEMP   TAMB;               // ambiant temperature (.01 degC)
-int    HAMB;               // humidity (0.01%)
-TEMP   TCOL;               // collector temperature (.01 degC)
-TEMP   TEXT;               // external temperature (.01 degC)
-TEMP   TUSR1;              // temperature user#1 (.01 degC)
-TEMP   TUSR2;              // temperature user#2 (.01 degC)
-
-/*
- * Calculated
- */
-int    NLOOPS = 0;         // number of loops per sec
-int    PSOLTH = 0;         // heating solar power (W)
-byte   SWSH = OFF;         // Solar heater switch (FAN)
-byte   SWMH = OFF;         // Main heater switch
-byte   SWUSR = OFF;        // user switch
-byte   STATESH = OFF;      // begin with the OFF state
-byte   STATEMH = OFF;      // begin with OFF state
-byte   STATECTRL = INIT;   // controller INIT state at power on
-byte   ERRSENSOR = 0;      // error status on sensor -- begin with no error
-byte   ERRCTRL = 0;        // internal error id# -- go to STOP mode if != 0
-ULONG  INDSH = 0;          // Cumulative index of solar energy (Wh)
-ULONG  TCSH = 0;           // Cumulated time of SH usage (h)
-ULONG  TCMH = 0;           // Cumulated time of MH usage (h)
-
-/*
- * Controller parameters
- */
-TEMP   TSET = 2400;        // set point (.01 degC)
-TEMP   DTECO = 500;        // delta T eco (.01 degC)
-byte   MODESH = ON;        // mode solar heater
-byte   MODEMH = ON;        // mode main heater
-ULONG  TMHON = 120;        // min time main heater in ON state(s)
-ULONG  TMHOFF = 120;       // min time main heater in OFF state(s)
-ULONG  TSHON = 120;        // min time Fan in ON state (s)
-ULONG  TSHOFF = 120;       // min time Fan in OFF state (s)
-TEMP   DTSHON = 600;       // delta T Fan ON (.01 deg.C)
-TEMP   DTSHOFF = 300;      // delta T Fan OFF (.01 deg.C)
-TEMP   AUG1 = 200;         // Solar heater set point delta (.01 deg.C)
-TEMP   AUG2 =   0;         // Main heater set point delta (.01 deg.C)
-TEMP   TFP = 800;          // Freeze protection set point (.01 deg.C)
-TEMP   HYST = 100;         // Hysteresis parameter (.01 deg.C)
-TEMP   DTDHT = 0;          // Overheating of the ambiance sensor when mounted inside the DIN package -- 0 if external mounting
-                           // 1000 for closed mounting
-int    VFAN = 200;         // Fan flow (cub.m/h)
-int    ASOLT = 4;          // Thermal collectors total area (sq.m) -- for INDSH calculation
-byte   SYSTEM = 1;         // System type (1=MH only, 2=MH+SH)
-byte   CONF1 = 1;          // Air circulation configuration (1=External, 2=Recirculated) -- for INDSH calculation
-
-/************************************************************/
-/********** END PARAMETERS DEFAULT VALUES *******************/
-/************************************************************/
-
-// Define the x.hour counters
-Counterh counterhTCMH( TCMH );   // time usage main heater (h)
-Counterh counterhTCSH( TCSH );   // time usage solar heater (h)
-Counterh counterhINDSH( INDSH ); // estimated usefull solar energy (Wh)
-
-// Various timers - see usage in util.cpp
-// declare delays in millis
-Timer  timerOW( 750 / (1 << (12 - TEMPERATURE_RESOLUTION)) ); // min delay for DS18B20 convertion
-Timer  timerDHT( 2000 );          // DHT readout delay, may be reduced...
-Timer  timerMH( 0 );              // main heater time-in-state, begin with OFF state
-Timer  timerSH( 0 );              // solar heater time-in-state, begin with OFF state
-Timer  timerEEPROM( ONEHOURMS );  // update period of EEPROM data
-Timer  timerLED( 3456 );          // flash the LED1
-Timer  timerBridge( 2000 );       // synchronize bridge data (i.e. commands responsivity...)
-
-// DHT sensor bus
-DHT dht(PINDHT, DHTTYPE);
-
-// 1-Wire buses & sensors
-OneWire ow1(PINOW1);    // for TCOL
-OneWire ow2(PINOW2);    // for TAMB
-OneWire ow3(PINOW3);    // for TUSR1
-OneWire ow4(PINOW4);    // for TUSR2
-
-DallasTemperature sensor1(&ow1);
-DallasTemperature sensor2(&ow2);
-DallasTemperature sensor3(&ow3);
-DallasTemperature sensor4(&ow4);
-
-/*
- * === setup() ===
- */
-void setup() {
-  // Set PinMode
-  pinMode( PINLED1, OUTPUT );
-  pinMode( PINDHT, OUTPUT );
-  pinMode( PINOW1, OUTPUT );
-  pinMode( PINOW2, OUTPUT );
-  pinMode( PINSWMH, OUTPUT );
-  pinMode( PINSWSH, OUTPUT );
-  pinMode( PINSWUSR, OUTPUT );
-
-  // setoutputs -- check STATECTRL = INIT
-  // done azap -- set switches in OFF position
-  STATECTRL = INIT; // force the INIT state
-  StateEngine();    // calculate the heaters states
-  SetOutputs();     // set the outputs
-
-  // bridge
-  Bridge.begin();   // start the script /usr/bin/run-bridge on the MPU side
-
-  // infos to the console by PrintInfo()
-  // only for debug purpose! It's waiting for the console for ever
-  BeginInfo();      // start the Console if CONSOLE if defined in util.h -- dev
-  PrintInfo('i', "Arduino Solar Controller - Kit, v%s", VERSION);
-
-  /************************************************************
-     WARNING:
-     THE DECLARATION ORDER DEFINES THE DATA STORAGE IN EEPROM
-     ANY CHANGE WILL PREVENT TO RETRIEVE THE STORED DATAS
-   ************************************************************/
-  //
-  // Parameters declaration
-  // ( pointer, label, options)
-  // options = "<access> <format>" (! only one space)
-  //   where <access> = {pgs}
-  //                  p: put the value to datastore
-  //                  g: get the value from datastore
-  //                  s: save the value into the EEPROM
-  //         <format> = f4.2 (xxxx.xx) i -- ipv4 (x.x.x.x)
-  //
-
-  // usr : user parameters
-  ascdata.par_F( &TSET,     F("tset"),     F("gs f4.2"));
-  ascdata.par_F( &DTECO,    F("dteco"),    F("gs f4.2"));
-  ascdata.par_F( &MODESH,   F("modesh"),   F("gs i"));
-  ascdata.par_F( &MODEMH,   F("modemh"),   F("gs i"));
-
-  // dev : device parameters
-  ascdata.par_F( &TMHON,    F("tmhon"),    F("gs i"));
-  ascdata.par_F( &TMHOFF,   F("tmhoff"),   F("gs i"));
-  ascdata.par_F( &TSHON,    F("tshon"),    F("gs i"));
-  ascdata.par_F( &TSHOFF,   F("tshoff"),   F("gs i"));
-  ascdata.par_F( &DTSHON,   F("dtshon"),   F("gs f4.2"));
-  ascdata.par_F( &DTSHOFF,  F("dtshoff"),  F("gs f4.2"));
-  ascdata.par_F( &AUG1,     F("aug1"),     F("gs f4.2"));
-  ascdata.par_F( &AUG2,     F("aug2"),     F("gs f4.2"));
-  ascdata.par_F( &TFP,      F("tfp"),      F("gs f4.2"));
-  ascdata.par_F( &HYST,     F("hyst"),     F("gs f4.2"));
-  ascdata.par_F( &DTDHT,    F("dtdht"),    F("gs f4.2"));
-  ascdata.par_F( &VFAN,     F("vfan"),     F("gs i"));
-  ascdata.par_F( &ASOLT,    F("asolt"),    F("gs i"));
-  ascdata.par_F( &SYSTEM,   F("system"),   F("gs i"));
-  ascdata.par_F( &CONF1,    F("conf1"),    F("gs i"));
-
-  // Calculated
-  ascdata.par_F( &NLOOPS,   F("nloops"),   F("p i"));
-  ascdata.par_F( &PSOLTH,   F("psolth"),   F("p i"));
-  ascdata.par_F( &INDSH,    F("indsh"),    F("ps i"));     // update period tbd
-  ascdata.par_F( &TCMH,     F("tcmh"),     F("ps i"));     // update period tbd
-  ascdata.par_F( &TCSH,     F("tcsh"),     F("ps i"));     // update period tbd
-
-  // sensors & switches
-  ascdata.par_F( &TAMB,     F("tamb"),     F("p f4.2"));
-  ascdata.par_F( &HAMB,     F("hamb"),     F("p f4.2"));
-  ascdata.par_F( &TCOL,     F("tcol"),     F("p f4.2"));
-  ascdata.par_F( &TEXT,     F("text"),     F("p f4.2"));
-  ascdata.par_F( &TUSR1,    F("tusr1"),    F("p f4.2"));
-  ascdata.par_F( &TUSR2,    F("tusr2"),    F("p f4.2"));
-  ascdata.par_F( &SWSH,     F("swsh"),     F("p i"));
-  ascdata.par_F( &SWMH,     F("swmh"),     F("p i"));
-  ascdata.par_F( &SWUSR,    F("swusr"),    F("gs i"));     // user switch -- saved?
-
-  // states
-  ascdata.par_F( &STATEMH,  F("statemh"),  F("p i"));
-  ascdata.par_F( &STATESH,  F("statesh"),  F("p i"));
-  ascdata.par_F( &STATECTRL, F("statectrl"), F("p i"));
-
-  // errors
-  ascdata.par_F( &ERRSENSOR, F("errsensor"), F("p i"));
-  ascdata.par_F( &ERRCTRL,   F("errctrl"),   F("p i"));
-
-  /************************************************************/
-  /***************  END OF DECLARATION   **********************/
-  /************************************************************/
-  ascdata.getNpar(); // info on data usage if console activated -- dev
-
-  //
-  // Get configuration from EEPROM (if available and consistent with the present version (TAG10)
-  //
-  PrintInfo( 'i', F("Get EEPROM saves data..."));
-
-  if ( ascdata.EEPROM_get( TAG10, 0 ) != 0 ) {
-    // data structure not compatible
-    // Note: EEPROM is reset after a schetch upload => we write the default values
-    PrintInfo( 'w', F("EEPROM TAG error."));
-    // then update the EEPROM with the defaults values defined in the sketch
-    // counters values are reset
-    PrintInfo( 'i', F("Update EEPROM data with the sketch default values..."));
-    ascdata.EEPROM_put( TAG10, 0 );
-    // write the default values into EEPROM as well
-    ascdata.EEPROM_put( TAG10, 1 );
-  }
-  else {
-    // Data retrieved from the EEPROM are ok
-    // Update counters values
-    counterhTCMH.set( TCMH );
-    counterhTCSH.set( TCSH );
-    counterhINDSH.set( INDSH );
-  }
-
-  //
-  // 1-Wire Initialization
-  //
-  // Start up the library and define the resolution
-  // Define the Async mode
-  // Start a conversion
-  //
-  OWsensorBegin( sensor1 );
-  OWsensorBegin( sensor2 );
-  OWsensorBegin( sensor3 );
-  OWsensorBegin( sensor4 );
-
-  // Keys generation in datastore
-  //
-  // put all the data to create the keys
-  ascdata.bridgePut('*'); // create all the keys in datastore
-
-  // add the 'version' data
-  ascdata.bridgePutVersion( VERSION );
-
-  // add the 'request' data
-  ascdata.bridgePutRequest("none");
-
-  // start the controller
-  LedBlinkingN( PINLED1, 200, 4 ); // indicate that the INIT phase is finished
-  STATECTRL = RUN; // go into RUN state after power on
-
-  // setup() finished
-  PrintInfo( 'i', F("Starting loop()..."));
-}
-
-/*
- * === loop() ===
- */
-void loop() {
-  //
-  static int nloops = 0;
-  static Timer timerLoops( 1000 );
-  int index;
-
-  ReadSensors();
-  CalcParameters();
-  StateEngine();
-  SetOutputs();
-
-  // loop performance calculation
-  nloops++;
-  if ( timerLoops.check() ) {
-    NLOOPS = nloops; // nb loops per sec
-    nloops = 0;
-  }
-
-  if ( timerBridge.check() ) {
-    // Bridge synchronization
-    // do it only at low rate (~500ms), but may be optimized
-    //
-    // Retrieve data from datastore (bridge)
-    // We get only the 'g' access values
-    if ( ascdata.bridgeGet('g') != 0 ) {
-      ascdata.EEPROM_put( TAG10, 0 ); // update EEPROM data if some modifications in saved data
-      PrintInfo( 'i', F("EEPROM update due to datastore change"));
-    }
-
-    // Update the data into datastore (bridge)
-    // we only put the 'p' access values
-    // you should not have both 'p' and 'g' access for the same data...
-    ascdata.bridgePut('p');
-
-    // request handle
-    // see RequestHandle()
-    if (ascdata.bridgeGetRequest()) {
-      ascdata.bridgePutRequest("none"); // reset request into datastore
-      RequestHandle();                  // execute the request
-    }
-  }
-
-  if ( timerEEPROM.check() ) {
-    ascdata.EEPROM_put( TAG10, 0 ); // periodic update of EEPROM saved data (counters)
-    PrintInfo( 'i', F("timerEEPROM update."));
-  }
-}
-
-/*
- * === ReadSensors() ===
- */
-void ReadSensors() {
-  // read the sensors
-  // what if an error occur?
-  // no check for time serie (i.e. glitches)
-  float dhtval;
-
-  /////////////////////
-  // Read DHT sensor //
-  // TAMB & HAMB     //
-  /////////////////////
-  if ( timerDHT.check() ) {
-
-    dhtval = dht.readTemperature(); // default is Celsius
-    if (isnan(dhtval)) {
-      // FAIL
-      if ( IsSensorValid( MASKTAMB ) ) PrintInfo( 'w', F("Failed to read from DHT sensor TAMB!...")); // only once
-      ErrSensorRaise( MASKTAMB );
-    }
-    else {
-      if ( !IsSensorValid( MASKTAMB ) ) PrintInfo( 'i', F("DHT sensor TAMB ok...")); // only once
-      TAMB = int(100 * dhtval) - DTDHT; // correction for overheating
-      ErrSensorClear( MASKTAMB );
-    }
-
-    dhtval = dht.readHumidity();
-    if (isnan(dhtval)) {
-      // soft FAIL
-      if ( IsSensorValid( MASKHAMB ) ) PrintInfo( 'w', F("Failed to read from DHT sensor HAMB!...")); // only once
-      ErrSensorRaise( MASKHAMB );
-    }
-    else {
-      if ( !IsSensorValid( MASKHAMB ) ) PrintInfo( 'i', F("DHT sensor HAMB ok...")); // only once
-      HAMB = int(100 * dhtval);
-      //simple correction for humidity
-      HAMB = HAMB + 100*int(DTDHT/(2*(100-int(HAMB/100))/3+6));
-      ErrSensorClear( MASKHAMB );
-    }
-  }
-
-  ///////////////////////////
-  // Read OW1 Bus => TCOL  //
-  // Read OW2 Bus => TEXT  //
-  // Read OW3 Bus => TUSR1 //
-  // Read OW4 Bus => TUSR2 //
-  ///////////////////////////
-  if ( timerOW.check() ) {
-    //
-    // to do -- should add error messages
-    //
-    TCOL  = ReadOWbus( sensor1, MASKTCOL );
-    TEXT  = ReadOWbus( sensor2, MASKTEXT );
-    TUSR1 = ReadOWbus( sensor3, MASKTUSR1 );
-    TUSR2 = ReadOWbus( sensor4, MASKTUSR2 );
-  }
-}
-
-/*
- * === CalcParameters() ===
- */
-void CalcParameters() {
-  // Parameters calculation
-  PSOLTH = 0; // default value
-  if ( STATESH == ON ) {
-    // PSOLTH (W) -- check positive value
-    if ( CONF1 == 1 && TCOL > TEXT ) PSOLTH = int( 0.335 * VFAN * (TCOL - TEXT) / 100 ); // external air
-    if ( CONF1 == 2 && TCOL > TAMB ) PSOLTH = int( 0.335 * VFAN * (TCOL - TAMB) / 100 ); // recirculated
-  }
-
-  // counters calls for cumulative quantities
-  TCMH = int(counterhTCMH.add(1)); // time integration (h)
-  TCSH = int(counterhTCSH.add(1)); // time integration (h)
-  INDSH = int(counterhINDSH.add((unsigned long) PSOLTH)); // power integration (Wh)
-}
-
-/*
- * === StateEngine() ===
- */
-void StateEngine() {
-  //
-  // Define the controller state STATECTRL ( INTI - STOP - RUN - FAIL1 - FAIL2 ) -- INIT defined during setup()
-  // Define the heaters states: STATEMH & STATESH
-  // See SetOutputs()
-  //
-  // TO BE CHECKED -- correction FAIL2???
-  //
-  if ( STATECTRL == INIT ) {
-    STATEMH = OFF;
-    STATESH = OFF;
-  }
-  else if ( STATECTRL == STOP ) {
-    STATEMH = OFF;
-    STATESH = OFF;
-  }
-  else { // i.e. RUN, FAIL1 or FAIL2
-    if ( IsSensorValid(MASKTAMB)&& IsSensorValid(MASKTCOL) ) {
-      STATECTRL = RUN;
-      StateEngineMH();
-      StateEngineSH();
-    }
-    else if ( IsSensorValid(MASKTAMB)&& !IsSensorValid(MASKTCOL) ) {
-      // patch for single zone usage
-      if ( SYSTEM == 2 ) {
-        STATECTRL = FAIL1;
-      }
-      else {
-        STATECTRL = RUN; // ignore TCOL error
-      }
-      StateEngineMH();
-      STATESH = OFF;
-    }
-    else {
-      STATECTRL = FAIL2; // ok?
-      STATEMH = OFF;
-      STATESH = OFF;
-    }
-  }
-
-  if ( ERRCTRL != 0 ) { // catch internal error => STOP
-    STATECTRL = STOP;
-    STATEMH = OFF;
-    STATESH = OFF;
-    // the only way to quit this mode is to reset the board or to send /data/put/request/run
-  }
-}
-
-/*
- * === StateEngineMH() ===
- */
-void StateEngineMH() {
-  // Main heater
-  boolean c1, c2, c3, c4;     // conditions
-  TEMP tsetmh;                // internal setpoint -- depends on MODEMH
-
-  // define tsetmh -- depends on MODEMH
-  switch ( MODEMH ) {
-    case HEAT:
-      tsetmh = TSET;
-      break;
-
-    case ECO:
-      tsetmh = TSET - DTECO;
-      break;
-
-    case FP:
-      tsetmh = TFP;
-      break;
-
-    default:
-      tsetmh = TSET;
-  }
-
-  switch ( STATEMH ) {
-    case OFF:
-      // compute the conditions to go ON
-      c1 = (MODEMH != OFF);
-      c2 = timerMH.check( 1000*TMHOFF );               // is minimum time in the OFF state?
-      c3 = (TAMB < tsetmh) && (STATESH == OFF);          // condition if STATESH = OFF
-      c4 = (TAMB < tsetmh - AUG2) && (STATESH == ON);    // condition if STATESH = ON
-
-      if ( c1 && c2 && (c3 || c4) ) {
-        PrintInfo('i', F("Main heater switched to ON"));
-        STATEMH = ON;
-        timerMH.start();                               // restart timer
-        counterhTCMH.run();                            // run time counter
-      }
-      break;
-
-    case ON:
-      // compute the conditions to go OFF
-      c1 = (MODEMH == OFF);
-      c2 = timerMH.check( 1000*TMHON );                      // is minimum time in the ON state?
-      c3 = (TAMB > tsetmh + HYST) && (STATESH == OFF);       // condition if STATESH = OFF
-      c4 = (TAMB > tsetmh + HYST - AUG2) && (STATESH == ON); // condition if STATESH = ON
-
-      if ( c1 || (c2 && (c3 || c4)) ) {
-        PrintInfo('i', F("Main heater switched to OFF"));
-        STATEMH = OFF;
-        timerMH.start();                              // restart timer
-        counterhTCMH.stop();                          // stop time counter
-      }
-      break;
-
-    default:
-      // error in software
-      ERRCTRL = 91; // at least... call the vendor! -- ERRCTRL = ???
-      PrintInfo('w', F("Internal error ERRCTRL=91"));
-  }
-}
-/*
- * ===stateEngineSH() ===
- */
-void StateEngineSH() {
-  // Solar heater
-  boolean c1, c2, c3, c4;     // conditions
-
-  switch ( STATESH ) {
-    case OFF:
-      // compute the conditions to go ON
-      c1 = (MODESH == ON);
-      c2 = timerSH.check( 1000*TSHOFF );               // is minimum time in the OFF state?
-      c3 = (TCOL > TAMB + DTSHON);                     // solar collector temp condition
-      c4 = (TAMB < TSET + AUG1);                       // ambiant condition
-
-      if ( c1 && c2 && c3 && c4 ) {
-        PrintInfo('i', F("Solar heater switched to HEAT"));
-        STATESH = ON;
-        timerSH.start();                               // restart timer
-        counterhINDSH.run();                           // run energy counter
-        counterhTCSH.run();                            // run time counter
-      }
-      break;
-
-    case ON:
-      // compute the conditions to go OFF
-      c1 = (MODESH == OFF);
-      c2 = timerSH.check( 1000*TSHON );                // is minimum time in the ON state?
-      c3 = (TCOL < TAMB + DTSHOFF);                    // solar collector temp condition
-      c4 = (TAMB > TSET + HYST + AUG1);                // ambiant condition
-
-      if ( c1 || (c2 && (c3 || c4)) ) {
-        PrintInfo('i', F("Solar heater switched to OFF"));
-        STATESH = OFF;
-        timerSH.start();                               // restart timer
-        counterhINDSH.stop();                          // stop energy counter
-        counterhTCSH.stop();                           // stop time counter
-      }
-      break;
-
-    default:
-      // error in software
-      ERRCTRL = 92; // at least... call the vendor!
-      PrintInfo('w', F("Internal error ERRCTRL=92"));
-  }
-}
-
-/*
- * SetOutputs()
- */
-void SetOutputs() {
-  //
-  // Set the outputs regarding to the controller state
-  // the controller state is defined in StateEngine()
-  //
-  // Set the heaters switches -- defined by STATEMH and STATESH
-
-  // main heater
-  if (STATEMH == ON) {
-    SWMH = ON;
-    digitalWrite( PINSWMH, HIGH );
-  }
-  else {
-    SWMH = OFF;
-    digitalWrite( PINSWMH, LOW );
-  }
-
-  // solar heater
-  if (STATESH == ON) {
-    SWSH = ON;
-    digitalWrite( PINSWSH, HIGH );
-  }
-  else {
-    SWSH = OFF;
-    digitalWrite( PINSWSH, LOW );
-  }
-
-  // switch user -- no error catch, simply copy the SWUSR value
-  if (SWUSR == HIGH) {
-    digitalWrite( PINSWUSR, HIGH );
-  }
-  else {
-    digitalWrite( PINSWUSR, LOW );
-  }
-  //
-  // set the LED1
-  switch ( STATECTRL ) {
-
-    case INIT:
-      // show LED1
-      LedBlinkingN( PINLED1, 100, 4 ); // 4 short pulses
-      digitalWrite( PINLED1, HIGH );   // lighted during INIT phase
-      break;
-
-    case STOP:
-      LedBlinkingN( PINLED1, 100, 5 ); // 5 pulses
-      break;
-
-    case RUN:
-      // run phase: switches controlled by the states
-      //LedBlinking( PINLED1, 100, &timerLED ); // RUN => short flash
-      LedGlowing( PINLED1, 6740, 20, 100 );
-      break;
-
-    case FAIL1:
-      LedBlinkingN( PINLED1, 100, 1 ); // one pulse
-      break;
-
-    case FAIL2:
-      LedBlinkingN( PINLED1, 100, 2 ); // two pulses
-      break;
-  }
-}
-
-/*
- *  === RequestHandle() ===
- */
-void RequestHandle() {
-  //
-  // Requests from datastore: data/put/request/request_type
-  //
-  // stop:          set STATECTRL to STOP
-  //+run:           set STATECTRL to RUN
-  // default:       retrieve the EEPROM values
-  //+setdefault:    copy the current values into the EEPROM (default values)
-  // rst_indsh:     reset the solar ventilation energy counter
-  // rst_tcsh:      reset the solar ventilation time counter
-  // rst_tcsh:      reset the main heater time counter
-  //
-
-  if ( ascdata.isRequest("stop") ) {
-    PrintInfo( 'i', F("request = stop"));
-    STATECTRL = STOP;
-  }
-
-  else if ( ascdata.isRequest("run") ) {
-    PrintInfo( 'i', F("request = run"));
-    STATECTRL = RUN;
-  }
-
-  else if ( ascdata.isRequest("default") ) {
-    PrintInfo( 'i', F("request = default"));
-
-    // get default data from EEPROM
-    // no need to check the TAG
-    ascdata.EEPROM_get( TAG10, 1 );
-    // update saved values
-     ascdata.EEPROM_put( TAG10, 0 );
-
-    // Update current counters values -- reset!
-    counterhTCMH.set( TCMH );
-    counterhTCSH.set( TCSH );
-    counterhINDSH.set( INDSH );
-    // update datastore -- otherwise, current datastore data will be retrieved!
-    ascdata.bridgePut('s'); // only the saved data are modified
-  }
-
-  else if ( ascdata.isRequest("setdefault") ) {
-    PrintInfo( 'i', F("request = setdefault"));
-    PrintInfo( 'i', F("EEPROM default data update with current values."));
-
-    // save current data into EEPROM default data
-    ascdata.EEPROM_put( TAG10, 1 );
-  }
-
-  else if ( ascdata.isRequest("rst_indsh") ) {
-    PrintInfo( 'i', F("request = rst_indsh"));
-
-    INDSH = 0;
-    counterhINDSH.set( INDSH );  // set the counter value
-
-    // save the values
-    PrintInfo( 'i', F("EEPROM update with current values."));
-    // update EEPROM data with current values
-    ascdata.EEPROM_put( TAG10, 0 );
-
-    // update datastore -- to be sure!
-    ascdata.bridgePut('s'); // only the saved data are modified
-  }
-
-  else if ( ascdata.isRequest("rst_tcmh") ) {
-    PrintInfo( 'i', F("request = rst_tcmh"));
-
-    TCMH = 0;
-    counterhTCMH.set( TCMH );  // set the counter value
-
-    // save the values
-    PrintInfo( 'i', F("EEPROM update with current values."));
-    // update EEPROM data with current values
-    ascdata.EEPROM_put( TAG10, 0 );
-
-    // update datastore -- to be sure!
-    ascdata.bridgePut('s'); // only the saved data are modified
-  }
-
-  else if ( ascdata.isRequest("rst_tcsh") ) {
-    PrintInfo( 'i', F("request = rst_tcsh"));
-
-    TCSH = 0;
-    counterhTCSH.set( TCSH );  // set the counter value
-
-    // save the values
-    PrintInfo( 'i', F("EEPROM update with current values."));
-    // update EEPROM data with current values
-    ascdata.EEPROM_put( TAG10, 0 );
-
-    // update datastore -- to be sure!
-    ascdata.bridgePut('s'); // only the saved data are modified
-  }
-
-  else {
-    PrintInfo('w', F("Undefined request"));
-  }
-
-/*
- * === end request handle ===
- */
-}
-
-// #############################
-// utilities for ERRSENSOR usage
-// #############################
-
-/*
- * IsSensorValid()
- */
-bool IsSensorValid( byte mask ) {
-  // Return true if the sensor is ok
-  return( (ERRSENSOR & mask) == 0 );
-}
-
-/*
- * ErrSensorRaise()
- */
-void ErrSensorRaise( byte mask ) {
-  // Raise an error on sensor
-  ERRSENSOR = ERRSENSOR | mask;
-}
-
-/*
- * ErrSensorClear()
- */
-void ErrSensorClear( byte mask ) {
-  // Clear error on sensor
-  ERRSENSOR = ERRSENSOR & ~mask;
-}
-
-// ################
-// 1-Wire utilities
-// ################
-
-/*
- * OWsensorBegin()
- */
-void OWsensorBegin(DallasTemperature sensor) {
-  // OW begin
-  // variable to get the device address of a 1-wire sensor
-  DeviceAddress deviceAddress;
-  //
-  sensor.begin();
-  if (sensor.getAddress(deviceAddress, 0)) {
-    sensor.setResolution(deviceAddress, TEMPERATURE_RESOLUTION);
-    sensor.setWaitForConversion(false);
-    sensor.requestTemperatures(); // start conversion
-  }
-}
-
-/*
- * ReadOWbus()
- */
-TEMP ReadOWbus( DallasTemperature sensor, byte masksensor ) {
-  // Get OW temperature data -- single device connected
-  TEMP temp;
-  //
-  temp = int(100 * sensor.getTempCByIndex(0));  // the unique sensor has index 0
-  sensor.requestTemperatures();                 // restart a conversion
-  // test for bad reading
-  if ( (temp > -5000) && (temp < 12500) ) {
-    ErrSensorClear( masksensor );
-  }
-  else {
-    ErrSensorRaise( masksensor );
-  }
-  return( temp );
-}
-


fix..

fix..

--- VardeLED.ino
+++ VardeLED.ino
@@ -204,10 +204,10 @@
             }
             break;
           case 0x5200: { //OpSync
-            FastLED[0].show(led_data, NUM_PIXELS_OUT_1 *4.0/3.0, 255);
-            FastLED[1].show(led_data, NUM_PIXELS_OUT_2 *4.0/3.0, 255);
-            FastLED[2].show(led_data, NUM_PIXELS_OUT_3 *4.0/3.0, 255);
-            FastLED[3].show(led_data, NUM_PIXELS_OUT_4 *4.0/3.0, 255);
+            FastLED[0].show((CRGB*)led_data_ptr_1, NUM_PIXELS_OUT_1 *4.0/3.0, 255);
+            FastLED[1].show((CRGB*)led_data_ptr_2, NUM_PIXELS_OUT_2 *4.0/3.0, 255);
+            FastLED[2].show((CRGB*)led_data_ptr_3, NUM_PIXELS_OUT_3 *4.0/3.0, 255);
+            FastLED[3].show((CRGB*)led_data_ptr_4, NUM_PIXELS_OUT_4 *4.0/3.0, 255);
              /*FastLED[1].show(led_data, NUM_RGB_LEDS_3, 255);
               FastLED[2].show(led_data, NUM_RGB_LEDS_2, 255);
                FastLED[3].show(led_data, NUM_RGB_LEDS_1, 255);              */


Change replyidx to bufferIndex which better matches what it is used for.

--- Arduino/BlueCube/BlueCube.ino
+++ Arduino/BlueCube/BlueCube.ino
@@ -179,19 +179,19 @@
 void readPacket(Adafruit_BLE *ble, int timeout)
 {
   // Copy the Timeout period
-  int origtimeout = timeout, replyidx = 0;
+  int origtimeout = timeout, bufferIndex = 0;

   /* Buffer to hold incoming characters */
   char packetbuffer[READ_BUFSIZE+1];
   memset(packetbuffer, 0, READ_BUFSIZE);

   while (timeout--) {
-    if (replyidx >= 32) break;
+    if (bufferIndex >= 32) break;
     while (ble->available()) {
       char c =  ble->read();
       serial->print(c);
-      packetbuffer[replyidx] = c;
-      replyidx++;
+      packetbuffer[bufferIndex] = c;
+      bufferIndex++;
       timeout = origtimeout;
       if (c == ';') {
         serial->println();
@@ -204,9 +204,9 @@
     delay(1);
   }

-  packetbuffer[replyidx] = 0;  // null term
-
-  if (!replyidx)  // no data or timeout
+  packetbuffer[bufferIndex] = 0;  // null term
+
+  if (!bufferIndex)  // no data or timeout
     return;

   bytecode_t bytecode = {};


Fixed beginning padding of packages

Fixed beginning padding of packages

--- Arduino/WirelessReceiver/WirelessReceiver.ino
+++ Arduino/WirelessReceiver/WirelessReceiver.ino
@@ -27,33 +27,11 @@
   while (radio.available()) {
     radio.read(&buffer, sizeof(int16_t [16]));
   }
-  /*
-  Serial.write(buffer[0]);
-  Serial.write(buffer[1]);
-  Serial.write(buffer[2]);
-  Serial.write(buffer[3]);
-  Serial.write(buffer[4]);
-  Serial.write(buffer[5]);
-  Serial.write(buffer[6]);
-  Serial.write(buffer[7]);
-  Serial.write(buffer[8]);
-  Serial.write(buffer[9]);
-  Serial.write(buffer[10]);
-  Serial.write(buffer[11]);
-  Serial.write(buffer[12]);
-  Serial.write(buffer[13]);
-  Serial.write(bitRead(buffer[14], 0));
-  Serial.write(bitRead(buffer[14], 1));
-  Serial.write(bitRead(buffer[14], 2));
-  Serial.write(bitRead(buffer[14], 3));
-  Serial.write(bitRead(buffer[14], 4));
-  Serial.write(bitRead(buffer[14], 5));
-  Serial.write(bitRead(buffer[14], 6));
-  Serial.write(bitRead(buffer[14], 7));
-  Serial.write(buffer[15]);
-  Serial.println();
-  */

+  Serial.print(' ');
+  // First character can get corrupted by previous data,
+  // make sure we have an extra to trim
+  Serial.print(' ');
   Serial.print(buffer[0]);
   Serial.print(' ');
   Serial.print(buffer[1]);


Tweaks to improve high rate performance.

--- GVRET.ino
+++ GVRET.ino
@@ -366,9 +366,13 @@
 	uint8_t temp8;
 	uint16_t temp16;
 	static bool markToggle = false;
+	bool isConnected = false;
+
+	if (SerialUSB) isConnected = true;

 	//there is no switch debouncing here at the moment
 	//if mark triggering causes bounce then debounce this later on.
+	/*
 	if (getDigital(0)) {
 		if (!markToggle) {
 			markToggle = true;
@@ -379,33 +383,27 @@
 		}
 	}
 	else markToggle = false;
-
-
-  loops++;
-  if (loops > 200000ul) {
-	  loops = 0;
-	  //SerialUSB.print(".");
-  }
-
-  if (Can0.available() > 0) {
+	*/
+
+  while (Can0.available()) {
 	Can0.read(incoming);
 	toggleRXLED();
-	if (SerialUSB) sendFrameToUSB(incoming, 0);
+	if (isConnected) sendFrameToUSB(incoming, 0);
 	if (SysSettings.logToFile) sendFrameToFile(incoming, 0);
 		//these two lines are for testing. Don't uncomment them or you get slapped.
         //incoming.id += 1;
         //Can0.sendFrame(incoming);
-        sendFrameToUSB(incoming, 0);
+        //sendFrameToUSB(incoming, 0);
   }

-  if (Can1.available()) {
+  while (Can1.available()) {
 	Can1.read(incoming);
-	toggleRXLED();
-	if (SerialUSB) sendFrameToUSB(incoming, 1);
-	if (SysSettings.logToFile) sendFrameToFile(incoming, 1);
+	//toggleRXLED();
+	if (isConnected) sendFrameToUSB(incoming, 1);
+	//if (SysSettings.logToFile) sendFrameToFile(incoming, 1);
   }

-  if (SerialUSB && SerialUSB.available()) {
+  if (isConnected && SerialUSB.available() > 0) {
 	in_byte = SerialUSB.read();
 	if (in_byte != -1) { //false alarm....
 	   switch (state) {
@@ -659,6 +657,6 @@
   }
 	Logger::loop();
 	//this should still be here. It checks for a flag set during an interrupt
-	sys_io_adc_poll();
-}
-
+	//sys_io_adc_poll();
+}
+


More debugging of the serial fun.

More debugging of the serial fun.

--- arduino/TMSDoorAccess/TMSDoorAccess.ino
+++ arduino/TMSDoorAccess/TMSDoorAccess.ino
@@ -49,10 +49,14 @@
 int redRFIDStatusLED = 5;
 // The output relay is connected to pin 7
 int relay = 7;
-// The software serial for verification is connected to pins 2 (RX) & 3 (TX).
-int verifyRX = 10;
-int verifyTX = 11;
-SoftwareSerial mySerial( verifyRX, verifyTX);
+// The software serial for reading the RFID module to pins 8 (TX) & 9 (RX).
+int rfidRX = 8;
+int rfidTX = 9;
+SoftwareSerial serRFID( rfidRX, rfidTX);
+// The software serial for verification is connected to pins 10 (TX) & 11 (RX).
+int gatewayRX = 10;
+int gatewayTX = 11;
+SoftwareSerial serGateway( gatewayRX, gatewayTX);
 // Input buffer from RFID reader ( currently 16 bytes)
 int currentCharRFID = 0;
 char inputRFID[ 16];
@@ -71,9 +75,15 @@
   pinMode( greenRFIDStatusLED, OUTPUT);
   pinMode( redRFIDStatusLED, OUTPUT);
   pinMode( relay, OUTPUT);
+  // Setup the serial pins
+  pinMode( rfidRX, INPUT);
+  pinMode( rfidTX, OUTPUT);
+  pinMode( gatewayRX, INPUT);
+  pinMode( gatewayTX, OUTPUT);
   // Setup the serial ports
   Serial.begin( 9600);
-  mySerial.begin( 9600);
+  serRFID.begin( 9600);
+  serGateway.begin( 9600);
   // A bit of the ol' debug info
   Serial.println( "Goodnight moon!");
   Serial.println( "TinkerMill Member Management System (MMS)");
@@ -81,6 +91,8 @@
   // Trying to clear the buffers
   inputRFIDClearBuffer();
   inputGatewayClearBuffer();
+  // Make sure we're listening on the correct serial port
+  serRFID.listen();
 }

 /* ### HELPER FUNCTIONS ### */
@@ -133,21 +145,21 @@
   //   byte[ 13] - Checksum byte[ 1] ( from the reader) ( inputRFID[ 12])
   //   byte[ 14] - \r ( 0x0D)
   //   byte[ 15] - \n ( 0x0A)
-  mySerial.write( myID);
-  mySerial.write( inputRFID[ 1]);
-  mySerial.write( inputRFID[ 2]);
-  mySerial.write( inputRFID[ 3]);
-  mySerial.write( inputRFID[ 4]);
-  mySerial.write( inputRFID[ 5]);
-  mySerial.write( inputRFID[ 6]);
-  mySerial.write( inputRFID[ 7]);
-  mySerial.write( inputRFID[ 8]);
-  mySerial.write( inputRFID[ 9]);
-  mySerial.write( inputRFID[ 10]);
-  mySerial.write( inputRFID[ 11]);
-  mySerial.write( inputRFID[ 12]);
-  mySerial.write( 0x0D);
-  mySerial.write( 0x0A);
+  serGateway.write( myID);
+  serGateway.write( inputRFID[ 1]);
+  serGateway.write( inputRFID[ 2]);
+  serGateway.write( inputRFID[ 3]);
+  serGateway.write( inputRFID[ 4]);
+  serGateway.write( inputRFID[ 5]);
+  serGateway.write( inputRFID[ 6]);
+  serGateway.write( inputRFID[ 7]);
+  serGateway.write( inputRFID[ 8]);
+  serGateway.write( inputRFID[ 9]);
+  serGateway.write( inputRFID[ 10]);
+  serGateway.write( inputRFID[ 11]);
+  serGateway.write( inputRFID[ 12]);
+  serGateway.write( 0x0D);
+  serGateway.write( 0x0A);
   return;
 }

@@ -212,23 +224,26 @@
 void loop() {
   // Currently, for testing and to get the system operational quickly, I'm going to code this using a simple polling methodology.
   // Check for an incoming character from the RFID reader.
-  if( Serial.available()) {
+  while( serRFID.available() > 0) {
     // If the buffer's not full
-    if( currentCharGateway < 16) {
+    if( currentCharRFID < 16) {
+      digitalWrite( statusLED, HIGH);
       // Save the byte to the RFID input buffer.
-      inputRFID[ currentCharRFID] = Serial.read();
+      inputRFID[ currentCharRFID] = serRFID.read();
+      Serial.write( inputRFID[ currentCharRFID]);
       currentCharRFID++;
+      digitalWrite( statusLED, LOW);
     } else {
       inputRFIDClearBuffer();
     }
   }

   // Check for an incoming character form the gateway.
-  if( mySerial.available()) {
+  while( serGateway.available() > 0) {
     // If the buffer's not full
     if( currentCharGateway < 6) {
       // Save the byte
-      inputGateway[ currentCharGateway] = mySerial.read();
+      inputGateway[ currentCharGateway] = serGateway.read();
       currentCharGateway++;
     } else {
       // otherwise clear the buffer
@@ -237,13 +252,15 @@
   }

   // Check to see if the RFID input buffer is full or the last char was a newline.
-  if( inputRFID[ currentCharRFID - 1] == 0x0A) {
+  if( inputRFID[ currentCharRFID - 1] == 0x03) {
     // Turn on the yellow status LED to show that a request is being processed
     digitalWrite( statusLED, HIGH);
+      delay( 100);
     // Check the buffer to make sure it's valid
     if( checkInputRFIDBuffer()) {
       // Send the request for an RFID swipe
       sendRFIDswipeRequest();
+      serGateway.listen();
     }
     // Clear the buffer
     inputRFIDClearBuffer();
@@ -280,6 +297,7 @@
           break;
         }
       }
+      serRFID.listen();
     }
     // Clear the buffer
     inputGatewayClearBuffer();


Revert "Small change to EsploraLightCalibrator example"

This reverts commit 7e5ca6244baefbdadaf16b735ff5624d979e3d21.

--- libraries/Esplora/examples/Beginners/EsploraLightCalibrator/EsploraLightCalibrator.ino
+++ libraries/Esplora/examples/Beginners/EsploraLightCalibrator/EsploraLightCalibrator.ino
@@ -32,7 +32,7 @@

 void loop() {
   // if switch 1 is pressed, go to the calibration function again:
-  if (Esplora.readButton(1) == HIGH) {
+  if (Esplora.readButton(1) == LOW) {
     calibrate();
   }
   // read the sensor into a variable:
@@ -64,7 +64,7 @@
   Serial.println("While holding switch 1, shine a light on the light sensor, then cover it.");

   // calibrate while switch 1 is pressed:
-  while(Esplora.readButton(1) == HIGH) {
+  while(Esplora.readButton(1) == LOW) {
     // read the sensor value:
     int light  = Esplora.readLightSensor();


Update the system settings to reflect our new baud rates when we set them.

--- GVRET.ino
+++ GVRET.ino
@@ -600,10 +600,13 @@
 				   if (build_int > 1000000) build_int = 1000000;
 				   Can0.enable();
 				   Can0.begin(build_int, SysSettings.CAN0EnablePin);
+				   settings.CAN0Speed = build_int;
+				   settings.CAN0_Enabled = true;
 			   }
 			   else //disable first canbus
 			   {
 				   Can0.disable();
+				   settings.CAN0_Enabled = false;
 			   }
 			   break;
 		   case 4:
@@ -622,10 +625,13 @@
 				   if (build_int > 1000000) build_int = 1000000;
 				   Can1.enable();
 				   Can1.begin(build_int, SysSettings.CAN1EnablePin);
+				   settings.CAN1Speed = build_int;
+				   settings.CAN1_Enabled = true;
 			   }
 			   else //disable first canbus
 			   {
 				   Can1.disable();
+				   settings.CAN0_Enabled = false;
 			   }
 			   state = IDLE;
 			   break;


First cleanup and documentation pass on read_parallel

To explain my thought process on adding PIN_COUNT:
1. Magic numbers are bad, so having "7" as our loop condition is not
very readable.
2. If someone ever changes the pin array(s) without changing PIN_COUNT,
the compiler SHOULD warn them, preventing silent failure in the form of
not reading pins past the 8th array element.