diff --git a/.github/workflows/build_esp_idf.yml b/.github/workflows/build_esp_idf.yml new file mode 100644 index 0000000..ff927cf --- /dev/null +++ b/.github/workflows/build_esp_idf.yml @@ -0,0 +1,20 @@ +name: Build simple-esp32 with ESP IDF + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: 'recursive' + path: ${{ github.workspace }}/app + + - name: esp-idf build + uses: espressif/esp-idf-ci-action@v1 + with: + esp_idf_version: v4.4.6 + target: esp32 + path: app/examples/simple-esp32-idf \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c78a8e4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,10 @@ +[submodule "examples/simple-esp32-idf/components/arduino-esp32"] + path = examples/simple-esp32-idf/components/arduino-esp32 + url = https://github.com/espressif/arduino-esp32 + branch = idf-release/v4.4 +[submodule "examples/simple-esp32-idf/components/AsyncTCP"] + path = examples/simple-esp32-idf/components/AsyncTCP + url = https://github.com/me-no-dev/AsyncTCP +[submodule "examples/simple-esp32-idf/components/espMqttClient"] + path = examples/simple-esp32-idf/components/espMqttClient + url = https://github.com/bertmelis/espMqttClient diff --git a/README.md b/README.md index a203ef1..b330fdd 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ MQTT client library for the Espressif devices ESP8266 and ESP32 on the Arduino f Aims to be a non-blocking, fully compliant MQTT 3.1.1 client. ![platformio](https://github.com/bertmelis/espMqttClient/actions/workflows/build_platformio.yml/badge.svg) +![ESP IDF Simple ESP32](https://github.com/bertmelis/espMqttClient/actions/workflows/build_esp_idf.yml/badge.svg) ![cpplint](https://github.com/bertmelis/espMqttClient/actions/workflows/cpplint.yml/badge.svg) ![cppcheck](https://github.com/bertmelis/espMqttClient/actions/workflows/cppcheck.yml/badge.svg) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/bertmelis/library/espMqttClient.svg)](https://registry.platformio.org/libraries/bertmelis/espMqttClient) @@ -18,7 +19,7 @@ Aims to be a non-blocking, fully compliant MQTT 3.1.1 client. - Fully async clients available via [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) or [ESPAsnycTCP](https://github.com/me-no-dev/ESPAsyncTCP) (no TLS supported) - Supported platforms: - Espressif ESP8266 and ESP32 using the Arduino framework - - Espressif ESP32 using the ESP IDF + - Espressif ESP32 using the ESP IDF, see [esp idf component](https://docs.espressif.com/projects/arduino-esp32/en/latest/esp-idf_component.html) - Basic Linux compatibility*. This includes WSL on Windows > Linux compatibility is mainly for automatic testing. It relies on a quick and dirty Arduino-style `Client` with a POSIX TCP client underneath and Arduino-style `ClientPosixIPAddress` class. These are lacking many features needed for proper Linux support. diff --git a/examples/simple-esp32-idf/CMakeLists.txt b/examples/simple-esp32-idf/CMakeLists.txt new file mode 100644 index 0000000..e1f4c03 --- /dev/null +++ b/examples/simple-esp32-idf/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +SET(SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(simple-esp32-idf) \ No newline at end of file diff --git a/examples/simple-esp32-idf/components/AsyncTCP b/examples/simple-esp32-idf/components/AsyncTCP new file mode 160000 index 0000000..ca8ac5f --- /dev/null +++ b/examples/simple-esp32-idf/components/AsyncTCP @@ -0,0 +1 @@ +Subproject commit ca8ac5f919d02bea07b474531981ddbfd64de97c diff --git a/examples/simple-esp32-idf/components/arduino-esp32 b/examples/simple-esp32-idf/components/arduino-esp32 new file mode 160000 index 0000000..b1500bf --- /dev/null +++ b/examples/simple-esp32-idf/components/arduino-esp32 @@ -0,0 +1 @@ +Subproject commit b1500bf9cb3424f2b0d94caad2480138e781c518 diff --git a/examples/simple-esp32-idf/components/espMqttClient b/examples/simple-esp32-idf/components/espMqttClient new file mode 160000 index 0000000..ee8adb9 --- /dev/null +++ b/examples/simple-esp32-idf/components/espMqttClient @@ -0,0 +1 @@ +Subproject commit ee8adb927801ad2f07707377ec63bada14c92279 diff --git a/examples/simple-esp32-idf/main/CMakeLists.txt b/examples/simple-esp32-idf/main/CMakeLists.txt new file mode 100644 index 0000000..475d0f7 --- /dev/null +++ b/examples/simple-esp32-idf/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register( + SRCS "main.cpp" + INCLUDE_DIRS "") \ No newline at end of file diff --git a/examples/simple-esp32-idf/main/main.cpp b/examples/simple-esp32-idf/main/main.cpp new file mode 100644 index 0000000..8833490 --- /dev/null +++ b/examples/simple-esp32-idf/main/main.cpp @@ -0,0 +1,142 @@ +#include +#include + +#include + +#define WIFI_SSID "yourSSID" +#define WIFI_PASSWORD "yourpass" + +#define MQTT_HOST IPAddress(192, 168, 1, 10) +#define MQTT_PORT 1883 + +espMqttClient mqttClient; +bool reconnectMqtt = false; +uint32_t lastReconnect = 0; + +void connectToWiFi() { + Serial.println("Connecting to Wi-Fi..."); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +} + +void connectToMqtt() { + Serial.println("Connecting to MQTT..."); + if (!mqttClient.connect()) { + reconnectMqtt = true; + lastReconnect = millis(); + Serial.println("Connecting failed."); + } else { + reconnectMqtt = false; + } +} + +void WiFiEvent(WiFiEvent_t event) { + Serial.printf("[WiFi-event] event: %d\n", event); + switch(event) { + case SYSTEM_EVENT_STA_GOT_IP: + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + connectToMqtt(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + Serial.println("WiFi lost connection"); + break; + default: + break; + } +} + +void onMqttConnect(bool sessionPresent) { + Serial.println("Connected to MQTT."); + Serial.print("Session present: "); + Serial.println(sessionPresent); + uint16_t packetIdSub = mqttClient.subscribe("foo/bar", 2); + Serial.print("Subscribing at QoS 2, packetId: "); + Serial.println(packetIdSub); + mqttClient.publish("foo/bar", 0, true, "test 1"); + Serial.println("Publishing at QoS 0"); + uint16_t packetIdPub1 = mqttClient.publish("foo/bar", 1, true, "test 2"); + Serial.print("Publishing at QoS 1, packetId: "); + Serial.println(packetIdPub1); + uint16_t packetIdPub2 = mqttClient.publish("foo/bar", 2, true, "test 3"); + Serial.print("Publishing at QoS 2, packetId: "); + Serial.println(packetIdPub2); +} + +void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) { + Serial.printf("Disconnected from MQTT: %u.\n", static_cast(reason)); + + if (WiFi.isConnected()) { + reconnectMqtt = true; + lastReconnect = millis(); + } +} + +void onMqttSubscribe(uint16_t packetId, const espMqttClientTypes::SubscribeReturncode* codes, size_t len) { + Serial.println("Subscribe acknowledged."); + Serial.print(" packetId: "); + Serial.println(packetId); + for (size_t i = 0; i < len; ++i) { + Serial.print(" qos: "); + Serial.println(static_cast(codes[i])); + } +} + +void onMqttUnsubscribe(uint16_t packetId) { + Serial.println("Unsubscribe acknowledged."); + Serial.print(" packetId: "); + Serial.println(packetId); +} + +void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total) { + (void) payload; + Serial.println("Publish received."); + Serial.print(" topic: "); + Serial.println(topic); + Serial.print(" qos: "); + Serial.println(properties.qos); + Serial.print(" dup: "); + Serial.println(properties.dup); + Serial.print(" retain: "); + Serial.println(properties.retain); + Serial.print(" len: "); + Serial.println(len); + Serial.print(" index: "); + Serial.println(index); + Serial.print(" total: "); + Serial.println(total); +} + +void onMqttPublish(uint16_t packetId) { + Serial.println("Publish acknowledged."); + Serial.print(" packetId: "); + Serial.println(packetId); +} + +void setup() { + Serial.begin(115200); + Serial.println(); + Serial.println(); + + WiFi.setAutoConnect(false); + WiFi.setAutoReconnect(true); + WiFi.onEvent(WiFiEvent); + + mqttClient.onConnect(onMqttConnect); + mqttClient.onDisconnect(onMqttDisconnect); + mqttClient.onSubscribe(onMqttSubscribe); + mqttClient.onUnsubscribe(onMqttUnsubscribe); + mqttClient.onMessage(onMqttMessage); + mqttClient.onPublish(onMqttPublish); + mqttClient.setServer(MQTT_HOST, MQTT_PORT); + + connectToWiFi(); +} + +void loop() { + static uint32_t currentMillis = millis(); + + if (reconnectMqtt && currentMillis - lastReconnect > 5000) { + connectToMqtt(); + } +} diff --git a/examples/simple-esp32-idf/sdkconfig.defaults b/examples/simple-esp32-idf/sdkconfig.defaults new file mode 100644 index 0000000..4661ad2 --- /dev/null +++ b/examples/simple-esp32-idf/sdkconfig.defaults @@ -0,0 +1,39 @@ +# +# Bootloader config +# +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y +CONFIG_BOOTLOADER_LOG_LEVEL=0 + +# +# Serial flasher config +# +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +CONFIG_ESPTOOLPY_FLASHFREQ_40M=y +CONFIG_ESPTOOLPY_FLASHFREQ="40m" +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" +# +# Partition Table +# +CONFIG_PARTITION_TABLE_CUSTOM=n + +# +# Arduino Configuration +# +CONFIG_ARDUINO_VARIANT="esp32" +CONFIG_ENABLE_ARDUINO_DEPENDS=y +CONFIG_AUTOSTART_ARDUINO=y + +# +# FreeRTOS +# +# 1000 require for Arduino +CONFIG_FREERTOS_HZ=1000 + +#ASYNC_TCP +CONFIG_ASYNC_TCP_RUN_NO_AFFINITY=y + +#MBEDTLS +CONFIG_MBEDTLS_PSK_MODES=y \ No newline at end of file