[SYS] Use PicoMQTT for MQTT communication (#1954)

* Update Arduino core for selected configurations

* Use PicoMQTT for MQTT communication
This commit is contained in:
Michał Leśniewski authored and GitHub committed 2024-07-03 11:39:58 -05:00
1 parent b20f2c4819
commit 9257433a50
8 files changed
+214 -233

No files matched your search

+1 -1
View File
@@ -18,7 +18,7 @@ PlatformIO config files work on the concept of overriding. At first, a very simp
[env] [env]
framework = arduino framework = arduino
lib_deps = lib_deps =
${libraries.pubsubclient} ${libraries.picomqtt}
${libraries.arduinojson} ${libraries.arduinojson}
${libraries.arduinolog} ${libraries.arduinolog}
build_flags = build_flags =
+3 -3
View File
@@ -38,9 +38,9 @@ instead of
## Repetitive MQTT disconnections or/and commands sent to the gateway not taken into account ## Repetitive MQTT disconnections or/and commands sent to the gateway not taken into account
Most probably a network issue, don't use a guest network and if going through a firewall check its rules. To put aside gateway issue, try to connect to a local broker on the same network. Most probably a network issue, don't use a guest network and if going through a firewall check its rules. To put aside gateway issue, try to connect to a local broker on the same network.
## You don't see the messages appearing on your broker but they appears on the serial monitor ## OMG ignores messages sent to it via MQTT
This is due to a too small MQTT packet size, open User_config.h and set: This can happen if the messages are too big and exceed the internal buffer size limit. To fix this, check the size of the message you're sending (in bytes). Next, open `User_config.h` and set `mqtt_max_payload_size` to be greater than that size, e.g.:
`#define mqtt_max_packet_size 1024` `#define mqtt_max_payload_size 1024`
## ESP Continuous restart or strange behaviour: ## ESP Continuous restart or strange behaviour:
This can be due to corruption of the ESP flash memory, try to erase flash and upload OMG on it again. This can be due to corruption of the ESP flash memory, try to erase flash and upload OMG on it again.
-2
View File
@@ -107,12 +107,10 @@ In this case the best way is to use hex values instead, but if you can't you may
In User_config.h replace: In User_config.h replace:
```cpp ```cpp
# define JSON_MSG_BUFFER 512 # define JSON_MSG_BUFFER 512
# define mqtt_max_packet_size 1024
``` ```
by by
```cpp ```cpp
# define JSON_MSG_BUFFER 1280 # define JSON_MSG_BUFFER 1280
# define mqtt_max_packet_size 1280
``` ```
## Repeat the IR signal OpenMQTTGateway receive ## Repeat the IR signal OpenMQTTGateway receive
+5 -3
View File
@@ -26,7 +26,7 @@ custom_description = RF gateway for the Sonoff RF Bridge relying on the internal
custom_hardware = RFBridge v1 custom_hardware = RFBridge v1
[env:rfbridge-direct] [env:rfbridge-direct]
platform = espressif8266@^2 platform = ${com.esp8266_platform}
board = esp8285 board = esp8285
lib_deps = lib_deps =
${com-esp.lib_deps} ${com-esp.lib_deps}
@@ -42,6 +42,7 @@ build_flags =
'-DZsensorGPIOInput="GPIOInput"' '-DZsensorGPIOInput="GPIOInput"'
'-DINPUT_GPIO=0' '-DINPUT_GPIO=0'
'-DGateway_Name="OMG_SRFB_Direct"' '-DGateway_Name="OMG_SRFB_Direct"'
'-fcommon'
board_build.flash_mode = dout board_build.flash_mode = dout
board_build.ldscript = eagle.flash.1m64.ld ;this frees more space for firmware uplad via OTA. board_build.ldscript = eagle.flash.1m64.ld ;this frees more space for firmware uplad via OTA.
;extra_scripts = scripts/compressFirmware.py ;uncomment this to compress the firmware. This helps updating e.g. Sonoff RF Bridge via OTA flash by saving space for the uploaded firmware. ;extra_scripts = scripts/compressFirmware.py ;uncomment this to compress the firmware. This helps updating e.g. Sonoff RF Bridge via OTA flash by saving space for the uploaded firmware.
@@ -1459,7 +1460,7 @@ board_build.flash_mode = dout
custom_description = KAKU RF gateway using NewRemoteSwitch library, need CC1101 custom_description = KAKU RF gateway using NewRemoteSwitch library, need CC1101
[env:nodemcuv2-pilight] [env:nodemcuv2-pilight]
platform = espressif8266@^2 platform = ${com.esp8266_platform}
board = nodemcuv2 board = nodemcuv2
lib_deps = lib_deps =
${com-esp.lib_deps} ${com-esp.lib_deps}
@@ -1470,6 +1471,7 @@ build_flags =
${com-esp.build_flags} ${com-esp.build_flags}
'-DZgatewayPilight="Pilight"' '-DZgatewayPilight="Pilight"'
'-DGateway_Name="OMG_ESP8266_Pilight"' '-DGateway_Name="OMG_ESP8266_Pilight"'
'-fcommon'
board_build.flash_mode = dout board_build.flash_mode = dout
custom_description = Gateway using ESPilight without the need of CC1101 custom_description = Gateway using ESPilight without the need of CC1101
@@ -1779,5 +1781,5 @@ build_flags =
'-DLED_SEND_RECEIVE_ON=0' '-DLED_SEND_RECEIVE_ON=0'
'-DGateway_Name="OMG_ESP32_BLE"' '-DGateway_Name="OMG_ESP32_BLE"'
'-DUSE_BLUFI=1' '-DUSE_BLUFI=1'
'-DARDUINO_LOOP_STACK_SIZE=15000' '-DARDUINO_LOOP_STACK_SIZE=16000'
custom_description = Regular BLE gateway based on esp-idf with adaptive scanning activated, automatically adapts the scan parameters depending on your devices custom_description = Regular BLE gateway based on esp-idf with adaptive scanning activated, automatically adapts the scan parameters depending on your devices
+2 -2
View File
@@ -162,8 +162,8 @@
# endif # endif
#endif #endif
#ifndef mqtt_max_topic_size #ifndef mqtt_max_payload_size
# define mqtt_max_packet_size JSON_MSG_BUFFER_MAX + mqtt_topic_max_size + 10 // maximum size of the MQTT packet # define mqtt_max_payload_size JSON_MSG_BUFFER_MAX // maximum size of the MQTT payload
#endif #endif
#ifndef MQTT_USER #ifndef MQTT_USER
+1 -1
View File
@@ -803,7 +803,7 @@ void coreTask(void* pvParameters) {
while (true) { while (true) {
if (!BTProcessLock) { if (!BTProcessLock) {
int n = 0; int n = 0;
while (client.state() != 0 && n <= InitialMQTTConnectionTimeout && !BTProcessLock) { while (mqtt->connected() && n <= InitialMQTTConnectionTimeout && !BTProcessLock) {
n++; n++;
delay(1000); delay(1000);
} }
+198 -217
View File
@@ -77,7 +77,9 @@ bool ready_to_sleep = false;
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <ArduinoLog.h> #include <ArduinoLog.h>
#include <PubSubClient.h> #include <PicoMQTT.h>
#include <memory>
struct JsonBundle { struct JsonBundle {
StaticJsonDocument<JSON_MSG_BUFFER> doc; StaticJsonDocument<JSON_MSG_BUFFER> doc;
@@ -221,9 +223,6 @@ struct GfSun2000Data {};
void setupTLS(int index = CNT_DEFAULT_INDEX); void setupTLS(int index = CNT_DEFAULT_INDEX);
//adding this to bypass the problem of the arduino builder issue 50
void callback(char* topic, byte* payload, unsigned int length);
char ota_pass[parameters_size] = gw_password; char ota_pass[parameters_size] = gw_password;
#ifdef USE_MAC_AS_GATEWAY_NAME #ifdef USE_MAC_AS_GATEWAY_NAME
# undef WifiManager_ssid # undef WifiManager_ssid
@@ -238,12 +237,12 @@ int failure_number_ntwk = 0; // number of failure connecting to network
int failure_number_mqtt = 0; // number of failure connecting to MQTT int failure_number_mqtt = 0; // number of failure connecting to MQTT
unsigned long timer_led_measures = 0; unsigned long timer_led_measures = 0;
static void* eClient = nullptr;
static unsigned long last_ota_activity_millis = 0; static unsigned long last_ota_activity_millis = 0;
// Global struct to store live SYS configuration data // Global struct to store live SYS configuration data
SYSConfig_s SYSConfig; SYSConfig_s SYSConfig;
bool failSafeMode = false; bool failSafeMode = false;
static bool mqttSetupPending = true;
static int cnt_index = CNT_DEFAULT_INDEX; static int cnt_index = CNT_DEFAULT_INDEX;
#ifdef ESP32 #ifdef ESP32
@@ -300,8 +299,8 @@ ESP8266WiFiMulti wifiMulti;
# include <Ethernet.h> # include <Ethernet.h>
#endif #endif
// client link to pubsub MQTT std::unique_ptr<::Client> eClient;
PubSubClient client; std::unique_ptr<PicoMQTT::Client> mqtt;
template <typename T> // Declared here to avoid pre-compilation issue (missing "template" in auto declaration by pio) template <typename T> // Declared here to avoid pre-compilation issue (missing "template" in auto declaration by pio)
void Config_update(JsonObject& data, const char* key, T& var); void Config_update(JsonObject& data, const char* key, T& var);
@@ -661,12 +660,12 @@ void pubMQTT(const char* topic, const char* payload) {
*/ */
void pubMQTT(const char* topic, const char* payload, bool retainFlag) { void pubMQTT(const char* topic, const char* payload, bool retainFlag) {
if (SYSConfig.XtoMQTT) { if (SYSConfig.XtoMQTT) {
if (client.connected()) { if (mqtt->connected()) {
SendReceiveIndicatorON(); SendReceiveIndicatorON();
Log.trace(F("[ OMG->MQTT ] topic: %s msg: %s " CR), topic, payload); Log.trace(F("[ OMG->MQTT ] topic: %s msg: %s " CR), topic, payload);
client.publish(topic, payload, retainFlag); mqtt->publish(topic, payload, 0, retainFlag);
} else { } else {
Log.warning(F("Client not connected, aborting the publication" CR)); Log.warning(F("MQTT not connected, aborting the publication" CR));
} }
} else { } else {
Log.notice(F("[ OMG->MQTT CANCELED] topic: %s msg: %s " CR), topic, payload); Log.notice(F("[ OMG->MQTT CANCELED] topic: %s msg: %s " CR), topic, payload);
@@ -848,49 +847,117 @@ void SYSConfig_load() {
void SYSConfig_load() {} void SYSConfig_load() {}
#endif #endif
#if AWS_IOT #if defined(MDNS_SD)
// Global variables to track reconnections std::pair<String, uint16_t> discoverMQTTbroker() {
unsigned long reconnection_count = 0; Log.trace(F("Browsing for MQTT service" CR));
unsigned long start_reconnection_window_millis = 0; int n = MDNS.queryService("mqtt", "tcp");
// Define a threshold for instability detection if (n == 0) {
const unsigned long reconnection_window_millis = 120000; Log.error(F("no services found" CR));
const unsigned int reconnection_threshold = 5; // Consider unstable if more than 5 reconnections in 2 minutes } else {
Log.trace(F("%d service(s) found" CR), n);
for (int i = 0; i < n; ++i) {
Log.trace(F("Service %d %s found" CR), i, MDNS.hostname(i).c_str());
Log.trace(F("IP %s Port %d" CR), MDNS.IP(i).toString().c_str(), MDNS.port(i));
}
if (n == 1) {
Log.trace(F("One MQTT server found setting parameters" CR));
return {MDNS.IP(0).toString(), uint16_t(MDNS.port(0))};
} else {
Log.error(F("Several MQTT servers found, please deactivate mDNS and set your default server" CR));
}
}
return {"", 0};
}
#endif #endif
void connectMQTT() { struct ss_cnt_parameters_backup {
#ifndef ESPWifiManualSetup ss_cnt_parameters parameters;
checkButton(); // check if a reset of wifi/mqtt settings is asked int cnt_index;
#endif bool saveOnSuccess;
};
Log.warning(F("MQTT connection..." CR)); static std::unique_ptr<ss_cnt_parameters_backup> cnt_parameters_backup;
#ifdef ESP32
//esp_task_wdt_add(NULL); void setupMQTT() {
//esp_task_wdt_reset(); Log.notice(F("Reconfiguring MQTT client..." CR));
#endif
char topic[mqtt_topic_max_size]; const auto& parameters = cnt_parameters_array[cnt_index];
strcpy(topic, mqtt_topic);
strcat(topic, gateway_name); // free the old MQTT client and underlying connection
strcat(topic, will_Topic); mqtt.reset();
client.setBufferSize(mqtt_max_packet_size); eClient.reset();
client.setSocketTimeout(GeneralTimeOut - 1); failure_number_mqtt = 0;
#if AWS_IOT
if (client.connect(gateway_name, cnt_parameters_array[cnt_index].mqtt_user, cnt_parameters_array[cnt_index].mqtt_pass)) { // AWS doesn't support will topic for the moment // configure socket
unsigned long current_millis = millis(); if (parameters.isConnectionSecure) {
if (start_reconnection_window_millis == 0 || current_millis - start_reconnection_window_millis > reconnection_window_millis) { eClient.reset(new WiFiClientSecure);
// Reset the count and timestamp at the start of a new window if (parameters.isCertValidate) {
reconnection_count = 0; setupTLS(cnt_index);
start_reconnection_window_millis = current_millis; } else {
} static_cast<WiFiClientSecure*>(eClient.get())->setInsecure();
reconnection_count++; // Increment reconnection count
Log.trace(F("MQTT connection count: %d" CR), reconnection_count);
if (reconnection_count > reconnection_threshold && SYSConfig.XtoMQTT) {
// Detected instability in MQTT connection
Log.warning(F("MQTT connection instability detected: %d reconnections in the last %d seconds" CR), reconnection_count, reconnection_window_millis / 1000);
// Stop xtoMQTT to see if it helps and still enables to receive data
SYSConfig.XtoMQTT = false;
} }
} else {
eClient.reset(new WiFiClient);
}
#if defined(MDNS_SD)
Log.trace(F("Connecting to MQTT by mDNS without MQTT hostname" CR));
const auto discovered_broker = discoverMQTTbroker();
const auto broker_host = discovered_broker.first.c_str();
const auto broker_port = discovered_broker.second;
#else #else
if (client.connect(gateway_name, cnt_parameters_array[cnt_index].mqtt_user, cnt_parameters_array[cnt_index].mqtt_pass, topic, will_QoS, will_Retain, will_Message)) { const auto broker_host = parameters.mqtt_server;
const auto broker_port = String(parameters.mqtt_port).toInt();
#endif
Log.trace(F("Mqtt server: %s" CR), broker_host);
Log.trace(F("Port: %u" CR), broker_port);
mqtt.reset(new PicoMQTT::Client(*eClient, broker_host, broker_port, gateway_name,
parameters.mqtt_user, parameters.mqtt_pass,
0, // minimum reconnect attempt interval [ms]
60 * 1000, // keep alive interval [ms]
(GeneralTimeOut - 1) * 1000 // socket timeout [ms]
));
#if AWS_IOT
// AWS doesn't support will topic for the moment
mqtt->will.topic = "";
mqtt->will.payload = "";
mqtt->will.qos = 0;
mqtt->will.retain = false;
#else
mqtt->will.topic = String(mqtt_topic) + gateway_name + will_Topic;
mqtt->will.payload = will_Message;
mqtt->will.qos = will_QoS;
mqtt->will.retain = will_Retain;
#endif
mqtt->connected_callback = [] {
#if AWS_IOT
{
// Define a threshold for instability detection
constexpr unsigned int reconnection_threshold = 5;
constexpr unsigned long reconnection_window_millis = 120000; // Consider unstable if more than 5 reconnections in 2 minutes
static unsigned int reconnection_count = 0;
static unsigned long start_reconnection_window_millis = 0;
const unsigned long current_millis = millis();
if (start_reconnection_window_millis == 0 || current_millis - start_reconnection_window_millis > reconnection_window_millis) {
// Reset the count and timestamp at the start of a new window
reconnection_count = 0;
start_reconnection_window_millis = current_millis;
}
reconnection_count++; // Increment reconnection count
Log.trace(F("MQTT connection count: %d" CR), reconnection_count);
if (reconnection_count > reconnection_threshold && SYSConfig.XtoMQTT) {
// Detected instability in MQTT connection
Log.warning(F("MQTT connection instability detected: %d reconnections in the last %d seconds" CR), reconnection_count, reconnection_window_millis / 1000);
// Stop xtoMQTT to see if it helps and still enables to receive data
SYSConfig.XtoMQTT = false;
}
}
#endif #endif
displayPrint("MQTT connected"); displayPrint("MQTT connected");
@@ -898,37 +965,58 @@ void connectMQTT() {
failure_number_mqtt = 0; failure_number_mqtt = 0;
// Once connected, publish an announcement... // Once connected, publish an announcement...
pub(will_Topic, Gateway_AnnouncementMsg, will_Retain); pub(will_Topic, Gateway_AnnouncementMsg, will_Retain);
//Subscribing to topic
char topic2[mqtt_topic_max_size]; if (cnt_parameters_backup) {
strcpy(topic2, mqtt_topic); // this was the first attempt to connect to a new server and it succeeded
strcat(topic2, gateway_name); Log.notice(F("MQTT connection successful" CR));
strcat(topic2, subjectMQTTtoX); cnt_parameters_array[cnt_index].validConnection = true;
if (client.subscribe(topic2)) { readCntParameters(cnt_index);
#ifdef ZgatewayRF
client.subscribe(subjectMultiGTWRF); // 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 #ifndef ESPWifiManualSetup
if (cnt_parameters_backup->saveOnSuccess) // Save the new parameters to the flash
saveConfig();
#endif #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 cnt_parameters_backup.reset();
#endif ESPRestart(7);
Log.trace(F("Subscription OK to the subjects %s" CR), topic2); }
};
mqtt->connection_failure_callback = [] {
if (WiFi.status() != WL_CONNECTED) {
// No WiFi connection, MQTT couldn't connect, ignore this failure
return;
} }
} else {
failure_number_mqtt++; // we count the failure failure_number_mqtt++; // we count the failure
Log.warning(F("failure_number_mqtt: %d" CR), failure_number_mqtt); Log.warning(F("failure_number_mqtt: %d" CR), failure_number_mqtt);
Log.warning(F("failed, rc=%d" CR), client.state());
const auto& parameters = cnt_parameters_array[cnt_index];
if (parameters.isConnectionSecure) {
WiFiClientSecure* client = static_cast<WiFiClientSecure*>(eClient.get());
#if defined(ESP32) #if defined(ESP32)
if (cnt_parameters_array[cnt_index].isConnectionSecure) Log.warning(F("failed, ssl error code=%d" CR), client->lastError(nullptr, 0));
Log.warning(F("failed, ssl error code=%d" CR), ((WiFiClientSecure*)eClient)->lastError(nullptr, 0));
#elif defined(ESP8266) #elif defined(ESP8266)
if (cnt_parameters_array[cnt_index].isConnectionSecure) Log.warning(F("failed, ssl error code=%d" CR), client->getLastSSLError());
Log.warning(F("failed, ssl error code=%d" CR), ((WiFiClientSecure*)eClient)->getLastSSLError());
#endif #endif
}
if (cnt_parameters_backup) {
// this was the first attempt to connect to a new server and it failed, revert to old settings
Log.error(F("MQTT connection failed, reverting to previous settings" CR));
cnt_parameters_array[cnt_index] = cnt_parameters_backup->parameters;
cnt_index = cnt_parameters_backup->cnt_index;
mqttSetupPending = true;
cnt_parameters_backup.reset();
ESPRestart(7);
return;
}
ErrorIndicatorON(); ErrorIndicatorON();
delayWithOTA(5000); delayWithOTA(5000);
ErrorIndicatorOFF(); ErrorIndicatorOFF();
delayWithOTA(5000); delayWithOTA(5000);
// If we have failed to connect to the MQTT broker, we will try to connect to the next set of connection parameters
if (failure_number_mqtt > maxRetryWatchDog) { if (failure_number_mqtt > maxRetryWatchDog) {
#ifndef ESPWifiManualSetup #ifndef ESPWifiManualSetup
// Look for the next valid connection // Look for the next valid connection
@@ -946,7 +1034,6 @@ void connectMQTT() {
} }
} }
#endif #endif
unsigned long millis_since_last_ota; unsigned long millis_since_last_ota;
while ( while (
// When // When
@@ -962,29 +1049,21 @@ void connectMQTT() {
} }
ESPRestart(1); ESPRestart(1);
} }
} };
}
// Callback function, when the gateway receive an MQTT value on the topics subscribed this function is called mqtt->subscribe(String(mqtt_topic) + gateway_name + subjectMQTTtoX, receivingMQTT, mqtt_max_payload_size);
void callback(char* topic, byte* payload, unsigned int length) {
// In order to republish this payload, a copy must be made
// as the original payload buffer will be overwritten whilst
// constructing the PUBLISH packet.
Log.trace(F("Hey I got a callback %s" CR), topic);
// Allocate the correct amount of memory for the payload copy
byte* p = (byte*)malloc(length + 1);
// Copy the payload to the new buffer
memcpy(p, payload, length);
// Conversion to a printable string
p[length] = '\0';
//launch the function to treat received data if this data concern OpenMQTTGateway
if ((strstr(topic, subjectMultiGTWKey) != NULL) ||
(strstr(topic, subjectGTWSendKey) != NULL) ||
(strstr(topic, subjectMQTTtoSYSupdate) != NULL))
receivingMQTT(topic, (char*)p);
// Free the memory #ifdef ZgatewayRF
free(p); // 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
mqtt->subscribe(subjectMultiGTWRF, receivingMQTT, mqtt_max_payload_size);
#endif
#ifdef ZgatewayIR
// 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
mqtt->subscribe(subjectMultiGTWIR, receivingMQTT, mqtt_max_payload_size);
#endif
mqtt->begin();
} }
#if defined(ESP32) && (defined(WifiGMode) || defined(WifiPower)) #if defined(ESP32) && (defined(WifiGMode) || defined(WifiPower))
@@ -1205,26 +1284,6 @@ void setup() {
modules.add(ZwebUI); modules.add(ZwebUI);
#endif #endif
if (cnt_parameters_array[cnt_index].isConnectionSecure) {
eClient = new WiFiClientSecure;
setupTLS(cnt_index);
} else {
eClient = new WiFiClient;
}
client.setClient(*(Client*)eClient);
#if defined(MDNS_SD)
Log.trace(F("Connecting to MQTT by mDNS without MQTT hostname" CR));
connectMQTTmdns();
#else
uint16_t port = strtol(cnt_parameters_array[cnt_index].mqtt_port, NULL, 10);
Log.trace(F("Port: %l" CR), port);
Log.trace(F("Mqtt server: %s" CR), cnt_parameters_array[cnt_index].mqtt_server);
client.setServer(cnt_parameters_array[cnt_index].mqtt_server, port);
#endif
client.setCallback(callback);
delay(1500); delay(1500);
#if defined(ZgatewayRF) || defined(ZgatewayPilight) || defined(ZgatewayRTL_433) || defined(ZgatewayRF2) || defined(ZactuatorSomfy) #if defined(ZgatewayRF) || defined(ZgatewayPilight) || defined(ZgatewayRTL_433) || defined(ZgatewayRF2) || defined(ZactuatorSomfy)
setupCommonRF(); setupCommonRF();
@@ -1382,7 +1441,7 @@ void setup() {
setupRTL_433(); setupRTL_433();
modules.add(ZgatewayRTL_433); modules.add(ZgatewayRTL_433);
#endif #endif
Log.trace(F("mqtt_max_packet_size: %d" CR), mqtt_max_packet_size); Log.trace(F("mqtt_max_payload_size: %d" CR), mqtt_max_payload_size);
char jsonChar[100]; char jsonChar[100];
serializeJson(modules, jsonChar, measureJson(modules) + 1); serializeJson(modules, jsonChar, measureJson(modules) + 1);
@@ -1481,7 +1540,7 @@ void setOTA() {
void setupTLS(int index) { void setupTLS(int index) {
configTime(0, 0, NTP_SERVER); configTime(0, 0, NTP_SERVER);
WiFiClientSecure* sClient = (WiFiClientSecure*)eClient; WiFiClientSecure* sClient = static_cast<WiFiClientSecure*>(eClient.get());
Log.notice(F("cnt index used: %d" CR), index); Log.notice(F("cnt index used: %d" CR), index);
if (!cnt_parameters_array[index].isCertValidate) { if (!cnt_parameters_array[index].isCertValidate) {
Log.notice(F("Disabling cert validation" CR)); Log.notice(F("Disabling cert validation" CR));
@@ -2195,27 +2254,6 @@ void WiFiEvent(WiFiEvent_t event) {
# endif # endif
#endif #endif
#if defined(MDNS_SD)
void connectMQTTmdns() {
Log.trace(F("Browsing for MQTT service" CR));
int n = MDNS.queryService("mqtt", "tcp");
if (n == 0) {
Log.error(F("no services found" CR));
} else {
Log.trace(F("%d service(s) found" CR), n);
for (int i = 0; i < n; ++i) {
Log.trace(F("Service %d %s found" CR), i, MDNS.hostname(i).c_str());
Log.trace(F("IP %s Port %d" CR), MDNS.IP(i).toString().c_str(), MDNS.port(i));
}
if (n == 1) {
Log.trace(F("One MQTT server found setting parameters" CR));
client.setServer(MDNS.IP(0), int(MDNS.port(0)));
} else {
Log.error(F("Several MQTT servers found, please deactivate mDNS and set your default server" CR));
}
}
}
#endif
void loop() { void loop() {
#ifndef ESPWifiManualSetup #ifndef ESPWifiManualSetup
checkButton(); // check if a reset of wifi/mqtt settings is asked checkButton(); // check if a reset of wifi/mqtt settings is asked
@@ -2225,6 +2263,11 @@ void loop() {
//esp_task_wdt_reset(); //esp_task_wdt_reset();
#endif #endif
if (mqttSetupPending) {
setupMQTT();
mqttSetupPending = false;
}
unsigned long now = millis(); unsigned long now = millis();
// Switch off of the LED after TimeLedON // Switch off of the LED after TimeLedON
@@ -2243,11 +2286,12 @@ void loop() {
#if defined(ZwebUI) && defined(ESP32) #if defined(ZwebUI) && defined(ESP32)
WebUILoop(); WebUILoop();
#endif #endif
if (client.loop()) { // MQTT client is still connected mqtt->loop();
if (mqtt->connected()) { // MQTT client is still connected
InfoIndicatorON(); InfoIndicatorON();
failure_number_ntwk = 0; failure_number_ntwk = 0;
// We have just re-connected if connected was previously false // We have just re-connected if connected was previously false
bool justReconnected = !connected; const bool justReconnected = !connected;
#ifdef ZmqttDiscovery #ifdef ZmqttDiscovery
// Deactivate autodiscovery after DiscoveryAutoOffTimer. // Deactivate autodiscovery after DiscoveryAutoOffTimer.
// Exception: when discovery_republish_on_reconnect is enabled, we never never automatically disable discovery // Exception: when discovery_republish_on_reconnect is enabled, we never never automatically disable discovery
@@ -2419,7 +2463,6 @@ void loop() {
} else { } else {
// MQTT disconnected // MQTT disconnected
connected = false; connected = false;
connectMQTT();
} }
} else { // disconnected from network } else { // disconnected from network
#ifdef ESP32 #ifdef ESP32
@@ -2984,8 +3027,9 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) {
} else { } else {
WiFiClientSecure update_client; WiFiClientSecure update_client;
if (cnt_parameters_array[cnt_index].isConnectionSecure) { if (cnt_parameters_array[cnt_index].isConnectionSecure) {
client.disconnect(); mqtt.reset();
update_client = *(WiFiClientSecure*)eClient; mqttSetupPending = true;
update_client = *static_cast<WiFiClientSecure*>(eClient.get());
} else { } else {
syncNTP(); syncNTP();
} }
@@ -3126,7 +3170,7 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
#endif #endif
String prev_ssid = WiFi.SSID(); String prev_ssid = WiFi.SSID();
String prev_pass = WiFi.psk(); String prev_pass = WiFi.psk();
client.disconnect(); // NOTE: There's no need to disconnect MQTT manually
WiFi.disconnect(true); WiFi.disconnect(true);
Log.warning(F("Attempting connection to new AP %s" CR), (const char*)SYSdata["wifi_ssid"]); Log.warning(F("Attempting connection to new AP %s" CR), (const char*)SYSdata["wifi_ssid"]);
@@ -3147,8 +3191,6 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
restartESP = true; restartESP = true;
} }
bool disconnectClient = false; // Trigger client.disconnet if a user/password change doesn't
if ((SYSdata.containsKey("mqtt_topic") && SYSdata["mqtt_topic"].is<char*>()) || if ((SYSdata.containsKey("mqtt_topic") && SYSdata["mqtt_topic"].is<char*>()) ||
(SYSdata.containsKey("gateway_name") && SYSdata["gateway_name"].is<char*>()) || (SYSdata.containsKey("gateway_name") && SYSdata["gateway_name"].is<char*>()) ||
(SYSdata.containsKey("gw_pass") && SYSdata["gw_pass"].is<char*>())) { (SYSdata.containsKey("gw_pass") && SYSdata["gw_pass"].is<char*>())) {
@@ -3165,7 +3207,7 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
#ifndef ESPWifiManualSetup #ifndef ESPWifiManualSetup
saveConfig(); saveConfig();
#endif #endif
disconnectClient = true; // trigger reconnect in loop using the new topic/name mqttSetupPending = true; // trigger reconnect in loop using the new topic/name
} }
#ifdef MQTTsetMQTT #ifdef MQTTsetMQTT
@@ -3173,6 +3215,7 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
bool save_cnt = false; bool save_cnt = false;
bool read_cnt = false; bool read_cnt = false;
bool test_cnt = false; bool test_cnt = false;
if (SYSdata.containsKey("save_cnt") && SYSdata["save_cnt"].is<bool>()) { if (SYSdata.containsKey("save_cnt") && SYSdata["save_cnt"].is<bool>()) {
save_cnt = SYSdata["save_cnt"].as<bool>(); save_cnt = SYSdata["save_cnt"].as<bool>();
} }
@@ -3183,23 +3226,20 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
test_cnt = SYSdata["test_cnt"].as<bool>(); test_cnt = SYSdata["test_cnt"].as<bool>();
} }
int prev_cnt_index = cnt_index;
char prev_mqtt_user[parameters_size];
strcpy(prev_mqtt_user, cnt_parameters_array[prev_cnt_index].mqtt_user);
char prev_mqtt_pass[parameters_size];
strcpy(prev_mqtt_pass, cnt_parameters_array[prev_cnt_index].mqtt_pass);
char prev_mqtt_server[parameters_size];
strcpy(prev_mqtt_server, cnt_parameters_array[prev_cnt_index].mqtt_server);
char prev_mqtt_port[6];
strcpy(prev_mqtt_port, cnt_parameters_array[prev_cnt_index].mqtt_port);
bool prev_mqtt_secure = cnt_parameters_array[prev_cnt_index].isConnectionSecure;
if (SYSdata.containsKey("cnt_index") && SYSdata["cnt_index"].is<int>()) { if (SYSdata.containsKey("cnt_index") && SYSdata["cnt_index"].is<int>()) {
if (SYSdata["cnt_index"].as<int>() < 0 || SYSdata["cnt_index"].as<int>() > 2) { if (SYSdata["cnt_index"].as<int>() < 0 || SYSdata["cnt_index"].as<int>() > 2) {
Log.error(F("Invalid cnt index provided - ignoring command" CR)); Log.error(F("Invalid cnt index provided - ignoring command" CR));
return; return;
} }
// we're overwrittng parameters, create a backup to be able to revert
cnt_parameters_backup.reset(new ss_cnt_parameters_backup());
cnt_parameters_backup->cnt_index = cnt_index;
cnt_parameters_backup->saveOnSuccess = save_cnt;
cnt_index = SYSdata["cnt_index"].as<int>(); cnt_index = SYSdata["cnt_index"].as<int>();
cnt_parameters_backup->parameters = cnt_parameters_array[cnt_index];
Log.notice(F("MQTT cnt index %d" CR), cnt_index); Log.notice(F("MQTT cnt index %d" CR), cnt_index);
if (SYSdata.containsKey("mqtt_user") && SYSdata["mqtt_user"].is<char*>() && SYSdata.containsKey("mqtt_pass") && SYSdata["mqtt_pass"].is<char*>()) { if (SYSdata.containsKey("mqtt_user") && SYSdata["mqtt_user"].is<char*>() && SYSdata.containsKey("mqtt_pass") && SYSdata["mqtt_pass"].is<char*>()) {
@@ -3244,6 +3284,7 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
cnt_parameters_array[cnt_index].ota_server_cert = processCert(SYSdata["ota_server_cert"].as<const char*>()); cnt_parameters_array[cnt_index].ota_server_cert = processCert(SYSdata["ota_server_cert"].as<const char*>());
Log.trace(F("Assigning OTA server cert %s" CR), generateHash(cnt_parameters_array[cnt_index].ota_server_cert).c_str()); Log.trace(F("Assigning OTA server cert %s" CR), generateHash(cnt_parameters_array[cnt_index].ota_server_cert).c_str());
} }
// Read the memory certs hash to MQTT // Read the memory certs hash to MQTT
if (read_cnt) if (read_cnt)
readCntParameters(cnt_index); readCntParameters(cnt_index);
@@ -3260,74 +3301,14 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding
stopProcessing(); stopProcessing();
# endif # endif
# endif # endif
client.disconnect();
prev_client = eClient; mqttSetupPending = true;
} else {
if (cnt_parameters_array[cnt_index].isConnectionSecure) { // no request to test or save the parameters, forget the old settings
Log.notice(F("Connecting to secure MQTT broker" CR)); cnt_parameters_backup.reset();
eClient = new WiFiClientSecure;
} else {
Log.warning(F("Connecting to unsecure MQTT broker" CR));
eClient = new WiFiClient;
}
client.setClient(*(Client*)eClient);
if (cnt_parameters_array[cnt_index].isConnectionSecure) {
setupTLS(cnt_index);
}
}
if (save_cnt || (test_cnt && !read_cnt)) {
Log.notice(F("Attempting connection to new MQTT broker" CR));
client.setServer(cnt_parameters_array[cnt_index].mqtt_server, strtol(cnt_parameters_array[cnt_index].mqtt_port, NULL, 10));
// Connect the client
connectMQTT();
// If the connection is successful we save the parameters to the flash memory
if (client.connected()) {
Log.notice(F("Connection successful" CR));
cnt_parameters_array[cnt_index].validConnection = true;
readCntParameters(cnt_index);
if (prev_client != nullptr) {
delete prev_client;
}
# ifndef ESPWifiManualSetup
if (save_cnt) // Save the new parameters to the flash
saveConfig();
# endif
} else { // Revert to previous settings
Log.error(F("Connection failed, reverting to previous settings" CR));
cnt_index = prev_cnt_index;
if (SYSdata.containsKey("mqtt_user") && SYSdata.containsKey("mqtt_pass")) {
strcpy(cnt_parameters_array[cnt_index].mqtt_user, prev_mqtt_user);
strcpy(cnt_parameters_array[cnt_index].mqtt_pass, prev_mqtt_pass);
}
if (SYSdata.containsKey("mqtt_server") && SYSdata.containsKey("mqtt_port")) {
client.setServer(prev_mqtt_server, strtol(prev_mqtt_port, NULL, 10));
}
// Revert the change of secure connection
if (SYSdata.containsKey("mqtt_secure")) {
cnt_parameters_array[cnt_index].isConnectionSecure = prev_mqtt_secure;
}
if (prev_client != nullptr) {
delete eClient;
eClient = prev_client;
client.setClient(*(Client*)eClient);
}
// Restest the connection
connectMQTT();
// If the parameters given does not enable to connect we want to exit directly and not take into account any associated parameters with the connection
ESPRestart(7);
}
restartESP = true;
} }
#endif #endif
if (disconnectClient) {
client.disconnect();
}
if (SYSdata.containsKey("xtomqtt") && SYSdata["xtomqtt"].is<bool>()) { if (SYSdata.containsKey("xtomqtt") && SYSdata["xtomqtt"].is<bool>()) {
SYSConfig.XtoMQTT = SYSdata["xtomqtt"]; SYSConfig.XtoMQTT = SYSdata["xtomqtt"];
Log.notice(F("xtomqtt: %T" CR), SYSConfig.XtoMQTT); Log.notice(F("xtomqtt: %T" CR), SYSConfig.XtoMQTT);
@@ -3395,4 +3376,4 @@ String toString(uint32_t input) {
return result; return result;
} }
#endif #endif
+4 -4
View File
@@ -113,7 +113,7 @@ extra_configs =
[libraries] [libraries]
arduinojson = ArduinoJson@6.18.3 arduinojson = ArduinoJson@6.18.3
arduinolog = https://github.com/1technophile/Arduino-Log.git#f634509 arduinolog = https://github.com/1technophile/Arduino-Log.git#f634509
pubsubclient = PubSubClient@2.8 picomqtt = PicoMQTT@1.1.1
rc-switch = https://github.com/1technophile/rc-switch.git#98537e9 rc-switch = https://github.com/1technophile/rc-switch.git#98537e9
newremoteswitch = https://github.com/1technophile/NewRemoteSwitch.git#8eb980e newremoteswitch = https://github.com/1technophile/NewRemoteSwitch.git#8eb980e
ble = https://github.com/h2zero/NimBLE-Arduino.git#1.4.1 ble = https://github.com/h2zero/NimBLE-Arduino.git#1.4.1
@@ -161,7 +161,7 @@ rn8209 = https://github.com/theengs/RN8209C-SDK.git#arduino
[env] [env]
framework = arduino framework = arduino
lib_deps = lib_deps =
${libraries.pubsubclient} ${libraries.picomqtt}
${libraries.arduinojson} ${libraries.arduinojson}
${libraries.arduinolog} ${libraries.arduinolog}
build_flags = build_flags =
@@ -174,7 +174,7 @@ monitor_speed = 115200
[com] [com]
esp8266_platform = espressif8266@4.1.0 esp8266_platform = espressif8266@4.1.0
esp32_platform = espressif32@6.1.0 esp32_platform = espressif32@6.1.0
esp32_solo_platform = https://github.com/tasmota/platform-espressif32/releases/download/v.2.0.5/platform-espressif32-v.2.0.5.zip esp32_solo_platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.02.00/platform-espressif32.zip
atmelavr_platform = atmelavr@3.3.0 atmelavr_platform = atmelavr@3.3.0
[com-esp] ; Used by all ESP8266/ESP8285 based builds [com-esp] ; Used by all ESP8266/ESP8285 based builds
@@ -219,4 +219,4 @@ lib_deps =
${libraries.ethernet} ${libraries.ethernet}
build_flags = build_flags =
${env.build_flags} ${env.build_flags}
'-DsimpleReceiving=false' '-DsimpleReceiving=false'