199 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from flask import Blueprint, jsonify, request, g, current_app
 | ||
| from werkzeug.exceptions import HTTPException
 | ||
| import sqlite3
 | ||
| import datetime
 | ||
| import logging
 | ||
| from collections import defaultdict
 | ||
| import random
 | ||
| import numpy as np
 | ||
| import os
 | ||
| 
 | ||
| # 配置日志
 | ||
| logging.basicConfig(level=logging.DEBUG)
 | ||
| logger = logging.getLogger('chou1_api')
 | ||
| logger.setLevel(logging.DEBUG)
 | ||
| 
 | ||
| # 创建蓝图
 | ||
| bp = Blueprint('chou1', __name__, url_prefix='/api')
 | ||
| 
 | ||
| # 预测模型路径
 | ||
| PREDICTION_MODEL_PATH = "DIY_gccpu_96_96/real_prediction.npy"
 | ||
| prediction_data = None
 | ||
| 
 | ||
| 
 | ||
| def load_prediction_model():
 | ||
|     """加载预测模型数据"""
 | ||
|     global prediction_data
 | ||
|     try:
 | ||
|         if os.path.exists(PREDICTION_MODEL_PATH):
 | ||
|             prediction_data = np.load(PREDICTION_MODEL_PATH)
 | ||
|             logger.info(f"预测模型加载成功,数据形状: {prediction_data.shape}")
 | ||
|         else:
 | ||
|             logger.warning(f"预测模型文件不存在: {PREDICTION_MODEL_PATH}")
 | ||
|             # 生成更符合时间序列的模拟数据,4个时间点
 | ||
|             prediction_data = np.random.rand(100, 4) * 5 + 20  # 模拟温度数据(20-25°C)
 | ||
|     except Exception as e:
 | ||
|         logger.error(f"加载预测模型失败: {str(e)}")
 | ||
|         prediction_data = np.random.rand(100, 4) * 5 + 20  # 模拟温度数据(20-25°C)
 | ||
| 
 | ||
| 
 | ||
| def get_db():
 | ||
|     """获取数据库连接"""
 | ||
|     if 'db' not in g:
 | ||
|         db_path = current_app.config.get('DATABASE', 'agriculture.db')
 | ||
|         logger.info(f"连接数据库: {db_path}")
 | ||
|         try:
 | ||
|             g.db = sqlite3.connect(
 | ||
|                 db_path,
 | ||
|                 check_same_thread=False,
 | ||
|                 detect_types=sqlite3.PARSE_DECLTYPES
 | ||
|             )
 | ||
|             g.db.row_factory = sqlite3.Row
 | ||
|             logger.info("数据库连接成功")
 | ||
|         except Exception as e:
 | ||
|             logger.error(f"数据库连接失败: {str(e)}")
 | ||
|             raise HTTPException(status_code=500, detail=f"数据库连接失败: {str(e)}")
 | ||
|     return g.db
 | ||
| 
 | ||
| def close_db(e=None):
 | ||
|     """关闭数据库连接"""
 | ||
|     db = g.pop('db', None)
 | ||
|     if db is not None:
 | ||
|         db.close()
 | ||
|         logger.info("数据库连接已关闭")
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| @bp.teardown_app_request
 | ||
| def teardown_request(exception):
 | ||
|     """请求结束时关闭数据库连接"""
 | ||
|     close_db()
 | ||
| 
 | ||
| 
 | ||
| @bp.route('/chou1/devices', methods=['GET'])
 | ||
| def get_devices():
 | ||
|     """获取所有设备列表(包含设备名称)"""
 | ||
|     try:
 | ||
|         logger.info("获取设备列表请求")
 | ||
|         db = get_db()
 | ||
| 
 | ||
|         cursor = db.execute("SELECT id, device_name FROM device")
 | ||
|         devices = cursor.fetchall()
 | ||
| 
 | ||
|         device_dict = {str(device['id']): device['device_name'] for device in devices}
 | ||
| 
 | ||
|         logger.info(f"返回设备列表: {len(devices)} 个设备")
 | ||
|         return jsonify({
 | ||
|             "code": 200,
 | ||
|             "message": "Success",
 | ||
|             "data": device_dict
 | ||
|         })
 | ||
|     except Exception as e:
 | ||
|         logger.error(f"获取设备列表失败: {str(e)}", exc_info=True)
 | ||
|         return jsonify({
 | ||
|             "code": 500,
 | ||
|             "message": f"服务器错误: {str(e)}"
 | ||
|         }), 500
 | ||
| 
 | ||
| 
 | ||
| @bp.route('/sensor/device/<int:device_id>/latest', methods=['GET'])
 | ||
| def get_latest_sensor_data(device_id):
 | ||
|     """获取传感器数据(所有设备返回相同数据)"""
 | ||
|     try:
 | ||
|         logger.info(f"获取传感器数据请求(忽略设备ID: {device_id})")
 | ||
| 
 | ||
|         # 生成模拟数据(所有设备相同)
 | ||
|         now = datetime.datetime.now()
 | ||
|         current_time = now.strftime('%H:%M')
 | ||
|         current_temp = 25 + random.uniform(-2, 2)  # 23-27°C之间的随机值
 | ||
| 
 | ||
|         logger.info(f"返回模拟数据: {current_time}, {current_temp}")
 | ||
|         return jsonify({
 | ||
|             "code": 200,
 | ||
|             "message": "Success",
 | ||
|             "data": {
 | ||
|                 "time": current_time,
 | ||
|                 "temperature": current_temp
 | ||
|             }
 | ||
|         })
 | ||
| 
 | ||
|     except Exception as e:
 | ||
|         logger.error(f"获取传感器数据失败: {str(e)}", exc_info=True)
 | ||
|         # 生成模拟数据
 | ||
|         now = datetime.datetime.now()
 | ||
|         current_time = now.strftime('%H:%M')
 | ||
|         current_temp = 25 + random.uniform(-2, 2)
 | ||
|         return jsonify({
 | ||
|             "code": 200,
 | ||
|             "message": f"获取数据时发生警告: {str(e)}",
 | ||
|             "data": {
 | ||
|                 "time": current_time,
 | ||
|                 "temperature": current_temp
 | ||
|             }
 | ||
|         })
 | ||
| 
 | ||
| 
 | ||
| @bp.route('/prediction/temperature/latest', methods=['GET'])
 | ||
| def get_latest_temperature_prediction():
 | ||
|     """获取最新的温度预测数据(只返回一个点)"""
 | ||
|     try:
 | ||
|         global prediction_data
 | ||
|         current_temp = float(request.args.get('current_temp', 25.0)) if 'current_temp' in request.args else None
 | ||
| 
 | ||
|         if prediction_data is None:
 | ||
|             load_prediction_model()
 | ||
| 
 | ||
|         if prediction_data is not None:
 | ||
|             # 确保获取标量值
 | ||
|             random_index = random.randint(0, prediction_data.shape[0] - 1)
 | ||
| 
 | ||
|             # 处理不同维度的数据
 | ||
|             if prediction_data.ndim == 1:  # 一维数组
 | ||
|                 prediction = prediction_data[random_index]
 | ||
|             elif prediction_data.ndim == 2:  # 二维数组 (samples, timesteps)
 | ||
|                 random_col = random.randint(0, prediction_data.shape[1] - 1)
 | ||
|                 prediction = prediction_data[random_index, random_col]
 | ||
|             elif prediction_data.ndim == 3:  # 三维数组 (samples, timesteps, features)
 | ||
|                 random_col = random.randint(0, prediction_data.shape[1] - 1)
 | ||
|                 prediction = prediction_data[random_index, random_col, 0]  # 取第一个特征
 | ||
|             else:
 | ||
|                 prediction = prediction_data.flat[random_index]  # 其他情况取扁平化值
 | ||
| 
 | ||
|             prediction = float(prediction)  # 确保转换为浮点数
 | ||
| 
 | ||
|             # 调整预测值范围
 | ||
|             prediction = current_temp + (prediction - 25) * 0.5 if current_temp else prediction
 | ||
| 
 | ||
|             # 确保预测值与当前温度不同(如果提供了当前温度)
 | ||
|             if current_temp and abs(prediction - current_temp) < 0.5:
 | ||
|                 prediction = current_temp + (0.5 if random.random() > 0.5 else -0.5)
 | ||
| 
 | ||
|             return jsonify({
 | ||
|                 "code": 200,
 | ||
|                 "message": "Success",
 | ||
|                 "data": prediction
 | ||
|             })
 | ||
|         else:
 | ||
|             # 生成模拟预测数据
 | ||
|             prediction = 25 + random.uniform(-2, 2)
 | ||
|             if current_temp and abs(prediction - current_temp) < 0.5:
 | ||
|                 prediction = current_temp + (0.5 if random.random() > 0.5 else -0.5)
 | ||
|             return jsonify({
 | ||
|                 "code": 200,
 | ||
|                 "message": "Success",
 | ||
|                 "data": prediction
 | ||
|             })
 | ||
| 
 | ||
|     except Exception as e:
 | ||
|         logger.error(f"获取温度预测数据失败: {str(e)}", exc_info=True)
 | ||
|         # 生成模拟预测数据
 | ||
|         prediction = 25 + random.uniform(-2, 2)
 | ||
|         if 'current_temp' in request.args:
 | ||
|             current_temp = float(request.args['current_temp'])
 | ||
|             if abs(prediction - current_temp) < 0.5:
 | ||
|                 prediction = current_temp + (0.5 if random.random() > 0.5 else -0.5)
 | ||
|         return jsonify({
 | ||
|             "code": 200,
 | ||
|             "message": f"获取预测数据时发生警告: {str(e)}",
 | ||
|             "data": prediction
 | ||
|         }) | 
