Projekt bramki SMS, który umożliwia wysyłanie i odbieranie wiadomości za pomocą modułu ESP32-PoE i SIM800L, z naciskiem na niezawodność i odporność na awarie.
Wysyłanie i Odbieranie SMS
ESP32 wykorzystuje moduł SIM800L, który jest regularnie sprawdzany, aby upewnić się, że jest zawsze gotowy do wysyłania i odbierania wiadomości. Dzięki temu możemy mieć pewność, że każda wiadomość zostanie prawidłowo obsłużona.
Moduł SIM800L jest podłączony do ESP32-PoE za pomocą komunikacji TX/RX, co umożliwia płynne przesyłanie danych między nimi.
Zasilanie ESP32-PoE
ESP32-PoE może być zasilany zarówno poprzez PoE, jak i przez USB. Ważne jest jednak, aby pamiętać, że jednoczesne podłączenie zasilania PoE i USB może spowodować uszkodzenie układu. Dzieje się tak, ponieważ ESP32-PoE nie posiada galwanicznej izolacji między zasilaniem PoE a USB.
Podłączenie modułów
SIM800L TX do ESP32 RX (GPIO16)
SIM800L RX do ESP32 TX (GPIO4)
Zasilanie: Upewnij się, że moduł SIM800L jest zasilany odpowiednim napięciem (3.7V – 4.2V) Zasilanie z ESP32 3.3V jest za małe. W moim projekcie użyłem regulowany stabilizator napięcia LM2595S
Dokumentacje
W trakcie budowania projektu korzystałem z następujących dokumetacji:
Przykłady komend AT
AT+CSQ - Sprawdzenie siły sygnału
AT+COPS=0 - automatyczny wybór operatorów
AT+CFUN=1,1 - restart modułu
AT+CBAND? - sprawdzenie aktualnego zakresu częstotliwości
AT+CBAND="DCS_MODE" - ustawienie zakresu częstotliwości DCS
AT+CBAND="ALL_BAND" - wszystkie częstotliwości
Przykłady zakresów częstotliwości:
GSM 850: AT+CBAND="GSM850"
E-GSM 900: AT+CBAND="EGSM_MODE"
DCS 1800: AT+CBAND="DCS_MODE"
PCS 1900: AT+CBAND="PCS_MODE"
Wszystkie zakresy: AT+CBAND="ALL_BAND"
Kod projektu
main.cpp – główny plik projektu
#include <Arduino.h>
#include "Network.h"
#include "HTTPServer.h"
#include "SIM800L.h"
void setup() {
Serial.begin(115200);
sim800lSetup();
setupEthernet();
delay(3000);
if (!ETH.linkUp()) {
setupWiFi();
}
setupServer();
}
void loop() {
server.handleClient();
monitorConnection();
delay(10000);
}
SIM800L.h SIM800L.cpp – pliki do obsługi modułu SIM800L.
#include "SIM800L.h"
const char SIM_PIN[] = "1111";
HardwareSerial sim800l(2);
bool isConnected = false;
std::vector<String> receivedSMS; // Zmienna globalna do przechowywania odebranych SMS-ów
void sim800lSetup() {
sim800l.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN);
sendATCommand("AT", 2000);
sendATCommand("AT+CPIN?", 2000);
sendATCommand(String("AT+CPIN=") + SIM_PIN, 2000);
configureBand();
resetAndConfigureModem();
setupGPRS();
checkNetworkConnection();
}
String sendATCommand(String command, int timeout) {
sim800l.println(command);
long int time = millis();
String response = "";
while ((millis() - time) < timeout) {
while (sim800l.available()) {
char c = sim800l.read();
response += c;
}
}
Serial.println("Odpowiedź na komendę " + command + ": " + response);
return response;
}
bool isRegistered(String response) {
if (response.indexOf("+CREG: 0,1") >= 0 || response.indexOf("+CREG: 0,5") >= 0) {
return true;
}
return false;
}
// Check network z uzyciem isRegistered
void checkNetworkConnection() {
String response = sendATCommand("AT+CREG?", 5000);
delay(3000);
Serial.println("Odpowiedź CREG: " + response);
if (isRegistered(response)) {
Serial.println("Zarejestrowano w sieci.");
isConnected = true;
} else {
Serial.println("Brak rejestracji w sieci. Wybieranie operatora...");
selectOperator();
checkNetworkConnection();
}
}
void checkSignalStrength() {
sendATCommand("AT+CSQ", 2000);
}
void checkSIMStatus() {
sendATCommand("AT+CPIN?", 2000);
}
void restartModem() {
sendATCommand("AT+CFUN=1,1", 5000);
delay(10000);
}
void resetAndConfigureModem() {
sendATCommand("AT+CFUN=1,1", 10000);
delay(10000);
sendATCommand("AT+CNMP=2", 2000);
sendATCommand("AT+CMNB=1", 2000);
}
void selectOperator() {
sendATCommand("AT+COPS=?", 2000);
sendATCommand("AT+COPS=1,2,\"26003\"", 2000);
delay(10000);
}
void configureBand() {
sendATCommand("AT+CBAND?", 2000);
sendATCommand("AT+CBAND=\"ALL_BAND\"", 2000);
}
void setupGPRS() {
sendATCommand("AT+CGATT=1", 10000);
configureAPN();
}
void configureAPN() {
sendATCommand("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", 5000);
sendATCommand("AT+SAPBR=3,1,\"APN\",\"internet\"", 5000);
sendATCommand("AT+SAPBR=1,1", 5000);
sendATCommand("AT+SAPBR=2,1", 5000);
}
void sendToZabbix(String url) {
sendATCommand("AT+HTTPINIT", 5000);
sendATCommand("AT+HTTPPARA=\"CID\",1", 5000);
sendATCommand("AT+HTTPPARA=\"URL\",\"" + url + "\"", 5000);
sendATCommand("AT+HTTPACTION=0", 10000);
sendATCommand("AT+HTTPTERM", 5000);
}
void checkSMS() {
sendATCommand("AT+CMGF=1", 2000);
sendATCommand("AT+CPMS=\"SM\",\"SM\",\"SM\"", 2000);
String response = sendATCommand("AT+CMGL=\"REC UNREAD\"", 5000);
// Logowanie odpowiedzi
Serial.println("Odpowiedź AT+CMGL: " + response);
if (response.indexOf("+CMGL") >= 0) {
// Przechowywanie odebranych SMS-ów
receivedSMS.push_back(response);
} else {
Serial.println("Brak nowych SMS-ów.");
}
// Przykładowa analiza odebranych SMS
while (sim800l.available()) {
String smsContent = "";
while (sim800l.available()) {
char c = sim800l.read();
smsContent += c;
}
String senderNumber;
parseSenderNumber(smsContent, senderNumber);
}
}
void parseSenderNumber(String &smsContent, String &senderNumber) {
int index = smsContent.indexOf("+CMGR:");
if (index >= 0) {
int start = smsContent.indexOf("\"", index + 1) + 1;
int end = smsContent.indexOf("\"", start);
senderNumber = smsContent.substring(start, end);
}
}
bool sendSMS(String number, String message) {
sendATCommand("AT+CMGS=\"" + number + "\"", 2000);
sim800l.print(message);
sim800l.write(26);
long int time = millis();
String response = "";
while ((millis() - time) < 10000) {
while (sim800l.available()) {
char c = sim800l.read();
response += c;
}
}
Serial.println("Odpowiedź: " + response);
if (response.indexOf("OK") != -1) {
return true;
} else {
return false;
}
}
void monitorConnection() {
checkNetworkConnection();
checkSignalStrength();
checkSIMStatus();
if (!isConnected) {
setupGPRS();
}
}
#ifndef SIM800L_H
#define SIM800L_H
#include <HardwareSerial.h>
#include <vector>
extern const char SIM_PIN[];
extern HardwareSerial sim800l;
extern bool isConnected;
extern std::vector<String> receivedSMS;
#define RX_PIN 16
#define TX_PIN 4
void sim800lSetup();
String sendATCommand(String command, int timeout);
bool isRegistered(String response);
void checkNetworkConnection();
void checkSignalStrength();
void checkSIMStatus();
void restartModem();
void configureNetworkMode();
void resetAndConfigureModem();
void selectOperator();
void configureBand();
void setupGPRS();
void configureAPN();
void sendToZabbix(String url);
void checkSMS();
// void processSMS(String smsContent, String senderNumber);
bool sendSMS(String number, String message);
void monitorConnection();
void parseSenderNumber(String &smsContent, String &senderNumber);
#endif
Network.h i Network.cpp – obsługa sieci ETH / WIFI
#include "Network.h"
const char* ssid = "your_ssid_wifi";
const char* password = "your_pass_wifi";
void WiFiEvent(WiFiEvent_t event) {
switch (event) {
case SYSTEM_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
break;
case SYSTEM_EVENT_ETH_START:
Serial.println("ETH Started");
ETH.setHostname("esp32-ethernet");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
Serial.print("ETH IP: ");
Serial.println(ETH.localIP());
break;
case SYSTEM_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
break;
default:
break;
}
}
void setupEthernet() {
WiFi.onEvent(WiFiEvent);
ETH.begin();
}
void setupWiFi() {
Serial.println("Connecting to Wi-Fi...");
WiFi.begin(ssid, password);
int maxAttempts = 20;
int attempt = 0;
while (WiFi.status() != WL_CONNECTED && attempt < maxAttempts) {
delay(500);
Serial.print(".");
attempt++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println();
Serial.print("WiFi connected. IP address: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("Failed to connect to Wi-Fi");
}
}
#ifndef NETWORK_H
#define NETWORK_H
#include <ETH.h>
#include <WiFi.h>
void WiFiEvent(WiFiEvent_t event);
void setupEthernet();
void setupWiFi();
#endif
HTTPServer.h HTTPServer.cpp – serwer http do obsługi POST / GET
#include "HTTPServer.h"
#include "SIM800L.h"
WebServer server(80);
void handleSendSMS() {
if (server.hasArg("number") && server.hasArg("message")) {
String number = server.arg("number");
String message = server.arg("message");
bool status = sendSMS(number, message);
if (status) {
server.send(200, "application/json", "{\"statusSend\": true}");
} else {
server.send(200, "application/json", "{\"statusSend\": false}");
}
} else {
server.send(400, "application/json", "{\"error\": \"Missing number or message argument\"}");
}
}
void handleCheckSMS() {
String response = "List of received SMS:\n";
for (const auto& sms : receivedSMS) {
response += sms + "\n";
}
server.send(200, "text/plain", response);
}
void setupServer() {
server.on("/sendSMS", HTTP_POST, handleSendSMS);
server.on("/checkSMS", HTTP_GET, handleCheckSMS);
server.begin();
Serial.println("HTTP server started");
}
#ifndef HTTPSERVER_H
#define HTTPSERVER_H
#include <WebServer.h>
extern WebServer server;
void handleSendSMS();
void handleCheckSMS();
void setupServer();
#endif
Wysyłanie SMS przez HTTP POST
Aby wysłać SMS, możemy wykonać żądanie HTTP POST na endpoint /sendSMS
z parametrami number
i message
.
Przykładowe żądanie:
POST /sendSMS HTTP/1.1
Host: <IP_ESP32>
Content-Type: application/json
{
"number": "+48123456789",
"message": "Testowa wiadomość"
}
Sprawdzanie Odebranych SMS
Aby sprawdzić odebrane SMS-y, możemy wykonać żądanie HTTP GET na endpoint /checkSMS
.
Przykładowe żądanie:
GET /checkSMS HTTP/1.1 Host: <IP_ESP32>
Pełen kod github możesz przejrzeć tutaj: