How to Build a DIY Smart Greenhouse (NPK) and Weather Station with Unihiker & LattePanda

0 14063 Medium

Introduction

In order to monitor the growth environment of crops outdoors and in greenhouses, I have designed an IoT agricultural monitoring system. The system utilizes Unihikers as the main board, combined with RS485 soil sensors, temperature and humidity sensors, CO2 sensors, UV light sensors, etc., collecting soil nutrients at different nodes, including soil temperature, humidity, PH, and NPK. At the same time, the system collects data on air temperature, humidity, CO2, and UV light. Additionally, cameras are also equipped for taking photos of crop growth.

 

Unihikers wirelessly upload the data to the local server of Lattepanda through WiFi. We can view real-time data using the Flask web. Moreover, the system not only records environmental data in greenhouses but also includes an Unihiker outdoor weather station, which monitors essential environmental data outdoors in real-time, including wind direction, wind speed, temperature, humidity, pressure, and rainfall.

All of the data uploaded to the cloud can support real-time analysis of soil nutrients, UV light, and other environmental data. It can also provide data labeling and learning foundations for future AI development. The program is written in Python, with functions such as automatically running script on startup and automatic network reconnection. The Lattepanda server can display the online status and data of different nodes.

By utilizing this system, we can effectively detect, control, and research plant growth. With the integration of local monitoring data, we can continuously monitor the parameters and imagery of the environment inside the greenhouse, and carry out data processing, visualization, and analysis, which will provide a foundation for designing rational solutions for scientific breeding and planting in the future.

 

                                                                               Monitoring lettuce in the greenhouse

 

                                                                                                weather station

 

                                                                              RS485 sensor monitors soil data

 

                                                                                        A monitoring node

 

                                                                         A monitoring node for greenhouse

 

                                                                           Remote viewing data on LattePanda

 

 

HARDWARE LIST
5 RS485 Soil Sensor(N&P&K)
1 LattePanda 3 Delta 864
6 Unihiker
3 Gravity: I2C SCD41 Infrared CO2 Sensor
3 Gravity: LTR390 UV Light Sensor
1 Weather Station Kit with Anemometer/Wind Vane/Rain Bucket
5 Gravity: Active Isolated RS485 to UART Signal Adapter Module
1 Gravity: SHT31-F Digital Temperature and Humidity Sensor
6 IO Extender for micro:bit / UNIHIKER
6 5V@3A USB Power Supply (EU Standard)
6 SCI
5 USB camera
1 Router
6 Waterproof enclosure

 

 

System functions:

- Real-time monitoring of major environmental indicators in the "one-meter field"(soil parameters: soil temperature and humidity, soil pH, NPK; environmental data: CO2, temperature and humidity, UV light).

- Crop monitoring: automatic image capture and save, automatically displaying the latest crop images.

- Weather station monitoring: real-time monitoring of outside weather conditions (wind direction, wind speed, temperature, air pressure, and rainfall).

- Displaying the data in the cloud.

- Online warning for offline node.

 

 

 

 

Solution diagram

Unihiker, the central monitoring core, is equipped with RS485 soil sensors, I2C temperature and humidity sensors, I2C CO2 sensors, and I2C ambient light sensors. These sensors collect soil nutrient data including temperature, humidity, PH, N, P, and K from different nodes. They also collect data on air CO2 concentration, temperature, humidity, and ambient light. Additionally, with the USB camera connected to the Unihiker, images of crop growth can be captured. The Unihiker and Lattepanda of each node are connected to the same local network. Unihiker wirelessly uploads data to Lattepanda's local server via WiFi. Unihiker collects weather station data through UART communication at the weather station node.

 

 

Power consumption estimate

 

 

Data usage estimate

Assuming data is uploaded every 5 minutes from each node (including image data). The data size for each node is 1KB and each image is 30 KB.

31KB ×288=8.928 MB

 

 

 

Connection:

1.  Taking a node as an example, the wiring for nodes 1-5 is the same.

 

 

The connection between the RS485 soil sensor, 485 to UART module (DFR0845), and Uihiker shield(MBT0008) is as follows:

 

 

The connection between SCI, sensors (SEN0536, SEN0540, SEN0334) and Uihiker is as follows:

 

 

2. The connection between the weather station (SEN0186) and Uihiker shield (MBT0008) is as follows:

 

 

3. Power:

Use FIT0639 and the power adapter module to supply power to Uihiker and shield (MBT0008).

Build the environment on the LP server:

 

 

 

Build the environment on the LP server:

Siot

SIoT is an open-source and free MQTT server software that allows you to easily create a local Internet of Things (IoT) server. SIoT consists of an MQTT server, a database, and a web interface. The MQTT server is responsible for data forwarding and storage decisions, while the web interface provides a convenient way to view data and perform simple program testing. SIoT supports operating systems such as Win10, Win7, Mac, Linux, and Debian.

1. Download the Windows version of SIoT and unzip it. Double-click start SIoT.bat to start SIoT. After startup, a command window will start the server.

 

 

2. Enter 127.0.0.1:8080 in the browser to open the web. The login account is "siot" and the password is "dfrobot". After opening, you can create a new topic or view data.

 

Flask

Flask is a popular web framework for building web applications in Python. It is known for its simplicity and minimalistic design, providing developers with the tools they need to create web applications quickly and efficiently.

1. Install python3.7: https://www.python.org/downloads/windows/

2. Install the flask

 

 

3. Download the code (see Section 6), and run flask-start.py

 

 

 

4. Enter the URL to access 

http://127.0.0.1:5000/index (you need to start Siot before you can use this Flask Web). On this web page, you can select to view the sensor data of the node through the button above.

 

 

Configure the router

Please log in to the router webpage on Lattepanda and set up the fixed IP addresses for Lattepanda and the Unihikers.

 

 

 

Code:
1. Unihiker node 1~5

CODE
# -*- 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
#Unihiker Initialize
Board("").begin()  

# SCI Initialize
SCI1 = DFRobot_RP2040_SCI_IIC(addr=0x21)
while SCI1.begin() != 0:
    print("Initialization Sensor Universal Adapter Board failed.")
    time.sleep(1)
print("Initialization Sensor Universal Adapter Board done.")

#UART P0-RX P3-TX
uart1 = UART() 
#Initialize UART 
uart1.init(baud_rate = 9600, bits=8, parity=0, stop = 1) 

#Unihiker GUI Initialize
u_gui=GUI()
#GUI setting
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")

#command sent to soil sensor
buf = [0x02, 0x03, 0x00, 0x00, 0x00, 0x0A, 0xC5,0xFE]

#sensor default return command 
#['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']

#Calculating CRC checksum
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))
    #USB camera setting
    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)     
    
    ret, frame = cap.read()
    if ret == True:
        #save photos on Unihiker
        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))
        
        # Send base64 buf of the photos to the server
        siot.publish_save(topic="siot/node1/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

count = 0
while True:
    #refresh GUI
    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 to soil sensor-----------")
    uart1.write(buf)
    time.sleep(1)
    count=0
    #"If there is data on the serial port"
    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)
        # This sensor's address is 0x02, pls review the wiki for more details.
        if uart1.read(1)[0] == 0x02:
            print("11")
            time.sleep(0.01)   
            #This sensor's default code is 0x03, pls review the wiki for more details.
            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 data read from soil sensor
                    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)
                    
                    #refresh GUI 
                    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 :
                        #get wifi's status
                        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 and connect to the LP server. The server's IP is 10.168.1.100. 
                        #pls note that each unihiker's client_id is different. 
                        siot.init(client_id="unihiker01",server="10.168.1.100",port=1883,user="siot",password="dfrobot")
                        siot.connect()
                        siot.loop()
                        #siot subscribe the topics
                        siot.getsubscribe(topic="siot/node1/soiltemperture")
                        siot.getsubscribe(topic="siot/node1/soilhum")
                        siot.getsubscribe(topic="siot/node1/soilpH")
                        siot.getsubscribe(topic="siot/node1/soilN")
                        siot.getsubscribe(topic="siot/node1/soilP")
                        siot.getsubscribe(topic="siot/node1/soilK")
                        #siot.getsubscribe(topic="siot/node1/二氧化碳")
                        siot.getsubscribe(topic="siot/node1/airtemper")
                        siot.getsubscribe(topic="siot/node1/airhum")
                        #siot.getsubscribe(topic="siot/image")
                        siot.getsubscribe(topic="siot/node1/image")

                        siot.publish_save(topic="siot/node1/soiltemperture", data=soil_tem)
                        siot.publish_save(topic="siot/node1/soilpH", data=soil_ph)
                        siot.publish_save(topic="siot/node1/soilhum", data=soil_hum)
                        siot.publish_save(topic="siot/node1/soilN", data=soil_N)
                        siot.publish_save(topic="siot/node1/soilP", data=soil_P)
                        siot.publish_save(topic="siot/node1/soilK", data=soil_K)
                        siot.publish_save(topic="siot/node1/airtemper", data=air_tem_value)
                        siot.publish_save(topic="siot/node1/airhum", data=air_hum_value)
                        print("send ok")
                        siot.stop()
                        
                        status_text.config(text="01_status: data send ok",x=0,y=270)
                        time.sleep(3600)
                    except :        
                        print("wifi reconnect!")
                        status_text.config(text="wifi reconnect!",x=0,y=270)
                        #"ssid=dfrobot&password=dfrobot2017"  wifi ssid and wifi password
                        my_variable = requests.get("http://10.1.2.3/wifi/connect?ssid=dfrobot&password=dfrobot2017")
                        print(my_variable.text)
                        time.sleep(60)
                        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 weatherstation

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

#Unihiker Initialize
Board("UNIHIKER").begin()  

#UART P0-RX P3-TX ,pls note that weather station's baud_rate is 9600
uart1 = UART()   
uart1.init(baud_rate = 9600, bits=8, parity=0, stop = 1) 
#siot init and connect to the LP server. The server's IP is 10.168.1.100. 
#pls note that each unihiker's client_id is different. 
siot.init(client_id="weatherstation",server="10.168.1.100",port=1883,user="siot",password="dfrobot")
while True:
    databuffer = ""
    #print(len("c000s000g000t082r000p000h48b10022*3C"))default buffer
    #read uart data
    buf = uart1.readline()

    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:  
            print("databuffer:",databuffer)
            
            '''get wind direction'''
            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)
            
            '''get wind speed'''
            # The average wind speed of the previous minute.
            try:
                WindSpeedAverage = round(0.44704 * float(databuffer[5:8]),1)
            except:
                WindSpeedAverage = 0
            print("Average Wind Speed (One Minute):" + str(WindSpeedAverage) + "m/s  ")
            # The maximum wind speed of the previous five minutes.
            try:
                WindSpeedMax = round(0.44704 * float(databuffer[9:12]),1)
            except:
                WindSpeedMax = 0     
            print("Max Wind Speed (Five Minutes):" + str(WindSpeedMax) + "m/s") 
             
            '''get temperture'''
            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  ")   
            
            '''get humidity'''
            try:
                Humidity = round(float(databuffer[25:27]) ,1)
            except:
                Humidity = 0
            print("Humidity:" + str(Humidity) +"%  ")
            
            '''get pressure'''
            try:
                BarPressure = round(float(databuffer[28:33])/ 10.00,1)
            except:
                BarPressure = 0
            print("BarPressure:" + str(BarPressure)  + "hPa")
            
        else: 
            databuffer = ""

    time.sleep(0.5)

 

 

3. Flask server(Web)

CODE
#  -*- 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. Python runs on Lattepanda(save pictures, query the online status of nodes)

CODE
#  -*- coding: UTF-8 -*-
import time
import siot
import os

#all IP addresses of unihikers
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']

#when get data from unihikers
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("form")!=-1):
        pass
    else:
        if (msg.topic.find("node1/soilN")!=-1):
            N1 = msg.payload.decode()
            print(msg.topic)
            print(N1)
        if (msg.topic.find("node1/soilP")!=-1):
            P1 = msg.payload.decode()
            print(msg.topic)
            print(P1)
        if (msg.topic.find("node1/soilK")!=-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/node1/NPKform", data=sendata1)


        if (msg.topic.find("node5/soilN")!=-1):
            N5 = msg.payload.decode()
            print(msg.topic)
            print(N5)
        if (msg.topic.find("node5/soilP")!=-1):
            P5 = msg.payload.decode()
            print(msg.topic)
            print(P5)
        if (msg.topic.find("node5/soilK")!=-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/node5/NPKform", data=sendata5)

        if (msg.topic.find("weatherstation/temper")!=-1):
            weather_tem = msg.payload.decode()
            print((str(msg.topic) + str(weather_tem)))
        if (msg.topic.find("weatherstation/humi")!=-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/weatherstation/temper_humi_form", data=sendataw)
            
        if (msg.topic.find("node1/temper")!=-1):
            weather_tem = msg.payload.decode()
            print((str(msg.topic) + str(weather_tem)))
        if (msg.topic.find("node1/humi")!=-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/node1/temper_humi_form", 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/node1/temper_humi_form")

siot.getsubscribe(topic="siot/weatherstation/temper_humi_form")
siot.getsubscribe(topic="siot/weatherstation/temper")
siot.getsubscribe(topic="siot/weatherstation/humi")

siot.getsubscribe(topic="siot/node1/temper")
siot.getsubscribe(topic="siot/node1/humi")

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

siot.getsubscribe(topic="siot/node1/NPKform")
siot.getsubscribe(topic="siot/node1/soilN")
siot.getsubscribe(topic="siot/node1/soilP")
siot.getsubscribe(topic="siot/node1/soilK")

siot.getsubscribe(topic="siot/node5/NPKform")
siot.getsubscribe(topic="siot/node5/soilN")
siot.getsubscribe(topic="siot/node5/soilP")
siot.getsubscribe(topic="siot/node5/soilK")

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(outdevice)
    print("online,outdevice:")
    print(output)
    siot.publish_save(topic="siot/devicestatus", data=output)
    print("send ok")
    time.sleep(100)

Download the full code: 

https://github.com/polamaxu/AgriculturalSmartSystem

 

 

 

Data analysis

Through careful analysis of outdoor temperature and humidity data collected by weather station sensors, we can observe some interesting trends. It is obvious from the table that the outdoor temperature has experienced a series of fluctuations and has shown an overall downward trend. At the same time, the humidity changes are also quite eye-catching, fluctuating up and down in the range of 40% to 80%. This humidity change may be related to the drop in temperature. As the temperature drops, water vapor in the air begins to condense. , causing the humidity to rise. We also noticed brief drops in humidity at certain moments, possibly due to water vapor condensing and falling as rain, reducing the amount of moisture in the air.

Reviewing recent meteorological records, we can confirm that these humidity changes are closely related to precipitation events. The occurrence time of precipitation is basically consistent with the period of reduced humidity, which further confirms our speculation.

 

 

 

 

 

Summary

This IoT agriculture monitoring system is designed to effectively detect soil nutrients like temperature, humidity, and PH, as well as nitrogen, phosphorus, and potassium levels in a stable manner. It can also continuously monitor the growth environment for crops both outdoors and the inside greenhouse. By leveraging wireless WIFI, sensor data and images from the greenhouse and outdoor weather station can be uploaded to the cloud in real-time, enabling the provision of real-time analysis of soil nutrients, environmental lighting, and environmental parameters, which are essential in providing accurate data support for agriculture.These precious data provided by weather stations and greenhouses provide a solid scientific ba.sis for us to foresee and respond to the possible impact of climate change on agricultural cultivation, thus greatly improving the stability and sustainability of agricultural production.

 

 

 

FAQ

1. The screen of Unihiker keeps showing that the wifi is reconnecting.

If the screen displays a loop of 'wifi connected' followed by 'wifi reconnecting,' please restart the Siot server on the LattePanda. If this does not appear, please check if the router is functioning properly.

 

2. Unihiker shows the error: runtime error: analog map retrieval time out.

Return to the Unihiker menu page and run the program again. If the problem still persists, you can flash the processor firmware 

https://www.Unihiker.com/wiki/faq

 

3. How to remotely monitor the screen of each line board?

Use the software remote desktop connection and fill in the IP to access.

 

4. How to remotely control and view the programs of each Unihiker?

Use mobaXterm, and select the IP corresponding to Unihiker to open Unihiker's system. The account is "siot", and the password is "dfrobot".

License
All Rights
Reserved
licensBg
0