OTA UPDATES ON ESP32 WITH SIM7500 #
Introduction #
The ESP32 microcontroller, in conjunction with the SIM7500 module, enables over-the-air (OTA) firmware updates. By storing the latest firmware on a GitHub repository, the ESP32 can periodically check for updates and download them via GPRS, ensuring that the device always runs the most recent version of the firmware. This process eliminates the need for physical access to the device and allows for efficient deployment of new features and security patches.
Project Overview #
The firmware update process works as follows:
- Current Version Check: The ESP32 checks the version.txt file in the GitHub repository to determine the latest firmware version.
- New Firmware Detection: If a new version is detected (i.e., different from the current firmware version running on the ESP32), the device downloads the latest (firmware_vX.X.X.bin) firmware file.
- OTA Update: The ESP32 initiates the OTA update and installs the new firmware. Once the update is complete, the ESP32 restarts and runs the new firmware.
Branch Setup
• The release branch of your GitHub repository should contain:
o The latest firmware file (firmware_vX.X.X.bin)
o A version.txt file that stores the version number of the latest firmware.
/release/
├── firmware_v1.0.1.bin
├── version.txt
• version.txt: This file should contain only the version number of the latest firmware. e.g., 1.0.1
Key components
• SIM7500 Module: Responsible for connecting to the internet via GPRS and making HTTPS requests.
• TinyGSM and SSLClient Libraries: Used for secure communication with the GitHub repository.
• ArduinoHttpClient Library: Handles the GET request to fetch the firmware version and download the binary file.
• Root CA Certificate: As GitHub uses HTTPS, the CA root certificate for raw.githubusercontent.com must be uploaded to the SIM module to ensure secure communication. This is required since the OTA process downloads the firmware from a secure GitHub URL. The cert.h file in this repository contains the CA root certificate.
Software Setup #
A. Install the ESP32 board in Arduino IDE:
- a. Go to File > Preferences.
- b. Go to Tools > Boards > Boards Manager, search for “ESP32”, and install.
- c. OTA on ESP32 (https://github.com/IndustrialArduino/OTA-on-ESP.git )
B. Install Required Libraries (Arduino):
a. Go to Sketch > Include Library > Manage Libraries and install:
- Wire.h, Update.h: For communication and OTA functionality
- TinyGsmClient.h: For GSM modem communication.
- ArduinoHttpClient.h: For making HTTP requests
- SSLClient.h: For secure communication.
- cert.h: Contains the CA certificate needed for HTTPS communication.
C. Configure the code:
- Open the code provided in your Arduino IDE.
- Replace the GPRS credentials (apn, user, pass) with your SIM card provider details.
- Set the correct server (raw.githubusercontent.com) and firmware version file paths.
Code Explanation #
This Arduino code demonstrates how to implement an Over-The-Air (OTA) firmware update on an ESP32 using a SIM7500 modem to connect to the internet. The program fetches the latest firmware version from a GitHub repository, compares it with the current version running on the device, and downloads the new firmware if necessary. Here’s a breakdown of the key components of the code.
- part 1
#include <Arduino.h>
#include <Wire.h>
#include <Update.h>
#define TINY_GSM_MODEM_SIM7500
// Increase RX buffer
#define TINY_GSM_RX_BUFFER 1030
#include <TinyGsmClient.h>
#include <ArduinoHttpClient.h>
#include "SSLClient.h"
#include "cert.h"
#define TINY_GSM_TEST_GPRS true
#define TINY_GSM_TEST_TCP true
#define SerialMon Serial
#define SerialAT Serial1
#define GSM_PIN ""
// Your GPRS credentials
const char apn[] = "dialogbb";
const char user[] = "";
const char pass[] = "";
const char server[] = "raw.githubusercontent.com";
const int port = 443;
#define CURRENT_VERSION_ADDR 2
#define UART_BAUD 115200
#define MODEM_TX 32
#define MODEM_RX 33
#define GSM_RESET 21
This Part defines essential libraries, constants, and variables for an OTA firmware update project on an ESP32 using the SIM7500 module. It includes libraries for communication, HTTP requests, and SSL, and defines parameters for the GSM module, GPRS credentials, and firmware update settings.
- part 2
String current_version = "1.0.0";
String new_version;
const char version_url[] = "/IndustrialArduino/OTA-on-ESP/release/version.txt";
String firmware_url;
//variabls to blink without delay:
const int led1 = 2;
const int led2 = 12;
unsigned long previousMillis = 0; // will store last time LED was updated
const long interval = 1000; // interval at which to blink (milliseconds)
int ledState = LOW; // ledState used to set the LED
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
// HTTPS Transport
TinyGsmClient base_client(modem, 0);
SSLClient secure_layer(&base_client);
HttpClient client = HttpClient(secure_layer, server, port);
This code initializes variables for firmware versions and LED control. It defines the URL of the text file containing the latest version number and sets up the HTTPS transport for communication with the SIM7500 module. Additionally, it includes conditional compilation for debugging output based on the DUMP_AT_COMMANDS preprocessor directive.
- Part 3
void setup() {
// Set console baud rate
Serial.begin(115200);
delay(10);
SerialAT.begin(UART_BAUD, SERIAL_8N1, MODEM_RX, MODEM_TX);
delay(2000);
pinMode(GSM_RESET, OUTPUT);
digitalWrite(GSM_RESET, HIGH); // RS-485
delay(10);
SerialMon.println("Wait...");
//Add CA Certificate
secure_layer.setCACert(root_ca);
Serial.println("Initializing modem...");
modem.restart();
String modemInfo = modem.getModemInfo();
Serial.print("Modem: ");
Serial.println(modemInfo);
Serial.print("Waiting for network...");
if (!modem.waitForNetwork())
{
Serial.println(" fail");
delay(10000);
return;
}
Serial.println(" OK");
Serial.print("Connecting to ");
Serial.print(apn);
if (!modem.gprsConnect(apn, user, pass))
{
Serial.println(" fail");
delay(10000);
return;
}
Serial.println(" OK");
This code initializes serial communication, resets the SIM7500 module, adds the CA certificate for secure communication, and establishes a GPRS connection. It checks for network connectivity and prints relevant information to the serial monitor, providing feedback on the setup process.
- Part 4
void loop() {
if (checkForUpdate(firmware_url)) {
performOTA(firmware_url.c_str());
}
delay(1000);
//add the code need to run and this is an example program
//loop to blink without delay
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
ledState = not(ledState);
// set the LED with the ledState of the variable:
digitalWrite(led1, ledState);
digitalWrite(led2, ledState);
}
}
This code loop() function continuously checks for firmware updates by calling the check ForUpdate() function. If an update is available, the performOTA() function is executed to download and install the new firmware. A delay of 1000 milliseconds is then added to prevent excessive polling. The code also includes an example program that blinks two LEDs without using delays, demonstrating the basic structure for adding other functionalities to the main loop.
- Part 5
//Check the version of the latest firmware which has uploaded to Github
bool checkForUpdate(String &firmware_url) {
Serial.println("Making GET request securely...");
client.get(version_url);
int status_code = client.responseStatusCode();
delay(1000);
String response_body = client.responseBody();
delay(1000);
Serial.print("Status code: ");
Serial.println(status_code);
Serial.print("Response: ");
Serial.println(response_body);
response_body.trim();
response_body.replace("\r", ""); // Remove carriage returns
response_body.replace("\n", ""); // Remove newlines
// Extract the version number from the response
new_version = response_body;
Serial.println("Current version: " + current_version);
Serial.println("Available version: " + new_version);
client.stop();
if (new_version != current_version) {
Serial.println("New version available. Updating...");
firmware_url = String("/IndustrialArduino/OTA-on-ESP/release/firmware_v") + new_version + ".bin";
Serial.println("Firmware URL: " + firmware_url);
return true;
} else {
Serial.println("Already on the latest version");
}
return false;
}
//Update the latest firmware which has uploaded to Github
void performOTA(const char* firmware_url) {
// Initialize HTTP
Serial.println("Making GET request securely...");
client.get(firmware_url);
int status_code = client.responseStatusCode();
delay(1000);
long contentlength = client.contentLength();
delay(1000);
Serial.print("Contentlength: ");
Serial.println(contentlength);
if (status_code == 200) {
if (contentlength <= 0) {
SerialMon.println("Failed to get content length");
client.stop();
return;
}
This code checks for updates by making a GET request to the GitHub repository and extracting the latest version number from the response. It compares the current version with the available version and updates the firmware URL if a new version is found. The code also prints relevant information to the serial monitor, including the status code, response body, and current and available versions.
- Part 6
// Begin OTA update
bool canBegin = Update.begin(contentlength);
size_t written ;
long totalBytesWritten = 0;
uint8_t buffer[1024];
int bytesRead ;
long contentlength_real = contentlength;
if (canBegin) {
while (contentlength > 0) {
bytesRead = client.readBytes(buffer, sizeof(buffer));
if (bytesRead > 0) {
written = Update.write(buffer, bytesRead);
if (written != bytesRead) {
Serial.println("Error: written bytes do not match read bytes");
Update.abort();
return;
}
totalBytesWritten += written; // Track total bytes written
contentlength -= bytesRead; // Reduce remaining content length
} else {
Serial.println("Error: Timeout or no data received");
break;
}
}
if (totalBytesWritten == contentlength_real) {
Serial.println("Written : " + String(totalBytesWritten) + " successfully");
} else {
Serial.println("Written only : " + String(written) + "/" + String(contentlength_real) + ". Retry?");
}
if (Update.end()) {
SerialMon.println("OTA done!");
if (Update.isFinished()) {
SerialMon.println("Update successfully completed. Rebooting.");
delay(300);
ESP.restart();
} else {
SerialMon.println("Update not finished? Something went wrong!");
}
} else {
SerialMon.println("Error Occurred. Error #: " + String(Update.getError()));
}
} else {
Serial.println("Not enough space to begin OTA");
}
} else {
Serial.println("Cannot download firmware. HTTP code: " + String(status_code));
}
client.stop();
}
This code implements an OTA (Over-the-Air) update mechanism for an ESP32 device. It first checks if there’s enough space to initiate the update. If so, it downloads the firmware from a specified server, writes it to the device’s flash memory, and verifies the integrity of the written data. Finally, it reboots the device to apply the new firmware. If any errors occur during the process, the update is aborted, and an error message is displayed.
How OTA Update work #
1.Version Check: The ESP32 sends a request to the server (GitHub) to check the latest firmware version by fetching a simple text file version.txt.
- Current version on ESP32: 1.0.0.
- Latest version from the server: e.g., 1.1.0.
2.Download Firmware: If a newer version is detected, the firmware binary is downloaded securely via HTTPS. The firmware file is hosted at a URL like:https://github.com/yknivag/ESP_OTA_GitHub
3.Perform OTA Update: The downloaded binary is written to the ESP32’s memory. After a successful update, the ESP32 will restart automatically and run the new firmware.
Testing setup #
1.Upload the Initial Firmware
- Compile and upload the firmware to the ESP32 with the initial version (1.0.0).
- Verify that the device is connected to the GSM network.
2.Host a New Firmware
- After making changes to the code export the code as binary and then rename the binary file
- as the new version of the firmware (e.g., 1.1.0) and upload the binary file to your server.
- Update the version.txt file to reflect the new version number.
- Monitor the Update
- Open the Serial Monitor at 115200 baud.
The ESP32 will:
• Connect to the GSM network.
• Fetch the latest version from the server.
• Compare the versions.
• If an update is available, it will download the firmware and install it.
• Reboot the device with the updated firmware.
3.Expected Output:
• ESP32 logs network connection and update status.
• If an update is available, the new firmware is downloaded and applied.
Error Handling #
Connection Failure: Ensure that the APN, username, and password are correct for your SIM card provider. Check for proper power supply to the SIM7500 module
• HTTPS Failures: If there are SSL/HTTPS errors, verify that the root CA certificate is properly loaded in the cert.h file.
• OTA Failures: If the update fails, the device will continue running the current version. Ensure that the binary file is correct and available at the specified URL.
Troubleshooting #
ESP32 Doesn’t Connect to Cellular Network:
• Double-check the wiring between the SIM7500 and the ESP32.
• Make sure the SIM card has an active data plan and is properly inserted.
OTA Update Fails:
• Check the size of the binary file and ensure there’s enough memory on the ESP32for the update.
• Ensure the server is reachable, and the firmware URL is correct.
HTTPS Request Fails:
• Confirm that the root CA is correctly added for HTTPS communication.
• Check if the GitHub URL is accessible and the server isn’t blocking your requests.