2024年8月17日 星期六

Arduino 物聯網應用 - 上課教材

Arduino 物聯網應用 - 上課教材

https://dic.vbird.tw/arduino/list.php


Arduino 物聯網應用 - 課程列表

我們會從 Arduino 的認識、IDE 環境的熟悉、與操作電腦的序列埠連動的功能、Arduino 開發語言的熟悉、 簡單的 LED 燈號控制同時與電阻功能的認識、由序列埠直接傳送互動參數的應用、各項基礎感測器的設計、 LCD 顯示器的應用、wifi 與藍芽的應用等,看看最終能不能連結到樹莓派來傳輸與互動囉!

使用教材:

  • ....

注意事項:

    課程列表:

    MQTT Basic2 (WOKWI ESP32 + MQTT Box )

     MQTT Basic2  (WOKWI  ESP32 + MQTT Box )

    使用 <ArduinoMqttClient.h> library


    主題有修正如下
    const char broker[] = "test.mosquitto.org";
    int        port     = 1883;
    const char Pubtopic1[]  = "alex9ufo/hello";
    const char Subtopic2[]  = "alex9ufo/led";
    message == "on" 亮 message == "off" 熄






    WOKWI程式

    #include <ArduinoMqttClient.h>
    #include <WiFi.h>

    ///////please enter your sensitive data in the Secret tab/arduino_secrets.h
    char ssid[] =  "Wokwi-GUEST"; // your network SSID (name)
    char pass[] =  "" ;           // your network password (use for WPA, or use as key for WEP)

    WiFiClient wifiClient;
    MqttClient mqttClient(wifiClient);

    const char broker[] = "test.mosquitto.org";
    int        port     = 1883;
    const char Pubtopic1[]  = "alex9ufo/hello";
    const char Subtopic2[]  = "alex9ufo/led";
    const char willTopic[] = "alex9ufo/Starting";

    //set interval for sending messages (milliseconds)

    const long interval = 8000;
    unsigned long previousMillis = 0;

    int count = 0;
    const int LED = 2;
    char msg[50];
    int value = 0;

    //=======================================================================
    void onMqttMessage(int messageSize) {
      // we received a message, print out the topic and contents
      Serial.println("Received a message with topic '");
      Serial.print(mqttClient.messageTopic());
      Serial.print("', length ");
      Serial.print(messageSize);
      Serial.println(" bytes:");
      String Topic= mqttClient.messageTopic();

      String message="";
      // use the Stream interface to print the contents
      while (mqttClient.available()) {
        //Serial.print((char)mqttClient.read());
        message += (char)mqttClient.read();
      }
      Serial.println(message);
      message.trim();
      Topic.trim();

      if (Topic=="alex9ufo/led") {
        if (message == "on") {
          digitalWrite(LED, LOW);  // Turn on the LED
          Serial.print("LED = on ");
        }

        if (message == "off" ) {
          digitalWrite(LED, HIGH); // Turn off the LED
          Serial.print("LED = off ");
        }
      }
      Serial.println();
      Serial.println();
    }

    //=======================================================================
    //副程式  setup wifi
    void setup_wifi() {
      delay(10);
      // We start by connecting to a WiFi network
      Serial.println();
      Serial.print("Connecting to ");
      Serial.println(ssid);     //print ssid
      WiFi.begin(ssid, pass);  //初始化WiFi 函式庫並回傳目前的網路狀態
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }   //假設 wifi 未連接 show ………

      Serial.println("");
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
    }  

    //=======================================================================
    void setup() {
      //Initialize serial and wait for port to open:
      Serial.begin(115200);
      pinMode(LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output

      Serial.begin(115200);   // Initialize serial communications with the PC
      while (!Serial);    // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
     
      setup_wifi();
      Serial.println("You're connected to the network");
      Serial.println();
     
      String willPayload = "ESP32 Start working....!";
      bool willRetain = true;
      int willQos = 1;

      mqttClient.beginWill(willTopic, willPayload.length(), willRetain, willQos);
      mqttClient.print(willPayload);
      mqttClient.endWill();

      Serial.print("Attempting to connect to the MQTT broker: ");
      Serial.println(broker);

      if (!mqttClient.connect(broker, port)) {
        Serial.print("MQTT connection failed! Error code = ");
        Serial.println(mqttClient.connectError());

        while (1);
      }

      Serial.println("You're connected to the MQTT broker!");
      Serial.println();

      // set the message receive callback
      mqttClient.onMessage(onMqttMessage);
      Serial.print("Subscribing to topic: ");
      Serial.println(Subtopic2);
      // subscribe to a topic
      // the second parameter sets the QoS of the subscription,
      // the the library supports subscribing at QoS 0, 1, or 2
      int subscribeQos = 1;
      mqttClient.subscribe(Subtopic2, subscribeQos);

    }

    //=======================================================================
    void loop() {
      // call poll() regularly to allow the library to send MQTT keep alive which
      // avoids being disconnected by the broker
      mqttClient.poll();

      unsigned long currentMillis = millis();

      if (currentMillis - previousMillis >= interval) {
        // save the last time a message was sent
        previousMillis = currentMillis;

        //record random value from A0, A1 and A2
        ++value;
        snprintf (msg, 75, "hello world #%ld", value);
        Serial.print("Publish message: ");
        Serial.println(msg);

        Serial.print("Sending message to topic: ");
        Serial.println(Pubtopic1);
        Serial.println(msg);

        // send message, the Print interface can be used to set the message contents
        mqttClient.beginMessage(Pubtopic1);
        mqttClient.print(msg);
        mqttClient.endMessage();

        Serial.println();
      }
    }

    2024年8月16日 星期五

    MQTT Basic (WOKWI ESP32 + MQTT Box )

     MQTT Basic (WOKWI  ESP32 + MQTT Box )












    WOKWI程式


    /*
     Basic ESP32 MQTT example
    */

    #include <WiFi.h>
    #include <PubSubClient.h>

    // Update these with values suitable for your network.

    const char* ssid = "Wokwi-GUEST";
    const char* password = "";
    //const char* mqtt_server = "broker.mqtt-dashboard.com";
    const char* mqtt_server = "test.mosquitto.org";

    WiFiClient espClient;
    PubSubClient client(espClient);

    #define LED 2

    long lastMsg = 0;
    char msg[50];
    int value = 0;


    //================================
    void setup_wifi() {

      delay(10);
      // We start by connecting to a WiFi network
      Serial.println();
      Serial.print("Connecting to ");
      Serial.println(ssid);

      WiFi.begin(ssid, password);

      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }

      randomSeed(micros());

      Serial.println("");
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
    }
    //============================================================
    void callback(char* topic, byte* message, unsigned int length) {
      printPayload(topic, message, length);  
    }

    void printPayload(char* topic, byte* message, unsigned int length) {
      // Printing Received Message
      Serial.print("Message received on topic: ");
      Serial.println(topic);

      String messageTemp;
      for(int i=0; i<length; i+=1) {
        messageTemp += (char)message[i];
      }
      if(String(topic) == "alex9ufo/esp32/led"){
          if(messageTemp=="ON"){
            Serial.println("Led ON");
            digitalWrite(LED,LOW);
          }  
          if(messageTemp=="OFF"){
            Serial.println("Led OFF");
            digitalWrite(LED,HIGH);
          }
      }
      Serial.println(messageTemp);
    }
    //============================================================
    void reconnect() {
      // Loop until we're reconnected
      while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        // Create a random client ID
        String clientId = "ESP32Client-";
        clientId += String(random(0xffff), HEX);
        // Attempt to connect
        if (client.connect(clientId.c_str())) {
          Serial.println("connected");
          // Once connected, publish an announcement...
          client.publish("alex9ufo/esp32/hello", "hello world");
          // ... and resubscribe
          client.subscribe("alex9ufo/esp32/led");
        } else {
          Serial.print("failed, rc=");
          Serial.print(client.state());
          Serial.println(" try again in 5 seconds");
          // Wait 5 seconds before retrying
          delay(5000);
        }
      }
    }
    //============================================================
    void setup() {
      pinMode(LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
      digitalWrite(LED,HIGH);

      Serial.begin(115200);
      setup_wifi();
      client.setServer(mqtt_server, 1883);
      client.setCallback(callback);
    }
    //============================================================
    void loop() {

      if (!client.connected()) {
        reconnect();
      }
      client.loop();

      long now = millis();
      if (now - lastMsg > 8000) {
        lastMsg = now;
        ++value;
        snprintf (msg, 75, "hello world #%ld", value);
        Serial.print("Publish message: ");
        Serial.println(msg);
        client.publish("alex9ufo/esp32/hello", msg);
      }
    }
    //============================================================

    2024年8月12日 星期一

    MQTT 協議入門:基礎知識和快速教程

     

    MQTT 協議入門:基礎知識和快速教程

    https://www.emqx.com/zh/blog/the-easiest-guide-to-getting-started-with-mqtt
    EMQX Team
    2022-9-9
    MQTT 協議入門:基礎知識和快速教程

    本文是MQTT 協議的入門指南,提供了實用的程式碼範例。物聯網和MQTT 的初學者可以透過本文掌握MQTT 的基本概念,快速開啟MQTT 服務和應用的開發。

    什麼是MQTT?

    MQTT(Message Queuing Telemetry Transport)是一種輕量級、基於發布-訂閱模式的訊息傳輸協議,適用於資源受限的裝置和低頻寬、高延遲或不穩定的網路環境。它在物聯網應用中廣受歡迎,能夠實現感測器、執行器和其它設備之間的高效通訊。

    為什麼MQTT 是適用於物聯網的最佳協定?

    MQTT 所具有的適用於物聯網特定需求的特性和功能,使其成為物聯網領域最佳的協定之一。它的主要特點包括:

    • 輕量級:物聯網設備通常在處理能力、記憶體和能耗方面受到限制。 MQTT 開銷低、報文小的特點使其非常適合這些設備,因為它消耗更少的資源,即使在有限的能力下也能實現高效的通訊。
    • 可靠:物聯網網路常常面臨高延遲或連線不穩定的情況。 MQTT 支援多種QoS 等級、會話感知和持久連接,即使在困難的條件下也能保證訊息的可靠傳遞,使其非常適合物聯網應用。
    • 安全通訊:安全對於物聯網網路至關重要,因為其經常涉及敏感資料的傳輸。為確保資料在傳輸過程中的機密性,MQTT 提供傳輸層安全性(TLS)和安全通訊端層(SSL)加密功能。此外,MQTT 還透過使用者名稱/密碼憑證或用戶端憑證提供身份驗證和授權機制,以保護網路及其資源的存取。
    • 雙向通訊: MQTT 的發布-訂閱模式為設備之間提供了無縫的雙向通訊方式。客戶端既可以向主題發布訊息,也可以訂閱接收特定主題上的訊息,從而實現了物聯網生態系統中的高效資料交換,而無需直接將設備耦合在一起。這種模式也簡化了新設備的集成,同時確保了系統易於擴展。
    • 連續、有狀態的會話: MQTT 提供了客戶端與Broker 之間保持有狀態會話的能力,這使得系統即使在斷開連接後也能記住訂閱和未傳遞的訊息。此外,用戶端還可以在建立連線時指定保活間隔,這會促使Broker 定期檢查連線狀態。如果連線中斷,Broker 會儲存未傳遞的訊息(根據QoS 等級決定),並在用戶端重新連線時嘗試傳遞它們。這個特性保證了通訊的可靠性,降低了因間斷性連接而導致資料遺失的風險。
    • 大規模物聯網設備支援:物聯網系統往往涉及大量設備,需要一種能夠處理大規模部署的協定。 MQTT 的輕量級特性、低頻寬消耗和對資源的高效利用使其成為大規模物聯網應用的理想選擇。透過採用發布-訂閱模式,MQTT 實現了發送者和接收者的解耦,從而有效地減少了網路流量和資源使用。此外,協議對不同QoS 等級的支援使得訊息傳遞可以根據需求進行定制,確保在各種場景下獲得最佳的效能表現。
    • 語言支援:物聯網系統包含使用各種程式語言開發的設備和應用。 MQTT 具有廣泛的語言支持,使其能夠輕鬆與多個平台和技術進行集成,從而實現了物聯網生態系統中的無縫通訊和互通性。您可以閱讀我們的MQTT 用戶端程式設計系列文章,學習如何在PHP、Node.js、Python、Golang、Node.js 等程式語言中使用MQTT。

    MQTT 的工作原理

    要了解MQTT 的工作原理,首先需要掌握以下幾個概念:MQTT 用戶端、MQTT Broker、發布-訂閱模式、主題、QoS。

    MQTT 用戶端

    任何運行MQTT 客戶端程式庫的應用程式或裝置都是MQTT 用戶端。例如,使用MQTT 的即時通訊應用是客戶端,使用MQTT 上報資料的各種感測器是客戶端,各種MQTT 測試工具也是客戶端。

    MQTT Broker

    MQTT Broker 是負責處理客戶端要求的關鍵元件,包括建立連線、斷開連線、訂閱和取消訂閱等操作,同時也負責訊息的轉送。一個高效強大的MQTT Broker 能夠輕鬆應對海量連接和百萬級訊息吞吐量,從而幫助物聯網服務供應商專注於業務發展,快速建立可靠的MQTT 應用。

    關於MQTT Broker 的更多詳情,請參閱文章2023 年最全面的MQTT Broker 比較指南

    發布-訂閱模式

    發布-訂閱模式與客戶端-伺服器模式的不同之處在於,它將發送訊息的客戶端(發布者)和接收訊息的客戶端(訂閱者)進行了解耦。發布者和訂閱者之間無需建立直接連接,而是透過MQTT Broker 來負責訊息的路由和分發。

    下圖展示了MQTT 發布/訂閱流程。溫度感測器作為客戶端連接到MQTT Broker,並透過發布操作將溫度資料發佈到一個特定主題(例如Temperature)。 MQTT Broker 接收到該訊息後會負責將其轉發給訂閱了對應主題(Temperature)的訂閱者用戶端。

    MQTT 發布-訂閱模式

    主題

    MQTT 協議根據主題來轉發訊息。主題透過/來區分層級,類似URL 路徑,例如:

    chat /room/ 1
    
    sensor /10/ temperature
    
    sensor /+/ temperature
    

    MQTT 主題支援以下兩種通配符:+#

    • +:表示單層通配符,例如a/+匹配a/xa/y
    • #:表示多層通配符,例如a/#匹配a/xa/b/c/d

    注意:通配符主題只能用於訂閱,不能用於發布。

    關於MQTT 主題的更多詳情,請參閱文章透過案例理解MQTT 主題與通配符

    QoS

    MQTT 提供了三種服務品質(QoS),在不同網路環境下保證訊息的可靠性。

    • QoS 0:訊息最多傳送一次。如果當前客戶端不可用,它將丟失這條訊息。
    • QoS 1:訊息至少傳送一次。
    • QoS 2:訊息只會傳送一次。

    關於MQTT QoS 的更多詳情,請參閱文章MQTT QoS 0, 1, 2 介紹

    MQTT 的工作流程

    在了解了MQTT 的基本組件之後,讓我們來看看它的一般工作流程:

    1. 用戶端使用TCP/IP 協定與Broker 建立連接,可選擇使用TLS/SSL 加密來實現安全通訊。用戶端提供認證訊息,並指定會話類型(Clean Session 或Persistent Session)。
    2. 客戶端既可以向特定主題發布訊息,也可以訂閱主題以接收訊息。當客戶端發布訊息時,它會將訊息傳送給MQTT Broker;而當客戶端訂閱訊息時,它會接收與訂閱主題相關的訊息。
    3. MQTT Broker 接收發佈的訊息,並將這些訊息轉發給訂閱了對應主題的用戶端。它根據QoS 等級確保訊息可靠傳遞,並根據會話類型為斷開連接的用戶端儲存訊息。

    開始使用MQTT:快速教學

    下面我們將透過一些簡單的範例來展示如何使用MQTT。在開始之前,需要準備MQTT Broker 和MQTT 用戶端。

    準備MQTT Broker

    您可以選擇私有部署或完全託管的雲端服務來建立自己的MQTT Broker。或者您也可以使用免費的公共Broker。

    • 私有部署

      EMQX是最具擴充性的開源MQTT Broker,適用於物聯網、工業物聯網和車聯網。您可以執行以下Docker 命令來安裝EMQX。

      docker run -d --name emqx -p 1883 : 1883 -p 8083 : 8083 -p 8084 : 8084 -p 8883 : 8883 -p 18083 : 18083 emqx/emem
      
    • 全託管的雲端服務

      透過全託管的雲端服務啟動MQTT 服務是最方便的方式。如下圖所示,EMQX Cloud可以在幾分鐘內啟動,並在AWS、Google Cloud 和Microsoft Azure 的17 個區域提供運作支援。

      EMQX MQTT Cloud

    • 免費的公共MQTT Broker

      在本文中,我們將使用EMQ 提供的免費公共MQTT Broker,它是基於完全託管的MQTT 雲端服務- EMQX Cloud創建。伺服器資訊如下:

      Server:broker.emqx.io

      TCP Port:1883

      WebSocket Port:8083

      SSL/TLS Port:8883

      Secure WebSocket Port:8084

    準備MQTT 用戶端

    在本文中,我們將使用MQTTX提供的支援瀏覽器存取的MQTT 用戶端工具,存取位址為http://mqtt-client.emqx.com/。 MQTTX 也提供了桌面用戶端命令列工具

    MQTTX是一款跨平台的MQTT 5.0 桌面用戶端,可在macOS、Linux、Windows 作業系統上運作。其用戶友好的聊天式介面使用戶能夠輕鬆創建多個MQTT/MQTTS 連接,並進行MQTT 訊息的訂閱和發布。

    MQTTX

    MQTTX 介面

    目前,各種程式語言都擁有成熟的開源MQTT 用戶端程式庫。我們在流行的MQTT 用戶端庫和SDK中精選了多個程式語言的MQTT 用戶端程式庫,並提供了詳細的程式碼範例,旨在幫助您快速了解MQTT 用戶端的使用。

    建立MQTT 連接

    在使用MQTT 協定進行通訊之前,客戶端需要建立一個MQTT 連線來連接到Broker。

    在瀏覽器中開啟http://mqtt-client.emqx.com/ , 點選頁面中間的New Connection按鈕,將會看到以下頁面。

    建立MQTT 連接

    我們在Name中輸入Simple Demo,然後點擊右上角的Connect按鈕,建立一個MQTT 連線。如下圖所示,表示連線成功。

    MQTT 連結成功

    若要了解更多關於MQTT 連線參數的內容,請查看我們的文章:建立MQTT 連線時如何設定參數

    透過通配符訂閱主題

    接下來,我們在上面創建的Simple Demo連接中透過通配符訂閱主題sensor/+/temperature,這樣就可以接收所有感測器發送的溫度資料了。

    如下圖所示,點選New Subscription按鈕,在彈出框中的Topic欄位中輸入主題sensor/+/temperature,QoS 保持預設值0。

    訂閱MQTT 通配符主題

    訂閱成功後,會在訂閱清單的中間看到新增了一筆記錄。

    MQTT 主題訂閱成功

    發布MQTT 訊息

    接下來,我們點擊左側選單上的+按鈕建立兩個連接,分別命名為Sensor 1Sensor 2,用來模擬兩個溫度感測器。

    建立MQTT 連接

    連接建立成功後,會看到三個連接,每個連接左側的在線狀態指示燈都是綠色的。

    三個連接創建成功

    選擇Sensor 1連接,在頁面下方的發布主題中輸入sensor/1/temperature,在訊息框中輸入以下JSON 格式的訊息,然後點擊右下方的發布按鈕發送訊息。

    { 
      "msg" :  "17.2" 
    }
    

    發布MQTT 訊息

    如下圖所示,訊息發送成功。

    MQTT 訊息發布成功

    使用相同的步驟,在Sensor 2連線中發布以下JSON 訊息到sensor/2/temperature主題。

    { 
      "msg" :  "18.2" 
    }
    

    您會看到Simple Demo連線收到兩個新訊息。

    2條訊息提示

    點擊Simple Demo連接,會看到兩個感測器發送的兩個訊息。

    查看訊息詳情

    MQTT 功能演示

    保留訊息

    當MQTT 用戶端向伺服器發布訊息時,可以設定保留訊息標誌。保留訊息儲存在訊息伺服器上,後續訂閱該主題的用戶端仍可收到該訊息。

    如下圖所示,我們在Sensor 1連線中勾選Retain選項,然後向retained_message主題發送兩個訊息。

    MQTT Retain

    接著,我們在Simple Demo連線中訂閱retained_message主題。訂閱成功後,會收到Sensor 1傳送的第二個保留訊息,這表示伺服器只會為主題保留最近的一條保留訊息。

    MQTT 保留訊息

    關於保留訊息的更多細節,請閱讀文章MQTT 保留訊息初學者指南

    Clean Session

    MQTT 用戶端通常只能在線上狀態下接收其它用戶端發布的訊息。如果客戶端離線後重新上線,它將無法收到離線期間的訊息。

    但是,如果客戶端連線時設定Clean Session 為false,並且使用相同的客戶端ID 再次上線,那麼訊息伺服器將為客戶端快取一定數量的離線訊息,並在它重新上線時傳送給它。

    本次示範使用的公共MQTT 伺服器設定為快取5 分鐘的離線訊息,最大訊息數為1000 條,且不儲存QoS 0 訊息。

    下面,我們建立一個MQTT 3.1.1 連接,並用QoS 1 來示範Clean Session 的使用。

    MQTT 5.0 中將Clean Session 分拆成了Clean Start 與Session Expiry Interval。詳情請參考文章Clean Start 與Session Expiry Interval

    建立名為MQTT V3的連接,設定Clean Session 為false,選擇MQTT 版本為3.1.1。

    設定Clean Session 為false

    連線成功後,訂閱clean_session_false主題,並將QoS 設定為1。

    訂閱clean_session_false 主題

    訂閱成功後,點選右上角的斷開按鈕,斷開連線。

    斷開MQTT 連接

    然後,建立一個名為MQTT_V3_Publish的連接,MQTT 版本也設定為3.1.1。連線成功後,向clean_session_false主題發布三條訊息。

    建立一個名為MQTT_V3_Publish 的連接

    接著,選擇MQTT_V3連接,點選連接按鈕重新連接到伺服器,會收到三條離線訊息。

    接收三條離線訊息

    關於Clean Session 的更多細節,請閱讀文章MQTT Persistent Session 與Clean Session 詳解

    遺囑消息

    MQTT 用戶端在向伺服器發起CONNECT 請求時,可以選擇是否發送遺囑訊息標誌,並指定遺囑訊息的主題和有效載荷。

    如果MQTT 用戶端異常離線(在斷開連線前沒有向伺服器發送DISCONNECT 訊息),MQTT 伺服器會發布遺囑訊息。

    我們建立一個名為Last Will的連結來示範這個功能。

    • 為了快速看到效果,我們把Keep Alive 設定為5 秒。
    • Last-Will Topic 設定為last_will
    • Last-Will QoS 設定為1
    • Last-Will Retain 設定為true
    • Last-Will Payload 設定為offline

    建立名為Last Will 的連接

    連線成功後,我們斷開電腦網路超過5 秒(模擬客戶端異常斷開連線),然後再恢復網路。

    接著啟動Simple Demo 連接,並訂閱last_will主題。您會收到Last Will連接設定的遺囑訊息。

    收到Last Will 連線設定的遺囑訊息

    關於MQTT 遺囑訊息的更多內容,請閱讀文章MQTT 遺囑訊息的使用

    深入學習MQTT

    本文詳細介紹了MQTT 的基本概念和使用流程,您可以按照本文所學的內容嘗試使用MQTT 協定。

    如果您想了解更多MQTT 的知識,建議您閱讀EMQ 提供的MQTT 教學:從入門到精通系列文章,了解MQTT 主題、通配符、保留訊息、遺囑訊息等功能。透過這些文章,您將能夠探索MQTT 的更高級應用場景,並開始進行MQTT 應用和服務的開發。

    2024_09 作業3 以Node-Red 為主

     2024_09 作業3  (以Node-Red 為主  Arduino 可能需要配合修改 ) Arduino 可能需要修改的部分 1)mqtt broker  2) 主題Topic (發行 接收) 3) WIFI ssid , password const char br...