湖畔科技 发表于 2019-6-6 11:24:48

NB-IoT模块 移远BC35全网通接入OneNET平台MQTT协议实现数据传输

NB-IoT模块 移远BC35全网通接入OneNET平台MQTT协议实现数据传输
网上很多NB-IOT模块的资料都是使用LWM2M、COAP协议去连接onenet平台
因为现在很多的NB-IOT模块都支持TCP协议,因此就想使用TCP协议然后转MQTT协议连接onenet平台,经过试验证明是可以的。
首先我们先分析一下如何登陆接入Onenet平台。


先从它数据格式开始分析。首先我们要从后台取出三个信息,我们以这个为例。
鉴权信息:test(具体的看你设置的)设备ID:123456789 产品ID:789123(具体是什么看你自己的设备)
MQTT接入都是发十六进制的数据。
那么我们发送的时候就是这样子的一串数据
0x10 0x24 0x00 0x04 0x4D 0x51 0x54 0x54 0x04 0xC0 0x00 0x78 0x00 0x09 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x00 0x07 0x37 0x38 0x39 0x31 0x32 0x33 0x20 0x00 0x04 0x74 0x65 0x73 0x74

<p>[ 0x10 ] // MQTT类型=1 DupFlag=0 QosLevel=0 Retain=0
[ 0x22 ] // remainedLength=34以下的数据长度0x00 04......0x74 0x65 0x73 0x74这个之间的长度,您可以数一下看看</p><p>[ 0x00 0x04 ] // protocolNameLength=4 这是发固定的MQTT这4个字母,长度为4.但是需要两个字节保存长度
[ 0x4D 0x51 0x54 0x54 ] // protocolName=MQTT
[ 0x04 ] // protocolLevel=4固定的一种类型
[ 0xC0 ] // userFlag=1 passwordFlag=1 willFlag=0 willRetainFlag=0 willQosFlag=0 clenSessionFlag=0 clenSessionFlag=0固定的一种类型
[ 0x00 0x78 ] // keepAlive=120这是保持连接的时间为120S</p><p>[ 0x00 0x08] // clientIdentifierLen=8 这是设备ID的长度 用两个字节记录
[ 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 ] // clientIdentifier=12345678 设备ID
[ 0x00 0x06 ] // userNameLen=6 这是产品ID的长度 用两个字节记录
[ 0x37 0x38 0x39 0x31 0x32 0x33] // userName=789123
[ 0x00 0x04 ] // userPasswordLen=4 这是鉴权信息的长度 用两个字节记录
[ 0x74 0x65 0x73 0x74 ] // userPassword=test</p>

这里面有个坑,长度的十六进制是十进制转换为十六进制。而“MQTT” ,test(具体的看你设置的)设备ID:123456789 产品ID:789123 这些信息都是字符串转十六进制
下面我们直接上指令

<p>AT
OK
AT+NRB//重启模块的指令,在单片机里面最好进行重启一下
AT+CMEE=1
OK
AT+CGSN=1
+CGSN:867725030027605
OK
AT+NBAND?
+NBAND:8 //移动的返回+NBAND:8,电信的返回+NBAND:5</p><p>OK
AT+NBAND=8 //设置为移动的,电信的指令为AT+NBAND=5
OK
AT+CIMI //查询卡号
460042437100213
OK
AT+CSQ //查询信号指令,如果返回+CSQ:99,99 说明还没有信号
+CSQ:29,99
OK
AT+NSOCR=STREAM,6,56000,1 //做TCP socket创建准备
AT+NSOCO=1,183.230.40.33,6002//连接服务器。6002为服务器端口号
OK</p>
注意:NB发送数据的时候数据内容需要转换为十六进制。大家可以使用在线转换工具
发送数据的指令为:AT+NSOSD=1,发送内容的长度,内容。//注意长度不可以多或者少

<p>AT+NSOSD=1,36,102200044D51545404C00078000831323334353637380006373839313233000474657374OK
+NSONMI:1,4//这是服务器返回来的数据。
AT+NSORF=1,4//查询接收内容的指令203是需要查询的长度。可以多,
1,183.230.40.33,80,203,20200000,0</p><p>
</p><p>
</p><p>OK </p><p>
</p><p>
</p>
这个时候已经连接上服务器了,那么现在就发送数据,原始数据如下

{"datastreams":[{"id":"temp","datapoints":[{"value":50}]}]}
但是需要增加一些数据头之类的格式

<div>这是转换后的数据</div><div>0x30 0x43 0x00 0x03 0x24 0x64 0x70 0x01 0x00 0x3B 0x7B 0x22 0x64 0x61 0x74 0x61 0x73 0x74 0x72 0x65 0x61 0x6D 0x73 0x22 0x3A 0x5B 0x7B 0x22 0x69 0x64 0x22 0x3A 0x22 0x74 0x65 0x6D 0x70 0x22 0x2C 0x22 0x64 0x61 0x74 0x61 0x70 0x6F 0x69 0x6E 0x74 0x73 0x22 0x3A 0x5B 0x7B 0x22 0x76 0x61 0x6C 0x75 0x65 0x22 0x3A 0x35 0x30 0x7D 0x5D 0x7D 0x5D 0x7D</div><div>
</div><div>各个数据的含义[ 0x30 ]   // MQTT类型=3DupFlag=0 QosLevel=0 Retain=0选用类型为3[ 0x43 ]   // remainedLength=67 [ 0x00 0x03 ]   // TopicNameLen=3 [ 0x24 0x64 0x70 ]   // TopicName=$dp </div><div>这是固定的数据[ 0x01 ]   // DpType=1 TimeSet=0 [ 0x00 0x3B ]   // JsonStrLen=59 这是json数据的长度[ 0x7B 0x22 0x64 0x61 0x74 0x61 0x73 0x74 0x72 0x65 0x61 0x6D 0x73 0x22 0x3A 0x5B 0x7B 0x22 0x69 0x64 0x22 0x3A 0x22 0x74 0x65 0x6D 0x70 0x22 0x2C 0x22 0x64 0x61 0x74 0x61 0x70 0x6F 0x69 0x6E 0x74 0x73 0x22 0x3A 0x5B 0x7B 0x22 0x76 0x61 0x6C 0x75 0x65 0x22 0x3A 0x35 0x30 0x7D 0x5D 0x7D 0x5D 0x7D ]   // JsonStr={"datastreams":[{"id":"temp","datapoints":[{"value":50}]}]} </div>

下面我们开始发送数据到服务器

AT+NSOSD=1,69,3043000324647001003B7B226461746173747265616D73223A5B7B226964223A2274656D70222C2264617461706F696E7473223A5B7B2276616C7565223A35307D5D7D5D7DOK
+NSONMI:1,4//这是服务器返回来的数据。AT+NSOCL=1 //关闭连接
OK

完整的步骤

<p>AT
OK
AT+NRB//重启模块的指令,在单片机里面最好进行重启一下
AT+CMEE=1
OK
AT+CGSN=1
+CGSN:867725030027605
OK
AT+NBAND?
+NBAND:8 //移动的返回+NBAND:8,电信的返回+NBAND:5</p><p>OK
AT+NBAND=8 //设置为移动的,电信的指令为AT+NBAND=5
OK
AT+CIMI //查询卡号
460042437100213
OK
AT+CSQ //查询信号指令,如果返回+CSQ:99,99 说明还没有信号
+CSQ:29,99
OK
AT+NSOCR=STREAM,6,56000,1 //做TCP socket创建准备
AT+NSOCO=1,183.230.40.33,6002//连接服务器。6002为服务器端口号
OK
AT+NSOSD=1,36,102200044D51545404C00078000831323334353637380006373839313233000474657374</p><p>OK
+NSONMI:1,4//这是服务器返回来的数据。
AT+NSORF=1,4//查询接收内容的指令203是需要查询的长度。可以多,
1,183.230.40.33,80,203,20200000,0</p><p>OK
AT+NSOSD=1,69,3043000324647001003B7B226461746173747265616D73223A5B7B226964223A2274656D70222C2264617461706F696E7473223A5B7B2276616C7565223A35307D5D7D5D7DOK
+NSONMI:1,4//这是服务器返回来的数据。AT+NSOCL=1 //关闭连接
OK</p>

附上C语言转十六进制函数

<p>int Str2Hex(char *str,char *hex)
{
int high = 0;
int low = 0;
int temp = 0;</p><p>if (NULL==str || NULL==hex){
//printf("the str or hex is wrong\n");
return -1;
}</p><p>if (0==strlen(str)){
//printf("the input str is wrong\n");
return -2;
}</p><p>while(*str)
{
temp = (int)(*str);
high = temp>>4;
low = temp & 15;
*hex = Value2Hex(high);
hex++;
*hex = Value2Hex(low);
hex++;
str++;
}
*hex = '\0';
return 0;
}</p>

附上发送MQTT连接服务器的数据及发送数据的格式化函数

<p>void ClearRAM(u8* ram,u32 n)
{
u32 i;
for (i = 0;i < n;i++)
{
ram = 0x00;
}
}
//构建MQTT连接包
u16 mqtt_connect_message(char *mqtt_message,char *PROID,char *AUTH_INFO,char *DEVID)
{
//      char HTTP_Buf; //HTTP报文缓存区
char str;
char strHEX;
u16 PROID_length = strlen(PROID);
u16 DEVID_length = strlen(DEVID);
u16 AUTH_INFO_length = strlen(AUTH_INFO);
u16 MQTT_length = strlen("MQTT");
u16 packetLen;
u16 i,baseIndex;
ClearRAM((u8*)str,200); //清空commandAT数据包缓存,发送命令包含ip端口和长度
ClearRAM((u8*)strHEX,200); //清空locationHex数据包缓存,转换为hex 需要发送的真实数据
packetLen = 12;//固定的数据头长度
if(PROID_length > 0)
packetLen = packetLen + 2 + PROID_length;
if(DEVID_length > 0)
packetLen = packetLen+ 2 + DEVID_length;
if(AUTH_INFO_length > 0)
packetLen = packetLen+ 2 + AUTH_INFO_length;</p><p>strncpy((char*)(mqtt_message+strlen((char*)mqtt_message)),"10",2);
sprintf(strHEX,"%02x",(packetLen-2));</p><p>strcat(mqtt_message,strHEX);
ClearRAM((u8*)str,200); //清空commandAT数据包缓存,发送命令包含ip端口和长度
ClearRAM((u8*)strHEX,200); //清空locationHex数据包缓存,转换为hex 需要发送的真实数据
strcat(mqtt_message,"00044D51545404C00100");      
//装载设备ID到数据包      
sprintf(str, "%02x%02x",((0xff00&(DEVID_length))>>8),(0xff&DEVID_length));
strcat(mqtt_message,str);
ClearRAM((u8*)str,200);
sprintf(str, "%s",DEVID);
Str2Hex((char*)str,(char*)strHEX);
strcat(mqtt_message,strHEX);      
ClearRAM((u8*)str,200);
ClearRAM((u8*)strHEX,200);
//装载产品ID到数据包      
sprintf(str, "%02x%02x",((0xff00&(PROID_length))>>8),(0xff&PROID_length));
strcat(mqtt_message,str);
ClearRAM((u8*)str,200);
sprintf(str, "%s",PROID);
Str2Hex((char*)str,(char*)strHEX);
strcat(mqtt_message,strHEX);      
ClearRAM((u8*)str,200);
ClearRAM((u8*)strHEX,200);
//装载产品ID到数据包      
sprintf(str, "%02x%02x",((0xff00&(AUTH_INFO_length))>>8),(0xff&AUTH_INFO_length));
strcat(mqtt_message,str);
ClearRAM((u8*)str,200);
sprintf(str, "%s",AUTH_INFO);
Str2Hex((char*)str,(char*)strHEX);
strcat(mqtt_message,strHEX);      
ClearRAM((u8*)str,200);
ClearRAM((u8*)strHEX,200);
Str2Hex((char*)str,(char*)strHEX);
strcat(mqtt_message,strHEX);
strcat(mqtt_message,"\r\n");      
return packetLen;
}
//构建MQTT数据包
u16 mqtt_SendData_message(char *mqtt_messageHEX,char *SendData,short length)
{
char str;
char strHEX;
u16 packetLen=length+8;
u16 SendData_length = strlen(SendData);
strncpy((char*)(mqtt_messageHEX+strlen((char*)mqtt_messageHEX)),"30",2);
sprintf(strHEX,"%02x",(packetLen));
strcat(mqtt_messageHEX,strHEX);
ClearRAM((u8*)str,200); //清空commandAT数据包缓存,发送命令包含ip端口和长度
ClearRAM((u8*)strHEX,200); //清空locationHex数据包缓存,转换为hex 需要发送的真实数据
strcat(mqtt_messageHEX,"01000324647001");      
//装载json数据到数据包      
sprintf(str, "%02x%02x",((0xff00&(SendData_length))>>8),(0xff&SendData_length));
strcat(mqtt_messageHEX,str);
ClearRAM((u8*)str,200);
sprintf(str, "%s",SendData);
Str2Hex((char*)str,(char*)strHEX);
strcat(mqtt_messageHEX,strHEX);      
ClearRAM((u8*)str,200);
ClearRAM((u8*)strHEX,200);      
return packetLen;
}      </p>

到此结束。有什么不对的地方还望指正
MQTT ONEnet测试调试工具


页: [1]
查看完整版本: NB-IoT模块 移远BC35全网通接入OneNET平台MQTT协议实现数据传输