Sending Text/SMS with Electron

Does anyone have example code to send text messages with the electron? I am using my own sim that supports text messages and not Particle’s sim.

I found this code but it gave me this error.

Code

    #define MAX_PHONE_NUMBER    14
#define CTRL_Z 0x1A
#define TIMEOUT 10000

unsigned char id;
boolean gain;     // Gain setting, 0 = X1, 1 = X16;
unsigned int ms;  // Integration ("shutter") time in milliseconds
unsigned int data1;
unsigned int data2;
char szPhoneNumber[MAX_PHONE_NUMBER] = "+18005551212";

int lowerLimit = 10;
boolean smsSend = false;

int callback(int type, const char* buf, int len, char* param){  
    Serial.print("Return: ");
    Serial.write((const uint8_t*)buf, len);
    Serial.println();
    
    return WAIT;
}

int setLowerLimit(String args){
    lowerLimit = args.toInt();
    
    return lowerLimit;
}

int sendMessage(char* pMessage){
    char szCmd[64];
    
    sprintf(szCmd, "AT+CMGS=\"+%s\",145\r\n", szPhoneNumber);
    
    Serial.print("Sending command ");
    Serial.print(szCmd);
    Serial.println();
    
    char szReturn[32] = "";
    
    Cellular.command(callback, szReturn, TIMEOUT, "AT+CMGF=1\r\n");
    Cellular.command(callback, szReturn, TIMEOUT, szCmd);
    Cellular.command(callback, szReturn, TIMEOUT, pMessage);
    
    sprintf(szCmd, "%c", CTRL_Z);
    
    int retVal = Cellular.command(callback, szReturn, TIMEOUT, szCmd);
    
    if(RESP_OK == retVal){
        Serial.println("+OK, Message Send");
    }
    else{
        Serial.println("+ERROR, error sending message");
    }
    
    return retVal;
}

void setup() {
    Serial.begin(115200);
    Spark.function("setmin", setLowerLimit);
}

void loop() {

    Serial.println();
    Serial.println();
    
    char szMessage[64];
	
	szMessage = "Particle Electron Test Message!";
	
	sendMessage(szMessage);
    
    delay(1000);
}

Error

test.cpp: In function 'void setup()':
test.cpp:60:5: warning: 'Spark' is deprecated (declared at ../wiring/inc/spark_wiring_cloud.h:271): Spark is now Particle. [-Wdeprecated-declarations]
         Serial.println("+ERROR, error sending message");
     ^
test.cpp: In function 'void loop()':

	

	
		
			
			test.cpp:70:12: error: incompatible types in assignment of 'const char [32]' to 'char [64]'
 
            ^
		
	

	
		make[1]: *** [../build/target/user/platform-10test.o] Error 1
make: *** [user] Error 2

Btw if the code did work, it be sms bombing the addressee.

It’s my phone and I have unlimited texting. The phone number in the code is not mine.

Hey @Greg123 - @bdub is the one who has the most info about SMS handling.

Where did you find that code?

You'd rather need to do this

  strcpy(szMessage, "Particle Electron Test Message!")

szMessage is a character array and with your assignment you'd try to alter its location (which is not allowed), but won't copy the contents of the string literal into the array.

You forgot the semicolon at the end.

Hmm!

If I only show the command and not the code line that’d not be an issue :wink:

I could’ve writen

  if(strlen(strcpy(szMessage, "Particle Electron Test Message!")) > 10)
  {
    // do whatever
  }

the command would still be the same, but an extra semi-colon would have been wrong there :sunglasses:

1 Like

Ok! Thanks!

I'll drop some code in here... we can do better in the future but for right now it's what I have :smile: and it works well!

Here's a polled SMS app that also has a smsSend() function. Read the Info.md file for how to interact with it. Make sure you set the APN credentials correctly at the top. This method has always been available.
SMS Test App (with Tinker) · GitHub

And here's an implementation of SMS reading that is done asynchronously (not polling). When a new message is received, the handler is called with the index of the sms message. This handler needs to be treated as if it's an interrupt service routine (get in out, and let your main loop process the update). This method is available in 0.5.1 system firmware. You can grab the smsSend() function from the previous GIST example to add to this one.

Keep in mind this async method is currently unfinished, and uses the cellular_hal directly for now. In the future it will be available from the Wiring Cellular API.

Hope that helps! :smile:

5 Likes

So like this

char szMessage[64];

if(strlen(strcpy(szMessage, "Particle Electron Test Message!")) > 10)
{

sendMessage(szMessage);

delay(1000);

}

@BDub Thanks for this example code.

I have a couple quick questions about these examples.

  1. Using this code to send SMS messages requires a 3rd party non Particle SIM card right?

  2. Do you have any idea how much data is consumed with the 1 second SMS message polling used in the first Github link: https://gist.github.com/technobly/fb164a7012c64eed7a775f4f7ba91662

That would work too, but was merely meant as an example how to use a command without the missing semicolon you complained about.
But you can use that same command as a single instruction when you add the semicolon.

I ran this code but it gave me this error

#define MAX_PHONE_NUMBER    14
#define CTRL_Z 0x1A
#define TIMEOUT 10000

unsigned char id;
boolean gain;     // Gain setting, 0 = X1, 1 = X16;
unsigned int ms;  // Integration ("shutter") time in milliseconds
unsigned int data1;
unsigned int data2;
char szPhoneNumber[MAX_PHONE_NUMBER] = "+18005551212";

int lowerLimit = 10;
boolean smsSend = false;

int callback(int type, const char* buf, int len, char* param){  
    Serial.print("Return: ");
    Serial.write((const uint8_t*)buf, len);
    Serial.println();
    
    return WAIT;
}

int setLowerLimit(String args){
    lowerLimit = args.toInt();
    
    return lowerLimit;
}

int sendMessage(char* pMessage){
    char szCmd[64];
    
    sprintf(szCmd, "AT+CMGS=\"+%s\",145\r\n", szPhoneNumber);
    
    Serial.print("Sending command ");
    Serial.print(szCmd);
    Serial.println();
    
    char szReturn[32] = "";
    
    Cellular.command(callback, szReturn, TIMEOUT, "AT+CMGF=1\r\n");
    Cellular.command(callback, szReturn, TIMEOUT, szCmd);
    Cellular.command(callback, szReturn, TIMEOUT, pMessage);
    
    sprintf(szCmd, "%c", CTRL_Z);
    
    int retVal = Cellular.command(callback, szReturn, TIMEOUT, szCmd);
    
    if(RESP_OK == retVal){
        Serial.println("+OK, Message Send");
    }
    else{
        Serial.println("+ERROR, error sending message");
    }
    
    return retVal;
}

void setup() {
    Serial.begin(115200);
    Spark.function("setmin", setLowerLimit);
}

void loop() {

    Serial.println();
    Serial.println();
    
    char szMessage[64];
    
    if(strlen(strcpy(szMessage, "Particle Electron Test Message!")) > 10)
    {
    
    sendMessage(szMessage);
    
    delay(1000);
}

ERROR

test.cpp: In function 'void setup()':
test.cpp:60:5: warning: 'Spark' is deprecated (declared at ../wiring/inc/spark_wiring_cloud.h:271): Spark is now Particle. [-Wdeprecated-declarations]
         Serial.println("+ERROR, error sending message");
test.cpp: In function 'void loop()':
			test.cpp:76:1: error: expected '}' at end of input
     char szMessage[64];
 		make[1]: *** [../build/target/user/platform-10test.o] Error 1
make: *** [user] Error 2

Just count your opening and closing curly braces - they have to match

Yep, 3rd party.

There is no data consumed to just poll for URCs (unsolicited response codes). I don't believe there would be any data consumed for receiving/sending an SMS on your 3rd party SIM either. It would just take away from the SMS's you have available. The one I've been testing with is unlimited as well.

1 Like

@BDub Thank you very much for the clarification.

Do you have any idea on when this code will be combined into an official library or is this just a side project for now?

I know we can merge @krvarma 's code that he has working for waking up a sleeping SMT32 using a interrupt supplied by the UBlox modem when it receives a text message. Here is his code for having a incoming SMS message trigger the RI pin on the uBlox that is connect to the SMT32.

Interesting to see you guys digging in! I had done some work to verify the RI_UC pin behavior a while back:
https://github.com/spark/firmware/tree/archive/feature/electron-ri-urc

I found that the RI_UC pin was kind of slow and did not always corresponds one to one to all URCs that were happening. For that reason it might be great for simple tasks like waking up a sleeping electron, but I think actually looking for the SMS received URC and calling a registered callback is much more accurate (as implemented in 0.5.1).

I haven’t thought of what the API for SMS should be just yet but it seems to gaining traction :slight_smile: Would love any thoughts there for what is needed. At a high level we need:

Cellular.smsList()
Cellular.smsSend()
Cellular.smsDelete()
Cellular.smsRead()
Cellular.smsOnReceive() // register callback for new SMS messages
3 Likes

@BDub So from your point of view what is the lower power consumption way to put the Electron to sleep yet still check for SMS messages every 1-10 mins to trigger a wake up?

The cell network will hold the SMS message in queue if the uBlox modem is off or disconnected from the network so when the Electron does reconnect to the network the SMS message will be received right?

I’m wondering how to go about this without having to do the cellular tower handshake every time the Electron reconnects. I know you say the URC’s polling does not require any data usage so that’s good but what about the progress with getting the handshaking data consumption down?

Would this work around the need for a webhook to a 3rd party api like twilio?