Introduction: ESP32: SIM800L and Barrier Sensor

About: Do you like technology? Follow my channel on Youtube and my Blog. In them I put videos every week of microcontrollers, arduinos, networks, among other subjects.

Today I’ll discuss an assembly that functions as an alarm and automation together, using the SIM800L. The modem is GPRS and needs a SIM card. We can say this is like a "cell phone," but it’s very cool. It’s extremely cheap and allows you to develop amazing projects. I'll introduce you to the assembly and source code with ESP32, SIM800L, and a barrier sensor, in addition to making calls and sending alerts via SMS to smartphones.

Step 1: Demonstration

Step 2: Assembly

Step 3: Resources Used

· ESP32 - WROOM

· SIM800L

· 1.8 '' TFT display

· Barrier sensor

· 2 Relay Module

· 10k ohm resistor

· 4.1V and 5V power supply

· Jumpers

· 1x SIM card with SMS plan for Smartphone

· 1x SIM card with SMS plan and connection to SIM800L

· Smartphone

Step 4: Pinout ESP32

Step 5: Pinout SIM800L

Step 6: Assembly

* Leave the GND in common

Step 7: Assembly - Table

Step 8: Code

Step 9: ESP32 Code - Declarations and Variables

#include <Arduino.h> //biblioteca arduino (opcional)
#include <Adafruit_GFX.h> //biblioteca do display grafico #include <Fonts/FreeSans9pt7b.h> //fonte usada no display #include <Adafruit_ST7735.h> // biblioteca de hardware do display #include <SPI.h> // biblioteca de comunicação SPI #define TINY_GSM_MODEM_SIM800 // definição do modem usado (SIM800L) #include <TinyGsmClient.h> // biblioteca com comandos GSM // pinos display #define TFT_CS 22 // CS #define TFT_RST 21 // RESET #define TFT_DC 5 // A0 #define TFT_MOSI 23 // SDA #define TFT_CLK 18 // SCK // objeto do display Adafruit_ST7735 display = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST); // tamanho da fonte do display int fontHeight = 12; // objeto de comunicação serial do SIM800L HardwareSerial SerialGSM(1); // objeto da bibliteca com as funções GSM TinyGsm modemGSM(SerialGSM); // velocidade da serial tanto do SIM800L quanto do monitor serial const int BAUD_RATE = 9600; // variáveis usadas para contar o tempo sem travar a função loop // millis de referencia long int millisRefCon, millisUserResp; // flag que indica a contagem de tempo (usadas pela função 'timeout') bool flagCon = false, flagUserResp = false; // pinos aonde os reles serão ligados e RX / TX aonde o SIM800L será ligado const int relayPin1 = 17, relayPin2 = 15, sensorPin = 16, RX_PIN = 4, TX_PIN = 2; //Access point name da vivo const char *APN = "zap.vivo.com.br"; //Usuario, se não existir deixe em vazio const char *USER = ""; //Password, se não existir deixe em vazio const char *PASSWORD = ""; // as variáveis abaixo usadas pela função loop // flag que indica se, após a ligação feita pelo SIM800L, um usuario respondeu com um SMS em até 1min bool userResponseSMS = false; // flag que indica se o sensor está ativo bool sensorActivated = false; // index do vetor de numeros de celular, usado para percorrer o vetor int i = 0; // quantidade de celulares que receberão mensagens e ligações e poderão enviar comandos SMS const int numbersTL = 2; // numero de celulares, a ordem de chamada pelo programa é da esquerda para a direita const String numbers[numbersTL] = {"+5518999999999", "+5518999999999"};

Step 10: ESP32 Code - Setup

void setup()
{ Serial.begin(BAUD_RATE); Serial.println("Starting..."); // seta pinos do sensor como entrada pinMode(sensorPin, INPUT); // seta pinos dos reles como saída pinMode(relayPin1, OUTPUT); pinMode(relayPin2, OUTPUT); // os reles trabalham com lógica inversa, setamos como HIGH para desligá-los de início digitalWrite(relayPin1, HIGH); digitalWrite(relayPin2, HIGH); // atribui para as variáveis de contagem de tempo o tempo atual antes de entrar no loop millisRefCon = millisUserResp = millis(); display.initR(INITR_BLACKTAB); resetDisplay(); // inicia e configura o SIM800L setupGSM(); resetDisplay(); display.println("GPRS: Connected"); }

Step 11: ESP32 Code - SetupGSM

// inicializa GSM
void setupGSM() { display.println("Setup GSM..."); display.setTextColor(ST7735_GREEN); // inicia serial SIM800L SerialGSM.begin(BAUD_RATE, SERIAL_8N1, RX_PIN, TX_PIN, false); delay(3000); // exibe info do modem no monitor serial Serial.println(modemGSM.getModemInfo()); // inicia o modem if (!modemGSM.restart()) { display.setTextColor(ST7735_RED); display.println("Restarting GSM\nModem failed"); delay(10000); ESP.restart(); return; } display.println("Modem restart OK"); // aguarda network if (!modemGSM.waitForNetwork()) { display.setTextColor(ST7735_RED); display.println("Failed to connect\nto network"); delay(10000); ESP.restart(); return; } display.println("Modem network OK"); // conecta na rede (tecnologia GPRS) if(!modemGSM.gprsConnect(APN,USER,PASSWORD)) { display.setTextColor(ST7735_RED); display.println("GPRS Connection\nFailed"); delay(10000); ESP.restart(); return; } display.println("GPRS Connect OK"); //Define modo SMS para texto (0 = PDU mode, 1 = Text mode) if(sendAT("AT+CMGF=1").indexOf("OK") < 0) { display.setTextColor(ST7735_RED); display.println("SMS Txt mode Error"); delay(10000); ESP.restart(); return; } display.println("SMS Txt mode OK"); //Exclui todos SMS armazenados sendAT("AT + CMGD=1,4"); resetDisplay(); display.setTextColor(ST7735_WHITE); }

Step 12: ESP32 Code - SendAT and ResetDisplay

//Envia comando AT e aguarda até que uma resposta seja obtida
String sendAT(String command) { String response = ""; SerialGSM.println(command); // aguardamos até que haja resposta do SIM800L while(!SerialGSM.available()); response = SerialGSM.readString(); return response; } // limpa e configura display void resetDisplay() { display.setRotation(1); display.setFont(&FreeSans9pt7b); display.fillScreen(ST77XX_BLACK); display.setTextColor(ST7735_WHITE); display.setCursor(0,fontHeight); }

Step 13: ESP32 Code - Loop

void loop()
{ String msg, number; // de 5 em 5 segundos, verifica se o SIM800L está desconectado, se sim, tenta reconectar if(timeout(5000, &millisRefCon, &flagCon)) verifyGPRSConnection(); // se o SIM800L está conectado if(modemGSM.isGprsConnected()) { // função que verifica se deve-se efetuar a chamada ou não if(isItToCall()) { // sinaliza que o sensor foi ativado sensorActivated = true; userResponseSMS = false; // atribui à variavel de referencia para contar o tempo, o valor atual do millis millisUserResp = millis(); Serial.println("Sensor activated!"); Serial.println("Calling to number "+String(i+1)); display.println("Sensor activated!"); display.println("Calling to number "+String(i+1)); // efetua a ligação para um dos nºs do vetor, iniciando com 0 call(numbers[i++]); // após a chamada soma-se 1 ao i // se chegou ao fim do vetor, retorna ao início (0) if(i>=numbersTL) i = 0; } // verifica se foi recebido um SMS if(SMSMessageRecv(&msg, &number)) { // exibe mensagem no display e monitor serial resetDisplay(); display.println("SMS Msg Received"); Serial.println("SMS Msg Received"); delay(2500); // validamos o SMS e executamos uma ação executeCommand(number, msg); } } else // exibe na serial que o modem está desconectado Serial.println("Disconnected"); // único delay no loop de 10ms (desconsiderando a função de reconexão, que possui delay para exibição do display) delay(10); }

Step 14: ESP32 Code - Timeout

// Função que compara se o tempo foi atingido, sem que 'congele' a execução do loop
bool timeout(const int DELAY, long *previousMillis, bool *flag) { if(*flag) { *previousMillis = millis(); *flag = false; } if((*previousMillis + DELAY) < millis()) { *flag = true; return true; } return false; }

Step 15: ESP32 Code - VerifyGPRSConnection

// verifica se o SIM800L se desconectou, se sim tenta reconectar
void verifyGPRSConnection() { resetDisplay(); display.print("GPRS: "); if(modemGSM.isGprsConnected()) display.println("Connected"); else { display.println("Disconnect"); display.println("Reconnecting..."); if(!modemGSM.waitForNetwork()) { display.setTextColor(ST7735_RED); display.println("GPRS Con. Failed"); delay(5000); display.setTextColor(ST7735_WHITE); } else { if(!modemGSM.gprsConnect(APN,USER,PASSWORD)) { display.setTextColor(ST7735_RED); display.println("GPRS Con. Failed"); delay(5000); display.setTextColor(ST7735_WHITE); } else { display.setTextColor(ST7735_GREEN); display.println("GPRS Con. OK"); } } } }

Step 16: ESP32 Code - IsItToCall and Call

bool isItToCall()
{ // se o sensor de barreira está ativo ou foi uma vez ativado e não foi recebido um SMS em 1 min, retornamos true indicando que deve-se ligar parao próx número return digitalRead(sensorPin) == HIGH || (sensorActivated && !userResponseSMS && timeout(60000, &millisUserResp, &flagUserResp)); } // executa chamada void call(String number) { display.print("Calling..."); Serial.println(number); // tenta executar chamada bool res = modemGSM.callNumber(number); // se obteve sucesso exibe OK, se não, fail if(res) display.println(" OK"); else display.println(" fail");

Step 17: ESP32 Code - Call (continued) and SMSMessageRecv

if (res)
{ // assim que a chamada for feita é finalizada res = modemGSM.callHangup(); // exibe se foi possível finalizar ou não display.print("Hang up: "); if(res) display.println("OK"); else display.println("fail"); } } // verifica se um sms é recebido e obtem o número de quem o enviou bool SMSMessageRecv(String *msg, String *number) { // comando AT que lista todos os SMS armazenados *msg = sendAT("AT+CMGL=\"ALL\""); // se o SIM800L responder com SM, significa que um novo SMS acaba de chegar // então pedimos novamente que o SIM nos liste os SMS armazenados if((*msg).indexOf("+CMTI: \"SM\"")>=0) *msg = sendAT("AT+CMGL=\"ALL\"");

Step 18: ESP32 Code - SMSMessageRecv (continued)

// se a mensagem possui um OK e possui mais que 10 caracteres (existe pelo menos um SMS)
if((*msg).indexOf("OK")>=0 && (*msg).length()>10) { // exibe a mensagem na serial Serial.println(*msg); // obtém o número que nos enviou o SMS e exibe se obteve sucesso if(getSMSNumber(*msg, *&number)) { Serial.println("numero obtido: "+*number); return true; } else { Serial.println("Erro ao obter numero"); return false; } } // exibe na serial um ponto (debug) Serial.print("."); return false; }

Step 19: ESP32 Code - ExecuteCommand

void executeCommand(String number, String msg)
{ // se o número não é válido, exibe mensagem e não faz nada if(!numberIsValid(number)) { display.println("Number is not valid"); Serial.println("Number is not valid"); Serial.println(number); delay(2500); } else { // se o número é valido // obtem o texto do SMS recebido Serial.println("Msg: '"+msg+"'"); getTextSMS(&msg); Serial.println("Cmd: '"+msg+"'"); // executa comando de acordo com o texto recebido if(commandOK(number, msg)) { // sinaliza que o usuario respondeu com um SMS válido userResponseSMS = true; // retorna para false a flag que indica se sensor está ativo sensorActivated = false; display.println("Sending status"); Serial.println("Sending status"); // Envia o estado dos dois relés em um SMS sendResponse(number); } else { // se o comando é inválido, exibe no display // sinaliza que o usuario respondeu com um SMS inválido userResponseSMS = false; display.println("Cmd is not valid"); Serial.println("Cmd is not valid"); } } // exclui todos os SMS armazenados sendAT("AT + CMGD=1,4"); }

Step 20: ESP32 Code - GetTextSMS

// obtem texto da mensagem e o retorna por parâmetro
void getTextSMS(String *msg) { String aux; /* Exemplo de mensagmem: [ +CMGL: 1,"REC UNREAD","+5518999999999","","18/11/30,11:36:14-08" Hello OK ] */ //pula primeiro \n *msg = (*msg).substring((*msg).indexOf( "\n" )+1); //pula primeira linha: 'Cmd: +CMGL: 1,"REC UNREAD","+5518999999999","","18/11/30,11:04:30-08"' *msg = (*msg).substring((*msg).indexOf( "\n" )+1); aux = *msg; if(aux.length() <= 8) return; *msg = ""; // retira a substring "\r\n\r\nOK\r\n" (8 caracteres) for(int i=0; i

Step 21: ESP32 Code - CommandOK

// executa comando de acordo com a variavel 'msg'
bool commandOK(String number, String msg) { // flag que indica se entrou em algum if (indicando comando válido) bool smsOK = false; // verifica se a msg corresponde a algum dos comandos existentes e seta os pinos correspondentes // os reles possuem lógica inversa if(msg.equalsIgnoreCase("relay 1 on")) { digitalWrite(relayPin1, LOW); smsOK = true; } else if(msg.equalsIgnoreCase("relay 1 off")) { digitalWrite(relayPin1, HIGH); smsOK = true; } else if(msg.equalsIgnoreCase("relay 2 on")) { digitalWrite(relayPin2, LOW); smsOK = true; } else if(msg.equalsIgnoreCase("relay 2 off")) { digitalWrite(relayPin2, HIGH); smsOK = true; } else if(msg.equalsIgnoreCase("relays off")) { digitalWrite(relayPin1, HIGH); digitalWrite(relayPin2, HIGH); smsOK = true; } else if(msg.equalsIgnoreCase("relays on")) { digitalWrite(relayPin1, LOW); digitalWrite(relayPin2, LOW); smsOK = true; } else if(msg.equalsIgnoreCase("ok")) // comando OK, usado para sinalizar alarme falso smsOK = true; else if(msg.equalsIgnoreCase("hello")) // comando hello, usado para verificar o funcionamento { modemGSM.sendSMS(number, "Hello!"); smsOK = true; } else if(msg.equalsIgnoreCase("status")) // comando status que obtém os estados dos pinos smsOK = true; return smsOK; }

Step 22: Files

Download the files

INO

PDF