#include <WiFi.h>
#include <PubSubClient.h>
#include <HTTPClient.h>
#include <Update.h>
// #define HOST "https://dl.dropboxusercontent.com/s/yol6sdu89gdvrrl/OTAWebUpdaterTest.ino.bin?dl=0"
int totalLength; //total size of firmware
int currentLength = 0; //current size of written firmware
WiFiClient WifiClient;
PubSubClient MqttClient("learning.masterofthings.com", 1883, WifiClient);
HTTPClient HttpClient;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("This is Version 1");
ConnectWiFi();
ConnectMQTT();
}
void loop() {
// Reconnect WiFi if Disconnected
if (WiFi.status() != WL_CONNECTED) {
ConnectWiFi();
}
//Reconnect MQTT if Disconnected
if (!MqttClient.connected()) {
ConnectMQTT();
}
// This should be called regularly to allow the client to process incoming messages and maintain its connection to the server.
MqttClient.loop();
}
void ConnectWiFi() {
WiFi.begin("Wokwi-GUEST", "");
Serial.print("WiFi Connecting");
delay(100);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("\nConnected to the WiFi network, Local IP:");
Serial.println(WiFi.localIP());
}
void ConnectMQTT() {
MqttClient.setCallback(MqttMessageCallback);
while (!MqttClient.connected()) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Attemping MQTT Connection While WiFi disconnected");
break;
} else {
Serial.println("Attempting MQTT connection");
if (MqttClient.connect("ESP_TestOTA", "ESP_18399400664700", "ESP_18399400664700")) {
Serial.println("MQTT Connected");
MqttClient.subscribe("ESP_18399400664700/Update");
} else {
Serial.println("failed to connect MQTT. try again in 2 seconds");
delay(2000);
}
}
}
}
void MqttMessageCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived. Topic:[");
Serial.print(topic);
Serial.print("], Message(");
String Payload = "";
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
Payload += (char)payload[i];
}
Serial.println(")");
//Check message and topic then take action
if (String(topic) == "ESP_18399400664700/Update") {
UpdateFOTA(Payload);
} else {
Serial.println("Undefiend topic");
}
}
void UpdateFOTA(String firmwareUrl) {
Serial.print("Attemp firmware download, URL : ");
Serial.println(firmwareUrl);
// Connect to external web server
HttpClient.begin(firmwareUrl);
// Get file, just to check if each reachable
int resp = HttpClient.GET();
Serial.print("Response: ");
Serial.println(resp);
// If file is reachable, start downloading
if (resp == 200) {
// get length of document (is -1 when Server sends no Content-Length header)
totalLength = HttpClient.getSize();
// transfer to local variable
int len = totalLength;
// this is required to start firmware update process
Update.begin(UPDATE_SIZE_UNKNOWN);
Serial.printf("FW Size: %u\n", totalLength);
// create buffer for read
uint8_t buff[128] = { 0 };
// get tcp stream
WiFiClient* stream = HttpClient.getStreamPtr();
// read all data from server
Serial.println("Updating firmware...");
while (HttpClient.connected() && (len > 0 || len == -1)) {
// get available data size
size_t size = stream->available();
if (size) {
// read up to 128 byte
int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
// pass to function
WriteFirmware(buff, c);
if (len > 0) {
len -= c;
}
}
delay(1);
}
} else {
Serial.println("Cannot download firmware file. Only HTTP response 200: OK is supported.");
}
HttpClient.end();
}
void WriteFirmware(uint8_t* data, size_t len) {
Update.write(data, len);
currentLength += len;
// Print dots while waiting for update to finish
int percent = map(currentLength, 0, totalLength, 0, 100);
Serial.println(percent);
// if current length of written firmware is not equal to total firmware size, repeat
if (currentLength != totalLength) return;
Update.end(true);
Serial.printf("\nUpdate Success, Total Size: %u\nRebooting...\n", currentLength);
// Restart ESP32 to see changes
ESP.restart();
}