531 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			531 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from flask import Blueprint, jsonify, request, current_app, g
 | 
						||
import sqlite3
 | 
						||
import datetime
 | 
						||
from dateutil.relativedelta import relativedelta
 | 
						||
import logging
 | 
						||
import random
 | 
						||
 | 
						||
# 配置日志
 | 
						||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
 | 
						||
logger = logging.getLogger(__name__)
 | 
						||
 | 
						||
bp = Blueprint('ph_data', __name__, url_prefix='/ph_data')
 | 
						||
 | 
						||
# 数据缓存字典,格式: {time_range: (seed, cached_data)}
 | 
						||
ph_data_cache = {}
 | 
						||
 | 
						||
 | 
						||
def get_db():
 | 
						||
    """获取数据库连接"""
 | 
						||
    if 'db' not in g:
 | 
						||
        try:
 | 
						||
            g.db = sqlite3.connect(
 | 
						||
                current_app.config.get('DATABASE', 'agriculture.db'),
 | 
						||
                check_same_thread=False,
 | 
						||
                detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES
 | 
						||
            )
 | 
						||
            g.db.row_factory = sqlite3.Row
 | 
						||
            logger.info("数据库连接成功")
 | 
						||
        except Exception as e:
 | 
						||
            logger.error(f"数据库连接失败: {str(e)}")
 | 
						||
            raise
 | 
						||
    return g.db
 | 
						||
 | 
						||
 | 
						||
def close_db(e=None):
 | 
						||
    """关闭数据库连接"""
 | 
						||
    db = g.pop('db', None)
 | 
						||
    if db is not None:
 | 
						||
        db.close()
 | 
						||
        logger.info("数据库连接已关闭")
 | 
						||
 | 
						||
 | 
						||
@bp.route('/get_time_ranges', methods=['GET'])
 | 
						||
def get_time_ranges():
 | 
						||
    """获取时间范围选项"""
 | 
						||
    try:
 | 
						||
        time_ranges = [
 | 
						||
            {'value': 'today', 'label': '今日'},
 | 
						||
            {'value': 'last_three_days', 'label': '前三天'},
 | 
						||
            {'value': 'next_two_days', 'label': '后两天'},
 | 
						||
        ]
 | 
						||
        logger.info("成功返回时间范围选项")
 | 
						||
        return jsonify({'time_ranges': time_ranges})
 | 
						||
    except Exception as e:
 | 
						||
        logger.error(f"获取时间范围失败: {str(e)}")
 | 
						||
        return jsonify({'error': '获取时间范围失败'}), 500
 | 
						||
 | 
						||
 | 
						||
def increase_ph_fluctuation(data_list, time_range, amplitude=1.5):
 | 
						||
    """
 | 
						||
    增加PH值的波动幅度,使用固定随机种子确保相同时间范围生成相同波动数据
 | 
						||
    :param data_list: 包含PH值的数据列表
 | 
						||
    :param time_range: 时间范围参数
 | 
						||
    :param amplitude: 波动幅度(默认±1.5)
 | 
						||
    :return: 修改后的列表
 | 
						||
    """
 | 
						||
    # 检查缓存
 | 
						||
    if time_range in ph_data_cache:
 | 
						||
        logger.info(f"使用缓存的波动数据 for {time_range}")
 | 
						||
        return ph_data_cache[time_range]
 | 
						||
 | 
						||
    # 为特定时间范围设置固定随机种子
 | 
						||
    seed = hash(time_range)
 | 
						||
    random.seed(seed)
 | 
						||
    logger.info(f"为时间范围 {time_range} 设置随机种子: {seed}")
 | 
						||
 | 
						||
    # 应用波动
 | 
						||
    modified_data = []
 | 
						||
    for item in data_list:
 | 
						||
        original_ph = item.get('ph') or item.get('avg_ph')
 | 
						||
        if original_ph is not None:
 | 
						||
            # 随机波动(可正可负)
 | 
						||
            fluctuation = random.uniform(-amplitude, amplitude)
 | 
						||
            new_ph = original_ph + fluctuation
 | 
						||
            # 确保PH值在合理范围(0-14)
 | 
						||
            new_ph = max(0, min(14, new_ph))
 | 
						||
            # 更新数据
 | 
						||
            modified_item = item.copy()
 | 
						||
            if 'ph' in modified_item:
 | 
						||
                modified_item['ph'] = round(new_ph, 2)
 | 
						||
            else:
 | 
						||
                modified_item['avg_ph'] = round(new_ph, 2)
 | 
						||
            modified_data.append(modified_item)
 | 
						||
 | 
						||
    # 缓存波动后的数据
 | 
						||
    ph_data_cache[time_range] = modified_data
 | 
						||
    return modified_data
 | 
						||
 | 
						||
 | 
						||
@bp.route('/get_ph_data', methods=['GET'])
 | 
						||
def get_ph_data():
 | 
						||
    """获取指定时间范围的PH值数据(合并所有设备)"""
 | 
						||
    time_range = request.args.get('time_range', 'today')
 | 
						||
    sample_method = request.args.get('sample_method', 'fixed')  # 采样方式:fixed(固定点)或hourly(每小时)
 | 
						||
    logger.info(f"请求PH数据,时间范围: {time_range},采样方式: {sample_method}")
 | 
						||
 | 
						||
    if time_range not in ['today', 'last_three_days', 'next_two_days', 'all']:
 | 
						||
        logger.warning(f"无效的时间范围: {time_range}")
 | 
						||
        return jsonify({'error': '无效的时间范围'}), 400
 | 
						||
 | 
						||
    try:
 | 
						||
        db = get_db()
 | 
						||
        # 硬编码今日为2025-05-27
 | 
						||
        today = datetime.datetime(2025, 5, 27)
 | 
						||
        today_str = today.strftime('%Y-%m-%d')
 | 
						||
 | 
						||
        result = []
 | 
						||
 | 
						||
        if time_range == 'today':
 | 
						||
            # 今日数据查询逻辑
 | 
						||
            start_date = today_str + ' 00:00:00'
 | 
						||
            end_date = today_str + ' 23:59:59'
 | 
						||
 | 
						||
            if sample_method == 'hourly':
 | 
						||
                # 每小时采样
 | 
						||
                for hour in range(0, 24):
 | 
						||
                    sample_time = f"{today_str} {hour:02d}:00:00"
 | 
						||
                    start_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                  - relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
                    end_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                + relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
 | 
						||
                    cursor = db.execute(
 | 
						||
                        '''SELECT AVG(ph) as avg_ph 
 | 
						||
                           FROM temperature_data 
 | 
						||
                           WHERE (timestamp BETWEEN ? AND ?) 
 | 
						||
                              OR (DATE(timestamp) = DATE(?))''',
 | 
						||
                        (start_time, end_time, sample_time)
 | 
						||
                    )
 | 
						||
                    row = cursor.fetchone()
 | 
						||
                    avg_ph = float(row['avg_ph']) if row and row['avg_ph'] is not None else 0
 | 
						||
 | 
						||
                    result.append({
 | 
						||
                        'timestamp': sample_time,
 | 
						||
                        'ph': round(avg_ph, 2)
 | 
						||
                    })
 | 
						||
            else:
 | 
						||
                # 固定点采样
 | 
						||
                cursor = db.execute(
 | 
						||
                    '''SELECT timestamp, AVG(ph) as avg_ph 
 | 
						||
                       FROM temperature_data 
 | 
						||
                       WHERE (timestamp BETWEEN ? AND ?) 
 | 
						||
                          OR (DATE(timestamp) = DATE(?))
 | 
						||
                       GROUP BY timestamp
 | 
						||
                       ORDER BY timestamp''',
 | 
						||
                    (start_date, end_date, today_str)
 | 
						||
                )
 | 
						||
                data = cursor.fetchall()
 | 
						||
                result = [{'timestamp': row['timestamp'], 'ph': float(row['avg_ph'])} for row in data]
 | 
						||
 | 
						||
            logger.info(f"查询到今日PH数据记录: {len(result)} 条")
 | 
						||
 | 
						||
        elif time_range == 'last_three_days':
 | 
						||
            # 前三天数据查询
 | 
						||
            if sample_method == 'hourly':
 | 
						||
                # 每小时采样
 | 
						||
                for i in range(3, 0, -1):
 | 
						||
                    date = today - relativedelta(days=i)
 | 
						||
                    date_str = date.strftime('%Y-%m-%d')
 | 
						||
                    for hour in range(0, 24):
 | 
						||
                        sample_time = f"{date_str} {hour:02d}:00:00"
 | 
						||
                        start_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                      - relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
                        end_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                    + relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
 | 
						||
                        cursor = db.execute(
 | 
						||
                            '''SELECT AVG(ph) as avg_ph 
 | 
						||
                               FROM temperature_data 
 | 
						||
                               WHERE (timestamp BETWEEN ? AND ?) 
 | 
						||
                                  OR (DATE(timestamp) = DATE(?))''',
 | 
						||
                            (start_time, end_time, sample_time)
 | 
						||
                        )
 | 
						||
                        row = cursor.fetchone()
 | 
						||
                        avg_ph = float(row['avg_ph']) if row and row['avg_ph'] is not None else 0
 | 
						||
 | 
						||
                        result.append({
 | 
						||
                            'timestamp': sample_time,
 | 
						||
                            'ph': round(avg_ph, 2)
 | 
						||
                        })
 | 
						||
            else:
 | 
						||
                # 固定点采样(每天6个点)
 | 
						||
                sample_hours = [4, 8, 12, 16, 20, 23]
 | 
						||
                for i in range(3, 0, -1):
 | 
						||
                    date = today - relativedelta(days=i)
 | 
						||
                    date_str = date.strftime('%Y-%m-%d')
 | 
						||
                    for hour in sample_hours:
 | 
						||
                        if hour == 23:
 | 
						||
                            sample_time = f"{date_str} {hour:02d}:00:00"
 | 
						||
                        else:
 | 
						||
                            sample_time = f"{date_str} {hour:02d}:00:00"
 | 
						||
 | 
						||
                        start_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                      - relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
                        end_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                    + relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
 | 
						||
                        cursor = db.execute(
 | 
						||
                            '''SELECT AVG(ph) as avg_ph 
 | 
						||
                               FROM temperature_data 
 | 
						||
                               WHERE (timestamp BETWEEN ? AND ?) 
 | 
						||
                                  OR (DATE(timestamp) = DATE(?))''',
 | 
						||
                            (start_time, end_time, sample_time)
 | 
						||
                        )
 | 
						||
                        row = cursor.fetchone()
 | 
						||
                        avg_ph = float(row['avg_ph']) if row and row['avg_ph'] is not None else 0
 | 
						||
 | 
						||
                        result.append({
 | 
						||
                            'timestamp': sample_time,
 | 
						||
                            'ph': round(avg_ph, 2)
 | 
						||
                        })
 | 
						||
 | 
						||
            logger.info(f"查询到前三天PH数据记录: {len(result)} 条")
 | 
						||
 | 
						||
        elif time_range == 'next_two_days':
 | 
						||
            # 后两天数据查询
 | 
						||
            if sample_method == 'hourly':
 | 
						||
                for i in range(1, 3):
 | 
						||
                    date = today + relativedelta(days=i)
 | 
						||
                    date_str = date.strftime('%Y-%m-%d')
 | 
						||
                    for hour in range(0, 24):
 | 
						||
                        sample_time = f"{date_str} {hour:02d}:00:00"
 | 
						||
                        start_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                      - relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
                        end_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                    + relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
 | 
						||
                        cursor = db.execute(
 | 
						||
                            '''SELECT AVG(ph) as avg_ph 
 | 
						||
                               FROM temperature_data 
 | 
						||
                               WHERE (timestamp BETWEEN ? AND ?) 
 | 
						||
                                  OR (DATE(timestamp) = DATE(?))''',
 | 
						||
                            (start_time, end_time, sample_time)
 | 
						||
                        )
 | 
						||
                        row = cursor.fetchone()
 | 
						||
                        avg_ph = float(row['avg_ph']) if row and row['avg_ph'] is not None else 0
 | 
						||
 | 
						||
                        result.append({
 | 
						||
                            'timestamp': sample_time,
 | 
						||
                            'ph': round(avg_ph, 2)
 | 
						||
                        })
 | 
						||
            else:
 | 
						||
                sample_hours = [8, 12, 16, 20]
 | 
						||
                for i in range(1, 3):
 | 
						||
                    date = today + relativedelta(days=i)
 | 
						||
                    date_str = date.strftime('%Y-%m-%d')
 | 
						||
                    for hour in sample_hours:
 | 
						||
                        sample_time = f"{date_str} {hour:02d}:00:00"
 | 
						||
                        start_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                      - relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
                        end_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                    + relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
 | 
						||
                        cursor = db.execute(
 | 
						||
                            '''SELECT AVG(ph) as avg_ph 
 | 
						||
                               FROM temperature_data 
 | 
						||
                               WHERE (timestamp BETWEEN ? AND ?) 
 | 
						||
                                  OR (DATE(timestamp) = DATE(?))''',
 | 
						||
                            (start_time, end_time, sample_time)
 | 
						||
                        )
 | 
						||
                        row = cursor.fetchone()
 | 
						||
                        avg_ph = float(row['avg_ph']) if row and row['avg_ph'] is not None else 0
 | 
						||
 | 
						||
                        result.append({
 | 
						||
                            'timestamp': sample_time,
 | 
						||
                            'ph': round(avg_ph, 2)
 | 
						||
                        })
 | 
						||
 | 
						||
            logger.info(f"查询到后两天PH数据记录: {len(result)} 条")
 | 
						||
 | 
						||
        elif time_range == 'all':
 | 
						||
            # 查询所有PH数据
 | 
						||
            cursor = db.execute(
 | 
						||
                '''SELECT timestamp, AVG(ph) as avg_ph 
 | 
						||
                   FROM temperature_data 
 | 
						||
                   WHERE ph IS NOT NULL
 | 
						||
                   GROUP BY timestamp
 | 
						||
                   ORDER BY timestamp'''
 | 
						||
            )
 | 
						||
            data = cursor.fetchall()
 | 
						||
            result = [{'timestamp': row['timestamp'], 'ph': float(row['avg_ph'])} for row in data]
 | 
						||
            logger.info(f"查询到所有PH数据记录: {len(result)} 条")
 | 
						||
 | 
						||
        # 关键修改:使用带随机种子的波动函数,并缓存结果
 | 
						||
        result = increase_ph_fluctuation(result, time_range, amplitude=2.0)
 | 
						||
 | 
						||
        return jsonify({
 | 
						||
            'time_range': time_range,
 | 
						||
            'sample_method': sample_method,
 | 
						||
            'data': result
 | 
						||
        })
 | 
						||
 | 
						||
    except sqlite3.Error as e:
 | 
						||
        logger.error(f"数据库查询错误: {str(e)}")
 | 
						||
        return jsonify({'error': '数据库查询错误'}), 500
 | 
						||
    except Exception as e:
 | 
						||
        logger.error(f"获取PH数据异常: {str(e)}")
 | 
						||
        return jsonify({'error': '服务器内部错误'}), 500
 | 
						||
    finally:
 | 
						||
        close_db()
 | 
						||
 | 
						||
 | 
						||
@bp.route('/get_ph_data_by_date_range', methods=['GET'])
 | 
						||
def get_ph_data_by_date_range():
 | 
						||
    """获取指定日期范围内的PH值数据(合并所有设备)"""
 | 
						||
    start_date_str = request.args.get('start_date')
 | 
						||
    end_date_str = request.args.get('end_date')
 | 
						||
    sample_method = request.args.get('sample_method', 'daily')  # 采样方式:daily(每日)或hourly(每小时)
 | 
						||
 | 
						||
    # 验证日期格式
 | 
						||
    try:
 | 
						||
        start_date = datetime.datetime.strptime(start_date_str, '%Y-%m-%d')
 | 
						||
        end_date = datetime.datetime.strptime(end_date_str, '%Y-%m-%d')
 | 
						||
    except ValueError:
 | 
						||
        logger.warning(f"无效的日期格式,需要YYYY-MM-DD格式,实际传入: {start_date_str}, {end_date_str}")
 | 
						||
        return jsonify({'error': '无效的日期格式,需要YYYY-MM-DD格式'}), 400
 | 
						||
 | 
						||
    # 验证日期范围
 | 
						||
    if start_date > end_date:
 | 
						||
        logger.warning(f"开始日期不能大于结束日期: {start_date_str} > {end_date_str}")
 | 
						||
        return jsonify({'error': '开始日期不能大于结束日期'}), 400
 | 
						||
 | 
						||
    logger.info(f"请求PH数据,日期范围: {start_date_str} 至 {end_date_str},采样方式: {sample_method}")
 | 
						||
 | 
						||
    try:
 | 
						||
        db = get_db()
 | 
						||
        result = []
 | 
						||
 | 
						||
        if sample_method == 'hourly':
 | 
						||
            # 每小时采样
 | 
						||
            current_date = start_date
 | 
						||
            while current_date <= end_date:
 | 
						||
                date_str = current_date.strftime('%Y-%m-%d')
 | 
						||
                for hour in range(0, 24):
 | 
						||
                    sample_time = f"{date_str} {hour:02d}:00:00"
 | 
						||
                    start_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                  - relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
                    end_time = (datetime.datetime.strptime(sample_time, '%Y-%m-%d %H:%M:%S')
 | 
						||
                                + relativedelta(minutes=30)).strftime('%Y-%m-%d %H:%M:%S')
 | 
						||
 | 
						||
                    cursor = db.execute(
 | 
						||
                        '''SELECT AVG(ph) as avg_ph 
 | 
						||
                           FROM temperature_data 
 | 
						||
                           WHERE (timestamp BETWEEN ? AND ?) 
 | 
						||
                              OR (DATE(timestamp) = DATE(?))''',
 | 
						||
                        (start_time, end_time, sample_time)
 | 
						||
                    )
 | 
						||
                    row = cursor.fetchone()
 | 
						||
                    avg_ph = float(row['avg_ph']) if row and row['avg_ph'] is not None else 0
 | 
						||
 | 
						||
                    result.append({
 | 
						||
                        'timestamp': sample_time,
 | 
						||
                        'ph': round(avg_ph, 2)
 | 
						||
                    })
 | 
						||
                current_date += relativedelta(days=1)
 | 
						||
        else:
 | 
						||
            # 每日采样
 | 
						||
            current_date = start_date
 | 
						||
            while current_date <= end_date:
 | 
						||
                date_str = current_date.strftime('%Y-%m-%d')
 | 
						||
                cursor = db.execute(
 | 
						||
                    '''SELECT AVG(ph) as avg_ph 
 | 
						||
                       FROM temperature_data 
 | 
						||
                       WHERE DATE(timestamp) = ?''',
 | 
						||
                    (date_str,)
 | 
						||
                )
 | 
						||
                row = cursor.fetchone()
 | 
						||
                avg_ph = float(row['avg_ph']) if row and row['avg_ph'] is not None else 0
 | 
						||
 | 
						||
                result.append({
 | 
						||
                    'date': date_str,
 | 
						||
                    'avg_ph': round(avg_ph, 2)
 | 
						||
                })
 | 
						||
                current_date += relativedelta(days=1)
 | 
						||
 | 
						||
        logger.info(f"查询到{start_date_str}至{end_date_str}的PH数据记录: {len(result)} 条")
 | 
						||
 | 
						||
        # 增加PH值的波动幅度,使用日期范围字符串作为种子
 | 
						||
        range_key = f"{start_date_str}_{end_date_str}"
 | 
						||
        result = increase_ph_fluctuation(result, range_key, amplitude=2.0)
 | 
						||
 | 
						||
        return jsonify({
 | 
						||
            'start_date': start_date_str,
 | 
						||
            'end_date': end_date_str,
 | 
						||
            'sample_method': sample_method,
 | 
						||
            'data': result
 | 
						||
        })
 | 
						||
 | 
						||
    except sqlite3.Error as e:
 | 
						||
        logger.error(f"数据库查询错误: {str(e)}")
 | 
						||
        return jsonify({'error': '数据库查询错误'}), 500
 | 
						||
    except Exception as e:
 | 
						||
        logger.error(f"获取PH数据异常: {str(e)}")
 | 
						||
        return jsonify({'error': '服务器内部错误'}), 500
 | 
						||
    finally:
 | 
						||
        close_db()
 | 
						||
 | 
						||
 | 
						||
@bp.route('/get_ph_today', methods=['GET'])
 | 
						||
def get_ph_today():
 | 
						||
    """获取2025年5月27日设备1的所有PH值数据"""
 | 
						||
    logger.info("请求获取2025年5月27日设备1的PH数据")
 | 
						||
    try:
 | 
						||
        db = get_db()
 | 
						||
        target_date = datetime.datetime(2025, 5, 27)
 | 
						||
        start = target_date.strftime('%Y-%m-%d 00:00:00')
 | 
						||
        end = target_date.strftime('%Y-%m-%d 23:59:59')
 | 
						||
 | 
						||
        logger.info(f"查询范围: {start} ~ {end},设备ID: 1")
 | 
						||
        cursor = db.execute(
 | 
						||
            '''SELECT timestamp, ph 
 | 
						||
               FROM temperature_data 
 | 
						||
               WHERE timestamp BETWEEN ? AND ? 
 | 
						||
               AND ph IS NOT NULL
 | 
						||
               AND device_id = 1  -- 只查询设备1的数据
 | 
						||
               ORDER BY timestamp''',
 | 
						||
            (start, end)
 | 
						||
        )
 | 
						||
        data = cursor.fetchall()
 | 
						||
 | 
						||
        if not data:
 | 
						||
            logger.warning("2025-05-27设备1无PH数据,查询最近10条调试")
 | 
						||
            debug_cursor = db.execute('''
 | 
						||
                SELECT timestamp, ph, device_id
 | 
						||
                FROM temperature_data 
 | 
						||
                ORDER BY timestamp DESC 
 | 
						||
                LIMIT 10
 | 
						||
            ''')
 | 
						||
            recent = debug_cursor.fetchall()
 | 
						||
            logger.info("数据库最近10条记录:")
 | 
						||
            for record in recent:
 | 
						||
                logger.info(f"  timestamp: {record['timestamp']}, ph: {record['ph']}, device_id: {record['device_id']}")
 | 
						||
            return jsonify({
 | 
						||
                'date': '2025-05-27',
 | 
						||
                'device_id': 1,
 | 
						||
                'message': '未找到设备1的PH数据',
 | 
						||
                'data': []
 | 
						||
            })
 | 
						||
 | 
						||
        result = []
 | 
						||
        for i, row in enumerate(data):
 | 
						||
            try:
 | 
						||
                # 提取原始数据
 | 
						||
                raw_ts = row['timestamp']
 | 
						||
                raw_ph = row['ph']
 | 
						||
 | 
						||
                # 验证时间格式
 | 
						||
                if isinstance(raw_ts, datetime.datetime):
 | 
						||
                    dt = raw_ts
 | 
						||
                else:
 | 
						||
                    dt = datetime.datetime.strptime(raw_ts, '%Y-%m-%d %H:%M:%S')
 | 
						||
 | 
						||
                # 验证PH值
 | 
						||
                if raw_ph is None:
 | 
						||
                    continue  # 跳过空值
 | 
						||
 | 
						||
                if isinstance(raw_ph, (float, int)):
 | 
						||
                    ph_value = raw_ph
 | 
						||
                elif isinstance(raw_ph, str):
 | 
						||
                    ph_str = raw_ph.strip()
 | 
						||
                    if 'pH' in ph_str:
 | 
						||
                        ph_str = ph_str.replace('pH', '').strip()
 | 
						||
                    ph_value = float(ph_str)
 | 
						||
                else:
 | 
						||
                    ph_value = float(raw_ph)
 | 
						||
 | 
						||
                result.append({
 | 
						||
                    'timestamp': raw_ts.strftime('%Y-%m-%d %H:%M:%S') if isinstance(raw_ts,
 | 
						||
                                                                                    datetime.datetime) else raw_ts,
 | 
						||
                    'ph': round(ph_value, 2),
 | 
						||
                    'formatted_time': dt.strftime('%H:%M')
 | 
						||
                })
 | 
						||
            except ValueError as ve:
 | 
						||
                logger.error(f"第 {i + 1} 条记录格式错误: {str(ve)}")
 | 
						||
                logger.error(f"  原始数据: timestamp={raw_ts}, ph={raw_ph}")
 | 
						||
            except TypeError as te:
 | 
						||
                logger.error(f"第 {i + 1} 条记录类型错误: {str(te)}")
 | 
						||
                logger.error(f"  原始数据: timestamp={raw_ts}, ph={raw_ph}")
 | 
						||
            except Exception as e:
 | 
						||
                logger.error(f"处理第 {i + 1} 条记录时未知错误: {str(e)}")
 | 
						||
 | 
						||
        if not result:
 | 
						||
            logger.warning("设备1的所有记录处理后无有效数据")
 | 
						||
            return jsonify({
 | 
						||
                'date': '2025-05-27',
 | 
						||
                'device_id': 1,
 | 
						||
                'message': '数据格式错误,无有效PH值',
 | 
						||
                'data': []
 | 
						||
            })
 | 
						||
 | 
						||
        logger.info(f"成功处理设备1的 {len(result)} 条有效数据")
 | 
						||
        return jsonify({
 | 
						||
            'date': '2025-05-27',
 | 
						||
            'device_id': 1,
 | 
						||
            'total_records': len(result),
 | 
						||
            'data': result
 | 
						||
        })
 | 
						||
 | 
						||
    except sqlite3.OperationalError as oe:
 | 
						||
        logger.error(f"数据库操作错误: {str(oe)}", exc_info=True)
 | 
						||
        return jsonify({
 | 
						||
            'date': '2025-05-27',
 | 
						||
            'device_id': 1,
 | 
						||
            'error': f'数据库操作错误: {str(oe)}'
 | 
						||
        }), 500
 | 
						||
    except sqlite3.Error as se:
 | 
						||
        logger.error(f"数据库错误: {str(se)}", exc_info=True)
 | 
						||
        return jsonify({
 | 
						||
            'date': '2025-05-27',
 | 
						||
            'device_id': 1,
 | 
						||
            'error': f'数据库错误: {str(se)}'
 | 
						||
        }), 500
 | 
						||
    except Exception as e:
 | 
						||
        logger.error(f"未知异常: {str(e)}", exc_info=True)
 | 
						||
        return jsonify({
 | 
						||
            'date': '2025-05-27',
 | 
						||
            'device_id': 1,
 | 
						||
            'error': f'未知错误: {str(e)}'
 | 
						||
        }), 500
 | 
						||
    finally:
 | 
						||
        close_db() |