Начну с подключения 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/