385 lines
13 KiB
Python
385 lines
13 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
内置 Action 处理器实现
|
||
─────────────────────────────────────────────────────────────────
|
||
每个处理函数签名:
|
||
def handler(action: Action, ctx: ActionContext) -> Any
|
||
|
||
处理函数内部通过 ctx.emit_event() 产生一个或多个 Event 对象
|
||
─────────────────────────────────────────────────────────────────
|
||
"""
|
||
|
||
import logging
|
||
import random
|
||
import time
|
||
|
||
from uas.action.action_context import ActionContext
|
||
from uas.action.action_model import Action
|
||
from uas.event.event_model import make_event
|
||
# 复用 Event 模块
|
||
from uas.event.event_type import EventType
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
# ─────────────────────────────────────────────────────────────────
|
||
# 控制类 Action 处理器
|
||
# ─────────────────────────────────────────────────────────────────
|
||
|
||
def handle_pause(action: Action, ctx: ActionContext) -> dict:
|
||
"""
|
||
暂停处理器
|
||
产生事件:DEVICE_STATUS_CHANGED
|
||
"""
|
||
ctx.report_progress(10, "发送暂停指令...")
|
||
time.sleep(0.1) # 模拟指令发送延迟
|
||
|
||
ctx.check_cancel()
|
||
ctx.report_progress(80, "等待设备响应...")
|
||
time.sleep(0.1)
|
||
|
||
# 产生状态变更事件
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_STATUS_CHANGED,
|
||
source = action.source,
|
||
message = f"设备已暂停",
|
||
prev_state = "running",
|
||
curr_state = "paused",
|
||
action_id = action.action_id,
|
||
))
|
||
|
||
ctx.report_progress(100, "暂停完成")
|
||
logger.info(f"⏸ 暂停完成: {action.source}")
|
||
return {"status": "paused", "device": action.source}
|
||
|
||
|
||
def handle_resume(action: Action, ctx: ActionContext) -> dict:
|
||
"""
|
||
继续处理器
|
||
产生事件:DEVICE_STATUS_CHANGED
|
||
"""
|
||
ctx.report_progress(20, "发送继续指令...")
|
||
time.sleep(0.1)
|
||
|
||
ctx.check_cancel()
|
||
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_STATUS_CHANGED,
|
||
source = action.source,
|
||
message = "设备已恢复运行",
|
||
prev_state = "paused",
|
||
curr_state = "running",
|
||
action_id = action.action_id,
|
||
))
|
||
|
||
ctx.report_progress(100, "继续完成")
|
||
logger.info(f"▶️ 继续完成: {action.source}")
|
||
return {"status": "running", "device": action.source}
|
||
|
||
|
||
def handle_stop(action: Action, ctx: ActionContext) -> dict:
|
||
"""
|
||
停止处理器
|
||
产生事件:DEVICE_STATUS_CHANGED + SYSTEM_WARNING(若强制停止)
|
||
"""
|
||
force = action.params.get("force", False)
|
||
ctx.report_progress(10, "准备停止...")
|
||
|
||
if force:
|
||
# 强制停止:产生警告事件
|
||
ctx.emit_event(make_event(
|
||
EventType.SYSTEM_WARNING,
|
||
source = action.source,
|
||
message = "强制停止指令已执行",
|
||
level = "warning",
|
||
))
|
||
|
||
ctx.report_progress(60, "执行停止序列...")
|
||
time.sleep(0.2)
|
||
ctx.check_cancel()
|
||
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_STATUS_CHANGED,
|
||
source = action.source,
|
||
message = "设备已停止",
|
||
prev_state = "running",
|
||
curr_state = "stopped",
|
||
force = force,
|
||
))
|
||
|
||
ctx.report_progress(100, "停止完成")
|
||
logger.info(f"⏹ 停止完成: {action.source} force={force}")
|
||
return {"status": "stopped", "force": force}
|
||
|
||
|
||
def handle_reset(action: Action, ctx: ActionContext) -> dict:
|
||
"""
|
||
重置处理器
|
||
产生事件:DEVICE_RESET + DEVICE_STATUS_CHANGED
|
||
"""
|
||
ctx.report_progress(10, "开始重置...")
|
||
time.sleep(0.1)
|
||
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_RESET,
|
||
source = action.source,
|
||
message = "设备重置开始",
|
||
))
|
||
|
||
ctx.report_progress(50, "重置中...")
|
||
time.sleep(0.2)
|
||
ctx.check_cancel()
|
||
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_STATUS_CHANGED,
|
||
source = action.source,
|
||
message = "设备重置完成",
|
||
curr_state = "idle",
|
||
))
|
||
|
||
ctx.report_progress(100, "重置完成")
|
||
logger.info(f"🔄 重置完成: {action.source}")
|
||
return {"status": "reset_done"}
|
||
|
||
|
||
# ─────────────────────────────────────────────────────────────────
|
||
# 感知类 Action 处理器
|
||
# ─────────────────────────────────────────────────────────────────
|
||
|
||
def handle_capture_photo(action: Action, ctx: ActionContext) -> dict:
|
||
"""
|
||
拍照处理器
|
||
产生事件:DEVICE_DATA_RECEIVED(含图像元数据)
|
||
"""
|
||
resolution = action.params.get("resolution", "1080P")
|
||
fmt = action.params.get("format", "jpg")
|
||
camera_id = action.source
|
||
|
||
ctx.report_progress(20, f"初始化相机 {camera_id}...")
|
||
time.sleep(0.05)
|
||
ctx.check_cancel()
|
||
|
||
ctx.report_progress(60, "曝光采集...")
|
||
time.sleep(0.1)
|
||
|
||
# 模拟图像数据
|
||
photo_meta = {
|
||
"camera_id": camera_id,
|
||
"resolution": resolution,
|
||
"format": fmt,
|
||
"file_path": f"/data/photos/{camera_id}_{int(time.time())}.{fmt}",
|
||
"size_kb": random.randint(500, 5000),
|
||
"exposure_ms": random.randint(10, 100),
|
||
}
|
||
|
||
# 产生数据到达事件
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_DATA_RECEIVED,
|
||
source = camera_id,
|
||
message = f"拍照完成 [{resolution}]",
|
||
data_type = "image",
|
||
**photo_meta,
|
||
))
|
||
|
||
ctx.report_progress(100, "拍照完成")
|
||
logger.info(f"📷 拍照完成: {camera_id} {resolution} -> {photo_meta['file_path']}")
|
||
return photo_meta
|
||
|
||
|
||
def handle_recognize_target(action: Action, ctx: ActionContext) -> dict:
|
||
"""
|
||
目标识别处理器
|
||
产生事件:
|
||
- DEVICE_DATA_RECEIVED(识别结果)
|
||
- EQUIPMENT_ALARM(若发现威胁目标)
|
||
"""
|
||
model = action.params.get("model", "yolov8")
|
||
confidence = action.params.get("confidence", 0.85)
|
||
image_path = action.params.get("image_path", "")
|
||
|
||
ctx.report_progress(10, f"加载模型 {model}...")
|
||
time.sleep(0.1)
|
||
ctx.check_cancel()
|
||
|
||
ctx.report_progress(40, "推理中...")
|
||
time.sleep(0.2)
|
||
ctx.check_cancel()
|
||
|
||
# 模拟识别结果
|
||
targets = [
|
||
{"id": f"T{i:03d}", "label": random.choice(["aircraft", "vehicle", "person"]),
|
||
"confidence": round(random.uniform(0.7, 0.99), 3),
|
||
"bbox": [random.randint(0, 640) for _ in range(4)]}
|
||
for i in range(random.randint(0, 3))
|
||
]
|
||
|
||
ctx.report_progress(80, f"发现 {len(targets)} 个目标...")
|
||
|
||
# 产生识别结果事件
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_DATA_RECEIVED,
|
||
source = action.source,
|
||
message = f"目标识别完成,发现 {len(targets)} 个目标",
|
||
data_type = "recognition",
|
||
model = model,
|
||
targets = targets,
|
||
image_path = image_path,
|
||
))
|
||
|
||
# 若发现高威胁目标,额外产生告警事件
|
||
threat_targets = [t for t in targets if t["label"] == "aircraft"
|
||
and t["confidence"] > 0.9]
|
||
if threat_targets:
|
||
ctx.emit_event(make_event(
|
||
EventType.EQUIPMENT_ALARM,
|
||
source = action.source,
|
||
message = f"发现 {len(threat_targets)} 个高威胁目标!",
|
||
level = "critical",
|
||
targets = threat_targets,
|
||
))
|
||
logger.warning(f"🚨 发现威胁目标: {threat_targets}")
|
||
|
||
ctx.report_progress(100, "识别完成")
|
||
logger.info(f"🎯 目标识别完成: {len(targets)} 个目标")
|
||
return {"targets": targets, "model": model}
|
||
|
||
|
||
def handle_scan_environment(action: Action, ctx: ActionContext) -> dict:
|
||
"""
|
||
环境扫描处理器
|
||
产生事件:DEVICE_DATA_RECEIVED(扫描数据)+ DEVICE_WARNING(若发现异常)
|
||
"""
|
||
scan_range = action.params.get("range_m", 100)
|
||
sensor = action.source
|
||
|
||
ctx.report_progress(10, "初始化传感器...")
|
||
time.sleep(0.05)
|
||
|
||
scan_data = []
|
||
steps = 5
|
||
for i in range(steps):
|
||
ctx.check_cancel()
|
||
time.sleep(0.05)
|
||
ctx.report_progress(
|
||
int((i + 1) / steps * 80),
|
||
f"扫描中 {int((i+1)/steps*100)}%..."
|
||
)
|
||
scan_data.append({
|
||
"angle": i * (360 // steps),
|
||
"distance": random.uniform(5, scan_range),
|
||
"intensity": random.uniform(0.1, 1.0),
|
||
})
|
||
|
||
# 产生扫描数据事件
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_DATA_RECEIVED,
|
||
source = sensor,
|
||
message = f"环境扫描完成,范围 {scan_range}m",
|
||
data_type = "lidar_scan",
|
||
points = len(scan_data),
|
||
scan_data = scan_data,
|
||
))
|
||
|
||
# 检测到近距离障碍物
|
||
close_obstacles = [d for d in scan_data if d["distance"] < 10]
|
||
if close_obstacles:
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_WARNING,
|
||
source = sensor,
|
||
message = f"检测到 {len(close_obstacles)} 个近距离障碍物",
|
||
obstacles = close_obstacles,
|
||
))
|
||
|
||
ctx.report_progress(100, "扫描完成")
|
||
return {"scan_points": len(scan_data), "range_m": scan_range}
|
||
|
||
|
||
# ─────────────────────────────────────────────────────────────────
|
||
# 系统类 Action 处理器
|
||
# ─────────────────────────────────────────────────────────────────
|
||
|
||
def handle_system_diagnose(action: Action, ctx: ActionContext) -> dict:
|
||
"""
|
||
系统诊断处理器
|
||
产生事件:SYSTEM_WARNING(若发现问题)或 DEVICE_STATUS_CHANGED
|
||
"""
|
||
checks = ["CPU", "内存", "存储", "网络", "传感器"]
|
||
results = {}
|
||
|
||
for i, check in enumerate(checks):
|
||
ctx.check_cancel()
|
||
time.sleep(0.05)
|
||
ctx.report_progress(int((i + 1) / len(checks) * 90), f"检查 {check}...")
|
||
status = random.choice(["normal", "normal", "normal", "warning"])
|
||
results[check] = status
|
||
|
||
if status == "warning":
|
||
ctx.emit_event(make_event(
|
||
EventType.SYSTEM_WARNING,
|
||
source = action.source,
|
||
message = f"诊断发现 {check} 异常",
|
||
component = check,
|
||
level = "warning",
|
||
))
|
||
|
||
# 产生诊断完成事件
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_STATUS_CHANGED,
|
||
source = action.source,
|
||
message = "系统诊断完成",
|
||
curr_state = "diagnosed",
|
||
results = results,
|
||
))
|
||
|
||
ctx.report_progress(100, "诊断完成")
|
||
warnings = [k for k, v in results.items() if v == "warning"]
|
||
logger.info(f"🔧 系统诊断完成: {results} warnings={warnings}")
|
||
return {"results": results, "warnings": warnings}
|
||
|
||
|
||
def handle_system_calibrate(action: Action, ctx: ActionContext) -> dict:
|
||
"""
|
||
设备校准处理器
|
||
产生事件:DEVICE_CALIBRATED
|
||
"""
|
||
sensor_ids = action.params.get("sensors", ["all"])
|
||
ctx.report_progress(10, "开始校准...")
|
||
|
||
for i, sid in enumerate(sensor_ids):
|
||
ctx.check_cancel()
|
||
time.sleep(0.1)
|
||
ctx.report_progress(
|
||
int((i + 1) / len(sensor_ids) * 90),
|
||
f"校准传感器 {sid}..."
|
||
)
|
||
|
||
ctx.emit_event(make_event(
|
||
EventType.DEVICE_CALIBRATED,
|
||
source = action.source,
|
||
message = f"校准完成,传感器: {sensor_ids}",
|
||
sensors = sensor_ids,
|
||
accuracy = round(random.uniform(0.95, 0.999), 4),
|
||
))
|
||
|
||
ctx.report_progress(100, "校准完成")
|
||
logger.info(f"📐 校准完成: {action.source} sensors={sensor_ids}")
|
||
return {"calibrated": sensor_ids}
|
||
|
||
|
||
# ─────────────────────────────────────────────────────────────────
|
||
# 处理器映射表(供 ActionRegistry 使用)
|
||
# ─────────────────────────────────────────────────────────────────
|
||
|
||
from uas.action.action_type import ActionType
|
||
|
||
BUILTIN_HANDLERS = {
|
||
ActionType.PAUSE: handle_pause,
|
||
ActionType.RESUME: handle_resume,
|
||
ActionType.STOP: handle_stop,
|
||
ActionType.RESET: handle_reset,
|
||
ActionType.CAPTURE_PHOTO: handle_capture_photo,
|
||
ActionType.RECOGNIZE_TARGET: handle_recognize_target,
|
||
ActionType.SCAN_ENVIRONMENT: handle_scan_environment,
|
||
ActionType.SYSTEM_DIAGNOSE: handle_system_diagnose,
|
||
ActionType.SYSTEM_CALIBRATE: handle_system_calibrate,
|
||
} |