vulture2600

Thermostat RTC I2C for Mega! V6.6

Mar 18th, 2015
374
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 30.96 KB | None | 0 0
  1. /*Thermostat with Real Time Clock Module and web support.
  2. This sketch takes temp readings from three temp sensors and a door sensor and decides when to turn the heat on or off while serving a web page.
  3. steve.a.mccluskey@gmail.com
  4.  
  5. Hardware used:
  6. Arduino Mega 2560 R3.    http://arduino.cc/en/Main/ArduinoBoardMega2560
  7. Arduino Ethernet Shield.    http://arduino.cc/en/Main/ArduinoEthernetShield
  8. Arduino ProtoShield.    http://arduino.cc/en/Main/ArduinoProtoShield
  9. Adafruit I2C RGB/LCD Shield.    https://www.adafruit.com/products/772
  10. Adafruit MCP9808 I2C temp sensor breakout board (3).    https://www.adafruit.com/products/1782
  11. DS18B20 OneWire digital waterproof temp sensor.    https://www.adafruit.com/products/381
  12. Adafruit DS1307 I2C Real Time Clock breakout board.    https://www.adafruit.com/products/264
  13. 5Vdc relay.
  14. Magnetic door sensor.
  15. 5V voltage regulator.
  16.  
  17. Web page and server code modified from sketch found at
  18. http://startingelectronics.com/tutorials/arduino/ethernet-shield-web-server-tutorial/SD-card-AJAX-XML-web-server/
  19. Original Author:  W.A. Smith, http://startingelectronics.com
  20. References:   - WebServer example by David A. Mellis and
  21.                 modified by Tom Igoe
  22.               - SD card examples by David A. Mellis and
  23.                 Tom Igoe
  24.  
  25. Revisions:
  26. V2.2: Web support using second arduino with ethernet shield. Master sends single char commands over serial and thermostat responds accordingly.
  27. V2.3: Added door and heater state to web page.
  28. V2.4: Added EEPROM functionality to save settings to resume on startup.
  29. V2.5: Added code to handle if one of the sensors is unplugged on the web page, 02/18/14.
  30. V2.6: Rewrote button polling, bottom line display and ReadTimeDate() with switch/cases; consolidated door logic, rewrote average functions. 02/19/14.
  31. V2.7: Added functionality to display negative temps down to -40. 02/20/14.
  32. V2.8: Removed averageC(), removed unneccesary lcd.setCursor()'s, fixed average() to correctly return negative temps, changed tempAvgC calculation,
  33.   sensorInterval variable added, C/F mode saved to EEPROM, tempHold limited to 12F minimum, getTemp() analog reading to tempC now uses floating point math and rounding. 03/02/14.
  34.   Changed average() to use floating point math as well. 03/03/14.
  35. V2.9: Changed how often ReadTimeDate() is called. 03/05/14.
  36. V3.0: Added daylight savings time option menu and functionality. 02/23/15.
  37. V3.1: Added doorState variable and only reads door once per loop instead of several times. 02/25/15.
  38. V3.2: Changed ReadTimeDate() to only initialize one string instead of three. Added heaterDelay variable. 02/27/15.
  39.  
  40. V4.0: Added One-Wire Temp sensor support for outdoor temps and getOneWireTemp(). Changed temp variables to temp1, temp2, temp3 from tempNear/Far/Out.
  41. Fixed closing parenthesis typo in getTemp(). Changed const uint8_t's to #define in pin declarations. Limited data[] to two slots in getOneWireTemp(). 03/02/14.
  42. Version 4.0 which uses analog TMP36 temp sensors can be found here: http://pastebin.com/YxKFUr2y
  43.  
  44. V5.0: Rewrote entire sketch to use I2C temp sensors and I2C clock module. 03/04/14.
  45. V5.1: TempHold is now changeable on M8 (temp Out) screen. Added RTC_Interval and changed sensorInterval. Added lastClockCheck variable. 03/09/14.
  46.  
  47. V6.0: Combined I2C and Ajax Server to run on a Mega. 03/10/14.
  48. V6.1: Shortened strings sent to and from client to save clock cycles. Combined lines in XML_Response() to eliminate cl.print()'s by butting successive HTML tags on the same line.
  49. Eliminated RTC_Interval check on Menu 5 and 6 since the RTC is being updated during loop(), eliminated lastClockCheck2. Misc clock cycle savings. 03/17/15.
  50. V6.2: Made C temp variables global because sketch initializes them every loop and it caused errors with web server. sendCommands() only called if there is a button pushed
  51. on web page. 03/18/15.
  52. V6.3: All temps are updated every sensor interval in celsius then converted to F regardless of celsius mode. getOneWireTemp() now only returns temp in C. 03/19/15.
  53. V6.4: Consolidated a few client.println()'s and index.htm is sent in 64 byte packets instead of byte by byte (thanks SurferTim!). Temps are read as floats then rounded. 03/20/15.
  54. V6.5: Button presses are executed as nested switch/cases instead of if/else if/else. 03/21/15.
  55. V6.6: Button presses and web commands now execute a specific function instead of identical code. IE tempHoldUp(), tempHoldDn(), etc.
  56. sendCommands() is now a switch/case, using char after "%" in HTTP_req as its argument to reduce calls to StrContains(). 03/25/15.
  57.  
  58.  
  59. Pin layout as follows:
  60. 0  : Hardware serial RX.
  61. 1  : Hardware serial TX.
  62. 2 ~: OneWire bus.
  63. 3 ~: Green LED.
  64. 4 ~: SD CS.
  65. 5 ~: Yellow LED.
  66. 6 ~: Red LED.
  67. 7 ~: Door sensor.
  68. 8 ~: Heater relay.
  69. 9 ~:
  70. 10~: Ethernet CS.
  71. 11~:
  72. 12~:
  73. 13~:
  74. 14 ... 19 : N/C.
  75. 20 : SDA.
  76. 21 : SCL.
  77. 22 ... 49 : N/C.
  78. 50 : SPI MISO.
  79. 51 : SPI MOSI.
  80. 52 : SPI SCK.
  81. 53 :
  82. A0 ... A15: N/C.
  83.  
  84. Sketch outline:
  85. Libraries.
  86. Pin Declarations.
  87. Global Variables.
  88. setup().
  89. loop() {
  90.   Web server.
  91.   Poll door.
  92.   Static variables.
  93.   Poll buttons.
  94.   Poll sensors.
  95.   Print avg/hold to first line.
  96.   Print menu to second line.
  97.   Door closed: switch/case for second line.
  98.   Door open: door open.
  99.   Heater on/off logic.
  100. }
  101. cToF().
  102. getOneWireTemp().
  103. heaterOn().
  104. heaterOff().
  105. clearLine().
  106. average().
  107. XML_Response().
  108. StrClear().
  109. StrContains().
  110. sendCommands().
  111. tempHoldUp().
  112. tempHoldDn().
  113. tempReductionUp().
  114. tempReductionDn().
  115. eveningHourUp().
  116. eveningHourDn().
  117. morningHourUp().
  118. morningHourDn().
  119. dayLightSavings().
  120. */
  121.  
  122. #include <Wire.h>
  123. #include "RTClib.h"
  124. #include <RTC_DS1307.h>
  125. #include "Adafruit_MCP9808.h"
  126. #include <Adafruit_MCP23017.h>
  127. #include <Adafruit_RGBLCDShield.h>
  128. #include <EEPROM.h>
  129. #include <OneWire.h>
  130. #include <SPI.h>
  131. #include <Ethernet.h>
  132. #include <SD.h>
  133.  
  134. #define RTC_Interval 150 //delay between RTC updates.
  135. #define sensorInterval 1000 //delay between sensor readings.
  136. #define heaterDelay 120000 //heater on/off delay.
  137.  
  138. #define REQ_BUF_SZ 60 // size of buffer used to capture HTTP requests.
  139.  
  140. //pin declarations:
  141. #define oneWireBus 2
  142. #define greenLed 3
  143. #define yellowLed 5
  144. #define redLed 6
  145. #define door 7
  146. #define relay 8
  147.  
  148. byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xFD };
  149. IPAddress ip(192, 168, 1, 177); // IP address, may need to change depending on network.
  150. EthernetServer server(80); // create a server at port 80.
  151. File webFile;
  152. char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string.
  153. char req_index = 0; // index into HTTP_req buffer.
  154.  
  155. OneWire oneWire(oneWireBus);
  156. byte addr[8]; //array to store OneWire device's address.
  157.  
  158. //objects:
  159. Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
  160. RTC_DS1307 rtc;
  161. Adafruit_MCP9808 tempSensor1 = Adafruit_MCP9808();
  162. Adafruit_MCP9808 tempSensor2 = Adafruit_MCP9808();
  163. Adafruit_MCP9808 tempSensor3 = Adafruit_MCP9808();
  164.  
  165. //global variables:
  166. boolean celsius = EEPROM.read(5);
  167. boolean doorLineCleared = false;
  168. boolean daylightSavings = EEPROM.read(6);
  169.  
  170. uint8_t tempHold = EEPROM.read(0); // read saved tempHold value from EEPROM.
  171. uint8_t menu = EEPROM.read(4);
  172. uint8_t heaterState = 0, doorState = 0;
  173. int8_t tempReduction = EEPROM.read(1);
  174. int8_t temp1, temp2, temp3, tempOneWire, tempAvg; // variables to store temps.
  175. int8_t tempAvgC, temp1C, temp2C, temp3C, tempOneWireC, tempHoldC, tempReductionC;
  176. unsigned long heaterOnTime = 0, heaterOffTime = 0, currentTime = 0, lastReadingTime = 0, lastClockCheck = 0;
  177.  
  178. DateTime now;
  179. uint8_t hour;
  180. uint8_t eveningHour = EEPROM.read(3);
  181. uint8_t morningHour = EEPROM.read(2);
  182.  
  183. void setup() {
  184.   pinMode(10, OUTPUT);
  185.   digitalWrite(10, HIGH); // disable Ethernet chip.  
  186.   Serial.begin(19200);
  187.   Wire.begin();
  188.   lcd.begin(16, 2);
  189.   lcd.setCursor(0, 0);
  190.   lcd.print(F("RTC Thermostat"));
  191.   lcd.setCursor(0, 1);
  192.   lcd.print(F("V 6.6 for Mega!"));
  193.   delay(1000);
  194.   lcd.clear();
  195.   lcd.setCursor(0, 0);
  196.  
  197.   if (!SD.begin(4)) { // initialize SD card.
  198.     lcd.print(F("No SD Card!"));    // init failed.
  199.     while(true);
  200.   } //end if.
  201.  
  202.   if (!SD.exists("index.htm")) { // check for index.htm file.
  203.     lcd.print(F("index.htm"));
  204.     lcd.setCursor(0, 1);
  205.     lcd.print(F("not found!"));
  206.     while(true);  // can't find index file.
  207.   } //end if.
  208.  
  209.   digitalWrite(10, LOW);
  210.   Ethernet.begin(mac, ip);
  211.   server.begin();
  212.   lcd.print(F("IP Address:"));
  213.   lcd.setCursor(0, 1);
  214.   lcd.print(Ethernet.localIP());
  215.   Serial.println(F("IP Address is:  "));
  216.   Serial.println(Ethernet.localIP());
  217.  
  218.   pinMode(redLed, OUTPUT);
  219.   pinMode(greenLed, OUTPUT);
  220.   pinMode(yellowLed, OUTPUT);
  221.   pinMode(door, INPUT_PULLUP); //door pin is pulled to ground while door is closed.
  222.   pinMode(relay, OUTPUT);
  223.  
  224.   tempSensor1.begin(0x18); //I2C address.
  225.   tempSensor2.begin(0x19);
  226.   tempSensor3.begin(0x1A);
  227.   oneWire.search(addr); //get connected OneWire device address.
  228.   rtc.begin();
  229.   //rtc.adjust(DateTime(__DATE__, __TIME__)); //set RTC to time of compile, will revert to that time every time arduino is reset. run once and then comment out and reload.
  230.   delay(1000);
  231.   lcd.clear();
  232. } //end setup().
  233.  
  234. void loop() {
  235.   float convF = (5.0 * (tempHold - 32)) / 9.0;
  236.   tempHoldC = round(convF);
  237.   tempReductionC = tempReduction / 4;
  238.  
  239.   uint8_t buttons = lcd.readButtons(); //MUST be in main loop. will not work if global.
  240.  
  241.   EthernetClient client = server.available();  // try to get client.
  242.  
  243.   if (client) {  // got client?
  244.     boolean currentLineIsBlank = true;
  245.     boolean commandRecieved = false;
  246.     uint8_t index = 0;
  247.    
  248.     while (client.connected()) {
  249.       if (client.available()) {
  250.         char c = client.read(); // read 1 byte (character) from client.
  251.         if (c == '%') {
  252.           commandRecieved = true; //"%" recieved indicating a web button was pressed.
  253.           index = req_index; //save slot of "%".
  254.         } //end if.
  255.        
  256.         // limit the size of the stored received HTTP request.
  257.         // buffer first part of HTTP request in HTTP_req array (string),
  258.         // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1).
  259.         if (req_index < (REQ_BUF_SZ - 1)) {
  260.           HTTP_req[req_index] = c; // save HTTP request character.
  261.           req_index ++;
  262.         } //end if.
  263.        
  264.         // last line of client request is blank and ends with \n
  265.         // respond to client only after last line received:
  266.         if (c == '\n' && currentLineIsBlank) { // send a standard http response header.
  267.           client.println(F("HTTP/1.1 200 OK"));
  268.           // remainder of header follows below, depending on if
  269.           // web page or XML page is requested.
  270.           // Ajax request - send XML file:
  271.           if (StrContains(HTTP_req, "getIO")) { //send rest of HTTP header.
  272.             client.println(F("Content-Type: text/xml\r\nConnection: keep-alive\r\n"));
  273.             if (commandRecieved) {
  274.               sendCommands(HTTP_req[index + 1]); //send char after "%".
  275.             }
  276.             XML_response(client); //send XML file containing input states.
  277.           } //end if.
  278.           else { // web page request.
  279.             // send rest of HTTP header:
  280.             client.println(F("Content-Type: text/html\r\nConnection: keep-alive\r\n\r\n"));            
  281.             // send web page:
  282.             char tBuf[64];
  283.             uint8_t clientCount;
  284.             webFile = SD.open("index.htm");
  285.             if (webFile) {
  286.               while(webFile.available()) {
  287.                 clientCount = webFile.read(tBuf, 64);
  288.                 client.write((byte*)tBuf, clientCount); //send web page to client 64 bytes at a time.
  289.               } //end while.
  290.               webFile.close();
  291.             } //end if.
  292.           } //end else.
  293.          
  294.           //Serial.println(HTTP_req); // display received HTTP request on serial port.
  295.          
  296.           // reset buffer index and all buffer elements to 0:
  297.           req_index = 0;
  298.           StrClear(HTTP_req, REQ_BUF_SZ); //clear the buffer.
  299.           break;
  300.         } //end if.
  301.        
  302.         // every line of text received from the client ends with \r\n.
  303.         if (c == '\n') {
  304.         // last character on line of received text.
  305.         // starting new line with next character read.
  306.           currentLineIsBlank = true;
  307.         }  //end if.
  308.         else if (c != '\r') { // a text character was received from client.
  309.           currentLineIsBlank = false;
  310.         } //end if.
  311.       } // end if client.available().
  312.     } // end while client.connected().
  313.     commandRecieved = false;
  314.     client.stop(); // close the connection.
  315.   } // end if (client).
  316.  
  317.   if (digitalRead(door) == HIGH) { //only read once per loop.
  318.     doorState = 1;
  319.   } //end if.
  320.   else {
  321.     doorState = 0;
  322.   } //end else.
  323.  
  324.   currentTime = millis();
  325.  
  326.   if (buttons) { //poll the buttons.
  327.     switch (buttons) {
  328.       case 1: //select:
  329.         celsius = !celsius;
  330.         EEPROM.write(5, celsius); //only write to EEPROM when something is changed to reduce write cycles.
  331.       break; // end select.
  332.  
  333.       case 8: //up:
  334.         switch (menu) { //update variables depending on which menu is selected.
  335.           case 1:
  336.             tempHoldUp();
  337.           break; //end case 1.
  338.  
  339.           case 2:
  340.             tempReductionUp();
  341.           break; //end case 2.
  342.  
  343.           case 3:
  344.             eveningHourUp();
  345.           break; //end case 3.
  346.  
  347.           case 4:
  348.             morningHourUp();
  349.           break; //end case 4.
  350.  
  351.           case 5:
  352.           break; //end case 5.
  353.  
  354.           case 6:
  355.           break; //end case 6.
  356.  
  357.           case 7:
  358.             dayLightSavings();
  359.           break; //end case 7.
  360.  
  361.           case 8:
  362.             tempHoldUp();
  363.           break; //end case 8.
  364.  
  365.           default:
  366.           break;
  367.         } //end switch.
  368.       break; //end up.
  369.      
  370.       case 4: //down:
  371.         switch (menu) {
  372.           case 1:
  373.             tempHoldDn();
  374.           break; //end case 1.
  375.  
  376.           case 2:
  377.             tempReductionDn();
  378.           break; //end case 2.
  379.  
  380.           case 3:
  381.             eveningHourDn();
  382.           break; //end case 3.
  383.  
  384.           case 4:
  385.             morningHourDn();
  386.           break; //end case 4.
  387.  
  388.           case 5:
  389.           break; //end case 5.
  390.  
  391.           case 6:
  392.           break; //end case 6.
  393.  
  394.           case 7:
  395.             dayLightSavings();
  396.           break; //end case 7.
  397.  
  398.           case 8:
  399.             tempHoldDn();
  400.           break; //end case 8.
  401.  
  402.           default:
  403.           break;
  404.         } //end switch.
  405.       break; //end down.
  406.      
  407.       case 2: //right:
  408.         menu ++; //advances menu.
  409.         clearLine(); //clears 2nd line only when menu number is changed.
  410.         if (menu > 8) {
  411.           menu = 1;
  412.         } //end if.
  413.         EEPROM.write(4, menu);
  414.       break; //end right.
  415.  
  416.       case 16: //left:
  417.         menu --; //retreats menu.
  418.         clearLine();
  419.         if (menu < 1) {
  420.           menu = 8;
  421.         } //end if.
  422.         EEPROM.write(4, menu);
  423.       break; //end left
  424.      
  425.       default:
  426.       break;
  427.     } //end switch buttons.
  428.   } // end if buttons.
  429.  
  430.   if (currentTime - lastClockCheck > RTC_Interval) { //get hour of day from RTC.
  431.     now = rtc.now();
  432.     hour = now.hour();
  433.     if (daylightSavings) {
  434.       hour += 1;
  435.     } //end if.
  436.     lastClockCheck = currentTime;
  437.   } //end if.
  438.  
  439.   if (currentTime - lastReadingTime > sensorInterval) { //only poll sensors every interval
  440.     float t1 = tempSensor1.readTempC();
  441.     float t2 = tempSensor2.readTempC();
  442.     float t3 = tempSensor3.readTempC();
  443.  
  444.     temp1C = round(t1);
  445.     temp2C = round(t2);
  446.     temp3C = round(t3);
  447.     tempAvgC = average(temp1C, temp2C, temp3C);
  448.    
  449.     temp1 = cToF(t1);
  450.     temp2 = cToF(t2);
  451.     temp3 = cToF(t3);
  452.     tempAvg = average(temp1, temp2, temp3);
  453.    
  454.     tempOneWireC = getOneWireTemp(addr);
  455.     tempOneWire = cToF(tempOneWireC);    
  456.  
  457.     lastReadingTime = currentTime;
  458.   } //end if.
  459.  
  460.   //print avg to screen:
  461.   lcd.setCursor(0, 0);
  462.   lcd.print(F("Avg:"));
  463.   if (!celsius) {
  464.     if (tempAvg >= -40 && tempAvg < 0) { //displays negative temps.
  465.       lcd.print(tempAvg);
  466.       lcd.print(F("F"));
  467.     } //end if.
  468.     else if (tempAvg >= 0) { //displays positive temps and clears last digit.
  469.       lcd.print(tempAvg);
  470.       lcd.print(F("F "));
  471.     } //end else if.
  472.     else {
  473.       lcd.print(F("--F ")); //displays "--" if all 3 sensors are unplugged.
  474.     } //end else.
  475.   } //end if !celsius.
  476.  
  477.   else {
  478.     if (tempAvgC >= -40 && tempAvgC < 0) {
  479.       lcd.print(tempAvgC);
  480.       lcd.print(F("C"));
  481.     } //end if.
  482.     else if (tempAvgC >= 0) {
  483.       lcd.print(tempAvgC);
  484.       lcd.print(F("C "));
  485.     } //end else if.
  486.     else {
  487.       lcd.print(F("--C "));
  488.     } //end else.
  489.   } //end else.
  490.  
  491.   //print hold temp to screen:
  492.   lcd.setCursor(8, 0);
  493.   lcd.print(F("Hold:"));
  494.   lcd.setCursor(13, 0);
  495.   if (hour < morningHour || hour >= eveningHour) { //displays night temp hold at night.
  496.     if (!celsius) {
  497.       lcd.print(tempHold - tempReduction);
  498.       lcd.print(F("*")); //star indicates night time temp reduction.
  499.     } //end if.
  500.     else {
  501.       lcd.print(tempHoldC - tempReductionC);
  502.       lcd.print(F("*"));
  503.     } //end else.
  504.   } //end if.
  505.  
  506.   else if (hour >= morningHour && hour < eveningHour) { //displays regular temp hold during day.
  507.     if (!celsius) {
  508.       lcd.print(tempHold);
  509.       lcd.print(F("F"));
  510.     } //end if.
  511.     else {
  512.       lcd.print(tempHoldC);
  513.       lcd.print(F("C"));
  514.     } //end else.
  515.   } //end else if.
  516.  
  517.   lcd.setCursor(0, 1);
  518.   lcd.print(F("M")); //displays menu number.
  519.   lcd.print(menu);
  520.  
  521.   //bottom line display:
  522.   if (doorState == 0) {
  523.     analogWrite(redLed, 0);
  524.     digitalWrite(greenLed, HIGH); //green led indicates system normal.
  525.     if (!doorLineCleared) { //only clears line once when door is shut.
  526.       clearLine();
  527.       doorLineCleared = true;
  528.     } //end if.
  529.  
  530.     switch (menu) {
  531.       case 1: //displays sensors to screen and allows changing of temp hold.
  532.         lcd.setCursor(2, 1);
  533.         if (!celsius) { //sensor one:
  534.           if (temp1 < -40) { //displays "--" if tempNear returns null and clears leading minus sign.
  535.             lcd.print(F(" --"));
  536.           } //end if.
  537.           else if (temp1 >= -40 && temp1 < 0) { //negative temps.
  538.             lcd.print(temp1);
  539.           } //end else if.
  540.           else {
  541.             lcd.print(F(" ")); //positive temps and clears minus sign.
  542.             lcd.print(temp1);
  543.           } //end else.
  544.           lcd.print(F("F "));
  545.         } //end if.
  546.         else {
  547.           if (temp1C < -40) {
  548.             lcd.print(F(" --"));
  549.           } //end if.
  550.           else if (temp1C >= 40 && temp1C < 0) {
  551.             lcd.print(temp1C);
  552.           } //end else if.
  553.           else {
  554.             lcd.print(F(" "));
  555.             lcd.print(temp1C);
  556.           } // end else.
  557.           lcd.print(F("C "));
  558.         } //end else.
  559.  
  560.         lcd.setCursor(7, 1);
  561.         if (!celsius) { //sensor 2:
  562.           if (temp2 < -40) {
  563.             lcd.print(F(" --"));
  564.           } //end if.
  565.           else if (temp2 >= -40 && temp2 < 0) {
  566.             lcd.print(temp2);
  567.           } //end else if.
  568.           else {
  569.             lcd.print(F(" "));
  570.             lcd.print(temp2);
  571.           } //end else.
  572.           lcd.print(F("F "));
  573.         } //end if.
  574.         else {
  575.           if (temp2C < -40) {
  576.             lcd.print(F(" --"));
  577.           } //end if.
  578.           else if (temp2C >= 40 && temp2C < 0) {
  579.             lcd.print(temp2C);
  580.           } //end else if.
  581.           else {
  582.             lcd.print(F(" "));
  583.             lcd.print(temp2C);
  584.           } // end else.
  585.           lcd.print(F("C "));
  586.         } //end else.
  587.  
  588.         lcd.setCursor(12, 1);
  589.         if (!celsius) { //sensor 3:
  590.           if (temp3 < -40) {
  591.             lcd.print(F(" --"));
  592.           } //end if.
  593.           else if (temp3 >= -40 && temp3 < 0) {
  594.             lcd.print(temp3);
  595.           } //end else if.
  596.           else {
  597.             lcd.print(F(" "));
  598.             lcd.print(temp3);
  599.           } //end else.
  600.           lcd.print(F("F "));
  601.         } //end if.
  602.         else {
  603.           if (temp3C < -40) {
  604.             lcd.print(F(" --"));
  605.           } //end if.
  606.           else if (temp3C >= 40 && temp3C < 0) {
  607.             lcd.print(temp3C);
  608.           } //end else if.
  609.           else {
  610.             lcd.print(F(" "));
  611.             lcd.print(temp3C);
  612.           } // end else.
  613.           lcd.print(F("C "));
  614.         } //end else.
  615.       break; //end menu 1.
  616.  
  617.       case 2: //displays temp drop amount.
  618.         lcd.setCursor(3, 1);
  619.         lcd.print(F("Drop Temp:"));
  620.         if (!celsius) {
  621.           if (tempReduction < 10) {
  622.             lcd.print(F(" "));
  623.           } //end if.
  624.           lcd.print(tempReduction);
  625.           lcd.print(F("F"));
  626.         } //end if.
  627.         else {
  628.           if (tempReductionC < 10) {
  629.             lcd.print(F(" "));
  630.           } //end if.
  631.           lcd.print(tempReductionC);
  632.           lcd.print(F("C"));
  633.         } //end else.
  634.       break; //end menu 2.
  635.  
  636.       case 3: //displays PM time to drop temp:
  637.         lcd.setCursor(3, 1);
  638.         lcd.print(F("Heat Dn: "));
  639.         if (eveningHour < 22) {
  640.           lcd.print(F(" "));
  641.         } //end if.
  642.         lcd.print(eveningHour - 12);
  643.         lcd.print(F("pm"));
  644.       break; //end menu 3.
  645.  
  646.       case 4: //displays AM time to raise temp:
  647.         lcd.setCursor(3, 1);
  648.         lcd.print(F("Heat Up: "));
  649.         if (morningHour < 10) {
  650.           lcd.print(F(" "));
  651.         } //end if.
  652.         lcd.print(morningHour);
  653.         lcd.print(F("am"));
  654.       break; //end menu 4.
  655.  
  656.       case 5: //display time to 2nd row:
  657.         lcd.setCursor(4, 1);
  658.         lcd.print(F("Tm: "));
  659.         if (hour < 10) {
  660.           lcd.print(F(" "));
  661.         } //end if.
  662.         lcd.print(now.hour());
  663.         lcd.print(F(":"));
  664.         if (now.minute() < 10) {
  665.           lcd.print(F("0"));
  666.         } //end if.
  667.         lcd.print(now.minute());
  668.         lcd.print(F(":"));
  669.         if (now.second() < 10) {
  670.           lcd.print(F("0"));
  671.         } //end if.
  672.         lcd.print(now.second());
  673.       break; //end menu 5.
  674.  
  675.       case 6: //display date to 2nd row:
  676.         lcd.setCursor(4, 1);
  677.         lcd.print(F("Dt: "));
  678.         if (now.month() < 10) {
  679.           lcd.print(F(" "));
  680.         } //end if.
  681.         lcd.print(now.month());
  682.         lcd.print(F("/"));
  683.         if (now.day() < 10) {
  684.           lcd.print(F("0"));
  685.         } //end if.
  686.         lcd.print(now.day());
  687.         lcd.print(F("/"));
  688.         lcd.print(now.year() - 2000);
  689.       break; //end menu 6.
  690.  
  691.       case 7: //daylight savings time enable/disable:
  692.         lcd.setCursor(4, 1);
  693.         lcd.print(F("DST:"));
  694.         if (daylightSavings) {
  695.           lcd.print(F("Active  "));
  696.         } //end if.
  697.         else {
  698.           lcd.print(F("Inactive"));
  699.         } //end else.
  700.       break;  //end menu 7.
  701.  
  702.       case 8: //prints outside temp to screen.
  703.         lcd.setCursor(4, 1);
  704.         lcd.print(F("Out: "));
  705.         if (!celsius) {
  706.           if (tempOneWire > -51) {
  707.             lcd.print(tempOneWire);
  708.           } //end if.
  709.           else {
  710.             lcd.print("--");
  711.           } //end else.
  712.           lcd.print(F("F   "));
  713.         } //end if celsius.
  714.         else {
  715.           if (tempOneWireC > -51) {
  716.             lcd.print(tempOneWireC);
  717.           } //end if.
  718.           else {
  719.             lcd.print("--");
  720.           } //end else.
  721.           lcd.print(F("C   "));
  722.         } // else.
  723.       break; //end case 8.
  724.     } //end switch menu.
  725.   } //end if door closed.
  726.  
  727.   else {
  728.     doorLineCleared = false;
  729.     lcd.setCursor(2, 1);
  730.     lcd.print(F(" Door open!   "));
  731.     digitalWrite(greenLed, LOW);
  732.     digitalWrite(yellowLed, LOW);
  733.     digitalWrite(relay, LOW);
  734.     heaterState = 0;
  735.     analogWrite(redLed, 180);
  736.     heaterOffTime = currentTime;
  737.   } //end else if.
  738.  
  739.   //decide when to turn heater on or off:
  740.   if (hour >= morningHour && hour < eveningHour) { //day time
  741.     if (((!celsius && tempAvg > -41 && tempAvg < tempHold) ||
  742.          (celsius && tempAvgC > -41 && tempAvgC < tempHoldC)) && doorState == 0) {
  743.       heaterOn();
  744.     } //end if.
  745.     else {
  746.       heaterOff();
  747.     } //end else.
  748.   } //end if day time.
  749.  
  750.   else if (hour < morningHour || hour >= eveningHour) { //night time
  751.     if (((!celsius && tempAvg > -41 && tempAvg < (tempHold - tempReduction)) ||
  752.          (celsius && tempAvgC > -41 && tempAvgC < (tempHoldC - tempReductionC))) && doorState == 0) {
  753.       heaterOn();
  754.     } //end if.
  755.     else {
  756.       heaterOff();
  757.     } //end else.
  758.   } //end if night time.
  759. } //end loop().
  760.  
  761. int8_t cToF(float c) { //convert float C to int F.
  762.   return round((1.8 * c) + 32.0);
  763. } //end cToF().
  764.  
  765. int8_t getOneWireTemp(byte *str) { //get OneWire temp.
  766.   byte data[2]; //array to store data retrieved from sensor.
  767.   oneWire.reset();
  768.   oneWire.select(str);
  769.   oneWire.write(0x44, 1); //start conversion.
  770.   oneWire.reset();
  771.   oneWire.select(str);
  772.   oneWire.write(0xBE); //read scratchpad.
  773.  
  774.   for (byte i = 0; i < 2; i ++) {
  775.     data[i] = oneWire.read(); //collect data.
  776.   } //end for.
  777.  
  778.   int16_t raw = (data[1] << 8) | data[0]; //convert raw data to C.
  779.   return round((float)raw / 16.0);
  780. } //end getOneWireTemp().
  781.  
  782. void heaterOn() {
  783.   if (currentTime - heaterOffTime > heaterDelay) { //check to see if heater has been off for at least 2 min.
  784.     digitalWrite(relay, HIGH);
  785.     analogWrite(yellowLed, 180);
  786.     heaterOnTime = currentTime;
  787.     heaterState = 1;
  788.   } //end if.
  789. } //end heaterOn().
  790.  
  791. void heaterOff() {
  792.   if (currentTime - heaterOnTime > heaterDelay) { //check to see if heater has been on for at least 2 min.
  793.     digitalWrite(relay, LOW);
  794.     digitalWrite(yellowLed, LOW);
  795.     heaterOffTime = currentTime;
  796.     heaterState = 0;
  797.   } //end if.
  798. } //end heaterOff().
  799.  
  800. void clearLine() { //clears 2nd line past M#.
  801.   lcd.setCursor(2, 1);
  802.   lcd.print(F("              "));
  803. } //end clearLine().
  804.  
  805. int8_t average(int8_t temp_1, int8_t temp_2, int8_t temp_3) { //averages 3 temps and knows how depending on which sensors are plugged in.
  806.   uint8_t count = 0;
  807.   float avg = 0.0;
  808.   if (temp_1 > -41) { //sensor connected.
  809.     count ++;
  810.     avg += temp_1;
  811.   } //end if.
  812.   if (temp_2 > -41) {
  813.     count ++;
  814.     avg += temp_2;
  815.   } //end if.
  816.   if (temp_3 > -41) {
  817.     count ++;
  818.     avg += temp_3;
  819.   } //end if.
  820.   if (count != 0) {
  821.     return round(avg / count);
  822.   } //end if.
  823.   else {
  824.     return -41; //all three sensors unplugged.
  825.   } //end else.
  826. } //end average().
  827.  
  828. void XML_response(EthernetClient cl) {
  829.   cl.print(F("<?xml version = \"1.0\" ?><inputs><tAvg>"));
  830.   cl.print(tempAvg);
  831.   cl.print(F("</tAvg><tHold>"));
  832.  
  833.   cl.print(tempHold);
  834.   cl.print(F("</tHold><eHour>"));
  835.  
  836.   cl.print(eveningHour - 12);
  837.   cl.print(F("</eHour><mHour>"));
  838.  
  839.   cl.print(morningHour);
  840.   cl.print(F("</mHour><tReduct>"));
  841.  
  842.   cl.print(tempReduction);
  843.   cl.print(F("</tReduct><dState>"));
  844.  
  845.   cl.print(doorState);
  846.   cl.print(F("</dState><hState>"));
  847.  
  848.   cl.print(heaterState);
  849.   cl.print(F("</hState><sensors>"));
  850.  
  851.   if (temp1 >= -40) { //sensor 1.
  852.     cl.print(temp1);
  853.   } //end if.
  854.   else {
  855.     cl.print(F("--"));
  856.   } //end else.
  857.   cl.print(F("</sensors><sensors>"));
  858.  
  859.   if (temp2 >= -40) { //sensor 2.
  860.     cl.print(temp2);
  861.   } //end if.
  862.   else {
  863.     cl.print(F("--"));
  864.   } //end else.
  865.   cl.print(F("</sensors><sensors>"));
  866.  
  867.   if (temp3 >= -40) { //sensor 3.
  868.     cl.print(temp3);
  869.   } //end if.
  870.   else {
  871.     cl.print(F("--"));
  872.   } //end else.
  873.   cl.print(F("</sensors><sensors>"));
  874.  
  875.   if (tempOneWire >= -40) { //outdoor sensor.
  876.     cl.print(tempOneWire);
  877.   } //end if.
  878.   else {
  879.     cl.print(F("--"));
  880.   } //end else.
  881.   cl.print(F("</sensors><dateTime>"));
  882.  
  883.   if (now.hour() < 10) {
  884.     cl.print(F("0"));
  885.   }
  886.   cl.print(now.hour());
  887.   cl.print(F(":"));
  888.   if (now.minute() < 10) {
  889.     cl.print(F("0"));
  890.   }
  891.   cl.print(now.minute());
  892.   cl.print(F(":"));
  893.   if (now.second() < 10) {
  894.     cl.print(F("0"));
  895.   }
  896.   cl.print(now.second());
  897.   cl.print(F("</dateTime><dateTime>"));
  898.   if (now.month() < 10) {
  899.     cl.print(F("0"));
  900.   }
  901.   cl.print(now.month());
  902.   cl.print(F("/"));
  903.   if (now.day() < 10) {
  904.     cl.print(F("0"));
  905.   }
  906.   cl.print(now.day());
  907.   cl.print(F("/"));
  908.   cl.print(now.year());
  909.   cl.print(F("</dateTime></inputs>"));  
  910. } //end XML_response().
  911.  
  912. // sets every element of str to 0 (clears array)
  913. void StrClear(char *str, char length) {
  914.   for (uint8_t i = 0; i < length; i ++) {
  915.     str[i] = 0;
  916.   } //end for.
  917. } //end StrClear().
  918.  
  919. // searches for the string sfind in the string str
  920. // returns 1 if string found
  921. // returns 0 if string not found
  922. char StrContains(char *str, char *sfind) {
  923.   char found = 0;
  924.   char index = 0;
  925.   char len;
  926.  
  927.   len = strlen(str);
  928.  
  929.   if (strlen(sfind) > len) {
  930.     return 0;
  931.   } //end if.
  932.   while (index < len) {
  933.     if (str[index] == sfind[found]) {
  934.       found ++;
  935.       if (strlen(sfind) == found) {
  936.         return 1;
  937.       } //end if.
  938.     } //end if.
  939.     else {
  940.       found = 0;
  941.     } //end else.
  942.     index ++;
  943.   } //end while.
  944.   return 0;
  945. } //end StrContains().
  946.  
  947. //issues commands according to HTTP_req char after "%".
  948. void sendCommands(char index) {
  949.   switch (index) {
  950.     case '1':
  951.       tempHoldUp();
  952.     break;
  953.    
  954.     case '2':
  955.       tempHoldDn();
  956.     break;
  957.    
  958.     case '3':
  959.       tempReductionUp();
  960.     break;
  961.    
  962.     case '4':
  963.       tempReductionDn();
  964.     break;
  965.    
  966.     case '5':
  967.       eveningHourUp();
  968.     break;
  969.    
  970.     case '6':
  971.       eveningHourDn();
  972.     break;
  973.    
  974.     case '7':
  975.       morningHourUp();
  976.     break;
  977.    
  978.     case '8':
  979.       morningHourDn();
  980.     break;
  981.    
  982.     default:
  983.     break;
  984.   } //end switch.
  985. } //end sendCommands().
  986.  
  987. void tempHoldUp() {
  988.   tempHold += 2;
  989.   if (tempHold > 80) {
  990.     tempHold = 80;
  991.   } //end if.
  992.   EEPROM.write(0, tempHold);
  993. } //end tempHoldUp().
  994.  
  995. void tempHoldDn() {
  996.   tempHold -= 2;
  997.   if (tempHold < 12) {
  998.     tempHold = 12;
  999.   } //end if.
  1000.   EEPROM.write(0, tempHold);
  1001. } //end tempHoldDn().
  1002.  
  1003. void tempReductionUp() {
  1004.   tempReduction += 2;
  1005.   if (tempReduction > 12) {
  1006.     tempReduction = 12;
  1007.   } //end if.
  1008.   EEPROM.write(1, tempReduction);
  1009. } //end tempReductionUp().
  1010.  
  1011. void tempReductionDn() {
  1012.   tempReduction -= 2;
  1013.   if (tempReduction < 0) {
  1014.     tempReduction = 0;
  1015.   } //end if.
  1016.   EEPROM.write(1, tempReduction);
  1017. } //end tempReductionDn().
  1018.  
  1019. void eveningHourUp() {
  1020.   eveningHour ++;
  1021.   if (eveningHour > 24) {
  1022.     eveningHour = 24;
  1023.   } //end if.
  1024.   EEPROM.write(3, eveningHour);
  1025. } //end eveningHourUp().
  1026.  
  1027. void eveningHourDn() {
  1028.   eveningHour --;
  1029.    if (eveningHour < 16) {
  1030.      eveningHour = 16;
  1031.    } //end if.
  1032.    EEPROM.write(3, eveningHour);
  1033. } //end eveningHourDn().
  1034.  
  1035. void morningHourUp() {
  1036.   morningHour ++;
  1037.   if (morningHour > 11) {
  1038.     morningHour = 11;
  1039.   } //end if.
  1040.   EEPROM.write(2, morningHour);
  1041. } //end morningHourUp().
  1042.  
  1043. void morningHourDn() {
  1044.   morningHour --;
  1045.   if (morningHour < 3) {
  1046.     morningHour = 3;
  1047.   } //end if.
  1048.   EEPROM.write(2, morningHour);
  1049. } //end morningHourDn().
  1050.  
  1051. void dayLightSavings() {
  1052.   daylightSavings = !daylightSavings;
  1053.   EEPROM.write(6, daylightSavings);
  1054. } //end dayLightSavings().
Add Comment
Please, Sign In to add comment