base_agent/uas/action/main.py

169 lines
7.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;}}")