Pull to refresh

Бесплатная отправка SMS из Arduino без GSM модуля

Reading time 5 min
Views 197K


Понадобилось мне слать SMS из ардуинины себе на телефон. Да так, что бы без заморочек с GSM, сим картами и оплатой. Под катом то, что из этого вышло.

Раз GSM не подходит, то слать придется через интернет. В закромах имелся сверх дешевый Wi-Fi модуль ESP8266. Про его предварительную настройку можно почитать в этой отличной статье ссылка.
Перво-наперво полез гуглить различные интернет-сервисы для отправки SMS. Сервисов оказалось много, но вот подходящего среди них не оказалось. Либо 10 SMS в день, либо хотят денег. Да и капчи ардуинине не по зубам. Но тут совершенно случайно наткнулся на на интересный сервис своего мобильного оператора (MTS BY) — всего за 1$ можно подключить услугу приема email в виде SMS ссылка. Что же, полностью бесплатно не получилось, и после оплаты я получил почтовый адрес вида 375XXYYYYYYY@sms.mts.by ( где XX и YYYYYYY — код сети и номер). То есть все свелось к банальной отправке email из arduino.

Но не тут-то было. Оказывается в последнее время все уважающие себя почтовые сервера отказываются принимать почту по 25 порту и без шифрования. А с другими связываться не хотелось, как и привязываться к своему домашнему серверу. Нагуглил вот такой сервис ссылка. В базовом бесплатном варианте дают 6к писем в месяц, что для моего домашнего использования хватает с головой. После регистрации идем в настройки и видим адрес smtp сервера, порт, логин и сгенерированный нам пароль.

Быстро накатал скетч, отправляю email 375XXYYYYYYY@sms.mts.by и… Облом. Отправляю на обычную почту — приходит. Пытался так и эдак переделывать заголовок — все равно письма исчезают в безднах серверов МТС, явно попадая в котел спам фильтра.

Значит нужно «отмыть» почту. В качестве сервиса отмывки выбрал (тихо ненавидимый мною за рекламу) mail.ru. Для отмывки в настройках почты, в разделе «Фильтры и пересылка», создал новое правило:
Настройки
После создания фильтра его понадобилось активировать введя код, пришедший в виде email-SMS на телефон.
Вот и момент триумфа — отправляю email из ардуинины, и через минуту телефон раздается радостным сигналом оповещения, при этом пугая проходящего рядом кота.

Далее скучные технические подробности.
В качестве платы взял Arduino Mega 2560, так как в нем целых три дополнительных последовательных порта (хотя можно и обычный UNO, только дебажить будет сложнее).
ESP8266 подключен: GND -> GND, VCC и CH_PD -> +3.3V, RX -> TX3, TX -> RX3. Скорость ESP8266 настроена на 115200 бод.
Для общения с smtp сервером нужно закодировать свои логин и пароль в Base64.
Можно воспользоваться консолью Linux:
openssl enc -base64 <<< 'email@gmail.com'
openssl enc -base64 <<< 'password'
Или же каким-либо онлайн сервисом, например ссылка.
Ну и собственно код скетча. После включения отправляется СМС и код уходит в вечный цикл. Дополнительные библиотеки не использовал.
Код
#define SSID "wi-fi_login" // ваш SSID
#define PASS "wi-fi_password" // ваш пароль Wi-Fi

#define SMTPServer "s02.atomsmtp.com" //smtp сервер
#define SMTPPort "2525" // smtp порт
#define MailLogin "smtp_example@gmail.com" // логин для smtp
#define MailLoginBase64 "dWd1LCBrb25lNG5vCg==" //логин для smtp в Base64
#define MailPasswordBase64 "aHJlbiB0YW0K" // пароль для smtp в Base64
#define MailRelay "example@mail.ru" // промежуточная почта для "отмывания" email
#define PhoneNumber "375290000000" // номер телефона
#define Message "Hello from Arduino!" //сообщение

#define SERIAL_RX_BUFFER_SIZE 256
#define SERIAL_TX_BUFFER_SIZE 256

void setup()
{
	delay(2000);
	Serial3.begin(115200);
	Serial3.setTimeout(5000);
	Serial.begin(115200); // для отладки
	Serial.println("Init");
	Serial3.println("AT+RST"); // сброс и проверка, что модуль готов
	if(WaiteString("Ready", 5000)) {
		while(Serial3.available()) { Serial3.read();}
		Serial.println("WiFi - Module is ready");
	}else{
		Serial.println("Module dosn't respond.");
		while(1);
	}
	delay(100);

	Serial3.println(" AT+CIPMODE=0");
	WaiteString("OK");
	while(Serial3.available()) { Serial3.read();}

	Serial3.println("AT+CIPMUX=1");
	WaiteString("OK");
	while(Serial3.available()) { Serial3.read();}

	// try to connect to wifi
	boolean connected = false;
	for(int i=0;i<5;i++) {
		if(connectWiFi()) {
			connected = true;
			break;
		}
	}
		if (!connected) {
		while(1);
	}
}
void loop()
{
	String cmd = "AT+CIPSTART=0,\"TCP\",\"";
	cmd += String(SMTPServer);
	cmd += "\"," + String(SMTPPort);
	Serial3.println(cmd);

	if(WaiteString("Linked", 5000)) {
		while(Serial3.available()) { Serial3.read();}
		Serial.println("Link");
	}
	else {
		Serial.println("Link fail");
		while (1);
	}

	if (WaiteString("OK", 2000)) {
		while(Serial3.available()) { Serial3.read();}
	}
	else {
		while (1);
	}
  
	Send("HELO 1.2.3.4", true);
	Send("AUTH LOGIN", true);
	Send(MailLoginBase64, true);
	Send(MailPasswordBase64, true);
	Send("MAIL FROM:<" + String(MailLogin) + ">", true);
	Send("RCPT TO:<" + String(MailRelay) + ">", true);
	Send("DATA", true);
	Send("Subject:SMS", false);
	Send("To:\"" + String(PhoneNumber) + "\" <" + String(PhoneNumber) + "@sms.mts.by>", false);
	Send("From: <" + String(MailLogin) + ">", false);
	Send("", false);
	Send(Message, false);
	Send(".", true);
	Send("QUIT", true);

	while(1) {};
}
 
boolean connectWiFi()
{
  Serial3.println("AT+CWMODE=1");
  while (!Serial3.available())	{ delay(10);}
  while (Serial3.available()) {Serial3.read();}
  String cmd="AT+CWJAP=\"";
  cmd+=SSID;
  cmd+="\",\"";
  cmd+=PASS;
  cmd+="\"";
  Serial3.println(cmd);

  if(WaiteString("OK", 8000)){
    Serial.println("Connected to WiFi.");
    return true;
  }else{
    Serial.println("Can not connect to the WiFi.");
    return false;
  }
}

bool Send(String S, bool wait) {
	Serial3.print("AT+CIPSEND=0,");
	Serial3.println(S.length()+2);
	while (!Serial3.available()) { delay(10);}
	if(Serial3.find(">")){
	}else{
		Serial3.println("AT+CIPCLOSE=0");
		delay(1000);
		return false;
	}
	Serial3.print(S + "\r\n");//добаяляем перевод строки
	if (WaitString("OK", 15000)) {
		if (wait) {
			WaitString("+IPD", 15000);
			while(Serial3.available()) {
				Serial3.read();}}
		return true;}
	else {
		return false;}
}

void WaiteString(String S) {
	int L = S.length();
	String T = String(" ");
	while(1) {
		if (Serial3.available()) {
			char c = Serial3.read();
			T = T + String(c);
			if (T.length() > L) T = T.substring(1);
			if (S.charAt(0) == T.charAt(0))
			if (S.compareTo(T) == 0) return;
		}
		else {
			delay(1);
		}
	}
}

bool WaiteString(String S, int Time) {
	int L = S.length();
	String T = String(" ");
	while(Time>0) {
		if (Serial3.available()) {
			char c = Serial3.read();
			T = T + String(c);
			if (T.length() > L) T = T.substring(1);
			if (S.charAt(0) == T.charAt(0))
			if (S.compareTo(T) == 0) return true;
		}
		else {
			delay(1);
			Time--;
		}
	}
	return false;
}

String WaiteString(int Time) {
	String T = String("");
	while(Time>0) {
		if (Serial3.available()) {
			char c = Serial3.read();
			T = T + String(c);
		}
		else {
			delay(1);
			Time--;
		}
	}
	return T;
}
Tags:
Hubs:
+37
Comments 46
Comments Comments 46

Articles