Compare commits

...

2 Commits

Author SHA1 Message Date
Junhan Chang
0584bd5e04 fix vessel_id param passing in protocols 2025-07-25 17:38:17 +08:00
Xuwznln
1b086a85f5 新增lab_id直接传入 2025-07-25 15:23:35 +08:00
13 changed files with 127 additions and 34 deletions

View File

@@ -22,7 +22,7 @@ from unilabos.config.config import load_config, BasicConfig, _update_config_from
from unilabos.utils.banner_print import print_status, print_unilab_banner from unilabos.utils.banner_print import print_status, print_unilab_banner
def load_config_from_file(config_path): def load_config_from_file(config_path, override_labid=None):
if config_path is None: if config_path is None:
config_path = os.environ.get("UNILABOS.BASICCONFIG.CONFIG_PATH", None) config_path = os.environ.get("UNILABOS.BASICCONFIG.CONFIG_PATH", None)
if config_path: if config_path:
@@ -31,10 +31,10 @@ def load_config_from_file(config_path):
elif not config_path.endswith(".py"): elif not config_path.endswith(".py"):
print_status(f"配置文件 {config_path} 不是Python文件必须以.py结尾", "error") print_status(f"配置文件 {config_path} 不是Python文件必须以.py结尾", "error")
else: else:
load_config(config_path) load_config(config_path, override_labid)
else: else:
print_status(f"启动 UniLab-OS时配置文件参数未正确传入 --config '{config_path}' 尝试本地配置...", "warning") print_status(f"启动 UniLab-OS时配置文件参数未正确传入 --config '{config_path}' 尝试本地配置...", "warning")
load_config(config_path) load_config(config_path, override_labid)
def parse_args(): def parse_args():
@@ -106,6 +106,12 @@ def parse_args():
default="disable", default="disable",
help="选择可视化工具: rviz, web", help="选择可视化工具: rviz, web",
) )
parser.add_argument(
"--labid",
type=str,
default="",
help="实验室唯一ID也可通过环境变量 UNILABOS.MQCONFIG.LABID 设置或传入--config设置",
)
return parser.parse_args() return parser.parse_args()
@@ -117,7 +123,7 @@ def main():
# 加载配置文件优先加载config然后从env读取 # 加载配置文件优先加载config然后从env读取
config_path = args_dict.get("config") config_path = args_dict.get("config")
load_config_from_file(config_path) load_config_from_file(config_path, args_dict["labid"])
# 设置BasicConfig参数 # 设置BasicConfig参数
BasicConfig.is_host_mode = not args_dict.get("without_host", False) BasicConfig.is_host_mode = not args_dict.get("without_host", False)

View File

@@ -346,7 +346,16 @@ def generate_add_protocol(
""" """
# 🔧 核心修改从字典中提取容器ID # 🔧 核心修改从字典中提取容器ID
vessel_id = vessel["id"] # 统一处理vessel参数
if isinstance(vessel, dict):
if "id" not in vessel:
vessel_id = list(vessel.values())[0].get("id", "")
else:
vessel_id = vessel.get("id", "")
vessel_data = vessel.get("data", {})
else:
vessel_id = str(vessel)
vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {}
# 🔧 修改:更新容器的液体体积(假设有 liquid_volume 字段) # 🔧 修改:更新容器的液体体积(假设有 liquid_volume 字段)
if "data" in vessel and "liquid_volume" in vessel["data"]: if "data" in vessel and "liquid_volume" in vessel["data"]:

View File

@@ -237,7 +237,10 @@ def generate_adjust_ph_protocol(
# 统一处理vessel参数 # 统一处理vessel参数
if isinstance(vessel, dict): if isinstance(vessel, dict):
vessel_id = list(vessel.values())[0].get("id", "") if "id" not in vessel:
vessel_id = list(vessel.values())[0].get("id", "")
else:
vessel_id = vessel.get("id", "")
vessel_data = vessel.get("data", {}) vessel_data = vessel.get("data", {})
else: else:
vessel_id = str(vessel) vessel_id = str(vessel)

View File

@@ -181,7 +181,16 @@ def generate_clean_vessel_protocol(
clean_protocol = generate_clean_vessel_protocol(G, {"id": "main_reactor"}, "water", 100.0, 60.0, 2) clean_protocol = generate_clean_vessel_protocol(G, {"id": "main_reactor"}, "water", 100.0, 60.0, 2)
""" """
# 🔧 核心修改从字典中提取容器ID # 🔧 核心修改从字典中提取容器ID
vessel_id = vessel["id"] # 统一处理vessel参数
if isinstance(vessel, dict):
if "id" not in vessel:
vessel_id = list(vessel.values())[0].get("id", "")
else:
vessel_id = vessel.get("id", "")
vessel_data = vessel.get("data", {})
else:
vessel_id = str(vessel)
vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {}
action_sequence = [] action_sequence = []

View File

@@ -288,7 +288,16 @@ def generate_evacuateandrefill_protocol(
""" """
# 🔧 核心修改从字典中提取容器ID # 🔧 核心修改从字典中提取容器ID
vessel_id = vessel["id"] # 统一处理vessel参数
if isinstance(vessel, dict):
if "id" not in vessel:
vessel_id = list(vessel.values())[0].get("id", "")
else:
vessel_id = vessel.get("id", "")
vessel_data = vessel.get("data", {})
else:
vessel_id = str(vessel)
vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {}
# 硬编码重复次数为 3 # 硬编码重复次数为 3
repeats = 3 repeats = 3

View File

@@ -201,7 +201,16 @@ def generate_evaporate_protocol(
""" """
# 🔧 核心修改从字典中提取容器ID # 🔧 核心修改从字典中提取容器ID
vessel_id = vessel["id"] # 统一处理vessel参数
if isinstance(vessel, dict):
if "id" not in vessel:
vessel_id = list(vessel.values())[0].get("id", "")
else:
vessel_id = vessel.get("id", "")
vessel_data = vessel.get("data", {})
else:
vessel_id = str(vessel)
vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {}
debug_print("🌟" * 20) debug_print("🌟" * 20)
debug_print("🌪️ 开始生成蒸发协议(支持单位和体积运算)✨") debug_print("🌪️ 开始生成蒸发协议(支持单位和体积运算)✨")

View File

@@ -68,7 +68,16 @@ def generate_filter_protocol(
""" """
# 🔧 核心修改从字典中提取容器ID # 🔧 核心修改从字典中提取容器ID
vessel_id = vessel["id"] # 统一处理vessel参数
if isinstance(vessel, dict):
if "id" not in vessel:
vessel_id = list(vessel.values())[0].get("id", "")
else:
vessel_id = vessel.get("id", "")
vessel_data = vessel.get("data", {})
else:
vessel_id = str(vessel)
vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {}
debug_print("🌊" * 20) debug_print("🌊" * 20)
debug_print("🚀 开始生成过滤协议(支持体积运算)✨") debug_print("🚀 开始生成过滤协议(支持体积运算)✨")

View File

@@ -217,7 +217,16 @@ def generate_heat_chill_protocol(
""" """
# 🔧 核心修改从字典中提取容器ID # 🔧 核心修改从字典中提取容器ID
vessel_id = vessel["id"] # 统一处理vessel参数
if isinstance(vessel, dict):
if "id" not in vessel:
vessel_id = list(vessel.values())[0].get("id", "")
else:
vessel_id = vessel.get("id", "")
vessel_data = vessel.get("data", {})
else:
vessel_id = str(vessel)
vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {}
debug_print("🌡️" * 20) debug_print("🌡️" * 20)
debug_print("🚀 开始生成加热冷却协议支持vessel字典") debug_print("🚀 开始生成加热冷却协议支持vessel字典")

View File

@@ -170,7 +170,16 @@ def generate_hydrogenate_protocol(
""" """
# 🔧 核心修改从字典中提取容器ID # 🔧 核心修改从字典中提取容器ID
vessel_id = vessel["id"] # 统一处理vessel参数
if isinstance(vessel, dict):
if "id" not in vessel:
vessel_id = list(vessel.values())[0].get("id", "")
else:
vessel_id = vessel.get("id", "")
vessel_data = vessel.get("data", {})
else:
vessel_id = str(vessel)
vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {}
action_sequence = [] action_sequence = []

View File

@@ -287,7 +287,16 @@ def generate_recrystallize_protocol(
""" """
# 🔧 核心修改从字典中提取容器ID # 🔧 核心修改从字典中提取容器ID
vessel_id = vessel["id"] # 统一处理vessel参数
if isinstance(vessel, dict):
if "id" not in vessel:
vessel_id = list(vessel.values())[0].get("id", "")
else:
vessel_id = vessel.get("id", "")
vessel_data = vessel.get("data", {})
else:
vessel_id = str(vessel)
vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {}
action_sequence = [] action_sequence = []

View File

@@ -418,7 +418,16 @@ def generate_separate_protocol(
raise ValueError("必须提供vessel字典参数") raise ValueError("必须提供vessel字典参数")
# 🔧 核心修改从字典中提取容器ID # 🔧 核心修改从字典中提取容器ID
vessel_id = vessel["id"] # 统一处理vessel参数
if isinstance(vessel, dict):
if "id" not in vessel:
vessel_id = list(vessel.values())[0].get("id", "")
else:
vessel_id = vessel.get("id", "")
vessel_data = vessel.get("data", {})
else:
vessel_id = str(vessel)
vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {}
debug_print("🌀" * 20) debug_print("🌀" * 20)
debug_print("🚀 开始生成分离协议支持vessel字典和体积运算") debug_print("🚀 开始生成分离协议支持vessel字典和体积运算")

View File

@@ -63,7 +63,7 @@ class ROSConfig:
] ]
def _update_config_from_module(module): def _update_config_from_module(module, override_labid: str):
for name, obj in globals().items(): for name, obj in globals().items():
if isinstance(obj, type) and name.endswith("Config"): if isinstance(obj, type) and name.endswith("Config"):
if hasattr(module, name) and isinstance(getattr(module, name), type): if hasattr(module, name) and isinstance(getattr(module, name), type):
@@ -74,6 +74,9 @@ def _update_config_from_module(module):
if len(OSSUploadConfig.authorization) == 0: if len(OSSUploadConfig.authorization) == 0:
OSSUploadConfig.authorization = f"lab {MQConfig.lab_id}" OSSUploadConfig.authorization = f"lab {MQConfig.lab_id}"
# 对 ca_file cert_file key_file 进行初始化 # 对 ca_file cert_file key_file 进行初始化
if override_labid:
MQConfig.lab_id = override_labid
logger.warning(f"[ENV] 当前实验室启动的ID被设置为{override_labid}")
if len(MQConfig.ca_content) == 0: if len(MQConfig.ca_content) == 0:
# 需要先判断是否为相对路径 # 需要先判断是否为相对路径
if MQConfig.ca_file.startswith("."): if MQConfig.ca_file.startswith("."):
@@ -155,7 +158,7 @@ def _update_config_from_env():
def load_config(config_path=None): def load_config(config_path=None, override_labid=None):
# 如果提供了配置文件路径,从该文件导入配置 # 如果提供了配置文件路径,从该文件导入配置
if config_path: if config_path:
_update_config_from_env() # 允许config_path被env设定后读取 _update_config_from_env() # 允许config_path被env设定后读取
@@ -172,7 +175,7 @@ def load_config(config_path=None):
return return
module = importlib.util.module_from_spec(spec) module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module) # type: ignore spec.loader.exec_module(module) # type: ignore
_update_config_from_module(module) _update_config_from_module(module, override_labid)
logger.info(f"[ENV] 配置文件 {config_path} 加载成功") logger.info(f"[ENV] 配置文件 {config_path} 加载成功")
except Exception as e: except Exception as e:
logger.error(f"[ENV] 加载配置文件 {config_path} 失败") logger.error(f"[ENV] 加载配置文件 {config_path} 失败")
@@ -180,4 +183,4 @@ def load_config(config_path=None):
exit(1) exit(1)
else: else:
config_path = os.path.join(os.path.dirname(__file__), "local_config.py") config_path = os.path.join(os.path.dirname(__file__), "local_config.py")
load_config(config_path) load_config(config_path, override_labid)

View File

@@ -2187,65 +2187,65 @@ virtual_multiway_valve:
data_source: executor data_source: executor
data_type: fluid data_type: fluid
description: 八通阀门端口1 description: 八通阀门端口1
handler_key: "1" handler_key: '1'
io_type: source io_type: source
label: "1" label: '1'
side: NORTH side: NORTH
- data_key: fluid_port_2 - data_key: fluid_port_2
data_source: executor data_source: executor
data_type: fluid data_type: fluid
description: 八通阀门端口2 description: 八通阀门端口2
handler_key: "2" handler_key: '2'
io_type: source io_type: source
label: "2" label: '2'
side: EAST side: EAST
- data_key: fluid_port_3 - data_key: fluid_port_3
data_source: executor data_source: executor
data_type: fluid data_type: fluid
description: 八通阀门端口3 description: 八通阀门端口3
handler_key: "3" handler_key: '3'
io_type: source io_type: source
label: "3" label: '3'
side: EAST side: EAST
- data_key: fluid_port_4 - data_key: fluid_port_4
data_source: executor data_source: executor
data_type: fluid data_type: fluid
description: 八通阀门端口4 description: 八通阀门端口4
handler_key: "4" handler_key: '4'
io_type: source io_type: source
label: "4" label: '4'
side: SOUTH side: SOUTH
- data_key: fluid_port_5 - data_key: fluid_port_5
data_source: executor data_source: executor
data_type: fluid data_type: fluid
description: 八通阀门端口5 description: 八通阀门端口5
handler_key: "5" handler_key: '5'
io_type: source io_type: source
label: "5" label: '5'
side: SOUTH side: SOUTH
- data_key: fluid_port_6 - data_key: fluid_port_6
data_source: executor data_source: executor
data_type: fluid data_type: fluid
description: 八通阀门端口6 description: 八通阀门端口6
handler_key: "6" handler_key: '6'
io_type: source io_type: source
label: "6" label: '6'
side: WEST side: WEST
- data_key: fluid_port_7 - data_key: fluid_port_7
data_source: executor data_source: executor
data_type: fluid data_type: fluid
description: 八通阀门端口7 description: 八通阀门端口7
handler_key: "7" handler_key: '7'
io_type: source io_type: source
label: "7" label: '7'
side: WEST side: WEST
- data_key: fluid_port_8 - data_key: fluid_port_8
data_source: executor data_source: executor
data_type: fluid data_type: fluid
description: 八通阀门端口8 description: 八通阀门端口8
handler_key: "8" handler_key: '8'
io_type: source io_type: source
label: "8" label: '8'
side: NORTH side: NORTH
icon: EightPipeline.webp icon: EightPipeline.webp
init_param_schema: init_param_schema: