Spaces:
Running
Running
| from flask import Flask, request, jsonify, redirect, url_for, render_template | |
| 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 api_logic import api | |
| import requests | |
| import logging | |
| import http.client | |
| import json | |
| from urllib.parse import urlencode # Добавлен правильный импорт | |
| 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, | |
| nPh TEXT, | |
| nEC TEXT, | |
| nTa TEXT, | |
| nLon TEXT, | |
| nLoff TEXT | |
| ) | |
| ''') | |
| # **Новая таблица для пользователей бота** | |
| cursor.execute(''' | |
| CREATE TABLE IF NOT EXISTS bot_users ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, -- Уникальный ID | |
| chat_id INTEGER UNIQUE, -- Telegram ID пользователя | |
| created_at TEXT -- Время добавления (ISO формат) | |
| ) | |
| ''') | |
| conn.commit() | |
| conn.close() | |
| # Глобальные переменные | |
| api_key_sys = os.getenv('api_key') # Берём значение API-ключа из .env | |
| 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(__name__, template_folder="./") | |
| app.config['DEBUG'] = True | |
| # Настроим логирование | |
| logging.basicConfig(level=logging.DEBUG) | |
| # Новый URL для отправки данных (Telegram API) | |
| TELEGRAM_API_URL = "api.telegram.org" | |
| TELEGRAM_BOT_TOKEN = "7766407698:AAGZHEbUuiOri4_YzZ7hDPSD6U8MGMXXSnA" | |
| CHAT_ID = 1343658673 # ID чата | |
| TEXT = "test11" # Текст сообщения | |
| def send_message(chat_id, text): | |
| """Отправка тестового сообщения на Telegram API.""" | |
| conn = http.client.HTTPSConnection(TELEGRAM_API_URL) | |
| # Подготовка данных для URL | |
| params = { | |
| "chat_id": chat_id, | |
| "text": text | |
| } | |
| # Кодируем параметры для URL | |
| url_params = urlencode(params) | |
| # Формируем путь для запроса | |
| url_path = f"/bot{TELEGRAM_BOT_TOKEN}/sendMessage?{url_params}" | |
| try: | |
| # Отправка запроса | |
| conn.request("GET", url_path) | |
| # Получение ответа | |
| response = conn.getresponse() | |
| data = response.read() | |
| # Логируем текстовый ответ для отладки | |
| logging.debug(f"Ответ от Telegram API: {data.decode('utf-8')}") | |
| except Exception as e: | |
| logging.error(f"Ошибка при отправке сообщения: {e}") | |
| finally: | |
| conn.close() | |
| def process(): | |
| """Обрабатывает входящие сообщения от Telegram по новому маршруту.""" | |
| try: | |
| data = request.get_json() | |
| logging.debug(f"Получены данные: {data}") # Лог входящих данных | |
| if "message" not in data: | |
| return {"ok": False, "error": "Нет данных message"}, 400 | |
| chat_id = data["message"]["chat"]["id"] | |
| text = data["message"].get("text", "") | |
| # Ответ на команду или пустой текст | |
| if text == "/start": | |
| send_message(chat_id, "Привет! Я твой бот. Чем могу помочь?") | |
| elif text: | |
| send_message(chat_id, f"Вы отправили: {text}") | |
| else: | |
| send_message(chat_id, "Ты прислал пустое сообщение. Пожалуйста, напиши что-нибудь!") | |
| except Exception as e: | |
| logging.error(f"Ошибка: {e}") | |
| return {"ok": True} | |
| def set_webhook_page(): | |
| return render_template("set_webhook.html") # Загружает HTML-страницу | |
| # Функция сохранения в базу пользователей TG | |
| def save_user(chat_id, db_name="your_database.db"): | |
| conn = sqlite3.connect(db_name) | |
| cursor = conn.cursor() | |
| created_at = datetime.now().isoformat() # Форматируем дату | |
| try: | |
| cursor.execute("INSERT INTO bot_users (chat_id, created_at) VALUES (?, ?)", (chat_id, created_at)) | |
| conn.commit() | |
| except sqlite3.IntegrityError: | |
| print(f"Пользователь {chat_id} уже есть в базе.") | |
| conn.close() | |
| # Функция сохранения в базу данных системы автоматизации гидропоники | |
| 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, nPh, nEC, nTa, nLon, nLoff | |
| ) 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'], data['nPh'], data['nEC'], data['nTa'], data['nLon'], data['nLoff'] | |
| )) | |
| conn.commit() | |
| conn.close() | |
| except Exception as e: | |
| return jsonify({'status': 'error', 'message': str(e)}), 500 | |
| # Маршрут сохранения в базу | |
| 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'), | |
| 'nPh': request.args.get('nPh'), | |
| 'nEC': request.args.get('nEC'), | |
| 'nTa': request.args.get('nTa'), | |
| 'nLon': request.args.get('nLon'), | |
| 'nLoff': request.args.get('nLoff') | |
| } | |
| # Проверяем, что все необходимые параметры переданы | |
| required_params = ['dey', 'wek', 'v_hid', 'v_min', 'ph', 'ec', 'tS', 'tA', 'hDm', 'sVen', 'onA', 'onB', 'onC', 'nPh', 'nEC', 'nTa', 'nLon', 'nLoff'] | |
| 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': 'Save OK'}) | |
| # Проверка входа на страницы | |
| def check_api_key(): | |
| api_sys_param = request.args.get('api_sys') # Получаем параметр из запроса | |
| if api_sys_param == api_key_sys: | |
| return jsonify({"status": "ok"}), 200 # ✅ Совпадает — отправляем "ok" | |
| else: | |
| return jsonify({"status": "error", "message": "Invalid API key"}), 403 # ❌ Ошибка 403 | |
| # Тестовый запрос с установки | |
| def test_server(): | |
| api_key_param = request.args.get('api_sys') # Получаем параметр из запроса | |
| err_ser = 1 if api_key_param == api_key_sys else 0 # Проверяем совпадение ключей | |
| return jsonify(err_ser=err_ser) | |
| def test_server_str(): | |
| api_key_param = request.args.get('api_sys') | |
| err_ser = "1" if api_key_param == api_key_sys else "0" | |
| return err_ser # Возвращаем строку "1" или "0" | |
| # Маршрут для вывода всех данных из таблицы | |
| 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 | |
| # Удаление базы | |
| def delete_db(): | |
| try: | |
| conn = sqlite3.connect("system_data.db") # Используем вашу БД | |
| cursor = conn.cursor() | |
| # ✅ Удаляем все записи из таблицы | |
| cursor.execute("DELETE FROM system_data") | |
| # ✅ Сбрасываем автоинкрементный счётчик ID (для SQLite) | |
| cursor.execute("DELETE FROM sqlite_sequence WHERE name='system_data'") | |
| conn.commit() | |
| conn.close() | |
| return jsonify({'status': 'ok', 'message': 'База данных успешно очищена'}) | |
| except Exception as e: | |
| return jsonify({'status': 'error', 'message': str(e)}), 500 | |
| 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, v_hid, v_min | |
| 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 | |
| 'sus': [f"{row[11]}:{row[12]}" if row[11] and row[12] else "0:0" for row in rows] # Объединяем v_hid и v_min | |
| } | |
| # Отправляем данные в 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)}") | |
| def index(): | |
| return flask.render_template('index.html') | |
| def online(): | |
| return render_template('online.html') | |
| def table(): | |
| return render_template('table.html') | |
| def online_api(): | |
| # Устанавливаем московское время (UTC+3) | |
| moscow_tz = pytz.timezone("Europe/Moscow") | |
| current_time = datetime.now(moscow_tz) | |
| # Форматируем дату и время отдельно | |
| date = current_time.strftime('%Y-%m-%d') # Например, "2025-03-23" | |
| time = current_time.strftime('%H:%M:%S') # Например, "14:35:42" | |
| 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, | |
| ec_A_eep=globs.ec_A_eep, | |
| ec_B_eep=globs.ec_B_eep, | |
| ec_C_eep=globs.ec_C_eep, | |
| date=date, # Добавляем дату | |
| time=time # Добавляем время | |
| ) | |
| def settings(): | |
| return render_template('settings.html') | |
| 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 | |
| ) | |
| def set_pH_value(): | |
| ph_value = request.args.get('value') | |
| globs.ph_set = ph_value | |
| globs.eep_set = 1 | |
| return "pH value set successfully" | |
| 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" | |
| def set_EC_value(): | |
| ec_value = request.args.get('value') | |
| globs.ec_set = ec_value | |
| globs.eep_set = 3 | |
| return "EC value set successfully" | |
| 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" | |
| 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" | |
| 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" | |
| 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" | |
| 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" | |
| 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" | |
| def but_start(): | |
| globs.eep_set = 10 | |
| return jsonify(value_set="start") | |
| def but_stop(): | |
| globs.eep_set = 11 | |
| return jsonify(value_set="stop") | |
| def but_res(): | |
| globs.eep_set = 12 | |
| return jsonify(value_set="res") | |
| def but_sliv(): | |
| globs.eep_set = 13 | |
| return jsonify(value_set="sliv") | |
| def handle_api(): | |
| response = api() | |
| return response | |
| def handle_save_db(): | |
| response = save_db() | |
| return response | |
| 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))) | |