#include <HardwareSerial.h>
#include <Wire.h> // For I2C OLED communication
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Define RX and TX pins for serial communication between ESP32 and SIM800L
#define SIM800L_RX_PIN 16 // ESP32 RX pin connected to SIM800L TX
#define SIM800L_TX_PIN 17 // ESP32 TX pin connected to SIM800L RX
// Define pin for the LED indicator
#define LED_PIN 2 // Example GPIO2 pin for LED, can be changed as needed
// Define pin for the push button
#define BUTTON_PIN 4 // Example GPIO4 pin for button, can be changed as needed
// Connect one side of the button to this pin, and the other side to GND.
// Internal pull-up resistor will be enabled.
// OLED screen dimensions (128x64)
#define SCREEN_WIDTH 128 // OLED width in pixels
#define SCREEN_HEIGHT 64 // OLED height in pixels
// Declare SSD1306 object (OLED I2C address 0x3C or 0x3D)
// Change 0x3C if your OLED uses address 0x3D
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Create HardwareSerial object for SIM800L
HardwareSerial sim800lSerial(1); // Use UART1 on ESP32 (UART0 is used for Serial debugging)
// --- Function Prototype Declarations ---
// Function to send AT command and read its response
String sendATCommand(String command);
// Function to get and display signal strength on OLED
void getAndDisplaySignalStrength();
// Function to send SMS
void sendSMS(String phoneNumber, String message);
// Function to control LED status based on "ping" result
void setLedStatus(bool pingSuccess);
// Function to make a phone call
void makeCall(String phoneNumber, int callDurationSeconds);
// Variables for button debouncing
long lastButtonPressTime = 0; // Last time the button was pressed
const long debounceDelay = 50; // Debounce time in milliseconds
void setup() {
// Initialize serial communication for debugging (serial monitor)
Serial.begin(115200);
Serial.println("Starting ESP32, SIM800L, OLED, LED, and Button connection test...");
// Initialize LED pin as output
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW); // Ensure LED is off at initialization
// Initialize button pin as input with internal pull-up resistor
// The button should be wired to connect this pin to GND when pressed.
pinMode(BUTTON_PIN, INPUT_PULLUP);
Serial.println("Button pin initialized with INPUT_PULLUP.");
// Initialize OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Common I2C address for OLED
Serial.println(F("SSD1306 allocation failed"));
for (;;) ; // Don't proceed if failed, stop here
}
display.display(); // Show Adafruit boot-up logo
delay(2000);
display.clearDisplay(); // Clear display
display.setTextSize(1); // Text size 1
display.setTextColor(SSD1306_WHITE); // White text color
// Display initialization message on OLED
display.setCursor(0, 0);
display.println("ESP32 + SIM800L");
display.println("Initializing...");
display.display();
delay(2000);
// Initialize serial communication for SIM800L
// Baud rate 9600, 8 data bits, no parity, 1 stop bit
sim800lSerial.begin(9600, SERIAL_8N1, SIM800L_RX_PIN, SIM800L_TX_PIN);
delay(1000); // Give module time to stabilize
// --- SIM800L Module and LED Indicator Test ---
Serial.println("Sending AT command to check connection...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Checking GSM Conn...");
display.display();
// Send AT command and update LED status
String atResponse = sendATCommand("AT");
// Update LED status: ON if "OK", blink if not
setLedStatus(atResponse.indexOf("OK") != -1);
delay(1000);
Serial.println("Sending AT+CSQ to check signal quality...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Checking Signal...");
display.display();
// Call function to get and display signal (this function also calls sendATCommand)
getAndDisplaySignalStrength();
delay(2000);
Serial.println("Sending AT+CREG? to check network registration...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Registering Net...");
display.display();
// Send AT+CREG? command and update LED status
String cregResponse = sendATCommand("AT+CREG?");
setLedStatus(cregResponse.indexOf("OK") != -1); // Update LED based on CREG response
delay(2000); // Give more time for network registration if needed
Serial.println("Attempting to send SMS...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Sending SMS...");
display.display();
// Send SMS (this function also calls sendATCommand and updates LED)
sendSMS("+628112508805", "Halo dari ESP32 dan SIM800L!");
delay(3000); // Give time after SMS sending
// --- Initial Phone Call Test (for verification during setup) ---
Serial.println("Attempting to make a phone call (initial test)...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Initial Call Test...");
display.display();
// Make a call to the same number, duration 10 seconds
makeCall("+628112508805", 10);
delay(3000); // Give time after call
// Final test message on OLED
display.clearDisplay();
display.setCursor(0, 0);
display.println("Test Complete!");
display.println("Press Button for Call.");
display.display();
}
void loop() {
// In the loop, we can update signal strength and "ping" periodically
// to keep the LED indicator relevant.
static unsigned long lastPingTime = 0;
static unsigned long pingInterval = 10000; // Ping every 10 seconds
if (millis() - lastPingTime >= pingInterval) {
lastPingTime = millis();
Serial.println("Performing ping (AT command) for LED indicator...");
String atResponseLoop = sendATCommand("AT");
setLedStatus(atResponseLoop.indexOf("OK") != -1); // Update LED status
getAndDisplaySignalStrength(); // Update signal strength on OLED and LED
}
// --- Button Check Logic ---
// Read the state of the button. Since INPUT_PULLUP is used, it's LOW when pressed.
int buttonState = digitalRead(BUTTON_PIN);
// Check if the button is pressed (LOW) and if enough time has passed since the last press
if (buttonState == LOW && (millis() - lastButtonPressTime) > debounceDelay) {
// Check if the button was just pressed (not held down from previous loop)
if (lastButtonPressTime != 0) { // Only trigger if it's a new press
Serial.println("Button Pressed! Initiating call...");
display.clearDisplay();
display.setCursor(0,0);
display.println("Button Pressed!");
display.println("Calling...");
display.display();
delay(500); // Brief delay for display update
// Trigger the makeCall function
makeCall("+628112508805", 15); // Call duration of 15 seconds when button is pressed
display.clearDisplay();
display.setCursor(0,0);
display.println("Call Initiated.");
display.println("Ready for next press.");
display.display();
}
lastButtonPressTime = millis(); // Record the time of this press
} else if (buttonState == HIGH) {
lastButtonPressTime = 0; // Reset debounce timer if button is released
}
}
// Function to send AT command to SIM800L and read its response
String sendATCommand(String command) {
Serial.print("Sending: ");
Serial.println(command);
sim800lSerial.println(command); // Send command to SIM800L
String response = "";
long timeout = millis();
// Wait for response for 2 seconds
while (millis() - timeout < 2000) {
if (sim800lSerial.available()) {
char c = sim800lSerial.read(); // Read character from SIM800L
Serial.write(c); // Write character to Serial Monitor for debugging
response += c; // Add character to response string
}
}
Serial.println(); // New line for clarity in Serial Monitor
return response; // Return the complete response string
}
// Function to control LED status based on "ping" result
// If pingSuccess TRUE (module responds with "OK"), LED stays on.
// If pingSuccess FALSE (module does not respond with "OK" or timeout), LED blinks fast.
void setLedStatus(bool pingSuccess) {
if (pingSuccess) {
digitalWrite(LED_PIN, HIGH); // LED ON (stable light)
Serial.println("LED ON: Module responded with OK.");
} else {
Serial.println("LED BLINK: Module did not respond OK (timeout or error).");
for (int i = 0; i < 5; i++) { // Blink fast 5 times
digitalWrite(LED_PIN, HIGH); // LED on
delay(100); // Short delay
digitalWrite(LED_PIN, LOW); // LED off
delay(100); // Short delay
}
digitalWrite(LED_PIN, LOW); // Ensure LED is off after blinking
}
}
// Function to get and display signal strength (RSSI) on OLED
void getAndDisplaySignalStrength() {
String response = sendATCommand("AT+CSQ"); // Send AT+CSQ and get response
// Update LED status based on AT+CSQ response as well
setLedStatus(response.indexOf("OK") != -1);
int rssi = -1; // Default value if not found
int commaIndex = response.indexOf(','); // Find the first comma
// Check if response contains "+CSQ:" and a comma
if (response.indexOf("+CSQ:") != -1 && commaIndex != -1) {
// Extract RSSI string
String rssiStr = response.substring(response.indexOf(":") + 1, commaIndex);
rssi = rssiStr.toInt(); // Convert to integer
}
// Display signal information on OLED
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.println("Signal Strength:");
display.setTextSize(2); // Larger text size for RSSI value
if (rssi >= 0 && rssi <= 31) { // Check if RSSI is valid
display.print("RSSI: ");
display.print(rssi);
display.print(" (");
display.print(-113 + rssi * 2); // Rough conversion to dBm (for reference)
display.println(" dBm)");
display.setTextSize(1);
display.print("Status: ");
if (rssi >= 20) {
display.println("Very Good");
} else if (rssi >= 10) {
display.println("Good");
} else if (rssi >= 2) {
display.println("Fair");
} else {
display.println("Weak/None");
}
} else {
display.println("Unknown"); // If RSSI is invalid
}
display.display(); // Display on OLED screen
}
// Function to send SMS to a specific phone number with a specific message
void sendSMS(String phoneNumber, String message) {
Serial.println("Setting SMS mode to Text Mode...");
// Set module to SMS Text Mode and update LED status
String modeResponse = sendATCommand("AT+CMGF=1");
setLedStatus(modeResponse.indexOf("OK") != -1);
delay(1000); // Give module time to respond
Serial.print("Sending SMS to: ");
Serial.println(phoneNumber);
sim800lSerial.print("AT+CMGS=\""); // Command to send SMS
sim800lSerial.print(phoneNumber); // Destination number
sim800lSerial.println("\""); // End command with quote and new line
delay(100); // Give a little time
sim800lSerial.print(message); // Send message content
sim800lSerial.write(0x1A); // Ctrl+Z character to end message and trigger sending
Serial.println("Message sent. Waiting for confirmation...");
String smsConfirmation = "";
long timeout = millis();
// Wait for SMS sending confirmation response for 10 seconds
while (millis() - timeout < 10000) {
if (sim800lSerial.available()) {
char c = sim800lSerial.read();
Serial.write(c);
smsConfirmation += c;
}
}
Serial.println();
// Update LED status: ON if SMS confirmed OK or +CMGS:, BLINK if error/timeout
setLedStatus(smsConfirmation.indexOf("OK") != -1 || smsConfirmation.indexOf("+CMGS:") != -1);
}
// Function to make a phone call to the specified number
// The call will automatically hang up after callDurationSeconds
void makeCall(String phoneNumber, int callDurationSeconds) {
Serial.print("Making call to: ");
Serial.println(phoneNumber);
display.clearDisplay();
display.setCursor(0,0);
display.println("Calling:");
display.println(phoneNumber);
display.display();
String callResponse = sendATCommand("ATD" + phoneNumber + ";"); // Dial command, ';' is important
// Update LED status: ON if module accepts dial command ("OK"), BLINK if not
setLedStatus(callResponse.indexOf("OK") != -1);
if (callResponse.indexOf("OK") != -1) {
Serial.println("Call started. Waiting for connection or timeout...");
display.clearDisplay();
display.setCursor(0,0);
display.println("Call In Progress...");
display.println(phoneNumber);
display.display();
// Wait for the specified call duration
delay(callDurationSeconds * 1000);
Serial.println("Ending call...");
display.clearDisplay();
display.setCursor(0,0);
display.println("Ending Call...");
display.display();
String hangupResponse = sendATCommand("ATH"); // Command to hang up the call
// Update LED based on ATH response
setLedStatus(hangupResponse.indexOf("OK") != -1);
delay(1000); // Give module time to hang up
Serial.println("Call ended.");
} else {
Serial.println("Failed to start call or invalid number.");
display.clearDisplay();
display.setCursor(0,0);
display.println("Call Failed!");
display.println("Check Signal/Number.");
display.display();
// LED is already set to BLINK by sendATCommand if failed
}
}
No comments:
Post a Comment