import flask from flask import request, jsonify import os import sqlite3 from datetime import datetime import pytz # Импортируем библиотеку для работы с часовыми поясами import matplotlib.pyplot as plt import io import base64 from dotenv import load_dotenv import globs from flask import render_template from api_logic import api load_dotenv() # Инициализация базы данных def init_db(db_name): conn = sqlite3.connect(db_name) cursor = conn.cursor() # Создаем таблицу cursor.execute(''' CREATE TABLE IF NOT EXISTS system_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- Автоинкрементный счётчик date_time TEXT, -- Дата и время dey TEXT, wek TEXT, v_hid TEXT, v_min TEXT, ph TEXT, ec TEXT, tS TEXT, tA TEXT, hDm TEXT, sVen TEXT, onA TEXT, onB TEXT, onC TEXT ) ''') conn.commit() conn.close() # Глобальные переменные globs.dey = 0 globs.wek = 0 globs.v_hid = 0 globs.v_min = 0 globs.ph = 0 globs.ec = 0 globs.tS = 0 globs.tA = 0 globs.hDm = 0 globs.sVen = 0 globs.onA = 0 globs.onB = 0 globs.onC = 0 globs.ph_eep = 0 globs.ph_on_eep = 0 globs.ec_eep = 0 globs.ec_A_eep = 0 globs.ec_B_eep = 0 globs.ec_C_eep = 0 globs.l_ON_h_eep = 0 globs.l_ON_m_eep = 0 globs.l_OFF_h_eep = 0 globs.l_OFF_m_eep = 0 globs.t_Voz_eep = 0 # Создаем экземпляр Flask-приложения app = flask.Flask(__name__, template_folder="./") app.config['DEBUG'] = True # Функция сохранения в базу def save_data_to_db(db_name, data): try: conn = sqlite3.connect(db_name) cursor = conn.cursor() # ✅ Устанавливаем московское время (UTC+3) moscow_tz = pytz.timezone("Europe/Moscow") current_time = datetime.now(moscow_tz).strftime('%Y-%m-%d %H:%M:%S') # Вставляем данные в таблицу cursor.execute(''' INSERT INTO system_data ( date_time, dey, wek, v_hid, v_min, ph, ec, tS, tA, hDm, sVen, onA, onB, onC ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( current_time, # ✅ Дата и время по Москве data['dey'], data['wek'], data['v_hid'], data['v_min'], data['ph'], data['ec'], data['tS'], data['tA'], data['hDm'], data['sVen'], data['onA'], data['onB'], data['onC'] )) conn.commit() conn.close() except Exception as e: return jsonify({'status': 'error', 'message': str(e)}), 500 # Маршрут сохранения в базу @app.route('/sav_db_api', methods=['GET']) def sav_db_api(): # Инициализируем базу данных init_db('system_data.db') # Получаем данные из запроса data = { 'dey': request.args.get('dey'), 'wek': request.args.get('wek'), 'v_hid': request.args.get('v_hid'), 'v_min': request.args.get('v_min'), 'ph': request.args.get('ph'), 'ec': request.args.get('ec'), 'tS': request.args.get('tS'), 'tA': request.args.get('tA'), 'hDm': request.args.get('hDm'), 'sVen': request.args.get('sVen'), 'onA': request.args.get('onA'), 'onB': request.args.get('onB'), 'onC': request.args.get('onC') } # Проверяем, что все необходимые параметры переданы required_params = ['dey', 'wek', 'v_hid', 'v_min', 'ph', 'ec', 'tS', 'tA', 'hDm', 'sVen', 'onA', 'onB', 'onC'] for param in required_params: if data[param] is None: return jsonify({'status': 'error', 'message': f'Отсутствует параметр: {param}'}), 400 # Сохраняем данные в базу save_data_to_db('system_data.db', data) # Возвращаем ответ return jsonify({'status': 'success', 'message': 'Данные сохранены'}) # Маршрут для вывода всех данных из таблицы @app.route('/get_all_data', methods=['GET']) def get_all_data(): try: conn = sqlite3.connect('system_data.db') cursor = conn.cursor() # Выполняем запрос для получения всех данных из таблицы cursor.execute('SELECT * FROM system_data') rows = cursor.fetchall() # Получаем названия столбцов column_names = [description[0] for description in cursor.description] # Преобразуем данные в формат JSON data = [] for row in rows: data.append(dict(zip(column_names, row))) conn.close() # Возвращаем данные в формате JSON return jsonify(data) except Exception as e: return jsonify({'status': 'error', 'message': str(e)}), 500 @app.route('/plot_ph', methods=['GET']) def plot_ph(): try: # Получаем параметры из URL (если они есть) start_date = request.args.get('start_date') end_date = request.args.get('end_date') # Если параметры есть, проверяем их корректность if start_date and end_date: try: # Преобразуем даты в формат datetime start_date = datetime.strptime(start_date, '%Y-%m-%dT%H:%M') end_date = datetime.strptime(end_date, '%Y-%m-%dT%H:%M') # Проверяем, что дата начала раньше даты окончания if start_date >= end_date: return '''

Неправильная дата выбрана

Дата начала должна быть раньше даты окончания.

''' except ValueError: return '''

Неправильная дата выбрана

Формат даты должен быть YYYY-MM-DDTHH:MM.

''' # Подключаемся к базе данных conn = sqlite3.connect('system_data.db') cursor = conn.cursor() # Проверяем, существует ли таблица cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='system_data'") table_exists = cursor.fetchone() if not table_exists: return '''

В базе данных отсутствуют значения

Таблица system_data не существует. Обновите базу данных.

''' # Выполняем запрос для получения данных в заданном диапазоне cursor.execute(''' SELECT date_time, ph, dey, wek FROM system_data WHERE date_time BETWEEN ? AND ? ORDER BY date_time ''', (start_date, end_date)) rows = cursor.fetchall() conn.close() # Проверяем, есть ли данные if not rows: return '''

Данные отсутствуют в базе данных

Для выбранного диапазона дат данные не найдены.

''' # Разделяем данные на дату и время, а также добавляем значения из столбцов dey и wek dates = [f"{row[0]} d: {row[2]} w: {row[3]}" for row in rows] # Дата и время + dey + wek ph_values = [float(row[1]) for row in rows] # Значения pH # Создаем график plt.figure(figsize=(15, 6)) # Увеличиваем ширину графика plt.plot(dates, ph_values, marker='o', linestyle='-', color='b') # Точки соединены линией plt.title('График значений pH') plt.xlabel('Дата и время') plt.ylabel('Значение pH') plt.xticks(rotation=90) # Поворачиваем подписи оси X вертикально plt.grid(True) plt.gcf().subplots_adjust(bottom=0.4) # Увеличиваем пространство снизу для надписей # Сохраняем график в буфер buffer = io.BytesIO() plt.savefig(buffer, format='png') buffer.seek(0) # Кодируем график в base64 plot_data = base64.b64encode(buffer.getvalue()).decode('utf-8') # Возвращаем график в формате HTML с кнопками "Новые данные" и "Обновить данные" return f'''

График значений pH



График pH ''' # Если параметров нет, отображаем форму для ввода даты и времени return '''

Выберите диапазон даты и времени для графика pH





''' except Exception as e: return jsonify({'status': 'error', 'message': str(e)}), 500 @app.route('/plot_week', methods=['GET']) def plot_week(): try: # Получаем номер недели из параметров запроса week_number = request.args.get('week', default=1, type=int) week_number = max(1, min(30, week_number)) # Ограничиваем диапазон 1-30 # Подключаемся к базе данных conn = sqlite3.connect('system_data.db') cursor = conn.cursor() # Проверяем существование таблицы cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='system_data'") table_exists = cursor.fetchone() if not table_exists: conn.close() return render_template('plot_week.html', data=None, week_number=week_number, table_exists=False) # Запрашиваем данные за выбранную неделю cursor.execute(''' SELECT date_time, dey, ph, ec, tS, tA, hDm, sVen, onA, onB, onC FROM system_data WHERE wek = ? ORDER BY date_time ''', (str(week_number),)) # Приводим week_number к строке, так как wek имеет тип TEXT rows = cursor.fetchall() conn.close() # Если данных нет if not rows: return render_template('plot_week.html', data=None, week_number=week_number, table_exists=True) # Формируем данные для JSON data = { 'week': week_number, 'dates': [row[0] for row in rows], 'days_of_week': [int(row[1]) if row[1] else 0 for row in rows], # Преобразуем dey в int 'ph': [float(row[2]) if row[2] else 0.0 for row in rows], # pH 'ec': [float(row[3]) if row[3] else 0.0 for row in rows], # EC 'tS': [float(row[4]) if row[4] else 0.0 for row in rows], # Температура раствора 'tA': [float(row[5]) if row[5] else 0.0 for row in rows], # Температура воздуха 'hDm': [float(row[6]) if row[6] else 0.0 for row in rows], # Влажность воздуха 'sVen': [float(row[7]) if row[7] else 0.0 for row in rows], # Обороты вентилятора 'onA': [float(row[8]) if row[8] else 0.0 for row in rows], # Насос A 'onB': [float(row[9]) if row[9] else 0.0 for row in rows], # Насос B 'onC': [float(row[10]) if row[10] else 0.0 for row in rows] # Насос C } # Отправляем данные в HTML-шаблон return render_template('plot_week.html', data=data, week_number=week_number, table_exists=True) except Exception as e: # Логируем ошибку в консоль для отладки print(f"Ошибка: {str(e)}") return render_template('plot_week.html', data=None, week_number=week_number, table_exists=True, message=f"Ошибка: {str(e)}") @app.route("/") def index(): return flask.render_template('index.html') @app.route('/online', methods=['GET']) def online(): return render_template('online.html') @app.route('/calculate', methods=['GET']) def calculate(): return render_template('calculate.html') @app.route('/online_api', methods=['GET']) def online_api(): return jsonify(dey=globs.dey, wek=globs.wek, v_hid=globs.v_hid, v_min=globs.v_min, ph=globs.ph, ec=globs.ec, tS=globs.tS, tA=globs.tA, hDm=globs.hDm, sVen=globs.sVen, rFul=globs.rFul, rLi=globs.rLi, rWat=globs.rWat, rRas=globs.rRas, rPH=globs.rPH, rEC=globs.rEC, rSl=globs.rSl, rLe=globs.rLe, alW=globs.alW ) @app.route('/settings', methods=['GET']) def settings(): return render_template('settings.html') @app.route('/settings_api', methods=['GET']) def settings_api(): return jsonify(ph_eep=globs.ph_eep, ph_on_eep=globs.ph_on_eep, ec_eep=globs.ec_eep, ec_A_eep=globs.ec_A_eep, ec_B_eep=globs.ec_B_eep, ec_C_eep=globs.ec_C_eep, l_ON_h_eep=globs.l_ON_h_eep, l_ON_m_eep=globs.l_ON_m_eep, l_OFF_h_eep=globs.l_OFF_h_eep, l_OFF_m_eep=globs.l_OFF_m_eep, t_Voz_eep=globs.t_Voz_eep ) @app.route('/pH_set', methods=['GET']) def set_pH_value(): ph_value = request.args.get('value') globs.ph_set = ph_value globs.eep_set = 1 return "pH value set successfully" @app.route('/ph_on_set', methods=['GET']) def ph_on_value(): ph_on_value = request.args.get('value') globs.ph_on_set = ph_on_value globs.eep_set = 2 return "EC value set successfully" @app.route('/EC_set', methods=['GET']) def set_EC_value(): ec_value = request.args.get('value') globs.ec_set = ec_value globs.eep_set = 3 return "EC value set successfully" @app.route('/ec_A_set', methods=['GET']) def ec_A_setValue(): ec_A_setValue = request.args.get('value') globs.ec_A_set = ec_A_setValue globs.eep_set = 4 return "EC value set successfully" @app.route('/ec_B_set', methods=['GET']) def ec_B_setValue(): ec_B_setValue = request.args.get('value') globs.ec_B_set = ec_B_setValue globs.eep_set = 5 return "EC value set successfully" @app.route('/ec_C_set', methods=['GET']) def ec_C_setValue(): ec_C_setValue = request.args.get('value') globs.ec_C_set = ec_C_setValue globs.eep_set = 6 return "EC value set successfully" @app.route('/l_ON_set', methods=['GET']) def l_ON_set(): globs.l_ON_h_set = request.args.get('l_ON_h_set') globs.l_ON_m_set = request.args.get('l_ON_m_set') globs.eep_set = 7 return "EC value set successfully" @app.route('/l_OFF_set', methods=['GET']) def l_OFF_set(): globs.l_OFF_h_set = request.args.get('l_OFF_h_set') globs.l_OFF_m_set = request.args.get('l_OFF_m_set') globs.eep_set = 8 return "EC value set successfully" @app.route('/t_Voz_eep_set', methods=['GET']) def t_Voz_eep_set(): t_Voz_eep_set = request.args.get('value') globs.t_Voz_set = t_Voz_eep_set globs.eep_set = 9 return "EC value set successfully" @app.route('/but_start', methods=['GET']) def but_start(): globs.eep_set = 10 return jsonify(value_set="start") @app.route('/but_stop', methods=['GET']) def but_stop(): globs.eep_set = 11 return jsonify(value_set="stop") @app.route('/but_res', methods=['GET']) def but_res(): globs.eep_set = 12 return jsonify(value_set="res") @app.route('/but_sliv', methods=['GET']) def but_sliv(): globs.eep_set = 13 return jsonify(value_set="sliv") @app.route("/api", methods=['GET']) def handle_api(): response = api() return response @app.route("/save_db", methods=['GET']) def handle_save_db(): response = save_db() return response @app.route('/set_res') def set_res(): globs.eep_set = 0 return jsonify(value_set="reset") if __name__ == '__main__': app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))