Hello all. I am trying to see if there is a way to have arduino read an email, parse it for a specific line, and then based on that line perform an action.
example:
blahblahblahblah blahblahblahblah lineofinterest in the format of (trigger:action) blahblahblahblah
effectively, there would be 4 or 5 different actions that may or may not appear in a list (action1, action2, action3) but the trigger at the beginning of the line is always going to be the same.
I have seen many examples of getting the Ethernet shield to check an account and see if there are emails existing, but i have not seen one yet about getting it to actually read the content of an email. any nudge in the right direction would be greatly appreciated
EDIT: So I finally had a chance to sit down and read all your replies and as much as I enjoyed the strings vs array battle that ensued, I think I should clarify my original post. Parsing the email for the line and determining the contents wasn't so much my issue, but I'm glad you all had plenty of opinions on the best way to go about that. I more need a nudge for how to actually get the email stored into the Arduino to be able to read it. I am not very familiar with how Arduino accesses the mailbox and how it can get retrieve the actual email. Once I can get the block of text into the Arduino, I should be good, but I have never tried accessing email from anything but a web browser and I'm not really sure where to start.
this one may be easier to understand, the example can be found in the Arduino examples
Im trying to simplify this for you myself, but maybe someone else already has a code you can try.
A very poor way of doing it would be to read in a character, store it in a string or array, and using an IF statement, compare it to the word you want.
pseudo:
void loop() {
if(Serial.available())
{
charData = Serial.read(); //Hi, my name is Andrew
if(charData == ' ' || charData == '\n') // if a space " " is found or a new line is made
{
if(StringIn == "Andrew"){ //does the string match? :: made an edit from ' ' to " "
Serial.println("Andrew was found!"); //string does match
}
else {
Serial.println("Andrew was NOT found!"); //string does NOT match
StringIn = ""; //clear string for new data
}
}
else StringIn += charData; //if string does not equal " ", then store data into string
}
}
EDIT: code is now compiled, but not tested. I dont have my stuff with me today, sorry.
Something along the lines of this. I do NOT reccommend this though
Given that you have an Ethernet shield, what you're asking for is possible.
I assume the email would come from a mailbox on the public internet. In that case you would have to set up your network so that the Arduino was able to connect to the public internet.
You would need to find what access protocols the mail server supported, the network ports used (if non-standard) and what authentications standards it supported.
You'd need to write a sketch that used the supported protocols to access and authenticate with the mail server. You may be able to find an existing library for the protocols you use, or you may not. If not, you'd need to create your own implementation. It wouldn't be especially difficult to implement your own, but it wouldn't be trivial either.
You'd need to configure the Arduino with details of the mail server, mailbox address and credentials.
Once you have all that working, you would be able to retrieve emails from the mailbox. The mails could easily be too big for the Arduino to hold in memory so you would probably need to buffer them one line at a time. Your next problem will be to interpret the mail encoding to extract the text. If you only need to support plain text email, no work is needed. If you need to deal with MIME encoded emails then this could be very complicated to implement.
Once you have obtained the text, parsing it to recognise specific key words or patterns would be relatively straight forward, and very similar to examples you'll already find of recognising commands received over the serial port.
What you're asking for would be very much easier to do on a PC since you can use existing software to deal with the networking and protocol handling issues and you could easily implement some pattern matching in JScript, VBScript, or whatever other language you like working in. It's possible on the Arduino, but would require you to find or create quite a bit of functionality.
void loop()
{
if(Serial.available())
{
charData = Serial.read(); //Hi, my name is Andrew
if(charData == ' ' || charData == '\n') // if a space " " is found or a new line is made
{
boolean tagged = StringIn.indexOf("Andrew"); //scan string for "Andrew", true if found
tagged ? Serial.println("Andrew was found!"): Serial.println("Andrew was NOT found!"); //string does it match, or NOT
StringIn = ""; //clear string for new data
}
}
else StringIn += charData; //if string does not equal " ", then store data into string
}
Here is the string equivalent just as a demonstration of how easy it actually is and less prone to errors down the road (I avoided fixing the piss-poor indenting as part of the demonstration):
char StringIn[80];
index i=0;
void loop() {
if(Serial.available())
{
charData = Serial.read(); //Hi, my name is Andrew
if(charData == ' ' || charData == '\n') // if a space " " is found or a new line is made
{
char *tagged = strstr(StringIn, "Andrew"); //scan string for "Andrew", true if found
tagged!=0 ? Serial.println("Andrew was found!"): Serial.println("Andrew was NOT found!"); //string does it match, or NOT
StringIn[0] = '\0'; //clear string for new data
i=0;
}
}
else StringIn[i++] = charData; //if string does not equal " ", then store data into string
}
So there ya go, my code uses the String Method and Arrch uses array method.
Now you said you were going to be reading from an email, so you will need to tweak this line a bit "char StringIn[80];" , Im not sure what the maximum size of an array is, but that should not matter if your getting the data and then clear the array.
Thanks guys, I'll take a more in depth look at all your suggestions over the weekend, and go from there. I'm still kind of new to Arduino so I'm glad you all were able to at least give me a helpful nudge.
So you demonstrated something he couldn't even test, just to show him how the string works? If it doesn't work then how will he know that the Idea even works to begin with.
HazardsMind:
So you demonstrated something he couldn't even test, just to show him how the string works? If it doesn't work then how will he know that the Idea even works to begin with.
Forums are public; the OP isn't the only one who reads this thread. The point was that anybody who looked at your code, then mine, would realize that c style strings aren't these scary things that are severely limited in what they can do. I didn't post code that worked because you didn't. I simply took your code and converted it into a char array to demonstrate that using Strings aren't that much easier.
I'll make sure that the next time you post code, to assume it doesn't work.
Never said it was, but why use it when there is (as demonstrated) an easy alternative when it's known to be a habitual issue causer?
The issue as I understand it, in the two often referenced discussions, is said to possibly occurr in sub routines using Strings where used memory is normally expected to be freed when the sub routine is exited is not released. I have yet to see any issues in simple code using Strings actually be corrected by changing to strings. Read the discussions and form your opinion.
This is a working code that uses arrays. If anyone wants to mod this, go ahead.
char StringIn[100];
int found;
char charData;
int i = 0;
int flag;
byte led = 13;
#include<string.h>
void setup()
{
pinMode(led,OUTPUT);
Serial.begin(9600);
}
void loop() {
if(Serial.available())
{
charData = Serial.read(); //Hi, this is a test and my name is Andrew.
if(charData =='.' || charData ==' ' || charData ==',' || charData =='\n') // if anyone of these is entered, it will compare it.
{
found = strcmp("Test",StringIn); // compares the test string to the inputted string. NOTE: will return 0 if they are equal!
if(found == 0) //are they equal?
{
Serial.println("got it");
flag = 0;
}
else
{
if(!flag)
{
Serial.println("Scanning"); //not equal yet
flag = 1;
}
}
while(i!=0)
{
StringIn[i--] = 0;
}
}
else{
StringIn[i++] = charData;
}
delay(20);
}
}
NOTE: This code will not return anything if the test word is NOT found.
Here's another method I've used when searching for keywords in data streaming in via a serially-connected WiFly wifi bee. A function that returns true if a searchstring (passed in searchString) is found in the serial buffer:
// --------------------------------------------------------------------------------------------
// read the WiFLy serial buffer until it's exhausted, looking for searchString
// return TRUE on finding searchString, leaving buffer at next character after
// the located searchString. Return FALSE if searchString not found in buffer
// Does not retry until timeout, returns once buffer empty.
// Does NOT empty buffer after finding string.
// Parameters:
// searchString: the response we're searching for
//
boolean findInWiFlyBuffer(char* searchString) {
char * ptr = searchString; // iterator for matching
char thisChar;
while(Serial.available() && *ptr) { // ends when found, or no more chars in buffer
thisChar = Serial.read(); // IDE likes using a variable rather than direct comparison
if(thisChar == *ptr) ptr++; // move to next searchSring character for comparison
else ptr = searchString; // back to start of searchString
} // while
return *ptr == 0 ? true : false; // returns true if comparison got to end of searchString (null char)
}
To test for the text "test" in the serial stream would simply be a call to:
if(findInWiFlyBuffer("test")) {
// do stuff
}
If you need it to instead return the number of characters read before the string match, that is also easy done with a slight modification. Note that in this method, everything up to the matched string is discarded from the serial buffer but a benefit is there is no need for a static array to be defined.
To be of good practical use, the code needs to check the data stream for something special, at which point the data is captured into a string (or what ever) for further evaluation of the string content.
zoomkat:
To be of good practical use, the code needs to check the data stream for something special, at which point the data is captured into a string (or what ever) for further evaluation of the string content.
In which case my function will be perfect - once it's found the keyword you're searching for, the next call to Serial.read() will be at the data you're wanting to interrogate. All without creating any additional data structure to store it in.
I'm curious as to how the streaming data stream would be searched for more than one data string without being very cumbersome. With a saved data string the typical string search functions would seem to be easier to use (maybe why they were developed).