?
一、環(huán)境介紹
上網(wǎng)方式:采用ESP8266,也可以使用其他設(shè)備代替,只要支持TCP協(xié)議即可。比如:GSM模塊、有線網(wǎng)卡等。
與物聯(lián)網(wǎng)云平臺(tái)的通信協(xié)議:標(biāo)準(zhǔn)MQTT協(xié)議3.1.1(TCP)
開發(fā)軟件:keil5
物聯(lián)網(wǎng)平臺(tái): 騰訊IOT物聯(lián)網(wǎng)物聯(lián)網(wǎng)平臺(tái)。騰訊的物聯(lián)網(wǎng)平臺(tái)比起其他廠家的物聯(lián)網(wǎng)平臺(tái)更加有優(yōu)勢,騰訊物聯(lián)網(wǎng)平臺(tái)可以將數(shù)據(jù)推到微信小程序上,用戶可以直接使用小程序綁定設(shè)備,完成與設(shè)備之間交互,現(xiàn)在用戶基本都會(huì)使用微信,所以使用起來非常方便。
?
?
?
?
?
二、智慧農(nóng)業(yè)介紹
智慧農(nóng)業(yè)就是將物聯(lián)網(wǎng)技術(shù)運(yùn)用到傳統(tǒng)農(nóng)業(yè)中去,運(yùn)用傳感器和軟件通過移動(dòng)平臺(tái)或者電腦平臺(tái)對農(nóng)業(yè)生產(chǎn)進(jìn)行控制,使傳統(tǒng)農(nóng)業(yè)更具有“智慧”。除 了精準(zhǔn)感知、控制與決策管理外,從廣泛意義上講,智慧農(nóng)業(yè)還包括農(nóng)業(yè)電子商務(wù)、食品溯源防偽、農(nóng)業(yè)休閑旅游、農(nóng)業(yè)信息服務(wù)等方面的內(nèi)容。
所謂“智慧農(nóng)業(yè)”就是充分應(yīng)用現(xiàn)代信息技術(shù)成果,集成應(yīng)用計(jì)算機(jī)與網(wǎng)絡(luò)技術(shù)、物聯(lián)網(wǎng)技術(shù)、音視頻技術(shù)、3S技術(shù)、無線通信技術(shù)及專家智慧與知識,實(shí)現(xiàn)農(nóng)業(yè)可視化遠(yuǎn)程診斷、遠(yuǎn)程控制、災(zāi)變預(yù)警等智能管理。
智慧農(nóng)業(yè)是農(nóng)業(yè)生產(chǎn)的高級階段,是集新興的互聯(lián)網(wǎng)、移動(dòng)互聯(lián)網(wǎng)、云計(jì)算和物聯(lián)網(wǎng)技術(shù)為一體,依托部署在農(nóng)業(yè)生產(chǎn)現(xiàn)場的各種傳感節(jié)點(diǎn)(環(huán)境溫濕度、土壤水分、二氧化碳、圖像等)和無線通信網(wǎng)絡(luò)實(shí)現(xiàn)農(nóng)業(yè)生產(chǎn)環(huán)境的智能感知、智能預(yù)警、智能決策、智能分析、專家在線指導(dǎo),為農(nóng)業(yè)生產(chǎn)提供精準(zhǔn)化種植、可視化管理、智能化決策。
“智慧農(nóng)業(yè)”是云計(jì)算、傳感網(wǎng)、3S等多種信息技術(shù)在農(nóng)業(yè)中綜合、全面的應(yīng)用,實(shí)現(xiàn)更完備的信息化基礎(chǔ)支撐、更透徹的農(nóng)業(yè)信息感知、更集中的數(shù)據(jù)資源、更廣泛的互聯(lián)互通、更深入的智能控制、更貼心的公眾服務(wù)?!爸腔坜r(nóng)業(yè)”與現(xiàn)代生物技術(shù)、種植技術(shù)等科學(xué)技術(shù)融合于一體,對建設(shè)世界水平農(nóng)業(yè)具有重要意義。
本項(xiàng)目采用STM32F103ZET6 + ESP8266 設(shè)計(jì)一個(gè)智慧農(nóng)業(yè)管理系統(tǒng),能夠獲取空氣中的溫濕度數(shù)據(jù),光照度數(shù)據(jù)等,根據(jù)種植區(qū)的空氣溫濕度數(shù)據(jù),判斷是否進(jìn)行灌溉;可以通過ESP8266 + MQTT 協(xié)議將采集的溫濕度、光照度上傳至騰訊云物聯(lián)網(wǎng)平臺(tái),并推送到微信小程序上實(shí)時(shí)查看;可以在小程序上直接控制電機(jī)抽水灌溉。
硬件詳情介紹:
主控MCU: STM32F103ZET6
環(huán)境光傳感器: BH1750
溫濕度傳感器:SHT30
本地OLED顯示屏: 中景園電子0.96寸 SPI接口 OLED顯示屏
電機(jī): 微型直流電機(jī)
三、創(chuàng)建騰訊云物聯(lián)網(wǎng)平臺(tái)設(shè)備并配置微信小程序
如果之前從來沒有使用過騰訊云物聯(lián)網(wǎng)平臺(tái),創(chuàng)建的詳細(xì)步驟請看這里: STM32+ESP8266+MQTT協(xié)議連接騰訊物聯(lián)網(wǎng)開發(fā)平臺(tái)_DS小龍哥的專欄-CSDN博客_騰訊物聯(lián)網(wǎng)平臺(tái)
下面就是登錄騰訊云物聯(lián)網(wǎng)平臺(tái),創(chuàng)建一個(gè)智慧農(nóng)業(yè)的設(shè)備的關(guān)鍵步驟,有些細(xì)節(jié)步驟沒寫,細(xì)節(jié)請看上面鏈接這篇文章。
官網(wǎng)地址:登錄 - 騰訊云
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
四、生成騰訊物聯(lián)網(wǎng)平臺(tái)的設(shè)備登錄信息
使用MQTT協(xié)議登錄需要一些參數(shù)信息,需要使用官網(wǎng)提供的方式生成。
?
Python示例代碼:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import base64
import hashlib
import hmac
import random
import string
import time
import sys
# 生成指定長度的隨機(jī)字符串
def RandomConnid(length):
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length))
# 生成接入物聯(lián)網(wǎng)通信平臺(tái)需要的各參數(shù)
def IotHmac(productID, devicename, devicePsk):
# 1. 生成 connid 為一個(gè)隨機(jī)字符串,方便后臺(tái)定位問題
connid = RandomConnid(5)
# 2. 生成過期時(shí)間,表示簽名的過期時(shí)間,從紀(jì)元1970年1月1日 00:00:00 UTC 時(shí)間至今秒數(shù)的 UTF8 字符串
expiry = int(time.time()) + 30*24*60 * 60
# 3. 生成 MQTT 的 clientid 部分, 格式為 ${productid}${devicename}
clientid = "{}{}".format(productID, devicename)
# 4. 生成 MQTT 的 username 部分, 格式為 ${clientid};${sdkappid};${connid};${expiry}
username = "{};12010126;{};{}".format(clientid, connid, expiry)
# 5. 對 username 進(jìn)行簽名,生成token
secret_key = devicePsk.encode('utf-8') # 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. 根據(jù)物聯(lián)網(wǎng)通信平臺(tái)規(guī)則生成 password 字段
password = "{};{}".format(token, "hmacsha256")
return {
"clientid" : clientid,
"username" : username,
"password" : password
}
if __name__ == '__main__':
# 參數(shù)分別填入: 產(chǎn)品ID,設(shè)備名稱,設(shè)備密匙
print(IotHmac("6142CX41XE", "SmartAgriculture","20Y/aAcmj+y6SDDh+ANR9g=="))
輸出的登錄參數(shù),用于MQTT協(xié)議填參數(shù):
{'clientid': '6142CX41XESmartAgriculture', 'username': '6142CX41XESmartAgriculture;12010126;HUA2G;1624271589',
'password': 'a8aadebe9721f70e6f9e14fe56ff1d2b5cac9625fa1f96af2f0e0098597fe78b;hmacsha256'}
五、使用MQTT軟件測試
?
設(shè)備主題發(fā)布與定義的格式:
?
設(shè)備消息數(shù)據(jù)上傳格式:
{"method":"report","clientToken":"123","params":{"light":78.4,"temperature":21.4,"humidity":60.8,"motor":1}}
登錄成功之后,就可以看到設(shè)備在線:
?
打開微信小程序可以查看到設(shè)備上傳的數(shù)據(jù):
?
六、編寫STM32設(shè)備端代碼
?
?
6.1 main.c代碼
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include
#include "timer.h"
#include "esp8266.h"
#include "mqtt.h"
#include "oled.h"
#include "fontdata.h"
#include "bh1750.h"
#include "iic.h"
#include "sht3x.h"
/*
硬件連接方式:
ESP8266串口WIFI模塊與STM32的串口3相連接。
PB10--RXD 模塊接收腳
PB11--TXD 模塊發(fā)送腳
GND---GND 地
VCC---VCC 電源(3.3V~5.0V)
OLED接線:
D0----SCK-----PB14
D1----MOSI----PB13
RES—復(fù)位(低電平有效)—PB12
DC---數(shù)據(jù)和命令控制管腳—PB1
CS---片選引腳-----PA7
微型直流電機(jī): PB8
紫光燈: PB9
LED硬件連接: PB5 PE5
KEY硬件連接:PE3 PE4
*/
#define ESP8266_WIFI_AP_SSID "CMCC-Cqvn" //將要連接的路由器名稱 --不要出現(xiàn)中文、空格等特殊字符
#define ESP8266_AP_PASSWORD "99pu58cb" //將要連接的路由器密碼
//騰訊物聯(lián)網(wǎng)服務(wù)器的設(shè)備信息
#define MQTT_ClientID "6142CX41XESmartAgriculture"
#define MQTT_UserName "6142CX41XESmartAgriculture;12010126;HUA2G;1624271589"
#define MQTT_PassWord "a8aadebe9721f70e6f9e14fe56ff1d2b5cac9625fa1f96af2f0e0098597fe78b;hmacsha256"
//訂閱與發(fā)布的主題
#define SET_TOPIC "$thing/down/property/6142CX41XE/SmartAgriculture" //訂閱
#define POST_TOPIC "$thing/up/property/6142CX41XE/SmartAgriculture" //發(fā)布
char mqtt_message[200];//上報(bào)數(shù)據(jù)緩存區(qū)
char OLED_ShowBuff[100];
u8 ESP8266_Stat=0;
/*
函數(shù)功能: 溫濕度\光強(qiáng)度顯示
*/
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);
}
/*
函數(shù)功能: ESP8266顯示頁面
*/
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");
//顯示字符串
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()
{
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();
KEY_Init();
IIC_Init();
//OLED初始化
OLED_Init(0xc8,0xa1); //OLED顯示屏初始化--正常顯示;
//清屏
OLED_Clear(0);
USART1_Init(115200);
TIMER1_Init(72,20000); //超時(shí)時(shí)間20ms
USART3_Init(115200);//串口-WIFI
TIMER3_Init(72,20000); //超時(shí)時(shí)間20ms
Init_SHT30();
USART1_Printf("正在初始化WIFI請稍等.\n");
if(ESP8266_Init())
{
ESP8266_Stat=1;
USART1_Printf("ESP8266硬件檢測錯(cuò)誤.\n");
}
else
{
//非加密端口
USART1_Printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode(ESP8266_WIFI_AP_SSID,ESP8266_AP_PASSWORD,"106.55.124.154",1883,1));
}
//2. MQTT協(xié)議初始化
MQTT_Init();
//3. 連接騰訊云IOT服務(wù)器
while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord))
{
USART1_Printf("服務(wù)器連接失敗,正在重試...\n");
delay_ms(500);
}
USART1_Printf("服務(wù)器連接成功.\n");
//3. 訂閱主題
if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
{
USART1_Printf("主題訂閱失敗.\n");
}
else
{
USART1_Printf("主題訂閱成功.\n");
}
while(1)
{
//按鍵可以測試開鎖和關(guān)鎖
key=KEY_Scan(0);
if(key==1)
{
//清屏
OLED_Clear(0);
//翻頁
if(page>=1)
{
page=0;
}
else
{
page++;
}
LED1=!LED1; //LEd狀態(tài)燈
}
else if(key==2)
{
LED1=!LED1; //LEd狀態(tài)燈
time_cnt=0;
//電機(jī)狀態(tài)改變
MOTOR_DEV=!MOTOR_DEV;
//電機(jī)狀態(tài)
motor_state=MOTOR_DEV;
//補(bǔ)光燈
LIGHT_DEV=!LIGHT_DEV;
}
//微信小程序開鎖方式: 接收WIFI返回的數(shù)據(jù)
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
//向串口打印微信小程序返回的數(shù)據(jù)
for(i=0;i5)
{
//使用字符串查找函數(shù)
if(strstr((char*)&USART3_RX_BUFFER[5],""motor":1"))
{
LED1=0; //亮燈
MOTOR_DEV=1; //開電機(jī)
motor_state=1;
}
else if(strstr((char*)&USART3_RX_BUFFER[5],""motor":0"))
{
LED1=1; //滅燈
MOTOR_DEV=0; //關(guān)電機(jī)
motor_state=0;
}
}
USART3_RX_CNT=0;
USART3_RX_FLAG=0;
}
//定時(shí)與保持與微信小程序的同步--1秒一次
delay_ms(10);
time_cnt++;
if(time_cnt==50)
{
time_cnt=0;
//狀態(tài)燈 --表示程序還活著
LED2=!LED2;
//讀取光強(qiáng)度
light=Read_BH1750_Data();
//讀取溫濕度
SHT3x_ReadData(&Humidity,&Temperature);
humi=Humidity;
temp=Temperature;
//上傳數(shù)據(jù)
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);
//根據(jù)濕度自動(dòng)灌溉
if(humi<50.0) //小于50自動(dòng)灌溉
{
motor_state=1; //電機(jī)狀態(tài)更新
MOTOR_DEV=1; //開電機(jī)
}
}
//OLED顯示屏
if(page==0)
{
ShowTemperatureAndHumidity(temp,humi,light);
}
else if(page==1)
{
ESP8266_ShowPageTable();
}
}
}
;i++)>
6.2 mqtt.c 代碼
#include "mqtt.h"
u8 *mqtt_rxbuf;
u8 *mqtt_txbuf;
u16 mqtt_rxlen;
u16 mqtt_txlen;
u8 _mqtt_txbuf[256];//發(fā)送數(shù)據(jù)緩存區(qū)
u8 _mqtt_rxbuf[256];//接收數(shù)據(jù)緩存區(qū)
typedef enum
{
//名字 值 報(bào)文流動(dòng)方向 描述
M_RESERVED1 =0 , // 禁止 保留
M_CONNECT , // 客戶端到服務(wù)端 客戶端請求連接服務(wù)端
M_CONNACK , // 服務(wù)端到客戶端 連接報(bào)文確認(rèn)
M_PUBLISH , // 兩個(gè)方向都允許 發(fā)布消息
M_PUBACK , // 兩個(gè)方向都允許 QoS 1消息發(fā)布收到確認(rèn)
M_PUBREC , // 兩個(gè)方向都允許 發(fā)布收到(保證交付第一步)
M_PUBREL , // 兩個(gè)方向都允許 發(fā)布釋放(保證交付第二步)
M_PUBCOMP , // 兩個(gè)方向都允許 QoS 2消息發(fā)布完成(保證交互第三步)
M_SUBSCRIBE , // 客戶端到服務(wù)端 客戶端訂閱請求
M_SUBACK , // 服務(wù)端到客戶端 訂閱請求報(bào)文確認(rèn)
M_UNSUBSCRIBE , // 客戶端到服務(wù)端 客戶端取消訂閱請求
M_UNSUBACK , // 服務(wù)端到客戶端 取消訂閱報(bào)文確認(rèn)
M_PINGREQ , // 客戶端到服務(wù)端 心跳請求
M_PINGRESP , // 服務(wù)端到客戶端 心跳響應(yīng)
M_DISCONNECT , // 客戶端到服務(wù)端 客戶端斷開連接
M_RESERVED2 , // 禁止 保留
}_typdef_mqtt_message;
//連接成功服務(wù)器回應(yīng) 20 02 00 00
//客戶端主動(dòng)斷開連接 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)
{
//緩沖區(qū)賦值
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);
//無條件先主動(dòng)斷開
MQTT_Disconnect();
delay_ms(100);
MQTT_Disconnect();
delay_ms(100);
}
/*
函數(shù)功能: 登錄服務(wù)器
函數(shù)返回值: 0表示成功 1表示失敗
*/
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;
//可變報(bào)頭+Payload 每個(gè)字段包含兩個(gè)字節(jié)的長度標(biāo)識
DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);
//固定報(bào)頭
//控制報(bào)文類型
mqtt_txbuf[mqtt_txlen++] = 0x10; //MQTT Message Type CONNECT
//剩余長度(不包括固定頭部)
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 );
//可變報(bào)頭
//協(xié)議名
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
//協(xié)議級別
mqtt_txbuf[mqtt_txlen++] = 4; // MQTT Protocol version = 4 對于 3.1.1 版協(xié)議,協(xié)議級別字段的值是 4(0x04)
//連接標(biāo)志
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心跳包 ?;顣r(shí)間
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;i++)usart1_printf("%#x>
本項(xiàng)目完整代碼下載地址:https://download.csdn.net/download/xiaolong1126626497/18973282
審核編輯:符乾江?
-
STM32
+關(guān)注
關(guān)注
2264文章
10854瀏覽量
354311 -
智慧農(nóng)業(yè)
+關(guān)注
關(guān)注
4文章
777瀏覽量
19791
發(fā)布評論請先 登錄
相關(guān)推薦
評論