Python实战--智能农业监控与管理系统

引言

随着人口增长和气候变化的挑战,传统农业面临着提高产量、降低成本、减少环境影响的多重压力。智能农业作为现代农业的发展方向,通过物联网(IoT)、大数据分析、人工智能等技术,为农业生产提供了全新的解决方案。

本文将介绍如何使用Python构建一个完整的智能农业监控与管理系统,该系统能够实时监测农作物生长环境,自动化管理灌溉系统,并通过数据分析为农业决策提供科学依据。

系统架构设计

整体架构

我们的智能农业系统采用分层架构设计,包含以下核心组件:

  • 数据采集层:传感器网络(温度、湿度、土壤pH值、光照强度等)
  • 数据处理层:Python后端服务,负责数据清洗、存储和分析
  • 控制执行层:自动化设备控制(灌溉系统、通风设备等)
  • 用户界面层:Web仪表板和移动端应用
  • 数据存储层:时序数据库和关系型数据库

技术选型

  • 后端框架:Flask/FastAPI
  • 数据库:PostgreSQL + InfluxDB(时序数据)
  • 数据分析:Pandas, NumPy, Scikit-learn
  • 可视化:Matplotlib, Plotly
  • 硬件通信:pySerial, MQTT
  • 任务调度:APScheduler
  • 前端:Bootstrap + Chart.js

核心功能实现

1. 传感器数据采集模块

import json
import time
import serial
from datetime import datetime
from dataclasses import dataclass
from typing import Dict, List
import paho.mqtt.client as mqtt

@dataclass
class SensorData:
    """传感器数据结构"""
    timestamp: datetime
    sensor_id: str
    temperature: float
    humidity: float
    soil_moisture: float
    ph_value: float
    light_intensity: float

class SensorCollector:
    """传感器数据采集器"""
    
    def __init__(self, serial_port: str = '/dev/ttyUSB0', mqtt_broker: str = 'localhost'):
        self.serial_port = serial_port
        self.mqtt_broker = mqtt_broker
        self.serial_conn = None
        self.mqtt_client = None
        self.setup_connections()
    
    def setup_connections(self):
        """初始化连接"""
        try:
            # 串口连接
            self.serial_conn = serial.Serial(
                port=self.serial_port,
                baudrate=9600,
                timeout=1
            )
            
            # MQTT连接
            self.mqtt_client = mqtt.Client()
            self.mqtt_client.on_connect = self.on_mqtt_connect
            self.mqtt_client.on_message = self.on_mqtt_message
            self.mqtt_client.connect(self.mqtt_broker, 1883, 60)
            
        except Exception as e:
            print(f"连接初始化失败: {e}")
    
    def collect_sensor_data(self) -> SensorData:
        """采集传感器数据"""
        try:
            if self.serial_conn and self.serial_conn.in_waiting:
                raw_data = self.serial_conn.readline().decode('utf-8').strip()
                data_dict = json.loads(raw_data)
                
                return SensorData(
                    timestamp=datetime.now(),
                    sensor_id=data_dict.get('sensor_id'),
                    temperature=float(data_dict.get('temperature', 0)),
                    humidity=float(data_dict.get('humidity', 0)),
                    soil_moisture=float(data_dict.get('soil_moisture', 0)),
                    ph_value=float(data_dict.get('ph_value', 7)),
                    light_intensity=float(data_dict.get('light_intensity', 0))
                )
        except Exception as e:
            print(f"数据采集错误: {e}")
            return None
    
    def on_mqtt_connect(self, client, userdata, flags, rc):
        """MQTT连接回调"""
        if rc == 0:
            print("MQTT连接成功")
            client.subscribe("sensors/+/data")
    
    def on_mqtt_message(self, client, userdata, msg):
        """MQTT消息回调"""
        try:
            data = json.loads(msg.payload.decode())
            self.process_mqtt_data(data)
        except Exception as e:
            print(f"MQTT消息处理错误: {e}")

2. 数据存储与管理

import sqlite3
from sqlalchemy import create_engine, Column, Integer, Float, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS

Base = declarative_base()

class SensorReading(Base):
    """传感器读数数据模型"""
    __tablename__ = 'sensor_readings'
    
    id = Column(Integer, primary_key=True)
    sensor_id = Column(String(50), nullable=False)
    timestamp = Column(DateTime, nullable=False)
    temperature = Column(Float)
    humidity = Column(Float)
    soil_moisture = Column(Float)
    ph_value = Column(Float)
    light_intensity = Column(Float)

class DatabaseManager:
    """数据库管理器"""
    
    def __init__(self, postgres_url: str, influxdb_url: str, influxdb_token: str):
        # PostgreSQL连接
        self.pg_engine = create_engine(postgres_url)
        self.pg_session = sessionmaker(bind=self.pg_engine)()
        Base.metadata.create_all(self.pg_engine)
        
        # InfluxDB连接
        self.influx_client = InfluxDBClient(
            url=influxdb_url,
            token=influxdb_token,
            org="agriculture"
        )
        self.influx_write_api = self.influx_client.write_api(write_options=SYNCHRONOUS)
    
    def save_sensor_data(self, data: SensorData):
        """保存传感器数据"""
        # 保存到PostgreSQL
        reading = SensorReading(
            sensor_id=data.sensor_id,
            timestamp=data.timestamp,
            temperature=data.temperature,
            humidity=data.humidity,
            soil_moisture=data.soil_moisture,
            ph_value=data.ph_value,
            light_intensity=data.light_intensity
        )
        self.pg_session.add(reading)
        self.pg_session.commit()
        
        # 保存到InfluxDB(时序数据)
        point = Point("sensor_data") \
            .tag("sensor_id", data.sensor_id) \
            .field("temperature", data.temperature) \
            .field("humidity", data.humidity) \
            .field("soil_moisture", data.soil_moisture) \
            .field("ph_value", data.ph_value) \
            .field("light_intensity", data.light_intensity) \
            .time(data.timestamp)
        
        self.influx_write_api.write(bucket="agriculture", record=point)
    
    def get_recent_data(self, sensor_id: str, hours: int = 24) -> List[Dict]:
        """获取最近的传感器数据"""
        query = f'''
        from(bucket: "agriculture")
        |> range(start: -{hours}h)
        |> filter(fn: (r) => r._measurement == "sensor_data" and r.sensor_id == "{sensor_id}")
        '''
        
        result = self.influx_client.query_api().query(query)
        return [record.values for table in result for record in table.records]

3. 数据分析与预警系统

import numpy as np
import pandas as pd
from sklearn.ensemble import IsolationForest
from sklearn.preprocessing import StandardScaler
from typing import Tuple, List
import smtplib
from email.mime.text import MIMEText

class AgricultureAnalyzer:
    """农业数据分析器"""
    
    def __init__(self, db_manager: DatabaseManager):
        self.db_manager = db_manager
        self.anomaly_detector = IsolationForest(contamination=0.1)
        self.scaler = StandardScaler()
        self.is_trained = False
    
    def prepare_data(self, sensor_id: str, days: int = 30) -> pd.DataFrame:
        """准备分析数据"""
        data = self.db_manager.get_recent_data(sensor_id, days * 24)
        df = pd.DataFrame(data)
        
        if not df.empty:
            df['timestamp'] = pd.to_datetime(df['_time'])
            df = df.set_index('timestamp')
            
            # 数据清洗
            df = df.select_dtypes(include=[np.number])
            df = df.dropna()
            
            # 添加时间特征
            df['hour'] = df.index.hour
            df['day_of_week'] = df.index.dayofweek
            
        return df
    
    def detect_anomalies(self, sensor_id: str) -> List[Dict]:
        """异常检测"""
        df = self.prepare_data(sensor_id)
        
        if df.empty:
            return []
        
        # 特征标准化
        features = ['temperature', 'humidity', 'soil_moisture', 'ph_value', 'light_intensity']
        scaled_data = self.scaler.fit_transform(df[features])
        
        # 异常检测
        anomalies = self.anomaly_detector.fit_predict(scaled_data)
        anomaly_indices = np.where(anomalies == -1)[0]
        
        anomaly_records = []
        for idx in anomaly_indices:
            anomaly_records.append({
                'timestamp': df.index[idx],
                'data': df.iloc[idx].to_dict(),
                'anomaly_score': self.anomaly_detector.score_samples(scaled_data[idx:idx+1])[0]
            })
        
        return anomaly_records
    
    def analyze_growth_conditions(self, sensor_id: str) -> Dict:
        """分析作物生长条件"""
        df = self.prepare_data(sensor_id, 7)  # 最近7天数据
        
        if df.empty:
            return {"error": "数据不足"}
        
        # 计算平均值和趋势
        analysis = {
            "averages": {
                "temperature": df['temperature'].mean(),
                "humidity": df['humidity'].mean(),
                "soil_moisture": df['soil_moisture'].mean(),
                "ph_value": df['ph_value'].mean(),
                "light_intensity": df['light_intensity'].mean()
            },
            "trends": {},
            "recommendations": []
        }
        
        # 计算趋势(简单线性回归斜率)
        for column in ['temperature', 'humidity', 'soil_moisture']:
            x = np.arange(len(df))
            trend = np.polyfit(x, df[column], 1)[0]
            analysis["trends"][column] = "上升" if trend > 0.1 else "下降" if trend < -0.1 else "稳定"
        
        # 生成建议
        if analysis["averages"]["soil_moisture"] < 30:
            analysis["recommendations"].append("土壤湿度偏低,建议增加灌溉")
        
        if analysis["averages"]["ph_value"] < 6.0 or analysis["averages"]["ph_value"] > 8.0:
            analysis["recommendations"].append(f"土壤pH值异常({analysis['averages']['ph_value']:.1f}),建议调节")
        
        return analysis

class AlertSystem:
    """预警系统"""
    
    def __init__(self, email_config: Dict):
        self.email_config = email_config
        self.alert_thresholds = {
            'temperature': {'min': 10, 'max': 35},
            'humidity': {'min': 40, 'max': 80},
            'soil_moisture': {'min': 20, 'max': 80},
            'ph_value': {'min': 6.0, 'max': 8.0}
        }
    
    def check_alerts(self, data: SensorData) -> List[str]:
        """检查预警条件"""
        alerts = []
        
        for param, thresholds in self.alert_thresholds.items():
            value = getattr(data, param)
            if value < thresholds['min']:
                alerts.append(f"{param}过低: {value}")
            elif value > thresholds['max']:
                alerts.append(f"{param}过高: {value}")
        
        return alerts
    
    def send_alert(self, sensor_id: str, alerts: List[str]):
        """发送预警邮件"""
        if not alerts:
            return
        
        subject = f"农业监控预警 - 传感器 {sensor_id}"
        body = f"检测到以下异常情况:\n\n" + "\n".join(f"• {alert}" for alert in alerts)
        
        msg = MIMEText(body, 'plain', 'utf-8')
        msg['Subject'] = subject
        msg['From'] = self.email_config['from']
        msg['To'] = self.email_config['to']
        
        try:
            with smtplib.SMTP(self.email_config['smtp_server'], self.email_config['smtp_port']) as server:
                server.starttls()
                server.login(self.email_config['username'], self.email_config['password'])
                server.send_message(msg)
            print(f"预警邮件已发送: {subject}")
        except Exception as e:
            print(f"邮件发送失败: {e}")

4. 自动化控制系统

import RPi.GPIO as GPIO
from typing import Dict
import json
import requests

class IrrigationController:
    """灌溉控制器"""
    
    def __init__(self, pump_pins: Dict[str, int]):
        self.pump_pins = pump_pins
        GPIO.setmode(GPIO.BCM)
        
        # 初始化GPIO引脚
        for zone, pin in pump_pins.items():
            GPIO.setup(pin, GPIO.OUT)
            GPIO.output(pin, GPIO.LOW)  # 初始状态关闭
    
    def start_irrigation(self, zone: str, duration_minutes: int):
        """启动灌溉"""
        if zone not in self.pump_pins:
            print(f"未知灌溉区域: {zone}")
            return False
        
        pin = self.pump_pins[zone]
        print(f"启动{zone}区域灌溉,持续{duration_minutes}分钟")
        
        GPIO.output(pin, GPIO.HIGH)
        
        # 使用定时器在指定时间后关闭
        import threading
        timer = threading.Timer(duration_minutes * 60, self.stop_irrigation, [zone])
        timer.start()
        
        return True
    
    def stop_irrigation(self, zone: str):
        """停止灌溉"""
        if zone not in self.pump_pins:
            return False
        
        pin = self.pump_pins[zone]
        GPIO.output(pin, GPIO.LOW)
        print(f"停止{zone}区域灌溉")
        return True
    
    def get_irrigation_status(self) -> Dict[str, bool]:
        """获取灌溉状态"""
        status = {}
        for zone, pin in self.pump_pins.items():
            status[zone] = bool(GPIO.input(pin))
        return status

class AutomationEngine:
    """自动化引擎"""
    
    def __init__(self, db_manager: DatabaseManager, irrigation_controller: IrrigationController):
        self.db_manager = db_manager
        self.irrigation_controller = irrigation_controller
        self.automation_rules = []
    
    def add_rule(self, condition: Dict, action: Dict):
        """添加自动化规则"""
        rule = {
            'condition': condition,
            'action': action,
            'enabled': True
        }
        self.automation_rules.append(rule)
    
    def evaluate_rules(self, sensor_data: SensorData):
        """评估并执行自动化规则"""
        for rule in self.automation_rules:
            if not rule['enabled']:
                continue
            
            if self._check_condition(sensor_data, rule['condition']):
                self._execute_action(rule['action'])
    
    def _check_condition(self, data: SensorData, condition: Dict) -> bool:
        """检查条件是否满足"""
        param = condition.get('parameter')
        operator = condition.get('operator')
        threshold = condition.get('threshold')
        
        if not all([param, operator, threshold]):
            return False
        
        value = getattr(data, param, None)
        if value is None:
            return False
        
        if operator == 'less_than':
            return value < threshold
        elif operator == 'greater_than':
            return value > threshold
        elif operator == 'equals':
            return value == threshold
        
        return False
    
    def _execute_action(self, action: Dict):
        """执行动作"""
        action_type = action.get('type')
        
        if action_type == 'irrigation':
            zone = action.get('zone')
            duration = action.get('duration_minutes', 10)
            self.irrigation_controller.start_irrigation(zone, duration)
        
        elif action_type == 'notification':
            message = action.get('message', '自动化规则触发')
            self._send_notification(message)
    
    def _send_notification(self, message: str):
        """发送通知"""
        # 这里可以集成微信、钉钉等通知服务
        print(f"自动化通知: {message}")

# 预设自动化规则示例
def setup_default_rules(automation_engine: AutomationEngine):
    """设置默认自动化规则"""
    
    # 土壤湿度低时自动灌溉
    automation_engine.add_rule(
        condition={
            'parameter': 'soil_moisture',
            'operator': 'less_than',
            'threshold': 30
        },
        action={
            'type': 'irrigation',
            'zone': 'zone_1',
            'duration_minutes': 15
        }
    )
    
    # 温度过高时发送通知
    automation_engine.add_rule(
        condition={
            'parameter': 'temperature',
            'operator': 'greater_than',
            'threshold': 35
        },
        action={
            'type': 'notification',
            'message': '温度过高,请注意通风降温'
        }
    )

5. Web API接口

from flask import Flask, jsonify, request
from flask_cors import CORS
from datetime import datetime, timedelta
import plotly.graph_objs as go
import plotly.utils

app = Flask(__name__)
CORS(app)

# 全局变量(实际项目中应使用依赖注入)
db_manager = None
analyzer = None
automation_engine = None

@app.route('/api/sensors', methods=['GET'])
def get_sensors():
    """获取传感器列表"""
    # 实现获取所有传感器ID的逻辑
    sensors = ['sensor_001', 'sensor_002', 'sensor_003']
    return jsonify({'sensors': sensors})

@app.route('/api/sensors/<sensor_id>/data', methods=['GET'])
def get_sensor_data(sensor_id):
    """获取传感器数据"""
    hours = request.args.get('hours', 24, type=int)
    data = db_manager.get_recent_data(sensor_id, hours)
    return jsonify({'data': data})

@app.route('/api/sensors/<sensor_id>/analysis', methods=['GET'])
def get_analysis(sensor_id):
    """获取数据分析结果"""
    analysis = analyzer.analyze_growth_conditions(sensor_id)
    return jsonify(analysis)

@app.route('/api/sensors/<sensor_id>/anomalies', methods=['GET'])
def get_anomalies(sensor_id):
    """获取异常检测结果"""
    anomalies = analyzer.detect_anomalies(sensor_id)
    return jsonify({'anomalies': anomalies})

@app.route('/api/irrigation/status', methods=['GET'])
def get_irrigation_status():
    """获取灌溉状态"""
    status = automation_engine.irrigation_controller.get_irrigation_status()
    return jsonify({'irrigation_status': status})

@app.route('/api/irrigation/start', methods=['POST'])
def start_irrigation():
    """手动启动灌溉"""
    data = request.json
    zone = data.get('zone')
    duration = data.get('duration_minutes', 10)
    
    success = automation_engine.irrigation_controller.start_irrigation(zone, duration)
    return jsonify({'success': success})

@app.route('/api/charts/<sensor_id>', methods=['GET'])
def get_chart_data(sensor_id):
    """获取图表数据"""
    hours = request.args.get('hours', 24, type=int)
    data = db_manager.get_recent_data(sensor_id, hours)
    
    if not data:
        return jsonify({'error': '无数据'})
    
    # 创建Plotly图表
    df = pd.DataFrame(data)
    df['timestamp'] = pd.to_datetime(df['_time'])
    
    fig = go.Figure()
    
    # 添加温度曲线
    fig.add_trace(go.Scatter(
        x=df['timestamp'],
        y=df['temperature'],
        mode='lines',
        name='温度',
        line=dict(color='red')
    ))
    
    # 添加湿度曲线
    fig.add_trace(go.Scatter(
        x=df['timestamp'],
        y=df['humidity'],
        mode='lines',
        name='湿度',
        line=dict(color='blue'),
        yaxis='y2'
    ))
    
    fig.update_layout(
        title=f'传感器 {sensor_id} 数据趋势',
        xaxis_title='时间',
        yaxis=dict(title='温度 (°C)', side='left'),
        yaxis2=dict(title='湿度 (%)', side='right', overlaying='y')
    )
    
    chart_json = plotly.utils.PlotlyJSONEncoder().encode(fig)
    return jsonify({'chart': chart_json})

if __name__ == '__main__':
    # 初始化系统组件
    db_manager = DatabaseManager(
        postgres_url="postgresql://user:password@localhost/agriculture",
        influxdb_url="http://localhost:8086",
        influxdb_token="your-token"
    )
    
    analyzer = AgricultureAnalyzer(db_manager)
    
    irrigation_controller = IrrigationController({
        'zone_1': 18,  # GPIO 18
        'zone_2': 19,  # GPIO 19
        'zone_3': 20   # GPIO 20
    })
    
    automation_engine = AutomationEngine(db_manager, irrigation_controller)
    setup_default_rules(automation_engine)
    
    app.run(host='0.0.0.0', port=5000, debug=True)

系统部署与运维

Docker容器化部署

创建 Dockerfile:

FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["python", "app.py"]

创建 docker-compose.yml:

version: '3.8'

services:
  app:
    build: .
    ports:
      - "5000:5000"
    environment:
      - DATABASE_URL=postgresql://postgres:password@db:5432/agriculture
      - INFLUXDB_URL=http://influxdb:8086
    depends_on:
      - db
      - influxdb
      - mqtt

  db:
    image: postgres:13
    environment:
      POSTGRES_DB: agriculture
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data

  influxdb:
    image: influxdb:2.0
    environment:
      - INFLUXDB_DB=agriculture
      - INFLUXDB_ADMIN_ENABLED=true
    volumes:
      - influxdb_data:/var/lib/influxdb

  mqtt:
    image: eclipse-mosquitto:2
    ports:
      - "1883:1883"
    volumes:
      - ./mosquitto.conf:/mosquitto/config/mosquitto.conf

volumes:
  postgres_data:
  influxdb_data:

系统监控

import psutil
import logging
from datetime import datetime

class SystemMonitor:
    """系统监控"""
    
    def __init__(self):
        self.logger = self.setup_logger()
    
    def setup_logger(self):
        """设置日志"""
        logger = logging.getLogger('agriculture_system')
        logger.setLevel(logging.INFO)
        
        handler = logging.FileHandler('system.log')
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        
        return logger
    
    def check_system_health(self):
        """检查系统健康状态"""
        health_status = {
            'timestamp': datetime.now().isoformat(),
            'cpu_usage': psutil.cpu_percent(),
            'memory_usage': psutil.virtual_memory().percent,
            'disk_usage': psutil.disk_usage('/').percent,
            'network_io': psutil.net_io_counters()._asdict()
        }
        
        # 检查异常情况
        if health_status['cpu_usage'] > 80:
            self.logger.warning(f"CPU使用率过高: {health_status['cpu_usage']}%")
        
        if health_status['memory_usage'] > 80:
            self.logger.warning(f"内存使用率过高: {health_status['memory_usage']}%")
        
        if health_status['disk_usage'] > 90:
            self.logger.warning(f"磁盘使用率过高: {health_status['disk_usage']}%")
        
        return health_status

项目总结与展望

项目价值

通过Python构建的智能农业监控与管理系统,我们实现了:

  1. 实时监控:7×24小时不间断监测农作物生长环境
  2. 智能分析:基于机器学习的异常检测和趋势分析
  3. 自动化控制:根据环境条件自动执行灌溉等操作
  4. 数据驱动:为农业决策提供科学的数据支持
  5. 成本优化:减少人工成本,提高资源利用效率

技术亮点

  • 模块化设计:各功能模块独立,便于维护和扩展
  • 多数据源整合:支持传感器、MQTT、串口等多种数据采集方式
  • 实时数据处理:使用时序数据库确保高效的数据存储和查询
  • 机器学习应用:异常检测算法提高系统智能化水平
  • 容器化部署:使用Docker简化部署和运维工作

未来发展方向

  1. 深度学习集成

    • 植物疾病识别
    • 产量预测模型
    • 最优种植策略推荐
  2. 物联网扩展

    • 支持更多类型的传感器
    • 集成气象站数据
    • 卫星遥感数据整合
  3. 移动端应用

    • 开发农户专用APP
    • 支持离线数据同步
    • 语音控制功能
  4. 边缘计算

    • 本地数据处理能力
    • 降低网络依赖
    • 提高响应速度
  5. 区块链应用

    • 农产品溯源
    • 数据真实性验证
    • 智能合约自动执行

这个智能农业监控系统展示了Python在物联网和农业现代化领域的强大应用潜力。通过不断的技术创新和功能完善,相信这样的系统将为农业可持续发展做出更大贡献。

源代码下载

项目代码

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天进步2015

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值