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
'''
# Если параметров нет, отображаем форму для ввода даты и времени
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)))