|
@@ -1,21 +1,44 @@
|
|
|
-from flask import Flask, jsonify, request, render_template, send_from_directory
|
|
|
|
|
|
|
+from flask import Flask, jsonify, request, render_template, send_from_directory, session, redirect, url_for, flash
|
|
|
|
|
+from functools import wraps
|
|
|
from flask_cors import CORS
|
|
from flask_cors import CORS
|
|
|
import json
|
|
import json
|
|
|
|
|
+import yaml
|
|
|
import os
|
|
import os
|
|
|
import time
|
|
import time
|
|
|
import uuid
|
|
import uuid
|
|
|
import socket
|
|
import socket
|
|
|
|
|
+import threading
|
|
|
from werkzeug.utils import secure_filename
|
|
from werkzeug.utils import secure_filename
|
|
|
from application.kodi_alive_thread import start_kodi_alive_check
|
|
from application.kodi_alive_thread import start_kodi_alive_check
|
|
|
from application.kodi_free_time_thread import start_kodi_free_time_play
|
|
from application.kodi_free_time_thread import start_kodi_free_time_play
|
|
|
from application.wled_thread import start_exhibit_led_effect, stop_led_effect, is_effect_running
|
|
from application.wled_thread import start_exhibit_led_effect, stop_led_effect, is_effect_running
|
|
|
-from application.kodi_thread import start_kodi_play, stop_kodi_play, is_kodi_thread_running, play_image, play_rtsp, revoke_individual_state, start_all_kodi_apps
|
|
|
|
|
|
|
+from application.kodi_thread import start_kodi_play, stop_kodi_play, is_kodi_thread_running, play_image, play_rtsp, revoke_individual_state, start_all_kodi_apps, get_kodi_clients, get_video_list, set_volume
|
|
|
|
|
+from hardware.mitvs_module import turn_on_display, turn_off_display, turn_on_all_displays, turn_off_all_displays
|
|
|
|
|
+from hardware.door_module import set_emergency_control, open_door_control
|
|
|
from utils.logger_config import logger
|
|
from utils.logger_config import logger
|
|
|
|
|
|
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
app = Flask(__name__)
|
|
|
|
|
+app.secret_key = 'your_secret_key_here_hnhz_0821' # 用于 session 加密,请更改为随机字符串
|
|
|
CORS(app) # 允许跨域请求
|
|
CORS(app) # 允许跨域请求
|
|
|
|
|
|
|
|
|
|
+# 登录账号配置
|
|
|
|
|
+ADMIN_USERNAME = 'admin'
|
|
|
|
|
+ADMIN_PASSWORD = 'HNYZ0821'
|
|
|
|
|
+
|
|
|
|
|
+# 登录验证装饰器
|
|
|
|
|
+def login_required(f):
|
|
|
|
|
+ @wraps(f)
|
|
|
|
|
+ def decorated_function(*args, **kwargs):
|
|
|
|
|
+ if 'logged_in' not in session:
|
|
|
|
|
+ # 如果是 API 请求,返回 401
|
|
|
|
|
+ if request.path.startswith('/api/'):
|
|
|
|
|
+ return jsonify({'success': False, 'message': '未登录'}), 401
|
|
|
|
|
+ # 如果是页面请求,跳转到登录页
|
|
|
|
|
+ return redirect(url_for('login'))
|
|
|
|
|
+ return f(*args, **kwargs)
|
|
|
|
|
+ return decorated_function
|
|
|
|
|
+
|
|
|
# 配置上传文件夹
|
|
# 配置上传文件夹
|
|
|
UPLOAD_FOLDER = 'uploads'
|
|
UPLOAD_FOLDER = 'uploads'
|
|
|
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'}
|
|
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'}
|
|
@@ -50,13 +73,56 @@ def get_server_ip():
|
|
|
return "127.0.0.1" # 回退到localhost
|
|
return "127.0.0.1" # 回退到localhost
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+def load_led_config():
|
|
|
|
|
+ """读取LED配置文件"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ config_path = 'led_config.yaml'
|
|
|
|
|
+ if os.path.exists(config_path):
|
|
|
|
|
+ with open(config_path, 'r', encoding='utf-8') as f:
|
|
|
|
|
+ config = yaml.safe_load(f)
|
|
|
|
|
+ return config.get('segments', [])
|
|
|
|
|
+ return []
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"读取LED配置文件失败: {e}")
|
|
|
|
|
+ return []
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@app.route('/login', methods=['GET', 'POST'])
|
|
|
|
|
+def login():
|
|
|
|
|
+ """登录页面"""
|
|
|
|
|
+ if request.method == 'POST':
|
|
|
|
|
+ username = request.form.get('username')
|
|
|
|
|
+ password = request.form.get('password')
|
|
|
|
|
+
|
|
|
|
|
+ if username == ADMIN_USERNAME and password == ADMIN_PASSWORD:
|
|
|
|
|
+ session['logged_in'] = True
|
|
|
|
|
+ # flash('登录成功', 'success') # 登录成功不需要提示,直接进
|
|
|
|
|
+ return redirect(url_for('index'))
|
|
|
|
|
+ else:
|
|
|
|
|
+ flash('账号或密码错误', 'error')
|
|
|
|
|
+ return render_template('login.html')
|
|
|
|
|
+
|
|
|
|
|
+ return render_template('login.html')
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@app.route('/logout')
|
|
|
|
|
+def logout():
|
|
|
|
|
+ """登出"""
|
|
|
|
|
+ session.pop('logged_in', None)
|
|
|
|
|
+ flash('已退出登录', 'success')
|
|
|
|
|
+ return redirect(url_for('login'))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
@app.route('/')
|
|
@app.route('/')
|
|
|
|
|
+@login_required
|
|
|
def index():
|
|
def index():
|
|
|
"""返回HTML页面"""
|
|
"""返回HTML页面"""
|
|
|
- return render_template('index.html')
|
|
|
|
|
|
|
+ led_segments = load_led_config()
|
|
|
|
|
+ return render_template('index.html', led_segments=led_segments)
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/led/status', methods=['GET'])
|
|
@app.route('/api/led/status', methods=['GET'])
|
|
|
|
|
+@login_required
|
|
|
def get_led_status():
|
|
def get_led_status():
|
|
|
"""获取LED状态"""
|
|
"""获取LED状态"""
|
|
|
try:
|
|
try:
|
|
@@ -76,6 +142,7 @@ def get_led_status():
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/led/start', methods=['POST'])
|
|
@app.route('/api/led/start', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
def start_led_effect():
|
|
def start_led_effect():
|
|
|
"""启动展品LED灯效控制"""
|
|
"""启动展品LED灯效控制"""
|
|
|
try:
|
|
try:
|
|
@@ -117,6 +184,7 @@ def start_led_effect():
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/led/stop', methods=['POST'])
|
|
@app.route('/api/led/stop', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
def stop_led_effect_api():
|
|
def stop_led_effect_api():
|
|
|
"""停止当前LED灯效"""
|
|
"""停止当前LED灯效"""
|
|
|
try:
|
|
try:
|
|
@@ -144,6 +212,7 @@ def stop_led_effect_api():
|
|
|
|
|
|
|
|
# ===== Kodi 播放控制接口 =====
|
|
# ===== Kodi 播放控制接口 =====
|
|
|
@app.route('/api/kodi/status', methods=['GET'])
|
|
@app.route('/api/kodi/status', methods=['GET'])
|
|
|
|
|
+@login_required
|
|
|
def get_kodi_status():
|
|
def get_kodi_status():
|
|
|
try:
|
|
try:
|
|
|
running = is_kodi_thread_running()
|
|
running = is_kodi_thread_running()
|
|
@@ -161,7 +230,40 @@ def get_kodi_status():
|
|
|
}), 500
|
|
}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+@app.route('/api/kodi/clients', methods=['GET'])
|
|
|
|
|
+@login_required
|
|
|
|
|
+def get_kodi_clients_api():
|
|
|
|
|
+ """获取所有Kodi客户端列表"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ clients = get_kodi_clients()
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": True,
|
|
|
|
|
+ "data": clients
|
|
|
|
|
+ })
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": f"获取Kodi客户端列表失败: {str(e)}"
|
|
|
|
|
+ }), 500
|
|
|
|
|
+
|
|
|
|
|
+@app.route('/api/kodi/videos', methods=['GET'])
|
|
|
|
|
+@login_required
|
|
|
|
|
+def get_kodi_videos_api():
|
|
|
|
|
+ """获取所有视频列表"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ videos = get_video_list()
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": True,
|
|
|
|
|
+ "data": videos
|
|
|
|
|
+ })
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": f"获取视频列表失败: {str(e)}"
|
|
|
|
|
+ }), 500
|
|
|
|
|
+
|
|
|
@app.route('/api/kodi/start', methods=['POST'])
|
|
@app.route('/api/kodi/start', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
def start_kodi_play_api():
|
|
def start_kodi_play_api():
|
|
|
try:
|
|
try:
|
|
|
data = request.get_json()
|
|
data = request.get_json()
|
|
@@ -171,17 +273,27 @@ def start_kodi_play_api():
|
|
|
"message": "缺少视频ID参数"
|
|
"message": "缺少视频ID参数"
|
|
|
}), 400
|
|
}), 400
|
|
|
video_id = data['video_id']
|
|
video_id = data['video_id']
|
|
|
|
|
+ volume = data.get('volume', -1)
|
|
|
if not isinstance(video_id, int) or video_id < 0:
|
|
if not isinstance(video_id, int) or video_id < 0:
|
|
|
return jsonify({
|
|
return jsonify({
|
|
|
"success": False,
|
|
"success": False,
|
|
|
"message": "视频ID必须是大于等于0的整数"
|
|
"message": "视频ID必须是大于等于0的整数"
|
|
|
}), 400
|
|
}), 400
|
|
|
- ok = start_kodi_play(video_id)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # 验证 volume 参数
|
|
|
|
|
+ if volume != -1:
|
|
|
|
|
+ if not isinstance(volume, int) or not (0 <= volume <= 100):
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "音量必须是 0-100 之间的整数"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ ok = start_kodi_play(video_id, volume)
|
|
|
if ok:
|
|
if ok:
|
|
|
return jsonify({
|
|
return jsonify({
|
|
|
"success": True,
|
|
"success": True,
|
|
|
- "message": f"Kodi开始/切换播放 视频ID={video_id}",
|
|
|
|
|
- "data": {"video_id": video_id}
|
|
|
|
|
|
|
+ "message": f"Kodi开始/切换播放 视频ID={video_id} 音量={'默认' if volume == -1 else volume}",
|
|
|
|
|
+ "data": {"video_id": video_id, "volume": volume}
|
|
|
})
|
|
})
|
|
|
return jsonify({
|
|
return jsonify({
|
|
|
"success": False,
|
|
"success": False,
|
|
@@ -195,6 +307,7 @@ def start_kodi_play_api():
|
|
|
|
|
|
|
|
# 指定某台kodi_client_index播放图片,这边要上传图片并且传递完整url给kodi播放
|
|
# 指定某台kodi_client_index播放图片,这边要上传图片并且传递完整url给kodi播放
|
|
|
@app.route('/api/kodi/play_image', methods=['POST'])
|
|
@app.route('/api/kodi/play_image', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
def play_image_api():
|
|
def play_image_api():
|
|
|
"""播放图片接口,支持文件上传或直接传递图片URL"""
|
|
"""播放图片接口,支持文件上传或直接传递图片URL"""
|
|
|
try:
|
|
try:
|
|
@@ -321,6 +434,7 @@ def play_image_api():
|
|
|
|
|
|
|
|
# 指定某台kodi_client_index播放rtsp视频
|
|
# 指定某台kodi_client_index播放rtsp视频
|
|
|
@app.route('/api/kodi/play_rtsp', methods=['POST'])
|
|
@app.route('/api/kodi/play_rtsp', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
def play_rtsp_api():
|
|
def play_rtsp_api():
|
|
|
"""播放RTSP视频流接口"""
|
|
"""播放RTSP视频流接口"""
|
|
|
try:
|
|
try:
|
|
@@ -393,6 +507,7 @@ def play_rtsp_api():
|
|
|
}), 500
|
|
}), 500
|
|
|
|
|
|
|
|
@app.route('/api/kodi/revoke_individual_state', methods=['POST'])
|
|
@app.route('/api/kodi/revoke_individual_state', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
def revoke_individual_state_api():
|
|
def revoke_individual_state_api():
|
|
|
"""撤销所有客户端的独立状态接口"""
|
|
"""撤销所有客户端的独立状态接口"""
|
|
|
try:
|
|
try:
|
|
@@ -415,6 +530,7 @@ def revoke_individual_state_api():
|
|
|
}), 500
|
|
}), 500
|
|
|
|
|
|
|
|
@app.route('/api/kodi/start_all_apps', methods=['POST'])
|
|
@app.route('/api/kodi/start_all_apps', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
def start_all_kodi_apps_api():
|
|
def start_all_kodi_apps_api():
|
|
|
"""启动所有kodi应用程序接口"""
|
|
"""启动所有kodi应用程序接口"""
|
|
|
try:
|
|
try:
|
|
@@ -436,6 +552,44 @@ def start_all_kodi_apps_api():
|
|
|
"message": f"启动所有kodi应用程序失败: {str(e)}"
|
|
"message": f"启动所有kodi应用程序失败: {str(e)}"
|
|
|
}), 500
|
|
}), 500
|
|
|
|
|
|
|
|
|
|
+@app.route('/api/kodi/set_volume', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
|
|
+def set_kodi_volume_api():
|
|
|
|
|
+ """设置Kodi播放音量接口"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ data = request.get_json()
|
|
|
|
|
+ if not data or 'volume' not in data:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "缺少 volume 参数"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ volume = data['volume']
|
|
|
|
|
+ if not isinstance(volume, int) or not (0 <= volume <= 100):
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "音量必须是 0-100 之间的整数"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ success = set_volume(volume)
|
|
|
|
|
+ if success:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": True,
|
|
|
|
|
+ "message": f"已设置音量为 {volume}",
|
|
|
|
|
+ "data": {"volume": volume}
|
|
|
|
|
+ })
|
|
|
|
|
+ else:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "设置音量失败"
|
|
|
|
|
+ }), 500
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"设置音量异常: {str(e)}")
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": f"设置音量失败: {str(e)}"
|
|
|
|
|
+ }), 500
|
|
|
|
|
+
|
|
|
# 提供上传文件的访问接口
|
|
# 提供上传文件的访问接口
|
|
|
@app.route('/uploads/<filename>')
|
|
@app.route('/uploads/<filename>')
|
|
|
def uploaded_file(filename):
|
|
def uploaded_file(filename):
|
|
@@ -443,6 +597,231 @@ def uploaded_file(filename):
|
|
|
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
|
|
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+# ===== 电视开关控制接口 =====
|
|
|
|
|
+
|
|
|
|
|
+@app.route('/api/mitv/turn_on', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
|
|
+def turn_on_display_api():
|
|
|
|
|
+ """唤醒指定ID的电视"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ data = request.get_json()
|
|
|
|
|
+ if not data or 'kodi_id' not in data:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "缺少 kodi_id 参数"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ kodi_id = data['kodi_id']
|
|
|
|
|
+ if not isinstance(kodi_id, int) or kodi_id < 0:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "kodi_id 必须是大于等于0的整数"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ def task():
|
|
|
|
|
+ try:
|
|
|
|
|
+ turn_on_display(kodi_id)
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"异步唤醒电视异常 (ID: {kodi_id}): {str(e)}")
|
|
|
|
|
+
|
|
|
|
|
+ threading.Thread(target=task).start()
|
|
|
|
|
+
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": True,
|
|
|
|
|
+ "message": f"已发送唤醒指令给电视 (ID: {kodi_id}) - 异步执行"
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"唤醒电视异常: {str(e)}")
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": f"唤醒电视失败: {str(e)}"
|
|
|
|
|
+ }), 500
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@app.route('/api/mitv/turn_off', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
|
|
+def turn_off_display_api():
|
|
|
|
|
+ """息屏指定ID的电视"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ data = request.get_json()
|
|
|
|
|
+ if not data or 'kodi_id' not in data:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "缺少 kodi_id 参数"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ kodi_id = data['kodi_id']
|
|
|
|
|
+ if not isinstance(kodi_id, int) or kodi_id < 0:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "kodi_id 必须是大于等于0的整数"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ def task():
|
|
|
|
|
+ try:
|
|
|
|
|
+ turn_off_display(kodi_id)
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"异步息屏电视异常 (ID: {kodi_id}): {str(e)}")
|
|
|
|
|
+
|
|
|
|
|
+ threading.Thread(target=task).start()
|
|
|
|
|
+
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": True,
|
|
|
|
|
+ "message": f"已发送息屏指令给电视 (ID: {kodi_id}) - 异步执行"
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"息屏电视异常: {str(e)}")
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": f"息屏电视失败: {str(e)}"
|
|
|
|
|
+ }), 500
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@app.route('/api/mitv/turn_on_all', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
|
|
+def turn_on_all_displays_api():
|
|
|
|
|
+ """唤醒所有电视"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ def task():
|
|
|
|
|
+ try:
|
|
|
|
|
+ turn_on_all_displays()
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"异步唤醒所有电视异常: {str(e)}")
|
|
|
|
|
+
|
|
|
|
|
+ threading.Thread(target=task).start()
|
|
|
|
|
+
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": True,
|
|
|
|
|
+ "message": "已发送唤醒指令给所有电视 - 异步执行"
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"唤醒所有电视异常: {str(e)}")
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": f"唤醒所有电视失败: {str(e)}"
|
|
|
|
|
+ }), 500
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@app.route('/api/mitv/turn_off_all', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
|
|
+def turn_off_all_displays_api():
|
|
|
|
|
+ """息屏所有电视"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ def task():
|
|
|
|
|
+ try:
|
|
|
|
|
+ turn_off_all_displays()
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"异步息屏所有电视异常: {str(e)}")
|
|
|
|
|
+
|
|
|
|
|
+ threading.Thread(target=task).start()
|
|
|
|
|
+
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": True,
|
|
|
|
|
+ "message": "已发送息屏指令给所有电视 - 异步执行"
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"息屏所有电视异常: {str(e)}")
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": f"息屏所有电视失败: {str(e)}"
|
|
|
|
|
+ }), 500
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+# ===== 门禁控制接口 =====
|
|
|
|
|
+@app.route('/api/door/control', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
|
|
+def door_control_api():
|
|
|
|
|
+ """门禁控制接口"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ data = request.get_json()
|
|
|
|
|
+ if not data or 'control_way' not in data:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "缺少 control_way 参数"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ control_way = data['control_way']
|
|
|
|
|
+ password = data.get('password') # 可选参数
|
|
|
|
|
+
|
|
|
|
|
+ if not isinstance(control_way, int) or control_way not in [0, 1, 2]:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "control_way 必须是 0(在线), 1(常开), 2(常闭)"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ def task():
|
|
|
|
|
+ try:
|
|
|
|
|
+ set_emergency_control(control_way, password)
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"异步门禁控制异常 (Mode: {control_way}): {str(e)}")
|
|
|
|
|
+
|
|
|
|
|
+ threading.Thread(target=task).start()
|
|
|
|
|
+
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": True,
|
|
|
|
|
+ "message": "已发送门禁控制指令 - 异步执行",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "control_way": control_way
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"门禁控制异常: {str(e)}")
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": f"门禁控制失败: {str(e)}"
|
|
|
|
|
+ }), 500
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@app.route('/api/door/open', methods=['POST'])
|
|
|
|
|
+@login_required
|
|
|
|
|
+def door_open_api():
|
|
|
|
|
+ """远程开门接口"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ data = request.get_json()
|
|
|
|
|
+ if not data or 'door_id' not in data:
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "缺少 door_id 参数"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ door_id = data['door_id']
|
|
|
|
|
+ password = data.get('password') # 可选参数
|
|
|
|
|
+
|
|
|
|
|
+ if not isinstance(door_id, int):
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": "door_id 必须是整数"
|
|
|
|
|
+ }), 400
|
|
|
|
|
+
|
|
|
|
|
+ def task():
|
|
|
|
|
+ try:
|
|
|
|
|
+ open_door_control(door_id, password)
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"异步远程开门异常 (ID: {door_id}): {str(e)}")
|
|
|
|
|
+
|
|
|
|
|
+ threading.Thread(target=task).start()
|
|
|
|
|
+
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": True,
|
|
|
|
|
+ "message": "已发送远程开门指令 - 异步执行",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "door_id": door_id
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"远程开门异常: {str(e)}")
|
|
|
|
|
+ return jsonify({
|
|
|
|
|
+ "success": False,
|
|
|
|
|
+ "message": f"远程开门失败: {str(e)}"
|
|
|
|
|
+ }), 500
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
if __name__ == '__main__':
|
|
|
# 创建templates目录
|
|
# 创建templates目录
|
|
@@ -460,10 +839,18 @@ if __name__ == '__main__':
|
|
|
logger.info(" POST /api/led/start - 启动展品灯效")
|
|
logger.info(" POST /api/led/start - 启动展品灯效")
|
|
|
logger.info(" POST /api/led/stop - 停止灯效")
|
|
logger.info(" POST /api/led/stop - 停止灯效")
|
|
|
logger.info(" GET /api/kodi/status - 获取Kodi状态")
|
|
logger.info(" GET /api/kodi/status - 获取Kodi状态")
|
|
|
|
|
+ logger.info(" GET /api/kodi/clients - 获取Kodi客户端列表")
|
|
|
|
|
+ logger.info(" GET /api/kodi/videos - 获取视频列表")
|
|
|
logger.info(" POST /api/kodi/start - 启动/切换Kodi播放")
|
|
logger.info(" POST /api/kodi/start - 启动/切换Kodi播放")
|
|
|
logger.info(" POST /api/kodi/play_image - 播放图片(支持上传或URL)")
|
|
logger.info(" POST /api/kodi/play_image - 播放图片(支持上传或URL)")
|
|
|
logger.info(" POST /api/kodi/play_rtsp - 播放RTSP视频流")
|
|
logger.info(" POST /api/kodi/play_rtsp - 播放RTSP视频流")
|
|
|
logger.info(" POST /api/kodi/revoke_individual_state - 撤销所有客户端的独立状态")
|
|
logger.info(" POST /api/kodi/revoke_individual_state - 撤销所有客户端的独立状态")
|
|
|
logger.info(" POST /api/kodi/start_all_apps - 启动所有kodi应用程序")
|
|
logger.info(" POST /api/kodi/start_all_apps - 启动所有kodi应用程序")
|
|
|
|
|
+ logger.info(" POST /api/mitv/turn_on - 唤醒电视 (参数: kodi_id)")
|
|
|
|
|
+ logger.info(" POST /api/mitv/turn_off - 息屏电视 (参数: kodi_id)")
|
|
|
|
|
+ logger.info(" POST /api/mitv/turn_on_all - 唤醒所有电视")
|
|
|
|
|
+ logger.info(" POST /api/mitv/turn_off_all - 息屏所有电视")
|
|
|
|
|
+ logger.info(" POST /api/door/control - 门禁控制 (参数: control_way [0:在线, 1:常开, 2:常闭])")
|
|
|
|
|
+ logger.info(" POST /api/door/open - 远程开门 (参数: door_id)")
|
|
|
|
|
|
|
|
app.run(debug=True, host='0.0.0.0', port=5050)
|
|
app.run(debug=True, host='0.0.0.0', port=5050)
|