[OTA] Enable 2 clicks OTA update / one simple MQTT command (#1485)

* [OTA] Add automatic OTA updates

This feature will enable to update the gateway with one button or a simple MQTT command.

* [CI] Enable automatic OTA for nightly development builds

And integrate the latest_version file creation into the CI

Enable to specify a particular version
and switch between dev and production builds
This commit is contained in:
Florian authored and GitHub committed 2023-02-27 12:54:30 -06:00
1 parent e83bfb0e4d
commit 454a062b3b
15 files changed
+186 -54

No files matched your search

+9 -1
View File
@@ -238,6 +238,14 @@ CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
# ifndef MQTT_HTTPS_FW_UPDATE_USE_PASSWORD
# define MQTT_HTTPS_FW_UPDATE_USE_PASSWORD 1 // Set this to 0 if not using TLS connection to MQTT broker to prevent clear text passwords being sent.
# endif
# if DEVELOPMENTOTA
# define OTA_JSON_URL "https://github.com/1technophile/OpenMQTTGateway/raw/gh-pages/dev/firmware_build/latest_version_dev.json" //OTA url used to discover new versions of the firmware from development nightly builds
# else
# define OTA_JSON_URL "https://github.com/1technophile/OpenMQTTGateway/raw/gh-pages/firmware_build/latest_version.json" //OTA url used to discover new versions of the firmware
# endif
# define ENTITY_PICTURE "https://github.com/1technophile/OpenMQTTGateway/raw/development/docs/img/Openmqttgateway_logo_mini_margins.png"
# define RELEASE_LINK_DEV "https://github.com/1technophile/OpenMQTTGateway/raw/gh-pages/dev/firmware_build/"
# define RELEASE_LINK "https://github.com/1technophile/OpenMQTTGateway/releases/download/"
# endif
# ifndef MQTT_SECURE_SELF_SIGNED
@@ -558,7 +566,6 @@ CRGB leds2[FASTLED_IND_NUM_LEDS];
#define subjectMQTTtoX "/commands/#"
#define subjectMultiGTWKey "toMQTT"
#define subjectGTWSendKey "MQTTto"
#define subjectFWUpdate "firmware_update"
// key used for launching commands to the gateway
#define restartCmd "restart"
@@ -599,6 +606,7 @@ CRGB leds2[FASTLED_IND_NUM_LEDS];
#define InitialMQTTConnectionTimeout 10 // time estimated (s) before the board is connected to MQTT
#define subjectSYStoMQTT "/SYStoMQTT"
#define subjectMQTTtoSYSset "/commands/MQTTtoSYS/config"
#define subjectMQTTtoSYSupdate "/commands/MQTTtoSYS/firmware_update"
#define TimeToResetAtStart 5000 // Time we allow the user at start for the reset command by button press
/*-------------------DEFINE LOG LEVEL----------------------*/
#ifndef LOG_LEVEL
+12 -1
View File
@@ -287,8 +287,10 @@ void createDiscovery(const char* sensor_type,
sensor["pl_prs"] = payload_on; // payload_press for a button press
} else if (strcmp(sensor_type, "number") == 0) {
sensor["cmd_tpl"] = payload_on; // payload_on for a switch
} else if (strcmp(sensor_type, "update") == 0) {
sensor["payload_install"] = payload_on; // payload_install for update
} else {
sensor["pl_on"] = payload_on; // payload_on for a switch
sensor["pl_on"] = payload_on; // payload_on for the rest
}
}
if (payload_off[0])
@@ -530,6 +532,15 @@ void pubMqttDiscovery() {
"", "", "", "", false, // device name, device manufacturer, device model, device ID, retain
stateClassNone //State Class
);
createDiscovery("update", //set Type
subjectSYStoMQTT, "SYS: Firmware Update", (char*)getUniqueId("update", "").c_str(), //set state_topic,name,uniqueId
will_Topic, "firmware", "", //set availability_topic,device_class,value_template,
LATEST_OR_DEV, "", "", //set,payload_on,payload_off,unit_of_meas,
0, //set off_delay
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoSYSupdate, //set,payload_available,payload_not available ,is a gateway entity, command topic
"", "", "", "", false, // device name, device manufacturer, device model, device ID, retain
stateClassNone //State Class
);
# ifdef ZsensorBME280
# define BMEparametersCount 5
Log.trace(F("bme280Discovery" CR));
+6
View File
@@ -268,4 +268,10 @@ const char* availableHASSUnits[] = {"W",
"mm/h",
"cm"};
// Define the command used to update through OTA depending if we want to update from dev nightly or latest release
#if DEVELOPMENTOTA
# define LATEST_OR_DEV "{\"version\":\"dev\"}"
#else
# define LATEST_OR_DEV "{\"version\":\"latest\"}"
#endif
#endif
+78 -18
View File
@@ -596,9 +596,6 @@ void connectMQTT() {
#endif
#ifdef ZgatewayIR
client.subscribe(subjectMultiGTWIR); // subject on which other OMG will publish, this OMG will store these msg and by the way don't republish them if they have been already published
#endif
#ifdef MQTT_HTTPS_FW_UPDATE
client.subscribe(subjectFWUpdate);
#endif
Log.trace(F("Subscription OK to the subjects %s" CR), topic2);
}
@@ -653,7 +650,7 @@ void callback(char* topic, byte* payload, unsigned int length) {
//launch the function to treat received data if this data concern OpenMQTTGateway
if ((strstr(topic, subjectMultiGTWKey) != NULL) ||
(strstr(topic, subjectGTWSendKey) != NULL) ||
(strstr(topic, subjectFWUpdate) != NULL))
(strstr(topic, subjectMQTTtoSYSupdate) != NULL))
receivingMQTT(topic, (char*)p);
// Free the memory
@@ -1509,6 +1506,10 @@ void loop() {
connected = true;
#if defined(ESP8266) || defined(ESP32) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
if (now > (timer_sys_measures + (TimeBetweenReadingSYS * 1000)) || !timer_sys_measures) {
# if defined(ESP32) && defined(MQTT_HTTPS_FW_UPDATE)
if (!timer_sys_measures) // Only check for updates at start for ESP32
checkForUpdates();
# endif
timer_sys_measures = millis();
stateMeasures();
# ifdef ZgatewayBT
@@ -1691,6 +1692,7 @@ void stateMeasures() {
SYSdata["uptime"] = uptime();
SYSdata["version"] = OMG_VERSION;
# if defined(ESP8266) || defined(ESP32)
SYSdata["env"] = ENV_NAME;
uint32_t freeMem;
freeMem = ESP.getFreeHeap();
SYSdata["freemem"] = freeMem;
@@ -1940,39 +1942,97 @@ void receivingMQTT(char* topicOri, char* datacallback) {
}
#ifdef MQTT_HTTPS_FW_UPDATE
String latestVersion;
# ifdef ESP32
# include <HTTPClient.h>
# include "zzHTTPUpdate.h"
/**
* Check on a server the latest version information to build a releaseLink
* The release link will be used when the user trigger an OTA update command
* Only available for ESP32
*/
bool checkForUpdates() {
HTTPClient http;
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
http.begin(OTA_JSON_URL, OTAserver_cert);
int httpCode = http.GET();
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
JsonObject jsondata = jsonBuffer.to<JsonObject>();
if (httpCode > 0) { //Check for the returning code
String payload = http.getString();
auto error = deserializeJson(jsonBuffer, payload);
if (error) {
Log.error(F("Deserialize MQTT data failed: %s" CR), error.c_str());
}
Log.trace(F("HttpCode %d" CR), httpCode);
Log.trace(F("Payload %s" CR), payload.c_str());
} else {
Log.error(F("Error on HTTP request"));
}
http.end(); //Free the resources
if (jsondata.containsKey("latest_version")) {
jsondata["installed_version"] = OMG_VERSION;
jsondata["entity_picture"] = ENTITY_PICTURE;
latestVersion = jsondata["latest_version"].as<String>();
pub(subjectSYStoMQTT, jsondata);
Log.trace(F("Update file found on server" CR));
return true;
} else {
Log.trace(F("No update file found on server" CR));
return false;
}
}
# elif ESP8266
# include <ESP8266httpUpdate.h>
# endif
void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) {
if (strstr(topicOri, subjectFWUpdate) != NULL) {
if (strstr(topicOri, subjectMQTTtoSYSupdate) != NULL) {
const char* version = HttpsFwUpdateData["version"];
if (version && ((strlen(version) != strlen(OMG_VERSION)) || strcmp(version, OMG_VERSION) != 0)) {
const char* url = HttpsFwUpdateData["url"];
String systemUrl;
if (url) {
if (!strstr((url + (strlen(url) - 5)), ".bin")) {
Log.error(F("Invalid firmware extension" CR));
return;
}
# if MQTT_HTTPS_FW_UPDATE_USE_PASSWORD > 0
const char* pwd = HttpsFwUpdateData["password"];
if (pwd) {
if (strcmp(pwd, ota_pass) != 0) {
Log.error(F("Invalid OTA password" CR));
return;
}
} else {
Log.error(F("No password sent" CR));
return;
}
# endif
# ifdef ESP32
} else if (strcmp(version, "latest") == 0) {
if (!checkForUpdates())
return;
systemUrl = RELEASE_LINK + latestVersion + "/" + ENV_NAME + "-firmware.bin";
url = systemUrl.c_str();
Log.notice(F("Using system OTA url with latest version %s" CR), url);
} else if (strcmp(version, "dev") == 0) {
systemUrl = String(RELEASE_LINK_DEV) + ENV_NAME + "-firmware.bin";
url = systemUrl.c_str();
Log.notice(F("Using system OTA url with dev version %s" CR), url);
} else if (version[0] == 'v') {
systemUrl = String(RELEASE_LINK) + version + "/" + ENV_NAME + "-firmware.bin";
url = systemUrl.c_str();
Log.notice(F("Using system OTA url with defined version %s" CR), url);
# endif
} else {
Log.error(F("Invalid URL" CR));
return;
}
# if MQTT_HTTPS_FW_UPDATE_USE_PASSWORD > 0
const char* pwd = HttpsFwUpdateData["password"];
if (pwd) {
if (strcmp(pwd, ota_pass) != 0) {
Log.error(F("Invalid OTA password" CR));
return;
}
} else {
Log.error(F("No password sent" CR));
return;
}
# endif
Log.warning(F("Starting firmware update" CR));
SendReceiveIndicatorON();
ErrorIndicatorON();