赞
踩
开发板功能区分布图
开发板俯视图
在之前的章节中,已经讲解过了MQTT的通讯原理和组包过程
,现在开始手把手的教大家用代码来实现连接MQTT平台以及数据的交互
,实际上这篇文章已经拖更接近两年了,非常感谢那些默默支持我的朋友们。代码的实现过程主要参考了MQTT中文网
[https://mqtt.p2hp.com/mqtt311],大家感兴趣的话可以打开进行学习,你们的点赞和支持是我持续更新的动力。
大家不要被我的代码量给吓到了,下面的代码无非是封装好的AT指令
,在下面我也会贴出AT指令实现的过程帮助大家理解,另外我也会贴出逆向后的报文
,让大家知道在明文情况
下,黑客抓包
会获得哪些数据。那些复杂指令集和实现过程也是通过一些重复且简单的指令组成的,希望你能够保持你的自信心,抱着良好的心态去对待生活。
服务器地址 broker-cn.emqx.io
服务器端口 1883
WIFI名称 MCSCV
WIFI密码 jnszstmOBB
//鉴权三元组
客户端ID 111|hmvcfu
用户名 hmvcfu
密码 a02d6361531c2dae941d5b022982d944
MQTT上报主题 sys/hmvcfu/post
MQTT下发主题 sys/hmvcfu/control
//设置STA模式
ESP8266> AT+CWMODE=1
//设置单连接模式
ESP8266> AT+CIPMUX=0
//连接路由器WIFI
ESP8266> AT+CWJAP="MCSCV","jnszstmOBB"
//连接服务器
ESP8266> AT+CIPSTART="TCP","broker-cn.emqx.io",1883
//发送连接报文
ESP8266> AT+CIPSEND=66
ESP8266> 10 40 00 04 4D 51 54 54 04 C0 00 78 00 0A 31 31 31 7C 68 6D 76 63 66 75 00 06 68 6D 76 63 66 75 00 20 61 30 32 64 36 33 36 31 35 33 31 63 32 64 61 65 39 34 31 64 35 62 30 32 32 39 38 32 64 39 34 34
//逆向后的连接报文
◇@\0MQTT繺0x\0
111|hmvcfu\0hmvcfu\0 a02d6361531c2dae941d5b022982d944□
//发送后回应
ESP8266< +IPD,5: 20 02 00 00
//发送订阅主题报文
ESP8266> AT+CIPSEND=25
ESP8266> 82 17 00 01 00 12 73 79 73 2F 68 6D 76 63 66 75 2F 63 6F 6E 74 72 6F 6C 00
//逆向后的订阅主题报文
?\0\0sys/hmvcfu/control\0□
//发送后回应
ESP8266< +IPD,5:90 03 00 01 00
//发送发布主题报文
ESP8266> AT+CIPSEND=64
ESP8266> 30 3E 00 0F 73 79 73 2F 68 6D 76 63 66 75 2F 70 6F 73 74 7B 22 6D 73 67 22 3A 7B 22 70 61 72 61 6D 64 61 74 61 22 3A 5B 7B 22 74 65 6D 70 22 3A 32 30 2C 22 68 75 6D 69 22 3A 39 38 7D 5D 7D 7D
//逆向后的发布主题报文
0>\0sys/hmvcfu/post{"msg":{"paramdata":[{"temp":20,"humi":98}]}}□
//接收到SEND OK说明发布成功
ESP8266< SEND OK
//接收到openLed指令
ESP8266< +IPD,29:30 1B 00 12 73 79 73 2F 68 6D 76 63 66 75 2F 63 6F 6E 74 72 6F 6C 6F 70 65 6E 4C 65 64
//逆向后的接收指令
0\0sys/hmvcfu/controlopenLed□
//接收到CloseLed指令
ESP8266< +IPD,30:30 1C 00 12 73 79 73 2F 68 6D 76 63 66 75 2F 63 6F 6E 74 72 6F 6C 63 6C 6F 73 65 4C 65 64
//逆向后的接收指令
0\0sys/hmvcfu/controlcloseLed□
MQTT组包函数 | |
---|---|
MQTT_PacketConnect | 连接服务器的组包函数 |
MQTT_UnPacketConnectAck | 连接回复消息解包 |
MQTT_PacketPublish | MQTT发布消息组包函数 |
MQTT_UnPacketPublishAck | MQTT发布回复消息解包函数 |
MQTT_UnPacketPublish | MQTT接收发布消息解包函数 |
MQTT_PacketSubscribe | MQTT订阅消息组包函数 |
MQTT_UnPacketSubscribe | MQTT订阅回复消息解包函数 |
MQTT_UnPacketUnSubscribe | MQTT取消订阅回复消息解包函数 |
MQTT_PacketUnSubscribe | MQTT取消订阅消息组包函数 |
MQTT_PacketDisConnect | 断开连接消息组包 |
MQTT_PacketPing | MQTT心跳请求组包函数 |
MQTT_UnPacketRecv | MQTT接收消息解包函数 |
MQTT基础函数 | |
---|---|
MQTTClient_DevLink | MQTT客户端连接函数 |
MQTTClient_Subscribe | MQTT客户端订阅函数 |
MQTTClient_Publish | MQTT客户端发布函数 |
MQTTClient_RevPro | MQTT客户端协议接收函数 |
MQTTClient_HeartBeat | MQTT客户端心跳函数 |
新建GloalConfig.h文件,添加以下代码
#ifndef __GLOAL_CONFIG_H_ #define __GLOAL_CONFIG_H_ #define SERVER_IP "broker-cn.emqx.io" //服务器地址 #define SERVER_PORT "1883"//服务器端口 #define WIFI_NAME "MCSCV" //WIFI名称 #define WIFI_PSWD "jnszstmOBB" //WIFI密码 //鉴权三元组 #define MQTT_CLIENTID "111|hmvcfu" //客户端ID #define MQTT_USERNAME "hmvcfu" //用户名 #define MQTT_PASSWORD "a02d6361531c2dae941d5b022982d944" //密码 #define MQTT_PUB_TOPIC "sys/hmvcfu/post" //MQTT上报主题 #define MQTT_SUB_TOPIC "sys/hmvcfu/control" //MQTT下发主题 #endif
新建shfm_mqtt.c文件,添加以下代码
#include "shfm_mqtt.h" /* *@brief 连接服务器的组包函数 *@param Username 用户名 * Password 密码 * ClientID 客户端ID * mqttPacket 数据包指针 *@return 数据包长度 */ uint16_t MQTT_PacketConnect(char *Username,char *Password,char *ClientID,uint8_t *mqttPacket) { int16_t len; int16_t ClientIDLen; int16_t UsernameLen; int16_t PasswordLen; uint16_t mqttPacketLen = 0; ClientIDLen = strlen(ClientID); UsernameLen = strlen(Username); PasswordLen = strlen(Password); //可变报头(10)+Payload 每个字段包含两个字节的长度标识 len = 10 + (ClientIDLen + 2) + (UsernameLen + 2) + (PasswordLen + 2); //加2是因为每个字段占两个字节 //固定报头 //控制报文类型 mqttPacket[mqttPacketLen++] = 0x10; //MQTT Message Type CONNECT //剩余长度(不包括固定头部),剩余长度最多可以用四个字节来表示 do { uint8_t encodedByte = len % 128; len = len / 128; // 如果有更多的数据要编码,请设置该字节的最高位 if ( len > 0 ) encodedByte = encodedByte | 128; mqttPacket[mqttPacketLen++] = encodedByte; } while ( len > 0 ); //可变报头 //协议名 mqttPacket[mqttPacketLen++] = 0; // 协议名长度高位 mqttPacket[mqttPacketLen++] = 4; // 协议名长度低位 mqttPacket[mqttPacketLen++] = 'M'; // ASCII 字符 M mqttPacket[mqttPacketLen++] = 'Q'; // ASCII 字符 Q mqttPacket[mqttPacketLen++] = 'T'; // ASCII 字符 T mqttPacket[mqttPacketLen++] = 'T'; // ASCII 字符 T //协议级别 mqttPacket[mqttPacketLen++] = 4; // MQTT协议版本号 4 //连接标志 mqttPacket[mqttPacketLen++] = MQTT_CONNECT_WILL_QOS0|MQTT_CONNECT_USER_NAME|MQTT_CONNECT_PASSORD; // 连接标志 mqttPacket[mqttPacketLen++] = WORD_MSB(MQTT_KEEP_LIVE_TIME); // 保活时间长度高位 mqttPacket[mqttPacketLen++] = WORD_LSB(MQTT_KEEP_LIVE_TIME); // 保活时间长度低位 mqttPacket[mqttPacketLen++] = WORD_MSB(ClientIDLen);// 客户端ID长度高位 mqttPacket[mqttPacketLen++] = WORD_LSB(ClientIDLen);// 客户端ID长度低位 memcpy(&mqttPacket[mqttPacketLen],ClientID,ClientIDLen); mqttPacketLen += ClientIDLen; if(UsernameLen > 0) { mqttPacket[mqttPacketLen++] = WORD_MSB(UsernameLen); //用户名长度高位 mqttPacket[mqttPacketLen++] = WORD_LSB(UsernameLen); //用户名长度低位 memcpy(&mqttPacket[mqttPacketLen],Username,UsernameLen); mqttPacketLen += UsernameLen; } if(PasswordLen > 0) { mqttPacket[mqttPacketLen++] = WORD_MSB(PasswordLen); //密码长度高位 mqttPacket[mqttPacketLen++] = WORD_LSB(PasswordLen); //密码长度低位 memcpy(&mqttPacket[mqttPacketLen],Password,PasswordLen); mqttPacketLen += PasswordLen; } return mqttPacketLen; } /* *@brief 连接消息解包 *@param rev_data 接收的数据 *@return 数据包长度 */ uint8_t MQTT_UnPacketConnectAck(uint8_t *rev_data) { if(rev_data[1] != 0x02) return 1; if(rev_data[2] == 0x00 || rev_data[2] == 0x01) return rev_data[3]; else return 255; } /* *@brief 断开连接消息组包 *@param mqttPacket 数据包指针 *@return 数据包长度 */ uint8_t MQTT_PacketDisConnect(uint8_t *mqttPacket) { uint16_t mqttPacketLen = 0; //固定报头 mqttPacket[mqttPacketLen++] = M_DISCONNECT << 4; //剩余长度值 mqttPacket[mqttPacketLen++] = 0; return 0; } /* *@brief MQTT订阅消息组包函数 *@param topic 主题名称 * qos 消息等级 * mqttPacket 数据包指针 *@return 数据包长度 */ uint16_t MQTT_PacketSubscribe(char *topic,uint8_t qos,uint8_t *mqttPacket) { int16_t len; int16_t topiclen; uint16_t mqttPacketLen = 0; topiclen = strlen(topic); len = 2 + (topiclen + 2) + 1; //可变报头的长度(2字节)加上有效载荷的长度 //固定报头 //控制报文类型 mqttPacket[mqttPacketLen++] = 0x82; //消息类型和标志订阅 //剩余长度 do { unsigned char encodedByte = len % 128; len = len / 128; // 如果有更多的数据要编码,请设置该字节的最高位 if ( len > 0 ) encodedByte = encodedByte | 128; mqttPacket[mqttPacketLen++] = encodedByte; } while ( len > 0 ); //可变报头 mqttPacket[mqttPacketLen++] = 0; //消息标识符 MSB mqttPacket[mqttPacketLen++] = 0x01; //消息标识符 LSB //有效载荷 mqttPacket[mqttPacketLen++] = WORD_MSB(topiclen);//主题长度 MSB mqttPacket[mqttPacketLen++] = WORD_LSB(topiclen);//主题长度 LSB memcpy(&mqttPacket[mqttPacketLen],topic,topiclen); mqttPacketLen += topiclen; mqttPacket[mqttPacketLen++] = qos;//QoS级别 return mqttPacketLen; } /* *@brief MQTT订阅回复消息解包函数 *@param rev_data 接收的数据 *@return 0-成功 其他-失败 */ uint8_t MQTT_UnPacketSubscribe(uint8_t *rev_data) { uint8_t result = 255; if(rev_data[2] == WORD_MSB(MQTT_SUBSCRIBE_ID) && rev_data[3] == WORD_LSB(MQTT_SUBSCRIBE_ID)) { switch(rev_data[4]) { case 0x00: case 0x01: case 0x02: //MQTT订阅成功 result = 0; break; case 0x80: //MQTT订阅失败 result = 1; break; default: //MQTT未知错误 result = 2; break; } } return result; } /* *@brief MQTT取消订阅消息组包函数 *@param topic 主题名称 * qos 消息等级 * mqttPacket 数据包指针 *@return 数据包长度 */ uint16_t MQTT_PacketUnSubscribe(char *topic,uint8_t qos,uint8_t *mqttPacket) { int16_t topiclen; int16_t len; uint16_t mqttPacketLen = 0; topiclen = strlen(topic); len = 2 + (topiclen + 2);//可变报头的长度(2字节)加上有效载荷的长度 //固定报头 //控制报文类型 mqttPacket[mqttPacketLen++] = 0xA2; //取消订阅 //剩余长度 do { uint8_t encodedByte = len % 128; len = len / 128; // if there are more data to encode, set the top bit of this byte if ( len > 0 ) encodedByte = encodedByte | 128; mqttPacket[mqttPacketLen++] = encodedByte; } while ( len > 0 ); //可变报头 mqttPacket[mqttPacketLen++] = 0; //消息标识符 MSB mqttPacket[mqttPacketLen++] = 0x01; //消息标识符 LSB //有效载荷 mqttPacket[mqttPacketLen++] = WORD_MSB(topiclen);//主题长度 MSB mqttPacket[mqttPacketLen++] = WORD_LSB(topiclen);//主题长度 LSB memcpy(&mqttPacket[mqttPacketLen],topic,topiclen); mqttPacketLen += topiclen; return mqttPacketLen; } /* *@brief MQTT取消订阅回复消息解包函数 *@param rev_data 接收的数据 *@return 0-成功 其他-失败 */ uint8_t MQTT_UnPacketUnSubscribe(uint8_t *rev_data) { uint8_t result = 1; if(rev_data[2] == WORD_MSB(MQTT_UNSUBSCRIBE_ID) && rev_data[3] == WORD_LSB(MQTT_UNSUBSCRIBE_ID)) { result = 0; } return result; } /* *@brief MQTT发布消息组包函数 *@param topic 主题 * message 消息 * qos 消息等级 * mqttPacket 数据包指针 *@return 0-成功 其他-失败 */ uint16_t MQTT_PacketPublish(char *topic, char *message, uint8_t qos,uint8_t *mqttPacket) { int16_t len; int16_t topicLength = strlen(topic); int16_t messageLength = strlen(message); static uint16_t id=0; uint16_t mqttPacketLen = 0; //有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度 //QOS为0时没有标识符 //数据长度 主题名 报文标识符 有效载荷 if(qos) len = (2+topicLength) + 2 + messageLength; else len = (2+topicLength) + messageLength; //固定报头 //控制报文类型 mqttPacket[mqttPacketLen++] = 0x30; // MQTT 消息类型是 PUBLISH //剩余长度 do { uint8_t encodedByte = len % 128; len = len / 128; // 如果有更多的数据要编码,请设置该字节的最高位 if ( len > 0 ) encodedByte = encodedByte | 128; mqttPacket[mqttPacketLen++] = encodedByte; } while ( len > 0 ); mqttPacket[mqttPacketLen++] = WORD_MSB(topicLength);//主题长度MSB mqttPacket[mqttPacketLen++] = WORD_LSB(topicLength);//主题长度LSB memcpy(&mqttPacket[mqttPacketLen],topic,topicLength);//拷贝主题 mqttPacketLen += topicLength; //报文标识符 if(qos) { mqttPacket[mqttPacketLen++] = WORD_MSB(id); mqttPacket[mqttPacketLen++] = WORD_LSB(id); id++; } memcpy(&mqttPacket[mqttPacketLen],message,messageLength); mqttPacketLen += messageLength; return mqttPacketLen; } /* *@brief MQTT发布回复消息解包函数 *@param rev_data 接收的数据 *@return 0-成功 其他-失败 */ uint8_t MQTT_UnPacketPublishAck(uint8_t *rev_data) { if(rev_data[1] != 2) return 1; if(rev_data[2] == WORD_MSB(MQTT_PUBLISH_ID) && rev_data[3] == WORD_LSB(MQTT_PUBLISH_ID)) return 0; else return 1; } /* *@brief MQTT收到发布消息解包函数 *@param rev_data 接收的数据 * topic 主题 * topic_len 主题长度 * payload 有效载荷 payload_len 有效载荷长度 *@return 0-成功 其他-失败 */ uint8_t MQTT_UnPacketPublish(uint8_t *rev_data, int8_t *topic, uint16_t *topic_len, int8_t *payload, uint16_t *payload_len) { int i = 0; uint8_t *msgPtr; uint32_t remain_len = 0; uint32_t multiplier = 1; uint8_t *in; in = rev_data+1; for(i = 0; i < 4; ++i) { remain_len += (in[i] & 0x7f) * multiplier; if(!(in[i] & 0x80)) { // return i + 1; i += 1; break; } multiplier <<= 7; if(multiplier >= 2097152) //128 * 128 * 128 { return -2; // error, out of range } } msgPtr = rev_data + i + 1; if(remain_len < 2) //retain return 255; *topic_len = (uint16_t)msgPtr[0] << 8 | msgPtr[1]; if(remain_len < *topic_len + 2) return 255; memcpy(topic, (int8_t *)msgPtr + 2, *topic_len); //复制数据 *payload_len = remain_len - 2 - *topic_len; memcpy(payload, (int8_t *)msgPtr + 2 + *topic_len, *payload_len); return 0; } /* *@brief MQTT心跳请求组包函数 *@param mqttPacket 数据包指针 *@return 0-成功 其他-失败 */ uint8_t MQTT_PacketPing(uint8_t *mqttPacket) { uint8_t mqttPacketLen = 0; /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket[mqttPacketLen++] = M_PINGREQ << 4; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket[mqttPacketLen++] = 0; return mqttPacketLen; } /* *@brief MQTT接收消息解包函数 *@param dataPtr 消息包指针 *@return 0-成功 其他-失败 */ uint8_t MQTT_UnPacketRecv(uint8_t *dataPtr) { uint8_t status = 255; uint8_t type = dataPtr[0] >> 4; //类型检查 if(type < 1 || type > 14) return status; if(type == M_PUBLISH) status = type; else status = type; return status; }
新建shfm_mqtt.h文件,添加以下代码
#ifndef __MQTTData_H #define __MQTTData_H //C库 #include <string.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #define WORD_MSB(A) (uint8_t)((A & 0xFF00) >> 8) #define WORD_LSB(A) (uint8_t)(A & 0x00FF) #define MQTT_PUBLISH_ID 10 #define MQTT_SUBSCRIBE_ID 20 #define MQTT_UNSUBSCRIBE_ID 30 #define MQTT_CONNECT_WILL_QOS0 0x00 #define MQTT_CONNECT_PASSORD 0x40 #define MQTT_CONNECT_USER_NAME 0x80 #define MQTT_KEEP_LIVE_TIME 120 //单位 S #define _DEBUG_MQTT 1 typedef enum { //名字 值 报文流动方向 描述 M_RESERVED1 =0 , // 禁止 保留 M_CONNECT , // 客户端到服务端 客户端请求连接服务端 M_CONNACK , // 服务端到客户端 连接报文确认 M_PUBLISH , // 两个方向都允许 发布消息 M_PUBACK , // 两个方向都允许 QoS 1消息发布收到确认 M_PUBREC , // 两个方向都允许 发布收到(保证交付第一步) M_PUBREL , // 两个方向都允许 发布释放(保证交付第二步) M_PUBCOMP , // 两个方向都允许 QoS 2消息发布完成(保证交互第三步) M_SUBSCRIBE , // 客户端到服务端 客户端订阅请求 M_SUBACK , // 服务端到客户端 订阅请求报文确认 M_UNSUBSCRIBE , // 客户端到服务端 客户端取消订阅请求 M_UNSUBACK , // 服务端到客户端 取消订阅报文确认 M_PINGREQ , // 客户端到服务端 心跳请求 M_PINGRESP , // 服务端到客户端 心跳响应 M_DISCONNECT , // 客户端到服务端 客户端断开连接 M_RESERVED2 , // 禁止 保留 } _typdef_mqtt_message; uint16_t MQTT_PacketConnect(char *Username,char *Password,char *ClientID,uint8_t *mqttPacket); uint8_t MQTT_UnPacketConnectAck(uint8_t *rev_data); uint16_t MQTT_PacketPublish(char *topic, char *message, uint8_t qos,uint8_t *mqttPacket); uint8_t MQTT_UnPacketPublishAck(uint8_t *rev_data); uint8_t MQTT_UnPacketPublish(uint8_t *rev_data, int8_t *topic, uint16_t *topic_len, int8_t *payload, uint16_t *payload_len); uint16_t MQTT_PacketSubscribe(char *topic,uint8_t qos,uint8_t *mqttPacket); uint8_t MQTT_UnPacketSubscribe(uint8_t *rev_data); uint8_t MQTT_UnPacketUnSubscribe(uint8_t *rev_data); uint16_t MQTT_PacketUnSubscribe(char *topic,uint8_t qos,uint8_t *mqttPacket); uint8_t MQTT_PacketDisConnect(uint8_t *mqttPacket); uint8_t MQTT_PacketPing(uint8_t *mqttPacket); uint8_t MQTT_UnPacketRecv(uint8_t *dataPtr); #endif
新建mqttclient.h文件,添加以下代码
#ifndef __MQTT_CLIENT_H_ #define __MQTT_CLIENT_H_ #include "sys.h" #ifndef MQTTCLIENT_OK #define MQTTCLIENT_OK 0 #endif #ifndef MQTTCLIENT_NOK #define MQTTCLIENT_NOK 1 #endif #define MQTTCLIENT_RETTYPE unsigned char MQTTCLIENT_RETTYPE MQTTClient_DevLink(void); MQTTCLIENT_RETTYPE MQTTClient_Subscribe(const char *topic); MQTTCLIENT_RETTYPE MQTTClient_Publish(const char *topic, const char *msg); MQTTCLIENT_RETTYPE MQTTClient_HeartBeat(void); void MQTTClient_RevPro(uint8_t *cmd); #endif
新建mqttclient.c文件,编写以下代码
#include "mqttclient.h" #include "shfm_mqtt.h" #include "ESP8266.h" #include "stdio.h" #include "GloalConfig.h" #include "gpio.h" /* *@brief MQTT连接函数 *@param void *@return MQTTCLIENT_OK-成功 其余-失败 */ MQTTCLIENT_RETTYPE MQTTClient_DevLink(void) { uint8_t mqttPacket[100]= {0}; uint16_t mqttPacketLen = 0; uint8_t *dataPtr = NULL; UsartPrintf(USART_DEBUG,"Tips: Connect Mqtt\r\n"); UsartPrintf(USART_DEBUG,"Tips: UserName:%s\r\n",MQTT_USERNAME); UsartPrintf(USART_DEBUG,"Tips: Password:%s\r\n",MQTT_PASSWORD); UsartPrintf(USART_DEBUG,"Tips: ClientId:%s\r\n",MQTT_CLIENTID); mqttPacketLen = MQTT_PacketConnect(MQTT_USERNAME,MQTT_PASSWORD,MQTT_CLIENTID,mqttPacket); if(mqttPacketLen < 2) return MQTTCLIENT_NOK; ESP8266_SendData(DISABLE,mqttPacket, mqttPacketLen,Single_ID_0); //上传平台 dataPtr = ESP8266_GetIPD(DISABLE,200); //等待平台响应 if(dataPtr != NULL) { if(MQTT_UnPacketRecv(dataPtr) == M_CONNACK) { return MQTT_UnPacketConnectAck(dataPtr); //返回0为连接成功 } } return MQTTCLIENT_NOK; } /* *@brief MQTT订阅函数 *@param topic 主题 *@return MQTTCLIENT_OK-成功 其余-失败 */ MQTTCLIENT_RETTYPE MQTTClient_Subscribe(const char *topic) { uint8_t mqttPacket[100]= {0}; uint16_t mqttPacketLen = 0; uint8_t *dataPtr = NULL; UsartPrintf(USART_DEBUG,"Tips: Subscribe Topic:%s\r\n",topic); mqttPacketLen = MQTT_PacketSubscribe((char*)topic,MQTT_CONNECT_WILL_QOS0,mqttPacket); if(mqttPacketLen < 2) return MQTTCLIENT_NOK; ESP8266_SendData(DISABLE,mqttPacket, mqttPacketLen,Single_ID_0); //上传平台 dataPtr = ESP8266_GetIPD(DISABLE,200); //等待平台响应 if(dataPtr != NULL) { if(MQTT_UnPacketRecv(dataPtr) == M_SUBACK) { return MQTT_UnPacketSubscribe(dataPtr); //返回0为连接成功 } } return MQTTCLIENT_NOK; } /* *@brief MQTT客户端发布函数 *@param topic 主题 * msg 发布消息 *@return MQTTCLIENT_OK-成功 其余-失败 */ MQTTCLIENT_RETTYPE MQTTClient_Publish(const char *topic, const char *msg) { uint8_t mqttPacket[100]= {0}; uint16_t mqttPacketLen = 0; uint8_t *dataPtr = NULL; uint8_t ucExecRes = MQTTCLIENT_NOK; UsartPrintf(USART_DEBUG,"Tips: Publish Topic:%s,Message:%s\r\n",topic,msg); mqttPacketLen = MQTT_PacketPublish((char*)topic,(char*)msg,MQTT_CONNECT_WILL_QOS0,mqttPacket); if(mqttPacketLen < 2) return MQTTCLIENT_NOK; if(ESP8266_SendData(DISABLE,mqttPacket, mqttPacketLen,Single_ID_0) == ESP8266_OK) //向平台发送订阅请求 ucExecRes = MQTTCLIENT_OK; return ucExecRes; } /* *@brief MQTT客户端心跳函数 *@param void *@return MQTTCLIENT_OK-成功 其余-失败 */ MQTTCLIENT_RETTYPE MQTTClient_HeartBeat(void) { uint8_t mqttPacket[2]= {0}; uint16_t mqttPacketLen = 0; uint8_t *dataPtr = NULL; UsartPrintf(USART_DEBUG,"Tips: HearBeat\r\n"); mqttPacketLen = MQTT_PacketPing(mqttPacket); ESP8266_SendData(DISABLE,mqttPacket, sizeof(mqttPacket),Single_ID_0); //向平台上传心跳请求 dataPtr = ESP8266_GetIPD(DISABLE,200); if(dataPtr != NULL) { if(dataPtr[0] == M_PINGRESP) { return MQTTCLIENT_OK; } } return MQTTCLIENT_NOK; } /* *@brief MQTT客户端协议接收函数 *@param cmd 接收到的命令 *@return MQTTCLIENT_OK-成功 其余-失败 */ void MQTTClient_RevPro(uint8_t *cmd) { uint8_t type = 0; uint8_t result = 0; int8_t cmdid_topic[50] = {0}; int8_t req_payload[100] = {0}; uint16_t topic_len = 0; uint16_t req_len = 0; type = MQTT_UnPacketRecv(cmd); //进行解包 if(type == M_PUBLISH) { result = MQTT_UnPacketPublish(cmd, cmdid_topic,&topic_len,req_payload, &req_len); if(result == 0) { UsartPrintf(USART_DEBUG, "topic: %s, topic_len: %d, payload: %s, payload_len: %d\r\n", cmdid_topic, topic_len, req_payload, req_len); if(strstr((char*)req_payload,"openLed")) { LED_Set(LED_ON); //打开LED灯 } else if(strstr((char*)req_payload,"closeLed")) { LED_Set(LED_OFF); //关闭LED灯 } } } }
打开main.c文件,在main函数输入以下代码
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
ESP8266_RETTYPE netStatus = ESP8266_NOK;
unsigned char netErrCount = 0;
/* USER CODE END PTD */
/* USER CODE BEGIN 1 */ unsigned char *dataPtr = NULL; uint32_t send_time = 0; ESP8266_RETTYPE ucExecRes = MQTTCLIENT_NOK; uint8_t mqttWork = 0; char sendData[100]; /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_LPUART1_UART_Init(); MX_USART1_UART_Init(); MX_TIM2_Init(); /* USER CODE BEGIN 2 */ USART_Interupt_Enable(); //使能串口中断 TIM_Interupt_Enable(); //使能定时器中断 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if(!netDeviceInfo.netWork) //如果网络未初始化 { if(!NET_DEVICE_Init()) //进行网络初始化 { mqttWork = MQTTClient_DevLink() == 0 ? 1 : 0; //连接MQTT服务器 if(mqttWork == 1) //如果连接MQTT成功 { printf("连接服务器成功\r\n"); MQTTClient_Subscribe(MQTT_SUB_TOPIC); //订阅MQTT下发主题 } } } if(mqttWork) { dataPtr = ESP8266_GetIPD(DISABLE,0); //等待平台响应 if(dataPtr != NULL) { if(MQTT_UnPacketRecv(dataPtr) == M_PUBLISH) { MQTTClient_RevPro(dataPtr); } } } if(time2Count - send_time >= 10000) //(1ms * 10000)相当于延时10秒钟 { send_time = time2Count; //记下当前定时器的数值 if(mqttWork) { sprintf(sendData,"{\"msg\":{\"paramdata\":[{\"temp\":20,\"humi\":98}]}}"); // ucExecRes = MQTTClient_Publish(MQTT_PUB_TOPIC,sendData); if(ucExecRes == MQTTCLIENT_NOK) { netErrCount++; //错误次数进行累加 if(netErrCount >= 3) //超过三次,进行自检 { netStatus = ESP8266_Get_LinkStatus(); //检查连接状态 if(netStatus == 4) //网络已经断开 { netErrCount = 0; //将错误清零 netDeviceInfo.netWork = 0; //标志网络断开 netDeviceInfo.initStep = 0; //将初始化步骤清零 } } } else { netErrCount = 0; //无错误,清除错误计数 } } } } /* USER CODE END 3 */
实现的功能 |
---|
1、上电自动连接WIFI |
2、连接WIFI成功后,连接MQTT服务器 |
3、连接MQTT服务器后,接收来自服务器的指令,并执行指令中的开关灯操作 |
4、每10秒向服务器上传一次数据 |
5、上传数据失败超过3次,自动进行网络初始化 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。