数字农业管理系统是提供给农业大棚管理员的,通过传感器获取到的大棚环境状态可视化展示,从而对大棚作物的生长状态进行监控和管理的平台。

此系统主要分为两大部分,第一部分是获取大棚中与作物生长环境有关的一系列数据,以及对相应数据进行管理和可视化的监控平台,第二部分是给不同管理员之间提供的相互留言的留言板,以及高级管理者对所有管理员之间留言的查看与删除。

使用到的知识

1.B\S架构

BS即Browser/Server(浏览器/服务器)结构,就是只安装维护一个服务器(Server),而客户端选用浏览器(Browse)运行软件。B/S结构应用程序相对于传统的C/S结构应用程序就是一个特别大的进步。 B/S结构的重要特征就是分布性强、维护方便、开发简单并且共享性强、总体拥有费用低。但数据安全性问题、对服务器需要过高、数据传输速度慢、软件的个性化特征明显减少,这些缺点就是有目共睹的,难以完成传统形式下的特殊功能请求。比如通过浏览器实行大量的数据输入或实行报表的应答、专用性打印输出全部相对比较困难与不便。另外,完成复杂的应用构造有较大的困难。

2.Tomcat

Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。

3.Echart

ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖轻量级的矢量图形库 ZRender ,提供直观,交互丰富,可高度个性化定制的数据可视化图表。

4.qt

Qt使用标准的C++和特殊的代码生成扩展(称为元对象编译器(Meta Object Compiler, moc))以及一些。通过语言绑定,其他的编程语言也可以使用Qt。Qt  是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(Meta Object Compiler, moc))以及一些宏,Qt很容易扩展,并且允许真正地组件编程。优良的跨平台特性:、面向对象、丰富的 API。

1.登录

智慧农业体系架构 智慧农业基本框架_智慧农业体系架构

2.注册

 

智慧农业体系架构 智慧农业基本框架_服务器_02

3.进入功能界面

 

智慧农业体系架构 智慧农业基本框架_apache_03

智慧农业体系架构 智慧农业基本框架_apache_04

 

4.可视化功能

智慧农业体系架构 智慧农业基本框架_git_05

 

 

智慧农业体系架构 智慧农业基本框架_tomcat_06

 

智慧农业体系架构 智慧农业基本框架_git_07

 

智慧农业体系架构 智慧农业基本框架_服务器_08

 

智慧农业体系架构 智慧农业基本框架_服务器_09

智慧农业体系架构 智慧农业基本框架_git_10

智慧农业体系架构 智慧农业基本框架_tomcat_11

 

智慧农业体系架构 智慧农业基本框架_智慧农业体系架构_12

 

智慧农业体系架构 智慧农业基本框架_git_13

 

智慧农业体系架构 智慧农业基本框架_服务器_14

 

 

智慧农业体系架构 智慧农业基本框架_智慧农业体系架构_15

 

智慧农业体系架构 智慧农业基本框架_服务器_16

 

1.arduino及串口

实验目的

掌握传感器的使用方法,掌握Arduino的使用方法,掌握数据库的开发方法,提升产品设计与架构能力,掌握Arduino的串口等通信方法,提升面向对象编程能力.

实验器材:

Arduino UNO

DHT11 温湿度传感器

光敏电阻传感器

土壤湿度传感器

继电器*2

Win10主机,SQLserver数据库,Python3等开发软件

实验原理:

简述:读取数据->传输数据->自响应

包括基于Qt开发的本地显示软件以及Web显示功能

总体架构设计

Arduino+SQLServer+Web+Qt

#include <dht11.h>

#define DHT11_Output 5
#define Light_Output 4
#define Relay_INPUT1 6
#define Relay_INPUT2 7

#define MS_INPUTA PIN_A0
#define MS_INPUTD 3
class MyDigitalOutput{
  public:
    int Dpin;
    int state;

    MyDigitalOutput(int Dpin,int state=0):Dpin(Dpin){
      this->state = state;
      pinMode(Dpin,OUTPUT);
      digitalWrite(Dpin,this->state);
    }
    ~MyDigitalOutput(){}
    void Open(){
      this->state = 1;
      digitalWrite(Dpin,this->state);
    }
    void Close(){
      this->state = 0;
      digitalWrite(Dpin,this->state);
    }
};
class MyDigitalInput{
  public:
    int Dpin;
    MyDigitalInput(int Dpin):Dpin(Dpin){
      pinMode(Dpin,INPUT);
    }
    ~MyDigitalInput(){}
    bool DGet(){           //Bool
      return digitalRead(this->Dpin);   
    }
};
class MyAnalogInput{
  public:
    int Apin;
    MyAnalogInput(int Apin):Apin(Apin){
      pinMode(Apin,INPUT);
    }
    ~MyAnalogInput(){}
    double AGet(){
      return analogRead(Apin);
    }
};
//土壤湿度
class MyMoistureSensor:public MyAnalogInput,public MyDigitalInput{
  public:
    MyMoistureSensor(int Dpin,int Apin):MyDigitalInput(Dpin),MyAnalogInput(Apin){}
    ~MyMoistureSensor(){}
    double Moisture(){
      return 1-(AGet()-245)/(1023-245);
    }
};
//光照
class MyLightSensor:public MyDigitalInput{
  public:
    MyLightSensor(int pin):MyDigitalInput(pin){}
    ~MyLightSensor(){}
};
//温湿度方法
double Fahrenheit(double celsius){  //华氏度
  return 1.8 * celsius + 32;
}
class MyDHT11{
  public:
    dht11 equip;
    int   pin;
    
    MyDHT11(int pin):pin(pin){
      pinMode(pin,INPUT);
    }
    ~MyDHT11(){}

    int UpDate(){
      int state = equip.read(this->pin);
      return state;
    }

    double Temperature(){
      return (float)this->equip.temperature;
    }
    double Humidity(){
      return (float)this->equip.humidity;
    }
};

//MyRelay

class MyRelay:public MyDigitalOutput{
  public:
    MyRelay(int pin,int state=0):MyDigitalOutput(pin,state){}
    ~MyRelay(){};
};

void setup() {
  Serial.begin(9600);
  //pinMode(DHT11_Output,INPUT);
  //pinMode(Light_Output,INPUT);
}


void stdPrint(String key,double temp){
  Serial.print(key);
  Serial.print(":");
  Serial.print(temp);
  Serial.print(",");
}
void stdPrint(String key,String temp){
  Serial.print(key);
  Serial.print(":");
  Serial.print(temp);
  Serial.print(",");
}
void stdPrint(String key,bool temp){
  Serial.print(key);
  Serial.print(":");
  Serial.print(temp==false?0:1);
  Serial.print(",");
}

MyDHT11 dht(DHT11_Output);
MyLightSensor lightSensor(Light_Output);
MyRelay relay1(Relay_INPUT1);
MyRelay relay2(Relay_INPUT2);
MyMoistureSensor ms(MS_INPUTD,MS_INPUTA);
void loop() {
  // put your main code here, to run repeatedly:
  dht.UpDate();
  stdPrint("Temperature",dht.Temperature());
  stdPrint("Humidity",dht.Humidity());
  stdPrint("Light",lightSensor.DGet());
  stdPrint("Moisture",ms.Moisture());
  Serial.println("");
  /*
  Serial.println(dht.Temperature());
  Serial.println(dht.Humidity());

  Serial.println(lightSensor.DGet());
  Serial.println(ms.Moisture());
  Serial.println(ms.DGet());
  Serial.println(js);
  */
  
  if(ms.Moisture()<0.2){
    relay1.Open();
  }else{
    relay1.Close();
  }

  if(lightSensor.DGet()==true){
    relay2.Open();
  }else{
    relay2.Close();
  }
  delay(2000);
}
#include <dht11.h>

#define DHT11_Output 5
#define Light_Output 4
#define Relay_INPUT1 6
#define Relay_INPUT2 7

#define MS_INPUTA PIN_A0
#define MS_INPUTD 3
class MyDigitalOutput{
  public:
    int Dpin;
    int state;

    MyDigitalOutput(int Dpin,int state=0):Dpin(Dpin){
      this->state = state;
      pinMode(Dpin,OUTPUT);
      digitalWrite(Dpin,this->state);
    }
    ~MyDigitalOutput(){}
    void Open(){
      this->state = 1;
      digitalWrite(Dpin,this->state);
    }
    void Close(){
      this->state = 0;
      digitalWrite(Dpin,this->state);
    }
};
class MyDigitalInput{
  public:
    int Dpin;
    MyDigitalInput(int Dpin):Dpin(Dpin){
      pinMode(Dpin,INPUT);
    }
    ~MyDigitalInput(){}
    bool DGet(){           //Bool
      return digitalRead(this->Dpin);   
    }
};
class MyAnalogInput{
  public:
    int Apin;
    MyAnalogInput(int Apin):Apin(Apin){
      pinMode(Apin,INPUT);
    }
    ~MyAnalogInput(){}
    double AGet(){
      return analogRead(Apin);
    }
};
//土壤湿度
class MyMoistureSensor:public MyAnalogInput,public MyDigitalInput{
  public:
    MyMoistureSensor(int Dpin,int Apin):MyDigitalInput(Dpin),MyAnalogInput(Apin){}
    ~MyMoistureSensor(){}
    double Moisture(){
      return 1-(AGet()-245)/(1023-245);
    }
};
//光照
class MyLightSensor:public MyDigitalInput{
  public:
    MyLightSensor(int pin):MyDigitalInput(pin){}
    ~MyLightSensor(){}
};
//温湿度方法
double Fahrenheit(double celsius){  //华氏度
  return 1.8 * celsius + 32;
}
class MyDHT11{
  public:
    dht11 equip;
    int   pin;
    
    MyDHT11(int pin):pin(pin){
      pinMode(pin,INPUT);
    }
    ~MyDHT11(){}

    int UpDate(){
      int state = equip.read(this->pin);
      return state;
    }

    double Temperature(){
      return (float)this->equip.temperature;
    }
    double Humidity(){
      return (float)this->equip.humidity;
    }
};

//MyRelay

class MyRelay:public MyDigitalOutput{
  public:
    MyRelay(int pin,int state=0):MyDigitalOutput(pin,state){}
    ~MyRelay(){};
};

void setup() {
  Serial.begin(9600);
  //pinMode(DHT11_Output,INPUT);
  //pinMode(Light_Output,INPUT);
}


void stdPrint(String key,double temp){
  Serial.print(key);
  Serial.print(":");
  Serial.print(temp);
  Serial.print(",");
}
void stdPrint(String key,String temp){
  Serial.print(key);
  Serial.print(":");
  Serial.print(temp);
  Serial.print(",");
}
void stdPrint(String key,bool temp){
  Serial.print(key);
  Serial.print(":");
  Serial.print(temp==false?0:1);
  Serial.print(",");
}

MyDHT11 dht(DHT11_Output);
MyLightSensor lightSensor(Light_Output);
MyRelay relay1(Relay_INPUT1);
MyRelay relay2(Relay_INPUT2);
MyMoistureSensor ms(MS_INPUTD,MS_INPUTA);
void loop() {
  // put your main code here, to run repeatedly:
  dht.UpDate();
  stdPrint("Temperature",dht.Temperature());
  stdPrint("Humidity",dht.Humidity());
  stdPrint("Light",lightSensor.DGet());
  stdPrint("Moisture",ms.Moisture());
  Serial.println("");
  /*
  Serial.println(dht.Temperature());
  Serial.println(dht.Humidity());

  Serial.println(lightSensor.DGet());
  Serial.println(ms.Moisture());
  Serial.println(ms.DGet());
  Serial.println(js);
  */
  
  if(ms.Moisture()<0.2){
    relay1.Open();
  }else{
    relay1.Close();
  }//打开继电器一浇水

  if(lightSensor.DGet()==true){
    relay2.Open();
  }else{
    relay2.Close();
  }//打开继电器二开灯
  delay(2000);
}

ser.py 用于读串口数据并放入数据库中pymssql,pymssql是python用来连接Microsoft SQL Server的一个工具库 (package)

pymssql的使用十分简单,基本就如下几个步骤

  1. 创建链接:使用connect()创建连接并获取Connection对象
  2. 交互操作:获取Connection对象的Cursor对象,然后使用Cursor对象的各种方法与数据库进行交互
  3. 关闭链接
import serial  # 导入串口包
import time  # 导入时间包


ser = serial.Serial("COM8",9600,timeout = 5)  
ser.flushInput()  # 清空缓冲区


import pymssql,sys,os,time,datetime,random
 
SSMSCONFIG = {
    "host":'127.0.0.1',
    "user":'sa',
    "password":'111',
    "database":"DigitalAgriculture",
    "charset":'GBK'
}
class SQLServerCore(object):
    def __init__(self,host='127.0.0.1',user='sa',password='111',database='test',charset='utf8',workPath='./'):
        self.connection = pymssql.connect(  host=host,
                                            user=user,
                                            password=password,
                                            database=database,
                                            charset=charset)
        self.BETA = True
        self.cursor = self.connection.cursor()

        self.stderr = sys.stderr
        self.errFile = open(workPath+'errFile.txt','a') 

    def insertMany(self,table,args:list,datas):
        args = ','.join(args)
        cmd = "INSERT INTO {} VALUES ({})".format(table,args)
        self.BetaPrintCmd(cmd)
        try:
            self.cursor.executemany(cmd,datas)
            self.connection.commit()
        except BaseException as e:
            self.BetaPrintError(e)
        '''
        args: 
            (%s,%s,%d,%f)
        datas:
            [(1, 'John Smith', 'John Doe'),
            (2, 'Jane Doe', 'Joe Dog'),
            (3, 'Mike T.', 'Sarah H.')]
        '''
    def execute(self,cmd):
        try:
            self.BetaPrintCmd(cmd)
        except BaseException as e:
            self.BetaPrintError(e)
        self.cursor.execute(cmd)

    def get(self,table,args:list):
        args = ','.join(args)
        cmd = 'select {} from {}'.format(args,table)
        self.BetaPrintCmd(cmd)
        self.cursor.execute(cmd)
        return self.cursor.fetchall()
        
    def getAll(self,table):
        self.cursor.execute('select * from {}'.format(table))
        return self.cursor.fetchall()
    
    def __del__(self):
        self.connection.close()
        sys.stderr = self.stderr
        self.errFile.close()

    def BetaPrintCmd(self,cmd):
        if self.BETA:
            print(">>> 执行了命令: {}".format(cmd))
    def BetaPrintError(self,e:BaseException):
        s = ">>> 发生了错误: {}".format(e)
        if self.BETA:
            print(s)
        self.BetaErrWrite(s)
    def BetaErrWrite(self,err):
        sys.stderr = self.errFile
        sys.stderr.write(err+'\n')
        sys.stderr = self.stderr

if __name__=='__main__':
    myServer = SQLServerCore(**SSMSCONFIG)
    while True:
        count = ser.inWaiting() # 获取串口缓冲区数据
        if count !=0 :
            time.sleep(0.2)  # 延时0.1秒,免得CPU出问题
            recv = ser.read(ser.in_waiting).decode("utf-8")  # 读出串口数据,数据采用gbk编码
            print(time.time()," ---  recv --> ", recv)  # 打印一下子

            temp = []
            datas = recv.lstrip().rstrip().split(',')
            for data in datas:
                #print(data)
                try:
                    temp.append(float(data.split(':')[1]))
                except:
                    pass
            print(temp)

            print('输入一条数据')
            timeStamp = time.time()
            dateArray = datetime.datetime.fromtimestamp(timeStamp)
            timer = dateArray.strftime("%Y-%m-%d %H:%M:%S")
            try:
                data = ("'UNO-0000'","'Arduino'",str(int(timeStamp)),"'{}'".format(timer),str(temp[0]),str(temp[1]),str(temp[3]))
                print('insert one message!\n')
            except Exception as e:
                print(e)
            myServer.execute('INSERT INTO dbo.STDRecord1 VALUES({});'.format(','.join(data)))
            myServer.connection.commit()

解析串口传过来的数据

import pymssql,sys,os,time,datetime,random,serial
 
SSMSCONFIG = {
    "host":'127.0.0.1',
    "user":'sa',
    "password":'111',
    "database":"DigitalAgriculture",
    "charset":'utf8'
}
class SQLServerCore(object):
    def __init__(self,host='127.0.0.1',user='sa',password='111',database='test',charset='utf8',workPath='./'):
        self.connection = pymssql.connect(  host=host,
                                            user=user,
                                            password=password,
                                            database=database,
                                            charset=charset)
        self.BETA = True
        self.cursor = self.connection.cursor()

        self.stderr = sys.stderr
        self.errFile = open(workPath+'errFile.txt','a') 

    def insertMany(self,table,args:list,datas):
        args = ','.join(args)
        cmd = "INSERT INTO {} VALUES ({})".format(table,args)
        self.BetaPrintCmd(cmd)
        try:
            self.cursor.executemany(cmd,datas)
            self.connection.commit()
        except BaseException as e:
            self.BetaPrintError(e)
        '''
        args: 
            (%s,%s,%d,%f)
        datas:
            [(1, 'John Smith', 'John Doe'),
            (2, 'Jane Doe', 'Joe Dog'),
            (3, 'Mike T.', 'Sarah H.')]
        '''
    def execute(self,cmd):
        try:
            self.BetaPrintCmd(cmd)
        except BaseException as e:
            self.BetaPrintError(e)
        self.cursor.execute(cmd)

    def get(self,table,args:list):
        args = ','.join(args)
        cmd = 'select {} from {}'.format(args,table)
        self.BetaPrintCmd(cmd)
        self.cursor.execute(cmd)
        return self.cursor.fetchall()
        
    def getAll(self,table):
        self.cursor.execute('select * from {}'.format(table))
        return self.cursor.fetchall()
    
    def __del__(self):
        self.connection.close()
        sys.stderr = self.stderr
        self.errFile.close()

    def BetaPrintCmd(self,cmd):
        if self.BETA:
            print(">>> 执行了命令: {}".format(cmd))
    def BetaPrintError(self,e:BaseException):
        s = ">>> 发生了错误: {}".format(e)
        if self.BETA:
            print(s)
        self.BetaErrWrite(s)
    def BetaErrWrite(self,err):
        sys.stderr = self.errFile
        sys.stderr.write(err+'\n')
        sys.stderr = self.stderr

myServer = SQLServerCore(**SSMSCONFIG)
ser      = serial.Serial("COM8",9600,5)
ser.flushInput()
ser.flushOutput()
while True:
    print('输入一条数据')
    recv = ""
    while True:
        if ser.inWaiting()>0:
            recv += ser.read().decode('utf-8')
        elif recv.endswith('\n'):
            break
    #recv = recv.lstrip(',').split(',')
    print(">>>接收到的数据:",recv)
    timeStamp = time.time()
    dateArray = datetime.datetime.fromtimestamp(timeStamp)
    timer = dateArray.strftime("%Y-%m-%d %H:%M:%S")
    data = ("'UNO-0000'","'Arduino'",str(int(timeStamp)),"'{}'".format(timer),recv[1],recv[3],recv[7])
    myServer.execute('INSERT INTO dbo.STDRecord1 VALUES({});'.format(','.join(data)))
    myServer.connection.commit()
    time.sleep(1)

2.echartCore.py

from pyecharts import options as opts
from pyecharts.charts import Bar, Grid, Line, Liquid, Page, Pie
from pyecharts.commons.utils import JsCode
from pyecharts.components import Table
from pyecharts.faker import Faker
def bar_base(v:list,name:str) ->Bar:
    bar=(
        Bar()
        .add_xaxis([int(len(v)-x) for x in range(len(v))])
        .add_yaxis(name,v)
        .set_global_opts(
            title_opts=opts.TitleOpts(title=name),
            datazoom_opts=[opts.DataZoomOpts(), opts.DataZoomOpts(type_="inside")]
            )
        )
    return bar

def table_base(headers=[],rows=[],title:str="default") -> Table:
    table = Table()
    
    table.add(headers, rows).set_global_opts(
        title_opts=opts.ComponentTitleOpts(title=title)
    )
    return table

def water(val1,title:str) ->Liquid:
    c=(Liquid()
    .add('water',[val1,val1+0.05],center=['20%','30%'])
    .set_global_opts(title_opts=opts.TitleOpts(title=title))
    )
    return c

def page_simple_layout(widgets:list,saveFile="./data_visiable.html"):
    page = Page(layout=Page.SimplePageLayout)
    page.add(
        *widgets
    )
    page.render(saveFile)

visiable1.py

#本脚本针对特定EId设备进行可视化
import EchartCore
import SQLServerCore

myServer = SQLServerCore.SQLServerCore(**SQLServerCore.SSMSCONFIG)

myServer.execute("SELECT TOP(10) EId,R1Temperature,R1Humidity,R1SoilMoisture\
                FROM UserTable1\
                WHERE EId = 'VE1-0001'\
                ORDER BY R1FlagTime DESC\
")
data = myServer.cursor.fetchall()
#print(data)
temperature = EchartCore.bar_base([data[i][1] for i in range(len(data))],'Temperature')
humidity = EchartCore.bar_base([data[i][2] for i in range(len(data))],'Humidity')
soilMoisture = EchartCore.bar_base([data[i][3] for i in range(len(data))],'SoilMoisture')

nowHumidity = EchartCore.water(data[0][2],'NowHumidity')
nowSoilMoisture = EchartCore.water(data[0][3],'NowSoilMoisture')

EchartCore.page_simple_layout([nowHumidity,nowSoilMoisture,temperature,humidity,soilMoisture],"../visiable1.html")

visiable2.py

#本脚本针对天气进行可视化
import EchartCore
import SQLServerCore

myServer = SQLServerCore.SQLServerCore(**SQLServerCore.SSMSCONFIG)

myServer.execute("\
    SELECT * FROM Weather\
    ORDER BY WFlagTime DESC\
")
data = myServer.cursor.fetchall()

table = EchartCore.table_base(['请求时间戳','数据更新时间','地区','天气','温度'],data,"天气情况")
EchartCore.page_simple_layout([table],"../visiable2.html")

 

5.2设计体会

         经过这次数字农业管理系统设计。在这次课程设计过程中,我深刻认识到学习一门课程并不只是单纯的仅仅学好这门课程。现实需求的实现往往极其复杂,所涉及到的技术单纯一门学科无论学的再好也远远不能满足,真正需要的能力是把多学科的融会贯通,将多学科结合起来使用,比如在本次实验中,涉及到了传感器的应用,ARDUNIO开发板的编程,串口通信技术,数据库设计,web网页开发等一系列多学科技术。

       “众人拾柴火焰高”,在这短短的时间里,要想实现对我来说这样一个复杂的综合性系统,仅仅靠自己的力量是远远不够的。团队的力量是可畏的,通过我们小组成员的分工合作,我深刻感受到团队合作的力量,将整个系统层层分工下来,每个人负责一部分功能的实现,大家还可以相互交流,相互帮助,大大提升了开发的进度和速度。因此要善于团队合作,善于利用别人的智慧,这才是真正的智慧。

         “实践出真知”,理论课学的再好,如果不能将它付诸实践,一切都是空把式。我深刻意识到自己动手能力的欠缺,在时间工程中,常常脑子中有相关的理论知识,却不知道如何在项目中使用。只有多多动手,将课本中的知识应用到实践中去,才能更加深刻的理解,才能转换成真正有用的知识,只会纸上谈兵,是无法体现一个人的价值与能力的。

         “不能则学,不知则问”,要想实现一个完整的项目,课本中的知识是远远不够的,比如我们的json解析天气数据,比如我们课本中未提及的CSS具体开发,都需要我们上网查询资料。面对自己能力的不足,一定要勤学好问,不懂就查,不懂就问,学无止境,不要以为自己学会课本中的知识就学得够多了,实际上,这是远远不足的,远远不够的。只有勤学好问,才能不断进步,才能真正提升自己的能力。