import os import json import time import threading from flask import Flask, jsonify, request, render_template from dotenv import load_dotenv from datetime import datetime load_dotenv() app = Flask(__name__) # Создаем папку для логов при запуске UPLOAD_FOLDER = 'data/battery_logs' os.makedirs(UPLOAD_FOLDER, exist_ok=True) # Глобальная переменная для хранения данных cached_data = {} def file_read(filename, interval=1.0): """Функция для постоянного чтения файла в отдельном потоке""" global cached_data while True: try: with open(filename, 'r', encoding='utf-8') as file: cached_data = json.load(file) except FileNotFoundError: print(f"Файл {filename} не найден. Ожидание...") except json.JSONDecodeError as e: print(f"Ошибка декодирования JSON в файле {filename}: {e}") except Exception as e: print(f"Неожиданная ошибка при чтении файла {filename}: {e}") time.sleep(interval) @app.route('/upload', methods=['POST']) def upload_file(): """ Принимаем CSV файл от ESP32-C3 """ try: device_id = request.headers.get('X-Device-ID', 'unknown') file_name = request.headers.get('X-File-Name', 'log.csv') csv_data = request.get_data(as_text=True) if not csv_data: return jsonify({'error': 'No data received'}), 400 device_folder = os.path.join(UPLOAD_FOLDER, device_id) os.makedirs(device_folder, exist_ok=True) timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') safe_filename = f"{timestamp}_{file_name}" file_path = os.path.join(device_folder, safe_filename) with open(file_path, 'w', encoding='utf-8') as f: f.write(csv_data) print(f"✅ Получен файл от {device_id}: {len(csv_data)} байт") print(f" Сохранен как: {file_path}") return jsonify({ 'status': 'success', 'message': 'File saved', 'filename': safe_filename, 'size': len(csv_data) }), 200 except Exception as e: print(f"❌ Ошибка: {e}") return jsonify({'error': str(e)}), 500 @app.route('/', methods=['POST']) def receive_string(): """Прием простой текстовой строки""" text_data = request.data.decode('utf-8') clean_list = [item.strip() for item in text_data.split(',')] if not cached_data: return '*no data*' result_values = [] for key in clean_list: if key in cached_data: strValue = str(cached_data[key]) if '_' in strValue: result_values.append(strValue[:strValue.index('_')]) else: result_values.append(strValue) else: result_values.append(f'? {key} ?') return '*' + '*'.join(result_values) + '*' @app.route('/', methods=['GET']) def sample(): global cached_data if cached_data: return jsonify(cached_data) else: test_data = { "Temp": 23.5, "Hum": 45, "Pres": 750, "status": "no_file" } return jsonify(test_data) @app.route('/sensors', methods=['GET']) def get_sensors(): """Красивое отображение данных датчиков в браузере""" global cached_data # Если запрошен JSON формат if request.args.get('format') == 'json': if cached_data: return jsonify(cached_data) else: test_data = { "Temp": 23.5, "Hum": 45, "Pres": 750, "status": "no_data" } return jsonify(test_data) # Иначе возвращаем красивую HTML страницу return render_template('sensors.html', data=cached_data) if __name__ == '__main__': filename = os.getenv('FILE_CACHE_JSON_NAME') if not filename: print("❌ Ошибка: переменная FILE_CACHE_JSON_NAME не задана в .env") filename = 'sensors_cache.json' print(f"📁 Файлы будут сохраняться в: {os.path.abspath(UPLOAD_FOLDER)}") print("🌐 Доступ по адресу: http://localhost:5000") print("📤 Endpoint для загрузки: http://localhost:5000/upload") print("📊 Endpoint для датчиков: http://localhost:5000/sensors") print("-" * 50) data_thread = threading.Thread(target=file_read, args=(filename, 2), daemon=True) data_thread.start() host = os.getenv('SERVER_IP', '0.0.0.0') port = int(os.getenv('PORT_HTTP', 5000)) app.run(host=host, port=port)