2022/08/14

Android #36 IoT 基本程式庫 Wifimanager FOTA MQTT (IOT Essential Code base with wifimanager, ElegantOTA, & MQTT)

Hi, Welcome to weekend project with Stonez56

This week's Arduino episode #37, "Essential IoT Code Base- Wifimanager FOTA + MQTT"

Here is the source code: https://stonez56.blogspot.com/2022/08/android-36-iot-wifimanager-fota-mqtt.html 


Today, I will show how to combine three commonly used IoT libraries;

WiFimanager, AsyncElegantOTA, and MQTT To become a common IoT code base. So, for our future projects, ESP8266 or ESP32, would have these basic functions.

Let's first look at these three libraries:

  • Wifimanager = Wi-Fi password management, no need to re-burn the code to change the Wi-Fi SSID & password
  • FOTA = Use Wi-Fi to update ESP32 code, you can burn code without connecting to USB
  • MQTT = Streamlined and lightweight communication protocol (Message Queueing Telemetry Transport)


This episode will only introduce how to integrate MQTT into Wifimanager + AsyncElegantFOTA.

To learn how to start Wifimanager + AsyncElegantOTA, Please watch Android #27 Wifimanager + OTA for ESP32/ESP8266 (ESPAsyncWifimanager / ESPAsyncElegantOTA)) https://youtu.be/UlRLTvl4DRc 


==References==

Arduino Library URL:


==Sample code URL==

ESPAsync_WiFiManager minimal: https://github.com/khoih-prog/ESPAsync_WiFiManager/blob/master/examples/Async_AutoConnect_ESP32_minimal/Async_AutoConnect_ESP32_minimal.ino 


ESP32 Async OTA : https://github.com/ayushsharma82/AsyncElegantOTA/blob/master/examples/ESP32_Async_Demo/ESP32_Async_Demo.ino 


If you don't have enough time, you can also select the part you want to watch from the timeline below!

Video Timeline: 00:00 Start 01:39 Demonstration of project results 01:57 mqttgo.io MQTT server, free, fast, & stable 05:52 Install three libraries 07:14 Added two ESP32 PINs as MQTT example 07:41 Encrypt the firmware update (ElegantOTA) page 11:44 Explain how the MQTT callback function works 13:07 Control ESP32 I/O pins with MQTT 15:16 Future program can be written from here

=====中文版本======

大家好, 歡迎收看本週的Weekend project with Stonez56。 

本周要進行的是 Arduino 第36集,"IoT 基本程式庫 - Wifimanager FOTA + MQTT”

今天來跟大家介紹如何把 一般的 IoT 專案常用到的三個程式庫,  WiFiManager 以及WiFi 韌體更新FOTA (Firmware Over the Air), 再加上 MQTT 三個整合在一起, 變成一個常用的 Code base.  往後你的 ESP32 IoT 專案呢, 就可以俱備這些基本功能了! 


  • Wifimanager = WiFi 密碼管理, 不用重新燒 Code 改 Wifi SSID & 密碼
  • FOTA = 用Wi-Fi更新ESP32程式碼, 不用接USB就可以燒Code
  • MQTT = 精簡輕量化的通訊協定(Message Queueing Telemetry Transport)


本集僅會介紹如何把 MQTT 整合到 Wifimanager + AsyncElegantFOTA

若想了解如何整合 Wifimanager + AsyncElegantOTA, 

請觀看 Arduino #26 AsyncWifimanager ElegantOTA ESP32 (WiFi 密碼管理+ WiFi 韌體更新) https://youtu.be/zepkinJ46Zg  




==參考資料==

Arduino Library URL: 


==Sample code URL==


如果時間不夠的朋友, 也可以從以下的時間軸挑選想看的部份即可! 

影片時間軸:

影片時間軸: 00:00 Start 01:39 專案成果示範 01:57 mqttgo.io 快速免費的 MQTT 伺服器 05:52 安裝三支程式庫 07:14 加入兩個 ESP32 PIN做為MQTT範例 07:41 為韌體更新(ElegantOTA)頁面加密 11:44 說明MQTT callback 函數運作方式 13:07 MQTT由此控制ESP32 PIN 15:16 把你的程式可以寫在這裡


IoT基本程式庫原始程式:


/** 
 * Arduino code base for IoT Projects
 * By: Stonez56 aka Kevin Chen 2022-08-16
 * 
 * This source code combined three most common Arduino libraries for IoT Projects, 
 * ESPAsync_Wifimanager, AsyncElegantOTA, & Pubsubclient MQTT Client.
 * 
 * 1. ESPAsync_WiFiManager: https://github.com/khoih-prog/ESPAsync_WiFiManager 
 * 2. AsyncElegantOTA: https://github.com/ayushsharma82/AsyncElegantOTA 
 * 3. Pubsubclient MQTT Client: https://github.com/knolleary/pubsubclient 
 * 
 * YouTube video: https://youtu.be/giFHp9RSMvQ
 * Source code is available my blog: https://stonez56.blogspot.com/2022/08/android-36-iot-wifimanager-fota-mqtt.html 
 **/

/*
 * Define Relay pins as examples to send/receive MQTT messages
 * **/
#define RELAY_PIN_1 12
#define RELAY_PIN_2 14

/** 
 * Perform OTAs for ESP8266 / ESP32 Elegantly with password protection! 
 * https://github.com/ayushsharma82/AsyncElegantOTA
 * **/
#include <AsyncElegantOTA.h>
const char *FOTA_USERNAME = "un";
const char *FOTA_PASSWORD = "pw";

/** 
 * Add MQTT client here` PubSubClient V2.8 by Nick O'Leary
 * https://github.com/knolleary/pubsubclient 
*/
#include <WiFiClient.h>
#include <PubSubClient.h>
#define MSG_BUFFER_SIZE (1024)
char msg[MSG_BUFFER_SIZE];

/** Taiwan No. 1 Free MQTT Server!! **/
const char *mqtt_server = "mqttgo.io";
const int mqtt_port = 1883;

/****************************************************************************************************************************
  Async_AutoConnect_ESP32_minimal.ino
  For ESP8266 / ESP32 boards
  Built by Khoi Hoang https://github.com/khoih-prog/ESPAsync_WiFiManager
  Licensed under MIT license
 *****************************************************************************************************************************/
#if !(defined(ESP32))
#error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
#endif
#include <ESPAsync_WiFiManager.h> 
AsyncWebServer webServer(80);

//Start DNS server
DNSServer dnsServer;

//MQTT - Start WiFi client and connect to MQTT server
WiFiClient espClient;
PubSubClient mqtt_client(espClient);

//Define device name
String DEVICE_NAME = "Dual_Relay_Switch";
String home_page_message = "";

void setup()
{
    Serial.begin(115200);
    pinMode(RELAY_PIN_1, OUTPUT);
    pinMode(RELAY_PIN_2, OUTPUT);

    while (!Serial)
        ;
    delay(200);
    Serial.print("\nAsyncWifimanager started on " + String(ARDUINO_BOARD) + "\n");

    //Initialize ESPAsyncWifimanager instance and assign Wi-Fi Client name "AsyncAutoConnect"!
    //This name and IP address can be checked from the router
    ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, &dnsServer, "Dual_Relay_Switch");

    //####### RESET SAVED WIFI SETTINGS #############
    //ESPAsync_wifiManager.resetSettings();   

    //ESPAsync_wifiManager.setAPStaticIPConfig(IPAddress(192, 168, 132, 1), IPAddress(192, 168, 132, 1), IPAddress(255, 255, 255, 0));
    //ESPAsync_wifiManager.autoConnect("Stonez_ESP32S", "AP-NAME", "AP-PASSWORD");
    
    ESPAsync_wifiManager.autoConnect("Dual_Switch_ESP32S");
    if (WiFi.status() == WL_CONNECTED)
    {
        Serial.print(DEVICE_NAME);
        Serial.print(" is on Local IP: ");
        Serial.println(WiFi.localIP());
    }
    else
    {
        Serial.println(ESPAsync_wifiManager.getStatus(WiFi.status()));
    }

    //Setup home page access content when visite
    home_page_message = "<!DOCTYPE html><html><head><title>" + DEVICE_NAME 
        + "</title></head><body><p><h2> Hi! This is " + DEVICE_NAME + "</h2>"
        + "To update firmware, <a href='/update'>Click here!!</a><br/><span>Username & Password required!</span></p><body></html>";

    webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
                 { request->send(200, "text/html", home_page_message); });

    //AsyncElegantOTA.begin(&webServer); // Start ElegantOTA WITHOUT username & password
    AsyncElegantOTA.begin(&webServer, FOTA_USERNAME, FOTA_PASSWORD); // Start ElegantOTA with username & password
    webServer.begin();
    Serial.println("AsyncElegantOTA server started @URL/update");

    //MQTT starts here!
    mqtt_client.setServer(mqtt_server, mqtt_port);
    mqtt_client.setCallback(callback);
}

/**
//When MQTT lost connection, this function will be called to reconnect MQTT//
 * Modified to accept multiple MQTT topics 
 * https://www.baldengineer.com/multiple-mqtt-topics-pubsubclient.html
 */
void callback(char *topic, byte *payload, unsigned int length)
{
    //Print message received
    Serial.print("Message arrived [");
    Serial.print(topic);
    Serial.print("] ");
    for (int i = 0; i < length; i++)
    {
        Serial.print((char)payload[i]);
    }
    Serial.println();

    //Process multiple topics here//
    payload[length] = '\0';
    String message = (char*)payload;
    
    if (strcmp(topic, "studio/humd_switch") == 0)
    {
      if(message == "true"){
        digitalWrite(RELAY_PIN_1, HIGH);
        Serial.println("humd_switch true");
      }
      if(message == "false"){
        digitalWrite(RELAY_PIN_1, LOW);
        Serial.println("humd_switch false");
      }
    }
    if (strcmp(topic, "studio/humd_switch2") == 0)
    {
      if(message == "true"){
        digitalWrite(RELAY_PIN_2, HIGH);
        Serial.println("humd_switch2 true");
      }
      if(message == "false"){
        digitalWrite(RELAY_PIN_2, LOW);
        Serial.println("humd_switch2 false");
      }
    }
}

//============= MQTT ===================
//When MQTT lost connection, this function will be called to reconnect MQTT//
void reconnect(){
    //Loop while MQTT connected
    while (!mqtt_client.connected())
    {
        Serial.print("Attempting MQTT connection... ");
        // Create a random client ID
        String clientId = "Stonez_ESP32Client-";
        clientId += String(random(0xffff), HEX);
        // Attempt to connect
        if (mqtt_client.connect(clientId.c_str()))
        {
            Serial.print("connected to ");
            Serial.print(mqtt_server);
            // Once connected, publish an announcement...
            mqtt_client.publish("outTopic", "Hello world");
            // ... and resubscribe
            mqtt_client.subscribe("studio/humd_switch");
            mqtt_client.subscribe("studio/humd_switch2");
        }
        else
        {
            Serial.print("failed, rc=");
            Serial.print(mqtt_client.state());
            Serial.println(" try again in 5 seconds");
            // Wait 5 seconds before retrying
            delay(5000);
        }
    }
}
void loop() {
    //============= MQTT ===================
    //if can't connect to MQTT server, then re-connect
    if (!mqtt_client.connected())
        { reconnect(); }
    //constantly check MQTT to see for messages sending/receiving
    mqtt_client.loop();

    /**
     * Write your own code here....
     * 
     */
}

Async_AutoConnect_ESP32_minimal.ino

/****************************************************************************************************************************
  Async_AutoConnect_ESP32_minimal.ino
  For ESP8266 / ESP32 boards
  Built by Khoi Hoang https://github.com/khoih-prog/ESPAsync_WiFiManager
  Licensed under MIT license
 *****************************************************************************************************************************/
#if !(defined(ESP32) )
  #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting.
#endif
#include <ESPAsync_WiFiManager.h>              //https://github.com/khoih-prog/ESPAsync_WiFiManager
AsyncWebServer webServer(80);
DNSServer dnsServer;

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200); while (!Serial); delay(200);
  Serial.print("\nStarting Async_AutoConnect_ESP32_minimal on " + String(ARDUINO_BOARD)); Serial.println(ESP_ASYNC_WIFIMANAGER_VERSION);
  ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, &dnsServer, "AutoConnectAP");
  //ESPAsync_wifiManager.resetSettings();   //reset saved settings
  ESPAsync_wifiManager.setAPStaticIPConfig(IPAddress(192,168,132,1), IPAddress(192,168,132,1), IPAddress(255,255,255,0));
  ESPAsync_wifiManager.autoConnect("AutoConnectAP");
  if (WiFi.status() == WL_CONNECTED) { Serial.print(F("Connected. Local IP: ")); Serial.println(WiFi.localIP()); }
  else { Serial.println(ESPAsync_wifiManager.getStatus(WiFi.status())); }
}

void loop() {  }

Async_AutoConnect_ESP8266_minimal.ino

/****************************************************************************************************************************
  Async_AutoConnect_ESP8266_minimal.ino
  For ESP8266 / ESP32 boards
  Built by Khoi Hoang https://github.com/khoih-prog/ESPAsync_WiFiManager
  Licensed under MIT license
 *****************************************************************************************************************************/
#if !( defined(ESP8266) )
  #error This code is intended to run on ESP8266 platform! Please check your Tools->Board setting.
#endif
#include <ESPAsync_WiFiManager.h>              //https://github.com/khoih-prog/ESPAsync_WiFiManager
AsyncWebServer webServer(80);
DNSServer dnsServer;

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200); while (!Serial); delay(200);
  Serial.print("\nStarting Async_AutoConnect_ESP8266_minimal on " + String(ARDUINO_BOARD)); Serial.println(ESP_ASYNC_WIFIMANAGER_VERSION);
  ESPAsync_WiFiManager ESPAsync_wifiManager(&webServer, &dnsServer, "AutoConnectAP");
  //ESPAsync_wifiManager.resetSettings();   //reset saved settings
  //ESPAsync_wifiManager.setAPStaticIPConfig(IPAddress(192,168,186,1), IPAddress(192,168,186,1), IPAddress(255,255,255,0));
  ESPAsync_wifiManager.autoConnect("AutoConnectAP");
  if (WiFi.status() == WL_CONNECTED) { Serial.print(F("Connected. Local IP: ")); Serial.println(WiFi.localIP()); }
  else { Serial.println(ESPAsync_wifiManager.getStatus(WiFi.status())); }
}

void loop() {  }