From 18c4eb3e4d42970240302623361d37a9b0a51480 Mon Sep 17 00:00:00 2001 From: Junhan Chang Date: Tue, 17 Jun 2025 13:27:27 +0800 Subject: [PATCH] fix device ports --- .../comprehensive_station.json | 8 +-- test/experiments/mock_reactor.json | 32 +++++----- unilabos/app/register.py | 63 +++++++++++++++++++ unilabos/registry/devices/pump_and_valve.yaml | 10 +-- unilabos/registry/devices/virtual_device.yaml | 32 +++++----- .../registry/resources/organic/container.yaml | 7 +++ unilabos/resources/graphio.py | 2 +- 7 files changed, 113 insertions(+), 41 deletions(-) create mode 100644 unilabos/app/register.py diff --git a/test/experiments/comprehensive_protocol/comprehensive_station.json b/test/experiments/comprehensive_protocol/comprehensive_station.json index 84c4863..19d0852 100644 --- a/test/experiments/comprehensive_protocol/comprehensive_station.json +++ b/test/experiments/comprehensive_protocol/comprehensive_station.json @@ -730,7 +730,7 @@ "type": "fluid", "port": { "multiway_valve_2": "2", - "solenoid_valve_1": "1" + "solenoid_valve_1": "in" } }, { @@ -739,7 +739,7 @@ "target": "vacuum_pump_1", "type": "fluid", "port": { - "solenoid_valve_1": "2", + "solenoid_valve_1": "out", "vacuum_pump_1": "vacuumpump" } }, @@ -750,7 +750,7 @@ "type": "fluid", "port": { "multiway_valve_2": "3", - "solenoid_valve_2": "1" + "solenoid_valve_2": "in" } }, { @@ -759,7 +759,7 @@ "target": "gas_source_1", "type": "fluid", "port": { - "solenoid_valve_2": "2", + "solenoid_valve_2": "out", "gas_source_1": "gassource" } }, diff --git a/test/experiments/mock_reactor.json b/test/experiments/mock_reactor.json index 546c15f..dfcf911 100644 --- a/test/experiments/mock_reactor.json +++ b/test/experiments/mock_reactor.json @@ -122,39 +122,39 @@ ], "links": [ { - "source": "reactor", - "target": "vacuum_valve", - "type": "physical", + "source": "vacuum_valve", + "target": "reactor", + "type": "fluid", "port": { "reactor": "top", - "vacuum_valve": "1" + "vacuum_valve": "out" } }, { - "source": "reactor", - "target": "gas_valve", - "type": "physical", + "source": "gas_valve", + "target": "reactor", + "type": "fluid", "port": { "reactor": "top", - "gas_valve": "1" + "gas_valve": "out" } }, { - "source": "vacuum_pump", - "target": "vacuum_valve", - "type": "physical", + "source": "vacuum_valve", + "target": "vacuum_pump", + "type": "fluid", "port": { "vacuum_pump": "out", - "vacuum_valve": "0" + "vacuum_valve": "in" } }, { - "source": "gas_source", - "target": "gas_valve", - "type": "physical", + "source": "gas_valve", + "target": "gas_source", + "type": "fluid", "port": { "gas_source": "out", - "gas_valve": "0" + "gas_valve": "in" } } ] diff --git a/unilabos/app/register.py b/unilabos/app/register.py new file mode 100644 index 0000000..478e1cf --- /dev/null +++ b/unilabos/app/register.py @@ -0,0 +1,63 @@ +import argparse +import time + +from unilabos.registry.registry import build_registry + +from unilabos.app.main import load_config_from_file +from unilabos.utils.log import logger + + +def register_devices_and_resources(mqtt_client, lab_registry): + """ + 注册设备和资源到 MQTT + """ + logger.info("[UniLab Register] 开始注册设备和资源...") + + # 注册设备信息 + for device_info in lab_registry.obtain_registry_device_info(): + mqtt_client.publish_registry(device_info["id"], device_info) + logger.debug(f"[UniLab Register] 注册设备: {device_info['id']}") + + # 注册资源信息 + for resource_info in lab_registry.obtain_registry_resource_info(): + mqtt_client.publish_registry(resource_info["id"], resource_info) + logger.debug(f"[UniLab Register] 注册资源: {resource_info['id']}") + + time.sleep(20) + + logger.info("[UniLab Register] 设备和资源注册完成.") + + +def main(): + """ + 命令行入口函数 + """ + parser = argparse.ArgumentParser(description="注册设备和资源到 MQTT") + parser.add_argument( + "--registry_path", + type=str, + default=None, + action="append", + help="注册表路径", + ) + parser.add_argument( + "--config", + type=str, + default=None, + help="配置文件路径,支持.py格式的Python配置文件", + ) + args = parser.parse_args() + + # 构建注册表 + build_registry(args.registry_path) + load_config_from_file(args.config) + + from unilabos.app.mq import mqtt_client + from unilabos.registry.registry import lab_registry + + # 注册设备和资源 + register_devices_and_resources(mqtt_client, lab_registry) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/unilabos/registry/devices/pump_and_valve.yaml b/unilabos/registry/devices/pump_and_valve.yaml index 71a2c97..651a25f 100644 --- a/unilabos/registry/devices/pump_and_valve.yaml +++ b/unilabos/registry/devices/pump_and_valve.yaml @@ -48,12 +48,14 @@ solenoid_valve.mock: feedback: {} result: {} handles: - - handler_key: 0 - label: 0 + - handler_key: in + label: in + io_type: target data_type: fluid side: NORTH - - handler_key: 1 - label: 1 + - handler_key: out + label: out + io_type: source data_type: fluid side: SOUTH init_param_schema: diff --git a/unilabos/registry/devices/virtual_device.yaml b/unilabos/registry/devices/virtual_device.yaml index 1321d01..af00af1 100644 --- a/unilabos/registry/devices/virtual_device.yaml +++ b/unilabos/registry/devices/virtual_device.yaml @@ -107,10 +107,10 @@ virtual_pump: success: success # 虚拟泵节点配置 - 具有多通道阀门特性,根据valve_position可连接多个容器 handles: - - handler_key: pump-inlet - label: Pump Inlet + - handler_key: pumpio + label: pumpio data_type: fluid - io_type: target + io_type: source data_source: handle data_key: fluid_in description: "泵的进液口,连接源容器" @@ -168,7 +168,7 @@ virtual_stirrer: label: stirrer data_type: mechanical side: NORTH - io_type: undirected + io_type: source data_source: handle data_key: vessel description: "搅拌器的机械连接口,直接与反应容器连接提供搅拌功能" @@ -323,19 +323,19 @@ virtual_solenoid_valve: success: success # 电磁阀门节点配置 - 双向流通的开关型阀门,流动方向由泵决定 handles: - - handler_key: 1 - label: 1 + - handler_key: in + label: in data_type: fluid side: NORTH - io_type: undirected + io_type: target data_source: handle data_key: fluid_port_in description: "电磁阀的双向流体口,开启时允许流体双向通过,关闭时完全阻断" - - handler_key: 2 - label: 2 + - handler_key: out + label: out data_type: fluid side: SOUTH - io_type: undirected + io_type: source data_source: handle data_key: fluid_port_out description: "电磁阀的双向流体口,开启时允许流体双向通过,关闭时完全阻断" @@ -391,7 +391,7 @@ virtual_centrifuge: label: centrifuge data_type: transport side: NORTH - io_type: undirected + io_type: target data_source: handle data_key: vessel description: "需要离心的样品容器" @@ -534,7 +534,7 @@ virtual_heatchill: label: heatchill data_type: mechanical side: NORTH - io_type: undirected + io_type: source data_source: handle data_key: vessel description: "加热/冷却器的物理连接口,容器直接放置在设备上进行温度控制" @@ -593,7 +593,7 @@ virtual_transfer_pump: label: transferpump data_type: fluid side: SOUTH - io_type: undirected + io_type: source data_source: handle data_key: fluid_port description: "注射器式转移泵的唯一连接口,通过阀门切换实现吸入和排出" @@ -716,7 +716,7 @@ virtual_rotavap: label: rotavap-sample data_type: fluid side: NORTH - io_type: undirected + io_type: target data_source: handle data_key: vessel description: "样品的双向连接口,可放入需要蒸发的样品,蒸发完成后取出浓缩物" @@ -787,7 +787,7 @@ virtual_separator: label: separatorin data_type: fluid side: NORTH - io_type: undirected + io_type: target data_source: handle data_key: from_vessel description: "需要分离的混合液体输入口" @@ -844,7 +844,7 @@ virtual_vacuum_pump: label: vacuumpump data_type: fluid side: SOUTH - io_type: target + io_type: source data_source: handle data_key: fluid_in description: "真空泵进气口,连接需要抽真空的容器或管路" diff --git a/unilabos/registry/resources/organic/container.yaml b/unilabos/registry/resources/organic/container.yaml index 33ee26c..0e8c0a5 100644 --- a/unilabos/registry/resources/organic/container.yaml +++ b/unilabos/registry/resources/organic/container.yaml @@ -6,9 +6,16 @@ container: handles: - handler_key: top label: top + io_type: target data_type: fluid side: NORTH - handler_key: bottom label: bottom + io_type: source data_type: fluid + side: SOUTH + - handler_key: bind + label: bind + io_type: target + data_type: mechanical side: SOUTH \ No newline at end of file diff --git a/unilabos/resources/graphio.py b/unilabos/resources/graphio.py index 36137b9..17b0f27 100644 --- a/unilabos/resources/graphio.py +++ b/unilabos/resources/graphio.py @@ -176,7 +176,7 @@ def modify_to_backend_format(data: list[dict[str, Any]]) -> list[dict[str, Any]] elif "target_port" in edge: edge["targetHandle"] = edge.pop("target_port") if "id" not in edge: - edge["id"] = f"link_generated_{source}_{target}" + edge["id"] = f"reactflow__edge-{edge['sourceHandle']}-{edge['targetHandle']}" for key in ["source_port", "target_port"]: if key in edge: edge.pop(key)