LiteOS雲端對接教程03-LiteOS基於MQTT對接EMQ-X服

wjaning發表於2021-09-09

1. LiteOS MQTT元件

概述

MQTT AL用來解耦基於MQTT的業務和MQTT的具體實現,具體來說以後的MQTT業務層應該有且只能使用MQTT AL提供的相關功能(API 資料結構 流程等)。MQTT AL定義MQTT的標準,用來遮蔽各個MQTT協議實現的差異(如軟體庫 或者硬體),讓上層業務無需關心MQTT的實現部分。

MQTT AL的api介面宣告在<mqtt_al.h>中,使用相關的介面需要包含該標頭檔案,關於函式的詳細引數請參考該標頭檔案的宣告。

配置並連線

對接伺服器的所有資訊儲存在結構體mqtt_al_conpara_t中,其定義在mqtt_al.h中,如下:

/** @brief defines the paramter for the mqtt connect */
typedef struct
{
	mqtt_al_string_t               serveraddr;   ///< mqtt server:support domain name and dot format
	int                            serverport;   ///< mqtt server port
	mqtt_al_security_para_t       *security;     ///< if NULL,will use en_mqtt_security_none
	en_mqtt_al_verison             version;      ///< mqtt version will be used
	mqtt_al_string_t               clientid;     ///< mqtt connect client identifier
	mqtt_al_string_t               user;         ///< mqtt connect user
	mqtt_al_string_t               passwd;       ///< mqtt connect passwd
	int                            cleansession; ///< 1 clean the session while 0 not
	mqtt_al_willmsg_t             *willmsg;      ///< mqtt connect will message
	unsigned short                 keepalivetime;///< keep alive time
	char                           conret;       ///< mqtt connect code, return by server
	int                            timeout;      ///< how much time will be blocked
}mqtt_al_conpara_t;

其中的一些引數值已經使用列舉給出:

  • security:安全連線引數(使用此需要確保mbedtls元件開啟)

列舉值如下:

/** @brief  this enum all the transport encode we support now*/
typedef enum
{
	en_mqtt_al_security_none = 0,    ///< no encode
	en_mqtt_al_security_psk,         ///< use the psk mode in transport layer
	en_mqtt_al_security_cas,	     ///< use the ca mode in transport layer,only check the server
	en_mqtt_al_security_cacs,	     ///< use the ca mode in transport layer,both check the server and client
	en_mqtt_al_security_end,         ///< the end for the mqtt
}en_mqtt_al_security_t;
  • version:使用的MQTT協議版本

列舉值如下:

/** @brief enum the mqtt version*/
typedef enum
{
	en_mqtt_al_version_3_1_0 = 0,
	en_mqtt_al_version_3_1_1,
}en_mqtt_al_verison;

另外,在複製的時候還需要注意,很多字串引數都是使用mqtt_al_string_t型別,其定義如下:

/** brief defines for all the ascii or data used in the mqtt engine */
typedef struct
{
	char *data;      ///< buffer to storage the data
	int   len;       ///< buffer data length
}mqtt_al_string_t;   //used to represent any type string (maybe not ascii)

在配置結構體完成之後,呼叫配置函式進行配置並連線,API如下:

/**
 *@brief: you could use this function to connect to the mqtt server
 *
 *@param[in] conparam  the parameter we will use in connect, refer to the data mqtt_al_conpara_t
 *@
 *@return: first you should check the return value then the return code in conparam
 *
 *@retval NULL which means you could not get the connect to the server,maybe network reason
 *@retval handle, which means you get the context, please check the conparam for more
 */
void * mqtt_al_connect( mqtt_al_conpara_t *conparam);

連線之後,首先應該檢查返回的handle指標是否為空,其次應該檢查mqtt_al_conpara_t結構體中conret的值,有以下列舉值:

/** @brief defines for the mqtt connect code returned by the server */
#define cn_mqtt_al_con_code_ok                0   ///< has been accepted by the server
#define cn_mqtt_al_con_code_err_version       1   ///< server not support the version
#define cn_mqtt_al_con_code_err_clientID      2   ///< client identifier is error
#define cn_mqtt_al_con_code_err_netrefuse     3   ///< server service not ready yet
#define cn_mqtt_al_con_code_err_u_p           4   ///< bad user name or password
#define cn_mqtt_al_con_code_err_auth          5   ///< the client is not authorized
#define cn_mqtt_al_con_code_err_unkown        -1  ///< unknown reason
#define cn_mqtt_al_con_code_err_network      0x80 ///< network reason,you could try once more

訂閱訊息

EMQ-X伺服器有心跳機制,實際應用中訂閱之前應該先檢查連線狀態,本實驗中暫不檢查。

連線成功後,首先訂閱訊息,設定回撥函式,方便接收下發的命令。

訂閱訊息的API如下:

/**
 * @brief you could use this function subscribe a topic from the server
 *
 * @param[in] handle the handle we get from mqtt_al_connect
 *
 * @param[in] subpara  refer to the data mqtt_al_subpara_t
 *
 * @return 0 success  -1  failed
 *
 */
int mqtt_al_subscribe(void *handle, mqtt_al_subpara_t *subpara);

兩個引數中,handle引數是之前使用mqtt_al_connect時返回的指標,直接傳入即可,subpara引數需要重點講述。

mqtt_al_subpara_t的定義如下:

/** @brief defines the mqtt subscribe parameter*/
typedef struct
{
	mqtt_al_string_t       topic;     ///< topic will be subscribe
	en_mqtt_al_qos_t       qos;       ///< qos requested
	fn_mqtt_al_msg_dealer  dealer;    ///< message dealer:used to deal the received message
	void                  *arg;       ///< used for the message dealer
	char                   subret;    ///< subscribe result code
	int                    timeout;   ///< how much time will be blocked
}mqtt_al_subpara_t;

其中訂閱訊息質量qos的列舉值如下:

/** @brief enum all the qos supported for the application */
typedef enum
{
	en_mqtt_al_qos_0 = 0,     ///< mqtt QOS 0
	en_mqtt_al_qos_1,         ///< mqtt QOS 1
	en_mqtt_al_qos_2,         ///< mqtt QOS 2
	en_mqtt_al_qos_err
}en_mqtt_al_qos_t;

dealer是一個函式指標,接收到下發命令之後會被回撥,arg是回撥函式引數,其定義如下:

/** @brief  defines the mqtt received message dealer, called by mqtt engine*/
typedef void (*fn_mqtt_al_msg_dealer)(void *arg,mqtt_al_msgrcv_t *msg);

訂閱之後,可以透過mqtt_al_subpara_t結構體中的subret值檢視是否訂閱成功。

釋出訊息

釋出訊息的API如下:

/**
 * @brief you could use this function to publish a message to the server
 *
 * @param[in] handle the handle we get from mqtt_al_connect
 *
 * @param[in] msg  the message we will publish, see the data mqtt_al_pubpara_t
 *
 * @return 0 success  -1  failed
 *
 */
int	mqtt_al_publish(void *handle, mqtt_al_pubpara_t *pubpara);

兩個引數中,handle引數是之前使用mqtt_al_connect時返回的指標,直接傳入即可,pubpara引數需要重點講述。

mqtt_al_pubpara_t的定義如下:

/** @brief defines for the mqtt publish */
typedef struct
{
	mqtt_al_string_t    topic;    ///< selected publish topic
	mqtt_al_string_t    msg;      ///< message to be published
	en_mqtt_al_qos_t    qos;      ///< message qos
	int                 retain;   ///< message retain :1 retain while 0 not
	int                 timeout;  ///< how much time will blocked
}mqtt_al_pubpara_t;

MQTT元件自動初始化

MQTT在配置之後,會自動初始化。

在SDK目錄中的IoT_LINK_1.0.0iot_linklink_main.c檔案中可以看到:

圖片描述

2. 配置準備

Makefile配置

因為本次實驗用到的元件較多:

  • AT框架
  • ESP8266裝置驅動
  • 串列埠驅動框架
  • cJSON元件
  • SAL元件
  • MQTT元件

這些實驗程式碼全部編譯下來,有350KB,而小熊派開發板所使用的主控晶片STM32L431RCT6的 Flash 僅有256KB,會導致編譯器無法連結出可執行檔案,所以要在makefile中修改最佳化選項,修改為-Os引數,即最大限度的最佳化程式碼尺寸,並去掉-g引數,即程式碼只能下載執行,無法除錯,如圖:

圖片描述

ESP8266裝置配置

在工程目錄中的OS_CONFIG/iot_link_config.h檔案中,配置ESP8266裝置的波特率和裝置名稱:

圖片描述

WIFI對接資訊配置

SDK:C:UsersAdministrator.icodesdkIoT_LINK_1.0.0(其中Administrator是實驗電腦的使用者名稱)。

在SDK目錄中的iot_linknetworktcpipesp8266_socketesp8266_socket_imp.c檔案中,配置連線資訊:

圖片描述

之後修改同路徑下的esp8266_socket_imp.mk檔案,如圖,將 TOP_DIR 改為 SDK_DIR :

圖片描述

修改paho_mqtt檔案路徑

在SDK目錄中的iot_linknetworkmqttpaho_mqttpaho_mqtt.mk檔案中,如圖,將 TOP_DIR 改為 SDK_DIR :

圖片描述

3. 使用mqtt.fx對接EMQ-X

配置

對接資訊配置如下:

圖片描述

其中ClientID隨機生成一個即可。

訂閱主題

使用mqtt.fx連線客戶端,訂閱本次實驗中的兩個主題:

  • 主題led_cmd:用於釋出控制命令
  • 主題lightness:用於上報亮度

圖片描述

4. 上雲實驗

編寫實驗檔案

在 Demo 資料夾下建立cloud_test_demo資料夾,在其中建立emqx_mqtt_demo.c檔案。

編寫程式碼:

#include <osal.h>
#include <mqtt_al.h>
#include <string.h>


#define DEFAULT_LIFETIME            60
#define DEFAULT_SERVER_IPV4         "122.51.89.94"
#define DEFAULT_SERVER_PORT         1883
#define CN_MQTT_EP_CLIENTID         "emqx-test-001"
#define CN_MQTT_EP_USERNAME         "mculover666"
#define CN_MQTT_EP_PASSWD           "123456789"
#define CN_MQTT_EP_SUB_TOPIC1       "led_cmd"
#define CN_MQTT_EP_PUB_TOPIC1       "lightness"

#define recv_buf_len 100
static char recv_buffer[recv_buf_len];   //下發資料接收緩衝區
static int  recv_datalen;                //表示接收資料長度

osal_semp_t recv_sync;  //命令接收回撥函式和處理函式之間的訊號量

char lightness_buf[10];

static void mqtt_al_msg_dealer(void *arg,mqtt_al_msgrcv_t *msg)
{
    if((msg->msg.len) < recv_buf_len)
    {
        //儲存資料
        memcpy(recv_buffer,msg->msg.data,msg->msg.len );
        recv_buffer[msg->msg.len] = '

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2983/viewspace-2824828/,如需轉載,請註明出處,否則將追究法律責任。

相關文章