1.thingscloud平台简介
ThingsCloud 是一个专注于物联网(IoT)设备连接、管理与应用开发的一站式云平台,旨在为企业和开发者提供高效、灵活且低成本的物联网解决方案,推动传统行业与新兴领域的智能化转型。作为物联网云平台的新标准,ThingsCloud 支持全球超过500亿设备的互联互通,已服务超过5000家大型企业,涵盖从初创公司到世界500强的广泛客户群体,覆盖智能电表、智能家居、工业网关、农业传感器、能源管理等多个领域。
其核心功能围绕设备接入、数据处理、应用开发与系统集成展开。平台支持多种通信协议,包括MQTT、HTTP、TCP、CoAP、LoRa、Zigbee、WiFi、BLE等,兼容不同品牌和类型的物联网设备,实现跨厂商设备的统一接入与管理。设备生命周期管理功能涵盖注册、配置、监控、OTA升级等环节,降低异构系统整合难度。数据采集模块可实时获取传感器数据、状态信息,并通过内置规则引擎支持数据过滤、转换、报警触发等操作,同时对接第三方云服务或本地数据库(如MySQL、InfluxDB),满足复杂场景需求。可视化与监控工具提供拖拽式仪表盘,用户可自定义数据看板,通过图表、地图、控件等形式直观展示设备状态,实时监控与异常告警功能通过邮件、短信、钉钉、企业微信、微信公众号等多渠道通知,确保问题及时响应。低代码开发环境则通过API和SDK支持快速应用开发,集成企业现有系统(如ERP、CRM)或构建新业务逻辑,显著缩短项目交付周期。
平台的技术架构采用分层设计,涵盖设备、数据、应用等核心要素。设备层通过统一接入协议与全球接入点,支持公有区、专有区、私有区等多种部署方式,确保海量设备的高并发连接与数据互通。数据层提供时序数据库与历史数据分析功能,支持10余种聚合算法,挖掘数据价值并导出分析结果。应用层通过零代码开发工具生成项目SaaS与用户App,公版ThingsX App支持iOS、Android、微信小程序、WebApp等多平台,定制App可绑定独立域名、设置品牌视觉元素,并内置用户账号体系与设备认领功能。此外,ThingsCloud 提供完善的设备地图、SQL查询、扩展信息维护、OTA固件升级等辅助功能,进一步增强设备管理能力。
2.thingscloud云配置
1.注册账号登录平台。thingscloud地址

进入控制台,创建项目

创建项目


2.创建设备



3.创建设备类型


4.关联设备

5.添加功能


6.创建用户

7.创建用户应用



8.配置应用UI


9.接入平台

10.数据上报与下发

3.安信可AI-WB2-12F应用

处理器搭载BL602芯片,内置低功耗32位RISC CPU,配备276KB RAM,支持复杂运算与多任务处理。支持802.11b/g/n协议,最高速率72.2Mbps,兼容20MHz带宽。支持BLE 5.0与Bluetooth Mesh,实现低功耗短距离通信。
安全性能上支持WPS/WEP/WPA/WPA2 Personal/WPA3安全协议,保障数据传输安全。内置安全启动功能,支持ECC-256签名镜像验证,防止固件篡改。
提供AES 128/192/256位加密引擎与SHA-1/224/256哈希算法,强化数据加密能力。
Wi-Fi接收灵敏度:-98dBm(11b模式,1Mbps速率),确保弱信号环境下的稳定连接。BLE输出功率:1Mbps速率下典型值9dBm,支持远距离通信。
支持AT指令集开发,串口通讯方式,帧格式为:115200、8、N、1
3.1 WIFI模式配置AT指令集
AI-WB2-12F可通过AT指令解析WIFI工作模式配置,相关指令如下:
c
"AT\r\n",
"AT+WMODE=1,1\r\n",//设置STA模式,并保存到FLSH
"AT+WSDHCP?\r\n",//查询STA模式下参数信息
"AT+WJAP=nfj_wifi,asdfghjkl\r\n", //-->WIFI名和密码"
"AT+STAINFO?\r\n",//查询连接信息
"AT+WAUTOCONN=1,nfj_wifi,asdfghjkl\r\n",//保存wifi信息,上电自动重连
"AT+SOCKET=4,192.168.43.5,8080\r\n",//连接服务器
"AT+SOCKETTT\r\n",//进入透传
3.2 指令发送函数设计
为便于相关指令发送,并保证指令发送成功,设计指令发送函数如下:
c
/*
WIFI发送命令,检查命令返状态信息
形参:
cmd --要发送的命令
stat --命令的返回状态
返回值:0--成功,其它值--失败
*/
static u8 ESP8266_SendCmd(const char *cmd,const char *stat)
{
u8 i=0;
u16 j=0;
for(i=0;i<3;i++)
{
usart3_cnt=0;
usart3_flag=0;
USARTx_SendStr(USART3,(u8*)cmd);//发送命令
for(j=0;j<5000;j++)
{
if(usart3_flag)
{
usart3_buffer[usart3_cnt]='\0';
if(strstr((char *)usart3_buffer,stat))
{
usart3_cnt=0;
usart3_flag=0;
return 0;//发送成功
}
else
{
usart3_cnt=0;
usart3_flag=0;
//memset(usart3_buffer,sizeof(usart3_buffer),0);
}
}
Delay_Ms(1);
}
Delay_Ms(100);
}
return 1;//命令发送失败
}
为保证指令成功率,采用循环发送方式,若多次发送仍不成功,则直接返回1。
3.3 配置WIFI工作模式为STA
封装函数,设置WIFI工作模式为STA。
c
/*
STA模式TCP_Clinet初始化
形参:wifi_name --wifi名字
wifi_key --wifi密码
server_ip --服务器ip
port --服务器端口号
//保存发出的指令
const char *wifi_cmd[]={
"AT\r\n",
"AT+WMODE=1,1\r\n",//设置STA模式,并保存到FLSH
"AT+WSDHCP?\r\n",//查询STA模式下参数信息
"AT+WJAP=nfj_wifi,asdfghjkl\r\n", //-->WIFI名和密码"
"AT+STAINFO?\r\n",//查询连接信息
"AT+WAUTOCONN=1,nfj_wifi,asdfghjkl\r\n",//保存wifi信息,上电自动重连
"AT+SOCKET=4,192.168.43.5,8080\r\n",//连接服务器
"AT+SOCKETTT\r\n",//进入透传
};
*/
u8 ESP8266_STA_Init(const char *wifi_name,const char *wifi_key)
{
//1.退出透传模式
int i=0;
for(i=0;i<3;i++)
{
if(ESP8266_SendCmd("AT\r\n","OK\r\n")==0)
{
i=0;
break;
}
printf("第%d次退出透传\r\n",i+1);
USARTx_SendStr(USART3,(u8 *)"+++\r\n");//退出透传模式
Delay_Ms(500);
}
if(i>=3)return 1;//退出透传失败
char buffer[100];
printf("2.关回显ATE0\r\n");
if(ESP8266_SendCmd("ATE0\r\n","OK"))return 2;
printf("3.查询WIF自动连接:\r\n");
if(ESP8266_SendCmd("AT+WAUTOCONN?\r\n","+WAUTOCONN")==0){
printf("rx3=%s\n",usart3_buffer);
if(strstr((char *)usart3_buffer,"+WAUTOCONN:0")){
printf("3.1 设置WIFI自动重连:\r\n");
snprintf(buffer,sizeof(buffer),"AT+WAUTOCONN=1,%s,%s\r\n",wifi_name,wifi_key);
if(ESP8266_SendCmd(buffer,"OK\r\n"))return 3;
printf("3.2重启WIFI模块\r\n");
if(ESP8266_SendCmd("AT+RST\r\n","ready"))return 4;
}
}
printf("等待WIFI连接成功\r\n");
if(ESP8266_WaitConnect()){
printf("4.查询连接WIFI信息:\r\n");
u8 ret=ESP8266_CheckStaInfo();
if(ret==0 || ret==4){//wifi信息错误
printf("ret=%d\n",ret);
printf("4.1 关闭WIFI自动重连:\r\n");
//snprintf(buffer,sizeof(buffer),"AT+WAUTOCONN=1,%s,%s\r\n",wifi_name,wifi_key);
if(ESP8266_SendCmd("AT+WAUTOCONN=0\r\n","OK\r\n"))return 3;
printf("3.2重启WIFI模块\r\n");
if(ESP8266_SendCmd("AT+RST\r\n","ready"))return 4;
//-->设置WIFI模式为STA并保存到flash
printf("4.1设置WIFI为STA模式\r\n");
if(ESP8266_SendCmd("AT+WMODE=1,1\r\n","OK\r\n"))return 5;//连接WIFI失败
//设置WIFI连接 AT+WJAP=wbyq_wifi,12345678\r\n //-->WIFI名和密码
printf("4.2 设置WIFI连信息\r\n");
snprintf(buffer,sizeof(buffer),"AT+WJAP=%s,%s\r\n",wifi_name,wifi_key);
printf("buffer=%s",buffer);
if(ESP8266_SendCmd(buffer,"WIFI_GOT_IP")){
printf("err=%s\n",usart3_buffer);
return 6;
}//连接WIFI失败
}
}
return 0;
}
4.MQTT接入hingscloud云
4.1 配置MQTT指令
AI-WB2-12F模组支持MQTT指令集,相关MQTT配置指令如下:
c
AT+MQTT MQTT 的配置和连接
AT+MQTT=1,192.168.202.10 //设置域名
OK
#AT+MQTT=2,1883 //设置端口号
OK
#AT+MQTT=3,1 //设置连接方式
OK
#AT+MQTT=4,client_id //设置用户 ID
OK
#AT+MQTT=5,admin //设置 MQTT 用户名
OK
#AT+MQTT=6,public //设置 MQTT 密码
OK
#AT+MQTT? //查询 MQTT 连接和配置情况
+MQTT:0,192.168.202.10,1883,1,client_id,admin,public
OK
#AT+MQTT //连接 MQTT
OK
#
+EVENT:MQTT_CONNECT //MQTT 连接成功
封装MQTT配置函数如下:
c
/*
MQTT连接物联网平台
*/
u8 MQTT_Config(const char *ip,u16 port,const char *client_id,const char *user_name,const char *password)
{
char buffer[200];
//断开连接
ESP8266_SendCmd("AT+MQTTDISCONN\r\n","OK\r\n");
//1.设置心跳间隔
//if(ESP8266_SendCmd("AT+MQTTKEEPALIVE=120,10\r\n","OK\r\n"))return 1;
//1.设置域名
snprintf(buffer,sizeof(buffer),"AT+MQTT=1,%s\r\n",ip);
if(ESP8266_SendCmd(buffer,"OK\r\n"))return 2;
//2.设置端口号
snprintf(buffer,sizeof(buffer),"AT+MQTT=2,%d\r\n",port);
if(ESP8266_SendCmd(buffer,"OK\r\n"))return 3;
//3.设置连接方式1为TCP、2为SSL
if(ESP8266_SendCmd("AT+MQTT=3,1\r\n","OK\r\n"))return 4;
//4.设置用户ID
snprintf(buffer,sizeof(buffer),"AT+MQTT=4,%s\r\n",client_id);
printf("设置客户端id:%s,len=%d\n",buffer,strlen(buffer));
if(ESP8266_SendCmd(buffer,"OK\r\n"))return 5;
//5.设置用户名
snprintf(buffer,sizeof(buffer),"AT+MQTT=5,%s\r\n",user_name);
if(ESP8266_SendCmd(buffer,"OK\r\n"))return 6;
//6.设置密码
snprintf(buffer,sizeof(buffer),"AT+MQTT=6,%s\r\n",password);
if(ESP8266_SendCmd(buffer,"OK\r\n"))return 7;
//7.MQTT接入
snprintf(buffer,sizeof(buffer),"AT+MQTT\r\n");
if(ESP8266_SendCmd(buffer,"MQTT_CONNECT")){
printf("rx3=%s\n",usart3_buffer);
return 8;
}
return 0;
}
4.2 消息订阅
消息订阅指令:
AT+MQTTSUB?
描述:查询已经订阅的主题和主题状态
响应 <status>,<Topic>
...
OK
//状态描述
status:订阅状态
0:初始化状态
1:订阅中(首次订阅)
2:订阅中(断线重连后重新订阅)
3:订阅成功
Topic:订阅的主题
AT+MQTTSUB=<topic>,<qos>
描述:订阅主题
参数 topic:要订阅的主题
qos:qos 等级(0,1,2)
响应 OK
示例 AT+MQTTSUB=testtopic0,0
OK
HELP 中的描述信息
响应 Subscribe MQTT Topic
注释 可以订阅的主题条数默认最多为 5 条,每条订阅大概消耗 100 字节内存。
函数实现如下:
c
/*消息订阅
形参:topic --要订阅的topic
qos --消息质量等级,0,1,2
flag --1为订阅,0为取消订阅
返回值:成功返回0,失败返回其他值
*/
u8 MQTT_SubTopic(const char *topic,int qos,int flag)
{
char buffer[200];
if(flag)
snprintf(buffer,sizeof(buffer),"AT+MQTTSUB=%s,%d\r\n",topic,qos);
else //取消订阅
snprintf(buffer,sizeof(buffer),"AT+MQTTUNSUB=%s\r\n",topic);
if(ESP8266_SendCmd(buffer,"OK"))return 1;
return 0;
}
4.2 消息发布
消息发布指令:
AT+MQTTPUBRAW=<topic>,<qos>,<Retained>,<length>
描述:发布 MQTT 消息
参数 topic:要发布的主题
qos:qos 等级(0,1,2)
Retained:是否为 Retained 消息 0 表示普通消息 1 表示 Retained 消息
length:要发送的数据长度
响应:OK
示例 AT+MQTTPUBRAW=testtopic,1,0,10 //向 testtopic 发送 10 字节的数据
> //收到这个字符之后开始输入要发送的数据
OK //当收到 10 字节数据后就会发送数据(可以是任意数据),发送完成会显示 OK
HELP 中的描述信息
响应 :Publish long MQTT message
函数实现如下:
c
/*发布内容*/
u8 MQTT_PublishMesg(const char *topic,int qos,const char *msg)
{
char buffer[512];
int len=strlen(msg);
//AT+MQTTPUBRAW=<topic>,<qos>,<Retained>,<length>
snprintf(buffer,sizeof(buffer),"AT+MQTTPUBRAW=%s,%d,0,%d\r\n",topic,qos,len);
if(ESP8266_SendCmd(buffer,">"))return 1;
if(ESP8266_SendCmd(msg,"OK"))return 2;
return 0;
}
5.主体函数
本案例运行流程如下:
- 初始硬件,如串口、RTC、OLED屏幕等;
- 配置WIFI模式为STA,连接wifi热点;
- 通过HTTP实现网络时间校准;
- 通过MQTT接入事物云平台;
- 实现数据订阅
- 实时上报数据
代码示例如下:
c
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "usart1.h"
#include "timer.h"
#include "esp8266.h"
#include "oled.h"
#include "rtc.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define WIFI_NAME "nfj_wifi"
#define PASSWORD "asdfghjkl"
#define SERVER_IP "sh-3-mqtt.iot-api.com"//服务器IP
#define SERVER_PORT 1883 //端口号
//客户端ID:随便填写
#define ClientID "smart_home"
//用户名和密码可使用密码生成工具完成
#define Username "bi3g04ioqcadc9wz"
#define Password "qyJfsdfsLChMuT"//密文
#define SET_TOPIC "attributes/push"//订阅
#define POST_TOPIC "attributes"//发布
u8 g_rtcflag=0;
/******************解析 天气数据****************
形参:u8* buff原始数据
u8 *Weather_stat天气数据标志
u8 *data解析获取到的数据
返回值:0---成功,其他值---失败
************************************************/
u8 Weather_analysis(u8* buff,u8 *Weather_stat,u8 *data)
{
char *p=NULL;
u16 i=0;
p=strstr((char *)buff,(char *)Weather_stat);//获取温度
if(p)
{
p+=strlen((char *)Weather_stat)+2;
i=0;
while(*p!='\"' && *p!='\0')
{
data[i++]=*p++;
}
data[i]='\0';
return 0;
}
else return 1;
}
int main()
{
LED_Init();//LED
Key_Init();
USARTx_Init(USART1,115200);//一个字符的收发时间:1s/(115200/10)=86us
USARTx_Init(USART2,115200);
USARTx_Init(USART3,115200);
OLED_Init();
OLED_DispalyFont(16,40,16,font_16[4]);
OLED_DispalyFont(16+16,40,16,font_16[5]);
OLED_DisplayStr(16+32,40,16,"|");
OLED_DispalyFont(16+40,40,16,font_16[6]);
OLED_DisplayStr(16+56,40,16,"|");
OLED_DisplayStr(16+64,40,16,"10");
OLED_DispalyFont(16+80,40,16,font_16[7]);
OLED_Refresh();
RTC_Init();
g_rtcflag=1;
u8 ret=1;
while(ret)
{
ret=ESP8266_STA_Init(WIFI_NAME,PASSWORD);
printf("ret=%d\n",ret);
if(ret==0)break;
USARTx_SendStr(USART3,"AT+RST\r\n");
Delay_Ms(2000);
}
// https://sapi.k780.com/
//AT+HTTPCLIENTLINE=2,2,,sapi.k780.com,,,?app=life.time&appkey=25273&sign=eae95a712a66e7a97dfd39534e24ffb1&format=json\r\n
//网络校时
USARTx_SendStr(USART3,(u8*)"AT+HTTPCLIENTLINE=2,2,,sapi.k780.com,,,?app=life.time&appkey=25273&sign=eae95a712a66e7a97dfd39534e24ffb1&format=json\r\n");
u16 time2=0;
while(1)
{
if(usart3_flag)
{
usart3_buffer[usart3_cnt]='\0';
/*
返回的数据格式:JSon
rx3={"success":"1",
"result":{
"timestamp":"1727487843", -->1970/1/1 0:0:0
"timestamp_ms":"1727487843658",
"datetime_1":"2024-09-28 09:44:03",
"datetime_2":"2024骞?9??28??09??4??03绉?",
"week_1":"6","week_2":"??????,"week_3":"?ㄥ??,"week_4":"Saturday"}}
解析内容:"timestamp":"1727487843", --当前秒单位时间
需要自行实现:将秒时间转化为:年月日时分秒
*/
printf("rx3=%s\r\n",usart3_buffer);
char data[30];
if(Weather_analysis(usart3_buffer,"\"timestamp\"",(u8*)data))
{
printf("获取网络时间失败\r\n");
break;
}
printf("data=%s\n",data);
u32 time_sec=atoi(data)+8*60*60;
//将秒时间写入到RTC计数器中
//3.配置RTC寄存器
RTC->CRH&=~(1<<0);//关闭秒中断
u8 stat=0;
while(!(RTC->CRL&1<<5))//等待上一次写操作完成
{
stat++;
Delay_Ms(1);
if(stat>=255)break;
}
if(stat>=255)
{
printf("RTC初始化失败,无法进入配置模式\r\n");
}
RTC->CRL|=1<<4;//进入配置模式
//写入秒时间
RTC->CNTH=(time_sec>>16);//写入高16位
RTC->CNTL=time_sec;//写入低16位
//退出配置模式
RTC->CRL&=~(1<<4);//清除配置模式
stat=0;
while(!(RTC->CRL&1<<5))//等待写操作完成
{
stat++;
Delay_Ms(1);
if(stat>=255)
{
printf("RTC初始化失败,退出配置模式失败\r\n");
}
}
RTC->CRH|=1<<0;//开启秒中断
STM32_SetNVICPriority(3,3,RTC_IRQn);//设置优先级
usart3_cnt=0;
usart3_flag=0;
break;
}
time2++;
Delay_Ms(1);
if(time2>=65535){
time2=0;
break;
}
}
printf("时间校准完成\r\n");
ret=1;
while(ret)
{
ret=MQTT_Config(SERVER_IP,SERVER_PORT,ClientID,Username,Password);
printf("连接:ret=%d\n",ret);
if(ret==0)break;
Delay_Ms(3000);
}
ret=MQTT_SubTopic(SET_TOPIC,0,1);//消息订阅
printf("消息订阅ret=%d\n",ret);
u32 time=0;
time2=5000;
char mqtt_message[256];
float temp=26;
int light=300;
while(1)
{
time++;
time2++;
Delay_Ms(1);
if(time2>=5000)
{
time2=0;
temp+=1.5;
light+=5;
sprintf(mqtt_message,"{\"temperature\":%.1f,\"luminosity\":%d}",temp,light);//温度
ret=MQTT_PublishMesg(POST_TOPIC,0,mqtt_message);
printf("消息发布ret=%d\n",ret);
}
if(usart3_flag)
{
usart3_buffer[usart3_cnt]='\0';
printf("rx3=%s\n",usart3_buffer);
//rx3=+EVENT:MQTT_SUB,attributes/push,20,{"alarm_state":true}
if(strstr((char *)usart3_buffer,"\"state\":true"))
{
LED1=0;
printf("开灯\n");
}
else if(strstr((char *)usart3_buffer,"\"state\":false"))
{
LED1=1;
printf("关灯\n");
}
usart3_cnt=0;
usart3_flag=0;
}
if(usart1_flag)
{
usart1_buffer[usart1_cnt]='\0';
printf("rx1=%s",usart1_buffer);
USARTx_SendStr(USART3,usart1_buffer);
usart1_cnt=0;
usart1_flag=0;
}
}
}
5.1 运行效果:
1.系统调试信息,WIFI模式配置和时间校准;

2.MQTT协议接入云平台和数据订阅、数据发布。


