Read Serial --> Send SMS --Ideas--

Hi,

I'm starting to implement an aplication with arduino.

Description:

I have a system, that has a serial port. Normally I connect my laptop and with hyperterminal I read the output.

I want to use the arduino to permanently read the serial output, 'look' at the data and store the important pieces ( XX.x%, alarms, errors, etc).

In the event of an error being detected, or at predetermined intervals it will use a gsm modem to send an SMS.

I'm thinking about using something like a siemens mc35 to manage the gsm comunication.

So basicly the arduino would be continuously reading the output of the serial port, store the 'important' values, and react to specific strings in the serial data or to calls to the mc35.

What problems do you forsee in this setup?

If you can get the devices to all talk to each other (should not be a real problem), the only issue I see is with the "permanently store the data" requirement. The Arduino does not have a lot of storage capability. You could add an SD card, and store data there.

One other potential issue that comes to mind is how fast the existing application/system is streaming the data. The Arduino is not the fastest device in the world. If the data rate is too high, the Arduino will not be able to keep up.

I've done some tests, and the arduino seems to handle the 9600 pretty well, doesn't it?

Anyway.. the screen is more or less this one:

The data storage doesn't seem to be a problem, since its continuously transmited.. at any time I should just have to wait for the 'screen' to be refreshed, right?

I'm thinking about using the 'real' serial port to read the stream, and a soft.serial to send the commands do the modem, any problems here?

mariorenato,

I see one potential complication. The tipoff is the highlighted "ON" next to "Compressor:". This was probably done with an escape sequence, consisting of an ASCII ESC character, followed by some printable characters that don't show up on the terminal emulator screen, but cause it to change into and out of reverse video.

It's possible to filter out the escape sequences, of course.

It's also possible that the device doesn't transmit the whole screen of information every time it refreshes. It might just update the values that changed, using escape sequences to position the cursor.

The easiest way to find out is to capture the data stream that comes from the device. Most decent terminal emulators can do this. :slight_smile:

It sounds like a fun project. Please keep us posted on your progress.

Regards,

-Mike

Hey, I working on a similar project, and was wondering how you are going to send data from the rs232 to the arduino?

-Thomas

I started working on this today.

Below is the 'very' beginning of the code.

Until now, I'm testing sending the captured text I saved from the system, with hyperterminal to the arduino, and se if it finds the character '%' and show.me the value.

Already have a max232 to interface with a 'real' serial port, but I'll keep testing the parsing with the laptop until I have it well sorted out

int lenghtArray = 100;
char str[100]; 
int a=0;
int i = 0;
void setup() {
  Serial.begin(9600);
}

void loop() {
  //delay(10)  ;

  while ( Serial.available() && i<lenghtArray ){    // Check if serial is availiable, and array still not full
    str[i] = Serial.read();
    i++;
    //Serial.println(i);
  }



//////////////////////////////////////////////////////////////////////////////////////////
///////////////                     Search for xx.x%                       /////////////// 
//////////////////////////////////////////////////////////////////////////////////////////


  if(i>=lenghtArray){                                 // If its full
    for(a=4; a<lenghtArray; a++){                      // go along the array 
      //Serial.print(str[a]);
      if (str[a]=='%' && str[a-2]=='.'){    // searching for the string xx.x%
        Serial.print  (str[a-4]);
        Serial.print  (str[a-3]);
        Serial.print  (str[a-2]);  
        Serial.print  (str[a-1]);
        Serial.println(str[a]);  
      }
    }
    i=0;
  }
//////////////////////////////////////////////////////////////////////////////////////////
///////////////               End of      Search for xx.x%                 /////////////// 
//////////////////////////////////////////////////////////////////////////////////////////

}

Now.. How do i concatenate the values a-4 to a in an integer? or is there a more eficient way of doing the hole thing?

OK... this is not a very Arduino like answer but: I don't understand why you'd want this. If you use a Siemens/Cinterion XT65 or XT75 you have a GSM/GPRS modem that can be Java programmed and do everything you want it to do. We are using this quite often for remote control and guarding.

Back to 'Arduino mode': if you want make this an Arduino thing then go all the way using a shield lik http://www.libelium.com/squidbee/index.php?title=New_GPRS_module_for_Arduino_(Hilo_-_Sagem)

When I started I was looking at 'dumb' gprs modems... so I would be using the arduino to do the processing and the modem to send the sms.

Now, When I saw the new gprs modems with java, yes, it could be done with them.. but since I still dont have one with me, and the code can be ported, why not start with the arduino.

As for the shield.. do you think the shield has the same 'reliability' as a comercial product?

my way of doing the concatenation:

value = (((str[a-4]-48)*10) + (str[a-3]-48) + ((str[a-1]-48) * 0.1)); // concatenate

Time to close for today.

so.. for the first day, I can read the serial stream, and convert to a float one of the values I'm searching for :slight_smile:

int lenghtArray = 100;
char str[100]; 
int a=0;
int i = 0;
float lHeLevel=0;
void setup() {
  Serial.begin(9600);
}

void loop() {
  //delay(10)  ;

  while ( Serial.available() && i<lenghtArray ){    // Check if serial is availiable, and array still not full
    str[i] = Serial.read();
    i++;
    //Serial.println(i);
  }

//////////////////////////////////////////////////////////////////////////////////////////
///////////////                     Search for xx.x%                       /////////////// 
//////////////////////////////////////////////////////////////////////////////////////////


  if(i>=lenghtArray){                                  // If its full
    for(a=4; a<lenghtArray; a++){                      // go along the array 
      //Serial.print(str[a]);
      if (str[a]=='%' && str[a-2]=='.'){    // searching for the string xx.x%
        //Serial.print  (str[a-4]);
        //Serial.print  (str[a-3]);
        //Serial.print  (str[a-2]);  
        //Serial.print  (str[a-1]);
        //Serial.println(str[a]); 
      lHeLevel = (((str[a-4]-48)*10) + (str[a-3]-48) + ((str[a-1]-48) * 0.1));      // concatenate
      Serial.print ("Level: ");
      Serial.print (lHeLevel); 
      Serial.println ("%");
      }
    }

    i=0;
  }
//////////////////////////////////////////////////////////////////////////////////////////
///////////////               End of      Search for xx.x%                 /////////////// 
//////////////////////////////////////////////////////////////////////////////////////////

}

When I started I was looking at 'dumb' gprs modems... so I would be using the arduino to do the processing and the modem to send the sms.

Now, When I saw the new gprs modems with java, yes, it could be done with them.. but since I still dont have one with me, and the code can be ported, why not start with the arduino.

One reason I could think of is: the Arduino has one serial port and it seems that you need two. One to read the device that is offering status updates and one to communicate with the modem. Or am I wrong here?

value = (((str[a-4]-48)*10) + (str[a-3]-48) + ((str[a-1]-48) * 0.1)); // concatenate

doesn't atoi solve your need? (http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/) It should convert at least the non-decimal part of the percentage to an integer.

Hi,

Thanks for the inputs! I didn't touch C since the end of the University about 4 years ago :slight_smile: I'll try his atoi function for the other strings i'll be searching.

What do you think about the way I'm searching for the strings? Is it eficient enough, or is there an easier, faster, better form of doing it?

Also about the serial ports.. As I believe I said in the begining, I was thinking of using the real serial port to read the output of the system, and a Software serial port to comunicate with the gsm modem.

Also, I found and bought on ebay a Siemens TC65 for about 45? including shipping. Let's see what I can do with it :slight_smile:

What do you think about the way I'm searching for the strings? Is it eficient enough, or is there an easier, faster, better form of doing it?

I'm not such a crack at C myself, but seeing your code I am wondering why you store everything in str. You can also act on each byte you read: if you find a digit then you start/continu building your value, if you find a % you have your value and if you find anything else you reset the value to 0. In pseudo code

value=0
while (byte = Serial.read) {
  if (byte in '0'..'9') {
    value = value*10 + atoi(byte)
  } else {
    if (byte == '%')
      do_something_with(value)
    value=0;
  }
}

Also about the serial ports.. As I believe I said in the begining, I was thinking of using the real serial port to read the output of the system, and a Software serial port to comunicate with the gsm modem.

Ah... missed that bit.

Also, I found and bought on ebay a Siemens TC65 for about 45? including shipping. Let's see what I can do with it Smiley

You're gonna love it and 45? is an absolute bargain. You need a development kit though, be sure to get it with your shipment. Those modems work like a dream, have a usable GPIO interface and I love them. But it isn't Arduino, so in order not to make it OT I'll stop drooling.

OT mode on:
You almost scared me with the sdk :slight_smile: found it here: http://florent.clairambault.fr/tag/cinterion

This is what you are meaning with dev kit?

I am going to continue to scare you because that is not it. The site is refering to the Exchange Suite. That is a tool/driver you need to be able to place software onto the device. But you also need the SMTK (Siemens Mobile ToolKit I assume) which is on a CD. It normally is delivered together with the modem, but seen as this is second hand it might not. If not then PM me.

'First read, then post' is a very good idea... If you read on that interesting blog you found (I didn't know it, but can learn from it), you'll find the download link for the SDK. Sorry if I startled you with the above.

I'm still waiting for the modem.. I've also clened the code a bit, and now it's pretty readable.

I'm now thinking on ways to determine when to send the SMS.

Maybe always when the power fails and when the power returns, and also once a day. Is there any easy way of doing this 'once a day' with millis()?

main:

void loop() {

  while ( Serial.available() && i<lenghtArray ){                     // Check if serial is available, and array still not full
    str[i] = Serial.read();
    i++;
  }

  if(i>=lenghtArray){                                                 // If its full
    findValues();
    printValues();
    i=0;  // start again filling the array from 0
  }

}

find values:

void findValues(){

  float lHeLevelTemp         =  findLheLevel        (lenghtArray, str);
  float avgPwrTemp           =  findAvgPwr          (lenghtArray, str);
  float avgPressTemp         =  findAvgPress        (lenghtArray, str);
  int compressorStatusTemp   =  findCompressorStatus(lenghtArray, str);
  // it only updates the value if it was found
  if (lHeLevelTemp           > -1)   lHeLevel         = lHeLevelTemp;
  if (avgPwrTemp             > -1)   avgPwr           = avgPwrTemp;
  if (avgPressTemp           > -1)   avgPress         = avgPressTemp;
  if (compressorStatusTemp   > -1)   compressorStatus = compressorStatusTemp;

  findDateTime  (lenghtArray, str);                                  // It will write the global variable dateTime   

}

find average power

// returns the 'averaged' power or -1 if no lHe was found

float findAvgPwr ( int lenghtArray, char str[]){
  int found=0;
  float averagePwr1 = 0;  
  float averagePwr = 0;

  for(int a=12; a<lenghtArray; a++){                                                 // go along the array 

    if (str[a]=='W' && str[a-7]=='H' && str[a-8]=='0'&& str[a-9]=='2'&& str[a-10]==';'&& str[a-11]=='1'&& str[a-12]=='2'){               // searching for the string [21;20H10.882W       averagePwr = (((str[a-6]-48)*10) + (str[a-5]-48) + ((str[a-3]-48) * 0.1) + ((str[a-2]-48) * 0.01) + ((str[a-1]-48) * 0.001));      // concatenate
      found += 1;
      if (found > 1) found =2;
      averagePwr1 = (averagePwr + averagePwr1) / found;
    }
  }
  if (found == 0 || averagePwr1 > 100) averagePwr1 = -1;
  return averagePwr1;
}

Is there any easy way of doing this 'once a day' with millis()?

As long as it doesn't matter when during the 24 hour period, you can use millis. There are 86,400,000 milliseconds in a day. Every 59 days, you'll have to deal with millis overflowing an unsigned long, and instead of returning a very large number, it sill return a very small value, while you have stored a very large value (based on the time of the last send).

If you store the time of the next send, instead, the next send time will overflow before the millis return value does, so you'll need to handle that case, instead.

hum...

So, I'll use millis to send an SMS to my Email for the 'routine' messages, so if its in the middle of the night, I dont wake up.

If I have an 'event' it will send an SMS to my mobile, and I dont care if it wakes me up