Go Down

Topic: sms based door lock (Read 1 time) previous topic - next topic

khizon18

Hi.. Recently I am trying to build a secret knock and sms based door lock.. but when I implement the sms the secret knock is not very responsive ? What should I do.. my board is Arduino Duemilanove w/ Atmega328, Icomsat 1.1.

Should I replace Arduino Duemilanove w/ Atmega328 to Arduino Mega2560 Rev3?


The code is attached below...


spatula

Sending (and receiving) sms is slow, and it doesn't depend on the Arduino. But I could not figure out how many messages need to be exchanged for the door to unlock, so it would help if you could summarize the sequence. The code contains many delay()s for the knocks; you can (and should) make yourself a comparison between the results with and without sms. That would help define a clearer target: are you looking for a 100% improvement, or a 30%, or...

khizon18

When the gsm module is off.. It is 100% fast and responsive.. however when it is turns on it remove 50% speed and accuracy.. do you It is fault of gsm ??

spatula


When the gsm module is off.. It is 100% fast and responsive.. however when it is turns on it remove 50% speed and accuracy.. do you It is fault of gsm ??


A reasonable estimate for sending an sms is 10 seconds (average, not maximum). So if a knock-based process takes 10 seconds the same process plus sms takes twice as long. But... a better estimate could be provided knowing how many knocks and sms are involved in the process. Then, speed improvements can be obtained by replacing the delay()s in your code with timer-based events. And finally, if you need to send sms frequently you may save time by keeping the connection to the gsm permanently open.

khizon18

No. If you see my code in the loop I am not sending a message unless otherwise the attempt is equal to 3, I only reply to message when I received it. In the loop I only monitor incoming messages.. and I only monitor attempt then said messages and its part of the process to wait when sending messages.. However the problem is when I insert this code
Code: [Select]
char pos =  sms.IsSMSPresent(SMS_UNREAD);
if (1==pos) {
  sms_detected();
}


If it is the problem what is the solution.. Should I use millis();   ?

spatula


No. If you see my code in the loop I am not sending a message unless otherwise the attempt is equal to 3, I only reply to message when I received it. In the loop I only monitor incoming messages.. and I only monitor attempt then said messages and its part of the process to wait when sending messages.. However the problem is when I insert this code
Code: [Select]
char pos =  sms.IsSMSPresent(SMS_UNREAD);
if (1==pos) {
  sms_detected();
}


If it is the problem what is the solution.. Should I use millis();   ?


sms.IsSMSPresent() is a function outside your code, in a library. I don't know what it does and if you want you can attach this library. I guess however that the function sends a command to the phone, something like AT+CGML="REC UNREAD", which lists the unread messages in the phone's memory. The problem is that it is blocking, it must wait for the modem response, and takes time even if there are no messages. You can measure the time it takes using millis(), this way:

Code: [Select]

loop()
{
  unsigned long elapsed_millis;
  unsigned long start_millis = millis();

  char pos =  sms.IsSMSPresent(SMS_UNREAD);

  elapsed_millis = millis() - start_millis;
  Serial.print("millis spent in sms.IsSMSPresent: ");
  Serial.println(elapsed_millis);
 
...
}


And the problem is that IsSMSPresent is called on each loop(). It is more or less like adding a delay() of a couple of seconds (my guess), but you cannot replace it with some millis-based event because this is time actually spent communicating with the phone. There is no easy solution.

You have some large delay()s in your loop, and instead of doing nothing you could use this time to check for new messages. These delays however only happen when a door is locked or unlocked, so perhaps this is not a valid solution.

Another thing you can do is to perform the check at timed intervals. Suppose you can do with a check every 30 seconds. Then you create a variable which is reset when the check is executed, something like:
Code: [Select]

unsigned long last_check = millis();

loop()
{
  if (millis() - last_check > 30000)
  {
     // do the check
     last_check = millis();
  }
}

Obviously, every 30 seconds you'll have a significant change in performance.

The only alternative I see is changing the library code so that instead of a single blocking function you have different functions that are called during successive repetitions of loop().

khizon18

Quote
The only alternative I see is changing the library code so that instead of a single blocking function you have different functions that are called during successive repetitions of loop().


How could I do this?

spatula

Understand your sms library. Then define one or more states, for example idle, command_sent, response_received. Study how to read from serial without blocking, for example here http://www.gammon.com.au/forum/?id=11425. Then, instead of calling IsSMSPresent,

- start from idle state.
- when in idle state, send the AT+CGML command (or whatever the library sends) and change state to command_sent.
- when in command_sent state, receive the response from the modem in a non-blocking way. The response will be processed during many loop()s and will contain more than one row. Each time you receive a complete row (a '\n' char) you take some action (e.g., update a counter, see what the library does) and clear the receive buffer.
- when you receive the OK ending the response from the modem take some further action, then return to idle state.

This is *not* a trivial modification to the library source code and will require a substantial amount of additional code.

khizon18

Quote
sms.IsSMSPresent() is a function outside your code, in a library. I don't know what it does and if you want you can attach this library. I guess however that the function sends a command to the phone, something like AT+CGML="REC UNREAD", which lists the unread messages in the phone's memory. The problem is that it is blocking, it must wait for the modem response, and takes time even if there are no messages. You can measure the time it takes using millis(), this way:



millis spent in sms.IsSMSPresent: 91
millis spent in sms.IsSMSPresent: 91
millis spent in sms.IsSMSPresent: 91
millis spent in sms.IsSMSPresent: 91
millis spent in sms.IsSMSPresent: 91
millis spent in sms.IsSMSPresent: 90


This is what it show when I test the time millis between

this code

Code: [Select]
unsigned long elapsed_millis;
  unsigned long start_millis = millis();
char pos =  sms.IsSMSPresent(SMS_UNREAD);
if (pos) {
  sms_detected();
}

  elapsed_millis = millis() - start_millis;
  Serial.print("millis spent in sms.IsSMSPresent: ");
  Serial.println(elapsed_millis);
 



khizon18

#10
Mar 18, 2013, 09:39 am Last Edit: Mar 18, 2013, 11:04 am by khizon18 Reason: 1
Quote
Understand your sms library. Then define one or more states, for example idle, command_sent, response_received. Study how to read from serial without blocking, for example here http://www.gammon.com.au/forum/?id=11425. Then, instead of calling IsSMSPresent,

- start from idle state.
- when in idle state, send the AT+CGML command (or whatever the library sends) and change state to command_sent.
- when in command_sent state, receive the response from the modem in a non-blocking way. The response will be processed during many loop()s and will contain more than one row. Each time you receive a complete row (a '\n' char) you take some action (e.g., update a counter, see what the library does) and clear the receive buffer.
- when you receive the OK ending the response from the modem take some further action, then return to idle state.

This is *not* a trivial modification to the library source code and will require a substantial amount of additional code.




I don't know how to do it.. I don't understand AT-COMMANDS .. I would be grateful if someone will do it for me T_T

khizon18

unsigned long last_check = millis();

loop()
{
  if (millis() - last_check > 30000)
  {
     // do the check
     last_check = millis();
  }
}

This code actually help me... but instead of 30000 millis interval I rather prefer 1000 which is give exactly what I want..
The logic you gave me is what I really need. If I'll have a problem regarding to this matter.. I'll post it. Thank you Monsieur


spatula

Glad to know. Actually 91 ms is a lot better than I thought, so I'm not surprised that you can get good results with a much smaller interval.
Good luck!

Go Up