mqtt
目录
回顾
-- 昨天我们写的AT指令是直接写在main中,在while循环的外面,没有很好的封装,所以今天我们写一个函数来封装AT指令
//要保证能在while循环中运行
uint8_t state = 0;
void wifi_get_time(void)
{
uint8_t back = 0;
switch(state)
{
case 0:
back = SendCmdAndJudgeSuccess("AT\r\n","OK",1000);
if(back == 1)//返回值如果是1,代表指令执行成功
state++;
break;
case 1:
back = SendCmdAndJudgeSuccess("AT+RST\r\n","OK",2000);
if(back == 1)
state++;
break;
case 2:
back = SendCmdAndJudgeSuccess("AT+CWMODE=1\r\n","OK",1000);
if(back == 1)
state++;
break;
case 3:
back = SendCmdAndJudgeSuccess("AT+CIPMUX=0\r\n","OK",1000);
if(back == 1)
state++;
break;
case 4:
//在flash里面读取wifi信息esp.wifiname,esp.wifipassword,这里没有用flash,先直接赋值
strcpy(esp.wifiname,"111");
strcpy(esp.wifipassword,"pimouren");
memset(esp.txbuff,0,1024);
sprintf(esp.txbuff,"AT+CWJAP=\"%s\",\"%s\"\r\n",esp.wifiname,esp.wifipassword);
back = SendCmdAndJudgeSuccess(esp.txbuff,"OK",10000);
if(back == 1)
state++;
break;
case 5:
memset(esp.txbuff,0,1024);
//sprintf(esp.txbuff,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",TIMEIP,TIMEPORT);
if(back == 1)
state++;
break;
case 6:
back = SendCmdAndJudgeSuccess("AT+CIPMODE=1\r\n","OK",1000);
if(back == 1)
state++;
break;
case 7:
back = SendCmdAndJudgeSuccess("AT+CIPSEND\r\n","OK",1000);
if(back == 1)
state++;
break;
case 8:
memset(esp.rxbuff,0,1024);
esp.rxlen = 0;
esp.rxflag = 0;
memset(esp.txbuff,0,1024);
sprintf(esp.txbuff,"%s",GETTIME);
uart3_txstr(esp.txbuff);
Delay_nms(1000);
state++;
break;
case 11:
back = SendCmdAndJudgeSuccess("AT+CIPCLOSE\r\n","OK",1000);
if(back == 1)
state++;
break;
}
}
云服务器的操作
-- 云服务器有公有的(阿里云。。)和私有的(公司单独的)。
- 1、和服务器进行连接(最简单的就是tcp连接,发送请求指令)
有一些服务器通信是比较复杂了
有的通信还要遵循一些协议
比如说mqtt协议
- 2、如何跟服务器通信
-- 阿里云有很多产品,具体用哪个 -- 打开阿里云,注册并登入,从产品里面选择物联网找到飞燕平台
-- 进入点击管理控制台
-- 注意:进不去就说明账号之前使用过,需要重新注册账号
-- 点击创建新项目
-- 双击创建好的项目
-- 点击创建产品
-- 填写相关信息
-- 其他就不用改了,随后点击确认
-- 添加自定义功能
-- 随后在人机交互模块
-- 配置基础APP
--
-- 在设备模块模块点击选择面板
-- 注意这里APP的模块官方会提供一些模板,但是有的公司会用自己的
-- 点击创建面板里面的空白面板
-- 进入APP的编辑界面
-- 现在右边栏选择一个背景,有很多可以选择,也可选择图片
-- 右边的侧边栏有对应的图标,可以直接拖进页面
-- 然后点击右上角的保存,并在之后输入面板名称,再次点击确认
-- 保存好的APP可以在手机上预览,点击右上角的预览,就会生成二维码,用手机上的云智能软件扫描二维码就可以看到APP
-- 重新回到刚刚的选择面板就可以选择刚刚设计的面板了
-- 剩下的语音交互和产品说明书可以不用管
-- 随后进入设备调试模块,新增测试设备
-- 新增的测试设备可以不写,直接点击确认就会自动生成设备名,复制生成的设备名
-- 随后回到人机交互,点击产品说明书,然后点击下载配网二维码
-- 用云智能APP扫这个码,可能会产生未激活的情况。
-- 那么怎么才能激活呢?需要底层的硬件的连接
-- 云平台操作完成,回归代码
MQTT协议
-- mqtt
-- 先看mqtt协议的相关手册了解mqtt
--
-- 注意这里0和15的消息类型不用,所以说mqtt协议拥有14中不同的消息类型。
-- mqtt协议专门连接物联网平台
-- 之前咱们连接时间服务器(用tcp连接)
-- 今天去连接阿里云服务器(也是tcp连接)
-- 关键问题是咱们所使用的是物联网平台,是属于阿里云服务器上的一个功能
-- 让数据显示在云平台
--主要是 和云平台建立通信
-- 不同的云平台建立通信的方式是不一样的
-- 阿里云物联网平台自身有自己的通信协议(mqtt协议)
-- 和物联网平台通信,就要用到mqtt协议
-- MQTT 协议的报文格式:固定报头+可变报头+有效载荷
对于 PUBLISH 来说有效载荷就是应用消息。
-- wifi模块要先建立tcp连接,然后才能用mqtt
-- mqtt到底应该怎么搭建怎么使用
-- 同官方库
-- 将官方库移植到工程
-- MQTT 库移植介绍
-
1、找到官方库
-
2、
-
3、在工程里面新建文件夹mqtt
-
4、将源码里面src文件夹里面的文件整体移入mqtt文件里面
-
5、将mqtt文件添加进工程
-
6、添加头文件路径
-- 其实咱们用到的函数也就几个:
MQTTSerialize_connect();建立连接报文
MQTTSerialize_publish();建立发布数据报文
MQTTSerialize_subscribe();建立订阅报文
MQTTSerialize_unsubscribe();取消订阅
MQTTSerialize_disconnect();断开连接
-- 应用
-- 官方库怎么用?可以选择百度
-- 用这个连接去实现了功能 Paho mqtt C语言库介绍-CSDN博客
-- 链接讲的是官方库的使用
-- 各个.c文件的作用
-- 这里我们根据例程来编写代码,使用官方库
-- 找到例程(可以参考)
-- 根据mqtt的官方例程,将我们需要用到的部分代码复制进我们的工程。
-- 编写一个mqtt的连接函数
//mqtt的连接函数
void mqtt_connect(void)
{
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;//定义了一个结构体,下面对结构体参数赋值
data.keepAliveInterval = 60;//保持连接时间(60s)
data.cleansession = 1;
data.clientID.cstring = CLIENTID;
data.username.cstring = USERNAME;
data.password.cstring = PASSWD;
memset(esp.txbuff,0,1024);
uint32_t len = MQTTSerialize_connect(esp.txbuff, 1024, &data);//返回值就是txbuff的长度
//发送连接报文
uart3_txbuff(esp.txbuff,len);
}
-- 其中,mqtt的ID,用户名和密码,在物联网平台里面可以找到
-- 同时打开物联网平台
-- 点击管理控制台
-- 点击公共实例,没开通的需要开通
-- 点击设备,找到之前我们创建的设备,点击查看
-- 找到mqtt的连接参数,点击查看(注意:这些参数是会改变的,随着时间有变化,但是只要连接上一次,以后这些参数就不用再改了)
-- 点击一键复制
-- 将这些参数复制到.h中,然后将他分成5份,可以根据逗号来分
-- 将这些参数改为宏定义
-- 前三个参数也就是刚刚我们需要的mqtt的ID,用户名和密码
-- 将AT指令的相关参数更改
-- 今天要通过tcp连接阿里云,所以要改为阿里云的IP的端口,也就是刚刚我们复制的部分参数
-- 将连接时间服务器改为今天写的mqtt连接函数
-- 之后打开刚刚的物联网平台,点击我们之前创建的产品,查看
-- 选择物模型通信Topic,找到主题,复制主题
-- 写成宏定义放在工程的.h中
-- 中间的参数是设备名称,将自己的设备名称替代
-- 将刚刚定义的宏定义写入发布函数的参数中,还有最后两个参数怎么得到
-- 这两个参数是主题名称,负载和负载长度,而负载有固定格式
-- 这里也就是buff,其中需要更改的就是以下这些
-- 这些名称可以在物联网平台中找到
-- 这里先写成定值,注意这里如果后面还有要写的数据,就要写",",否则不写,注意这里格式不能错
-- 随后根据官方例程找到mqtt的订阅和发布函数,复制到工程中,更改上述得到的相关参数
void mqtt_pub(void)
{
//返回值长度
char buff[512] = {0};
sprintf(buff,"{\"id\":1724227172076,\"params\":\
{\"temperature\":20.1,\
\"HCHO\":23,\
\"CO2\":23\
},\"version\":\"1.0\",\
\"method\":\"thing.event.property.post\"}");
MQTTString topicString = MQTTString_initializer;
topicString.cstring = TOPIC_PUB;
memset(esp.txbuff,0,1024);
uint32_t len = MQTTSerialize_publish(esp.txbuff, 1024, 0, 0, 0, 0,topicString, buff, strlen(buff)); //主题名称,负载和负载长度
uart3_txbuff(esp.txbuff,len);
}
-- 在主函数中调用
if(rtctime >=999)
{
rtctime = 0;
get_time();
}
if(wifitime >=1000)
{
wifitime = 0;
//天气,时间,ap,云服务器
wifi_get_time();
}
-- 更改有封装AT指令的函数
//要保证能在while循环中运行
uint8_t state = 0;
void wifi_get_time(void)
{
uint8_t back = 0;
switch(state)
{
case 0:
back = SendCmdAndJudgeSuccess("AT\r\n","OK",1000);
if(back == 1)
state++;
break;
case 1:
back = SendCmdAndJudgeSuccess("AT+RST\r\n","OK",2000);
if(back == 1)
state++;
break;
case 2:
back = SendCmdAndJudgeSuccess("AT+CWMODE=1\r\n","OK",1000);
if(back == 1)
state++;
break;
case 3:
back = SendCmdAndJudgeSuccess("AT+CIPMUX=0\r\n","OK",1000);
if(back == 1)
state++;
break;
case 4:
//在flash里面读取wifi信息esp.wifiname,esp.wifipassword,这里没有用flash,先直接赋值
strcpy(esp.wifiname,"111");
strcpy(esp.wifipassword,"pimouren");
memset(esp.txbuff,0,1024);
sprintf(esp.txbuff,"AT+CWJAP=\"%s\",\"%s\"\r\n",esp.wifiname,esp.wifipassword);
back = SendCmdAndJudgeSuccess(esp.txbuff,"OK",10000);
if(back == 1)
state++;
break;
case 5:
memset(esp.txbuff,0,1024);
//sprintf(esp.txbuff,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",TIMEIP,TIMEPORT);
//换成阿里云的IP的端口
sprintf(esp.txbuff,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",MATTHOSTURL,PORT);
back = SendCmdAndJudgeSuccess(esp.txbuff,"OK",10000);
if(back == 1)
state++;
break;
case 6:
back = SendCmdAndJudgeSuccess("AT+CIPMODE=1\r\n","OK",1000);
if(back == 1)
state++;
break;
case 7:
back = SendCmdAndJudgeSuccess("AT+CIPSEND\r\n","OK",1000);
if(back == 1)
state++;
break;
case 8:
// memset(esp.rxbuff,0,1024);
// esp.rxlen = 0;
// esp.rxflag = 0;
// memset(esp.txbuff,0,1024);
// sprintf(esp.txbuff,"%s",GETTIME);
// uart3_txstr(esp.txbuff);
// Delay_nms(1000);
// state++;
mqtt_connect();
state++;
break;
case 9:
mqtt_pub();
// if(esp.rxflag==1)
// {
// esp.rxflag=0;
// uint8_t timebuff[11] = {0};
// char *p = strstr((char *)esp.rxbuff,"time");//strstr找到返回地址,没找到返回空
// if(p!=NULL)
// {
// p+=6;
//
// for(uint8_t i=0;i<10;i++)
// {
// timebuff[i] = *(p+i);
//
// }
// }
// uint32_t timesec = atoi(timebuff);
// printf("time:%s %ld\r\n",timebuff,(long)timesec);
// updata_time(timesec);
//state++;
// }
break;
case 10:
uart3_txstr("+++");
Delay_nms(1000);
state++;
break;
case 11:
back = SendCmdAndJudgeSuccess("AT+CIPCLOSE\r\n","OK",1000);
if(back == 1)
state++;
break;
}
}
-- 可能会出现的问题:
-
1、接收的计数值给的单位太小了,而有的AT指令回复的数据量比较大(会回复乱码),导致接收不到数据 ,所以要将单位改大
-
2、出现上传一遍数据之后程序就不执行了
-- 出现问题先调试,看在哪个位置卡死了,如果出现不明显的错误,就要考虑数组的大小和空间的大小,适当增加数组的大小。
-- 这里出现的问题就是buff的错误,buff的大小不够大,导致接收不到数据,所以将buff的大小改大,就可以正常接收数据了
-- 执行效果
-- 执行代码,该设备显示在线,点击该设备,可以看到数据
-- 记得点击实时更新
-- 设备在线后,就可以用云智能APP扫码查看APP
完整代码
- esp.c
#include "esp.h"
#include "string.h"
#include "delay.h"
#include "rtc.h"
#include "dht11.h"
#include "MQTTPacket.h"
//#include "transport.h"
ESP esp ={0};
void esp_init(void)
{
//时钟 B端口 USART3(外设自身也有时钟)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //看数据手册在哪条线上 - APB2
//IO PA9/PA10
GPIO_InitTypeDef GPIO_InitStructure = {0}; //定义结构体变量,并且将结构体变量赋初值
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PA9 复用推挽
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //ESP_EN使能引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_6);//置1
USART_InitTypeDef USART_InitStructure = {0};
USART_InitStructure.USART_BaudRate = 115200; //波特率 常用的是4800 9600 115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位长度
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位长度
USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶校验(这里写不使用)
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制失能(不使用硬件流控制)
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//模式
USART_Init(USART3, &USART_InitStructure);
USART_Cmd(USART3,ENABLE);//开启串口 //使能或者失能 USART 外设(一般外设都要写这个)
//使能中断源 //串口有10个,用哪一个就要开哪一个中断源
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
USART_ITConfig(USART3,USART_IT_IDLE,ENABLE); //空闲中断怎么开
//中断
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; //中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能(使能哪个中断通道,就要写哪个(必须写)中断服务函数)
NVIC_Init(&NVIC_InitStructure);
}
void USART3_IRQHandler(void)//串口收到1字节数据,中断就会被触发一次
{
uint8_t data = 0;
//判断接收中断是否发生
if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
{
//处理中断:保存数据
data = USART_ReceiveData(USART3);
USART_SendData(USART1, data);
esp.rxbuff[esp.rxlen++] = data;
esp.rxlen%=1024; //计数值最大是1024(前面一堆乱码也会存在buff里面,要控制数据)
//清理终端
USART_ClearITPendingBit(USART3,USART_IT_RXNE);
}
if(USART_GetITStatus(USART3, USART_IT_IDLE) == SET)
{
esp.rxflag=1;
//清理空闲中断标志(比较特殊)
data = USART_ReceiveData(USART3);
}
}
//应用函数
//发送
void uart3_tx(uint8_t data)
{
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET){}
USART_SendData(USART3, data);
}
void uart3_txbuff(uint8_t *buff,uint32_t len)
{
for(uint32_t i=0;i<len;i++)
uart3_tx(buff[i]);
}
//发送不定长数组
void uart3_txstr(uint8_t *buff)
{
while( *buff )
{
uart3_tx(*buff);
buff++;
}
}
//判断指令是否发送成功
uint8_t SendCmdAndJudgeSuccess(uint8_t *cmd,uint8_t * ack,uint16_t outtime)//指令和回复的,超时时间(每条指令都有最大的超时时间)
{
//清空缓冲区
memset(esp.rxbuff,0,1024);
esp.rxlen = 0;
esp.rxflag = 0;
//1、发送指令
uart3_txstr(cmd);
//2、判断接收数据中是否有对应的ack
while(outtime--)
{
if(esp.rxflag==1)
{
esp.rxflag=0; //接受两次数据,一次是(前三句话)disconnect会触发,没有OK,然后退出,后面输出ok会再次触发
if(strstr((char *)esp.rxbuff,(char *)ack)!=NULL)//strstr找到返回地址,没找到返回空
return 1;
}
Delay_nms(1);
}
return 0;
}
//要保证能在while循环中运行
uint8_t state = 0;
void wifi_get_time(void)
{
uint8_t back = 0;
switch(state)
{
case 0:
back = SendCmdAndJudgeSuccess("AT\r\n","OK",1000);
if(back == 1)
state++;
break;
case 1:
back = SendCmdAndJudgeSuccess("AT+RST\r\n","OK",2000);
if(back == 1)
state++;
break;
case 2:
back = SendCmdAndJudgeSuccess("AT+CWMODE=1\r\n","OK",1000);
if(back == 1)
state++;
break;
case 3:
back = SendCmdAndJudgeSuccess("AT+CIPMUX=0\r\n","OK",1000);
if(back == 1)
state++;
break;
case 4:
//在flash里面读取wifi信息esp.wifiname,esp.wifipassword,这里没有用flash,先直接赋值
strcpy(esp.wifiname,"111");
strcpy(esp.wifipassword,"pimouren");
memset(esp.txbuff,0,1024);
sprintf(esp.txbuff,"AT+CWJAP=\"%s\",\"%s\"\r\n",esp.wifiname,esp.wifipassword);
back = SendCmdAndJudgeSuccess(esp.txbuff,"OK",10000);
if(back == 1)
state++;
break;
case 5:
memset(esp.txbuff,0,1024);
//sprintf(esp.txbuff,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",TIMEIP,TIMEPORT);
//换成阿里云的IP的端口
sprintf(esp.txbuff,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",MATTHOSTURL,PORT);
back = SendCmdAndJudgeSuccess(esp.txbuff,"OK",10000);
if(back == 1)
state++;
break;
case 6:
back = SendCmdAndJudgeSuccess("AT+CIPMODE=1\r\n","OK",1000);
if(back == 1)
state++;
break;
case 7:
back = SendCmdAndJudgeSuccess("AT+CIPSEND\r\n","OK",1000);
if(back == 1)
state++;
break;
case 8:
// memset(esp.rxbuff,0,1024);
// esp.rxlen = 0;
// esp.rxflag = 0;
// memset(esp.txbuff,0,1024);
// sprintf(esp.txbuff,"%s",GETTIME);
// uart3_txstr(esp.txbuff);
// Delay_nms(1000);
// state++;
mqtt_connect();
state++;
break;
case 9:
mqtt_pub();
// if(esp.rxflag==1)
// {
// esp.rxflag=0;
// uint8_t timebuff[11] = {0};
// char *p = strstr((char *)esp.rxbuff,"time");//strstr找到返回地址,没找到返回空
// if(p!=NULL)
// {
// p+=6;
//
// for(uint8_t i=0;i<10;i++)
// {
// timebuff[i] = *(p+i);
//
// }
// }
// uint32_t timesec = atoi(timebuff);
// printf("time:%s %ld\r\n",timebuff,(long)timesec);
// updata_time(timesec);
//state++;
// }
break;
case 10:
uart3_txstr("+++");
Delay_nms(1000);
state++;
break;
case 11:
back = SendCmdAndJudgeSuccess("AT+CIPCLOSE\r\n","OK",1000);
if(back == 1)
state++;
break;
}
}
//mqtt的连接函数
void mqtt_connect(void)
{
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;//定义了一个结构体,下面对结构体参数赋值
data.keepAliveInterval = 60;//保持连接时间(60s)
data.cleansession = 1;
data.clientID.cstring = CLIENTID;
data.username.cstring = USERNAME;
data.password.cstring = PASSWD;
memset(esp.txbuff,0,1024);
uint32_t len = MQTTSerialize_connect(esp.txbuff, 1024, &data);//返回值就是txbuff的长度
//发送连接报文
uart3_txbuff(esp.txbuff,len);
}
void mqtt_pub(void)
{
//返回值长度
char buff[512] = {0};
sprintf(buff,"{\"id\":1724227172076,\"params\":\
{\"temperature\":20.1,\
\"HCHO\":23,\
\"CO2\":23\
},\"version\":\"1.0\",\
\"method\":\"thing.event.property.post\"}");
MQTTString topicString = MQTTString_initializer;
topicString.cstring = TOPIC_PUB;
memset(esp.txbuff,0,1024);
uint32_t len = MQTTSerialize_publish(esp.txbuff, 1024, 0, 0, 0, 0,topicString, buff, strlen(buff)); //主题名称,负载和负载长度
uart3_txbuff(esp.txbuff,len);
}
- esp.h
#ifndef _ESP_H_
#define _ESP_H_
#include "STM32f10x.h"
void esp_init(void);
void USART3_tx(uint8_t data);
void uart3_txbuff(uint8_t *buff,uint32_t len);
void uart3_txstr(uint8_t *buff);
typedef struct {
uint8_t rxbuff[1024];//接收缓冲区
uint16_t rxlen; //接收计数值
uint8_t rxflag;
uint8_t txbuff[1024];//发送缓冲区
uint8_t txlen; //发送计数值
uint8_t wifiname[20];
uint8_t wifipassword[20];
}ESP;
extern ESP esp;
#define TIMEIP "pinduoduo.com"
#define TIMEPORT 80
#define GETTIME "GET http://api.pinduoduo.com/api/server/_stm\r\n"
void wifi_get_time(void);
uint8_t SendCmdAndJudgeSuccess(uint8_t *cmd,uint8_t * ack,uint16_t outtime);
void AP();
void STA();
void mqtt_pub(void);
void mqtt_connect(void);
//前三个参数是mqtt
#define CLIENTID "a11eYOq0ru1.P6WNlYrtAnbisS3rfMEm|securemode=2,signmethod=hmacsha256,timestamp=1729079936092|"
#define USERNAME "P6WNlYrtAnbisS3rfMEm&a11eYOq0ru1"
#define PASSWD "a4a4e8eec7638bc2c74fc057c5e311051261e38f1a2d1730f32191a475f90011"
#define MATTHOSTURL "a11eYOq0ru1.iot-as-mqtt.cn-shanghai.aliyuncs.com"//阿里云ip地址
#define PORT 1883//端口号
#define TOPIC_PUB "/sys/a11eYOq0ru1/P6WNlYrtAnbisS3rfMEm/thing/event/property/post"
//{"clientId":"a11eYOq0ru1.P6WNlYrtAnbisS3rfMEm|securemode=2,signmethod=hmacsha256,timestamp=1729059510986|",
// "username":"P6WNlYrtAnbisS3rfMEm&a11eYOq0ru1",
// "mqttHostUrl":"a11eYOq0ru1.iot-as-mqtt.cn-shanghai.aliyuncs.com",
//"passwd":"a9d11176d0ff901a8e93b3d2cb1eebc64b665f1dda595d1532a4d2ed6a97366c",
//"port":1883}
#endif
标签:USART,esp,--,back,mqtt,GPIO,服务器
From: https://blog.csdn.net/m0_71813740/article/details/142998083