Control relay with sms and turn on for 5 minutes

Hi, I have a problem understanding how to use millis(). May home automation project is that when the sim800L receive a "ON" message it will turn on the relay for 5 minutes. and it will turn off after 5 minutes. Thank you in advance. :slight_smile:

Here's the code I found in the internet without turn on the relay for 5 minutes

#include <Sim800l.h>
#include <SoftwareSerial.h>

// Configure software serial port
SoftwareSerial Sim800l(4, 5);

// Variable to store text message
char incomingMessage;
String textMessage;

// Relay connected to pin 7
const int relay = 7;



void setup() {

  pinMode(relay, OUTPUT); // Set relay as OUTPUT
  digitalWrite(relay, HIGH); // By default the relay is off  // HIGH is OFF // LOW is ON
  // Initializing serial commmunication
  Serial.begin(9600);
  Sim800l.begin(9600);


  while (!Sim800l.available()) {
    Sim800l.println("AT");
    delay(1000);
    Serial.println("Connecting...");
  }
  Serial.println("Connected!");
  Sim800l.println("AT+CMGF=1");  //Set SMS to Text Mode
  delay(1000);
  Sim800l.println("AT+CNMI=1,2,0,0,0");  //Procedure to handle newly arrived messages(command name in text: new message indications to TE)
  delay(1000);
  Sim800l.println("AT+CMGL=\"REC UNREAD\""); // Read Unread Messages
}

void loop() {


  if (Sim800l.available()) {
    delay(100);

    // Serial Buffer
    while (Sim800l.available()) {
      incomingMessage = Sim800l.read();
      textMessage += incomingMessage;
    }

    delay(10);

    Serial.println(textMessage);
    textMessage.toUpperCase(); // Uppercase the Received Message

    //turn RELAY ON or OFF
    if (textMessage.indexOf("ON") > -1) {
      digitalWrite(relay, LOW);
      
    }

    //for test only
    if (textMessage.indexOf("OFF") > -1) {
      digitalWrite(relay, HIGH);
    } //test end

    delay(50);

    //Delete Messages & Save Memory
    if (textMessage.indexOf("OK") == -1) {
      Sim800l.println("AT+CMGDA=\"DEL ALL\"");

      delay(1000);
    }

    textMessage = "";
  }
}

Have you tried to compile that code?
You're missing the closing brace on your loop.
previousMillis is never declared.
You are using String which should be avoided, better to use a char array.
You have no 5 minute timing loop after turning the relay "ON", only a test for "OFF".
The instances of delay() have no apparent use.

char incomingByte;

Why are you using a type (byte) in the name of a variable, when the type in the name is not the type OF the variable?

You wouldn't create a variable, of type int, named incomingFloat would you?

I am not going to fix all your code, but I will address your actual question about millis() and delay(). Delay is "ok" if your sketch proceeds from a to b to c to d etc., for example, listen to serial Rx and send what is received on the serial Tx. I have used delay() in my setup() as a simple method to wait for other parts of my circuit to stabilize before running the loop() of my program. However, for programs that handle multiple inputs, some push-buttons, serial, softwareSerial, SPI, I2C etc. You want to create branches, a() for serial, b() for SPI etc., and you want to run those branches almost simultaneously. To do this, you never stay in one place very long. This is done by setting a flag:

if (conditionMet == true) conditionFlag = true;

then taking that condition as a conditional elsewhere where needed in your respective branch or branches, and clearing the flag once you've taken appropriate action.
With respect to "time" and millis(), your condition is "after 5 minutes" so, when you turn on the relay:

digitalWrite(relayPin, HIGH);

you want to set a global variable that saves the current value of millis(), which is an unsigned long:

myUnsignedLongTimestamp = millis();

Then in one of your branches of code, where appropriate, or it's own branch if necessary, you want to compare the current value of millis() to your time stamp from before:

if (millis() - myUnsignedLongTimestamp >= 300000UL) {// 300000UL is 5 minutes in milliseconds
     digitalWrite(relayPin, LOW);
     }

This always works because with unsigned variables, there is no meridian on the number line. Even if millis() had rolled over to 0, 0 - 4291967295 is still greater than or equal to 3000000.

Thank you for all the replies. But I really don't get it. I'm sorry.

What is it that you don't get? Anything specific or all of it?

Hi DKWatson,

You are using String which should be avoided, better to use a char array.

What do mean by this? I change the String to char and this line of code is error

textMessage.toUpperCase(); // Uppercase the Received Message

You have no 5 minute timing loop after turning the relay "ON", only a test for "OFF".
The instances of delay() have no apparent use.

I don't have a code for 5 minutes delay. So the ON and OFF code is for test only if I can control the relay via sms.

Thank you.

Additional question.

If I use delay() for may relay to stay on for 5 minutes. And I have a DS1307 TinyRTC I2c Module for sending a sms (reminder) to turn on the relay at a specific time (eg. 6AM everyday) the delay() will also delay the time of RTC?

I'm struggling to understand the millis() so I think I will use the delay(). But I'm wondering if the delay() will stop the RTC time also?

Thank you

If you use a RTC you are, sorry, a bit stupid using delay(), because that function is relative to the internal timer, that is not as good as a RTC. If you are using a RTC you have to learn how to use it and use it every time

Hi Silente,

Yeah, I know. Thanks btw. :slight_smile:

Same as millis()?

Yes. If you have an extwrnal RTC is because you want precision, millis() isn't precise (not as precise as a RTC). The only thing is (I think) that RTCs mesure only seconds, millis is smaller

You remind me of my first efforts with sim800l. Let me tell you some tips

  1. If you use a 3.3V Arduino then go to paragraph 2. Else you MUST verify that there is a level shifter on module. Some modules have just the sim800 like this:

These modules NEED external - additional level shifter, even if seller says they don;t. If not use a shifter they will burned by 5V arduino port. Look in datasheet and application handbook of simm800l

  1. In order to check for "ON", better you send also a code in front, for example "2314ON". That because a sms may contain a ON (for example :default data by provider : "..you dON;t have extra free sms in your account...") or a friend of yours may send an "ON" sms just for joke. In all above cases you get a false relay activation.

  2. First try to send a "no cost" sms to provider for example ask for remain money. Then try to get and verify the sms sent by provider. Depending on country and provider the received sms may not be clear-readable (for example there might be data between each character , so ON appears as "%345%344". In this case you must do a processing to convert (in example, 345=O, 344=N)

good luck

textMessage.toUpperCase();
That is a String class method. When you use char arrays there are library functions to perform most of those actions. For example, the function to convert a char array to uppercase is strupr(), so textMessage.toUpperCase(); becomes strupr(textMessage);

I've attached the latest copy of the AVR C library manual just in case you've misplaced yours.

avr-libc-user-manual-2.0.0.pdf (1.6 MB)

DKWatson:
textMessage.toUpperCase();
That is a String class method. When you use char arrays there are library functions to perform most of those actions. For example, the function to convert a char array to uppercase is strupr(), so textMessage.toUpperCase(); becomes strupr(textMessage);

I've attached the latest copy of the AVR C library manual just in case you've misplaced yours.

Thanks DKWatson. I'm just wondering, the tutorials or codes that I saw they use String for that particular line of code. But you said that String must be avoided.

demkat1:
2. In order to check for "ON", better you send also a code in front, for example "2314ON". That because a sms may contain a ON (for example :default data by provider : "..you dON;t have extra free sms in your account...") or a friend of yours may send an "ON" sms just for joke. In all above cases you get a false relay activation.

Thanks for this. I try to send "NONE" and it turn on the relay.

for your project (use of 2-3 Strings) and ~50 variables, inmy oppinion, you will not have problems with Stings. The probles come if you use more Strings. There is an effort NOT to use Strings but the limits use/no use are not black/white.

if (finally) you use Strings as in demos, this statement

String textMessage;

is better to be written as

//about 100 character String
String textMessage="         1         2         3         4         5         6         7         8         9         0";

// and then , in setup
textMessage="";

This way you have less possibilities of "problems" with this String

Try these for ideas -

SEPARATE YOUR PROBLEMS

GETTING STARTED

HOW TO BUILD UP A LARGER PROGRAM FROM BITS

TOP FIFTEEN MISTAKES

EVERYTHING IS A FUNCTION

I didn't say String MUST be avoided, I said SHOULD. String can cause problems in a resource restricted environment (like Arduino or any other small micro-controller) that you have no control over, unless you want to devote many more resources to the code necessary for memory management. A lose-lose situation.

I agree with the "should" . But there is a conflict in my mind:

If I google search "String arduino" I go to reference and from there I can find all the supporting operations (substring, indexOf, length...). On post #12 above you say

For example, the function to convert a char array to uppercase is strupr(), so textMessage.toUpperCase(); becomes strupr(textMessage);

ok, you know it, now (after about 4 years of using arduino) I know it too. But,

  1. how a "newcomer" can find these functions if they are not in reference (ie char array)? He is leaded to the String() , he uses Strings

  2. Why there is a SerialRead example with String and NOT with char array? The OP is using a typical Serial Read following a typical example.

demkat1:
2. Why there is a SerialRead example with String and NOT with char array? The OP is using a typical Serial Read following a typical example.

Totally understand. Doesn't mean I can answer the question though. I can appreciate the developers of the IDE using existing class libraries, already proven effective. For the extreme neophyte, and in the original intent of the Arduino, the environment was safe enough. In it's decade plus of existence however, the ecosystem has changed radically. The Arduino (and it's derivatives) is being used in ways that are far beyond I'm sure, the imagination of the founders. The IDE works, so why change it. It works well within the context of the original thinkers. As the user becomes more sophisticated, and without proper training, they will test the limits of the environment. And this is good. I believe that the responsibility of those of us who have chosen to be mouthpieces in the forum, is to fill in those training gaps, not by spoon-feeding coded solutions, but in trying to lead the learner towards an understanding of the limits and ways to work around.
I coded my first microprocessor 46 years ago. The instruction sets have not changed in all that time. The use of high level languages has made these devices more accessible, but the underlying principals are still the same. What has changed is the need, more significantly the lack of need, to understand what happens when you strip away all the abstractions. I'm happier that a pig in... mud to see young and old alike getting back in touch with the fundamentals. As your understanding of the lower levels of processing increase, I believe your abilities with the higher levels increase even more. It may be that introducing Arduino with class-based libraries and a C++ like environment was the perfect compromise. I do feel though, that we've evolved beyond that. High level languages are meant to be safe. C++ gives you enough capability to shoot yourself in the foot. C gives you the tools to blow your whole leg off. You sure you want to teach that without a solid grounding in the fundamentals?
I believe the IDE is properly positioned, as an entry point. As the user evolves, so must his/her exposure to the environment, carefully. There are many things yet to discover and I feel the onus is on the senior members of the forum to do so in a prescribed, if not always genteel, fashion. Remember that the posts are read by more than a few and not everyone is at the same level. What advice I (or others) may give to one, could have serious negative effects for another. Recently I held off answering a question as to how multiple pins on different ports could be updated simultaneously. Can you imagine the havoc that would wreck for someone just visiting? Trying something they didn't fully understand, and then trying to debug it? It's difficult to decide how much, or how little to say without destroying the whole experience for everybody. I doubt there are any in the 'senior' class that would disagree. When the questions get more demanding, the answers will too. In the meantime, feel free to be critical. I'm an engineer, not a teacher. I don't know how effective my methods are, only you can tell me that. I try the best I can to lead the poster towards a solution I feel he/she is comfortable with. My choice also to be here.