base_agent/uas/action/main.py

169 lines
7.3 KiB
Python
Raw Normal View History

2026-06-18 03:28:14 +00:00
import logging
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QMainWindow, QWidget,
QVBoxLayout, QHBoxLayout, QSplitter,
QGroupBox, QLabel, QPushButton, QProgressBar
)
from registry.action_registry import action_factory
from uas.action.action_executor import action_executor
from uas.action.action_model import ActionState
# ── Action 模块 ───────────────────────────────────────────────────
from uas.action.action_type import ActionCategory, action_registry
from uas.event.event_bus import event_bus
from uas.event.event_model import make_event
# ── Event 模块(复用)────────────────────────────────────────────
from uas.event.event_type import EventType
from uas.event.handlers.device_handlers import (
DeviceErrorHandler, DeviceTimeoutHandler, EquipmentFaultHandler
)
logging.basicConfig(
level = logging.DEBUG,
format = "%(asctime)s [%(levelname)-8s] %(name)s - %(message)s",
)
logger = logging.getLogger("main")
# ─────────────────────────────────────────────────────────────────
# 主窗口
# ─────────────────────────────────────────────────────────────────
class ActionMonitorWindow(QMainWindow):
STATE_COLORS = {
ActionState.COMPLETED: "#4CAF50",
ActionState.FAILED: "#f44336",
ActionState.CANCELLED: "#FF9800",
ActionState.RUNNING: "#2196F3",
ActionState.QUEUED: "#607D8B",
ActionState.TIMEOUT: "#9C27B0",
ActionState.INTERRUPTED: "#FF5722",
}
def __init__(self):
super().__init__()
self.setWindowTitle("🛰️ Action 监控系统 — PyQt5 演示")
self.resize(1300, 800)
self._setup_modules()
self._setup_ui()
self._auto_demo()
# ── 模块初始化 ────────────────────────────────────────────────
def _setup_modules(self):
# 1. 注册 EventBus 处理器
event_bus.register_handler(DeviceErrorHandler())
event_bus.register_handler(DeviceTimeoutHandler())
event_bus.register_handler(EquipmentFaultHandler())
event_bus.scan_decorators()
# 2. 将 EventBus 注入 ActionExecutorAction产生的Event自动提交
action_executor.set_event_bus(event_bus)
# 3. 注册自定义 Action 类型(演示扩展)
action_registry.register(
"perception.thermal_scan",
category = ActionCategory.PERCEPTION,
description = "红外热成像扫描",
timeout_sec = 20.0,
)
from uas.action.action_context import ActionContext
from uas.action.action_model import Action
def handle_thermal_scan(action: Action, ctx: ActionContext):
import time, random
ctx.report_progress(30, "预热红外传感器...")
time.sleep(0.1)
ctx.check_cancel()
ctx.report_progress(70, "采集热成像数据...")
time.sleep(0.1)
ctx.emit_event(make_event(
EventType.DEVICE_DATA_RECEIVED,
source = action.source,
message = "红外热成像采集完成",
data_type = "thermal",
max_temp = round(random.uniform(20, 80), 1),
min_temp = round(random.uniform(-10, 20), 1),
))
ctx.report_progress(100, "热成像完成")
return {"thermal": "ok"}
action_factory.register("perception.thermal_scan", handle_thermal_scan)
# 4. 连接 ActionExecutor 信号到 UI 槽
action_executor.action_submitted.connect(self._on_action_submitted)
action_executor.action_completed.connect(self._on_action_completed)
action_executor.action_failed.connect(self._on_action_failed)
action_executor.action_cancelled.connect(self._on_action_cancelled)
action_executor.action_progress.connect(self._on_action_progress)
action_executor.events_produced.connect(self._on_events_produced)
action_executor.stats_updated.connect(self._on_stats_updated)
# 5. 连接 EventBus 信号到 UI 槽
event_bus.event_handled.connect(self._on_event_handled)
# ── UI 构建 ───────────────────────────────────────────────────
def _setup_ui(self):
central = QWidget()
self.setCentralWidget(central)
root = QVBoxLayout(central)
root.setContentsMargins(6, 6, 6, 6)
splitter = QSplitter(Qt.Horizontal)
# ── 左侧:控制面板 ────────────────────────────────────────
left = QWidget()
left.setFixedWidth(300)
left_layout = QVBoxLayout(left)
# 统计卡片
stats_box = QGroupBox("📊 执行统计")
stats_layout = QHBoxLayout(stats_box)
self._lbl_submitted = self._stat_card("提交", "0", "#2196F3")
self._lbl_completed = self._stat_card("完成", "0", "#4CAF50")
self._lbl_failed = self._stat_card("失败", "0", "#f44336")
self._lbl_cancelled = self._stat_card("取消", "0", "#FF9800")
for lbl in [self._lbl_submitted, self._lbl_completed,
self._lbl_failed, self._lbl_cancelled]:
stats_layout.addWidget(lbl)
left_layout.addWidget(stats_box)
# 进度条
prog_box = QGroupBox("⚙️ 当前进度")
prog_layout = QVBoxLayout(prog_box)
self._prog_label = QLabel("等待任务...")
self._prog_label.setStyleSheet("color: gray; font-size: 11px;")
self._progress_bar = QProgressBar()
self._progress_bar.setRange(0, 100)
self._progress_bar.setValue(0)
prog_layout.addWidget(self._prog_label)
prog_layout.addWidget(self._progress_bar)
left_layout.addWidget(prog_box)
# Action 触发按钮
btn_box = QGroupBox("🎯 触发 Action")
btn_layout = QVBoxLayout(btn_box)
btn_defs = [
("⏸ 暂停", self._do_pause, "#607D8B"),
("▶️ 继续", self._do_resume, "#4CAF50"),
("⏹ 停止", self._do_stop, "#f44336"),
("🔄 重置", self._do_reset, "#FF9800"),
("📷 拍照", self._do_capture_photo, "#2196F3"),
("🎯 识别目标", self._do_recognize, "#9C27B0"),
("🔍 环境扫描", self._do_scan, "#00BCD4"),
("🌡️ 红外扫描", self._do_thermal, "#FF5722"),
("🔧 系统诊断", self._do_diagnose, "#795548"),
("📐 设备校准", self._do_calibrate, "#009688"),
("🚀 批量执行(5个)", self._do_batch, "#673AB7"),
]
for text, slot, color in btn_defs:
btn = QPushButton(text)
btn.setMinimumHeight(30)
btn.setStyleSheet(
f"QPushButton{{background:{color};color:white;"
f"border-radius:4px;font-size:12px;}}")