修复solid_feeding_vials方法中的volume参数处理逻辑,优化solvents参数的使用条件

This commit is contained in:
ZiWei
2025-10-29 11:24:37 +08:00
parent b9ddee8f2c
commit 545ea45024
2 changed files with 101 additions and 8 deletions

View File

@@ -232,7 +232,7 @@ class BioyondReactionStation(BioyondWorkstation):
temperature: 温度设定(°C) temperature: 温度设定(°C)
""" """
# 处理 volume 参数:优先使用直接传入的 volume,否则从 solvents 中提取 # 处理 volume 参数:优先使用直接传入的 volume,否则从 solvents 中提取
if volume is None and solvents is not None: if not volume and solvents is not None:
# 参数类型转换:如果是字符串则解析为字典 # 参数类型转换:如果是字符串则解析为字典
if isinstance(solvents, str): if isinstance(solvents, str):
try: try:

View File

@@ -85,8 +85,90 @@ class BioyondResourceSynchronizer(ResourceSynchronizer):
def sync_to_external(self, resource: Any) -> bool: def sync_to_external(self, resource: Any) -> bool:
"""将本地物料数据变更同步到Bioyond系统""" """将本地物料数据变更同步到Bioyond系统"""
try: try:
if self.bioyond_api_client is None: # ✅ 跳过仓库类型的资源 - 仓库是容器,不是物料
logger.error("Bioyond API客户端未初始化") resource_category = getattr(resource, "category", None)
if resource_category == "warehouse":
logger.debug(f"[同步→Bioyond] 跳过仓库类型资源: {resource.name} (仓库是容器,不需要同步为物料)")
return True
logger.info(f"[同步→Bioyond] 收到物料变更: {resource.name}")
# 获取物料的 Bioyond ID
extra_info = getattr(resource, "unilabos_extra", {})
material_bioyond_id = extra_info.get("material_bioyond_id")
# ⭐ 如果没有 Bioyond ID尝试从 Bioyond 系统中按名称查询
if not material_bioyond_id:
logger.warning(f"[同步→Bioyond] 物料 {resource.name} 没有 Bioyond ID尝试按名称查询...")
try:
# 查询所有类型的物料0=耗材, 1=样品, 2=试剂
import json
all_materials = []
for type_mode in [0, 1, 2]:
query_params = json.dumps({
"typeMode": type_mode,
"filter": "", # 空字符串表示查询所有
"includeDetail": True
})
materials = self.bioyond_api_client.stock_material(query_params)
if materials:
all_materials.extend(materials)
logger.info(f"[同步→Bioyond] 查询到 {len(all_materials)} 个物料")
# 按名称匹配
for mat in all_materials:
if mat.get("name") == resource.name:
material_bioyond_id = mat.get("id")
mat_type = mat.get("typeName", "未知")
logger.info(f"✅ 找到物料 {resource.name} ({mat_type}) 的 Bioyond ID: {material_bioyond_id[:8]}...")
# 保存 ID 到资源对象
extra_info["material_bioyond_id"] = material_bioyond_id
setattr(resource, "unilabos_extra", extra_info)
break
if not material_bioyond_id:
logger.warning(f"⚠️ 在 Bioyond 系统中未找到名为 {resource.name} 的物料")
logger.info(f"[同步→Bioyond] 这是一个新物料,将创建并入库到 Bioyond 系统")
# 不返回,继续执行后续的创建+入库流程
except Exception as e:
logger.error(f"查询 Bioyond 物料失败: {e}")
import traceback
traceback.print_exc()
return False
# 检查是否有位置更新请求
update_site = extra_info.get("update_resource_site")
if not update_site:
logger.debug(f"[同步→Bioyond] 无位置更新请求")
return True
# ===== 物料移动/创建流程 =====
if material_bioyond_id:
logger.info(f"[同步→Bioyond] 🔄 开始移动物料 {resource.name}{update_site}")
else:
logger.info(f"[同步→Bioyond] 开始创建新物料 {resource.name} 并入库到 {update_site}") # 第1步获取仓库配置
from .config import WAREHOUSE_MAPPING
warehouse_mapping = WAREHOUSE_MAPPING
# 确定目标仓库名称(通过遍历所有仓库的库位配置)
parent_name = None
target_location_uuid = None
for warehouse_name, warehouse_info in warehouse_mapping.items():
site_uuids = warehouse_info.get("site_uuids", {})
if update_site in site_uuids:
parent_name = warehouse_name
target_location_uuid = site_uuids[update_site]
logger.info(f"[同步] 目标仓库: {parent_name}/{update_site}")
logger.info(f"[同步] 目标库位UUID: {target_location_uuid[:8]}...")
break
if not parent_name or not target_location_uuid:
logger.error(f"❌ 库位 {update_site} 没有在 WAREHOUSE_MAPPING 中配置")
logger.debug(f"可用仓库: {list(warehouse_mapping.keys())}")
return False return False
bioyond_material = resource_plr_to_bioyond( bioyond_material = resource_plr_to_bioyond(
@@ -171,11 +253,22 @@ class BioyondWorkstation(WorkstationBase):
def post_init(self, ros_node: ROS2WorkstationNode): def post_init(self, ros_node: ROS2WorkstationNode):
self._ros_node = ros_node self._ros_node = ros_node
# ⭐ 上传 deck包括所有 warehouses 及其中的物料)
# 注意:如果有从 Bioyond 同步的物料,它们已经被放置到 warehouse 中了
# 所以只需要上传 deck物料会作为 warehouse 的 children 一起上传
logger.info("正在上传 deck包括 warehouses 和物料)到云端...")
ROS2DeviceNode.run_async_func(self._ros_node.update_resource, True, **{ ROS2DeviceNode.run_async_func(self._ros_node.update_resource, True, **{
"resources": [self.deck] "resources": [self.deck]
}) })
# 清理临时变量(物料已经在 deck 的 warehouse children 中,不需要单独上传)
if hasattr(self, "_synced_resources"):
logger.info(f"{len(self._synced_resources)} 个从Bioyond同步的物料已包含在 deck 中")
self._synced_resources = []
def transfer_resource_to_another(self, resource: List[ResourceSlot], mount_resource: List[ResourceSlot], sites: List[str], mount_device_id: DeviceSlot): def transfer_resource_to_another(self, resource: List[ResourceSlot], mount_resource: List[ResourceSlot], sites: List[str], mount_device_id: DeviceSlot):
time.sleep(3)
ROS2DeviceNode.run_async_func(self._ros_node.transfer_resource_to_another, True, **{ ROS2DeviceNode.run_async_func(self._ros_node.transfer_resource_to_another, True, **{
"plr_resources": resource, "plr_resources": resource,
"target_device_id": mount_device_id, "target_device_id": mount_device_id,
@@ -246,7 +339,7 @@ class BioyondWorkstation(WorkstationBase):
} }
# ==================== 工作流合并与参数设置 API ==================== # ==================== 工作流合并与参数设置 API ====================
def append_to_workflow_sequence(self, web_workflow_name: str) -> bool: def append_to_workflow_sequence(self, web_workflow_name: str) -> bool:
# 检查是否为JSON格式的字符串 # 检查是否为JSON格式的字符串
actual_workflow_name = web_workflow_name actual_workflow_name = web_workflow_name
@@ -257,7 +350,7 @@ class BioyondWorkstation(WorkstationBase):
print(f"解析JSON格式工作流名称: {web_workflow_name} -> {actual_workflow_name}") print(f"解析JSON格式工作流名称: {web_workflow_name} -> {actual_workflow_name}")
except json.JSONDecodeError: except json.JSONDecodeError:
print(f"JSON解析失败使用原始字符串: {web_workflow_name}") print(f"JSON解析失败使用原始字符串: {web_workflow_name}")
workflow_id = self._get_workflow(actual_workflow_name) workflow_id = self._get_workflow(actual_workflow_name)
if workflow_id: if workflow_id:
self.workflow_sequence.append(workflow_id) self.workflow_sequence.append(workflow_id)
@@ -322,7 +415,7 @@ class BioyondWorkstation(WorkstationBase):
# ============ 工作站状态管理 ============ # ============ 工作站状态管理 ============
def get_station_info(self) -> Dict[str, Any]: def get_station_info(self) -> Dict[str, Any]:
"""获取工作站基础信息 """获取工作站基础信息
Returns: Returns:
Dict[str, Any]: 工作站基础信息包括设备ID、状态等 Dict[str, Any]: 工作站基础信息包括设备ID、状态等
""" """
@@ -450,8 +543,8 @@ class BioyondWorkstation(WorkstationBase):
# 转换为UniLab格式 # 转换为UniLab格式
unilab_resources = resource_bioyond_to_plr( unilab_resources = resource_bioyond_to_plr(
bioyond_data, bioyond_data,
type_mapping=self.bioyond_config["material_type_mappings"], type_mapping=self.bioyond_config["material_type_mappings"],
deck=self.deck deck=self.deck
) )