import asyncio import logging from typing import Dict, Any, Optional from unilabos.ros.nodes.base_device_node import BaseROS2DeviceNode class VirtualSeparator: """Virtual separator device for SeparateProtocol testing""" _ros_node: BaseROS2DeviceNode def __init__(self, device_id: Optional[str] = None, config: Optional[Dict[str, Any]] = None, **kwargs): # 处理可能的不同调用方式 if device_id is None and "id" in kwargs: device_id = kwargs.pop("id") if config is None and "config" in kwargs: config = kwargs.pop("config") # 设置默认值 self.device_id = device_id or "unknown_separator" self.config = config or {} self.logger = logging.getLogger(f"VirtualSeparator.{self.device_id}") self.data = {} # 添加调试信息 print(f"=== VirtualSeparator {self.device_id} is being created! ===") print(f"=== Config: {self.config} ===") print(f"=== Kwargs: {kwargs} ===") # 从config或kwargs中获取配置参数 self.port = self.config.get("port") or kwargs.get("port", "VIRTUAL") self._volume = self.config.get("volume") or kwargs.get("volume", 250.0) self._has_phases = self.config.get("has_phases") or kwargs.get("has_phases", True) # 处理其他kwargs参数,但跳过已知的配置参数 skip_keys = {"port", "volume", "has_phases"} for key, value in kwargs.items(): if key not in skip_keys and not hasattr(self, key): setattr(self, key, value) def post_init(self, ros_node: BaseROS2DeviceNode): self._ros_node = ros_node async def initialize(self) -> bool: """Initialize virtual separator""" print(f"=== VirtualSeparator {self.device_id} initialize() called! ===") self.logger.info(f"Initializing virtual separator {self.device_id}") self.data.update( { "status": "Ready", "separator_state": "Ready", "volume": self._volume, "has_phases": self._has_phases, "phase_separation": False, "stir_speed": 0.0, "settling_time": 0.0, "progress": 0.0, "message": "", } ) return True async def cleanup(self) -> bool: """Cleanup virtual separator""" self.logger.info(f"Cleaning up virtual separator {self.device_id}") return True async def separate( self, purpose: str, product_phase: str, from_vessel: str, separation_vessel: str, to_vessel: str, waste_phase_to_vessel: str = "", solvent: str = "", solvent_volume: float = 50.0, through: str = "", repeats: int = 1, stir_time: float = 30.0, stir_speed: float = 300.0, settling_time: float = 300.0, ) -> bool: """Execute separate action - matches Separate action""" self.logger.info(f"Separate: purpose={purpose}, product_phase={product_phase}, from_vessel={from_vessel}") # 验证参数 if product_phase not in ["top", "bottom"]: self.logger.error(f"Invalid product_phase {product_phase}, must be 'top' or 'bottom'") self.data["message"] = f"产物相位 {product_phase} 无效,必须是 'top' 或 'bottom'" return False if purpose not in ["wash", "extract"]: self.logger.error(f"Invalid purpose {purpose}, must be 'wash' or 'extract'") self.data["message"] = f"分离目的 {purpose} 无效,必须是 'wash' 或 'extract'" return False # 开始分离 self.data.update( { "status": "Running", "separator_state": "Separating", "purpose": purpose, "product_phase": product_phase, "from_vessel": from_vessel, "separation_vessel": separation_vessel, "to_vessel": to_vessel, "waste_phase_to_vessel": waste_phase_to_vessel, "solvent": solvent, "solvent_volume": solvent_volume, "repeats": repeats, "stir_speed": stir_speed, "settling_time": settling_time, "phase_separation": True, "progress": 0.0, "message": f"正在分离: {from_vessel} -> {to_vessel}", } ) # 模拟分离过程 total_time = (stir_time + settling_time) * repeats simulation_time = min(total_time / 60.0, 15.0) # 最多模拟15秒 for repeat in range(repeats): # 搅拌阶段 for progress in range(0, 51, 10): await self._ros_node.sleep(simulation_time / (repeats * 10)) overall_progress = ((repeat * 100) + (progress * 0.5)) / repeats self.data["progress"] = overall_progress self.data["message"] = f"第{repeat+1}次分离 - 搅拌中 ({progress}%)" # 静置分相阶段 for progress in range(50, 101, 10): await self._ros_node.sleep(simulation_time / (repeats * 10)) overall_progress = ((repeat * 100) + (progress * 0.5)) / repeats self.data["progress"] = overall_progress self.data["message"] = f"第{repeat+1}次分离 - 静置分相中 ({progress}%)" # 分离完成 self.data.update( { "status": "Ready", "separator_state": "Ready", "phase_separation": False, "stir_speed": 0.0, "progress": 100.0, "message": f"分离完成: {repeats}次分离操作", } ) self.logger.info(f"Separation completed: {repeats} cycles from {from_vessel} to {to_vessel}") return True # 状态属性 @property def status(self) -> str: return self.data.get("status", "Unknown") @property def separator_state(self) -> str: return self.data.get("separator_state", "Unknown") @property def volume(self) -> float: return self.data.get("volume", self._volume) @property def has_phases(self) -> bool: return self.data.get("has_phases", self._has_phases) @property def phase_separation(self) -> bool: return self.data.get("phase_separation", False) @property def stir_speed(self) -> float: return self.data.get("stir_speed", 0.0) @property def settling_time(self) -> float: return self.data.get("settling_time", 0.0) @property def progress(self) -> float: return self.data.get("progress", 0.0) @property def message(self) -> str: return self.data.get("message", "")