更新物料接口

This commit is contained in:
Xuwznln
2025-10-10 07:13:59 +08:00
parent cfc1ee6e79
commit 5610c28b67
14 changed files with 1801 additions and 325 deletions

View File

@@ -4,6 +4,7 @@
这个模块包含用于创建设备类实例的工厂类。
基础工厂类提供通用的实例创建方法,而特定工厂类提供针对特定设备类的创建方法。
"""
import asyncio
import inspect
import traceback
@@ -53,7 +54,6 @@ class DeviceClassCreator(Generic[T]):
if c["type"] != "device":
self.resource_tracker.add_resource(c)
def create_instance(self, data: Dict[str, Any]) -> T:
"""
创建设备类实例
@@ -118,7 +118,9 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
return nested_dict_to_list(resource), Resource
return resource, source_type
def _process_resource_references(self, data: Any, to_dict=False, states=None, prefix_path="") -> Any:
def _process_resource_references(
self, data: Any, to_dict=False, states=None, prefix_path="", name_to_uuid=None
) -> Any:
"""
递归处理资源引用替换_resource_child_name对应的资源
@@ -127,11 +129,13 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
to_dict: 是否返回字典形式的资源
states: 用于保存所有资源状态
prefix_path: 当前递归路径
name_to_uuid: name到uuid的映射字典
Returns:
处理后的数据
"""
from pylabrobot.resources import Deck, Resource
if states is None:
states = {}
@@ -155,6 +159,9 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
return serialized
else:
self.resource_tracker.add_resource(resource_instance)
# 立即设置UUID
if name_to_uuid:
self.resource_tracker.loop_set_uuid(resource_instance, name_to_uuid)
return resource_instance
except Exception as e:
logger.warning(f"无法导入资源类型 {type_path}: {e}")
@@ -169,12 +176,12 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
result = {}
for key, value in data.items():
new_prefix = f"{prefix_path}.{key}" if prefix_path else key
result[key] = self._process_resource_references(value, to_dict, states, new_prefix)
result[key] = self._process_resource_references(value, to_dict, states, new_prefix, name_to_uuid)
return result
elif isinstance(data, list):
return [
self._process_resource_references(item, to_dict, states, f"{prefix_path}[{i}]")
self._process_resource_references(item, to_dict, states, f"{prefix_path}[{i}]", name_to_uuid)
for i, item in enumerate(data)
]
@@ -193,22 +200,42 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
"""
deserialize_error = None
stack = None
# 递归遍历 children 构建 name_to_uuid 映射
def collect_name_to_uuid(children_dict: Dict[str, Any], result: Dict[str, str]):
"""递归遍历嵌套的 children 字典,收集 name 到 uuid 的映射"""
for child in children_dict.values():
if isinstance(child, dict):
result[child["name"]] = child["uuid"]
collect_name_to_uuid(child["children"], result)
name_to_uuid = {}
collect_name_to_uuid(self.children, name_to_uuid)
if self.has_deserialize:
deserialize_method = getattr(self.device_cls, "deserialize")
spect = inspect.signature(deserialize_method)
spec_args = spect.parameters
for param_name, param_value in data.copy().items():
if isinstance(param_value, dict) and "_resource_child_name" in param_value and "_resource_type" not in param_value:
if (
isinstance(param_value, dict)
and "_resource_child_name" in param_value
and "_resource_type" not in param_value
):
arg_value = spec_args[param_name].annotation
data[param_name]["_resource_type"] = self.device_cls.__module__ + ":" + arg_value
logger.debug(f"自动补充 _resource_type: {data[param_name]['_resource_type']}")
# 首先处理资源引用
states = {}
processed_data = self._process_resource_references(data, to_dict=True, states=states)
processed_data = self._process_resource_references(
data, to_dict=True, states=states, name_to_uuid=name_to_uuid
)
try:
self.device_instance = deserialize_method(**processed_data)
from pylabrobot.resources import Resource
self.device_instance: Resource = deserialize_method(**processed_data)
self.resource_tracker.loop_set_uuid(self.device_instance, name_to_uuid)
all_states = self.device_instance.serialize_all_state()
for k, v in states.items():
logger.debug(f"PyLabRobot反序列化设置状态{k}")
@@ -229,11 +256,15 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
spect = inspect.signature(self.device_cls.__init__)
spec_args = spect.parameters
for param_name, param_value in data.copy().items():
if isinstance(param_value, dict) and "_resource_child_name" in param_value and "_resource_type" not in param_value:
if (
isinstance(param_value, dict)
and "_resource_child_name" in param_value
and "_resource_type" not in param_value
):
arg_value = spec_args[param_name].annotation
data[param_name]["_resource_type"] = self.device_cls.__module__ + ":" + arg_value
logger.debug(f"自动补充 _resource_type: {data[param_name]['_resource_type']}")
processed_data = self._process_resource_references(data, to_dict=False)
processed_data = self._process_resource_references(data, to_dict=False, name_to_uuid=name_to_uuid)
self.device_instance = super(PyLabRobotCreator, self).create_instance(processed_data)
except Exception as e:
logger.error(f"PyLabRobot创建实例失败: {e}")
@@ -247,22 +278,31 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
return self.device_instance
def post_create(self):
if hasattr(self.device_instance, "setup") and asyncio.iscoroutinefunction(getattr(self.device_instance, "setup")):
if hasattr(self.device_instance, "setup") and asyncio.iscoroutinefunction(
getattr(self.device_instance, "setup")
):
from unilabos.ros.nodes.base_device_node import ROS2DeviceNode
def done_cb(*args):
from pylabrobot.resources import set_volume_tracking
# from pylabrobot.resources import set_tip_tracking
set_volume_tracking(enabled=True)
# set_tip_tracking(enabled=True) # 序列化tip_spot has为False
logger.debug(f"PyLabRobot设备实例 {self.device_instance} 设置完成")
from unilabos.config.config import BasicConfig
if BasicConfig.vis_2d_enable:
from pylabrobot.visualizer.visualizer import Visualizer
vis = Visualizer(resource=self.device_instance, open_browser=True)
def vis_done_cb(*args):
logger.info(f"PyLabRobot设备实例开启了Visualizer {self.device_instance}")
ROS2DeviceNode.run_async_func(vis.setup).add_done_callback(vis_done_cb)
logger.debug(f"PyLabRobot设备实例提交开启Visualizer {self.device_instance}")
ROS2DeviceNode.run_async_func(getattr(self.device_instance, "setup")).add_done_callback(done_cb)
@@ -299,6 +339,7 @@ class WorkstationNodeCreator(DeviceClassCreator[T]):
deck_dict = data.get("deck")
if deck_dict:
from pylabrobot.resources import Deck, Resource
plrc = PyLabRobotCreator(Deck, self.children, self.resource_tracker)
deck = plrc.create_instance(deck_dict)
data["deck"] = deck