I. Introduction to the environment
MCU: STM32F103ZET6
Internet access: Use ESP8266 or other devices as long as they support TCP. For example: GSM module, wired network card and so on.
Communication protocol with iot cloud platform: standard MQTT protocol 3.1.1(TCP)
Development software: KEil5
Internet of Things platform: Tencent IOT platform. Tencent’s Internet of Things platform has more advantages than other manufacturers’ Internet of Things platform. Tencent’s Internet of Things platform can push data to wechat mini program, and users can directly use the mini program to bind devices and complete interaction with devices. Now, most users use wechat, so it is very convenient to use.
This project complete code download address: download.csdn.net/download/xi…
Ii. Introduction to smart agriculture
Smart agriculture is the application of Internet of Things technology to traditional agriculture. Sensors and software are used to control agricultural production through mobile platforms or computer platforms to make traditional agriculture more “smart”. In addition to accurate perception, control and decision management, smart agriculture in a broad sense also includes agricultural e-commerce, food traceability and anti-counterfeiting, agricultural leisure tourism, agricultural information services and other aspects. The so-called “smart agriculture” is the full application of modern information technology achievements, integrated application of computer and network technology, Internet of things technology, audio and video technology, 3S technology, wireless communication technology and expert wisdom and knowledge, agricultural visual remote diagnosis, remote control, disaster early warning and other intelligent management.
Smart agriculture is an advanced stage of agricultural production, integrating emerging Internet, mobile Internet, cloud computing and Internet of Things technologies. Relying on various sensor nodes deployed in the field of agricultural production, environmental temperature and humidity, soil moisture, carbon dioxide, image, etc.) and wireless communication network to realize the agricultural production environment of intellisense, intelligent early warning, intelligent decision-making, intelligent online analysis, expert guidance, to provide agricultural production precision planting, visual management, intelligent decision making. “Smart agriculture” is the comprehensive and comprehensive application of cloud computing, sensor network, 3S and other information technologies in agriculture, to achieve more complete information base support, more thorough agricultural information perception, more centralized data resources, broader connectivity, more in-depth intelligent control, and more intimate public services. The integration of “smart agriculture” with modern biotechnology, planting technology and other science and technology is of great significance to the construction of world-class agriculture.
This project uses STM32F103ZET6 + ESP8266 to design an intelligent agricultural management system, which can obtain the data of temperature and humidity in the air and illuminance, and judge whether to carry out irrigation according to the data of air temperature and humidity in the planting area. The collected temperature, humidity and illuminance can be uploaded to Tencent Cloud Internet of Things platform through ESP8266 + MQTT protocol, and pushed to wechat mini program for real-time viewing; Motor pumping irrigation can be directly controlled in small program.
Hardware details:
Master MCU: STM32F103ZET6
Ambient light sensor: BH1750
T/H sensor: SHT30
Local OLED display: 0.96 “SPI interface OLED display from Zhongjingyuan Electronics
Motor: miniature DC motor
3. Create Tencent Cloud Internet of Things platform equipment and configure wechat applets
If never use tencent cloud before the Internet of things platform, to create detailed steps is described here: blog.csdn.net/xiaolong112…
The following are the key steps to log in to Tencent cloud Internet of Things platform and create an intelligent agriculture equipment. Some details are not written. Please refer to the article linked above for details.
Website address: console.cloud.tencent.com/iotexplorer
Iv. Generate device login information of Tencent Internet of Things platform
Parameters required for login using the MQTT protocol must be generated in the method provided on the official website.
Python example code:
#! /usr/bin/python # -*- coding: UTF- 8 -- * -import base64
import hashlib
import hmac
import random
import string
import time
importSys # generates a random string of specified lengthdef RandomConnid(length):
return Join (random.choice(string.ascii_uppercase + string.digits) for _ in range(length) IotHmac(productID, devicename, devicePsk): # 1. Generate connID as a random string to facilitate background location problem connid = RandomConnid(5) # 2 UTF8 string expiry = int(time.time()) + 30*24*60 *60 # 3. ${productid}${devicename} clientid = "{}{}". Format (productid, devicename) # 4. Generate the USERNAME part of MQTT in the format ${clientid}; ${sdkappid}; ${connid}; ${expiry} username = "{}; 12010126; {}; {}".format(clientid, connid, expiry) # 5. Secret_key = devicepsk.encode ('utf8 ') # convert to bytes
data_to_sign = username.encode('utf-8') # convert to bytes
secret_key = base64.b64decode(secret_key) # this is still bytes
token = hmac.new(secret_key, data_to_sign, digestmod=hashlib.sha256).hexdigest(#)6.Generate the password field password = according to the rules of the Internet of Things communication platform"{}; {}".format(token, "hmacsha256")
return {
"clientid" : clientid,
"username" : username,
"password" : password
}
if __name__ == '__main__'Enter the product ID, device name, and device key respectivelyprint(IotHmac("6142CX41XE"."SmartAgriculture"."20Y/aAcmj+y6SDDh+ANR9g=="))
Copy the code
Logon parameters for the MQTT protocol:
{'clientid': '6142CX41XESmartAgriculture', 'username': '6142CX41XESmartAgriculture; 12010126; HUA2G; 1624271589', 'password': 'a8aadebe9721f70e6f9e14fe56ff1d2b5cac9625fa1f96af2f0e0098597fe78b; hmacsha256'}Copy the code
Five, use MQTT software test
The MQTT client software download address: download.csdn.net/download/xi…
The software adopts the QT development, source address: blog.csdn.net/xiaolong112…
Device topics published and defined in format:
Device message data upload format:
{" method ":" report ", "clientToken" : "123", "params" : {" light ": 78.4," temperature ": 21.4," humidity ": 60.8," motor ": 1}}Copy the code
After successful login, you can see that the device is online:
Open the wechat mini program to view the data uploaded by the device:
6. Write STM32 device side code
6.1 the main c 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"
#include "oled.h"
#include "fontdata.h"
#include "bh1750.h"
#include "iic.h"
#include "sht3x.h"
/* Hardware connection: ESP8266 serial port WIFI module is connected to serial port 3 of STM32. PB10--RXD module receiving pin PB11--TXD module sending pin GND---GND GROUND VCC---VCC power supply (3.3V~5.0V) OLED wiring: D0 - SCK - PB14 D1 - MOSI - PB13 RES - reset (effective) low level - PB12 DC - data and command control pin - PB1 CS - piece selected pin -- -- -- -- -- PA7 miniature DC motor: PB8 light: PB9 LED hardware connection: PB5 PE5 KEY Hardware connection :PE3 PE4 */
#define ESP8266_WIFI_AP_SSID "CMCC-Cqvn" // Name of the router to be connected -- do not contain special characters such as Chinese characters and Spaces
#define ESP8266_AP_PASSWORD "99pu58cb" // Password of the router to be connected
// Device information of Tencent iot server
#define MQTT_ClientID "6142CX41XESmartAgriculture"
#define MQTT_UserName "6142CX41XESmartAgriculture; 12010126; HUA2G; 1624271589"
#define MQTT_PassWord "a8aadebe9721f70e6f9e14fe56ff1d2b5cac9625fa1f96af2f0e0098597fe78b; hmacsha256"
// Subscribe and publish topics
#define SET_TOPIC "$thing/down/property/6142CX41XE/SmartAgriculture" / / subscribe
#define POST_TOPIC "$thing/up/property/6142CX41XE/SmartAgriculture" / / release
char mqtt_message[200];// Report data cache
char OLED_ShowBuff[100];
u8 ESP8266_Stat=0;
/* Function function: temperature and humidity \ light intensity display */
void ShowTemperatureAndHumidity(float temp,float humi,float light)
{
sprintf(OLED_ShowBuff,"T: %.2f",temp);
OLED_ShowString(40.16*0.16,OLED_ShowBuff);
sprintf(OLED_ShowBuff,"H: %.2f%%",humi);
OLED_ShowString(40.16*1.16,OLED_ShowBuff);
sprintf(OLED_ShowBuff,"L: %.2f%%",light);
OLED_ShowString(40.16*2.16,OLED_ShowBuff);
}
/* ESP8266 displays a page */
void ESP8266_ShowPageTable(void)
{
if(ESP8266_Stat)OLED_ShowString(0.16*0.16."WIFI STAT:ERROR");
else OLED_ShowString(0.16*0.16."WIFI STAT:OK");
// Displays a string
sprintf((char*)OLED_ShowBuff,"%s",ESP8266_WIFI_AP_SSID);
OLED_ShowString(0.16*1.16,OLED_ShowBuff);
sprintf((char*)OLED_ShowBuff,"%s",ESP8266_AP_PASSWORD);
OLED_ShowString(0.16*2.16,OLED_ShowBuff);
}
int main(a)
{
u32 time_cnt=0;
u32 i;
u8 key;
u8 page=0;
float temp=0;
float humi=0;
float light=0;
u8 motor_state=0;
float Humidity;
float Temperature;
delay_ms(1000);
delay_ms(1000);
LED_Init(a);KEY_Init(a);IIC_Init(a);/ / OLED initialization
OLED_Init(0xc8.0xa1); //OLED display initialization -- normal display;
/ / clear screen
OLED_Clear(0);
USART1_Init(115200);
TIMER1_Init(72.20000); // The timeout time is 20ms
USART3_Init(115200);/ / serial port - WIFI
TIMER3_Init(72.20000); // The timeout time is 20ms
Init_SHT30(a);USART1_Printf("Please wait while initializing WIFI.\n");
if(ESP8266_Init())
{
ESP8266_Stat=1;
USART1_Printf("ESP8266 hardware detection error.\n");
}
else
{
// Unencrypted port
USART1_Printf("WIFI:%d\n".ESP8266_STA_TCP_Client_Mode(ESP8266_WIFI_AP_SSID,ESP8266_AP_PASSWORD,"106.55.124.154".1883.1));
}
//2. Initialize the MQTT protocol
MQTT_Init(a);//3. Connect to Tencent Cloud IOT server
while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord))
{
USART1_Printf("Server connection failed, trying again... \n");
delay_ms(500);
}
USART1_Printf("Server connected successfully.\n");
//3. Subscribe to topics
if(MQTT_SubscribeTopic(SET_TOPIC,0.1))
{
USART1_Printf("Topic subscription failed.\n");
}
else
{
USART1_Printf("Theme subscribed successfully.\n");
}
while(1)
{
// Key can test unlock and unlock
key=KEY_Scan(0);
if(key==1)
{
/ / clear screen
OLED_Clear(0);
/ / page
if(page>=1)
{
page=0;
}
else{ page++; } LED1=! LED1;/ / state of the LEd lamp
}
else if(key==2) { LED1=! LED1;/ / state of the LEd lamp
time_cnt=0;
// The state of the motor changesMOTOR_DEV=! MOTOR_DEV;// Motor status
motor_state=MOTOR_DEV;
/ / fill lightLIGHT_DEV=! LIGHT_DEV; }// wechat applet unlock mode: receive data returned by WIFI
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\ 0';
// Prints the data returned by the wechat applet to the serial port
for(i=0; i<USART3_RX_CNT; i++) {USART1_Printf("%c",USART3_RX_BUFFER[i]);
}
// If the attribute is delivered, determine whether to unlock or disable the lock
if(USART3_RX_CNT>5)
{
// Use the string lookup function
if(strstr((char*)&USART3_RX_BUFFER[5]."\"motor\":1"))
{
LED1=0; / / light
MOTOR_DEV=1; / / drive motor
motor_state=1;
}
else if(strstr((char*)&USART3_RX_BUFFER[5]."\"motor\":0"))
{
LED1=1; / / out the light
MOTOR_DEV=0; / / off the motor
motor_state=0;
}
}
USART3_RX_CNT=0;
USART3_RX_FLAG=0;
}
// Time and keep in sync with wechat applet -- once every second
delay_ms(10);
time_cnt++;
if(time_cnt==50)
{
time_cnt=0;
// Status light -- indicates that the application is still aliveLED2=! LED2;// Read the light intensity
light=Read_BH1750_Data(a);// Read the temperature and humidity
SHT3x_ReadData(&Humidity,&Temperature);
humi=Humidity;
temp=Temperature;
// Upload data
sprintf(mqtt_message,"{\"method\":\"report\",\"clientToken\":\"123\",\"params\":{\"temperature\":%f,\"humidity\":%f,\"motor\":%d,\"light\":%f }}",
temp,humi,motor_state,light);
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
// Automatic irrigation according to humidity
if(humi<50.0) // Less than 50 automatic irrigation
{
motor_state=1; // Update motor status
MOTOR_DEV=1; / / drive motor}}/ / OLED displays
if(page==0)
{
ShowTemperatureAndHumidity(temp,humi,light);
}
else if(page==1)
{
ESP8266_ShowPageTable(a); }}}Copy the code
6.2 the MQTT. C code
#include "mqtt.h"
u8 *mqtt_rxbuf;
u8 *mqtt_txbuf;
u16 mqtt_rxlen;
u16 mqtt_txlen;
u8 _mqtt_txbuf[256];// Send data cache
u8 _mqtt_rxbuf[256];// Receive data cache
typedef enum
{
// Name value Indicates the packet flow direction
M_RESERVED1 =0 , // Disallow reservation
M_CONNECT , // Client to server The client requests a connection to the server
M_CONNACK , // Confirm the connection packet from the server to the client
M_PUBLISH , // Both directions allow messages to be published
M_PUBACK , // QoS 1 is allowed in both directions
M_PUBREC , // Allow publish received in both directions (first step to ensure delivery)
M_PUBREL , // Release is allowed in both directions (step 2 to ensure delivery)
M_PUBCOMP , // Allow QoS 2 message publishing to complete in both directions (ensure interaction step 3)
M_SUBSCRIBE , // Client-to-server The client subscribes to requests
M_SUBACK , // Confirm the server - to - client subscription request packet
M_UNSUBSCRIBE , // Client-to-server The client unsubscribes the request
M_UNSUBACK , // The server unsubscribes the packet from the client
M_PINGREQ , // Heartbeat request from client to server
M_PINGRESP , // Heartbeat response from server to client
M_DISCONNECT , // Client to server The client is disconnected
M_RESERVED2 , // Disallow reservation
}_typdef_mqtt_message;
20 02 00 00
// The client 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);
// Disconnect unconditionally
MQTT_Disconnect(a);delay_ms(100);
MQTT_Disconnect(a);delay_ms(100);
}
/* Function Function: Login server function Returned value: 0: successful 1: failed */
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);
// Fix the header
// Control the packet type
mqtt_txbuf[mqtt_txlen++] = 0x10; //MQTT Message Type CONNECT
// Rest 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
/ / agreement
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, the value of the Protocol level field is 4(0x04)
// The 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 alive duration
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]) // The connection succeeded
{
return 0;// The connection succeeded}}return 1;
}
Topic topic qos message level 0: distributed at most once 1: distributed at least once 2: distributed only once Whether subscribe/unsubscribe request packet (1 indicates subscribe,0 indicates unsubscribe) Returned 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
// Fix the header
// Control the packet type
if(whether)mqtt_txbuf[mqtt_txlen++] = 0x82; // Message type and flag subscription
else mqtt_txbuf[mqtt_txlen++] = 0xA2; // Unsubscribe
// The 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);// The topic length is MSB
mqtt_txbuf[mqtt_txlen++] = BYTE0(topiclen);// The topic length is LSB
memcpy(&mqtt_txbuf[mqtt_txlen],topic,topiclen);
mqtt_txlen += topiclen;
if(whether)
{
mqtt_txbuf[mqtt_txlen++] = qos;/ / the QoS
}
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]) // The subscription succeeded
{
return 0;// The subscription succeeded}}}return 1; / / fail
}
//MQTT publishes data packaging functions
/ / the topic subject
/ / the 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 payload length is calculated by subtracting the variable header length from the value of the remaining length field in the fixed header
// When QOS is 0, there is no identifier
// Data length Subject name Packet identifier Payload
if(qos) DataLen = (2+topicLength) + 2 + messageLength;
else DataLen = (2+topicLength) + messageLength;
// Fix the header
// Control the packet type
mqtt_txbuf[mqtt_txlen++] = 0x30; // MQTT Message Type PUBLISH
// The 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);// The topic length is MSB
mqtt_txbuf[mqtt_txlen++] = BYTE0(topicLength);// The topic length is LSB
memcpy(&mqtt_txbuf[mqtt_txlen],topic,topicLength);// Copy the theme
mqtt_txlen += topicLength;
// Packet 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);
}
Copy the code