diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ee604d..dab8e13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ file(GLOB SRCFILES networkDevices/EthLan8720Device.cpp networkDevices/ClientSyncW5500.cpp networkDevices/espMqttClientW5500.cpp + networkDevices/espMqttClientWifi.cpp QueryCommand.h NukiWrapper.cpp NukiOpenerWrapper.cpp diff --git a/Config.h b/Config.h index 538eb48..f1d34de 100644 --- a/Config.h +++ b/Config.h @@ -1,6 +1,6 @@ #pragma once -#define NUKI_HUB_VERSION "8.12-pre-9" +#define NUKI_HUB_VERSION "8.12-pre-10" #define MQTT_QOS_LEVEL 1 #define MQTT_CLEAN_SESSIONS false \ No newline at end of file diff --git a/lib/espMqttClient/docs/index.md b/lib/espMqttClient/docs/index.md index 8b8efb9..84d1122 100644 --- a/lib/espMqttClient/docs/index.md +++ b/lib/espMqttClient/docs/index.md @@ -312,11 +312,13 @@ Publish a packet with a callback for payload handling. Return the packet ID (or The callback has the following signature: `size_t callback(uint8_t* data, size_t maxSize, size_t index)`. When the library needs payload data, the callback will be invoked. It is the callback's job to write data indo `data` with a maximum of `maxSize` bytes, according the `index` and return the amount of bytes written. ```cpp -void clearQueue() +void clearQueue(bool deleteSessionData = false) ``` -When disconnected, clears all queued messages. -Keep in mind that this also deletes any session data and therefore is no MQTT compliant. +Clears all queued messages. +Keep in mind that this may also delete any session data and therefore is not MQTT compliant. + +- **`deleteSessionData`**: When true, delete all outgoing messages. Not MQTT compliant! ```cpp void loop() @@ -361,12 +363,19 @@ Set this to 1 if you use the async version on ESP8266. For the regular client th ### EMC_ALLOW_NOT_CONNECTED_PUBLISH 1 By default, you can publish when the client is not connected. If you don't want this, set this to 0. +Regardless of this setting, after you called `disconnect()`, no messages can be published until fully disconnected. + +### EMC_WAIT_FOR_CONNACK 1 + +espMqttClient waits for the CONNACK (connection acknowledge) packet before starting to send other packets. +The MQTT specification allows to start sending before the broker acknowledges the connection but some brokers +don't allow this (AWS for example doesn't). ### EMC_CLIENTID_LENGTH 18 + 1 The (maximum) length of the client ID. (Keep in mind that this is a c-string. You need to have 1 position available for the null-termination.) -### EMC_TASK_STACK_SIZE 5000 +### EMC_TASK_STACK_SIZE 5120 Only used on ESP32. Sets the stack size (in words) of the MQTT client worker task. diff --git a/lib/espMqttClient/examples/largepayload-esp8266/largepayload-esp8266.ino b/lib/espMqttClient/examples/largepayload-esp8266/largepayload-esp8266.ino index f719080..aff6fac 100644 --- a/lib/espMqttClient/examples/largepayload-esp8266/largepayload-esp8266.ino +++ b/lib/espMqttClient/examples/largepayload-esp8266/largepayload-esp8266.ino @@ -1,5 +1,4 @@ #include -#include #include #define WIFI_SSID "yourSSID" @@ -11,7 +10,6 @@ WiFiEventHandler wifiConnectHandler; WiFiEventHandler wifiDisconnectHandler; espMqttClient mqttClient; -Ticker reconnectTimer; size_t fetchPayload(uint8_t* dest, size_t len, size_t index) { Serial.printf("filling buffer at index %zu\n", index); @@ -45,8 +43,6 @@ void onWiFiConnect(const WiFiEventStationModeGotIP& event) { void onWiFiDisconnect(const WiFiEventStationModeDisconnected& event) { Serial.println("Disconnected from Wi-Fi."); - reconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi - reconnectTimer.once(5, connectToWiFi); } void onMqttConnect(bool sessionPresent) { @@ -60,7 +56,7 @@ void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) { Serial.printf("Disconnected from MQTT: %u.\n", static_cast(reason)); if (WiFi.isConnected()) { - reconnectTimer.once(5, connectToMqtt); + connectToMqtt(); } } @@ -75,6 +71,8 @@ void setup() { Serial.println(); Serial.println(); + WiFi.setAutoConnect(false); + WiFi.setAutoReconnect(true); wifiConnectHandler = WiFi.onStationModeGotIP(onWiFiConnect); wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWiFiDisconnect); diff --git a/lib/espMqttClient/examples/ota-esp8266/ota-esp8266.ino b/lib/espMqttClient/examples/ota-esp8266/ota-esp8266.ino index 07bb1aa..5152d9b 100644 --- a/lib/espMqttClient/examples/ota-esp8266/ota-esp8266.ino +++ b/lib/espMqttClient/examples/ota-esp8266/ota-esp8266.ino @@ -1,6 +1,5 @@ #include #include -#include #include #define WIFI_SSID "yourSSID" @@ -14,7 +13,6 @@ WiFiEventHandler wifiConnectHandler; WiFiEventHandler wifiDisconnectHandler; espMqttClient mqttClient; -Ticker reconnectTimer; bool disconnectFlag = false; bool restartFlag = false; @@ -35,8 +33,6 @@ void onWiFiConnect(const WiFiEventStationModeGotIP& event) { void onWiFiDisconnect(const WiFiEventStationModeDisconnected& event) { Serial.println("Disconnected from Wi-Fi."); - reconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi - reconnectTimer.once(5, connectToWiFi); } void onMqttConnect(bool sessionPresent) { @@ -57,7 +53,7 @@ void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) { } if (WiFi.isConnected()) { - reconnectTimer.once(5, connectToMqtt); + connectToMqtt(); } } @@ -114,6 +110,8 @@ void setup() { Serial.println(); Serial.println(); + WiFi.setAutoConnect(false); + WiFi.setAutoReconnect(true); wifiConnectHandler = WiFi.onStationModeGotIP(onWiFiConnect); wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWiFiDisconnect); diff --git a/lib/espMqttClient/examples/simple-esp32/simple-esp32.ino b/lib/espMqttClient/examples/simple-esp32/simple-esp32.ino index 581db1f..27dc6b9 100644 --- a/lib/espMqttClient/examples/simple-esp32/simple-esp32.ino +++ b/lib/espMqttClient/examples/simple-esp32/simple-esp32.ino @@ -1,5 +1,4 @@ #include -#include #include #define WIFI_SSID "yourSSID" @@ -9,7 +8,6 @@ #define MQTT_PORT 1883 espMqttClient mqttClient; -Ticker reconnectTimer; void connectToWiFi() { Serial.println("Connecting to Wi-Fi..."); @@ -32,7 +30,6 @@ void WiFiEvent(WiFiEvent_t event) { break; case SYSTEM_EVENT_STA_DISCONNECTED: Serial.println("WiFi lost connection"); - reconnectTimer.once(5, connectToWiFi); break; default: break; @@ -60,7 +57,7 @@ void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) { Serial.printf("Disconnected from MQTT: %u.\n", static_cast(reason)); if (WiFi.isConnected()) { - reconnectTimer.once(5, connectToMqtt); + connectToMqtt(); } } @@ -109,6 +106,8 @@ void setup() { Serial.println(); Serial.println(); + WiFi.setAutoConnect(false); + WiFi.setAutoReconnect(true); WiFi.onEvent(WiFiEvent); mqttClient.onConnect(onMqttConnect); diff --git a/lib/espMqttClient/examples/simple-esp8266/simple-esp8266.ino b/lib/espMqttClient/examples/simple-esp8266/simple-esp8266.ino index 0747ec6..39e725d 100644 --- a/lib/espMqttClient/examples/simple-esp8266/simple-esp8266.ino +++ b/lib/espMqttClient/examples/simple-esp8266/simple-esp8266.ino @@ -1,5 +1,4 @@ #include -#include #include #define WIFI_SSID "yourSSID" @@ -11,7 +10,6 @@ WiFiEventHandler wifiConnectHandler; WiFiEventHandler wifiDisconnectHandler; espMqttClient mqttClient; -Ticker reconnectTimer; void connectToWiFi() { Serial.println("Connecting to Wi-Fi..."); @@ -30,8 +28,6 @@ void onWiFiConnect(const WiFiEventStationModeGotIP& event) { void onWiFiDisconnect(const WiFiEventStationModeDisconnected& event) { Serial.println("Disconnected from Wi-Fi."); - reconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi - reconnectTimer.once(5, connectToWiFi); } void onMqttConnect(bool sessionPresent) { @@ -55,7 +51,7 @@ void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) { Serial.printf("Disconnected from MQTT: %u.\n", static_cast(reason)); if (WiFi.isConnected()) { - reconnectTimer.once(5, connectToMqtt); + connectToMqtt(); } } @@ -104,6 +100,8 @@ void setup() { Serial.println(); Serial.println(); + WiFi.setAutoConnect(false); + WiFi.setAutoReconnect(true); wifiConnectHandler = WiFi.onStationModeGotIP(onWiFiConnect); wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWiFiDisconnect); diff --git a/lib/espMqttClient/examples/simpleAsync-esp32/simpleAsync-esp32.ino b/lib/espMqttClient/examples/simpleAsync-esp32/simpleAsync-esp32.ino index c4d9aa0..a556789 100644 --- a/lib/espMqttClient/examples/simpleAsync-esp32/simpleAsync-esp32.ino +++ b/lib/espMqttClient/examples/simpleAsync-esp32/simpleAsync-esp32.ino @@ -1,5 +1,4 @@ #include -#include #include #define WIFI_SSID "yourSSID" @@ -9,7 +8,6 @@ #define MQTT_PORT 1883 espMqttClientAsync mqttClient; -Ticker reconnectTimer; void connectToWiFi() { Serial.println("Connecting to Wi-Fi..."); @@ -32,7 +30,6 @@ void WiFiEvent(WiFiEvent_t event) { break; case SYSTEM_EVENT_STA_DISCONNECTED: Serial.println("WiFi lost connection"); - reconnectTimer.once(5, connectToWiFi); break; default: break; @@ -60,7 +57,7 @@ void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) { Serial.printf("Disconnected from MQTT: %u.\n", static_cast(reason)); if (WiFi.isConnected()) { - reconnectTimer.once(5, connectToMqtt); + connectToMqtt(); } } @@ -109,6 +106,8 @@ void setup() { Serial.println(); Serial.println(); + WiFi.setAutoConnect(false); + WiFi.setAutoReconnect(true); WiFi.onEvent(WiFiEvent); mqttClient.onConnect(onMqttConnect); diff --git a/lib/espMqttClient/examples/simpleAsync-esp8266/simpleAsync-esp8266.ino b/lib/espMqttClient/examples/simpleAsync-esp8266/simpleAsync-esp8266.ino index 2ed6b53..76c20a9 100644 --- a/lib/espMqttClient/examples/simpleAsync-esp8266/simpleAsync-esp8266.ino +++ b/lib/espMqttClient/examples/simpleAsync-esp8266/simpleAsync-esp8266.ino @@ -1,5 +1,4 @@ #include -#include #include #define WIFI_SSID "yourSSID" @@ -11,7 +10,6 @@ WiFiEventHandler wifiConnectHandler; WiFiEventHandler wifiDisconnectHandler; espMqttClientAsync mqttClient; -Ticker reconnectTimer; void connectToWiFi() { Serial.println("Connecting to Wi-Fi..."); @@ -30,8 +28,6 @@ void onWiFiConnect(const WiFiEventStationModeGotIP& event) { void onWiFiDisconnect(const WiFiEventStationModeDisconnected& event) { Serial.println("Disconnected from Wi-Fi."); - reconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi - reconnectTimer.once(5, connectToWiFi); } void onMqttConnect(bool sessionPresent) { @@ -55,7 +51,7 @@ void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) { Serial.printf("Disconnected from MQTT: %u.\n", static_cast(reason)); if (WiFi.isConnected()) { - reconnectTimer.once(5, connectToMqtt); + connectToMqtt(); } } @@ -104,6 +100,8 @@ void setup() { Serial.println(); Serial.println(); + WiFi.setAutoConnect(false); + WiFi.setAutoReconnect(true); wifiConnectHandler = WiFi.onStationModeGotIP(onWiFiConnect); wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWiFiDisconnect); diff --git a/lib/espMqttClient/examples/tls-esp32/tls-esp32.ino b/lib/espMqttClient/examples/tls-esp32/tls-esp32.ino index 73a6db4..551d241 100644 --- a/lib/espMqttClient/examples/tls-esp32/tls-esp32.ino +++ b/lib/espMqttClient/examples/tls-esp32/tls-esp32.ino @@ -1,5 +1,4 @@ #include -#include #include #define WIFI_SSID "yourSSID" @@ -16,7 +15,6 @@ const char rootCA[] = \ "-----END CERTIFICATE-----\n"; espMqttClientSecure mqttClient; -Ticker reconnectTimer; void connectToWiFi() { Serial.println("Connecting to Wi-Fi..."); @@ -39,7 +37,6 @@ void WiFiEvent(WiFiEvent_t event) { break; case SYSTEM_EVENT_STA_DISCONNECTED: Serial.println("WiFi lost connection"); - reconnectTimer.once(5, connectToWiFi); break; default: break; @@ -64,7 +61,7 @@ void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) { Serial.printf("Disconnected from MQTT: %u.\n", static_cast(reason)); if (WiFi.isConnected()) { - reconnectTimer.once(5, connectToMqtt); + connectToMqtt(); } } @@ -113,6 +110,8 @@ void setup() { Serial.println(); Serial.println(); + WiFi.setAutoConnect(false); + WiFi.setAutoReconnect(true); WiFi.onEvent(WiFiEvent); //mqttClient.setInsecure(); diff --git a/lib/espMqttClient/examples/tls-esp8266/tls-esp8266.ino b/lib/espMqttClient/examples/tls-esp8266/tls-esp8266.ino index b5b6567..b196a8c 100644 --- a/lib/espMqttClient/examples/tls-esp8266/tls-esp8266.ino +++ b/lib/espMqttClient/examples/tls-esp8266/tls-esp8266.ino @@ -1,5 +1,4 @@ #include -#include #include #define WIFI_SSID "yourSSID" @@ -14,7 +13,6 @@ const uint8_t fingerprint[] = {0xee, 0xbc, 0x4b, 0xf8, 0x57, 0xe3, 0xd3, 0xe4, 0 WiFiEventHandler wifiConnectHandler; WiFiEventHandler wifiDisconnectHandler; espMqttClientSecure mqttClient; -Ticker reconnectTimer; void connectToWiFi() { Serial.println("Connecting to Wi-Fi..."); @@ -33,8 +31,6 @@ void onWiFiConnect(const WiFiEventStationModeGotIP& event) { void onWiFiDisconnect(const WiFiEventStationModeDisconnected& event) { Serial.println("Disconnected from Wi-Fi."); - reconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi - reconnectTimer.once(5, connectToWiFi); } void onMqttConnect(bool sessionPresent) { @@ -58,7 +54,7 @@ void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) { Serial.printf("Disconnected from MQTT: %u.\n", static_cast(reason)); if (WiFi.isConnected()) { - reconnectTimer.once(5, connectToMqtt); + connectToMqtt(); } } @@ -107,6 +103,8 @@ void setup() { Serial.println(); Serial.println(); + WiFi.setAutoConnect(false); + WiFi.setAutoReconnect(true); wifiConnectHandler = WiFi.onStationModeGotIP(onWiFiConnect); wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWiFiDisconnect); diff --git a/lib/espMqttClient/src/Config.h b/lib/espMqttClient/src/Config.h index 540bb2f..aba7795 100644 --- a/lib/espMqttClient/src/Config.h +++ b/lib/espMqttClient/src/Config.h @@ -40,13 +40,17 @@ the LICENSE file. #define EMC_ALLOW_NOT_CONNECTED_PUBLISH 1 #endif +#ifndef EMC_WAIT_FOR_CONNACK +#define EMC_WAIT_FOR_CONNACK 1 +#endif + #ifndef EMC_CLIENTID_LENGTH // esp8266abc123 and esp32abcdef123456 #define EMC_CLIENTID_LENGTH 23 + 1 #endif #ifndef EMC_TASK_STACK_SIZE -#define EMC_TASK_STACK_SIZE 5000 +#define EMC_TASK_STACK_SIZE 5120 #endif #ifndef EMC_USE_WATCHDOG diff --git a/lib/espMqttClient/src/Logging.h b/lib/espMqttClient/src/Logging.h index 7c6f33e..a1d85fa 100644 --- a/lib/espMqttClient/src/Logging.h +++ b/lib/espMqttClient/src/Logging.h @@ -9,13 +9,14 @@ the LICENSE file. #pragma once #if defined(ARDUINO_ARCH_ESP32) - // Logging is en/disabled by Arduino framework macros #include #if defined(DEBUG_ESP_MQTT_CLIENT) + // Logging is en/disabled by Arduino framework macros #define emc_log_i(...) log_i(__VA_ARGS__) #define emc_log_e(...) log_e(__VA_ARGS__) #define emc_log_w(...) log_w(__VA_ARGS__) #else + // Logging is disabled #define emc_log_i(...) #define emc_log_e(...) #define emc_log_w(...) diff --git a/lib/espMqttClient/src/MqttClient.cpp b/lib/espMqttClient/src/MqttClient.cpp index 6b3758c..9868c27 100644 --- a/lib/espMqttClient/src/MqttClient.cpp +++ b/lib/espMqttClient/src/MqttClient.cpp @@ -76,7 +76,7 @@ MqttClient::MqttClient() MqttClient::~MqttClient() { disconnect(true); - _clearQueue(true); + _clearQueue(2); #if defined(ARDUINO_ARCH_ESP32) vSemaphoreDelete(_xSemaphore); if (_useTask) { @@ -144,9 +144,11 @@ bool MqttClient::disconnect(bool force) { uint16_t MqttClient::publish(const char* topic, uint8_t qos, bool retain, const uint8_t* payload, size_t length) { #if !EMC_ALLOW_NOT_CONNECTED_PUBLISH if (_state != State::connected) { + #else + if (_state > State::connected) { + #endif return 0; } - #endif uint16_t packetId = (qos > 0) ? _getNextPacketId() : 1; EMC_SEMAPHORE_TAKE(); if (!_addPacket(packetId, topic, payload, length, qos, retain)) { @@ -166,9 +168,11 @@ uint16_t MqttClient::publish(const char* topic, uint8_t qos, bool retain, const uint16_t MqttClient::publish(const char* topic, uint8_t qos, bool retain, espMqttClientTypes::PayloadCallback callback, size_t length) { #if !EMC_ALLOW_NOT_CONNECTED_PUBLISH if (_state != State::connected) { + #else + if (_state > State::connected) { + #endif return 0; } - #endif uint16_t packetId = (qos > 0) ? _getNextPacketId() : 1; EMC_SEMAPHORE_TAKE(); if (!_addPacket(packetId, topic, callback, length, qos, retain)) { @@ -180,8 +184,8 @@ uint16_t MqttClient::publish(const char* topic, uint8_t qos, bool retain, espMqt return packetId; } -void MqttClient::clearQueue(bool all) { - _clearQueue(all); +void MqttClient::clearQueue(bool deleteSessionData) { + _clearQueue(deleteSessionData ? 2 : 0); } const char* MqttClient::getClientId() const { @@ -214,6 +218,31 @@ void MqttClient::loop() { _state = State::connectingMqtt; } break; + case State::connectingMqtt: + #if EMC_WAIT_FOR_CONNACK + _sendPacket(); + _checkIncoming(); + _checkPing(); + break; + #else + // receipt of CONNACK packet will set state to CONNECTED + // client however is allowed to send packets before CONNACK is received + // so we fall through to 'connected' + [[fallthrough]]; + #endif + case State::connected: + [[fallthrough]]; + case State::disconnectingMqtt2: + if (_transport->connected()) { + // CONNECT packet is first in the queue + _checkOutbox(); + _checkIncoming(); + _checkPing(); + } else { + _state = State::disconnectingTcp1; + _disconnectReason = DisconnectReason::TCP_DISCONNECTED; + } + break; case State::disconnectingMqtt1: EMC_SEMAPHORE_TAKE(); if (_outbox.empty()) { @@ -226,25 +255,9 @@ void MqttClient::loop() { } } EMC_SEMAPHORE_GIVE(); - // fall through to 'connected' to send out DISCONN packet - [[fallthrough]]; - case State::disconnectingMqtt2: - [[fallthrough]]; - case State::connectingMqtt: - // receipt of CONNACK packet will set state to CONNECTED - // client however is allowed to send packets before CONNACK is received - // so we fall through to 'connected' - [[fallthrough]]; - case State::connected: - if (_transport->connected()) { - // CONNECT packet is first in the queue - _checkOutgoing(); - _checkIncoming(); - _checkPing(); - } else { - _state = State::disconnectingTcp1; - _disconnectReason = DisconnectReason::TCP_DISCONNECTED; - } + _checkOutbox(); + _checkIncoming(); + _checkPing(); break; case State::disconnectingTcp1: _transport->stop(); @@ -252,7 +265,7 @@ void MqttClient::loop() { break; case State::disconnectingTcp2: if (_transport->disconnected()) { - _clearQueue(false); + _clearQueue(0); _state = State::disconnected; if (_onDisconnectCallback) _onDisconnectCallback(_disconnectReason); } @@ -294,6 +307,15 @@ uint16_t MqttClient::_getNextPacketId() { return packetId; } +void MqttClient::_checkOutbox() { + while (_sendPacket() > 0) { + if (!_advanceOutbox()) { + break; + } + } +} + +/* void MqttClient::_checkOutgoing() { EMC_SEMAPHORE_TAKE(); Packet* packet = _outbox.getCurrent(); @@ -330,6 +352,57 @@ void MqttClient::_checkOutgoing() { } EMC_SEMAPHORE_GIVE(); } +*/ + +int MqttClient::_sendPacket() { + EMC_SEMAPHORE_TAKE(); + Packet* packet = _outbox.getCurrent(); + + int32_t wantToWrite = 0; + int32_t written = 0; + if (packet && (wantToWrite == written)) { + // mixing signed with unsigned here but safe because of MQTT packet size limits + wantToWrite = packet->available(_bytesSent); + if (wantToWrite == 0) { + EMC_SEMAPHORE_GIVE(); + return 0; + } + written = _transport->write(packet->data(_bytesSent), wantToWrite); + if (written < 0) { + emc_log_w("Write error, check connection"); + EMC_SEMAPHORE_GIVE(); + return -1; + } + _lastClientActivity = millis(); + _bytesSent += written; + emc_log_i("tx %zu/%zu (%02x)", _bytesSent, packet->size(), packet->packetType()); + } + EMC_SEMAPHORE_GIVE(); + return written; +} + +bool MqttClient::_advanceOutbox() { + EMC_SEMAPHORE_TAKE(); + Packet* packet = _outbox.getCurrent(); + if (packet && _bytesSent == packet->size()) { + if ((packet->packetType()) == PacketType.DISCONNECT) { + _state = State::disconnectingTcp1; + _disconnectReason = DisconnectReason::USER_OK; + } + if (packet->removable()) { + _outbox.removeCurrent(); + } else { + // handle with care! millis() returns unsigned 32 bit, token is void* + packet->token = reinterpret_cast(millis()); + if ((packet->packetType()) == PacketType.PUBLISH) packet->setDup(); + _outbox.next(); + } + packet = _outbox.getCurrent(); + _bytesSent = 0; + } + EMC_SEMAPHORE_GIVE(); + return packet; +} void MqttClient::_checkIncoming() { int32_t remainingBufferLength = _transport->read(_rxBuffer, EMC_RX_BUFFER_SIZE); @@ -355,7 +428,7 @@ void MqttClient::_checkIncoming() { } break; case PacketType.PUBLISH: - if (_state == State::disconnectingMqtt1 || _state == State::disconnectingMqtt2) break; // stop processing incoming once user has called disconnect + if (_state >= State::disconnectingMqtt1) break; // stop processing incoming once user has called disconnect _onPublish(); break; case PacketType.PUBACK: @@ -427,8 +500,9 @@ void MqttClient::_onConnack() { if (_parser.getPacket().variableHeader.fixed.connackVarHeader.returnCode == 0x00) { _pingSent = false; // reset after keepalive timeout disconnect _state = State::connected; + _advanceOutbox(); if (_parser.getPacket().variableHeader.fixed.connackVarHeader.sessionPresent == 0) { - _clearQueue(true); + _clearQueue(1); } if (_onConnectCallback) { _onConnectCallback(_parser.getPacket().variableHeader.fixed.connackVarHeader.sessionPresent); @@ -636,15 +710,11 @@ void MqttClient::_onUnsuback() { } } -void MqttClient::_clearQueue(bool clearSession) { - emc_log_i("clearing queue (clear session: %s)", clearSession ? "true" : "false"); +void MqttClient::_clearQueue(int clearData) { + emc_log_i("clearing queue (clear session: %d)", clearData); EMC_SEMAPHORE_TAKE(); espMqttClientInternals::Outbox::Iterator it = _outbox.front(); - if (clearSession) { - while (it) { - _outbox.remove(it); - } - } else { + if (clearData == 0) { // keep PUB (qos > 0, aka packetID != 0), PUBREC and PUBREL // Spec only mentions PUB and PUBREL but this lib implements method B from point 4.3.3 (Fig. 4.3) // and stores the packet id in the PUBREC packet. So we also must keep PUBREC. @@ -652,12 +722,25 @@ void MqttClient::_clearQueue(bool clearSession) { espMqttClientInternals::MQTTPacketType type = it.get()->packetType(); if (type == PacketType.PUBREC || type == PacketType.PUBREL || - (type == PacketType.PUBLISH && it.get()->packetId() != 0)) { + (type == PacketType.PUBLISH && it.get()->packetId() != 0)) { ++it; } else { _outbox.remove(it); } } + } else if (clearData == 1) { + // keep PUB + while (it) { + if (it.get()->packetType() == PacketType.PUBLISH) { + ++it; + } else { + _outbox.remove(it); + } + } + } else { // clearData == 2 + while (it) { + _outbox.remove(it); + } } EMC_SEMAPHORE_GIVE(); } diff --git a/lib/espMqttClient/src/MqttClient.h b/lib/espMqttClient/src/MqttClient.h index 1d8f906..f95b966 100644 --- a/lib/espMqttClient/src/MqttClient.h +++ b/lib/espMqttClient/src/MqttClient.h @@ -63,13 +63,13 @@ class MqttClient { uint16_t publish(const char* topic, uint8_t qos, bool retain, const uint8_t* payload, size_t length); uint16_t publish(const char* topic, uint8_t qos, bool retain, const char* payload); uint16_t publish(const char* topic, uint8_t qos, bool retain, espMqttClientTypes::PayloadCallback callback, size_t length); - void clearQueue(bool all = false); // Not MQTT compliant and may cause unpredictable results when `all` = true! + void clearQueue(bool deleteSessionData = false); // Not MQTT compliant and may cause unpredictable results when `deleteSessionData` = true! const char* getClientId() const; #if defined(ARDUINO_ARCH_ESP32) - void loop(); protected: #endif + void loop(); #if defined(ARDUINO_ARCH_ESP32) explicit MqttClient(bool useTask, uint8_t priority = 1, uint8_t core = 1); bool _useTask; @@ -106,15 +106,15 @@ class MqttClient { // state is protected to allow state changes by the transport system, defined in child classes // eg. to allow AsyncTCP enum class State { - disconnected, - connectingTcp1, - connectingTcp2, - connectingMqtt, - connected, - disconnectingMqtt1, - disconnectingMqtt2, - disconnectingTcp1, - disconnectingTcp2 + disconnected = 0, + connectingTcp1 = 1, + connectingTcp2 = 2, + connectingMqtt = 3, + connected = 4, + disconnectingMqtt1 = 5, + disconnectingMqtt2 = 6, + disconnectingTcp1 = 7, + disconnectingTcp2 = 8 }; std::atomic _state; @@ -161,7 +161,9 @@ class MqttClient { return false; } - void _checkOutgoing(); + void _checkOutbox(); + int _sendPacket(); + bool _advanceOutbox(); void _checkIncoming(); void _checkPing(); @@ -174,7 +176,9 @@ class MqttClient { void _onSuback(); void _onUnsuback(); - void _clearQueue(bool clearSession); + void _clearQueue(int clearData); // 0: keep session, + // 1: keep only PUBLISH qos > 0 + // 2: delete all void _onError(uint16_t packetId, espMqttClientTypes::Error error); #if defined(ARDUINO_ARCH_ESP32) diff --git a/lib/espMqttClient/src/espMqttClientAsync.cpp b/lib/espMqttClient/src/espMqttClientAsync.cpp index 156572c..bc53878 100644 --- a/lib/espMqttClient/src/espMqttClientAsync.cpp +++ b/lib/espMqttClient/src/espMqttClientAsync.cpp @@ -66,69 +66,3 @@ void espMqttClientAsync::onPollCb(void* a, AsyncClient* c) { } #endif - - -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) -#if defined(ARDUINO_ARCH_ESP32) -espMqttClientSecureAsync::espMqttClientSecureAsync(uint8_t priority, uint8_t core) - : MqttClientSetup(false, priority, core) - , _client() { -#else - espMqttClientSecure::espMqttClientSecure() -: _client() { -#endif - _transport = &_client; -} - -espMqttClientSecureAsync& espMqttClientSecureAsync::setInsecure() { - _client.client.setInsecure(); - return *this; -} - -#if defined(ARDUINO_ARCH_ESP32) -espMqttClientSecureAsync& espMqttClientSecureAsync::setCACert(const char* rootCA) { - _client.client.setCACert(rootCA); - return *this; -} - -espMqttClientSecureAsync& espMqttClientSecureAsync::setCertificate(const char* clientCa) { - _client.client.setCertificate(clientCa); - return *this; -} - -espMqttClientSecureAsync& espMqttClientSecureAsync::setPrivateKey(const char* privateKey) { - _client.client.setPrivateKey(privateKey); - return *this; -} - -espMqttClientSecureAsync& espMqttClientSecureAsync::setPreSharedKey(const char* pskIdent, const char* psKey) { - _client.client.setPreSharedKey(pskIdent, psKey); - return *this; -} -#elif defined(ARDUINO_ARCH_ESP8266) -espMqttClientSecureAsync& espMqttClientSecureAsync::setFingerprint(const uint8_t fingerprint[20]) { - _client.client.setFingerprint(fingerprint); - return *this; -} - -espMqttClientSecureAsync& espMqttClientSecureAsync::setTrustAnchors(const X509List *ta) { - _client.client.setTrustAnchors(ta); - return *this; -} - -espMqttClientSecureAsync& espMqttClientSecureAsync::setClientRSACert(const X509List *cert, const PrivateKey *sk) { - _client.client.setClientRSACert(cert, sk); - return *this; -} - -espMqttClientSecureAsync& espMqttClientSecureAsync::setClientECCert(const X509List *cert, const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type) { - _client.client.setClientECCert(cert, sk, allowed_usages, cert_issuer_key_type); - return *this; -} - -espMqttClientSecureAsync& espMqttClientSecureAsync::setCertStore(CertStoreBase *certStore) { - _client.client.setCertStore(certStore); - return *this; -} -#endif -#endif \ No newline at end of file diff --git a/lib/espMqttClient/src/espMqttClientAsync.h b/lib/espMqttClient/src/espMqttClientAsync.h index 3493989..f3f321d 100644 --- a/lib/espMqttClient/src/espMqttClientAsync.h +++ b/lib/espMqttClient/src/espMqttClientAsync.h @@ -16,7 +16,6 @@ the LICENSE file. #include "Transport/ClientAsync.h" #include "MqttClientSetup.h" -#include "Transport/ClientSecureSync.h" class espMqttClientAsync : public MqttClientSetup { public: @@ -39,32 +38,3 @@ class espMqttClientAsync : public MqttClientSetup { }; #endif - - -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) -class espMqttClientSecureAsync : public MqttClientSetup { -public: -#if defined(ARDUINO_ARCH_ESP32) - explicit espMqttClientSecureAsync(uint8_t priority = 1, uint8_t core = 1); -#else - espMqttClientSecure(); -#endif - espMqttClientSecureAsync& setInsecure(); -#if defined(ARDUINO_ARCH_ESP32) - espMqttClientSecureAsync& setCACert(const char* rootCA); - espMqttClientSecureAsync& setCertificate(const char* clientCa); - espMqttClientSecureAsync& setPrivateKey(const char* privateKey); - espMqttClientSecureAsync& setPreSharedKey(const char* pskIdent, const char* psKey); -#else - espMqttClientSecure& setFingerprint(const uint8_t fingerprint[20]); - espMqttClientSecure& setTrustAnchors(const X509List *ta); - espMqttClientSecure& setClientRSACert(const X509List *cert, const PrivateKey *sk); - espMqttClientSecure& setClientECCert(const X509List *cert, const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type); - espMqttClientSecure& setCertStore(CertStoreBase *certStore); -#endif - -protected: - espMqttClientInternals::ClientSecureSync _client; -}; - -#endif \ No newline at end of file diff --git a/lib/espMqttClient/test/test_client_native/test_client_native.cpp b/lib/espMqttClient/test/test_client_native/test_client_native.cpp index 01a3896..7afd7e1 100644 --- a/lib/espMqttClient/test/test_client_native/test_client_native.cpp +++ b/lib/espMqttClient/test/test_client_native/test_client_native.cpp @@ -43,6 +43,8 @@ void test_connect() { TEST_ASSERT_TRUE(mqttClient.connected()); TEST_ASSERT_TRUE(onConnectCalledTest); TEST_ASSERT_FALSE(sessionPresentTest); + + mqttClient.onConnect(nullptr); } /* @@ -93,6 +95,8 @@ void test_subscribe() { TEST_ASSERT_TRUE(mqttClient.connected()); TEST_ASSERT_TRUE(subscribeTest); + + mqttClient.onSubscribe(nullptr); } /* @@ -133,6 +137,9 @@ void test_publish() { TEST_ASSERT_GREATER_THAN_UINT16(0, sendQos2Test); TEST_ASSERT_EQUAL_INT(2, publishSendTest); TEST_ASSERT_EQUAL_INT(3, publishReceiveTest); + + mqttClient.onPublish(nullptr); + mqttClient.onMessage(nullptr); } void test_publish_empty() { @@ -165,6 +172,9 @@ void test_publish_empty() { TEST_ASSERT_GREATER_THAN_UINT16(0, sendQos2Test); TEST_ASSERT_EQUAL_INT(2, publishSendEmptyTest); TEST_ASSERT_EQUAL_INT(3, publishReceiveEmptyTest); + + mqttClient.onPublish(nullptr); + mqttClient.onMessage(nullptr); } /* @@ -200,6 +210,9 @@ void test_receive1() { TEST_ASSERT_TRUE(mqttClient.connected()); TEST_ASSERT_GREATER_THAN_INT(0, publishReceive1Test); + + mqttClient.onMessage(nullptr); + mqttClient.onSubscribe(nullptr); } /* @@ -235,6 +248,9 @@ void test_receive2() { TEST_ASSERT_TRUE(mqttClient.connected()); TEST_ASSERT_EQUAL_INT(1, publishReceive2Test); + + mqttClient.onMessage(nullptr); + mqttClient.onSubscribe(nullptr); } @@ -261,6 +277,8 @@ void test_unsubscribe() { TEST_ASSERT_TRUE(mqttClient.connected()); TEST_ASSERT_TRUE(unsubscribeTest); + + mqttClient.onUnsubscribe(nullptr); } /* @@ -288,6 +306,71 @@ void test_disconnect() { TEST_ASSERT_TRUE(onDisconnectCalled); TEST_ASSERT_EQUAL_UINT8(espMqttClientTypes::DisconnectReason::USER_OK, reasonTest); TEST_ASSERT_TRUE(mqttClient.disconnected()); + + mqttClient.onDisconnect(nullptr); +} + +void test_pub_before_connect() { + std::atomic onConnectCalledTest(false); + std::atomic publishSendTest(0); + bool sessionPresentTest = true; + mqttClient.setServer(broker, broker_port) + .setCleanSession(true) + .setKeepAlive(5) + .onConnect([&](bool sessionPresent) mutable { + sessionPresentTest = sessionPresent; + onConnectCalledTest = true; + }) + .onPublish([&](uint16_t packetId) mutable { + (void) packetId; + publishSendTest++; + }); + uint16_t sendQos0Test = mqttClient.publish("test/test", 0, false, "test0"); + uint16_t sendQos1Test = mqttClient.publish("test/test", 1, false, "test1"); + uint16_t sendQos2Test = mqttClient.publish("test/test", 2, false, "test2"); + mqttClient.connect(); + uint32_t start = millis(); + while (millis() - start < 2000) { + if (onConnectCalledTest) { + break; + } + std::this_thread::yield(); + } + TEST_ASSERT_TRUE(mqttClient.connected()); + TEST_ASSERT_TRUE(onConnectCalledTest); + TEST_ASSERT_FALSE(sessionPresentTest); + start = millis(); + while (millis() - start < 10000) { + std::this_thread::yield(); + } + + TEST_ASSERT_EQUAL_UINT16(1, sendQos0Test); + TEST_ASSERT_GREATER_THAN_UINT16(0, sendQos1Test); + TEST_ASSERT_GREATER_THAN_UINT16(0, sendQos2Test); + TEST_ASSERT_EQUAL_INT(2, publishSendTest); + + mqttClient.onConnect(nullptr); + mqttClient.onPublish(nullptr); +} + +void final_disconnect() { + std::atomic onDisconnectCalled(false); + mqttClient.onDisconnect([&](espMqttClientTypes::DisconnectReason reason) mutable { + (void) reason; + onDisconnectCalled = true; + }); + mqttClient.disconnect(); + uint32_t start = millis(); + while (millis() - start < 2000) { + if (onDisconnectCalled) { + break; + } + std::this_thread::yield(); + } + if (mqttClient.connected()) { + mqttClient.disconnect(true); + } + mqttClient.onDisconnect(nullptr); } int main() { @@ -307,6 +390,8 @@ int main() { RUN_TEST(test_receive2); RUN_TEST(test_unsubscribe); RUN_TEST(test_disconnect); + RUN_TEST(test_pub_before_connect); + final_disconnect(); exitProgram = true; t.join(); return UNITY_END(); diff --git a/networkDevices/EthLan8720Device.cpp b/networkDevices/EthLan8720Device.cpp index 83aa9a5..3c5a75d 100644 --- a/networkDevices/EthLan8720Device.cpp +++ b/networkDevices/EthLan8720Device.cpp @@ -25,7 +25,7 @@ EthLan8720Device::EthLan8720Device(const String& hostname, Preferences* _prefere { Log->println(F("MQTT over TLS.")); Log->println(_ca); - _mqttClientSecure = new espMqttClientSecureAsync(); + _mqttClientSecure = new espMqttClientWifiSecure(); _mqttClientSecure->setCACert(_ca); if(crtLength > 1 && keyLength > 1) // length is 1 when empty { @@ -38,7 +38,7 @@ EthLan8720Device::EthLan8720Device(const String& hostname, Preferences* _prefere } else { Log->println(F("MQTT without TLS.")); - _mqttClient = new espMqttClientAsync(); + _mqttClient = new espMqttClientWifi(); } if(_preferences->getBool(preference_mqtt_log_enabled)) @@ -112,11 +112,11 @@ void EthLan8720Device::update() { if(_useEncryption) { - _mqttClientSecure->loop(); + _mqttClientSecure->update(); } else { - _mqttClient->loop(); + _mqttClient->update(); } } diff --git a/networkDevices/EthLan8720Device.h b/networkDevices/EthLan8720Device.h index a74af82..1d23615 100644 --- a/networkDevices/EthLan8720Device.h +++ b/networkDevices/EthLan8720Device.h @@ -4,7 +4,7 @@ #include #include #include "NetworkDevice.h" -#include "espMqttClientAsync.h" +#include "espMqttClientWifi.h" class EthLan8720Device : public NetworkDevice { @@ -54,8 +54,8 @@ public: private: void onDisconnected(); - espMqttClientAsync* _mqttClient = nullptr; - espMqttClientSecureAsync* _mqttClientSecure = nullptr; + espMqttClientWifi* _mqttClient = nullptr; + espMqttClientWifiSecure* _mqttClientSecure = nullptr; bool _restartOnDisconnect = false; bool _startAp = false; diff --git a/networkDevices/W5500Device.cpp b/networkDevices/W5500Device.cpp index 93c3343..db414ab 100644 --- a/networkDevices/W5500Device.cpp +++ b/networkDevices/W5500Device.cpp @@ -197,7 +197,7 @@ void W5500Device::initializeMacAddress(byte *mac) void W5500Device::update() { _maintainResult = Ethernet.maintain(); - _mqttClient.loop(); + _mqttClient.update(); } int8_t W5500Device::signalStrength() diff --git a/networkDevices/WifiDevice.cpp b/networkDevices/WifiDevice.cpp index 92188f1..7ddf5ae 100644 --- a/networkDevices/WifiDevice.cpp +++ b/networkDevices/WifiDevice.cpp @@ -25,7 +25,7 @@ WifiDevice::WifiDevice(const String& hostname, Preferences* _preferences) { Log->println(F("MQTT over TLS.")); Log->println(_ca); - _mqttClientSecure = new espMqttClientSecureAsync(); + _mqttClientSecure = new espMqttClientWifiSecure(); _mqttClientSecure->setCACert(_ca); if(crtLength > 1 && keyLength > 1) // length is 1 when empty { @@ -38,7 +38,7 @@ WifiDevice::WifiDevice(const String& hostname, Preferences* _preferences) } else { Log->println(F("MQTT without TLS.")); - _mqttClient = new espMqttClientAsync(); + _mqttClient = new espMqttClientWifi(); } if(_preferences->getBool(preference_mqtt_log_enabled)) @@ -144,11 +144,11 @@ void WifiDevice::update() { if(_useEncryption) { - _mqttClientSecure->loop(); + _mqttClientSecure->update(); } else { - _mqttClient->loop(); + _mqttClient->update(); } } diff --git a/networkDevices/WifiDevice.h b/networkDevices/WifiDevice.h index 52a5c64..53414e2 100644 --- a/networkDevices/WifiDevice.h +++ b/networkDevices/WifiDevice.h @@ -5,7 +5,7 @@ #include #include "NetworkDevice.h" #include "WiFiManager.h" -#include "espMqttClientAsync.h" +#include "espMqttClientWifi.h" class WifiDevice : public NetworkDevice { @@ -58,8 +58,8 @@ private: void onDisconnected(); WiFiManager _wm; - espMqttClientAsync* _mqttClient = nullptr; - espMqttClientSecureAsync* _mqttClientSecure = nullptr; + espMqttClientWifi* _mqttClient = nullptr; + espMqttClientWifiSecure* _mqttClientSecure = nullptr; bool _restartOnDisconnect = false; bool _startAp = false; diff --git a/networkDevices/espMqttClientW5500.cpp b/networkDevices/espMqttClientW5500.cpp index eeb7e0b..aa4bd84 100644 --- a/networkDevices/espMqttClientW5500.cpp +++ b/networkDevices/espMqttClientW5500.cpp @@ -6,3 +6,8 @@ espMqttClientW5500::espMqttClientW5500(uint8_t priority, uint8_t core) { _transport = &_client; } + +void espMqttClientW5500::update() +{ + loop(); +} diff --git a/networkDevices/espMqttClientW5500.h b/networkDevices/espMqttClientW5500.h index f880ed7..76c3520 100644 --- a/networkDevices/espMqttClientW5500.h +++ b/networkDevices/espMqttClientW5500.h @@ -11,6 +11,8 @@ public: espMqttClient(); #endif + void update(); + protected: #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) espMqttClientInternals::ClientSyncW5500 _client; diff --git a/networkDevices/espMqttClientWifi.cpp b/networkDevices/espMqttClientWifi.cpp new file mode 100644 index 0000000..4ce1c87 --- /dev/null +++ b/networkDevices/espMqttClientWifi.cpp @@ -0,0 +1,97 @@ +/* +Copyright (c) 2022 Bert Melis. All rights reserved. + +This work is licensed under the terms of the MIT license. +For a copy, see or +the LICENSE file. +*/ + +#include "espMqttClientWifi.h" + +#if defined(ARDUINO_ARCH_ESP32) +espMqttClientWifi::espMqttClientWifi(uint8_t priority, uint8_t core) + : MqttClientSetup(false, priority, core) + , _client() { +#else + espMqttClient::espMqttClient() +: _client() { +#endif + _transport = &_client; +} + +void espMqttClientWifi::update() +{ + loop(); +} + +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP32) +espMqttClientWifiSecure::espMqttClientWifiSecure(uint8_t priority, uint8_t core) + : MqttClientSetup(false, priority, core) + , _client() { +#else + espMqttClientSecure::espMqttClientSecure() +: _client() { +#endif + _transport = &_client; +} + +espMqttClientWifiSecure& espMqttClientWifiSecure::setInsecure() { + _client.client.setInsecure(); + return *this; +} + +#if defined(ARDUINO_ARCH_ESP32) +espMqttClientWifiSecure& espMqttClientWifiSecure::setCACert(const char* rootCA) { + _client.client.setCACert(rootCA); + return *this; +} + +espMqttClientWifiSecure& espMqttClientWifiSecure::setCertificate(const char* clientCa) { + _client.client.setCertificate(clientCa); + return *this; +} + +espMqttClientWifiSecure& espMqttClientWifiSecure::setPrivateKey(const char* privateKey) { + _client.client.setPrivateKey(privateKey); + return *this; +} + +espMqttClientWifiSecure& espMqttClientWifiSecure::setPreSharedKey(const char* pskIdent, const char* psKey) { + _client.client.setPreSharedKey(pskIdent, psKey); + return *this; +} + +void espMqttClientWifiSecure::update() +{ + loop(); +} + +#elif defined(ARDUINO_ARCH_ESP8266) +espMqttClientWifiSecure& espMqttClientWifiSecure::setFingerprint(const uint8_t fingerprint[20]) { + _client.client.setFingerprint(fingerprint); + return *this; +} + +espMqttClientWifiSecure& espMqttClientWifiSecure::setTrustAnchors(const X509List *ta) { + _client.client.setTrustAnchors(ta); + return *this; +} + +espMqttClientWifiSecure& espMqttClientWifiSecure::setClientRSACert(const X509List *cert, const PrivateKey *sk) { + _client.client.setClientRSACert(cert, sk); + return *this; +} + +espMqttClientWifiSecure& espMqttClientWifiSecure::setClientECCert(const X509List *cert, const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type) { + _client.client.setClientECCert(cert, sk, allowed_usages, cert_issuer_key_type); + return *this; +} + +espMqttClientWifiSecure& espMqttClientWifiSecure::setCertStore(CertStoreBase *certStore) { + _client.client.setCertStore(certStore); + return *this; +} +#endif + +#endif diff --git a/networkDevices/espMqttClientWifi.h b/networkDevices/espMqttClientWifi.h new file mode 100644 index 0000000..e78527c --- /dev/null +++ b/networkDevices/espMqttClientWifi.h @@ -0,0 +1,69 @@ +/* +Copyright (c) 2022 Bert Melis. All rights reserved. + +API is based on the original work of Marvin Roger: +https://github.com/marvinroger/async-mqtt-client + +This work is licensed under the terms of the MIT license. +For a copy, see or +the LICENSE file. +*/ + +#pragma once + +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +#include "Transport/ClientSync.h" +#include "Transport/ClientSecureSync.h" +#elif defined(__linux__) +#include "Transport/ClientPosix.h" +#endif + +#include "MqttClientSetup.h" + +class espMqttClientWifi : public MqttClientSetup { +public: +#if defined(ARDUINO_ARCH_ESP32) + explicit espMqttClientWifi(uint8_t priority = 1, uint8_t core = 1); +#else + espMqttClient(); +#endif + + void update(); + +protected: +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + espMqttClientInternals::ClientSync _client; +#elif defined(__linux__) + espMqttClientInternals::ClientPosix _client; +#endif +}; + +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +class espMqttClientWifiSecure : public MqttClientSetup { +public: +#if defined(ARDUINO_ARCH_ESP32) + explicit espMqttClientWifiSecure(uint8_t priority = 1, uint8_t core = 1); +#else + espMqttClientSecure(); +#endif + espMqttClientWifiSecure& setInsecure(); +#if defined(ARDUINO_ARCH_ESP32) + espMqttClientWifiSecure& setCACert(const char* rootCA); + espMqttClientWifiSecure& setCertificate(const char* clientCa); + espMqttClientWifiSecure& setPrivateKey(const char* privateKey); + espMqttClientWifiSecure& setPreSharedKey(const char* pskIdent, const char* psKey); +#else + espMqttClientSecure& setFingerprint(const uint8_t fingerprint[20]); + espMqttClientSecure& setTrustAnchors(const X509List *ta); + espMqttClientSecure& setClientRSACert(const X509List *cert, const PrivateKey *sk); + espMqttClientSecure& setClientECCert(const X509List *cert, const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type); + espMqttClientSecure& setCertStore(CertStoreBase *certStore); +#endif + + void update(); + +protected: + espMqttClientInternals::ClientSecureSync _client; +}; + +#endif