2023-12-11 14:21:55 [显示全部楼层]
12600浏览
查看: 12600|回复: 5

[M10项目] 物联网农业土壤养分和气象站监测系统

[复制链接]

物联网农业土壤养分和气象站监测系统

前言

为监测户外和大棚的作物生长环境,我设计了一个物联网农业监测系统,使用Unihiker作为主要的监测核心,并结合了RS485土壤传感器,温湿度传感器,CO2传感器,环境光传感器等,采集不同节点的土壤养分,包括温湿度、PH和氮磷钾数据,同时采集空气二氧化碳、温湿度,环境光等的数据,同时还配备了摄像头,对作物的成长进行拍摄。Unihiker通过无线WIFI将数据上传至Lattepanda的本地服务器,我们可以使用Flask Web网页端查看数据,如果需要还可以对作物进行实时的监测。这个系统不仅记录大棚温室的环境数据,我还设立了一个Unihiker室外气象站,实时监测户外的重要环境参数,包括风向、风速、温度、气压和雨量。所有上传云端的数据,可以提供实时分析土壤养分、环境光照和环境参数的数据支持,以及为今后的智能农业发展提供数据标记和学习的基础。整体程序使用Python编写,具有自动运行和断网自动重连等功能。Lattepanda服务器可以显示不同节点的在线状态和数据,如果有节点出现问题,会显示节点不在线,方便及时维护。

利用此系统,我们可以更好地检测、控制、研究育种和植物生长。结合本地监测数据,实时掌握大棚内环境参数和图像,进行数据的采集、数据处理、数据可视化、数据分析等环节,为今后科学化育种育苗栽种进行合理方案设计。

物联网农业土壤养分和气象站监测系统图1

物联网农业土壤养分和气象站监测系统图2

物联网农业土壤养分和气象站监测系统图3

硬件清单

  1. 土壤氮磷钾传感器 x5
  2. Lattepanda 3 delta x1
  3. Unihiker x6
  4. 二氧化碳传感器 SEN0536 x3
  5. 环境光传感器 SEN0540 x3
  6. 气象站 SEN0186 x1
  7. 485转UART模块 DFR0845 x5
  8. 温湿度传感器 SEN0334 x1
  9. Unihiker扩展板 MBT0008 x6
  10. Power Adapter FIT0639 x6
  11. SCI x 6
  12. WIFI 监控摄像头 x1
  13. 摄像头 x5
  14. 路由器 x1
  15. 防水箱体 x6
  16. 电源转接模块 x 6

功能

  • 实时监测大棚内“一米田”内主要环境指标(土壤参数:土壤温湿度、土壤pH、土壤营养盐,环境参数:二氧化碳浓度 、温湿度、光照强度)。
  • 苗情监测:图像采集按时自动发送命令远程拍照,自动展示最新作物苗情图片。
  • 气象站监测:实时监测大棚外气象情况(风向、风速、温度、气压和雨量)。
  • 将监测到的数据在云端显示。
  • 离线节点设备在线预警。

物联网农业土壤养分和气象站监测系统图4

方案拓扑图

Unihikerx行空板作为主要的监测核心,并结合了RS485土壤传感器,I2C 温湿度传感器,I2C CO2传感器,I2C 环境光传感器等,采集不同节点的土壤养分,包括温湿度、PH和氮磷钾数据,同时采集空气二氧化碳、温湿度,环境光等的数据,同时还配备了USB摄像头连接Unihiker行空板,对作物的成长进行拍摄。各个节点的Unihiker和Lattepanda都在同一个局域网下,Unihiker通过无线WIFI将数据上传至Lattepanda的本地服务器。

在气象站节点中,Unihiker通过UART通讯收集气象站数据。

物联网农业土壤养分和气象站监测系统图5

重要技术指标

  1. 土壤传感器:用于检测土壤养分数据

    • 土壤温湿度,PH值,氮磷钾数据
  2. Lattepanda 3 delta:用做本地服务器

    • 处理器: Intel®赛扬®N5105
    • CPU: 2.0~2.9GHz,四核,四线程
    • GPU: Intel®UHD显卡(频率:450 - 800MHz)
    • 内存:LPDDR4 8GB 2933MHz
    • 存储:64GB eMMC V5.1
  3. Unihiker:用做每个节点的主控

    • CPU: 国产 4核 1.2GHz
    • 内存: 512MB DDR3
    • 硬盘: 16GB eMMC
    • 内置操作系统:Debian
    • Wi-Fi:  2.4G
    • 蓝牙:  4.0
    • 实体按键:Home按键,A/B按键
    • 幕:2.8寸240*320 TFT彩屏
    • 供电: Type-C 5V供电
    • 工作电压: 3.3V
    • 最大工作电流: 2000mA
    • 接口:
      > USB  Type-C 1
      > USB  TYPE-A 1
      > microSD卡接口 1
      > 3Pin I/O 4  (其中支持3路PWM 2路ADC)
      > 4Pin I2C 2

流量和存储估算

按每个节点每5分钟上传一次数据(含图片数据),每个节点数据约为1kb,每张JPG图片约为30kb,图片文件可以直接保存在Lattepanda上,节点数据保存在服务器的Siot数据库中,如果有额外内存需求,可以考虑Lattepanda增加内存条。

硬件连接

1. 以节点1土培生菜为例,节点1-节点5接线相同

物联网农业土壤养分和气象站监测系统图6

USB摄像头和行空板的USB连接。

RS485土壤传感器,485转UART模块(DFR0845)和Uihiker扩展板(MBT0008)连接方式如下表。485转UART模块和土壤传感器之间使用接线柱连接较牢固,485转UART模块和Uihiker扩展板使用杜邦线连接,建议使用热熔胶二次固定,防止电线松动。

物联网农业土壤养分和气象站监测系统图7

SCI,传感器(SEN0536,SEN0540 ,SEN0334)和Uihiker连接方式如图:

物联网农业土壤养分和气象站监测系统图8

2.气象站节点

气象站(SEN0186)和 Uihiker扩展板(MBT0008)连接方式如下表,使用杜邦线连接,建议使用热熔胶二次固定,防止电线松动。

物联网农业土壤养分和气象站监测系统图9

3. 供电:

使用FIT0639和电源转接模块,给Uihiker和扩展板(MBT0008)整体供电。

在LP服务器搭建环境:

安装服务器程序Siot

  1. 下载windows版本的SIoT解压,双击start SIoT.bat即可启动SIoT,启动之后会弹出命令窗口启动服务器。

物联网农业土壤养分和气象站监测系统图10

  1. 在浏览器输入 127.0.0.1:8080 即可打开网页端口,登录账号为siot,密码为dfrobot,打开后可以新建Topic或查看消息。

物联网农业土壤养分和气象站监测系统图11

安装Web应用框架Flask

  1. windows安装python3.7,下载网页:

  2. Python安装flask库

物联网农业土壤养分和气象站监测系统图12

  1. 访问项目网址下载代码(见第六节),并运行Flask程序
    cd flask-demo 
    flask-start.py

物联网农业土壤养分和气象站监测系统图13

  1. 网址输入访问http://127.0.0.1:5000/index(需要先启动Siot V2,才可以使用这个Flask Web),在这个网页中,你可以通过上方的按钮选择查看节点的传感器数据。

物联网农业土壤养分和气象站监测系统图14

路由器设置

在lattepanda网页登录路由器页面设置,固定Lattepanda、六个Unihiker的IP。

物联网农业土壤养分和气象站监测系统图15

代码:

1. Unihiker 以节点1 土培生菜为例

(请开启Unihiker开机自启动设置)

# -*- coding: utf-8 -*-
import time
from dfrobot_rp2040_sci import *
from pinpong.board import Board, UART
import serial 
import time
import siot
import os
from unihiker import GUI
import requests
import base64 
import cv2

Board("").begin()  #初始化,选择板型,不输入板型则进行自动识别
SCI1 = DFRobot_RP2040_SCI_IIC(addr=0x21)
u_gui=GUI()
#硬串口1 P0-RX P3-TX
uart1 = UART() 
# ser = serial.Serial("/dev/ttyUSB0",115200,timeout=0.5)
#初始化串口 baud_rate 波特率, bits 数据位数(8/9) parity奇偶校验(0 无校验/1 奇校验/2 偶校验) stop 停止位(1/2)
uart1.init(baud_rate = 9600, bits=8, parity=0, stop = 1) 

soil_tem_text=u_gui.draw_text(text="soil temperature:NAN",x=0,y=0,font_size=16, color="#0000FF")
soil_hum_text=u_gui.draw_text (text="soil humidity:NAN",x=0,y=30,font_size=16, color="#0000FF")
soil_ph_text=u_gui.draw_text(text="soil ph:NAN",x=0,y=60,font_size=16, color="#0000FF")
soil_N_text=u_gui.draw_text(text="soil N:NAN",x=0,y=90,font_size=16, color="#0000FF")
soil_P_text=u_gui.draw_text(text="soil P:NAN",x=0,y=120,font_size=16, color="#0000FF")
soil_K_text=u_gui.draw_text(text="soil K:NAN",x=0,y=150,font_size=16, color="#0000FF")
CO2_text = u_gui.draw_text(text="CO2:NAN",x=0,y=180,font_size=16, color="#0000FF")
status_text = u_gui.draw_text(text="01_status:NAN",x=0,y=270,font_size=16, color="#0000FF")
air_tem_text=u_gui.draw_text(text="air temperature:NAN",x=0,y=210,font_size=16, color="#0000FF")
air_hum_text=u_gui.draw_text(text="air humidity:NAN",x=0,y=240,font_size=16, color="#0000FF")
#lux_text=u_gui.draw_text(text="light lux:NAN",x=0,y=270,font_size=16, color="#0000FF")
while SCI1.begin() != 0:
    print("Initialization Sensor Universal Adapter Board failed.")
    time.sleep(1)
print("Initialization Sensor Universal Adapter Board done.")

#发送给传感器的指令
buf = [0x02, 0x03, 0x00, 0x00, 0x00, 0x0A, 0xC5,0xFE]

#返回指令 04传感器地址;03功能码;14数据长度;'00', 'e7'温度;'00', '00'湿度;00 00 空白;'00', '28'ph;'00', '00', '00', '00', '00', '00'氮磷钾;'00', '00', '00', '00'空白;'25', '80'波特率9600;25,b2校验和
#['04', '03', '14', '00', 'e7', '00', '00', '00', '00', '00', '28', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '25', '80', '25', 'b2']
def calc_crc(string):
    #print(string)
    #data = bytearray.fromhex(string)

    data =  ['{:02x}'.format(i) for i in string]
    #print(data)
    data = " ".join(data)
    data = data.replace('0x','')
    global data2
    data2 = data
    print(data2)
    data = bytearray.fromhex(data)

    crc = 0xFFFF
    for pos in data:
        crc ^= pos
        for i in range(8):
            if ((crc & 1) != 0):
                crc >>= 1
                crc ^= 0xA001
            else:
                crc >>= 1
    return hex(((crc & 0xff) << 8) + (crc >> 8))

def send_photos():

    photos_path = '/root/photos'
    photos_path_list = os.listdir(photos_path)
    photos_path_list.sort(reverse=False)
    photos_quan = len(photos_path_list)

    photos_count = photos_quan+1
    print("count:"+str(photos_count))
    cap = cv2.VideoCapture(0) 
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)  #设置摄像头图像宽度
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) #设置摄像头图像高度
    cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)     #设置OpenCV内部的图像缓存,可以极大提高图像的实时性。

    ret, frame = cap.read()
    if ret == True:
        cv2.imwrite(photos_path+'/Frame'+ str(photos_count) +'.jpg', frame)
        print("save photo!")
    cap.release()

    with open(photos_path+'/Frame'+ str(photos_count) +'.jpg',"rb") as f: 
    # b64encode是编码,b64decode是解码 
        data = base64.b64encode(f.read())
        src = "data:image/{ext};base64,{data}".format(ext='jpg', data=str(data))
        #print(src)
        #print(len(src))

        siot.publish_save(topic="siot/节点1/image", data=src)
        siot.publish_save(topic="siot/image", data=src)
        print("photos send ok")
        f.close()
        status_text.config(text="04_status: photo send ok",x=0,y=290)
        photos_count = int(photos_count) + 1

flag = 1
count=0

while True:
    air_tem_value=SCI1.get_value0("Temp_Air")
    air_tem_t = "Temp_Air: "+str(air_tem_value)+"℃"
    air_tem_text.config(text=air_tem_t,x=0,y=210)
    air_hum_value=SCI1.get_value0("Humi_Air")
    air_hum__t = "Humi_Air: "+str(air_hum_value)+"%RH"
    air_hum_text.config(text=air_hum__t,x=0,y=240)

    print("-----------write buf-----------")
    uart1.write(buf)
    time.sleep(1)
    count=0
    while uart1.any()==0:
        print("any:"+str(count))
        count=count+1
        if count>10:
            break
        time.sleep(0.1)

    while uart1.any()>0:
        print("while2:"+str(uart1.any()))
        #print(uart1.read(uart1.any()))
        time.sleep(0.01)
        if uart1.read(1)[0] == 0x02:
            print("11")
            time.sleep(0.01)   
            if uart1.read(1)[0] == 0x03:       
                time.sleep(0.01)  
                print("while2:"+str(uart1.any()))
                data = uart1.read(23) 
                data.insert(0,0x02)
                data.insert(1,0x03)
                #print(data)
                crc = calc_crc((data))
                #print(data[11],data(12))
                print("crc="+str(crc))

                if crc == '0x0':
                    print(data2)
                    data3 = data2.split()
                    #print(str(data3[10])+str(data3[11]))

                    soil_tem = int(str(data3[3])+str(data3[4]),16)/10
                    soil_ph = int(str(data3[9])+str(data3[10]),16)/10
                    soil_hum = int(str(data3[5])+str(data3[6]),16)/10
                    soil_N = int(str(data3[11])+str(data3[12]),16)
                    soil_P = int(str(data3[13])+str(data3[14]),16)
                    soil_K = int(str(data3[15])+str(data3[16]),16)

                    soil_ph_t = "soil_ph:"+ str(soil_ph)
                    soil_ph_text.config(text= soil_ph_t ,x=0,y=60)
                    soil_hum_t = "soil_hum: "+str(soil_hum)+"%"
                    soil_hum_text.config(text= soil_hum_t ,x=0,y=30)
                    soil_tem_t = "soil_tem:"+str(soil_tem)+"℃"
                    soil_tem_text.config(text= soil_tem_t ,x=0,y=0)
                    soil_N_t = "soil_N: "+str(soil_N)+"mg/kg"
                    soil_N_text.config(text= soil_N_t ,x=0,y=90)
                    soil_P_t = "soil_P: "+str(soil_P)+"mg/kg"
                    soil_P_text.config(text= soil_P_t ,x=0,y=120)
                    soil_K_t = "soil_K: "+str(soil_K)+"mg/kg"
                    soil_K_text.config(text= soil_K_t ,x=0,y=150)

                    try :
                        my_variable = requests.get("http://10.1.2.3/wifi/status")
                        print(my_variable.text)
                        status = my_variable.text.split('"')[11]
                        print("wifi: "+status)

                        status_text.config(text="01_wifi:"+status,x=0,y=270)

                        siot.init(client_id="unihiker01",server="10.168.1.100",port=1883,user="siot",password="dfrobot")
                        siot.connect()
                        siot.loop()
                        siot.getsubscribe(topic="siot/节点1/土壤温度")
                        siot.getsubscribe(topic="siot/节点1/土壤湿度")
                        siot.getsubscribe(topic="siot/节点1/土壤pH")
                        siot.getsubscribe(topic="siot/节点1/土壤氮")
                        siot.getsubscribe(topic="siot/节点1/土壤磷")
                        siot.getsubscribe(topic="siot/节点1/土壤钾")
                        #siot.getsubscribe(topic="siot/节点1/二氧化碳")
                        siot.getsubscribe(topic="siot/节点1/空气温度")
                        siot.getsubscribe(topic="siot/节点1/空气湿度")
                        siot.getsubscribe(topic="siot/image")
                        siot.getsubscribe(topic="siot/节点1/image")

                        siot.publish_save(topic="siot/节点1/土壤温度", data=soil_tem)
                        siot.publish_save(topic="siot/节点1/土壤pH", data=soil_ph)
                        siot.publish_save(topic="siot/节点1/土壤湿度", data=soil_hum)
                        siot.publish_save(topic="siot/节点1/土壤氮", data=soil_N)
                        siot.publish_save(topic="siot/节点1/土壤磷", data=soil_P)
                        siot.publish_save(topic="siot/节点1/土壤钾", data=soil_K)
                        siot.publish_save(topic="siot/节点1/空气温度", data=air_tem_value)
                        siot.publish_save(topic="siot/节点1/空气湿度", data=air_hum_value)

                        if flag == 50:
                            flag = 0
                            send_photos()

                        print("send ok")
                        siot.stop()
                        status_text.config(text="01_status: data send ok",x=0,y=270)
                        time.sleep(3600)
                    except :        
                        print("wifi正在重连!")
                        status_text.config(text="wifi正在重连!",x=0,y=270)
                        my_variable = requests.get("http://10.1.2.3/wifi/connect?ssid=dfrobot&password=dfrobot2017") # ssid和password后面改为需要连接的wifi名字密码
                        print(my_variable.text)
                        time.sleep(60)
                        print("查看WiFi连接情况:")
                        my_variable = requests.get("http://10.1.2.3/wifi/status")
                        print(my_variable.text)
                        status = my_variable.text.split('"')[11]
                        print(status)
                        status_text.config(text="01_wifi:"+status,x=0,y=270)

2. Unihiker 气象站

# -*- coding: utf-8 -*-
import time
from pinpong.board import Board, UART
import siot
import os

Board("UNIHIKER").begin()  #初始化,选择板型,不输入板型则进行自动识别
#行空板硬串口1 P0-RX P3-TX
uart1 = UART()   
#初始化串口 baud_rate 波特率, bits 数据位数(8/9) parity奇偶校验(0 无校验/1 奇校验/2 偶校验) stop 停止位(1/2)
uart1.init(baud_rate = 9600, bits=8, parity=0, stop = 1) 
#uart1.init() #气象站波特率为9600
siot.init(client_id="hostclient01",server="10.1.2.3",port=1883,user="siot",password="dfrobot")
while True:
    databuffer = ""
    #print(len("c000s000g000t082r000p000h48b10022*3C"))默认字长
    buf = uart1.readline()
    #uart1.write(buf)
    #b = type(buf)
    #print(b)
    if buf is None:
        print("recv None")
    else:
        for i in buf:
            #print(i)
            a = chr(i)
            databuffer = databuffer + a

        length = len(databuffer)
        print(databuffer)
        if length == 38:  # 如果数据长度为38
            print("databuffer:",databuffer) # 打印显示数据串

            '''解析获取其中的风向数据'''
            try:
                WindDirection = int(databuffer[1:4])
            except:
                WindDirection = 0
            if 0 <= WindDirection and WindDirection < 22.5 or 337.5<=WindDirection and WindDirection < 360:
                WindDirection_dir = 'S'
            if 22.5 <= WindDirection and WindDirection < 67.5:
                WindDirection_dir = 'SW'
            if 67.5 <= WindDirection and WindDirection < 112.5:
                WindDirection_dir = 'W'
            if 112.5 <= WindDirection and WindDirection < 157.5:
                WindDirection_dir = 'NW'
            if 157.5 <= WindDirection and WindDirection < 202.5:
                WindDirection_dir = 'N'
            if 202.5 <= WindDirection and WindDirection < 247.5:
                WindDirection_dir = 'NE'
            if 247.5 <= WindDirection and WindDirection < 292.5:
                WindDirection_dir = 'E'
            if 292.5 <= WindDirection and WindDirection < 337.5:
                WindDirection_dir = 'SE'
            print("WindDirection:" +str(WindDirection) +" degree","WindDirection_dir:"+WindDirection_dir)

            '''解析获取其中的风速数据'''# 1英里每小时=1609.34米/3600秒=0.44703889m/s
            # 前一分钟的平均风速
            try:
                WindSpeedAverage = round(0.44704 * float(databuffer[5:8]),1)
            except:
                WindSpeedAverage = 0
            print("Average Wind Speed (One Minute):" + str(WindSpeedAverage) + "m/s  ")
            # 前五分钟的最大风速
            try:
                WindSpeedMax = round(0.44704 * float(databuffer[9:12]),1)
            except:
                WindSpeedMax = 0     
            print("Max Wind Speed (Five Minutes):" + str(WindSpeedMax) + "m/s") 

            '''解析其中的温度数据'''# 摄氏度=(华氏度-32)*5/9
            try:
                Temperature = round((float(databuffer[13:16]) - 32.00) * 5.00 / 9.00,2) 
            except:
                Temperature = 0
            print("Temperature:" + str(Temperature)+ "℃  ")   
            # print("Temperature:" + "{:.2f}".format(Temperature)+ "C  ")   

            '''解析其中的湿度数据'''
            try:
                Humidity = round(float(databuffer[25:27]) ,1)
            except:
                Humidity = 0
            print("Humidity:" + str(Humidity) +"%  ")

            '''解析其中的气压数据'''
            try:
                BarPressure = round(float(databuffer[28:33])/ 10.00,1)
            except:
                BarPressure = 0
            print("BarPressure:" + str(BarPressure)  + "hPa")

        else: # 如果长度不是38,那么就令数据为空
            databuffer = ""

    time.sleep(0.5)

3. Flask服务器程序

#  -*- coding: UTF-8 -*-
from flask import Flask,Response,render_template,request
flask_app = Flask(__name__)

# 事件回调函数
def rec_route_funca():
    print("b click")
    return "rount_func"
def rec_route_funcb():
    print("b click")
    return "b"
def rec_index():
    return render_template("test.html")

@flask_app.route('/index',methods=['GET','POST'])
def route_index():
    return rec_index()
flask_app.run(host='0.0.0.0', port=5000, threaded=True)

4. 服务器程序(保存图片,查询节点在线状态)

#  -*- coding: UTF-8 -*-

# MindPlus
# Python
import time
import siot
import os

ip = ['ping 10.168.1.114','ping 10.168.1.117','ping 10.168.1.118','ping 10.168.1.122','ping 10.168.1.115','ping 10.168.1.112']

# 事件回调函数
def on_message_callback(client, userdata, msg):
    global P1
    global N1
    global K1

    global P5
    global N5
    global K5

    global sendata1
    global sendata5
    global sendataw
    global sendata

    global weather_hum
    global weather_tem

    global indoor_hum
    global indoor_tem

    if (msg.topic.find("表格")!=-1):
        pass
    else:
        if (msg.topic.find("节点1/土壤氮")!=-1):
            N1 = msg.payload.decode()
            print(msg.topic)
            print(N1)
        if (msg.topic.find("节点1/土壤磷")!=-1):
            P1 = msg.payload.decode()
            print(msg.topic)
            print(P1)
        if (msg.topic.find("节点1/土壤钾")!=-1):
            K1 = msg.payload.decode()
            print(msg.topic)
            print(K1)

        status = ((not (P1 == 0)) and (not (N1 == 0)))

        if ((not (status == 0)) and (not (K1 == 0))):
            sendata1 = N1 +","+ P1 +","+ K1
            print(sendata1)
            siot.publish_save(topic="siot/节点1/氮磷钾总和表格", data=sendata1)

        if (msg.topic.find("节点5/土壤氮")!=-1):
            N5 = msg.payload.decode()
            print(msg.topic)
            print(N5)
        if (msg.topic.find("节点5/土壤磷")!=-1):
            P5 = msg.payload.decode()
            print(msg.topic)
            print(P5)
        if (msg.topic.find("节点5/土壤钾")!=-1):
            K5 = msg.payload.decode()
            print(msg.topic)
            print(K5)

        status = ((not (P5 == 0)) and (not (N5 == 0)))

        if ((not (status == 0)) and (not (K5 == 0))):
            sendata5 = N5 +","+ P5 +","+ K5
            print(sendata5)
            siot.publish_save(topic="siot/节点5/氮磷钾总和表格", data=sendata5)

        if (msg.topic.find("气象站/温度")!=-1):
            weather_tem = msg.payload.decode()
            print((str(msg.topic) + str(weather_tem)))
        if (msg.topic.find("气象站/湿度")!=-1):
            weather_hum = msg.payload.decode()
            print((str(msg.topic) + str(weather_hum)))

        if ((not (weather_hum == 0)) and (not (weather_tem == 0))):
            sendataw = weather_hum+ "," + weather_tem
            print(sendataw)
            siot.publish_save(topic="siot/气象站/温湿度表格", data=sendataw)

        if (msg.topic.find("节点1/温度")!=-1):
            weather_tem = msg.payload.decode()
            print((str(msg.topic) + str(weather_tem)))
        if (msg.topic.find("节点1/湿度")!=-1):
            weather_hum = msg.payload.decode()
            print((str(msg.topic) + str(weather_hum)))
        if ((not (indoor_hum == 0)) and (not (indoor_tem == 0))):
            sendata = indoor_hum+ "," + indoor_tem
            print(sendata)
            siot.publish_save(topic="siot/节点1/温湿度表格", data=sendata)

siot.init(client_id="",server="10.168.1.100",port=1883,user="siot",password="dfrobot")
siot.set_callback(on_message_callback)
siot.connect()
siot.loop()
P1 = 0
N1 = 0
K1 = 0

P5 = 0
N5 = 0
K5 = 0

weather_hum = 0
weather_tem = 0

indoor_tem = 0
indoor_hum = 0

siot.getsubscribe(topic="siot/节点1/温湿度表格")

siot.getsubscribe(topic="siot/气象站/温湿度表格")
siot.getsubscribe(topic="siot/气象站/温度")
siot.getsubscribe(topic="siot/气象站/湿度")

siot.getsubscribe(topic="siot/节点1/温度")
siot.getsubscribe(topic="siot/节点1/湿度")

siot.getsubscribe(topic="siot/devicestatus")

siot.getsubscribe(topic="siot/节点1/氮磷钾总和表格")
siot.getsubscribe(topic="siot/节点1/土壤氮")
siot.getsubscribe(topic="siot/节点1/土壤磷")
siot.getsubscribe(topic="siot/节点1/土壤钾")

siot.getsubscribe(topic="siot/节点5/氮磷钾总和表格")
siot.getsubscribe(topic="siot/节点5/土壤氮")
siot.getsubscribe(topic="siot/节点5/土壤磷")
siot.getsubscribe(topic="siot/节点5/土壤钾")

while True:
    outdev = 0
    online = 0
    for i in ip:
        result = os.popen(i)
        status = result.read()
        loc = "unreachable" in status
        print(loc)
        if loc != True:
            loc = status.find('Lost')
            loss_data = status[loc+7]

            if loss_data == '4':
                outdev = outdev+1
            else:
                online = online+1
        else:
            outdev = outdev+1

    output = str(online) + ','+ str(outdev)
    print("online,outdev:")
    print(output)
    siot.publish_save(topic="siot/devicestatus", data=output)
    print("send ok")
    time.sleep(100)

访问项目下载完整程序:https://github.com/polamaxu/AgriculturalSmartSystem

总结

该物联网农业监测系统能够稳定地检测土壤养分,包括温湿度、PH和氮磷钾数据,同时还能监测户外和大棚的作物生长环境。通过无线WIFI,将大棚环境和室外气象站的传感器数据和图片实时上传云端,提供土壤养分、环境光照、环境参数的实时分析,为家庭精准农业提供必要的数据支持。

FAQ

  1. Unihiker 一直显示wifi正在重连?
    观察屏幕是否循环显示wifi connected->wifi 正在重连。如果有,请重启lattepanda上的siot服务器。如果没有出现,请检查路由器是否正常。
  2. Unihiker 显示报错:runtimeerror:analog map retrieal time out.
    返回Unihiker 菜单页面,重新运行程序,如果还无法解决,可以刷处理器固件,方法:https://www.Unihiker.com/wiki/faq
  3. 如何远程监控各个行空板的屏幕?
    使用windows自带的远程软件remote desktop connection,填入行空的ip来访问
  4. 如何远程控制查看各个行空板的程序?
    使用mobaXterm.exe,选择行空对应的ip就可以打开行空板的系统运行命令行界面,账号是siot,密码是dfrobot。

JOVI  高级技师 来自手机

发表于 2023-12-12 08:56:13

学习
回复

使用道具 举报

DeadWalking  中级技师

发表于 2024-1-10 13:12:46

学习!!!
回复

使用道具 举报

福安2021  学徒

发表于 2024-3-14 22:36:03

有没有教程呢,关于行空板如何使用及硬件设备,有关这个项目的详细课程
回复

使用道具 举报

木子呢  管理员
 楼主|

发表于 2024-3-28 11:43:35

福安2021 发表于 2024-3-14 22:36
有没有教程呢,关于行空板如何使用及硬件设备,有关这个项目的详细课程

教程很多:https://mc.dfrobot.com.cn/featured/unihiker
回复

使用道具 举报

waynewan  见习技师

发表于 2024-6-19 10:17:03

#发送给传感器的指令
buf = [0x02, 0x03, 0x00, 0x00, 0x00, 0x0A, 0xC5,0xFE]  这是读的一个数据的值 吧  能说明一下吗谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail