1, Environment introduction
Single chip microcomputer: STM32F103C8T6
Internet access mode: ESP8266 can be used, or other devices can be used instead, as long as TCP protocol is supported. For example: GSM module, wired network card, etc.
Development software: keil5
Hardware connection function: ESP8266 is connected to serial port 3 of STM32. Communicate with ESP8266 through AT command.
Note: This article does not post the bottom programming code of ESP8266. If you do not know the bottom programming of ESP8266, please see here:
https://blog.csdn.net/xiaolong1126626497/article/details/107379554
If you need to understand the ESP8266+MQTT protocol to connect to Alibaba cloud Internet of things server, please see here: https://blog.csdn.net/xiaolong1126626497/article/details/107311897
Download the complete source code of the project: https://download.csdn.net/download/xiaolong1126626497/15803518
2, Function introduction
2.1 function description
Remote uploading and distribution of equipment data and data interaction are realized through onenet Internet of things server (those who do not know the function of onenet Internet of things server can enter Baidu's official website to see the introduction). The previous onenet server did not support the standard MQTT protocol login. Now the official website supports the standard MQTT protocol after updating. This article introduces the use of STM32+ESP8266 to log in to the onenet server using the standard MQTT protocol to realize data interaction. Implementation steps onenet official provides a very detailed document for reference.
Document address: https://open.iot.10086.cn/devdoc/


2.2 hardware resources
There are 4 LED lights, a buzzer and 4 keys on the currently used development board. The ESP8266 model is ESP-12F and the STM32 model is STM32F103C8T6.

3, MQTT protocol version supported by OneNet
At present, OneNet server supports MQTT version 3.1.1. MQTT protocol official website: http://mqtt.org/?spm=a2c4g.11186623.2.11.19083f86gxhJ7h
Message support: connect, subscribe, publish, ping, unsubscribe, disconnect and other messages are supported, but pubrec, pubrel and pubcomp messages are not supported.

4, Log in to OneNet server to create Internet of things products
If there is no registered account, you need to log in to the official website to register the account in advance, and then enter the following steps:



Fill in here according to your own products.



After the product is created successfully, click the product name, jump to the page and continue to add the device.
















Next, select the data source of the dashboard according to the data points you created.

Create a text control to display the update time of data points for debugging.




OneNte has a mobile APP. You can also see this page after logging in.
Download address: https://open.iot.10086.cn/doc/book/device-develop/multpro/sdk-doc-tool/APP.html


The following is the interface effect seen when logging in to the APP on the mobile phone:


5, Introduction to related formats of MQTT login address and subscription topic of OneNet server
Official website introduction document address: https://open.iot.10086.cn/doc/mqtt/book/get-start/connect.html

5.1 MQTT server login address

At present, MQTT protocol supports two IP addresses and port numbers, one needs encryption and the other does not need encryption.
Note: it is troublesome to transplant the encryption algorithm on the single chip microcomputer. The port that does not need encryption is used here. (IP address: 183.230.40.96 port: 1883)

5.2 MQTT login: device ID, user name, password format parameters



The above picture shows the corresponding relationship between OneNet device parameters and login parameters of standard MQTT protocol. OneNet device parameters can be viewed on the device page.
See the following steps for login password generation:



Note: the tool may prompt untrusted programs when running on win10 system. Click any to run.
The following is an example of the tool used to generate the MQTT login key.

Note: please refer to the document for the parameter description filled in the tool.
Format of res option parameter: products / {product ID}/devices / {device name}
et is to set the expiration time of the token: calculate the expiration time from 1970-1-1 to the time you want to set. The unit is seconds. Just fill in.
For example, if the timeout is set to 2020-07-20, the seconds filled in here are the second unit time between 1970-1-1 and 2020-07-20.
Code under Linux:
#include <stdio.h> #include <time.h> #include <time.h> int main() { time_t time_sec; time_sec=time(NULL); //Current second unit time -- UTC time printf("current time (second):%ld\n",time_sec); printf("Plus 30 days(second):%ld\n",time_sec+30*24*60*60); return 0; }
Key parameter format: the key in the device details page after the device is created
The result value generated by the tool is directly used as the password for MQTT login.
5.3 theme subscription format
Document address: https://open.iot.10086.cn/doc/mqtt/book/device-develop/protocol.html


5.4 equipment live time


5.5 transmitting data points to the server



6, Core code
6.1 matt.c code
#include "mqtt.h" u8 *mqtt_rxbuf; u8 *mqtt_txbuf; u16 mqtt_rxlen; u16 mqtt_txlen; u8 _mqtt_txbuf[256];//Send data buffer u8 _mqtt_rxbuf[256];//Receive data buffer typedef enum { //name Value Message flow direction describe M_RESERVED1 =0 , // prohibit retain M_CONNECT , // Client to server The client requests to connect to the server M_CONNACK , // Server to client Connection message confirmation M_PUBLISH , // Both directions are allowed Release news M_PUBACK , // Both directions are allowed QoS 1 message publishing receipt confirmation M_PUBREC , // Both directions are allowed Release received (first step of guaranteed delivery) M_PUBREL , // Both directions are allowed Release release (the second step of guaranteed delivery) M_PUBCOMP , // Both directions are allowed QoS 2 message publishing is completed (the third step of ensuring interaction) M_SUBSCRIBE , // Client to server Client subscription request M_SUBACK , // Server to client Subscription request message confirmation M_UNSUBSCRIBE , // Client to server Client unsubscribe request M_UNSUBACK , // Server to client Unsubscribe message confirmation M_PINGREQ , // Client to server Heartbeat request M_PINGRESP , // Server to client Heartbeat response M_DISCONNECT , // Client to server Client disconnect M_RESERVED2 , // prohibit retain }_typdef_mqtt_message; //Connection succeeded. The server responded 20 02 00 00 //Client actively disconnects e0 00 const u8 parket_connetAck[] = {0x20,0x02,0x00,0x00}; const u8 parket_disconnet[] = {0xe0,0x00}; const u8 parket_heart[] = {0xc0,0x00}; const u8 parket_heart_reply[] = {0xc0,0x00}; const u8 parket_subAck[] = {0x90,0x03}; void MQTT_Init(void) { //Buffer assignment mqtt_rxbuf = _mqtt_rxbuf; mqtt_rxlen = sizeof(_mqtt_rxbuf); mqtt_txbuf = _mqtt_txbuf; mqtt_txlen = sizeof(_mqtt_txbuf); memset(mqtt_rxbuf,0,mqtt_rxlen); memset(mqtt_txbuf,0,mqtt_txlen); //Unconditional active disconnection MQTT_Disconnect(); delay_ms(100); MQTT_Disconnect(); delay_ms(100); } /* Function function: login server Function return value: 0 means success, 1 means failure */ u8 MQTT_Connect(char *ClientID,char *Username,char *Password) { u8 i,j; int ClientIDLen = strlen(ClientID); int UsernameLen = strlen(Username); int PasswordLen = strlen(Password); int DataLen; mqtt_txlen=0; //Variable header + Payload each field contains a two byte length identifier DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2); //Fixed header //Control message type mqtt_txbuf[mqtt_txlen++] = 0x10; //MQTT Message Type CONNECT //Remaining length (excluding fixed head) do { u8 encodedByte = DataLen % 128; DataLen = DataLen / 128; // if there are more data to encode, set the top bit of this byte if ( DataLen > 0 ) encodedByte = encodedByte | 128; mqtt_txbuf[mqtt_txlen++] = encodedByte; }while ( DataLen > 0 ); //Variable header //Protocol name mqtt_txbuf[mqtt_txlen++] = 0; // Protocol Name Length MSB mqtt_txbuf[mqtt_txlen++] = 4; // Protocol Name Length LSB mqtt_txbuf[mqtt_txlen++] = 'M'; // ASCII Code for M mqtt_txbuf[mqtt_txlen++] = 'Q'; // ASCII Code for Q mqtt_txbuf[mqtt_txlen++] = 'T'; // ASCII Code for T mqtt_txbuf[mqtt_txlen++] = 'T'; // ASCII Code for T //Protocol level mqtt_txbuf[mqtt_txlen++] = 4; // MQTT Protocol version = 4 for version 3.1.1 protocol, the value of the protocol level field is 4(0x04) //Connection flag mqtt_txbuf[mqtt_txlen++] = 0xc2; // conn flags mqtt_txbuf[mqtt_txlen++] = 0; // Keep-alive Time Length MSB mqtt_txbuf[mqtt_txlen++] = 100; // Keep alive time length LSB 100s heartbeat packet keep alive time mqtt_txbuf[mqtt_txlen++] = BYTE1(ClientIDLen);// Client ID length MSB mqtt_txbuf[mqtt_txlen++] = BYTE0(ClientIDLen);// Client ID length LSB memcpy(&mqtt_txbuf[mqtt_txlen],ClientID,ClientIDLen); mqtt_txlen += ClientIDLen; if(UsernameLen > 0) { mqtt_txbuf[mqtt_txlen++] = BYTE1(UsernameLen); //username length MSB mqtt_txbuf[mqtt_txlen++] = BYTE0(UsernameLen); //username length LSB memcpy(&mqtt_txbuf[mqtt_txlen],Username,UsernameLen); mqtt_txlen += UsernameLen; } if(PasswordLen > 0) { mqtt_txbuf[mqtt_txlen++] = BYTE1(PasswordLen); //password length MSB mqtt_txbuf[mqtt_txlen++] = BYTE0(PasswordLen); //password length LSB memcpy(&mqtt_txbuf[mqtt_txlen],Password,PasswordLen); mqtt_txlen += PasswordLen; } memset(mqtt_rxbuf,0,mqtt_rxlen); MQTT_SendBuf(mqtt_txbuf,mqtt_txlen); for(j=0;j<10;j++) { delay_ms(50); if(USART3_RX_FLAG) { memcpy((char *)mqtt_rxbuf,USART3_RX_BUFFER,USART3_RX_CNT); //memcpy for(i=0;i<USART3_RX_CNT;i++)USART1_Printf("%#x ",USART3_RX_BUFFER[i]); USART3_RX_FLAG=0; USART3_RX_CNT=0; } //CONNECT if(mqtt_rxbuf[0]==parket_connetAck[0] && mqtt_rxbuf[1]==parket_connetAck[1]) //Connection succeeded { return 0;//Connection succeeded } } return 1; } /* Function function: MQTT subscription / unsubscribe data packaging function Function parameters: topic theme qos Message level 0: distribute at most once 1: distribute at least once 2: distribute only once whether Subscribe / unsubscribe request package (1 means subscribe, 0 means unsubscribe) Return value: 0 indicates success, 1 indicates failure */ u8 MQTT_SubscribeTopic(char *topic,u8 qos,u8 whether) { u8 i,j; mqtt_txlen=0; int topiclen = strlen(topic); int DataLen = 2 + (topiclen+2) + (whether?1:0);//The length of the variable header (2 bytes) plus the length of the payload //Fixed header //Control message type if(whether)mqtt_txbuf[mqtt_txlen++] = 0x82; //Message type and flag subscription else mqtt_txbuf[mqtt_txlen++] = 0xA2; //Unsubscribe //Remaining length do { u8 encodedByte = DataLen % 128; DataLen = DataLen / 128; // if there are more data to encode, set the top bit of this byte if ( DataLen > 0 ) encodedByte = encodedByte | 128; mqtt_txbuf[mqtt_txlen++] = encodedByte; }while ( DataLen > 0 ); //Variable header mqtt_txbuf[mqtt_txlen++] = 0; //Message identifier MSB mqtt_txbuf[mqtt_txlen++] = 0x0A; //Message identifier LSB //Payload mqtt_txbuf[mqtt_txlen++] = BYTE1(topiclen);//Subject length MSB mqtt_txbuf[mqtt_txlen++] = BYTE0(topiclen);//Subject length LSB memcpy(&mqtt_txbuf[mqtt_txlen],topic,topiclen); mqtt_txlen += topiclen; if(whether) { mqtt_txbuf[mqtt_txlen++] = qos;//QoS level } for(i=0;i<10;i++) { memset(mqtt_rxbuf,0,mqtt_rxlen); MQTT_SendBuf(mqtt_txbuf,mqtt_txlen); for(j=0;j<10;j++) { delay_ms(50); if(USART3_RX_FLAG) { memcpy((char *)mqtt_rxbuf,(char*)USART3_RX_BUFFER,USART3_RX_CNT); USART3_RX_FLAG=0; USART3_RX_CNT=0; } if(mqtt_rxbuf[0]==parket_subAck[0] && mqtt_rxbuf[1]==parket_subAck[1]) //Subscription succeeded { return 0;//Subscription succeeded } } } return 1; //fail } //MQTT publish data packaging function //Topic topic //Message message //qos message level u8 MQTT_PublishData(char *topic, char *message, u8 qos) { int topicLength = strlen(topic); int messageLength = strlen(message); static u16 id=0; int DataLen; mqtt_txlen=0; //The length of the payload is calculated by subtracting the length of the variable header from the value of the remaining length field in the fixed header //No identifier when QOS is 0 //Data length subject name message identifier payload if(qos) DataLen = (2+topicLength) + 2 + messageLength; else DataLen = (2+topicLength) + messageLength; //Fixed header //Control message type mqtt_txbuf[mqtt_txlen++] = 0x30; // MQTT Message Type PUBLISH //Remaining length do { u8 encodedByte = DataLen % 128; DataLen = DataLen / 128; // if there are more data to encode, set the top bit of this byte if ( DataLen > 0 ) encodedByte = encodedByte | 128; mqtt_txbuf[mqtt_txlen++] = encodedByte; }while ( DataLen > 0 ); mqtt_txbuf[mqtt_txlen++] = BYTE1(topicLength);//Subject length MSB mqtt_txbuf[mqtt_txlen++] = BYTE0(topicLength);//Subject length LSB memcpy(&mqtt_txbuf[mqtt_txlen],topic,topicLength);//Copy theme mqtt_txlen += topicLength; //message identifier if(qos) { mqtt_txbuf[mqtt_txlen++] = BYTE1(id); mqtt_txbuf[mqtt_txlen++] = BYTE0(id); id++; } memcpy(&mqtt_txbuf[mqtt_txlen],message,messageLength); mqtt_txlen += messageLength; MQTT_SendBuf(mqtt_txbuf,mqtt_txlen); return mqtt_txlen; } void MQTT_SentHeart(void) { MQTT_SendBuf((u8 *)parket_heart,sizeof(parket_heart)); } void MQTT_Disconnect(void) { MQTT_SendBuf((u8 *)parket_disconnet,sizeof(parket_disconnet)); } void MQTT_SendBuf(u8 *buf,u16 len) { USARTx_DataSend(USART3,buf,len); }
6.2 mqtt.h code
#ifndef __FY_MQTT_H_ #define __FY_MQTT_H_ #include "stm32f10x.h" #include "string.h" #include "stdio.h" #include "stdlib.h" #include "stdarg.h" #include "delay.h" #include "usart.h" #define BYTE0(dwTemp) (*( char *)(&dwTemp)) #define BYTE1(dwTemp) (*((char *)(&dwTemp) + 1)) #define BYTE2(dwTemp) (*((char *)(&dwTemp) + 2)) #define BYTE3(dwTemp) (*((char *)(&dwTemp) + 3)) //User name initialization void OneNet_LoginInit(char *ProductKey,char *DeviceName,char *DeviceSecret); //MQTT protocol related function declaration u8 MQTT_PublishData(char *topic, char *message, u8 qos); u8 MQTT_SubscribeTopic(char *topic,u8 qos,u8 whether); void MQTT_Init(void); u8 MQTT_Connect(char *ClientID,char *Username,char *Password); void MQTT_SentHeart(void); void MQTT_Disconnect(void); void MQTT_SendBuf(u8 *buf,u16 len); #endif
6.3 main.c main function code
#include "stm32f10x.h" #include "led.h" #include "delay.h" #include "key.h" #include "usart.h" #include <string.h> #include "timer.h" #include "esp8266.h" #include "mqtt.h" /* Serial number Symbol code 1 + %2B 2 Space% 20 3 / %2F 4 ? %3F 5 % %25 6 # %23 7 & %26 8 = %3D */ //Device information of OneNet IOT server #define MQTT_ClientID "mq2" #define MQTT_UserName "361594" #define MQTT_PassWord "version=2018-10-31&res=products%2F361594%2Fdevices%2Fmq2&et=1597492895&method=sha1&sign=uqvA0KkjXw0FlN01aT6fWrGBLGw%3D" //Topics for subscriptions and publications //Format: $sys / {product ID} / {device name}/# #define SET_TOPIC "$sys/361594/mq2/#"/ / subscribe to all device information //Format: $sys / {product ID} / {device name} / dp/post/json #define POST_TOPIC "$sys/361594/mq2/dp/post/json" / / publish char mqtt_message[200];//Report data buffer int main() { u32 time_cnt=0; u32 i; u8 key; LED_Init(); BEEP_Init(); KEY_Init(); USART1_Init(115200); TIMER1_Init(72,20000); //Timeout 20ms USART3_Init(115200);//Serial WIFI TIMER3_Init(72,20000); //Timeout 20ms USART1_Printf("Initializing WIFI One moment please.\n"); if(ESP8266_Init()) { USART1_Printf("ESP8266 Hardware detection error.\n"); } else { //Encryption port //USART1_Printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode("OnePlus5T","1126626497","183.230.40.16",8883,1)); //Unencrypted port USART1_Printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode("OnePlus5T","1126626497","183.230.40.96",1883,1)); } //2. MQTT protocol initialization MQTT_Init(); //3. Connect OneNet server while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord)) { USART1_Printf("OneNet Server connection failed,Retrying...\n"); delay_ms(500); } USART1_Printf("OneNet Server connection succeeded.\n"); //3. Subscribe to topics if(MQTT_SubscribeTopic(SET_TOPIC,0,1)) { USART1_Printf("Topic subscription failed.\n"); } else { USART1_Printf("Topic subscription succeeded.\n"); } while(1) { key=KEY_Scan(0); if(key==2) { time_cnt=0; sprintf(mqtt_message,"{\"id\":1,\"dp\":{\"mq2\":[{\"v\":50}]}}"); MQTT_PublishData(POST_TOPIC,mqtt_message,0); USART1_Printf("Send status 1\r\n"); } else if(key==3) { time_cnt=0; sprintf(mqtt_message,"{\"id\":1,\"dp\":{\"mq2\":[{\"v\":80}]}}"); MQTT_PublishData(POST_TOPIC,mqtt_message,0); USART1_Printf("Send status 0\r\n"); } if(USART3_RX_FLAG) { USART3_RX_BUFFER[USART3_RX_CNT]='\0'; for(i=0;i<USART3_RX_CNT;i++) { USART1_Printf("%c",USART3_RX_BUFFER[i]); } USART3_RX_CNT=0; USART3_RX_FLAG=0; } //Send heartbeat packets regularly and keep connected delay_ms(10); time_cnt++; if(time_cnt==500) { MQTT_SentHeart();//Send heartbeat packet time_cnt=0; } } }
7, Device login operation effect
After successful login, the web page will display the online status.

Press the development button to upload smoke data to the server effect:

