目录
前言
本次项目通过各类传感器与2560进行通讯后,通过串口的形式发送至8266的方式实现超远程传输,因为目前的slq数据库只能够通过局域网传输,而通常在大棚,农场等地基本上不会去专门配置wifi传输的,也可以使用lora模块使用,后续可以考虑开发。
在项目开始之前,需要准备SGP30二氧化碳检测模块,DHT11温湿度检测模块,以及光敏传感器,我这边光敏直接选用adc读取的光敏传感器,还有土壤湿度传感器。开发板为esp8266以及mega2560并且最后的成品大概是下面这样子
中间应该还有2560但是暂时没有插上去
mqtt的配置
mqtt我使用的是emqx,主要是,emqx是免费的,然后目前可以通过emqx的公用服务器进行传输,不过考虑到安全问题还是采用了在emqx上配置的私人服务器开发,首先先进入网址EMQX: 大规模分布式 MQTT 消息服务器
试用即可没有账号就先注册一个
进入这个界面以后
可以看个人选择,我这边选择用免费的,直接免费开启
emqx我使用的是杭州(阿里云)的服务器,首次开启需要等待2分钟
在这个界面上认证你先添加认证账号密码随便,但你自己要记住,后面会用到,并且认证设备要添加两个,一个给esp8266,一个给python,python后面作为mqtt转到slq也要用到一个认证
SQL数据库的配置
SQL我使用的是腾讯云的数据库
腾讯云slq具体的注册方法我这边我不做过多讲诉,具体可以参考下面这篇文章,目前在校大学生开通这个还是蛮划算的我直接开通了一年,这波算是阿里与腾讯的伟大结合(dog)
https://blog.csdn.net/qq_41188880/article/details/113876439
开通好了进入以下界面
选择新建库名字自己取,我取名字叫greenhouses
然后再选择slq窗口
选择好刚建好的数据库输入以下代码执行
-- `greenhouses`
create table if not exists `greenhouses`
(
`id` int not null comment 'id',
`humidity` varchar(256) not null comment '湿度',
`temperature` varchar(256) not null comment '温度',
`Soilmoisture` varchar(256) not null comment '土壤湿度',
`CO2` varchar(256) not null comment 'co2浓度',
`TVOC` varchar(256) not null comment 'TVOC浓度',
`illumination` varchar(256) not null comment '光照',
`timedata` varchar(256) not null comment '时间'
) comment '`greenhouses`';
代码的含义是创建一个包含温湿度等数据的表,表名和注释都有了自己取琢磨琢磨吧,至此,slq的数据库搭建就算是结束了。
esp8266的代码编写
esp8266书写mqtt传输数据的代码配合下面的python代码,mega2560代码以及原理图使用,不用原理图的pcb直接接也是没有问题的,esp8266的配置和esp8266的PubSubClient库下载我就不讲述了,这是在太so easy了不会的参考下面的文章
Arduino IDE傻瓜式离线安装ESP8266/ESP32固件支持包_esp8266支持包_perseverance52的博客-CSDN博客
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// WiFi
const char *ssid = "输入wifi账号,你后面直接上5g模块就不用局域网了"; // wifi账号
const char *password = "wifi密码"; // wifi密码
// MQTT Broker
const char *mqtt_broker = "x1e3aa1a.ala.cn-hangzhou.emqxsl.cn"; //
const char *topic = "Greenhouses"; // 主题自己定后面主题要和python代码的相同
const char *mqtt_username = "pythonmqtt"; // 此处填写之前两个在emqx中认证过的其中一个账号
const char *mqtt_password = "12345678"; // 这里填写认证的密码
const int mqtt_port = 8883; // port of MQTT over TLS/SSL
// init wifi client
WiFiClientSecure espClient;
PubSubClient client(espClient);
/*
The common fingerprints of EMQX broker, for reference only.
If you are not using EMQX Cloud Serverless or public EMQX broker,
you need to calculate the sha1 fingerprint of your server certificate
and update the 'fingerprint' variable below.
*/
// 1. fingerprint of public emqx broker. Host: broker.emqx.io
//const char* fingerprint = "B6 C6 FF 82 C6 59 09 BB D6 39 80 7F E7 BC 10 C9 19 C8 21 8E";
// 2. fingerprint of EMQX Cloud Serverless. Host: *.emqxsl.com
// const char* fingerprint = "42:AE:D8:A3:42:F1:C4:1F:CD:64:9C:D7:4B:A1:EE:5B:5E:D7:E2:B5";
// 3. fingerprint of EMQX Cloud Serverless. Host: *.emqxsl.cn
const char* fingerprint = "7E:52:D3:84:48:3C:5A:9F:A4:39:9A:8B:27:01:B1:F8:C6:AD:D4:47";//这里是证书认证,私人mqtt需要,公用的可以不用
void setup() {
Serial.begin(9600);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to the WiFi network");
// set fingerprint
espClient.setFingerprint(fingerprint);
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
while (!client.connected()) {
String client_id = "esp8266clientrust";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to the mqtt broker\n", client_id.c_str());
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
Serial.println("Connected to MQTT broker.");
} else {
Serial.print("Failed to connect to MQTT broker, rc=");
Serial.print(client.state());
Serial.println(" Retrying in 5 seconds.");
delay(5000);
}
}
// publish and subscribe
//client.publish(topic, "hello emqx"); // publish message to the topic
//client.subscribe(topic); // subscribe message from the topic
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char) payload[i]);
}
Serial.println();
Serial.println("-----------------------");
}
void uart(){
char c[50];
if(Serial.available()>0){
String uart=Serial.readString();//串口接收到什么就对mqtt发送什么
//if(uart=='t'){
//int t=Serial.parseInt();
Serial.println(uart);
String data=String(uart);
char *p;
p=strcpy(c,data.c_str());
client.publish(topic,p,false);
}
}
void loop() {
/*if (!client.connected()) {
reconnect();
}*/
client.loop();
uart();
}
python代码的编写
python代码主要是mqtt转slq用,并且发送时间数据到slq中
下载python相关库方式你就自己去研究了这里也不做过多的阐述,esp8266开始运行后再启动python代码,可以使用树莓派作为python运行代码的控制板,python代码也只是作为中转站这个无所谓。
import random
from paho.mqtt import client as mqtt_client
import re
import mysql.connector
import time
# 连接MySQL数据库
db = mysql.connector.connect(
host = "这里填写腾讯云slq的连接地址" , # 服务器地址
port = 22100, # 端口
user = "root" , # 填自己的用户名默认是root
passwd = "123456" , # slq数据库的密码
buffered = True,
database="greenhouses"
)
broker = '填自己的mqtt连接地址'
port = 8883
topic = "Greenhouses"#这里是主题,要个esp8266主题一致
client_id = f'python-mqtt-{random.randint(0, 100)}'
username = 'test'#这里填写mqtt认证的另一个账号
password = '123456'#这里填写密码
x=0
a=[]
cursor = db.cursor()
def extract_numbers(text):
numbers = re.findall(r'\d+', text)
return [int(num) for num in numbers]
def connect_mqtt():
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to MQTT Broker!")
else:
print("Failed to connect, return code %d\n", rc)
# Set Connecting Client ID
client = mqtt_client.Client(client_id)
# Set CA certificate
client.tls_set(ca_certs='D:\农业大棚\emqxsl-ca.crt')
client.username_pw_set(username, password)
client.on_connect = on_connect
client.connect(broker, port)
return client
def subscribe(client: mqtt_client):
def on_message(client, userdata, msg):
print(msg.payload.decode())
t=msg.payload.decode()
if t:
number = re.findall("\d+",t) # 输出结果为列表
print(number)
timedata=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
humidity=number[0]+""
temperature=number[1]+"'c"
Soilmoisture=number[2]+"%"
CO2=number[3]+"ppm"
TVOC=number[4]+"mg"
illumination=number[5]+"lx"
sql = "INSERT INTO greenhouses (humidity,temperature,Soilmoisture,CO2,TVOC,illumination,timedata) " \
"VALUES (%s, %s, %s, %s, %s, %s, %s)"
values = (humidity,temperature,Soilmoisture,CO2,TVOC,illumination,timedata)
cursor.execute(sql, values)
#提交事务
db.commit()
print("土壤数据添加成功!")
#numer=湿度,温度,土壤湿度,co2,tvoc,光照,时间
#num=extract_numbers(msg.payload.decode())
#print(num)
client.subscribe(topic)
client.on_message = on_message
def run():
client = connect_mqtt()
subscribe(client)
client.loop_forever()
if __name__ == '__main__':
run()
各类传感器配合mega2560开发板代码
原本打算通过esp8266直接获取数据并传输,但是8266的adc读取不太准确,因此选用了2560,不过也可以换成stm32会更划算一些主要是2560有多的,其中包含了dht11库以及sgp30库自行下载吧
#include "dht112.h"
#define DHT_PIN 2
#include "SGP30.h"
#define SCL 21 //这里可以自己设
#define SDA 20 //定义SCL,SDA引脚
SGP mySGP30;
u16 CO2Data,TVOCData;//定义CO2浓度变量与TVOC浓度变量
u32 sgp30_dat;
DHT11 dht11(DHT_PIN);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
mySGP30.SGP30_Init();
mySGP30.SGP30_Write(0x20,0x08);
sgp30_dat = mySGP30.SGP30_Read();//读取SGP30的值
CO2Data = (sgp30_dat & 0xffff0000) >> 16;
TVOCData = sgp30_dat & 0x0000ffff;
while(CO2Data == 400 && TVOCData == 0) //设定初始值
{
mySGP30.SGP30_Write(0x20,0x08);
sgp30_dat = mySGP30.SGP30_Read();//读取SGP30的值
CO2Data = (sgp30_dat & 0xffff0000) >> 16;//取出CO2浓度值
TVOCData = sgp30_dat & 0x0000ffff; //取出TVOC值
Serial.println("正在检测中...");
delay(500);
}
}
void loop() {
// put your main code here, to run repeatedly:
//--------------------------空气温湿度
int ret = dht11.read();
if(ret == DHTLIB_ERROR_CHECKSUM) {
Serial.println("(E) Checksum failed");
return;
}
else if(ret == DHTLIB_ERROR_TIMEOUT) {
Serial.println("(E) Read time out");
return;
}
//----------------------------------土壤湿度
float P=analogRead(A0);
float a=(1-(P-380)/643)*100;
//Serial.print(P);
//----------------------------------空气co2浓度
mySGP30.SGP30_Write(0x20,0x08);
sgp30_dat = mySGP30.SGP30_Read();//读取SGP30的值
CO2Data = (sgp30_dat & 0xffff0000) >> 16;//取出CO2浓度值
TVOCData = sgp30_dat & 0x0000ffff;
//----------------------------------光照强度
int s=analogRead(A1);
int b=(1024-s)/3;
Serial.print("H");//湿度
Serial.print((float)dht11.getHumidity(), 2);
Serial.print("T");//温度
Serial.print((float)dht11.getTemperature(), 2);
Serial.print("P");//土壤湿度
Serial.print((float)a,3);
Serial.print("C");//co2值
Serial.print(CO2Data,DEC);
Serial.print("V:");//TVOC值
Serial.print(TVOCData,DEC);
Serial.println(b);
//Serial.println("%");
delay(1000);//380=100
//1023=0
//6.43
}
原理图
原理图使用嘉立创画的可以直接打板