Мы с каждым разом разбираем все более интересные применения GSM-модуля SIM800. В этот раз я покажу, как принимать SMS сообщения и обрабатывать команды, которые могут в них храниться.
На основании программы из предыдущего видео я набросал следующие строки из двух команд, отправляемых в SIM800 для чтения SMS.
//https://geekmatic.in.ua | https://pinout.uno #include <SoftwareSerial.h> SoftwareSerial SIM800serial (2, 3); #define OK 1 #define NOTOK 2 #define TIMEOUT 3 String txt; void setup() { pinMode(5, OUTPUT); digitalWrite(5, HIGH); //SIM800 ON only for this module pinMode(6, OUTPUT); pinMode(7, OUTPUT); Serial.begin(9600); SIM800serial.begin(9600); delay(5000); SIM800command("AT", "OK", "ERROR", 500, 5); } void loop() { SIM800command("AT+CMGF=1", "OK", "ERROR", 2000, 1); //SMS to text mode - not PDU mode SIM800command("AT+CMGL=\"ALL\"", "OK", "ERROR", 5000, 1);////sms list SIM800command("AT+CMGD=1,3", "OK", "ERROR", 10000, 1);//sms delete delay(2000); }
byte SIM800command(String command, String response1, String response2, uint16_t timeOut, uint16_t repetitions) { byte returnValue = NOTOK; byte countt = 0; while (countt < repetitions && returnValue != OK) { SIM800serial.println(command); if (SIM800waitFor(response1, response2, timeOut) == OK) { returnValue = OK; } else {returnValue = NOTOK;} countt++; } return returnValue; } byte SIM800waitFor(String response1, String response2, uint16_t timeOut) { uint16_t entry = 0; uint16_t count = 0; String reply = SIM800read(); byte retVal = 99; do { reply = SIM800read(); delay(1); entry ++; } while ((reply.indexOf(response1) + reply.indexOf(response2) == -2) && entry < timeOut ); if (entry >= timeOut) { retVal = TIMEOUT; } else { if (reply.indexOf(response1) + reply.indexOf(response2) > -2) retVal = OK; else retVal = NOTOK; } return retVal; } String SIM800read() { String reply = ""; if (SIM800serial.available()) { reply = SIM800serial.readString(); } if (reply!=""){ Serial.print("Reply: "); Serial.println(reply); txt = reply; } return reply; }
Первая команда включает текстовый режим отображения SMS.
Вторая команда выводит список всех входящих SMS из памяти SIM-карты. Существует так же отдельная команда у SIM800 для отображения одной SMS, но надо знать номер ячейки, где она сейчас хранится. Нам все-таки более интересен вывод всего списка.
Вот расшифровка этой команды. Тут можно задавать такие фильтрующие параметры, как полученные непрочтенные, полученные прочтенные, не отправленные, отправленные или вообще все.
У меня в команде стоит параметр ALL – значит SIM800 выдаст список всех входящих и выходящих SMS, которые сохранены в памяти. Загружаю скетч в контроллер. Программа будет проверять наличие текстовых сообщений каждые 2 секунды и выводить их список.
Открываю монитор порта.
Отправляю текст Sms на номер SIM-карты, вставленной в SIM800.
В мониторе порта видим, что в памяти появилось одно сообщение с текстом, который я написал в телефоне. Кстати, обратите внимание, что в начале, в момент прихода SMS, GSM-модуль ругнулся кодом CMTI: SM, 1, что означает, что пришло текстовое сообщение и оно помещено в ячейку 1 памяти SIM-карты. Такой отчет SIM800 пишет в UART без запросов от контроллера.
Так же здесь видим, что нам желательно очищать память, где хранятся сообщения после их прочтения. Для чего, добавляем в скетч команду удаления CMGD.
Вот расшифровка этой команды. Первый параметр – номер ячейки памяти. Второй – это фильтр:
0 удалить одну ячейку;
1 удалить все прочитанные;
2 удалить все прочитанные и отправленные;
3 удалить все прочитанные входящие и все исходящие.
4 удалить абсолютно все.
Я выбрал третий вариант, удаляющий все входящие и исходящие SMS, оставляющий непрочитанные, чтобы случайно не удалить входящее сообщение, которое еще не обработано.
Прямо сейчас поставьте жирный лайк этому видео, а я загружу программу в Arduino. И открою монитор порта.
Видим ответ команды удаления сообщений CMGD OK.
Отправляю сообщение Sms2.
Сообщение пришло и прочитано. И повторно уже не читается. Потому, что память очищена.
Приём SMS – это чудесно, но давайте же перейдем в практическую плоскость и заставим Arduino Nano выполнять команды.
Для тестирования SMS-команд соберём следующую схему. Я к своему шилду добавлю два светодиода, которыми попробую управлять при помощи SMS.
Вот мой шилд для проектов на Arduino Nano и SIM800, но вы можете собрать эту схему по своему без моего шилда. Припаиваю светодиоды и их ограничивающие резисторы прямо к контроллеру Arduino Nano.
Получилось красиво!
Программа будет такой. Команду включения текстового режима я перенёс в setup. Её не обязательно выполнять каждый цикл.
//https://geekmatic.in.ua | https://pinout.uno #include <SoftwareSerial.h> SoftwareSerial SIM800serial (2, 3); #define OK 1 #define NOTOK 2 #define TIMEOUT 3 String txt; void setup() { pinMode(5, OUTPUT); digitalWrite(5, HIGH); //SIM800 ON only for this module pinMode(6, OUTPUT); pinMode(7, OUTPUT); Serial.begin(9600); SIM800serial.begin(9600); delay(5000); SIM800command("AT", "OK", "ERROR", 500, 5); SIM800command("AT+CMGF=1", "OK", "ERROR", 2000, 1); //SMS to text mode - not PDU mode } void loop() { SIM800command("AT+CMGL=\"ALL\"", "OK", "ERROR", 5000, 1);////sms list parse_cmd( txt ); SIM800command("AT+CMGD=1,3", "OK", "ERROR", 10000, 1);//sms delete delay(2000); } void parse_cmd( String str){ String part1; Serial.println("read_cmd start"); if (str.indexOf("sms")>-1) { //sms SIM800command("AT+CMGS=\"+380934158245\"", ">", "ERROR", 5000, 1); String str = "Hello from Arduino and SIM800!"; //SMS text SIM800serial.print(str);//the content of the message char j=0x1A; SIM800command((String)j, ">", "ERROR", 2000, 1); Serial.println("Sms"); delay(4000); } if (str.indexOf("ring")>-1) { //ring Serial.println("Ring"); SIM800command("ATD+380934158245;", "OK", "ERROR", 1000, 1); delay(10000); SIM800command("ATH", "OK", "ERROR", 500, 5); } //on if (str.indexOf("on")>-1) { digitalWrite(7, HIGH); Serial.println("On");} //off if (str.indexOf("off")>-1) { digitalWrite(7, LOW); Serial.println("Off");} if (str.indexOf("pwm")>-1) {//pwm part1 = str.substring(str.indexOf("pwm") + 4, str.length()); int brightness = part1.toInt(); Serial.print("Pwm = "); Serial.println(brightness); analogWrite(6, brightness); } }
byte SIM800command(String command, String response1, String response2, uint16_t timeOut, uint16_t repetitions) { byte returnValue = NOTOK; byte countt = 0; while (countt < repetitions && returnValue != OK) { SIM800serial.println(command); if (SIM800waitFor(response1, response2, timeOut) == OK) { returnValue = OK; } else {returnValue = NOTOK;} countt++; } return returnValue; } byte SIM800waitFor(String response1, String response2, uint16_t timeOut) { uint16_t entry = 0; uint16_t count = 0; String reply = SIM800read(); byte retVal = 99; do { reply = SIM800read(); delay(1); entry ++; } while ((reply.indexOf(response1) + reply.indexOf(response2) == -2) && entry < timeOut ); if (entry >= timeOut) { retVal = TIMEOUT; } else { if (reply.indexOf(response1) + reply.indexOf(response2) > -2) retVal = OK; else retVal = NOTOK; } return retVal; } String SIM800read() { String reply = ""; if (SIM800serial.available()) { reply = SIM800serial.readString(); } if (reply!=""){ Serial.print("Reply: "); Serial.println(reply); txt = reply; } return reply; }
Дальше в loop идет команда чтения списка текстовых сообщений.
Потом новая функция для отсеивания команд из сообщений. В неё передаётся текст списка всех сообщений из памяти SIM-карты.
И команда удаления прочитанных SMS.
Вот наша хитрая функция. Если в тексте будет найдена строка sms, то устройство отправит ответное сообщение: "Hello from Arduino and SIM800!".
Если будет найдена строка ring, то Arduino позвонит по заданному номеру телефона.
Следующие две текстовые команды – on и off. Они должны включать и выключать первый светодиод.
Последняя отслеживаемая команда – это pwm. Она будет управлять яркостью второго светодиода.
Сначала в переменную brightness записывается выделенное из текста сообщения значение яркости.
Потом функцией analogWrite мы активируем ШИМ управление пином номер 6 с заданным заполнением, то есть яркостью.
Загружаю скетч в контроллер.
Отправляю первую команду для включения светодиода.
Есть включение светодиода. Теперь отправляю команду выключения.
Есть выключение.
Теперь задам яркость второму светодиоду – 100 (в диапазоне от 0 до 255).
Команда выполнилась. Теперь 10.
Светодиод почти потух. Отправлю значение яркости 254.
Получаем максимальную яркость. И выключу светодиод, передав значение ноль.
Теперь проверим команду sms.
Получил очень быстрый ответ. Так же ввожу команду ring. А вот пришла и неожиданная вторая SMS. Попробуем это исправить.
Команда ring хорошо сработала – устройство мне перезвонило.
Отправляю команду sms ещё раз. Может это была случайность?
Нет, это не случайность. Я вроде понял в чем дело. Увеличу delay на 2 секунды после отправки сообщения. Так как команда удаления не успевает обработаться в модуле SIM800.
Проверяю команду sms еще раз.
Получаю ответ и удаление прошло удачно.
Отправляю еще раз.
И снова удачный ответ без повторов. Думаю на сегодня достаточно команд.
В ответных SMS можно вставлять значения различных датчиков, подключенных к Arduino Nano. Вместо светодиодов можно управлять различными исполнительными механизмами и другими приборами. Так же вы можете добавлять множество других текстовых команд редактируя функцию parse_cmd.