Mass SMS sending

Hello guys! I'm developing a desktop application that is sending SMS messages to many people at once(over 1000 and more). Since I am new to Arduino coding, I could need some help. I used the default code for sending SMS messages, of which I deleted code I don't need. So what was left is this:

void loop() {

  char remoteNum[30]; 
  readSerial(remoteNum);

  char txtMsg[500];
  readSerial(txtMsg);

sms.beginSMS(remoteNum);
  sms.print(txtMsg);
  sms.endSMS();
  
}

And this:

void loop() {

  char remoteNum[30];  // telephone number to send sms  
  readSerial(remoteNum);

  char txtMsg[500];
  readSerial(txtMsg);

sms.beginSMS(remoteNum);
  sms.print(txtMsg);
  sms.endSMS();
  
}

As far as I understand, Arduino comunicates with ports, so I created a serial port in my C# code, which loopes trough all contacts that are going to receive a SMS.
This code looks like this:

try
            {
                port.BaudRate = 9600;
                port.PortName = "COM13";
                port.Open();
            }
            catch {return; }
            foreach (person in list)
            {
                string smsText = new TextRange(smsText_rtb.Document.ContentStart, smsText_rtb.Document.ContentEnd).Text;
                
                port.WriteLine(phoneNbr);
              
                port.WriteLine(smsText);

It seemed easy enough for me but since it doesn't work well, I am looking for an explaination for that. The thing is, that when I send 5 messages at once, sometimes only one is sent, sometimes more and many time none. I have no clue why the code is bhaving that way.
What I am trying to do is that the arduino code first accepts all numbers and then sends them once they are all received. Or is there a better solution to this? Thanks for your help, guys!

Since you posted only part of your code, I'll post only part if the answer.

What you need to do is change line

Hope that's enough...

PaulS:
Since you posted only part of your code, I'll post only part if the answer.

The part left out is the list of spam SMS messages the op want to bombard people with :smiling_imp:

Riva:
The part left out is the list of spam SMS messages the op want to bombard people with :smiling_imp:

Actually, the part left out is how the Arduino reads the serial data.

The problem is likely that the C# app spams the Arduino with data faster than it can read it and send the message.

Hand-shaking is likely to solve the problem.

PaulS:
The problem is likely that the C# app spams the Arduino with data faster than it can read it and send the message.

If the object is to send spam then the whole thing works better when submersed in a bucket of water as this fixes the handshake problem. :wink:

Riva:
If the object is to send spam then the whole thing works better when submersed in a bucket of water as this fixes the handshake problem. :wink:

Now, now. There may be a good reason for wanting to send the same message to multiple people. For instance, my company has a process for sending text message,s to people that sign up for them, in the event of site closures due to inclement weather. It's unlikely that they use an Arduino to send the messages, but a company on a shoe-string budget might.

One modem can only do one thing at a time - significantly slower than the host or Arduino can deliver them.

In your Arduino - there are THREE steps to sending a single SMS.

  • Check the modem is not busy - then initiate (+CMGS) with the recipient number
  • Send the message body followed by CTL-Z
  • Wait for the ERROR/CMGS OK confirmation

This sequence can take several seconds per message.

Trick #1
Write your sending code as a state-machine, so the rest of the code wrapped around it can keep doing things - like buffering future send requests.

Trick #2
Have some handshaking, or a large enough buffer in the SMS controller (Arduino) to store incoming messages before they're sent. Keep in mind the possibility of failed messages and retries.

Trick #3
Subscribe to an SMS service that offers bulk messaging capability. This may be cheaper per message sent.

I do #1 and #2 on Arduino - and send a new message every second or so.
The queue is currently set for 20 separate 140 char messages, but that could easily be massaged to any number of messages to any number of recipients that will fit in RAM

Hello and thanks for your replies!
As you found out, the service will be used for sending notifications to customers, debtors and so on... I really like the idea with some handshaking. Would it be possible to send all numbers to the device first and then sending the message to all of them? I didn't test how much memory the device has, can it handle tousands of numbers at once?
The good thing is that Arduino programming language is similar to C# :smiley:

I'm open for more suggestions and thanks for your help!

I didn't test how much memory the device has

You need to.

Would it be possible to send all numbers to the device first and then sending the message to all of them?

It would make more sense to send the message first, and then the numbers, as the Arduino/Whatever acknowledges that it is ready for more.

The good thing is that Arduino programming language is similar to C#

In that they involve the same letter, yeah. C++ requires you to engage your brain a lot more. It does not handle memory leaks for you, like some other #$^*%#% programming language.

Good thing that there is not only C++. I wrote a simple script in hope that it'll work but it doesn't.

What I did is that the program first sends the message and the count of how many it'll be delivered to.
The following loop iterater for every number and is suppost to send the message with no success. What am I missing?

#include <GSM.h>
#define pinNumber ""

GSM gsm;
GSM_SMS sms;

int phoneCount;

void setup(){
  Serial.begin(9600);
 while (!Serial) {}
boolean notConnected = true;

while(notConnected)
{
if(gsm.begin(pinNumber) == GSM_READY)
{
 notConnected = false; 
}
else{delay(1000);}
}

Serial.println("connected");  

}
void loop(){


char tempCount[10];
char msg[200];

readSerial(tempCount);
readSerial(msg);

phoneCount = atoi(tempCount);


for(int i = 0; i< phoneCount; i++){

char nbr[20];
readSerial(nbr);

sms.beginSMS(nbr);
sms.print(msg);
sms.endSMS();
}

}
int readSerial(char result[]) {
  int i = 0;
  while (1) {
    while (Serial.available() > 0) {
      char inChar = Serial.read();
      if (inChar == '\n') {
        result[i] = '\0';
        Serial.flush();
        return 0;
      }
      if (inChar != '\r') {
        result[i] = inChar;
        i++;
      }
    }
  }
}

What I did is that the program first sends the message and the count of how many it'll be delivered to.

In that order? That is not the order that you are reading the data.

        Serial.flush();

You don't have a clue what this does, do you? If you did, you would not be calling it.

Your readSerial() method needs to be told how many characters the array can hold, and must NOT write more characters into the array than that.

It IS possible to use the serial port in two directions. You could send data to the C# app, and you could make the C# app read and display what it reads from the serial port.

Honestly, I took readSerial from the already written code(Send sms) by Arduino and modified it.

I already succeeded in sending messages via port in both ways. I wrote a onReceive even method, that reads received data. But yeah, like I said Im new to Arduino and port stuff, so I have lots to learn.

Instead of readSerial, could I simply use the Serial.read() method to read incoming data?
Anyways, Im gonna do some study work to see how this works and will try to make it work today.

Edit: I did some more coding which didn't work aswell.
I first stored the numbers via for loop, which worked.

I sent the data back to my program which recieved it(though not in the same way as sent.

Example: I sent 2 numbers -> "123456789", "987654321"

and recieved-> " ", "123456789", "\n", "987654321", "\n\r"

Not sure how this can even be...

As for the actual sms code: should I use the gsm/sms library or should I try it with AT commands?

My current code:

#include <GSM.h>
#define pinNumber ""

GSM gsm;
GSM_SMS sms;


int phoneCount;

void setup(){
  Serial.begin(9600);
 while (!Serial) {}
boolean notConnected = true;

while(notConnected)
{
if(gsm.begin(pinNumber) == GSM_READY)
{
 notConnected = false; 
}
else{delay(1000);}
}

Serial.println("connected");  

}

void loop(){

char tempCount[10];
char msg[200];

readSerial(tempCount);
readSerial(msg);

phoneCount = atoi(tempCount);

char phoneNumbers[20][phoneCount];

for(int i = 0; i< phoneCount; i++){

readSerial(phoneNumbers[i]);

}

for(int i = 0; i< phoneCount; i++){
sms.beginSMS(phoneNumbers[i]);
sms.print(msg);
sms.endSMS();

}

}

int readSerial(char result[20]) {
  int i = 0;
  while (1) {
    while (Serial.available() > 0) {
      char inChar = Serial.read();
      if (inChar == '\n') {
        result[i] = '\0';
        Serial.flush();
        return 0;
      }
      if (inChar != '\r') {
        result[i] = inChar;
        i++;
      }
    }
  }
}

As it was told by PaulS before, the readSerial method is probably not correct. But since I just reused it from the default SMS sender, I don't know how to modify it.

I don't know how to modify it.

If you can't figure out how to add another argument to the function, that defines the size of the array, then this project is beyond your abilities at this point.

Have the C# app send the message to the Arduino. Have the Arduino read the message and then send a message to the serial port that says "Ready for next number".

When the C# app gets this message, it should send ONE phone number. The Arduino should read the ONE phone number, send the text message, and send a message to the serial port that says "Ready for next number".

When the C# app has no more numbers, it should send "00000000000", which the Arduino should interpret as a clue to go back to the start of loop, where it will spin waiting for another message.

I had the exact same idea in mind at the begining, but I was afraid that it would take much longer. I'll try this concept tomorrow and keep you posted. Thanks

One more question: Is there a way to read variables at runtime via Arduino app? Other than writing serial.writeln I mean. Would be useful for testing data received from C#.

First a bit of complaining. Why do you make yourself blind in your C# code?

try
{
    port.BaudRate = 9600;
    port.PortName = "COM13";
    port.Open();
}
catch {return; }

You will not even be informed that something goes wrong. Result: "Help, it does not work and I don't know why".

And to the basic problem
You need to define a protocol. It was mentioned above.

Send SMS message from PC to Arduino
2)
Let Arduino respond with e.g. OK and number of bytes received. That way the C# application knows that everything was OK or if the number of bytes reported was less than the number of bytes send, the PC can send the same message again.

Now send the number
4)
Once Arduino has sent the message to GSM module, Arduino sends reply back to PC. That reply can be OK but it can also be e.g. ERR if something went wrong during the sending. That ERR message can contain additional information about the error (no network, network busy, whatever ....). Depending on the status, the C# application can decide if it want to retry or leave a retry for later.

Go back to 3) to send next number to Arduino.

It can be more detailed but this shows the principle.

Hello guys, sorry for the delayed post. I managed to make it work with this code:

#include <GSM.h>
#define pinNumber ""

GSM gsm;
GSM_SMS sms;

char msg[160];
char nbr[20];


void setup(){
  Serial.begin(9600);
 while (!Serial) {}
boolean notConnected = true;

while(notConnected)
{
if(gsm.begin(pinNumber) == GSM_READY)
{
 notConnected = false; 
}
else{delay(1000);}
}

Serial.println("connected");  

}

void loop(){
int count;
char counts[10];
readSerial(msg);
readSerial(counts);

Serial.println("ok");

//while(true){
count = atoi(counts);

for(int i = 0; i < count; i++){
//if(nbr == "000"){break;}

readSerial(nbr);
sms.beginSMS(nbr);
sms.print(msg);
sms.endSMS();
Serial.println("ok");

  
}

}

So now arduino first gets the number of sms, that are going to be sent. I wanted to make it with a while loop, but for some reason it didn't break when "done" was received. This however works nicely. It is quiet fast aswell, sending 1,5-2 sms per second.
I am also going to add a sms receive feature, which will allow recipients to unsubscribe(in other words deleting it's contact from the list). Will keep you posted and thank you for your time!

So now arduino first gets the number of sms, that are going to be sent. I wanted to make it with a while loop, but for some reason it didn't break when "done" was received.

If you send (unnecessarily) the number of phone numbers (not SMSs), a while loop is inappropriate. A for loop is appropriate.

If the nbr array contains "Done",

   if(strcmp(nbr, "Done") == 0)
   {
      break;
   }

would break out of the while loop.

The address of the array will never equal "000" (or "Done").

I did use a for loop, the while loop is commented out :slight_smile:
Thanks for your provided solution for the while loop.

I'd use it like this:

while(strcmp(nbr, "done") != 0){

//doStuff

readSerial();
}

This should save me an if statement.

Now I need to add a read sms feature, that allows recipients to unsubscribe, in other words deleting them from the program's list.

How could I simultaneously read incoming SMS and send sms when instructed from C#? I'll try out some ideas, hopefully one will work. Best thanks!

Your SIM card is likely going to be black listed by your operator for sending too many SMS at fast pace which usually breaks the fair use policy attached to your contract.

Why don't you send directly from the PC using your operator SMS IP bridge? Most of them have one those days...

There are some business packs which allow sending comercial/notification SMS, so this is no problem.

I could send them from PC, but the project is going to extend further, with usage of the same arduino device, so thats the reason why we're using the current method.