|
|
@@ -3,6 +3,8 @@ from mcp.server.fastmcp import FastMCP
|
|
|
import sys
|
|
|
import logging
|
|
|
import os
|
|
|
+import threading
|
|
|
+import time
|
|
|
from typing import List, Dict, Any, Optional
|
|
|
import requests
|
|
|
from utils.logger_config import logger
|
|
|
@@ -213,6 +215,9 @@ def kodi_start(video_id: int) -> dict:
|
|
|
def set_global_volume(volume: int) -> dict:
|
|
|
"""设置电视播放视频的全局音量 (转发到 Flask: POST /api/kodi/set_volume)。
|
|
|
|
|
|
+ 使用场景:
|
|
|
+ - 在播放产品视频或公司宣传视频时候,播放声音太小或太大就可以通过这个来控制。
|
|
|
+
|
|
|
参数:
|
|
|
- volume: 音量值,整数 0-100
|
|
|
"""
|
|
|
@@ -230,11 +235,15 @@ def set_global_volume(volume: int) -> dict:
|
|
|
return _flask_post('/api/kodi/set_volume', {"volume": volume})
|
|
|
|
|
|
@mcp.tool(name="打开办公楼大门")
|
|
|
-def open_door(door_id: int) -> dict:
|
|
|
+def open_door(door_id: int = 1) -> dict:
|
|
|
"""打开办公楼大门 (转发到 Flask: POST /api/door/open)。
|
|
|
|
|
|
+ 使用场景:
|
|
|
+ - 当用户说"打开大门"、"帮我开门"时调用此工具。
|
|
|
+ - 目前只控制一个门,默认 door_id 为 1。
|
|
|
+
|
|
|
参数:
|
|
|
- - door_id: 门ID,整数 (必填)
|
|
|
+ - door_id: 门ID,整数,默认为 1
|
|
|
"""
|
|
|
if not isinstance(door_id, int):
|
|
|
return {"success": False, "message": "door_id 必须为整数"}
|
|
|
@@ -302,13 +311,24 @@ def turn_off_tv(kodi_id: int) -> dict:
|
|
|
|
|
|
@mcp.tool(name="打开所有电视")
|
|
|
def turn_on_all_tvs() -> dict:
|
|
|
- """打开所有电视 (转发到 Flask: POST /api/mitv/turn_on_all)。"""
|
|
|
+ """打开所有电视 (转发到 Flask: POST /api/mitv/turn_on_all)。
|
|
|
+
|
|
|
+ 使用场景:
|
|
|
+ - 当用户明确提到"所有"、"全部"时使用,如"打开所有电视"。
|
|
|
+ - 如果用户仅说"开电视"、"帮我把电视打开",未明确指明是"所有"还是"某一台",请不要直接调用本工具,而是先向用户确认:"请问是打开所有电视,还是指定哪一台?"
|
|
|
+ """
|
|
|
logger.info("请求打开所有电视")
|
|
|
return _flask_post('/api/mitv/turn_on_all')
|
|
|
|
|
|
@mcp.tool(name="关闭所有电视")
|
|
|
def turn_off_all_tvs() -> dict:
|
|
|
- """关闭所有电视 (转发到 Flask: POST /api/mitv/turn_off_all)。"""
|
|
|
+ """关闭所有电视 (转发到 Flask: POST /api/mitv/turn_off_all)。
|
|
|
+
|
|
|
+ 使用场景:
|
|
|
+ - 当用户明确提到"所有"、"全部"时使用,如"关闭所有电视"。
|
|
|
+ - 用户说"关闭电视电源"通常也理解为关闭所有电视。
|
|
|
+ - 如果用户仅说"关电视"、"把电视关了",未明确指明是"所有"还是"某一台",请不要直接调用本工具,而是先向用户确认:"请问是关闭所有电视,还是指定哪一台?"
|
|
|
+ """
|
|
|
logger.info("请求关闭所有电视")
|
|
|
return _flask_post('/api/mitv/turn_off_all')
|
|
|
|
|
|
@@ -391,6 +411,167 @@ def control_exhibition_stand_light_strip(action: str) -> dict:
|
|
|
logger.info(f"请求控制展台灯带: {action}")
|
|
|
return _flask_post(f'/api/ha/exhibition_stand_light_strip/{action}')
|
|
|
|
|
|
+@mcp.tool(name="重启展厅所有设备")
|
|
|
+def restart_all_devices() -> dict:
|
|
|
+ """重启展厅所有设备。
|
|
|
+
|
|
|
+ 使用场景:
|
|
|
+ - 当用户反馈设备故障、卡顿、无反应时调用。
|
|
|
+ - 例如用户说:"电视播放卡住了"、"灯光控制没反应"、"设备出问题了"、"系统好像死机了"。
|
|
|
+ - 此时建议主动询问用户:"检测到设备可能出现异常,建议重启展厅所有设备进行恢复,是否现在执行重启?"
|
|
|
+
|
|
|
+ 功能:
|
|
|
+ - 依次关闭所有电视、桌面3D风扇投影、展品灯座。
|
|
|
+ - 等待 1 分钟。
|
|
|
+ - 依次重新启动上述设备。
|
|
|
+ - 此操作异步执行。
|
|
|
+ """
|
|
|
+ def _restart_process():
|
|
|
+ try:
|
|
|
+ logger.info("【重启任务】开始执行...")
|
|
|
+
|
|
|
+ # 1. 关闭设备
|
|
|
+ logger.info("【重启任务】正在关闭设备...")
|
|
|
+ # 关闭所有电视
|
|
|
+ _flask_post('/api/mitv/turn_off_all')
|
|
|
+ # 关闭桌面3D风扇投影
|
|
|
+ _flask_post('/api/ha/exhibition_3d_fan/turn_off')
|
|
|
+ # 关闭展品灯座
|
|
|
+ _flask_post('/api/ha/exhibition_desktop_switch/turn_off')
|
|
|
+
|
|
|
+ # 2. 等待
|
|
|
+ logger.info("【重启任务】设备已关闭,等待 60 秒...")
|
|
|
+ time.sleep(60)
|
|
|
+
|
|
|
+ # 3. 启动设备
|
|
|
+ logger.info("【重启任务】正在启动设备...")
|
|
|
+ # 启动所有电视
|
|
|
+ _flask_post('/api/mitv/turn_on_all')
|
|
|
+ # 启动桌面3D风扇投影
|
|
|
+ _flask_post('/api/ha/exhibition_3d_fan/turn_on')
|
|
|
+ # 启动展品灯座
|
|
|
+ _flask_post('/api/ha/exhibition_desktop_switch/turn_on')
|
|
|
+ # 启动视频播放
|
|
|
+ _flask_post('/api/kodi/free_time/control', {"action": "start"})
|
|
|
+
|
|
|
+ logger.info("【重启任务】执行完成")
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"【重启任务】发生异常: {e}")
|
|
|
+
|
|
|
+ # 启动后台线程
|
|
|
+ t = threading.Thread(target=_restart_process)
|
|
|
+ t.daemon = True
|
|
|
+ t.start()
|
|
|
+
|
|
|
+ return {"success": True, "message": "已开始重启展厅所有设备,全程约需 1 分钟,请耐心等待。"}
|
|
|
+
|
|
|
+@mcp.tool(name="启动迎宾模式")
|
|
|
+def start_welcome_mode() -> dict:
|
|
|
+ """启动迎宾模式。
|
|
|
+
|
|
|
+ 使用场景:
|
|
|
+ - 当用户明确要求"启动迎宾模式"时调用。
|
|
|
+ - 如果用户提到"有客人要来"、"准备接待客人"、"开启接待模式"等含义,请先主动询问用户:"是否需要为您开启迎宾模式?"
|
|
|
+
|
|
|
+ 功能(异步执行):
|
|
|
+ 1. 打开一楼大门玄关顶灯
|
|
|
+ 2. 打开一楼大门玄关射灯
|
|
|
+ 3. 打开一楼展厅顶灯
|
|
|
+ 4. 打开展台桌子灯带
|
|
|
+ 5. 把大门模式设置为常开模式
|
|
|
+ """
|
|
|
+ def _process():
|
|
|
+ try:
|
|
|
+ logger.info("【迎宾模式】正在启动...")
|
|
|
+ # 1.打开一楼大门玄关顶灯
|
|
|
+ _flask_post('/api/ha/entrance_lights/turn_on')
|
|
|
+ # 2.打开一楼大门玄关射灯
|
|
|
+ _flask_post('/api/ha/exhibition_spotlight/turn_on')
|
|
|
+ # 3.打开一楼展厅顶灯
|
|
|
+ _flask_post('/api/ha/exhibition_ceiling_light/turn_on')
|
|
|
+ # 6.打开展台桌子灯带
|
|
|
+ _flask_post('/api/ha/exhibition_stand_light_strip/turn_on')
|
|
|
+ # 7.把大门模式设置为常开模式 (1:常开)
|
|
|
+ _flask_post('/api/door/control', {"control_way": 1})
|
|
|
+ logger.info("【迎宾模式】启动完成")
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"【迎宾模式】启动失败: {e}")
|
|
|
+
|
|
|
+ t = threading.Thread(target=_process)
|
|
|
+ t.daemon = True
|
|
|
+ t.start()
|
|
|
+ return {"success": True, "message": "正在启动迎宾模式..."}
|
|
|
+
|
|
|
+@mcp.tool(name="关闭迎宾模式")
|
|
|
+def stop_welcome_mode() -> dict:
|
|
|
+ """关闭迎宾模式。
|
|
|
+
|
|
|
+ 功能(异步执行):
|
|
|
+ 1. 关闭一楼大门玄关顶灯
|
|
|
+ 2. 关闭一楼大门玄关射灯
|
|
|
+ 3. 关闭一楼展厅顶灯
|
|
|
+ 4. 关闭展台桌子灯带
|
|
|
+ 5. 把大门模式设置为正常模式
|
|
|
+ """
|
|
|
+ def _process():
|
|
|
+ try:
|
|
|
+ logger.info("【迎宾模式】正在关闭...")
|
|
|
+ # 1.关闭一楼大门玄关顶灯
|
|
|
+ _flask_post('/api/ha/entrance_lights/turn_off')
|
|
|
+ # 2.关闭一楼大门玄关射灯
|
|
|
+ _flask_post('/api/ha/exhibition_spotlight/turn_off')
|
|
|
+ # 3.关闭一楼展厅顶灯
|
|
|
+ _flask_post('/api/ha/exhibition_ceiling_light/turn_off')
|
|
|
+ # 6.关闭展台桌子灯带
|
|
|
+ _flask_post('/api/ha/exhibition_stand_light_strip/turn_off')
|
|
|
+ # 7.把大门模式设置为正常模式 (0:正常)
|
|
|
+ _flask_post('/api/door/control', {"control_way": 0})
|
|
|
+ logger.info("【迎宾模式】关闭完成")
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"【迎宾模式】关闭失败: {e}")
|
|
|
+
|
|
|
+ t = threading.Thread(target=_process)
|
|
|
+ t.daemon = True
|
|
|
+ t.start()
|
|
|
+ return {"success": True, "message": "正在关闭迎宾模式..."}
|
|
|
+
|
|
|
+@mcp.tool(name="控制展品以及宣传视频自动播放")
|
|
|
+def control_free_time_playback(action: str) -> dict:
|
|
|
+ """控制展品以及宣传视频自动播放功能 (转发到 Flask: POST /api/kodi/free_time/control)。
|
|
|
+
|
|
|
+ 功能别名:继续电视播放、开启/关闭公司宣传视频播放。
|
|
|
+
|
|
|
+ 使用场景:
|
|
|
+ - 当用户说"继续播放电视"、"电视继续播放"时,通常意味着恢复默认的宣传视频循环播放,请调用 action="start"。
|
|
|
+ - 当用户说"播放宣传视频"、"开启公司宣传视频"、"开启自动播放"时,调用 action="start"。
|
|
|
+ - 当用户说"停止自动播放"、"关闭宣传视频"、"不要播放宣传片了"时,调用 action="stop"。
|
|
|
+
|
|
|
+ 参数:
|
|
|
+ - action: "start" (开启/强制开启) 或 "stop" (停止)
|
|
|
+
|
|
|
+ 功能说明:
|
|
|
+ - 开启后,如果在 07:30-18:00 时间段内,会自动循环播放视频 ID 0 (通常为公司宣传片)。
|
|
|
+ - 手动发送 "start" 会立即强制开启播放,无论是否在时间段内。
|
|
|
+ - 发送 "stop" 会立即强制停止播放。
|
|
|
+ """
|
|
|
+ if action not in ["start", "stop"]:
|
|
|
+ return {"success": False, "message": "action 必须为 'start' 或 'stop'"}
|
|
|
+
|
|
|
+ logger.info(f"请求控制展品以及宣传视频自动播放: {action}")
|
|
|
+ return _flask_post('/api/kodi/free_time/control', {"action": action})
|
|
|
+
|
|
|
+@mcp.tool(name="获取展品以及宣传视频自动播放状态")
|
|
|
+def get_free_time_playback_status() -> dict:
|
|
|
+ """获取展品以及宣传视频自动播放功能的状态 (转发到 Flask: GET /api/kodi/free_time/status)。
|
|
|
+
|
|
|
+ 返回包含:
|
|
|
+ - is_running: 功能开关状态
|
|
|
+ - enabled: 同 is_running
|
|
|
+ - is_thread_alive: 底层线程存活状态
|
|
|
+ """
|
|
|
+ logger.info("请求获取展品以及宣传视频自动播放状态")
|
|
|
+ return _flask_get('/api/kodi/free_time/status')
|
|
|
+
|
|
|
# Start the server
|
|
|
if __name__ == "__main__":
|
|
|
mcp.run(transport="stdio")
|