Начну с подключения GSM модуля SIM800. Хотя оно подробно описано в серии статей по этому GSM модулю, но есть один нюнас. Во всех предыдущих статьях я говорил, что модуль потребляет до 2A в пике, поэтому его нельзя запитывать от USB порта ноутбка. Рассмотрю, как запитывать:
- Модуль SIM800.
- Микроконтроллер MH ET LiveESP32
- от блока питания 5V 2A. Из рассмотренных мне понравился вот этот. Особенно цена порадовала. 🙂
- через недорогой DC-DC преобразователь Mini 360 или аналогичный.
Немало вопросов в интернет как параллельно запитать микроконтроллер и GSM модуль, чтобы можно было подключать USB кабель для заливки прошивки.
Подключение внешего источника питания к ESP32 и SIM800
Как подключить внешний мощный источник питания 5V к ESP32, чтобы запитать SIM800, потребляющий до 2A в пике? Рассмотрим, сделано ли что-то схематике ESP32/ESP8266, чтобы не сжечь USB порт ПК при подключении внешнего источника питания.
На схеме от производителя виден диод Шоттки BAT-760 в цепи питания +5V. Этот диод присутствует не на всех платах, поэтому прежде чем подключить USB от ПК к плате запитанной от внешнего источника +5V нужно убедится, что на плате диод распаян. Даже если нет схемы платы, то проверить несложно. Черный планарный диод относительно большого размера хорошо выделяется на плате. Катод диода идет на PIN +5V, а анод на вывод +5V питания USB разъема.
Если диода нет, то его нужно добавить в схему питания.


Получение SMS. Инициализация.
Для начала нужно проверить, что тариф допускает отправку сообщений. Например, у Билайна на SIM-картах привязанных к основной голосовой но для использования в планшете, ноутбуке и пр. под Интернет нет опции отправки SMS. Можно потратить немало времени, пытаясь отправить SMS с такой SIM-ки.
Для работы с SIM800L я использую библиотеку TinyGSM.
Для отправки SMS используется простой код:
bool res = modemGSM.sendSMS("+7960XXXXXX", "GSM modem with IMEA " + modemGSM.getIMEI() + " has started.");
Serial.println("SMS sending status: " + String(res ? "OK" : "fail"));Он простой и хорошо работает.
К сожалению, в библиотеке не реализован функционал чтения SMS. При использовании сообщений SMS для управления устройствами нужно быть предельно внимательным, поскольку в зависимости от инициализации SIM800 модуль будет по-разному обрабатывать SMS сообщения.
AT команда AT+CNMI определяет будет ли принятое сообщение буферизовываться на SIM карте или будет лишь отображаться и передаваться напрямую в TE (например, микроконтроллеру). В последнем случае на SIM карте не будут сохранятся полученные SMS. Это довольно эксремальный вариант работы, поскольку в случае если по каким-то причинам микроконтроллер не вычитал SMS, то может быть проигнорирована важная команда управления.
Поэтому я предпочитаю сначала записывать все приходящие SMS и затем периодически вычитывать их на предмет появления новых. Как только команда полученная в SMS отработана IoT устройством, SMS можно удалить.
Для инициализации я использую несколько команд:
void smsInit()
{
modemGSM.sendAT(GF("+CPMS=SM,SM,SM")); //Storage to store SMS
modemGSM.waitResponse();
modemGSM.sendAT(GF("+CMGF=1")); //Text type messages instead of PDU
modemGSM.waitResponse();
modemGSM.sendAT(GF("+CNMI=1,0"));
modemGSM.waitResponse();
modemGSM.sendAT(GF("+CSCS=\"GSM\""));
modemGSM.waitResponse();
}AT+CPMS задает память для сохранения SMS сообщений:
- SM – Память SIM-карты
- ME – Память модема/телефона
- MT – Это общая память SIM-карты и модема, т.е. MT = SM+ME
- BM – Память для широковещательных сообщений сети
- SR – Память для отчетов (о доставке и т.п.)
Память модема делится на три логических секции и поэтому при вызове +CPMS можно передавать три аргумента:
- Первая — для просмотра, чтения и удаления сообщений
- Вторая — для сохранения и отправки исходящих сообщений.
- Третья — только для вновь полученных сообщений.
Я не нашел примеров работы с этими тремя видами памяти. Если кто-то найдет информацию — буду благодарен, если поделитесь. Для надежности буду использовать только SM.
Далее задаем формат SMS сообщений AT+CMGF=1 (тесктовые сообщения). Для формата PDU используется AT+CMGF=0. Формат PDU
(Protocol Data Unit) используется по умолчанию. Он более информативный, но и более сложный для парсинга. Для управления IoT устройством достаточно простого текстового формата.
Например, команда AT+CNMI=1,2,0,0,0 говорит модулю SIM800 либо направлять толкьо что полученные SMS сообщения напрямую микроконтроллеру, или сохранять их в хранилище сообщений и затем уведомлять микроконтроллер о их размещении в хранилище. При использовании этой команды пришедшее SMS приходит в Serial порт микроконтроллера в виде:
15:52:58.028 -> +CMT: "+79601XXXXX","","19/05/02,15:52:53+12" 15:52:58.062 -> Test again
При этом пришедшие SMS сообщения не сохраняются в памяти SIM-карты.
Чтобы пришедшее SMS сообщение сохранилось в памяти SIM-ки нужно использовать команду AT+CNMI=1,0 или AT+CNMI=0,0. Мне не удалось найти обстоятельно описанные примеры использования команды.
Последняя команда AT+CSCS=»GSM» в функции инициализации устанавливает charset «GSM» для TE. Возможные значения:
- «GSM» GSM 7 bit default alphabet (3GPP TS 23.038);
- «UCS2» 16-bit universal multiple-octet coded character set (ISO/IEC10646); UCS2 character strings are converted to hexadecimal numbers from 0000 to FFFF; e.g. «004100620063» equals three 16-bit characters with decimal values 65, 98 and 99
- «IRA» International reference alphabet (ITU-T T.50)
- «HEX» Character strings consist only of hexadecimal numbers from 00 to FF;
- «PCCP» PC character set Code
- «PCDN» PC Danish/Norwegian character set «8859-1» ISO 8859 Latin 1 character set
Отправка SMS
При использовании указанной выше команды AT+CNMI=1,0 при приходе SMS строчек
09:33:19.153 -> +CMT: "+79601XXXXX","","19/05/05,09:33:15+12" 09:33:19.187 -> Test the SMS send
индициирующих о приходе сообщения не будет. Нужно вычитывать сообщения. Чтобы вычитать все SMS сообщения я написал функцию:
enum ReadSMSMode
{
ReceivedUnread,
ReceivedRead,
StoredUnsent,
StoredSent,
All
};
void readAllSMSs(ReadSMSMode mode = ReadSMSMode::AllSMS)
{
smsInit();
String readMode = "ALL";
switch (mode)
{
case ReadSMSMode::ReceivedUnread:
readMode = "REC UNREAD";
break;
case ReadSMSMode::ReceivedRead:
readMode = "REC READ";
break;
case ReadSMSMode::StoredUnsent:
readMode = "STO UNSENT";
break;
case ReadSMSMode::StoredSent:
readMode = "STO SENT";
break;
case ReadSMSMode::AllSMS:
readMode = "ALL";
break;
}
modemGSM.sendAT(GF("+CMGL=\"" + readMode + "\""));
Serial.println("Read all SMSs.");
while (true)
{
if (modemGSM.waitResponse(10000L, GF(GSM_NL "+CMGL:"), GFP(GSM_OK), GFP(GSM_ERROR)))
{
String data = modemGSM.stream.readStringUntil('\n');
data.trim();
if (data.length() == 0)
break;
Serial.println("Data: " + data);
String msg = modemGSM.stream.readStringUntil('\n');
Serial.println("Message: " + msg);
}
else
{
break;
}
}
}Чтобы прочитать SMS с определенным id функция:
void readSMS(uint8_t i)
{
char message[300];
modemGSM.sendAT(GF("+CMGF=1"));
modemGSM.waitResponse();
modemGSM.sendAT(GF("+CNMI=1,2,0,0,0"));
modemGSM.waitResponse();
modemGSM.sendAT(GF("+CMGR="), i);
if (modemGSM.waitResponse(10000L, GF(GSM_NL "+CMGR:")))
{
String header = modemGSM.stream.readStringUntil('\n');
String body = modemGSM.stream.readStringUntil('\n');
Serial.println("Header: " + header);
Serial.println("Body: " + body);
}
}После того как SMS сообщение получено, распарсено и команда отработана, сообщение его лучше удалить. Для удаления SMS сообщения с определенным id используется функция:
bool deleteSmsMessage(const uint8_t index)
{
modemGSM.sendAT(GF("+CMGD="), index, GF(","), 0); // Delete SMS Message from <mem1> location
return modemGSM.waitResponse(5000L) == 1;
}Для удаления сообщений определенного типа использую функцию:
enum DeleteSmsMode
{
Read = 1,
Unread = 2,
Sent = 3,
Unsent = 4,
Received = 5,
All = 6
};
bool deleteAllSmsMessages(DeleteSmsMode method);
bool deleteAllSmsMessages(DeleteSmsMode method)
{
// Select SMS Message Format: PDU mode. Spares us space now
modemGSM.sendAT(GF("+CMGF=0"));
if (modemGSM.waitResponse() != 1) {
return false;
}
modemGSM.sendAT(GF("+CMGDA="), static_cast<const uint8_t>(method));
const bool ok = modemGSM.waitResponse(25000L) == 1;
modemGSM.sendAT(GF("+CMGF=1"));
modemGSM.waitResponse();
return ok;
}Результат
22:21:40.333 -> Read all SMSs. 22:21:40.367 -> Data: 1,"REC READ","+79601XXXXX","","19/05/05,16:52:16+12" 22:21:40.435 -> Message: Test again. 22:21:40.469 -> Data: 2,"REC READ","+79601XXXXX","","19/05/05,16:53:01+12" 22:21:40.502 -> Message: And again 22:21:40.537 -> Data: 3,"REC READ","+79601XXXXX","","19/05/05,17:12:05+12" 22:21:40.604 -> Message: And one again 22:21:40.637 -> Data: 4,"REC READ","+79601XXXXX","","19/05/05,17:58:59+12" 22:21:40.706 -> Message: Ones again 22:21:40.706 -> Data: 5,"REC READ","+79601XXXXX","","19/05/05,21:27:58+12" 22:21:40.777 -> Message: New message again.
Полезные ссылки
- Fork билиотеки TinyGSM в который добавлен функционал чтения SMS.
- Пример использования AT команд чтения SMS.
- https://lastminuteengineers.com/sim800l-gsm-module-arduino-tutorial/
- https://www.developershome.com/sms/