文章背景:旨在完成毕设,本来准备使用STM32f4最小系统+ESP8266模块+MQTT协议实现设备上云,但是移植MQTT协议库对我来讲在程序没有调通之前感觉一切都是疑点,在那卡了很久决定先把程序调通再由浅入深,于是转变为烧MTQQ固件使用指令的方式来连接阿里云物联网平台。
关键的关键词:ESP8266,MQTT,Topic,Json
摘要:以esp8266模块为媒介实现单片机数据和阿里云物联网平台进行数据的交换
参考网站:https://docs.ai-thinker.com (安信可)
https://blog.csdn.net/espressif/article/details/101713780 (CSDN乐鑫科技)
https://blog.csdn.net/espressif/article/details/107367189 (CSDN乐鑫科技)
https://blog.csdn.net/Boantong_/article/details/104791452(CSDN安信可)
连接协议:MQTT协议
硬件:ESP8266模块,stm32f4最小系统,ST-Link,面包板,杜邦线
软件平台:阿里云物联网平台
阿里云物联网平台——云平台
学习过程中间遇到很多坑,和技术上的不足,本文大概讲述一下整体路线,尽量还原学习过程,主要记录指令和阿里云连接和通讯
//…………………………………技术正文……………………………………//
(通过MQTT固件,暂未使用MQTT库)
刚开始先可以先不使用模块连接阿里云,1.先学习MQTT.fx和云平台之间进行通讯这个过程主要是了解云平台,熟悉云平台的一些操作,需要什么信息才能连接到自己的设备。2.然后使用串口工具为了把第一阶段得到的数据通过一定的发送顺序连接上模块体验这个连接的过程和3.再用模块进行通讯有了前两步的经验可以快速写出自己想要数据的代码,这一过程看的是细心,串口调试的数据可以直接使用但是要把AT指令转换为字符发送出去。程序代码通讯和模块指令差不多,不过是一些转义字符容易出错,先用串口工具进行调试,调试完成之后转到代码中(涉及到指针使用,转义字符的理解)
1.MQTT.fx (熟悉云平台要什么数据)
2.ESP模块+串口工具 (熟悉怎么给云平台数据)
3.ESP模块+stm32单片机 (重点)
首先创建一个设备获取三元素组是基本(点击设备->查看,获取设备证书,点击一键复制)
找到我资源包里面的开发小工具,生成自己需要的信息
串口指令先使用串口跟阿里云通讯,然后移植到代码当中
//功能:设备上线,六步上云
AT+RST
AT+CWMODE=1
AT+CIPSNTPCFG=1,8,"ntp1.aliyun.com" //a里云端时域和 SNTP 服务器
AT+CWJAP="路由账号","路由密码"
//官方:
//AT+MQTTUSERCFG=,,<"client_id">,<"username">,<"password">,,,<"path">
//自己(找到之前使用小工具生成的Username Password)
AT+MQTTUSERCFG=0,1,"NULL","DeviceName&ProductKey","Password",0,0,""
AT+MQTTCLIENTID=0,"DeviceName|securemode=3\,signmethod=hmacsha1|" //坑 注意第二个参数后面的每一个,前面都要要加\ 例如:t|securemode=3\,signmethod=hmacsha1\,
AT+MQTTCONN=0,"ProductKey.iot-as-mqtt.cn-shanghai.aliyuncs.com",1883,1
//功能:订阅发布Topic,数据收发
//官方 AT+MQTTSUB=,<"topic">,
//自定义订阅Topic(数据下发至硬件)
AT+MQTTSUB=0,"/gcuvGKgCsUL/${deviceName}/user/get",1 //在设备Topic列表里面就可以发送数据,单片机就能收到
//发布Topic(数据上发到云端)
AT+MQTTSUB=0,"/sys/gcuvGKgCsUL/${deviceName}/thing/event/property/post",1 //${deviceName}一定换成自己的DeviceName
//连接发布Topic之后就可以通过上发数据进行数据传输
//官方 AT+MQTTPUB=,<"topic">,<"data">,,
//自己发布数据
AT+MQTTPUB=0,"topic","data_Json",1,0 //简化的Json格式数据 {\"params\":{\"设备功能标识符\":66.6}}
//简单一览Json格式
{
"id": "12345",
"version": "1.0",
"params": {
"CurrentTemperature": 21,"CurrentHumidity":50.5,"SocketSwitch_1":1,"SocketSwitch_2":1},
"method": "thing.event.property.post"
}
关联的web界面,(阿里云要是只做到数据交换也就太low了,可以把收到的数据用界面展出才是最棒的)
这个里面我遇到一个大坑,希望大家别入坑:
上面使用的都是串口进行模块上云和模块与云端进行的数据交换,然后我们最终还是要使用MCU进行控制的,但是MCU进行控制的时候数据格式会略有变化,主要是转义字符的带来的。
/" = " (重要)
// = / (重要)
/,=,
坑:来自Json格式的数据 比如我需要一个{“params”:{“CurrentHumidity”:21.5}}我在代码里面应该怎么表示呢?
错误:{\“params\”:{\“CurrentHumidity\”:21.5}} // 认为\等于\然后\“等于” 可是\等于\ “才等于”
正确:{\“params\”:{\“CurrentHumidity\”:21.5}} //看似很简单不过一旦转进去就得卡好一段时间迷不过来
wifi通过串口怎么发送和接收不再展示,仅仅展示数据的收发格式
void Connect_alicloud(void)
{
u8 key=0;
char *m;
m=mymalloc(SRAMIN,64); //申请64字节内存
printf("设置a里云端时域和 SNTP 服务器\r\n");
sprintf((char*)m,"AT+CIPSNTPCFG=1,8,\"%s\"",aliyun_time);
atk_8266_send_cmd(m,"OK",20);
printf("正在连接路由器\r\n");
//设置连接到的WIFI网络名称/加密方式/密码,这几个参数需要根据您自己的路由器设置进行修改!!
sprintf((char*)m,"AT+CWJAP=\"%s\",\"%s\"",wifista_ssid,wifista_password);//设置无线参数:ssid,密码
while(atk_8266_send_cmd(m,"WIFI GOT IP",300)); //连接目标路由器
PRESTA:
printf("正在连接a里云\r\n");
sprintf((char*)m,"AT+MQTTUSERCFG=0,1,\"NULL\",\"%s&%s\",\"%s\",0,0,\"\"",DeviceName,ProductKey,Password);
delay_ms(20);
while(atk_8266_send_cmd(m,"OK",200))
{
printf("账号密码输入错误\r\n"); //
printf("输入按键WK_UP开启重新连接\r\n");
key=Key_Scanf(0);
if(key==1)goto PRESTA;
}
printf("账号密码输入正确\r\n");
sprintf((char*)m,"AT+MQTTCLIENTID=0,\"%s|securemode=3\\,signmethod=hmacsha1|\"",Client_ld);
while(atk_8266_send_cmd(m,"OK",200))
{
printf("远端错误\r\n"); //
printf("输入按键WK_UP开启重新连接\r\n");
key=Key_Scanf(0);
if(key==1)goto PRESTA;
}
printf("远端配置正确\r\n");
sprintf((char*)m,"AT+MQTTCONN=0,\"%s.iot-as-mqtt.cn-shanghai.aliyuncs.com\",1883,1",ProductKey);
while(atk_8266_send_cmd(m,"OK",200))
{
printf("a里云连接错误\r\n"); //
printf("输入按键WK_UP开启重新连接\r\n");
key=Key_Scanf(0);
if(key==1)goto PRESTA;
}
printf("恭喜你已经连接到a里云服务器\r\n");
printf("设备订阅Topic\r\n");//AT+MQTTSUB=0,"",1
sprintf((char*)m,"AT+MQTTSUB=0,\"%s\",1",Topic_myself_get); //自定义订阅Topic
atk_8266_send_cmd(m,"OK",200);
sprintf((char*)m,"AT+MQTTSUB=0,\"%s\",1",Topic_Physical_get);//物模型属性订阅Topic
while(atk_8266_send_cmd(m,"OK",200))
{
printf("设备订阅Topic错误\r\n");
printf("输入按键WK_UP开启重新连接\r\n");
key=Key_Scanf(0);
if(key==1)goto PRESTA;
}
printf("设备订阅Topic成功\r\n");
printf("设备物模型属性发布Topic\r\n");//AT+MQTTSUB=0,"",1
sprintf((char*)m,"AT+MQTTSUB=0,\"%s\",1",Topic_Physical_post); //物模型属性发布Topic
while(atk_8266_send_cmd(m,"OK",200))
{
printf("设备物模型属性发布Topic错误\r\n");
printf("输入按键WK_UP开启重新连接\r\n");
key=Key_Scanf(0);
if(key==1)goto PRESTA;
}
printf("设备物模型属性发布Topic成功\r\n");
//当初大坑就在这,试了很多格式一直以为是自己的格式问题,仅供参考
// sprintf((char*)m,"AT+MQTTPUB=0,\"%s\",\"{\"id\":\"12345\",\"version\":\"1.0\",\"params\":{\"CurrentTemperature\":66,\"CurrentHumidity\":88.5,\"SocketSwitch_1\":1,\"SocketSwitch_2\":1},\"method\":\"thing.event.property.post\"}\",1,0",Topic_Physical_post); //物模型属性发布Topic
//AT+MQTTPUB=0,"%s","{\"params\":{\"CurrentTemperature\":15\,\"CurrentHumidity\":11.5}}",1,0
//\"AT+MQTTPUB=0,\"/sys/gcuvGKgCsUL/&DeviceName/thing/event/property/post\",\"{\"params\":{\"CurrentTemperature\":15}}\",1,0\"
// sprintf((char*)m,"AT+MQTTPUB=0,\"%s\",\"{\"params\":{\"CurrentTemperature\":45\\,\"CurrentHumidity\":41.5}}\",1,0",Topic_Physical_post);
// sprintf((char*)m,"AT+MQTTPUB=0,\"/sys/gcuvGKgCsUL/&DeviceName/thing/event/property/post\",\"{\"params\":{\"CurrentHumidity\":21.5}}\",1,0"); //物模型属性发布Topic
// sprintf((char*)m,"AT+MQTTPUB=0,\"/sys/gcuvGKgCsUL/&DeviceName/thing/event/property/post\",\"{\\\"params\\\":{\\\"CurrentTemperature\\\":95}}\",1,0"); //物模型属性发布Topic
sprintf((char*)m,"AT+MQTTPUB=0,\"%s\",\"{\\\"params\\\":{\\\"CurrentTemperature\\\":95}}\",1,0",Topic_Physical_post); //物模型属性发布Topic
printf("%s\r\n",m);
while(atk_8266_send_cmd(m,"OK",400))
{
printf("向云端发布数据错误\r\n");
printf("输入按键WK_UP开启重新连接\r\n");
key=Key_Scanf(0);
if(key==1)goto PRESTA;
}
printf("向云端发布数据成功\r\n");
myfree(SRAMIN,m); //释放内存
m=NULL; //避免成为野指针
}
使用固件上云和数据交换很简单,只要不入坑,很快就搞出来了。不过还是建议大家学会这个之后,要继续学习通过移植MQTT库和Json库来实现这个功能。
本文意在让大家少走弯路,也可以总结一下自己的的零碎知识,增加自己的语言描述能力,如文章有错误,还望能慷慨指出、一起交流。