Automated Reptile Control System(webserver, Data Logging, RTC and much more)

Hi everyone
"wallaceb" you have done a very good job here.

Question: It possible this code to work on UNO ?

Thanks

gvaf:
Hi everyone
"wallaceb" you have done a very good job here.

Question: It possible this code to work on UNO ?

Thanks

unfortunately no. the entire sketch currently uses 106,000 bytes of FLASH, too much for the UNO. However with that said, most of the 106,000 bytes is the PROGMEM storage of the HTML pages. If the sketch was somehow changed to pull the HTML off the SD card instead, it might fit, but i have not checked.

Is it me or is there an issue with the Arduino.zip file? When I try to open it, it seems it is invalid...
I could benefit from this code. I'm looking for tabulating code to be able to show status of things and then yet to be able to set values via the web.

tb

i have actually completed my code. i added more functionality and fixed bugs.

in the data logging adjust page, i added the ability to delete selected data files and fixed a bug in my used space calculation. now the webpage displays the exact same value as windows explorer does. :grin:

i also added another page for system information that includes system up-time, MAC address, number of sensor malfunctions if any, and the amount of free system RAM.

there were about 10 bugs that i found over the course of testing which appear to be fixed. there is still a bug in that the watch dog timer will reset the unit ever 1-2 days if i have data logging enabled, but not if it is off. i am looking into that.

with this said, tonight when i get off work, i will post all the code directly on this page.

Very Nice Work indeed do you have a set up diagram as well :slight_smile:

ericklil:
Very Nice Work indeed do you have a set up diagram as well :slight_smile:

are you referring to a system schematic?

i cannot paste my code into the page because of a 9500 character limit. i am going to try uploading it to a file service

edit:

hopefully the supplied link will work.

Zip worked fine, very nice.

System schematic would be grand, looks well thought out in the pictures.

Wallaceb,
That is a very nice project. One of the absolute best I have ever seen! True genius.
Peter

106K flash is really large :P, use microSD instead!

it looks great!!!

however after uploading the code I can not get into it- DHCP on my router does not seem to see it.

What would be the way to set the static ip in the code ?

thanks!

ODwyerPW:
Wallaceb,
That is a very nice project. One of the absolute best I have ever seen! True genius.
Peter

thanks very much for the complement 8)

mkcinek:
it looks great!!!

however after uploading the code I can not get into it- DHCP on my router does not seem to see it.

What would be the way to set the static ip in the code ?

thanks!

:fearful: oops.. i forgot to post the code i used to "program" the EEPROM for all the "default" settings. when i get home later tonight i will post that code :grin:

iouzzr:
106K flash is really large :P, use microSD instead!

with 256 k of available memory i was not going to worry about it. i originally thought to use the SD card, but decided that PROGMEM coding would be easier to code and control and faster with respect to I/O since the processor would not have to read a byte from SD card, store it locally, then send it to the Ethernet shield.

robtillaart:
Looks very well done (+1),

(nitpicking - Automated Reptile Environment Control System - makes a better acronym arecs that's an anagram of scare :wink:

thanks for pointing that out. i made the upadtes to the code. have not gotten to changing the pictures in the post though

edit: added a link to the initialization sketch.

download this to the arduino, it will configure all the EEPROM.
download the normal code to the arduino and the web-page default URL is static at 192.168.1.200
you can then configure all the settings to your likings.

edit:

i am adding more stuff to my code from here:

to make the downloading of log files MUCH faster. i will post the new code soon

for anyone who is trying to use my code, there was a fairly large bug that was cause by my attempt to reduce the amount of RAM usage. this bug would make any page forms submitted to not process properly.

i have subsequently corrected the bug. the latest version of ALL code is in the link below, the libraries i use, the EEPROM initialize code, and the latest working code that i have.

https://www.dropbox.com/s/3e75754ivc1m0by/Arduino_2-24-2013.zip

Thanks for an update :slight_smile:

Would you be so kind and draw a diagram and list parts used,please?

i cannot really give a list other than what i did on the first page. all the enclosure supplies i either already had lying around the house and do not have part number for, or i got on e-bay by performing searches for what i wanted and combed through the results until i found what looked good. the case, the switches, the terminal blocks, the fuse blocks, i do not have part numbers for. the outlets are standard outlets you can get a home depot or something.

i do not have a diagram of how it is wired... i do all that from my head, but i feel it is fairly straightforward how the outlets should be wired to the relays. all the low voltage wiring for the sensors and the RTC are based on the respective device data sheets, and how the libraries require them to be wired.

i am suddenly experiencing some complete crash / freeze issues after about half a day =(

i previously was having issues where the watch dog would reset my program after a few days, but this is horrible.

i do know it is suggested to not use strings in programs, but it was the way i figured out how to code what i wanted. i did some searching and i have found this thread:

"String corrupts the heap and crashes" http://arduino.cc/forum/index.php/topic,115552.0.html

i am going to try using the modified string library Paul Stoffregen created to correct the memory issues related to the string library.

i wanted to know if anyone can either run the code on their own setup and see if you also crash/freeze, or help me come up with a better way to remove all need for strings. Thanks :grin:

Do you do the below with your Strings before exiting the subroutines in which the Strings were used?

String datastring = "";

zoomkat:
Do you do the below with your Strings before exiting the subroutines in which the Strings were used?

String datastring = "";

no i do not. i thought that when a function is ended, any local variables used within the function were cleared.

i will give that a try though

i am also wondering if it is something with the ethernet shield. i have been able to crash the arduino if i purposfully send lots of information over to it really fast. it just stops responding.

i am also wondering why my arduino freezes when i have the watchdog enabled. should that not reset the system?

i tried to use the "Wstring.cpp" and "Wstring.h" from Paul Stoffregen's teensey system. everything compiled, but it would no longer function and i have not determined what is causing it to not work.

no i do not. i thought that when a function is ended, any local variables used within the function were cleared.

From what others have discussed, that is the premis of Strings issue, that the last String memory location used in the function is not automatically cleared as expected, resulting in that memory location no longer being available for use. May or may not help.

zoomkat:

no i do not. i thought that when a function is ended, any local variables used within the function were cleared.

From what others have discussed, that is the premis of Strings issue, that the last String memory location used in the function is not automatically cleared as expected, resulting in that memory location no longer being available for use. May or may not help.

i have read that as well.

i have added to my code the lines to set all used strings to "" before the function ends. so far the arduino has 14 hours of up time.

i am in the process of trying to remove all uses of strings within my code. the main area strings are used is in processing of the data submitted by a web-page form in the function "sendPage"

void sendPage(EthernetClient & client, int nUriIndex, BUFFER & requestContent, char * global_pUri)
{
  if (nUriIndex < NUM_PAGES){
    wdt_reset();
    String datastring = "";
    
    //page was received, need to determine if the page returned ay form data
    //if form data was was received we need to process it on a per page process
    //page 1 does not have any form data
    //page 2 have 17 form entries for different temperature settings. these settings need to be extracted from the requestcontent 
    //variable. once the data is extracted it needs to be saved to the correct variables and then to EEPROM so the setting take effect
    //between power outages
    
    /***************************************************************
    //PAGE 2 DATA PROCESSING
    ***************************************************************/
    
    if (nUriIndex == 1){//page 2
      //convert the request content variable from an array into a string
      
      for (byte x=0; x < 129; x++){
        datastring.concat(requestContent[x]);
      }  
      if (datastring.substring(0,2)=="1="){ //tests if the page has had a form submitted with data or not
          for (byte x = 1; x<18; x++){ //page 2 contains 17 data entry text boxes, so we want to run through all of them
            String temp1 = ""; //initilize temp variables to clear any previous data
            String temp2 = "";
            //the format for the submitetd form data is:
            //1=entry1&2=entry2&3=entry3 ect... 
            //we want to use the sub string command, so we need to know the index locations for where the desired data entry index is
            //along with the data entry index of the next entry. 
            temp1.concat(x);
            temp1.concat("=");
            temp2.concat(x+1);
            temp2.concat("=");
            //we need to see if the current entry is below 10. if the entry is below 10, we only need to skip 2 entries, one for the entry number
            //and another for the equals sign. however if the entry is above 10, we need to skip 3 entries becuase of the two digits for the entry
            //and another entry for the equals sign
            if (x<10){
              char valueArray[datastring.substring(datastring.indexOf(temp1) + 2,datastring.indexOf(temp2) -1).length() + 1];
              datastring.substring(datastring.indexOf(temp1) + 2,datastring.indexOf(temp2) -1).toCharArray(valueArray, sizeof(valueArray));
              if (x == 1){      //if the currently processing entry is entry 1
                if (atoi(valueArray)>= min_temp_setting && atoi(valueArray) <= max_temp_setting){    //is the entred entry within the allowable bounds?
                  INCSGDTON = atoi(valueArray);    //converts the string value of the entred data into a interger
                  if (EEPROM.read(INCSGDTONEEPROMADDR)!=INCSGDTON){    //if the user has not changed the entry from what is already in memory, then we do not want to save to EEPROM again as the EEPROM has a shorter life time
                    EEPROM.write(INCSGDTONEEPROMADDR, INCSGDTON);    //since the user has entered a new number, we now need to save this to memory
                    INCSGDTON_incorrect = false;    //because a valid entry was entered, we do not want the web-page to display "Invalid Entry!"
                  }
                }else{
                  INCSGDTON_incorrect = true;//if the user did enter an invalid value then we want the web-page to display "invalid entry!" when the substitution function runs
                }
              }else if (x == 2){
                if (atoi(valueArray)>= min_temp_setting && atoi(valueArray) <= max_temp_setting){
                  CSGDTOFF = atoi(valueArray);
                  if (EEPROM.read(CSGDTOFFEEPROMADDR)!=CSGDTOFF){
                    EEPROM.write(CSGDTOFFEEPROMADDR, CSGDTOFF);
                    CSGDTOFF_incorrect = false;
                  }
                }else{
                  CSGDTOFF_incorrect = true;
                }
              }else if (x == 3){
                if (atoi(valueArray)>= min_temp_setting && atoi(valueArray) <= max_temp_setting){
                  MSGDTON = atoi(valueArray);
                  if (EEPROM.read(MSGDTONEEPROMADDR)!=MSGDTON){
                    EEPROM.write(MSGDTONEEPROMADDR, MSGDTON);
                    MSGDTON_incorrect = false;
                  }
                }else{
                  MSGDTON_incorrect = true;
                }
              }else if (x == 4){
                if (atoi(valueArray)>= min_temp_setting && atoi(valueArray) <= max_temp_setting){
                  MSGDTOFF = atoi(valueArray);
                  if (EEPROM.read(MSGDTOFFEEPROMADDR)!=MSGDTOFF){
                    EEPROM.write(MSGDTOFFEEPROMADDR, MSGDTOFF);
                    MSGDTOFF_incorrect = false;
                  }
                }else{
                  MSGDTOFF_incorrect = true;
                }
              }else if (x == 5){


ect....

i turn the submitted data into a string so i can use this code

char valueArray[datastring.substring(datastring.indexOf(temp1) + 2,datastring.indexOf(temp2) -1).length() + 1];
              datastring.substring(datastring.indexOf(temp1) + 2,datastring.indexOf(temp2) -1).toCharArray(valueArray, sizeof(valueArray));

to extract the different entry values

i have not tested it yet, but i am going to try using the following demonstration code instead

#include <.h>
void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);
}

void loop()
{
 //incomming string of data. string is actually 128 characters long, but this is the only section we care ot process. The "=%" indicates the end of the part of the strign we care about
 char str[] = "1=80&2=82&3=83&4=84&5=85&6=86&7=87&8=88&9=89&10=90&11=91&12=92&13=93&14=94&15=95&16=96&17=97&18=%";
 Serial.print("The string of submitted data is: ");
 Serial.println(str);
 for (byte x = 1;x<=17;x++){
   char ValueArray={NULL};
   PROCESSREQUESTCONTENT(x, str, &ValueArray);
   Serial.print("The value of entry # ");
   Serial.print(x);
   Serial.print(" is equal to: ");
   Serial.println(atoi((char *)ValueArray));
 }
}

void PROCESSREQUESTCONTENT(byte index, char * str, char * output){
 int pch=0;
 byte beginning=0;
 byte ending=0;
 byte counter=0;
 //locate where "%" is located so we know where to stop
 pch=atoi(strchr(str,'%'));
 
 //"pch-4" is required because pch indicates where the "%" sign is with the first character starting at 1. however the char array starts at 0. in addition we do not care about the "&17=" part of the ending.
 //the length of the "5" itself is removed because of the offset from starting point 1 to starting point 0
 //the "-4" is so the code ignores the "&18=" characters
 for (byte x=0;x<= pch-4;x++){
   if (strncmp((char *)str[x],"=",1)==0){
     beginning = x+1; //starting character position of actual data entry
   }else if (strncmp((char *)str[x],"&",1)==0){
     ending=x-1;//ending character position of actual data entry
     counter++;//increment counter so we can see if this is the data entry we care about
   }
   if (counter==index){//have we found the data antry we care about?
     counter = 0;
     for (byte i=0; i<=(ending-beginning);i++){//copy the data entry so we can use it
       output[i] = str[beginning + i];
       break;
     }
   }     
 }
  
}

wish me luck

Check in the playground for memory usage. There are a couple of routines there that can tell you how much you have left at any given time. I use them extensively to keep away from running out of memory. You can put them in temporarily to measure what you have left and isolate a problem area then fix whatever is needed.

In a couple of hard cases, I put them in the loop() and automatically rebooted the board to clean things out when free memory reached a low number. This was a stop gap measure I used while I tried to figure out what the heck was going on. These days, I try desperately to avoid using Strings and use the old reliable strcat, strcmp, etc. instead.

Something like:

#include <avr/pgmspace.h>

void showMem(){
  uint8_t * heapptr, * stackptr;
  
  strcpy_P(Dbuf,PSTR("Mem = "));
  Serial.print(Dbuf);
  stackptr = (uint8_t *)malloc(4);   // use stackptr temporarily
  heapptr = stackptr;                // save value of heap pointer
  free(stackptr);                    // free up the memory again (sets stackptr to 0)
  stackptr =  (uint8_t *)(SP);       // save value of stack pointer
  Serial.println(stackptr - heapptr);
}

// and then sprinkle these around to get a feel for what is going on

    showMem();

Or maybe you would prefer:

#include <MemoryFree.h>

void showMem(){
  strcpy_P(Dbuf,PSTR("Mem = "));
  Serial.print(Dbuf);
  Serial.println(freeMemory());
}

// and then, as above, I sprinkle these around to see what is happening

showMem();

I use both in different applications. Don't have a preference either way.