概述
云平台小项目
- 关于物联网
- 物联网云平台
- MQTT协议
- 使用设备连接到OneNet
- 硬件和软件实现
- 数据可视化
- 使用设备连接到私云
- 需要代码的戳这里:
关于物联网
物联网在最近几年非常的火,尤其是在5G概念席卷整个社会之后,物联网,大数据,人工智能的概念更是成为了人们茶余饭后的谈资。
物联网(Internet of Things,IoT)是指通过信息传感设备,按约定的协议,将任何物体与网络相连接,物体通过信息传播媒介进行信息交换和通信。物联网的目的是实现不受地点、时间限制,长期快速的连接如智能家庭、智慧城市等场景的移动设备。
物联网云平台
在物联网高速发展的时期,物联网设备终端和物联网云平台都得到了大量的投入研发。从根本上说,物联网云平台充当的是网关,也可以充当管理工具,对现场设备进行管理。云平台允许设备端采集的大量数据上传到平台,也能够通过平台发送数据到设备端,是一个双向的通信。基本的功能,如设备管理、OTA远程升级、数据管理等典型功能。
目前,市面上有很多知名的云平台,比如中移物联网OneNet、阿里云、华为云、机智云等。这些云平台都有较为简单的接入方式,并且有大量的资料供我们学习。
MQTT协议
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。
MQTT 协议提供一对多的消息发布,可以降低应用程序的耦合性,用户只需要编写极少量的应用代码就能完成一对多的消息发布与订阅,该协议是基于<客户端-服务器>模型,在协议中主要有三种身份:发布者(Publisher)、服务器(Broker)以及订阅者(Subscriber)。其中,MQTT 消息的发布者和订阅者都是客户端,服务器只是作为一个中转的存在,将发布者发布的消息进行转发给所有订阅该主题的订阅者;发布者可以发布在其权限之内的所有主题,并且消息发布者可以同时是订阅者,实现了生产者与消费者的脱耦,发布的消息可以同时被多个订阅者订阅。
使用设备连接到OneNet
中移物联网OneNet平台,支持多协议接入,还具有多种增值服务。注册认证后,可以免费创建几个产品,对于学生来说,是一个学习物联网十分不错的平台,当然,阿里云,百度云也很不错。
硬件和软件实现
硬件上,我使用的是野火的STM32F103VE指南者和WiFi模组ESP8266,硬件设备上还是比较大众化,便宜又好用,对于ESP8266直接使用AT指令控制就可以了。然后数据采集使用的是一个DHT11温湿度传感器,控制设备使用的是一个继电器。
WiFi模块和STM32通过串口连接,如下所示:
WiFi STM32
RX ------> TX
TX ------> RX
VCC ------> 3v3
GND -----> GND
软件上,使用串口1进行答疑调试,使用串口2来驱动ESP8266 WiFi模块。串口接收使用的是DMA+串口空闲中断来接收数据。具体可以参考我之前写的博客:
DMA+串口空闲中断
我使用的是OneNet的官方文档和资料移植的代码。
1)首先要做的是初始化ESP8266。
.c文件如下
UsartPrintf(USART_DEBUG, "rn1. ATrn");
while(ESP8266_SendCmd(AT, "OK"))
delay_ms(100);
UsartPrintf(USART_DEBUG, "2. CWMODErn");
while(ESP8266_SendCmd(CWMODE, "OK"))
delay_ms(200);
UsartPrintf(USART_DEBUG, "3. 复位模块rn");
while(ESP8266_SendCmd(RST, "OK"))
delay_ms(200);
UsartPrintf(USART_DEBUG, "4. 连接WiFirn");
while(ESP8266_SendCmd(CWJAP, "GOT IP"))
delay_ms(300);
UsartPrintf(USART_DEBUG, "5. 连接TCP服务器rn");
while(ESP8266_SendCmd(CIPSTART, "CONNECT"))
delay_ms(300);
UsartPrintf(USART_DEBUG, "8. ESP8266 初始化成功rn");
.h文件
#define AT "ATrn"
#define CWMODE "AT+CWMODE=3rn" //STA+AP模式
#define CWDHCP "AT+CWDHCP=1,1rn" //STA+AP模式
#define RST "AT+RSTrn"
#define CIFSR "AT+CIFSRrn"
#define CWJAP "AT+CWJAP="你家的WiFi名字","你家的WiFi密码"rn" //ssid: onenet 密码:空
#define CIPSTART "AT+CIPSTART="TCP","183.230.40.39",6002rn" //MQTT服务器 183.230.40.39/876
#define CIPMODE0 "AT+CIPMODE=0rn" //非透传模式
#define CIPMODE1 "AT+CIPMODE=1rn" //透传模式
#define CIPSEND "AT+CIPSENDrn"
#define Out_CIPSEND "+++"
#define CIPSTATUS "AT+CIPSTATUSrn" //网络状态查询
发送了这些AT指令之后,WiFi模组就初始化成功并且成功连接上OneNet的MQTT服务器了。
2)然后连接到OneNet平台
这个函数的作用就是将产品号、鉴权信息、设备ID组包,通过WiFi模组上传到服务器,并对服务器返回的数据进行判断,是否连接到平台。
#define PROID "产品号"
#define AUTH_INFO "鉴权信息"
#define DEVID "设备ID"
_Bool OneNet_DevLink(void)
{
MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包
unsigned char *dataPtr;
_Bool status = 1;
UsartPrintf(USART_DEBUG,"OneNET_DevLinkrn");
UsartPrintf(USART_DEBUG,"PROID: %s, AUIF: %s, DEVID:%srn", PROID, AUTH_INFO, DEVID);
if(MQTT_PacketConnect(PROID, AUTH_INFO, DEVID, 512, 0, MQTT_QOS_LEVEL0, NULL, NULL, 0, &mqttPacket) == 0)
{
ESP8266_SendData(mqttPacket._data, mqttPacket._len); //上传平台
dataPtr = ESP8266_GetIPD(250); //等待平台响应
if(dataPtr != NULL)
{
if(MQTT_UnPacketRecv(dataPtr) == MQTT_PKT_CONNACK)
{
switch(MQTT_UnPacketConnectAck(dataPtr))
{
case 0:UsartPrintf(USART_DEBUG, "Tips: 连接成功rn");status = 0;break;
case 1:UsartPrintf(USART_DEBUG, "WARN: 连接失败:协议错误rn");break;
case 2:UsartPrintf(USART_DEBUG, "WARN: 连接失败:非法的clientidrn");break;
case 3:UsartPrintf(USART_DEBUG, "WARN: 连接失败:服务器失败rn");break;
case 4:UsartPrintf(USART_DEBUG, "WARN: 连接失败:用户名或密码错误rn");break;
case 5:UsartPrintf(USART_DEBUG, "WARN: 连接失败:非法链接(比如token非法)rn");break;
default:UsartPrintf(USART_DEBUG, "ERR: 连接失败:未知错误rn");break;
}
}
}
MQTT_DeleteBuffer(&mqttPacket); //删包
ESP8266_Clear();
}
else
UsartPrintf(USART_DEBUG, "WARN: MQTT_PacketConnect Failedrn");
return status;
}
3)封装上传的数据,我们通过字符串拼接函数把数据封装成cJSON格式的。
unsigned char OneNet_FillBuf(char *buf)//Type3 CJson格式
{
char text[24];
memset(text, 0, sizeof(text));
strcpy(buf, "{");
memset(text, 0, sizeof(text));//将text清零
sprintf(text, ""key":%d,", key);//控制精度并打印到text中
strcat(buf, text);//将字符串text添加到buf结尾处并添加'