Send SMS with USB GSM modem when alarm triggered

Keep in mind that the SIM800 chip can only handle GSM / 2G networks, so make sure that such a network is available in your area and that your SIM card and service plan supports it. Sadly a lot of countries and operators have opted to close down GSM service over the last years. If you are certain to have such service available in your area, plug the SIM card into your phone and force it into GSM / 2G mode. Make a call using the 2G network. Then put the card back into the modem and see if it registers.

In my testing the sim800c chip requires to specify the baud speed

If he can issue AT commands and gets responses that aren’t gibberish (like the reponse to AT+CREG he mentioned), then the baud rate is correct at least on the OS and modem level. But maybe the SMS integration requires explicit baud rate config, I don’t know, I don’t use this integration.

I’m not using Gammu or anything like that either. If all you want is to send SMS (not receive) then this whole stuff is overkill. I just wrote a quick and dirty executable that will directly communicate with the SIM800 chip and send any text you supply as arguments to the shell command as an SMS to a predefined number. This can then be integrated into HA as a shell command. I can post the source if there’s interest, it’s really not very complicated.

Yeah I have done that, I’m able to send a sms on my phone on 2g.
So it’s very strange that the sim800 module can’t connect to the network.

Also it spits out a lof of response when executing a simple AT command.

Indeed my response isn’t gibbisch, I see the OK response and so on but it does it like 300 times for 1 command.

HeylmAlex would you want to share your script because I only want to send SMS for now.
It’s just that I want to use this for my home security system when notifications are down due internet loss or power loss (server is on a backup battery).

It’s really quick and dirty, but it works. Open the following code in a text editor, edit the lines with the ‘define’ to match your serial device and the phone number you want to send your sms to (in full format, including the + and country code). Then save it as a file called send_sms.cpp

// --------------------------------------------------------------------------------
// Send SMS V0.1
// --------------------------------------------------------------------------------

#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/times.h>
#include <fcntl.h>
#include <termios.h> 
#include <string>
#include <bits/stdc++.h>
#include <algorithm>
#include <sys/file.h>


// --------------------------------------------------------------------------------
// Configuration
// --------------------------------------------------------------------------------

#define SIM800_DEVICE		"/dev/ttyUSB0"
#define DESTINATION_NBR		"+33673xxxxxx"


// --------------------------------------------------------------------------------
// Generic monotonic system clock, second granularity
// --------------------------------------------------------------------------------

unsigned long long GetClock(void)
{
	static struct timespec ts;
	clock_gettime(CLOCK_MONOTONIC, &ts);
	return( ts.tv_sec );
}


// --------------------------------------------------------------------------------
// Wait for SIM800 to reply to a command, timeout after 60 seconds
// --------------------------------------------------------------------------------

bool WaitForReply(int sfd, std::string *out = nullptr)
{
	const unsigned long long timeout = 60;
	
	char Buffer[201] = { 0 };
	int p = 0;
	
	unsigned long long t = GetClock();
	
	int result = 0;
	
	while( !result ) {
		char c;
		int count = read(sfd, &c, 1);
		if( count ) {
			if( c != '\r' ) {
				Buffer[p++] = c;
				Buffer[p] = 0;
				if( strstr(Buffer, "OK\n") ) result = 1;
				if( strstr(Buffer, "ERROR\n") ) result = 2;
				if( p == 200 ) result = 2;
			}
			t = GetClock();
		}
		if( GetClock() - t > timeout ) result = 2;
	}
	
	if( out ) *out = Buffer;
	
	return( result == 1 );
}


// --------------------------------------------------------------------------------
// Reply parsing
// --------------------------------------------------------------------------------

std::vector<std::string> ParseReply(const std::string &s)
{
	std::stringstream ss(s);
	std::string part;
	std::vector<std::string> out;
	while( std::getline(ss, part, '\n') ) out.push_back(part);
	return( out );
}

std::string SearchReplyLine(const char *token, const std::vector<std::string> &out)
{
	for( auto &i : out ) {
		if( strstr(i.c_str(), token) ) return( i );
	}
	return( "" );
}


// --------------------------------------------------------------------------------
// Flush the UART read cache
// --------------------------------------------------------------------------------

void FlushAll(int sfd)
{
	while( 1 ) {
		char c;
		int count = read(sfd, &c, 1);
		if( !count ) break;
	}
}


// --------------------------------------------------------------------------------
// SMS send command
// --------------------------------------------------------------------------------

int main(int argc, char *argv[])
{
	if( argc != 2 ) {
		printf("Incorrect parameters (%d)\n", argc);
		printf("Usage: send_sms <text to send>\n", argc);
		return( 10 );
	}
	
	std::string smstext = argv[1];
	
	// Turn %20 into spaces
	while( smstext.size() ) {
		size_t i = smstext.find("%20");
		if( i == std::string::npos ) break;
		smstext.erase(i, 3);
		smstext.insert(i, " ");
	}
	
	// Open SIM800
	int sfd = open(SIM800_DEVICE, O_RDWR | O_NOCTTY); 
	
	if( sfd != -1 ) {
		
		// Lock access to the device, if another process is using it, then wait for it to unlock
		int fr = flock(sfd, LOCK_EX);
		if( fr != 0 ) {
			printf("Lock did not succeed\n");
			return( 11 );
		}
	
		// Configure UART
		struct termios options;
	
		tcgetattr(sfd, &options);
	
		cfsetspeed(&options, B9600);
	
		options.c_cflag &= ~CSTOPB;	
		options.c_cflag |= CLOCAL;
		options.c_cflag |= CREAD;
		
		cfmakeraw(&options);
	
		options.c_cc[VTIME] = 5;
		options.c_cc[VMIN] = 0;
		
		options.c_lflag &= ~ECHO;
	
		tcsetattr(sfd, TCSANOW, &options);
		
		printf("OK, serial open\n");
	
	} else {
	
		printf("Can't open serial connection, error code %d\n", errno);
		
		return( 1 );
		
	}
	
	int exitCode = 0;
	
	try {
		
		bool result;
		
		// Clear the UART
		FlushAll(sfd);

		// Check if modem responds to AT commands
		dprintf(sfd, "AT\n");
		fsync(sfd);
		result = WaitForReply(sfd);
		if( !result ) throw(2);
		
		// Reject all incoming calls
		dprintf(sfd, "AT+GSMBUSY=1\n");
		fsync(sfd);
		result = WaitForReply(sfd);
		if( !result ) throw(2);
	
		// Check if registered to a network
		dprintf(sfd, "AT+CREG?\n");
		fsync(sfd);
		std::string s;
		result = WaitForReply(sfd, &s);
		if( result ) {
			std::vector<std::string> out = ParseReply(s);
			s = SearchReplyLine("+CREG:", out);
			if( s.empty() ) throw(3);
			if( !s.size() > 0 || (s[s.size() - 1] != '5' && s[s.size() - 1] != '1')) throw(3);
			printf("Registered to network: OK\n");
		} else 
			throw(2);
		
		// Set SMS format to text
		dprintf(sfd, "AT+CMGF=1\n");
		fsync(sfd);
		result = WaitForReply(sfd);
		if( !result ) throw(2);

		printf("Sending <%s>\n", smstext.c_str());
		
		// Send SMS
		dprintf(sfd, "AT+CMGS=\"" DESTINATION_NBR "\"\n");
		fsync(sfd);
		usleep(250 * 1000);	
		dprintf(sfd, smstext.c_str());
		dprintf(sfd, "\x1A");
		fsync(sfd);
		
		printf("SMS sent, waiting for ACK\n");

		// Wait for network to ACK the SMS
		result = WaitForReply(sfd, &s);
		if( result ) {
			std::vector<std::string> out = ParseReply(s);
			s = SearchReplyLine("+CMGS:", out);
			if( s.empty() ) throw(4);
			s.erase(0, 7);
			printf("ACK received, message ID is %s\n", s.c_str());
		} else
			throw(4);
		
		// Clear the UART
		FlushAll(sfd);
	
	}
	
	catch( int c ) {
		// 2 = modem not responding to AT commands
		// 3 = Not registered on network
		// 4 = SMS not sent
		printf("ERROR code %d\n", c);
		exitCode = c;
	}

	close(sfd);

	return( exitCode );
}

Next open a terminal, go to the folder where you saved the file and compile it with the following command:

g++ -o send_sms ./send_sms.cpp

This will only work on Linux and you will need the base development tools installed.

This will create an executable called send_sms. To test, call it from the terminal with a message to send, like this:

./send_sms "Hello there"

This will send the text Hello there as an sms to to the phone number you specified earlier. If that works you can then integrate it into HA as a shell command.

1 Like

Thanks, will give it a try in 1 of the coming days.

Hi, I have started a PR with the required support for ANSI messages.
Support ANSI SMS by ocalvo · Pull Request #76733 · home-assistant/core (github.com)

1 Like

Please note the breaking change in the sms integration in 2022.9

Yaml notify is no longer needed. You can specify the phone number using the target parameter.

1 Like

Hello

It works with one target but it seems not possible to put a list of targets in a single command.

Flash SMS?
Would it be possible to add flash sms as an option. Gammu has an option [-flash] for text messages. The result is a “normal” SMS but it always pops up a “sticky” notification on the phone. Impossible to miss or ignore. Very handy for urgent notification like Fire! etc

Do you know how integrate now with automation? I have over 50 automation with notify via SMS and all of them I need to somehow adjust. Previous was easy request service and sent SMS via configured service in configuration.yaml now after this “new” change I have no idea how separate this between the numbers. :frowning:

Yes, we updated the docs to address this issue:

Let me know if you need more help.

Wierd, I tested this and it works for me.
Can you replace + by 00 and try again?

Can you point me to this in the Gammu docs?

target: 123456, 123457, 123458 …

doesn’t work (?)

Thats invalid yaml syntax, you need to specify:
target:

  • 122344
  • 123523

No commas.

1 Like

https://docs.gammu.org/gammu/#cmdoption-gammu-flash

-flash
Class 0 SMS (should be displayed after receiving on recipients’ phone display after receiving without entering Inbox)

I have juste made a test, this works :

service: notify.sms
data:
  target:
    12345
  message: "Hello"

this doesn’t work :

service: notify.sms
data:
  target:
    12345
    12346
  message: "Hello"

You are missing the dashes:
- 1234
- 1234

1 Like