Hi everyone,
I am fairly new to Arduino, and a beginner programmer, and could really use another pair of eyes to help me figure out how to dig my way out of a problem.
Here's my setup. I have an Arduino Uno, an Ethernet Shield 2, a magnetic window sensor, an HC-SR04 ultrasonic sensor, and an IP camera. I have the ultrasonic sensor pointing at a small box that I have place to simulate a "window".
Here's how things are supposed to work. When the magnetic sensor is pulled apart, the "window" is open. The ultrasonic sensor sends out a ping, and if the return is measured to be at least 15cm, the IP camera is accessed to retrieve a still image. This image is saved to the SD card on the Ethernet shield, and then encoded and sent off as an email attachment via SMTP2GO.
At present, I have the call to "encode()" commented out (line 251 below). With everything else in place, my sketch uses up 82% program space and 78% dynamic memory. When run, I successfully retrieve and save the image from the IP camera and the email is successfully sent (albeit with a blank attached file - remember, no encoding takes place). That works well. The second that I remove the comments to the call to "encode()", my program space is used up by 84%, and dynamic memory by 81%. This time, running the sketch results in the image failing to save. The file opens and closes, but no data ever gets written. re-comment the call to "encode()", and all is well again.
Thinking that this was a memory problem, I started looking into Arduino memory management. I am new to this, so I am not sure that I understand everything. I already have F() placed around my Serial.println strings, but none around my client.println strings. Putting F() around even one of these client.println strings reduces my dynamic memory use by 1% (good!), but when I run the code my image fails to save again (bad!).
I have successfully tested each segment of this (window sensor, ultrasonic sensor, camera access, image retrieval, attachment sent as email) in separate sketches. My challenge has been in combining them all into a single sketch. Most of it has gone well - and things have only started to go wrong when I tried adding the email portion of this.
Can someone please tell me where I am going wrong? Here is my code that I am using, borrowed from several examples found online.
#include <SPI.h> #include <SD.h> #include <Ethernet2.h> #include <NewPing.h> // Arduino pin tied to trigger pin on the ultrasonic sensor. #define TRIGGER_PIN 8 // Arduino pin tied to echo pin on the ultrasonic sensor. #define ECHO_PIN 7 // Maximum distance we want to ping for (in centimeters). Maximum sensor //distance is rated at 400-500cm. #define MAX_DISTANCE 200 // window sensor pin #define WindowPin 6 //variable to hold the distance to the "window" int distance; // NewPing setup of pins and maximum distance. NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); byte mac[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; IPAddress server(192, 168, 1, 27); IPAddress ip(192, 168, 1, 100); char mailServer[] = "mail.smtp2go.com"; EthernetClient client; boolean currentLineIsBlank = true; File theFile; File sendFile; //variable to use for encoding process static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; void setup() { Serial.begin(9600); Serial.println(F("Starting the serial monitor")); pinMode(WindowPin, INPUT_PULLUP); // disable Ethernet chip pinMode(10, OUTPUT); digitalWrite(10, HIGH); Serial.print(F("Initializing SD card...")); if (!SD.begin(4)) { Serial.println(F(" initialization failed!")); return; } Serial.println(F(" initialization done.")); // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { Serial.println(F("Failed to configure Ethernet using DHCP")); // try to congifure using IP address instead of DHCP: Ethernet.begin(mac, ip); } // give the Ethernet shield a second to initialize: delay(1000); // print your local IP address: Serial.println(Ethernet.localIP()); } void loop() { //take a read of the WindowPin. If it reads HIGH, the window is open, //and a message can be displayed as such if(digitalRead(WindowPin) == HIGH) { Serial.println(F("the window is open. check to see if person is inside or outside")); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the //shortest delay between pings. delay(50); Serial.print(F("Ping: ")); // Send ping, get distance in cm and print result (0 = outside set distance range) distance = sonar.ping_cm(); Serial.print(distance); Serial.print(F("cm")); //if the distance to the "window" is less than 15cm, indicate that it was //opened from inside. Otherwise, insicate that it was opened from outside if(distance <15) { Serial.println(F(" --opened from inside")); Serial.println(); } else { Serial.println(F(" --opened from outside")); Serial.println(F("Let's take a picture")); Serial.println(F("connecting to camera...")); // if you get a connection, report back via serial: if (client.connect(server, 80)) { Serial.println(F("connected")); // Make a HTTP request: client.println("GET /image.jpg"); client.println("Authorization: Basic Y="); client.println("Host: 192.168.1.27"); //client.println("Connection: close"); client.println(); delay(1000); } else { // kf you didn't get a connection to the server: Serial.println(F("connection failed")); } // open the file for writing Serial.println(F("Creating file.")); theFile = SD.open("pic.jpg", FILE_WRITE); // change file name to write to here if (!theFile) { Serial.println(F("Could not create file")); while (1); } // from the server, read them and print them: while (client.available()) { char c = client.read(); if (c == '\n' && currentLineIsBlank) { // end of HTTP header, now save requested file while (client.connected()) { // stay in this loop until the file has been received if (client.available()) { c = client.read(); // get file byte Serial.print(c); theFile.print(c); // save file byte } } } // detect the end of the incoming HTTP header if (c == '\n') { // starting a new line currentLineIsBlank = true; } else if (c != '\r') { // got a character on the current line currentLineIsBlank = false; } } // if the server's disconnected, stop the client: if (!client.connected()) { Serial.println(); Serial.println(F("disconnecting.")); client.stop(); theFile.close(); Serial.println(F("Finished writing to file")); if(sendEmail()) Serial.println(F("Email Sent")); else Serial.println(F("Email Failed")); while(true); // do nothing forevermore: //while (true); } } //delay for 2 seconds, to avoid incessant scrolling delay(2000); } //If the sensor reads LOW, the window is closed, and a message can be //displayed as such. No need to involve the ultrasonic sensor else { Serial.println(F("Window is closed. No need to check distance")); //delay for 2 seconds, to avoid incessant scrolling delay(2000); } } byte sendEmail(){ byte thisByte = 0; byte respCode; if(client.connect(mailServer, 80) == 1){ Serial.println(F("Connected")); } else { Serial.println(F("Connection Failed")); return 0; } if(!eRcv()) return 0; Serial.println(F("Sending Hello")); //replace 1.2.3.4 with your Arduino's ip************************** client.println("EHLO"); if(!eRcv()) return 0; Serial.println(F("Sending authorizes login")); client.println("auth login"); if(!eRcv()) return 0; Serial.println(F("Sending User")); //Change to your base64 encoded user************************** client.println("Y="); if(!eRcv()) return 0; Serial.println(F("Sending Password")); //change to your base64 encoded password************************** client.println("Y="); if(!eRcv()) return 0; //change to your email address (sender)************************** Serial.println(F("Sending From")); client.println("MAIL From: <ME@gmail.com>"); if(!eRcv()) return 0; //change to recipient address************************** Serial.println(F("Sending To")); client.println("RCPT To: <YOU@gmail.com>"); if(!eRcv()) return 0; Serial.println(F("Sending DATA")); client.println("DATA"); if(!eRcv()) return 0; Serial.println(F("Sending email")); //change to recipient address************************** client.println("To: You <YOU@gmail.com>"); //change to your address************************** client.println("From: Me <ME@gmail.com>"); client.println("Subject: Sent from Donny's Arduino"); //Start of Attach File sendFile =SD.open("pic.jpg",FILE_READ); client.print("Content-Type: image/jpg; name=\"pic.jpg\"\r\n"); client.write("Content-Disposition: attachment; filename=pic.jpg\r\n"); client.print("Content-Transfer-Encoding: base64\r\n\r\n"); //encode(); sendFile.close(); //End of Attach File client.print("\r\n.\r\nQUIT\n"); if(!eRcv()) return 0; client.stop(); Serial.println(F("disconnected")); return 1; } byte eRcv(){ byte respCode; byte thisByte; int loopCount = 0; while(!client.available()){ delay(1); loopCount++; // if nothing received for 10 seconds, timeout if(loopCount > 10000) { client.stop(); Serial.println(F("\r\nTimeout")); return 0; } } respCode = client.peek(); while(client.available()){ thisByte = client.read(); Serial.write(thisByte); } if(respCode >= '4'){ efail(); return 0; } return 1; } void efail(){ byte thisByte = 0; int loopCount = 0; client.println(F("QUIT")); while(!client.available()) { delay(1); loopCount++; // if nothing received for 10 seconds, timeout if(loopCount > 10000) { client.stop(); Serial.println(F("\r\nTimeout")); return; } } while(client.available()){ thisByte = client.read(); Serial.write(thisByte); } client.stop(); Serial.println(F("isconnected")); } void encodeblock(unsigned char in[3],unsigned char out[4],int len) { out[0]=cb64[in[0]>>2]; out[1]=cb64[((in[0]&0x03)<<4)|((in[1]&0xF0)>>4)]; out[2]=(unsigned char) (len>1 ? cb64[((in[1]&0x0F)<<2)|((in[2]&0xC0)>>6)] : '='); out[3]=(unsigned char) (len>2 ? cb64[in[2]&0x3F] : '='); } void encode() { unsigned char in[3],out[4]; int i,len,blocksout=0; while (sendFile.available()!=0) { len=0; for (i=0;i<3;i++){ in[i]=(unsigned char) sendFile.read(); if (sendFile.available()!=0) len++; else in[i]=0; } if (len){ encodeblock(in,out,len); for(i=0;i<4;i++) client.write(out[i]); blocksout++; } if (blocksout>=19||sendFile.available()==0){ if (blocksout) client.print("\r\n"); blocksout=0; } } }
Thanks for your help in advance. I really appreciate it!
Donny