1. /*
  2. ############################################################################
  3. MEGA 1280 - DOMOTIC PROJECT
  4.  
  5. Binary sketch size: 28598 bytes (of a 126976 byte maximum)
  6. ############################################################################
  7.  
  8. Le 13 Decembre 2011
  9.  
  10. TAG : programme en cours. Utilisation ancienne librairie S1D13700.
  11.       Ajout mode hors-gel ou off.
  12.  
  13. Le 16 decembre 2011
  14.       Refonte inertie -1, 0, 1. Perdition, stable, distribution.
  15.       Moyenne sur 5 valeurs, 1 valeur/mn pour coller à la courbe.
  16.       TouchScreen.cpp --> NUMSAMPLE 1
  17.      
  18. Le 19 decembre 2011
  19.       Modification inertie --> regulation
  20.       Ajout variable sommetCourbe, HYSTERESIS, ecart.
  21.  
  22. Le 26 decembre 2011
  23.       Regulation en logique floue.
  24.       Le temperature exterieure est fixe : 6
  25.       Ajout cycle de forcage
  26.  
  27. Ajout menu, layer1.
  28.  
  29. MODIFICATION :
  30.     - liaison pc seriel a la demande
  31.     - variable temperature de declenchement chauffage fixe a t+O.8
  32.     - default temperatures : 18.4, 17.5, 15.0, 5.0 (Jour, nuit, abs, vac, hors-gel)
  33.         - DS18B20 OneWire Pin 3
  34.                 - Ajout securite mauvaise lecture (DEVICE_DISCONNECTED = -127)
  35.     - Rs485 Pin 2 declaration (Tx3, Rx3)
  36.         - bit 1, Tx
  37.         - bit 0, release
  38.     - Modification librairie Time (Time.cpp)
  39.         - Ligne 239/259 : Desactivation de la synchro automatique.
  40.     - LED Pins :
  41.                 - Pin 8, voyant Auto.
  42.                 - Pin 9, voyant Absence.
  43.                 - Pin 10, voyant Vacances.
  44.                 - Pin 11, voyant OFF.
  45.         - GLCD S1D13700
  46.                 - Modification librairie S1D13700.h :
  47.                        - Utilisation du port A, pins D0 a D7.
  48.                        - DDRA, PORTA, PINA
  49.                 - Pins : rd = 38
  50.                          wr = 39
  51.                          a0 = 40
  52.                          cs = 41
  53.                          rst = 42
  54.         - TouchScreen (librairie from ladyada)
  55.                 - Pins : YP (Y2 ou YD) A13
  56.                          YM (Y1 ou YU) A15
  57.                          XM (X1 ou XL) A12
  58.                          XP (X2 ou XR) A14
  59.                 - Utilisation function map.
  60.  
  61. TODO :
  62.         - GLCD menu.
  63.                 - layer0 : affichage principal (date, heure, mode en cours, temperatures, etat de chauffe)
  64.                 - layer1 : boutons options (auto, off, abs, vac, cycle)
  65.                 - layer2 :
  66.                 - layer3 :
  67.         >> - Securiser la chauffe avec une temporisation.(20*60*1000)
  68.         >> - determiner une zone rouge avant la chauffe en mode nocturne.
  69.         >> - calibration glcd/touchscreen
  70.  
  71. REMARQUE :
  72.         - suppression application carte Sd (manque de fiabilite: 1 ecriture sur 2).
  73.                 - Sd Card Pins
  74.                 - CS pin 53
  75.                 - DI pin 51
  76.                 - DO pin 50
  77.                 - CLK pin 52
  78.  
  79. HELP :
  80.         - char * dtostrf(double val, signed char width, unsigned char prec, char * s) // convert double to string.
  81.         - int sprintf(char * str, const char * format, ...)                           // write formatted data to string.
  82.         - int printf ( const char * format, ...)                                      // print formatted data to stdout.
  83. */
  84.  
  85. /*
  86. ############################################################################
  87. GLOBAL : GLOBAL TIME DECLARATIONS
  88. ############################################################################
  89. */
  90. #include <Time.h>
  91. #define TIME_REQUEST  7
  92. #define TIME_MSG_LEN  11
  93. /*
  94. ############################################################################
  95. GLOBAL : DECLARATION VARIABLES TEMPS
  96. ############################################################################
  97. */
  98. int _hour; //= (hour());
  99. int _minute; //= (minute());
  100. int current_time; //= (_hour*60) + _minute;
  101. int last_minute;
  102.  
  103. time_t timeAbsence, timeVacances;                                          // sauvegarde since epoch time
  104.  
  105. int run_task;
  106. int tempo3;
  107. boolean overheat;
  108. /*
  109. ############################################################################
  110. GLOBAL : GLOBAL TEMPERATURE SENSORS DECLARATIONS
  111. ############################################################################
  112. */
  113. #include <OneWire.h>
  114. #include <DallasTemperature.h>
  115. #define ONE_WIRE_BUS 3
  116. OneWire oneWire(ONE_WIRE_BUS);
  117. DallasTemperature sensors(&oneWire);
  118. uint8_t sonde_ds18b20_1[8] = {0x28, 0xFC, 0x97, 0x56, 0x2, 0x0, 0x0, 0x69};
  119. //uint8_t sonde_ds18b20_2[8] = {};
  120. //uint8_t sonde_ds18b20_3[8] = {};
  121. //uint8_t sonde_ds18b20_4[8] = {};
  122. /*
  123. ############################################################################
  124. GLOBAL : GLOBAL SERIAL MESSAGE DECLARATIONS
  125. ############################################################################
  126. */
  127. #define STARTBIT '*'
  128. #define STOPBIT '!'
  129. #define BUFFERSIZE 96
  130. char buffer[BUFFERSIZE + 1];
  131. char* TRAME[12]; // Set there default data
  132. /*
  133. ############################################################################
  134. GLOBAL : SERIAL RELAY CARD PIN DECLARATION
  135. ############################################################################
  136. */
  137. #define txPin 2
  138. /*
  139. ############################################################################
  140. GLOBAL : GLCD S1D13700 DECLARATIONS
  141. ############################################################################
  142. */
  143. #include "lucida_font.h"
  144. #include <S1D13700.h>
  145. S1D13700 glcd;
  146. /*
  147. ############################################################################
  148. GLOBAL : TOUCH SCREEN DECLARATIONS
  149. ############################################################################
  150. */
  151. #include <stdint.h>
  152. #include "TouchScreen.h"
  153.  
  154. #define YP A13                                                              // must be an analog pin, use "An" notation! (Y2 = YD)
  155. #define XM A12                                                              // must be an analog pin, use "An" notation! (X1 = XL)
  156. #define YM A15                                                              // can be a digital pin (Y1 = YU)
  157. #define XP A14                                                              // can be a digital pin (X2 = XR)
  158.  
  159. TouchScreen ts = TouchScreen(XP, YP, XM, YM, 630);                          // mesured : 630 ohms
  160. /*
  161. ############################################################################
  162. GLOBAL : DECLARATION VARIABLES CHAUFFAGE
  163. ############################################################################
  164. */
  165. int intervalle_journuit[] = {390, 1365};                                   // 06h30 a 22h45
  166. float consigne_chauffage[] = {18.4, 17.5, 16.0, 10.0, 5.0};                // values to start with (jour, nuit, abs, vac, hors-gel)
  167. float calibrage;                                                           // temperature_marche_max = temperature1 + calibrage
  168.  
  169. boolean redzone;
  170. int h_redzone = intervalle_journuit[1] - 15;
  171.  
  172. float temperature1;
  173. float temperature_marche_max;
  174. float consigne_courante;
  175.  
  176. int mode_select;
  177. int etat_chauffage, prev_etat_chauffage;
  178. /*
  179. ############################################################################
  180. GLOBAL : DECLARATION REGULATION
  181. ############################################################################
  182. */
  183. const float POIDS1 = 0.7; /* CONSIGNE */
  184. const float POIDS2 = 0.1; /* PROBABILITE DEPERDITION CALORIFIQUE */
  185. const float POIDS3 = 0.15; /* TEMPERATURE EXTERIEURE */
  186.  
  187. float CIBLE[4][3] = {
  188.     { -127.0, 0.0, POIDS1*100 }, /* UNDER */
  189.     { 0.0, 0.1, POIDS1*86 }, /* TOUCH */
  190.     { 0.1, 0.2, POIDS1*80 }, /* MEDIUM */
  191.     { 0.2, 127.0, POIDS1*0 }, /* FAR */
  192. };
  193.  
  194. float PROBABILITY[5][3] = {
  195.         { -127.0, 0.0, POIDS2*0 },
  196.     { 0.0, 0.1, POIDS2*10 }, /* ECART P1 */
  197.     { 0.1, 0.15, POIDS2*30 }, /* ECART P2 */
  198.     { 0.15, 0.2, POIDS2*80 }, /* ECART P3 */
  199.     { 0.2, 127.0, POIDS2*100 } /* ECART P4 */
  200. };
  201.  
  202. float EXTERIEUR[6][3] = {
  203.     { -127.0, -2.0, POIDS3*100 }, /* FREEZE */
  204.     { -2.0, 2.0, POIDS3*80 }, /* COLD */
  205.     { 2.0, 6.0, POIDS3*60 }, /* WINTER */
  206.     { 6.0, 10.0, POIDS3*40 }, /* AUTOMN */
  207.     { 10.0, 16.0, POIDS3*20 }, /* SPRING */
  208.     { 16.0, 127.0, POIDS3*0 } /* SUMMER */
  209. };
  210.  
  211. const int longueurTable1 = sizeof(EXTERIEUR)/sizeof(EXTERIEUR[0]);
  212. const int longueurTable2 = sizeof(CIBLE)/sizeof(CIBLE[0]);
  213. const int longueurTable3 = sizeof(PROBABILITY)/sizeof(PROBABILITY[0]);
  214.  
  215. float sommetCourbe, ecart;
  216. float temperature_ext = 6.0;
  217. boolean check_regulation, chauffage, forcage;
  218. int value1, value2, value3;
  219. /*
  220. ############################################################################
  221. GLOBAL : LOGS DELAY
  222. ############################################################################
  223. */
  224. int eventTimer2 = _minute % 10;              
  225. /*
  226. ############################################################################
  227. GLOBAL : DECLARATION VARIABLES IHM
  228. ############################################################################
  229. */
  230. int menu;
  231. int prev_led;
  232. int localClient, remoteClient;
  233. /*
  234. ############################################################################
  235. GLOBAL : DECLARATION VARIABLES ACTIONNEUR
  236. ############################################################################
  237. */
  238. int state_relay1;
  239. /*
  240. ############################################################################
  241. GLOBAL : DECLARATION VARIABLES MILLIS
  242. ############################################################################
  243. */
  244. //unsigned long timer1 = 0, timer2 = 0;
  245. //unsigned long timeout1 = 60*1000, timeout2 = 10*1000;
  246. unsigned long timeout2 = 10*1000;
  247. /*
  248. ############################################################################
  249. GLOBAL : CLASS IHM
  250. ############################################################################
  251. */
  252. #define PIXH 14
  253.  
  254. class Objet {
  255.   public:
  256.     Objet();
  257.     int gadget;
  258.     char *text;
  259.    
  260.     //int _layer;
  261.     int radius;
  262.    
  263.     Objet(int,char*,int,int,int,int);     // type, text, x0, y0, x1, y1
  264.  
  265.     void draw() {
  266.       switch(gadget) {
  267.         case 0 : {                                                 // BitmapText
  268.           glcd.writeBitmapText(text, x1, y1, LUCIDA_FONT);
  269.           break;
  270.         }
  271.         case 1 : {                                                 // Box
  272.           //int dx1 = ((x2 + sizeof(text)) - x1)/2;
  273.           int dx1 = (x2 + x1 - (strlen(text)*PIXH))/2;
  274.           int dy1 = ((y2 + y1)/2) - PIXH;
  275.      
  276.           glcd.drawBox(x1, y1, x2, y2);
  277.           glcd.writeBitmapText(text, dx1, dy1, LUCIDA_FONT);
  278.           break;
  279.         }
  280.         case 2 : {                                                 // circle
  281.           int dx1 = x1 - (PIXH/2);
  282.           int dy1 = y1 + (PIXH/2);
  283.           radius = x2;
  284.           glcd.drawCircle(x1, y1, radius);
  285.           if (radius > PIXH) { glcd.writeBitmapText(text, dx1, dy1, LUCIDA_FONT); }
  286.           break;
  287.         }
  288.       }
  289.     };
  290.  
  291.     void disable() {
  292.       switch(gadget) {
  293.         case 0 : { break; }
  294.         case 1 : { break; }
  295.         case 2 : { break; }
  296.       }
  297.     };
  298.    
  299.     boolean check(int x, int y) {
  300.         // Adjust value from determinated calibration formula.
  301.         int X = float((1.22*x) + (-0.02*y) - 26.08);    // Xd = 1.22*x + -0.02*y - 26.06
  302.         int Y = float((-0.01*x) + (1.28*y) - 35.53);    // Yd = -0.01*x + 1.28*y - 35.53
  303.        
  304.         if ((gadget == 1) && (X > x1) && (X < x2) && (Y > y1) && (Y < y2))
  305.         { return true; }
  306.         else if ((gadget == 2) && (X > (x1 - (radius/2))) && (X < (x1 + (radius/2))) && (Y > (y1 - (radius/2))) && (Y < (y1 + (radius/2))))
  307.         { return true; }
  308.       return false;
  309.     };
  310.          
  311.   private:
  312.     int x1,y1,x2,y2;
  313. };
  314.  
  315. Objet::Objet(int g, char *t, int a, int b, int c=0, int d=0) {
  316.   gadget = g;
  317.   text = t;
  318.   x1 = a;
  319.   y1 = b;
  320.   x2 = c;
  321.   y2 = d;
  322. }
  323.  
  324. /*
  325. ############################################################################
  326. GLOBAL : DECLARATION DES OBJETS IHM
  327. ############################################################################
  328. */
  329. // LAYER 0
  330. Objet IHM_menu(1, "menu", 165, 190, 300, 230);                              // box
  331. Objet IHM_clock(0, "", 230, 10);                                            // text
  332. Objet IHM_mode(0, "", 10, 10);                                              // text
  333. Objet IHM_temp1(0, "", 10, 100);                                            // text
  334. Objet IHM_etat1(0, "", 100, 40);                                            // text
  335. // LAYER 1
  336. Objet IHM_auto(1, "auto", 20, 20, 150, 60);                                 // box
  337. Objet IHM_off(1, "off", 20, 80, 150, 120);                                  // box
  338. Objet IHM_abs2(1, "Abs 2H", 170, 20, 300, 60);                          // box
  339. Objet IHM_abs4(1, "Abs 4H", 170, 80, 300, 120);                         // box
  340. Objet IHM_forcage(1, "forcage", 20, 140, 150, 180);                     // box
  341. Objet IHM_return(1, "Back", 200, 180, 300, 220);                            // box
  342. Objet IHM_selectionLayer0(0, "", 30, 200);                                  // text
  343. // LAYER 2
  344.  
  345. /*
  346. ############################################################################
  347. ############################################################################
  348. ############################################################################
  349. SETUP - SETUP - SETUP - SETUP - SETUP - SETUP - SETUP - SETUP - SETUP
  350. ############################################################################
  351. ############################################################################
  352. ############################################################################
  353. */
  354. void setup() {
  355. /*
  356. ############################################################################
  357. SETUP : INITIALISER LES VOYANTS
  358. ############################################################################
  359. */
  360.   pinMode(8, OUTPUT);                                                      // voyant auto
  361.   pinMode(9, OUTPUT);                                                      // voyant absence
  362.   pinMode(10, OUTPUT);                                                     // voyant vacances
  363.   pinMode(11, OUTPUT);                                                     // voyant off
  364. /*
  365. ############################################################################
  366. SETUP : INITIALISER LES VARIABLES DE CHAUFFE
  367. ############################################################################
  368. */
  369.   calibrage = 0.75;
  370.   temperature_marche_max = consigne_chauffage[0];
  371.   etat_chauffage = 0;
  372.   mode_select = 1;
  373.   overheat = false;
  374.   tempo3 = 0;
  375.   check_regulation = true;
  376.   forcage = false;
  377. /*
  378. ############################################################################
  379. SETUP : INITIALISER LES VARIABLES IHM
  380. ############################################################################
  381. */  
  382.   menu = 1;
  383.   localClient = 0;
  384.   remoteClient = 0;
  385. /*
  386. ############################################################################
  387. SETUP : INITIALISER LES VARIABLES SEQUENTIELLES
  388. ############################################################################
  389. */    
  390.   run_task = 0;
  391. /*
  392. ############################################################################
  393. SETUP : INITIALISER LA LIAISON SERIE
  394. ############################################################################
  395. */
  396.   Serial.begin(57600);
  397.   delay(1000);
  398. /*
  399. ############################################################################
  400. SETUP : INITIALISER LA CARTE RELAIS RS485
  401. ############################################################################
  402. */
  403.   Serial3.begin(9600);
  404.   delay(1000);
  405.   pinMode(txPin, OUTPUT);
  406.   digitalWrite(txPin, LOW);
  407.   delay(50);
  408. /*
  409. ############################################################################
  410. SETUP : INITIALISER LE RELAIS DE CHAUFFE
  411. ############################################################################
  412. */
  413.  rs485TxMsg("\xFF\x01\x00");
  414.  state_relay1 = 0;
  415.  delay(50);
  416. /*
  417. ############################################################################
  418. SETUP : INITIALISER LES SONDES DE TEMPERATURES
  419. ############################################################################
  420. */
  421.   sensors.begin();
  422.   sensors.setResolution(sonde_ds18b20_1, 12);
  423.   sensors.requestTemperatures();
  424.   delay(1000);
  425. /*
  426. ############################################################################
  427. SETUP : INITIALISER AFFICHEUR
  428. ############################################################################
  429. */  
  430.  glcd.pins.rd = 38;
  431.  glcd.pins.wr = 39;
  432.  glcd.pins.a0 = 40;
  433.  glcd.pins.cs = 41;
  434.  glcd.pins.rst = 42;
  435.  delay(50);
  436.  
  437.  glcd.initLCD();
  438.  glcd.clearText();
  439.  glcd.clearGraphic();
  440.  delay(2000);
  441.  
  442.  layer0();                                                                  // draw initial display.
  443. /*
  444. ############################################################################
  445. SETUP :
  446. ############################################################################
  447. */
  448.   Serial.println("LOG : Setup complete");
  449. }
  450. /*
  451. ############################################################################
  452. ############################################################################
  453. ############################################################################
  454. LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP
  455. ############################################################################
  456. ############################################################################
  457. ############################################################################
  458. */
  459. void loop() {
  460.   Point p = ts.getPoint();
  461.   if (p.z > 0) {                                                       //if (p.z > ts.pressureThreshhold)
  462.     int x = map(p.x, 0, 1023, 0, 320);                                // to test : map(p.x, 128, 895, 0, 320)
  463.     int y = map(p.y, 0, 1023, 0, 240);                                // to test : map(p.y, 170, 853, 0, 240)
  464.     switch(menu) {
  465.       case 1: {
  466.         if (IHM_menu.check(x, y)) { layer1(); }
  467.         break;
  468.       }
  469.       case 2: {
  470.         if (IHM_auto.check(x, y)) { mode_select = 1; IHM_selectionLayer0.text = "Auto"; IHM_selectionLayer0.draw(); }
  471.         if (IHM_off.check(x, y)) { mode_select = 4; IHM_selectionLayer0.text = "Off"; IHM_selectionLayer0.draw(); }
  472.         if (IHM_forcage.check(x, y)) { mode_select = 5; IHM_selectionLayer0.text = "Run"; IHM_selectionLayer0.draw(); check_regulation = false; forcage = true; }
  473.         if (IHM_abs2.check(x, y)) { mode_select = 2; timeAbsence = now() + (2*3600); IHM_selectionLayer0.text = "Abs 2H"; IHM_selectionLayer0.draw(); }
  474.         if (IHM_abs4.check(x, y)) { mode_select = 2; timeAbsence = now() + (4*3600); IHM_selectionLayer0.text = "Abs 4H"; IHM_selectionLayer0.draw(); }
  475.         if (IHM_return.check(x, y)) { layer0(); }
  476.         break;
  477.       }
  478.     }
  479.   }
  480.  
  481. if (!localClient) { checkMsg(); }
  482. // AMELIORER CETTE PARTIE
  483. /*
  484. if (touched) {
  485.   unsigned long timer0 = millis();
  486.  
  487.   if (timer2 == 0) { timer2 = timer0; localClient = 1; remoteClient = 0; }
  488.   else {
  489.     if ((timer0 - timer2) > timeout2) { localClient = 0; timer2 = 0;}
  490.   }
  491.   Tactile();
  492. }
  493. */
  494.  
  495. switch (run_task) {
  496.   case 0 :
  497.       {
  498.       if (timeStatus() == timeNotSet) { Serial.println(TIME_REQUEST, BYTE); delay(1000); checkMsg();}
  499.       else { Serial.println("CLOCK UPDATED"); voyant(8); run_task = 1; }
  500.       break;
  501.       }
  502.   case 1 :
  503.     {
  504.       mainProgram();
  505.       break;
  506.     }
  507.   default :
  508.     {
  509.       run_task = 0;
  510.     }
  511.   }
  512. }
  513.  
  514. void voyant(int led) {
  515.   if (prev_led != led) {
  516.     switch (led) {
  517.       case 8 : { digitalWrite(led, HIGH); digitalWrite(9, LOW); digitalWrite(10, LOW); digitalWrite(11, LOW); break; }
  518.       case 9 : { digitalWrite(8, LOW); digitalWrite(led, HIGH); digitalWrite(10, LOW); digitalWrite(11, LOW); break; }
  519.       case 10 : { digitalWrite(8, LOW); digitalWrite(9, LOW); digitalWrite(led, HIGH); digitalWrite(11, LOW); break; }
  520.       case 11 : { digitalWrite(8, LOW); digitalWrite(9, LOW); digitalWrite(10, LOW); digitalWrite(led, HIGH); break; }
  521.       default : ;;
  522.     }
  523.     prev_led = led;
  524.   }
  525. }
  526.  
  527. /*
  528. MAIN ROUTINE
  529. */
  530. void mainProgram() {
  531. /*
  532. ############################################################################
  533. LOOP : DECLARATION OF ROLLING VARIABLES
  534. ############################################################################
  535. */
  536.     _hour = (hour());
  537.     _minute = (minute());
  538.  
  539.     current_time = (_hour*60) + _minute;
  540.  
  541.         //eventTimer1 = _minute % 4;
  542.         eventTimer2 = _minute % 10;
  543. /*
  544. ############################################################################
  545. LOOP : FURNACE MODE : 1-AUTO, 2-AWAY, 3-HOLLYDAYS, 4-OFF
  546. ############################################################################
  547. */  
  548.   switch(mode_select) {
  549.         case 1 :      // auto
  550.                 {
  551.           if (intervalle_journuit[0] < current_time && current_time < intervalle_journuit[1])
  552.           {
  553.             if (consigne_courante != consigne_chauffage[0]) { consigne_courante = consigne_chauffage[0]; }
  554.             if (h_redzone != (intervalle_journuit[1] - 15)) { h_redzone = intervalle_journuit[1] - 15; }// consigne diurne
  555.           }
  556.           else
  557.           {
  558.             if (consigne_courante != consigne_chauffage[1]) { consigne_courante = consigne_chauffage[1];}// consigne nocturne
  559.           }
  560.           voyant(8);
  561.                   if ((IHM_mode.text != "Auto") && (menu == 1)) { IHM_mode.text = "Auto"; IHM_mode.draw(); }
  562.               break;
  563.                 }
  564.         case 2 :      // absence
  565.                 {
  566.                   if (timeAbsence <= now()) { mode_select = 1; timeAbsence = 0; }
  567.                   else { if (consigne_courante != consigne_chauffage[2]) { consigne_courante = consigne_chauffage[2]; } }                      
  568.           voyant(9);
  569.                   if ((IHM_mode.text != "Abs") && (menu == 1)) { IHM_mode.text = "Abs"; IHM_mode.draw(); }
  570.           break;
  571.                 }
  572.         case 3 :      // vacances
  573.                 {
  574.                   if (timeVacances <= now()) { mode_select = 1; timeVacances = 0; }
  575.                   else { if (consigne_courante != consigne_chauffage[3]) { consigne_courante = consigne_chauffage[3]; } }                      
  576.           voyant(10);
  577.                   if ((IHM_mode.text != "Vac") && (menu == 1)) { IHM_mode.text = "Vac"; IHM_mode.draw(); }
  578.           break;
  579.                 }
  580.         case 4 :      // OFF ou hors-gel
  581.                 {
  582.           if (etat_chauffage != 0)
  583.           {
  584.             rs485TxMsg("\xFF\x01\x00");
  585.           }
  586.                   if (consigne_courante != consigne_chauffage[4]) { consigne_courante = consigne_chauffage[4]; }
  587.           voyant(11);
  588.                   if ((IHM_mode.text != "Off") && (menu == 1)) { IHM_mode.text = "Off"; IHM_mode.draw(); }
  589.           break;
  590.                 }
  591.                 case 5 :      // launch 1 cycle
  592.                 {
  593.                   if ((IHM_mode.text != "Run") && (menu == 1)) { IHM_mode.text = "Run"; IHM_mode.draw(); }
  594.                   if (forcage == false) { mode_select = 1; }
  595.                   break;
  596.                 }
  597.         default :
  598.                 {
  599.               mode_select = 1;
  600.                 }
  601.               }
  602. /*
  603. ############################################################################
  604. LOOP : UPDATE TIME AND TEMPERATURE EVERY MINUTE
  605. ############################################################################
  606. */
  607.           if (_minute != last_minute) {
  608.    
  609.             last_minute = _minute;
  610.    
  611.                 sensors.requestTemperaturesByAddress(sonde_ds18b20_1);
  612.                 temperature1 = sensors.getTempC(sonde_ds18b20_1);
  613.            
  614.             if (h_redzone < current_time && current_time < intervalle_journuit[1]) { redzone = true; }
  615.             else { redzone = false; }
  616.  
  617.                 if ((temperature1 != DEVICE_DISCONNECTED) && check_regulation) { chauffage = regulation(); }
  618.                    
  619.             if (((chauffage == true) && (!redzone)) || (forcage == true))
  620.           {
  621.           etat_chauffage = 1;
  622.           if (etat_chauffage != prev_etat_chauffage)
  623.             {
  624.             temperature_marche_max = temperature1 + calibrage;      // ajustement de la temperature
  625.                     sommetCourbe = 0.0;                                     // init sommetCourbe
  626.                     check_regulation = false;
  627.             rs485TxMsg("\xFF\x01\x01");                             // marche
  628.                     if (menu == 1) { IHM_etat1.text = "Marche"; IHM_etat1.draw(); }
  629.             }
  630.           }
  631.         if ((temperature1 >= temperature_marche_max) || (overheat))
  632.           {
  633.           etat_chauffage = 0;
  634.           if (etat_chauffage != prev_etat_chauffage)
  635.             {
  636.             overheat = false;
  637.             check_regulation = true;
  638.                     if (forcage == true) { forcage = false; }
  639.             temperature_marche_max = consigne_courante;
  640.             rs485TxMsg("\xFF\x01\x00");                             // arret
  641.                     if (menu == 1) { IHM_etat1.text = "Arret"; IHM_etat1.draw(); }
  642.             }
  643.           }
  644.                 prev_etat_chauffage = etat_chauffage;
  645.         if(remoteClient) { sendData(); }
  646.            
  647.                 if (etat_chauffage) {
  648.           if (tempo3 >= 20) { overheat = true; tempo3 = 0; }         // temps maxi chauffe.
  649.           else { tempo3++; }
  650.           }
  651.                 else { if (tempo3 != 0) { tempo3 = 0; } }                   // reinitialisation de la tempo si la temperature est atteinte avant.
  652.                
  653.           if ((etat_chauffage) || (eventTimer2 == 0)) { logs(); }
  654.                
  655.                 if (menu == 1) {
  656.                   IHM_clock.text = update_clock(); IHM_clock.draw();
  657.                   IHM_temp1.text = update_temp1(); IHM_temp1.draw();
  658.                 }
  659.           }
  660. }
  661. /*
  662. ############################################################################
  663. SECTION : LOOK AND MANAGE INCOMING SERIAL MESSAGE
  664. ############################################################################
  665. The getSerialString function looks for a valid message, with a header and a foot.
  666. if message is valid, it is split to each TRAME spaces in filldata function.
  667. Every splited data begins with a unique identifier flag, which will build valid
  668. functions and variables depending on position. This is my choice!
  669. For exemple, the 'T' flag means that data is concerning clock update.
  670. More things could be combined.
  671. ############################################################################
  672. */
  673. void checkMsg() {
  674.   if (getSerialString()) {                                                  // On verifie que la trame soit complete
  675.     filldata(buffer);                                                       // On remplit la structure des donnees
  676.     checkdata();                                                            // On renseigne les variables modifiees
  677.   }
  678. }
  679.  
  680. boolean getSerialString() {
  681.   int dataBufferIndex = 0;
  682.   boolean storebuffer = false;
  683.   delay(20);
  684.   if(Serial.available() > 1){
  685.         char incoming = Serial.read();
  686.         if(incoming==STARTBIT){
  687.             dataBufferIndex = 0;                                            //Initialize our dataBufferIndex variable
  688.             storebuffer = true;
  689.         }
  690.         if(storebuffer){
  691.           while(Serial.available()){
  692.             char incoming = Serial.read();
  693.             delay(50);
  694.             if(dataBufferIndex == BUFFERSIZE){dataBufferIndex = 0; break; }
  695.             if(incoming == STOPBIT) {buffer[dataBufferIndex] = 0; dataBufferIndex = 0; storebuffer = false; return true; }
  696.             else { buffer[dataBufferIndex++] = incoming; }
  697.           }
  698.         }
  699.   }
  700.   return false;
  701. }
  702.  
  703. void filldata(char *buffer) {
  704.   char *p = buffer;
  705.   char *str;
  706.   int i = 0;
  707.   while ((str = strtok_r(p, ";", &p)) != NULL) {                             // delimiter is the semicolon
  708.     char *q = str;
  709.     TRAME[i] = q;
  710.     i++;
  711.   }
  712. }
  713.  
  714. void checkdata() {
  715.   if (strcmp(TRAME[0], "CLOCK") == 0) {
  716.     if (strcmp(TRAME[1], "#") != 0) { updateTime(); }                        // Auto update Time
  717.   }
  718.   if (strcmp(TRAME[0], "SYNCTIME") == 0) { Serial.println(TIME_REQUEST, BYTE); delay(50); } // Manual update Time
  719.   if (strcmp(TRAME[0], "RELAY") == 0) {
  720.     // 0, relay number, relay state
  721.     if ((strcmp(TRAME[1], "1") == 0) && (strcmp(TRAME[2], "0") == 0)) { rs485TxMsg("\xFF\x01\x00"); state_relay1 = 0; Serial.print("@relay1:"); Serial.println(state_relay1); etat_chauffage = 0; }
  722.     if ((strcmp(TRAME[1], "1") == 0) && (strcmp(TRAME[2], "1") == 0)) { rs485TxMsg("\xFF\x01\x01"); state_relay1 = 1; Serial.print("@relay1:"); Serial.println(state_relay1); etat_chauffage = 1; }
  723.   }
  724.   if (strcmp(TRAME[0], "PARAM") == 0) {
  725.     // 'mode':'#', 'abs':'#', 'vac':'#', 't_jour':'#', 't_nuit':'#', 't_abs':'#', 't_vac':'#', 'cal':'#', 'day_at':'#', 'night_at':'#'
  726.     if (strcmp(TRAME[1], "#") != 0) { mode_select = string2integer(TRAME[1]); }
  727.     if (strcmp(TRAME[2], "#") != 0) { timeAbsence = string2long(TRAME[2]); }
  728.     if (strcmp(TRAME[3], "#") != 0) { timeVacances = string2long(TRAME[3]); }
  729.     if (strcmp(TRAME[4], "#") != 0) { consigne_chauffage[0] = string2float(TRAME[4]); }
  730.     if (strcmp(TRAME[5], "#") != 0) { consigne_chauffage[1] = string2float(TRAME[5]); }
  731.     if (strcmp(TRAME[6], "#") != 0) { consigne_chauffage[2] = string2float(TRAME[6]); }
  732.     if (strcmp(TRAME[7], "#") != 0) { consigne_chauffage[3] = string2float(TRAME[7]); }
  733.     if (strcmp(TRAME[8], "#") != 0) { calibrage = string2float(TRAME[8]); }
  734.     if (strcmp(TRAME[9], "#") != 0) { intervalle_journuit[0] = string2integer(TRAME[9]); }
  735.     if (strcmp(TRAME[10], "#") != 0) { intervalle_journuit[1] = string2integer(TRAME[10]); }                           
  736.   }
  737.   if (strcmp(TRAME[0], "START_CLI") == 0) {
  738.     // send data next to real time (1 mn)
  739.     remoteClient = 1; Serial.println("LOG : Client connected");
  740.     }
  741.   if (strcmp(TRAME[0], "STOP_CLI") == 0) {
  742.     // send data to normal timer (5 mn)
  743.     remoteClient = 0; Serial.println("LOG : Client dropped");
  744.   }
  745. }
  746.  
  747. void updateTime() {
  748.   int i = 0;
  749.   time_t pctime = 0;    
  750.   for(i = 0; i < TIME_MSG_LEN; i++) {
  751.       if( int(TRAME[1][i]) >= '0' && int(TRAME[1][i]) <= '9'){  
  752.         pctime = (10 * pctime) + (int(TRAME[1][i]) - '0') ;                 // convert digits to a number    
  753.         }
  754.       }
  755.       setTime(pctime);                                                      // Sync Arduino clock to the time received on the serial port
  756. }
  757.  
  758. /*
  759. ############################################################################
  760. SECTION : CONVERT STRING TO SOMETHING
  761. ############################################################################
  762. */
  763. int string2integer(char* data) { return atoi(data); }
  764. float string2float(char* data) { return atof(data); }
  765. unsigned long string2long(char* data) { return atol(data); }
  766.  
  767. /*
  768. ############################################################################
  769. SECTION : SWITCH RS485 FURNACE RELAY
  770. ############################################################################
  771. */
  772. void rs485TxMsg(char *msg) {
  773.   Serial3.flush();
  774.   digitalWrite(txPin, HIGH);
  775.   delay(10);
  776.   Serial3.print(msg);
  777.   delay(10);
  778.   digitalWrite(txPin, LOW);
  779. }
  780.  
  781. /*
  782. ############################################################################
  783. SECTION : SEND STATUS TO REMOTE CLIENT
  784. ############################################################################
  785. */
  786. void sendData() {
  787.     // 'mode':'#', 'abs':'#', 'vac':'#', 't_jour':'#', 't_nuit':'#', 't_abs':'#', 't_vac':'#', 'cal':'#', 'day_at':'#', 'night_at':'#'
  788.     Serial.flush();
  789.     Serial.print("@data;");
  790.     Serial.print(temperature1); Serial.print(";");                           // temperature 1
  791.     Serial.print("00.0"); Serial.print(";");                                 // temperature 2
  792.     Serial.print("00.0"); Serial.print(";");                                 // temperature 3
  793.     Serial.print("00.0"); Serial.print(";");                                 // temperature 4
  794.     Serial.print("0"); Serial.print(";");                                    // luminosite 1
  795.     Serial.print("0"); Serial.print(";");                                    // lux 1
  796.     Serial.print(mode_select); Serial.print(";");                            // mode
  797.     Serial.print(etat_chauffage); Serial.print(";");                         // chauffage on/off          
  798.     Serial.print(_hour); Serial.print(";");                                  // heure
  799.     Serial.print(_minute); Serial.print(";");                                // minute
  800.     if (mode_select == 2) { Serial.print(timeAbsence); }                 // Absence
  801.     else { Serial.print("0"); }
  802.     Serial.print(";");
  803.     if (mode_select == 3) { Serial.print(timeVacances); }                // Vacances
  804.     else { Serial.print("0"); }
  805.     Serial.print(";");
  806.     Serial.print(consigne_chauffage[0]); Serial.print(";");              // consigne jour
  807.     Serial.print(consigne_chauffage[1]); Serial.print(";");              // consigne nuit
  808.     Serial.print(consigne_chauffage[2]); Serial.print(";");              // consigne abs
  809.     Serial.print(consigne_chauffage[3]); Serial.print(";");              // consigne vac
  810.     Serial.print(calibrage); Serial.print(";");                          // calibrage
  811.     Serial.print(intervalle_journuit[0]); Serial.print(";");             // debut horaire jour
  812.     Serial.print(intervalle_journuit[1]);                                // fin horaire jour
  813.     Serial.println();
  814.     Serial.print("Zone rouge="); Serial.println(h_redzone);
  815. }
  816. /*
  817. ############################################################################
  818. SECTION : SEND LOGS TO SERVER
  819. ############################################################################
  820. */
  821. void logs() {
  822.     Serial.print("LOG:");
  823.     Serial.print(_hour); Serial.print("h"); Serial.print(_minute);
  824.     Serial.print(";"); Serial.print(temperature1); Serial.print(";");
  825.     Serial.print(etat_chauffage); Serial.print(";");
  826.     Serial.print(mode_select); Serial.print(";");
  827.         //if(inertie == true) { Serial.println("true"); }
  828.         //if(inertie == false) { Serial.println("false"); }
  829.     Serial.println(ecart);
  830. }
  831. /*
  832. ############################################################################
  833. SECTION : GLCD S1D13700 MENU
  834. ############################################################################
  835. */
  836. char* update_clock() {
  837.   static char time_buff[17] = { '\0' };
  838.   snprintf(time_buff, 17, "%02dh%02d", _hour, _minute);
  839.   return time_buff;
  840. }
  841.  
  842. char* update_temp1() {
  843.   char ibuff1[6] = { '\0' };
  844.   static char obuff1[20] = { '\0' };                                       // static = conserver en memoire, non detruite a la fin de la fonction.
  845.   dtostrf(temperature1,5,2,ibuff1);
  846.   snprintf(obuff1, 20, "T: %s", ibuff1);
  847.   return obuff1;
  848. }
  849.  
  850. void layer0() {
  851.   glcd.clearText();
  852.   glcd.clearGraphic();
  853.   //glcd.drawBitmap(RAIN, 180, 60, 128, 75);
  854.   IHM_menu.draw();
  855.   IHM_clock.text = "##h##"; IHM_clock.draw();
  856.   IHM_mode.text = "###"; IHM_mode.draw();
  857.   IHM_temp1.text = "###"; IHM_temp1.draw();
  858.   IHM_etat1.text = "###"; IHM_etat1.draw();
  859.   menu = 1;
  860.   delay(200);
  861. }
  862.  
  863. void layer1() {
  864.   glcd.clearText();
  865.   glcd.clearGraphic();
  866.   IHM_auto.draw();
  867.   IHM_off.draw();
  868.   IHM_forcage.draw();
  869.   IHM_abs2.draw();
  870.   IHM_abs4.draw();
  871.   IHM_return.draw();
  872.   IHM_selectionLayer0.text = IHM_mode.text; IHM_selectionLayer0.draw();
  873.   menu = 2;
  874.   delay(200);
  875. }
  876.  
  877. void layer2() {
  878. }
  879.  
  880. void layer3() {
  881. }
  882.  
  883. boolean regulation() {
  884.    
  885.     sommetCourbe = max(sommetCourbe, temperature1);
  886.     ecart = (sommetCourbe - temperature1);
  887.  
  888.     for (int i = 0; i < longueurTable1; i++) {
  889.     if ((temperature_ext > EXTERIEUR[i][0]) && (temperature_ext <= EXTERIEUR[i][1])) { value1 = EXTERIEUR[i][2]; }
  890.     }
  891.  
  892.     for (int i = 0; i < longueurTable2; i++) {
  893.     if (((temperature1 - consigne_courante) > CIBLE[i][0]) && ((temperature1 - consigne_courante) <= CIBLE[i][1])) { value2 = CIBLE[i][2]; }
  894.     }
  895.  
  896.     for (int i = 0; i < longueurTable3; i++) {
  897.       if ((ecart > PROBABILITY[i][0]) && (ecart <= PROBABILITY[i][1])) { value3 = PROBABILITY[i][2]; }
  898.     }
  899.  
  900.     if ((value1+value2+value3) >= 80) { return true; }
  901.     else { return false; };
  902.  
  903. }