本案例程序将演示编写一个连接MQTT服务器的业务程序,实现开发板联网上报数据到服务器。
typedef struct
{
/** The eyecatcher for this structure. must be MQTC. */
char struct_id[4];
/** The version number of this structure. Must be 0 */
int struct_version;
/** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1
*/
unsigned char MQTTVersion;
MQTTString clientID;
unsigned short keepAliveInterval;
unsigned char cleansession;
unsigned char willFlag;
MQTTPacket_willOptions will;
MQTTString username;
MQTTString password;
} MQTTPacket_connectData;
述:
MQTT客户端连接参数
参数:
名字 | 描述 |
---|---|
MQTTVersion | MQTT协议版本号 |
clientID | 用户ID |
keepAliveInterval | 保活周期 |
cleansession | 是否清除session信息 |
willFlag | 是否使用临终遗言 |
will | 临终遗言信息 |
username | 用户名 |
password | 用户密钥 |
示例代码如下:
// 连接参数
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
// 客户ID,唯一
data.clientID.cstring= "Talkweb";
// 不使用临终遗言
data.willFlag = 0;
// MQTT版本号
data.MQTTVersion = 3;
// 保存存活时间
data.keepAliveInterval = 0;
// 重新连接后是否清除以前的信息 0表示不清除,1表示重连清除
data.cleansession = 1;
// 服务器用户名
data.username.cstring = "Talkweb";
// 服务器用户密码
data.password.cstring = "Talkweb1996";
typedef struct MQTTMessage
{
enum QoS qos;
unsigned char retained;
unsigned char dup;
unsigned short id;
void *payload;
size_t payloadlen;
} MQTTMessage;
描述:
MQTT消息结构体
参数:
名字 | 描述 |
---|---|
qos | 服务等级 |
retained | 是否保留 |
dup | 重发标识 |
id | 消息id |
payload | 消息数据 |
payloadlen | 消息数据长度 |
void NetworkInit(Network* n)
描述: 初始化网络
参数:
名字 | 描述 |
---|---|
n | 要初始化的Network结构体 |
int NetworkConnect(Network* n, char* addr, int port)
描述:
连接MQTT服务器
参数:
名字 | 描述 |
---|---|
n | 已经初始化的Network. |
addr | MQTT服务器IP地址 |
port | MQTT服务器端口 |
void MQTTClientInit(MQTTClient* c, Network* network, unsigned int command_timeout_ms,
unsigned char* sendbuf, size_t sendbuf_size, unsigned char* readbuf, size_t readbuf_size)
描述:
MQTT客户端初始化
参数:
名字 | 描述 |
---|---|
c | MQTTClient客户端 |
network | 网络结构体 |
command_timeout_ms | 延时毫秒 |
sendbuf | 发送内容数组 |
sendbuf_size | 发送内容数组长度 |
readbuf | 接收内容数组 |
readbuf_size | 接收内容数组长度 |
int MQTTConnect(MQTTClient* c, MQTTPacket_connectData* options)
描述:
MQTT客户端连接服务器
参数:
名字 | 描述 |
---|---|
c | MQTT客户端 |
options | 连接参数 详细参数请查看上面定义 |
int MQTTSubscribe(MQTTClient* c, const char* topicFilter, enum QoS qos,
messageHandler messageHandler)
描述:
订阅主题
参数:
名字 | 描述 |
---|---|
c | MQTT客户端 |
topicFilter | 订阅的主题 |
qos | 订阅质量 |
00:最多一次,即:<=1 | |
01:至少一次,即:>=1 | |
10:一次,即:=1 | |
11:预留 | |
messageHandler | 消息处理回调函数 |
int MQTTPublish(MQTTClient* c, const char* topicName, MQTTMessage* message)
描述:
订阅主题
参数:
名字 | 描述 |
---|---|
c | MQTT客户端 |
topicName | 发布的主题 |
message | MQTTMessage 消息 |
主要代码分析
static void MQTTDemoTask(void)
{
// 连接WIFI
WifiConnect(SELECT_WIFI_SSID, SELECT_WIFI_PASSWORD);
printf("Starting ...\n");
int rc, count = 0;
MQTTClient client;
// 初始化网络参数
NetworkInit(&network);
printf("NetworkConnect ...\n");
begin:
// 连接服务器网络
NetworkConnect(&network, "123.60.8.120", 1883);
printf("MQTTClientInit ...\n");
// 初始化客户端
MQTTClientInit(&client, &network, 2000, sendBuf, sizeof(sendBuf), readBuf, sizeof(readBuf));
// 连接参数
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
// 客户ID,唯一
data.clientID.cstring= "Talkweb";
// 不使用临终遗言
data.willFlag = 0;
// MQTT版本号
data.MQTTVersion = 3;
// 保存存活时间
data.keepAliveInterval = 0;
// 重新连接后是否清除以前的信息 0表示不清除,1表示重连清除
data.cleansession = 1;
// 服务器用户名
data.username.cstring = "Talkweb";
// 服务器用户密码
data.password.cstring = "Talkweb1996";
printf("MQTTConnect ...\n");
// 登录服务器
rc = MQTTConnect(&client, &data);
// 失败处理
if (rc != 0) {
printf("MQTTConnect: %d\n", rc);
NetworkDisconnect(&network);
MQTTDisconnect(&client);
osDelay(200);
goto begin;
}
printf("MQTTSubscribe ...\n");
// 订阅主题,并绑定回调函数处理接收到的消息
rc = MQTTSubscribe(&client, "pubtopic", 2, MessageArrived);
// 订阅失败处理
if (rc != 0) {
printf("MQTTSubscribe: %d\n", rc);
osDelay(200);
goto begin;
}
while (count++) {
MQTTMessage message;
// 发布的内容
char payload[] = {"{\"name\": \"Talkweb\",\"url\": \"https://www.talkweb.com.cn/\"}"};
// 仅一次
message.qos = 2;
message.retained = 0;
message.payload = payload;
message.payloadlen = strlen(payload);
// 发布
if ((rc = MQTTPublish(&client, "pubtopic", &message)) != 0) {
printf("Return code from MQTT publish is %d\n", rc);
NetworkDisconnect(&network);
MQTTDisconnect(&client);
goto begin;
}
osDelay(100);
}
}
修改mqtt_main.h
第32行和33行的WiFi热点SSID和密码,改成自己环境中的WiFi热点。
// 默认WiFi名和密码
#define SELECT_WIFI_SSID "*****"
#define SELECT_WIFI_PASSWORD "*******"
修改 applications/app/BUILD.gn
路径中的 BUILD.gn 文件,指定 network_mqttclient_example
参与编译。
# "TW208_Module_ds1307:module_ds1307_example",
# "TW209_Module_gps:module_gps_example",
# "TW301_Network_wifista:network_wifista_example",
# "TW302_Network_wifiap:network_wifiap_example",
"TW303_Network_mqttclient:network_mqttclient_example",
# "TW304_Network_httpclient:network_httpclient_example",
# "TW305_Network_ntpclient:network_ntpclient_example",
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印连接到的Wifi热点信息,以及订阅MQTT服务器主题,并接收发布后返回的结果。
Starting ...
NetworkConnect ...
MQTTClientInit ...
MQTTConnect ...
MQTTSubscribe ...
wait for suback
Message arrived on topic pubtopic: {"code":-20,"desc":"appId cannot be empty"}
Message arrived on topic pubtopic: {"code":-20,"desc":"appId cannot be empty"}
Message arrived on topic pubtopic: {"code":-20,"desc":"appId cannot be empty"}
Message arrived on topic pubtopic: {"code":-20,"desc":"appId cannot be empty"}
Message arrived on topic pubtopic: {"code":-20,"desc":"appId cannot be empty"}
Message arrived on topic pubtopic: {"code":-20,"desc":"appId cannot be empty"}
Message arrived on topic pubtopic: {"code":-20,"desc":"appId cannot be empty"}
Message arrived on topic pubtopic: {"code":-20,"desc":"appId cannot be empty"}
自己搭建MQTT服务器,用于测试。测试步骤如下: 1、下载apache-apollo-1.7.1搭建本地mqtt服务器,用于接入测试。工具使用参考:2、获取本地IP地址,并把本地IP地址和端口61613替换案例中的地址。替换MQTTDemoTask函数中的NetworkConnect(&network, "为自己地址"); 3、对应修改服务器用户名和密码,替换为apollo的默认用户名和密码:admin,password。 4、为了方便测试,可以把本地电脑,开发板连接同一个网络。 5、正常显示如下:
NetworkConnect ...
MQTTClientInit ...
MQTTConnect ...
MQTTSubscribe ...
wait for suback
Message arrived on topic pubtopic: {"name": "Talkweb","url": "https://www.talkweb.com.cn/"}
Message arrived on topic pubtopic: {"name": "Talkweb","url": "https://www.talkweb.com.cn/"}
Message arrived on topic pubtopic: {"name": "Talkweb","url": "https://www.talkweb.com.cn/"}
Message arrived on topic pubtopic: {"name": "Talkweb","url": "https://www.talkweb.com.cn/"}
Message arrived on topic pubtopic: {"name": "Talkweb","url": "https://www.talkweb.com.cn/"}
Message arrived on topic pubtopic: {"name": "Talkweb","url": "https://www.talkweb.com.cn/"}
Message arrived on topic pubtopic: {"name": "Talkweb","url": "https://www.talkweb.com.cn/"}
Message arrived on topic pubtopic: {"name": "Talkweb","url": "https://www.talkweb.com.cn/"}