全部產品
Search
文件中心

IoT Platform:Paho-MQTT C(嵌入式版)接入樣本

更新時間:Jun 30, 2024

本文介紹如何使用Paho提供的嵌入式C語言MQTT開源工程,將裝置接入阿里雲物聯網平台,並進行訊息收發。

使用前必讀

本文操作步驟以普通使用者權限為例。如果您在操作過程中涉及到管理員權限才能執行的操作,可嘗試使用sudo命令執行。

前提條件

已在物聯網平台控制台,對應執行個體下,建立產品和裝置,並擷取MQTT接入網域名稱和裝置認證資訊(ProductKey、DeviceName和DeviceSecret)。具體操作,請參見:

準備開發環境

本樣本使用Ubuntu 16.04-LTS作為開發環境。執行以下命令構建開發環境。

sudo apt-get update
sudo apt-get install build-essential git sed cmake

下載C語言Paho MQTT庫

執行以下命令,複製C語言版本的Paho MQTT庫。

git clone https://github.com/eclipse/paho.mqtt.embedded-c.git
說明

編寫本Demo樣本時,使用master分支,commit id29ab2aa29c5e47794284376d7f8386cfd54c3eed

Paho嵌入式C工程提供了以下三個子專案:

  • MQTTPacket:提供MQTT資料包的序列化與還原序列化,以及部分輔助函數。

  • MQTTClient:封裝MQTTPacket產生的進階別C++用戶端程式。

  • MQTTClient-C:封裝MQTTPacket產生的進階別C用戶端程式。

    MQTTClient-C中包含:

    ├── CMakeLists.txt
    ├── samples
    │   ├── CMakeLists.txt
    │   ├── FreeRTOS
    │   └── linux
    ├── src
    │   ├── CMakeLists.txt
    │   ├── FreeRTOS
    │   ├── MQTTClient.c
    │   ├── MQTTClient.h
    │   ├── cc3200
    │   └── linux
    └── test
        ├── CMakeLists.txt
        └── test1.c
    • samples目錄提供FreeRTOSLinux兩個常式,分別支援FreeRTOS和Linux系統。

    • src目錄提供MQTTClient的代碼實現能力,以及用於移植到FreeRTOS、cc3200和Linux的網路驅動。

    瞭解Paho MQTT的更多API細節,可以查看MQTTClient.h

接入物聯網平台

  1. 單擊開啟aiot_mqtt_sign.c,複製阿里雲提供的計算MQTT串連參數所需的源碼,然後粘貼儲存為本地的aiot_mqtt_sign.c檔案。

    aiot_mqtt_sign.c檔案定義了函數aiotMqttSign(),函數說明如下:

    • 原型:

      int aiotMqttSign(const char *productKey, const char *deviceName, const char *deviceSecret,
                       char clientId[150], char username[65], char password[65]);
    • 功能:

      用於計算裝置接入物聯網平台的MQTT串連參數usernamepasswordclientid

    • 輸入參數:

      參數

      類型

      說明

      productKey

      const char *

      裝置所屬產品的ProductKey,該裝置在物聯網平台上的身份認證資訊之一。

      deviceName

      const char *

      裝置名稱,該裝置在物聯網平台上的身份認證資訊之一。

      deviceSecret

      const char *

      裝置密鑰,該裝置在物聯網平台上的身份認證資訊之一。

    • 輸出參數:

      參數

      類型

      說明

      username

      char *

      MQTT串連所需的使用者名稱。

      password

      char *

      MQTT串連所需的密碼。

      clientId

      char *

      MQTT用戶端ID。

    • 返回碼說明:

      返回碼

      說明

      0

      成功

      -1

      失敗

  2. 添加實現裝置接入物聯網平台的程式檔案。

    您需編寫程式調用aiot_mqtt_sign.c中的aiotMqttSign()函數計算MQTT串連參數,實現接入物聯網平台和通訊。

    開發說明和範例程式碼如下:

    • 調用aiotMqttSign()介面,產生串連MQTT服務端的三個建連參數clientIdusernamepassword

      #define EXAMPLE_PRODUCT_KEY            "a11xsrW****"
      #define EXAMPLE_DEVICE_NAME            "paho_****"
      #define EXAMPLE_DEVICE_SECRET       "Y877Bgo8X5owd3lcB5wWDjryNPoB****"
      
      extern int aiotMqttSign(const char *productKey, const char *deviceName, const char *deviceSecret,
                              char clientId[150], char username[65], char password[65]);
      
      /* invoke aiotMqttSign to generate mqtt connect parameters */
      char clientId[150] = {0};
      char username[65] = {0};
      char password[65] = {0};
      
      if ((rc = aiotMqttSign(EXAMPLE_PRODUCT_KEY, EXAMPLE_DEVICE_NAME, EXAMPLE_DEVICE_SECRET, clientId, username, password) < 0)) {
          printf("aiotMqttSign -%0x4x\n", -rc);
          return -1;
      }
      printf("clientid: %s\n", clientId);
      printf("username: %s\n", username);
      printf("password: %s\n", password);
    • 接入物聯網平台。

      需配置以下內容:

      • 調用NetworkInitNetworkConnect建立TCP串連。

      • 調用MQTTClientInit初始化MQTT用戶端。

      • 配置MQTT建連參數結構體MQTTPacket_connectData

      範例程式碼:

      /* network init and establish network to aliyun IoT platform */
      NetworkInit(&n);
      rc = NetworkConnect(&n, host, port);
      printf("NetworkConnect %d\n", rc);
      
      /* init mqtt client */
      MQTTClientInit(&c, &n, 1000, buf, sizeof(buf), readbuf, sizeof(readbuf));
      
      /* set the default message handler */
      c.defaultMessageHandler = messageArrived;
      
      /* set mqtt connect parameter */
      MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
      data.willFlag = 0;
      data.MQTTVersion = 3;
      data.clientID.cstring = clientId;
      data.username.cstring = username;
      data.password.cstring = password;
      data.keepAliveInterval = 60;
      data.cleansession = 1;
      printf("Connecting to %s %d\n", host, port);
      
      rc = MQTTConnect(&c, &data);
      printf("MQTTConnect %d, Connect aliyun IoT Cloud Success!\n", rc);
    • 發布訊息。

      調用MQTTPublish()介面,向指定的自訂Topic發布自訂格式訊息。

      通訊Topic介紹,請參見什麼是Topic

      char *pubTopic = "/"EXAMPLE_PRODUCT_KEY"/"EXAMPLE_DEVICE_NAME"/user/update";
      int cnt = 0;
      unsigned int msgid = 0;
      while (!toStop)
      {
          MQTTYield(&c, 1000);    
      
          if (++cnt % 5 == 0) {
              MQTTMessage msg = {
                  QOS1,
                  0,
                  0,
                  0,
                  "Hello world",
                  strlen("Hello world"),
              };
              msg.id = ++msgid;
              rc = MQTTPublish(&c, pubTopic, &msg);
              printf("MQTTPublish %d, msgid %d\n", rc, msgid);
          }
      }
    • 訂閱Topic,擷取雲端下發的訊息。

      void messageArrived(MessageData* md)
      {
          MQTTMessage* message = md->message;
      
          printf("%.*s\t", md->topicName->lenstring.len, md->topicName->lenstring.data);
          printf("%.*s\n", (int)message->payloadlen, (char*)message->payload);
      }
      
      char *subTopic = "/"EXAMPLE_PRODUCT_KEY"/"EXAMPLE_DEVICE_NAME"/user/get";
      
      printf("Subscribing to %s\n", subTopic);
      rc = MQTTSubscribe(&c, subTopic, 1, messageArrived);
      printf("MQTTSubscribe %d\n", rc);

    關於裝置、伺服器和物聯網平台的通訊方式介紹,請參見物聯網平台通訊方式概述

  3. 將步驟1下載的aiot_mqtt_sign.c檔案和步驟2編輯的檔案放到../paho.mqtt.embedded-c/MQTTClient-C/samples/linux中,然後編譯工程。

範例程式碼

使用Demo代碼程式接入物聯網平台。

  1. 下載Demo包,並解壓縮。

    解壓縮後,程式碼封裝裡有以下兩個檔案:

    檔案

    說明

    aiot_mqtt_sign.c

    該檔案中的代碼用於產生MQTT建連參數。aiot_c_demo.c運行時,會調用該檔案中定義的aiotMqttSign()函數,計算出串連參數usernamepasswordclientId

    aiot_c_demo.c

    該檔案包含裝置與物聯網平台串連和通訊的邏輯代碼。

  2. aiot_c_demo.c中,將裝置資訊修改為您的裝置資訊。

    • 替換以下代碼中EXAMPLE_PRODUCT_KEYEXAMPLE_DEVICE_NAMEEXAMPLE_DEVICE_SECRET後的值為您的裝置認證資訊。

      #define EXAMPLE_PRODUCT_KEY            "產品ProductKey" 
      #define EXAMPLE_DEVICE_NAME            "裝置名稱DeviceName" 
      #define EXAMPLE_DEVICE_SECRET          "裝置密鑰DeviceSecret"
    • 修改代碼char *host = EXAMPLE_PRODUCT_KEY".iot-as-mqtt.cn-shanghai.aliyuncs.com"中的值為對應接入網域名稱。

      公用執行個體和企業版執行個體接入網域名稱的格式說明,請參見查看執行個體終端資訊

  3. aiot_mqtt_sign.c和已修改的aiot_c_demo.c檔案放到Paho工程的目錄../paho.mqtt.embedded-c/MQTTClient-C/samples/linux中。

  4. 編譯工程,並運行程式。

    有兩種方法可以編譯出可執行檔程式:

    • 使用CMake

      1. /paho.mqtt.embedded-c/MQTTClient-C/samples/linux目錄下的CMakeLists.txt檔案中,增加aiot_c_demo.caiot_mqtt_sign.c

        修改後的CMakeLists.txt檔案內容如下。

        add_executable(
          stdoutsubc
          stdoutsub.c
        )
        
        add_executable(
          aiot_c_demo
          aiot_c_demo.c
          aiot_mqtt_sign.c
        )
        
        target_link_libraries(stdoutsubc paho-embed-mqtt3cc paho-embed-mqtt3c)
        target_include_directories(stdoutsubc PRIVATE "../../src" "../../src/linux")
        target_compile_definitions(stdoutsubc PRIVATE MQTTCLIENT_PLATFORM_HEADER=MQTTLinux.h)
        
        target_link_libraries(aiot_c_demo paho-embed-mqtt3cc paho-embed-mqtt3c)
        target_include_directories(aiot_c_demo PRIVATE "../../src" "../../src/linux")
        target_compile_definitions(aiot_c_demo PRIVATE MQTTCLIENT_PLATFORM_HEADER=MQTTLinux.h)
      2. 回到/paho.mqtt.embedded-c目錄,執行以下命令,完成編譯。

        mkdir build.paho
        cd build.paho
        cmake ..
        make
      3. 編譯完成後,在/paho.mqtt.embedded-c/build.paho目錄下執行以下命令,運行程式。

        ./MQTTClient-C/samples/linux/aiot_c_demo
    • 使用build.sh

      1. 開啟/paho.mqtt.embedded-c/MQTTClient-C/samples/linux目錄下的build.sh檔案。

      2. build.sh中的stdoutsub.c替換為aiot_mqtt_sign.c aiot_c_demo.c-o stdoutsub替換為-o aiot_c_demo,然後儲存build.sh

      3. 修改完成後,在/paho.mqtt.embedded-c/MQTTClient-C/samples/linux目錄下,執行命令./build.sh,完成編譯。

        完成編譯後,產生aiot_c_demo可執行檔。

      4. 執行命令./aiot_c_demo,運行程式。

    運行成功,接入物聯網平台的本地日誌如下:

    clientid: paho_mqtt&a11xsrW****|timestamp=2524608000000,_v=sdk-c-1.0.0,securemode=3,signmethod=hmacsha256,lan=C|
    username: paho_mqtt&a11xsrW****
    password: 36E955DC3D9D012EF62C80657A29328B1CFAE6186C611A17DC7939FAB637****
    NetworkConnect 0
    Connecting to a11xsrW****.iot-as-mqtt.cn-shanghai.aliyuncs.com 443
    MQTTConnect 0, Connect aliyun IoT Cloud Success!
    Subscribing to /a11xsrW****/paho_mqtt/user/get
    MQTTSubscribe 0
    MQTTPublish 0, msgid 1
    MQTTPublish 0, msgid 2
    MQTTPublish 0, msgid 3
    MQTTPublish 0, msgid 4
    MQTTPublish 0, msgid 5
    ...

    登入物聯網平台控制台,可查看裝置狀態和日誌。

    • 選擇裝置管理 > 裝置,可看到該裝置的狀態顯示為線上
    • 選擇監控營運 > Log Service,可查看雲端作業記錄裝置本地日誌日誌。詳細內容,請參見雲端作業記錄裝置本地日誌

錯誤碼

如果裝置通過MQTT協議接入物聯網平台失敗,請根據錯誤碼排查問題。服務端錯誤碼說明,請參見錯誤排查