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

21 篇文章 2 订阅
21 篇文章 5 订阅

网上很多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 
[ 0x10 ] // MQTT类型=1 DupFlag=0 QosLevel=0 Retain=0 
[ 0x22 ] // remainedLength=34  以下的数据长度  0x00 04......0x74 0x65 0x73 0x74这个之间的长度,您可以数一下看看
[ 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
[ 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

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

AT 
OK 
AT+NRB//重启模块的指令,在单片机里面最好进行重启一下 
AT+CMEE=1 
OK 
AT+CGSN=1 
+CGSN:867725030027605 
OK 
AT+NBAND? 
+NBAND:8 //移动的返回+NBAND:8,电信的返回+NBAND:5

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,35001,1 //做TCP socket创建准备 
AT+NSOCO=0,183.230.40.33,6002//连接服务器。6002为服务器端口号 
OK

注意:NB发送数据的时候数据内容需要转换为十六进制。大家可以使用在线转换工具
发送数据的指令为:AT+NSOSD=0,发送内容的长度,内容。//注意长度不可以多或者少

AT+NSOSD=0,36,102200044D51545404C00078000831323334353637380006373839313233000474657374

这个时候已经连接上服务器了,那么现在就发送数据,原始数据如下
{"datastreams":[{"id":"temp","datapoints":[{"value":50}]}]}

但是需要增加一些数据头之类的格式
这是转换后的数据

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

各个数据的含义

[ 0x30 ]   // MQTT类型=3  DupFlag=0 QosLevel=0 Retain=0  选用类型为3
[ 0x43 ]   // remainedLength=67
[ 0x00 0x03 ]   // TopicNameLen=3 
[ 0x24 0x64 0x70 ]   // TopicName=$dp 这是固定的数据
[ 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}]}]} [/indent]

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

AT+NSOSD=0,69,3043000324647001003B7B226461746173747265616D73223A5B7B226964223A2274656D70222C2264617461706F696E7473223A5B7B2276616C7565223A35307D5D7D5D7D

数据头的内容:

3043000324647001003B

数据头的含义

30 // MQTT类型=3  DupFlag=0 QosLevel=0 Retain=0 
43 //remainedLength=67 即是本位以下的内容数据长度,是十进制的长度装16进制
0003// TopicNameLen=3 
246470//TopicName=$dp 
01//数据类型:数据类型1:Json数据1;一共有七种 
003B//两位数据包长度,即发送内容的长度

完整的步骤

AT 
OK 
AT+NRB//重启模块的指令,在单片机里面最好进行重启一下 
AT+CMEE=1 
OK 
AT+CGSN=1 
+CGSN:867725030027605 
OK 
AT+NBAND? 
+NBAND:8 //移动的返回+NBAND:8,电信的返回+NBAND:5

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,35001,1 //做TCP socket创建准备 
AT+NSOCO=0,183.230.40.33,6002//连接服务器。6002为服务器端口号 
OK
AT+NSOSD=0,36,102200044D51545404C00078000831323334353637380006373839313233000474657374
0,36
OK 

AT+NSORF=0,4//查询接收内容的指令203是需要查询的长度。可以多, 
0,183.230.40.33,80,203,20200000,0

OK 
AT+NSOSD=0,69,3043000324647001003B7B226461746173747265616D73223A5B7B226964223A2274656D70222C2264617461706F696E7473223A5B7B2276616C7565223A35307D5D7D5D7D
0,69
OK 

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

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

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

void ClearRAM(u8* ram,u32 n)

{
	u32 i;
	for (i = 0;i < n;i++)
	{
	ram[i] = 0x00;
	}
}
//构建MQTT连接包 
u16 mqtt_connect_message(char *mqtt_message,char *PROID,char *AUTH_INFO,char *DEVID)
{
	    //        char HTTP_Buf[400]; //HTTP报文缓存区
	    char str[500];
	    char strHEX[500];
	    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;
	    
	    strncpy((char*)(mqtt_message+strlen((char*)mqtt_message)),"10",2);
	    sprintf(strHEX,"%02x",(packetLen-2));
	    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[200];
		    char strHEX[200];
		    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; 
	    }   

到此结束。有什么不对的地方还望指正
MQTT ONEnet测试调试工具:https://www.amobbs.com/thread-5698272-1-1.html
Onenet平台MQTT协议数据包生成器:关注微信公众号“NNHPTCH”,南宁湖畔科技,回复“Onenet平台MQTT协议数据包生成器”
QQ群:
796415884
欢迎大家进群交流!!!

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于Arduino平台,使用Arduino IDE编写的NB-IoT接入阿里云平台MQTT协议实现数据传输的示例代码。在使用前需要先在阿里云平台创建设备和Topic,并且获取对应的设备信息和证书。 ```C++ #include <SoftwareSerial.h> #include <PubSubClient.h> #include <ArduinoJson.h> #include <OneWire.h> #include <DallasTemperature.h> #include <DFRobot_SIM808.h> //定义NB-IoT模块相关参数 #define PIN_TX 7 #define PIN_RX 8 #define BAUDRATE 9600 //定义DS18B20温度传感器相关参数 #define ONE_WIRE_BUS 2 #define TEMPERATURE_PRECISION 9 //定义阿里云MQTT平台相关参数 #define MQTT_SERVER "xxx.mqtt.aliyuncs.com" //MQTT服务器地址 #define MQTT_PORT 1883 //MQTT服务器端口 #define MQTT_CLIENT_ID "GID_xxxxxxxxxxxxxx" //客户端ID #define MQTT_USERNAME "xxxxxxxxxxxxx" //MQTT用户名 #define MQTT_PASSWORD "xxxxxxxxxxxxx" //MQTT密码 #define MQTT_TOPIC "/xxxxxxxxxxxxx/xxxxxxxxxxxxx" //MQTT Topic SoftwareSerial mySerial(PIN_RX, PIN_TX); DFRobot_SIM808 sim808(&mySerial);//创建NB-IoT模块对象 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); WiFiClient wifiClient; PubSubClient mqttClient(MQTT_SERVER, MQTT_PORT, wifiClient); void setup() { Serial.begin(9600); mySerial.begin(BAUDRATE); while(!sim808.init());//等待模块初始化完成 delay(2000); Serial.println("SIM808 init success!"); sensors.begin(); } void loop() { sim808.checkPowerUp();//检查模块是否开机 if (sim808.isNetworkRegistered()) { Serial.println("Network is registered."); if (sim808.isGprsActived()) { Serial.println("GPRS is actived."); if (!mqttClient.connected()) { Serial.println("MQTT client is not connected."); connectMqttServer(); } mqttClient.loop(); float temperature = readTemperature(); publishMqttMessage(temperature); } else { Serial.println("GPRS is not actived, trying to activate..."); sim808.activeGprs("CMNET");//激活GPRS } } else { Serial.println("Network is not registered, trying to register..."); sim808.waitForNetworkRegistered();//等待网络注册 } } float readTemperature() { sensors.requestTemperatures(); float temperature = sensors.getTempCByIndex(0); return temperature; } void connectMqttServer() { Serial.println("Connecting to MQTT server..."); if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) { Serial.println("MQTT server connected."); mqttClient.subscribe(MQTT_TOPIC);//订阅MQTT Topic } else { Serial.print("Failed to connect MQTT server, rc="); Serial.println(mqttClient.state()); } } void publishMqttMessage(float temperature) { StaticJsonDocument<200> jsonDoc; jsonDoc["temperature"] = temperature; char message[200]; serializeJson(jsonDoc, message, sizeof(message)); mqttClient.publish(MQTT_TOPIC, message);//发布MQTT消息 } ``` 此代码实现了以下功能: 1. 连接NB-IoT模块和DS18B20温度传感器; 2. 检查NB-IoT网络状态; 3. 激活GPRS连接; 4. 连接阿里云MQTT平台; 5. 订阅指定的MQTT Topic; 6. 读取DS18B20传感器数据; 7. 将温度数据以JSON格式发布到MQTT Topic。 注意:由于NB-IoT网络和阿里云MQTT平台的连接较为复杂,上述代码仅供参考,具体实现需要根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值