vulture2600

Thermostat RTC I2C for Mega! V6.6

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