mirror of
https://github.com/deepmodeling/Uni-Lab-OS
synced 2026-03-30 18:28:05 +00:00
Upgrade to py 3.11.14; ROS2 Humble 0.7; unilabos 0.10.16
Workbench example, adjust log level, and ci check (#220) * TestLatency Return Value Example & gitignore update * Adjust log level & Add workbench virtual example & Add not action decorator & Add check_mode & * Add CI Check Fix/workstation yb revision (#217) * Revert log change & update registry * Revert opcua client & move electrolyte node Workstation yb merge dev ready 260113 (#216) * feat(bioyond): 添加计算实验设计功能,支持化合物配比和滴定比例参数 * feat(bioyond): 添加测量小瓶功能,支持基本参数配置 * feat(bioyond): 添加测量小瓶配置,支持新设备参数 * feat(bioyond): 更新仓库布局和尺寸,支持竖向排列的测量小瓶和试剂存放堆栈 * feat(bioyond): 优化任务创建流程,确保无论成功与否都清理任务队列以避免重复累积 * feat(bioyond): 添加设置反应器温度功能,支持温度范围和异常处理 * feat(bioyond): 调整反应器位置配置,统一坐标格式 * feat(bioyond): 添加调度器启动功能,支持任务队列执行并处理异常 * feat(bioyond): 优化调度器启动功能,添加异常处理并更新相关配置 * feat(opcua): 增强节点ID解析兼容性和数据类型处理 改进节点ID解析逻辑以支持多种格式,包括字符串和数字标识符 添加数据类型转换处理,确保写入值时类型匹配 优化错误提示信息,便于调试节点连接问题 * feat(registry): 新增后处理站的设备配置文件 添加后处理站的YAML配置文件,包含动作映射、状态类型和设备描述 * 添加调度器启动功能,合并物料参数配置,优化物料参数处理逻辑 * 添加从 Bioyond 系统自动同步工作流序列的功能,并更新相关配置 * fix:兼容 BioyondReactionStation 中 workflow_sequence 被重写为 property * fix:同步工作流序列 * feat: remove commented workflow synchronization from `reaction_station.py`. * 添加时间约束功能及相关配置 * fix:自动更新物料缓存功能,添加物料时更新缓存并在删除时移除缓存项 * fix:在添加物料时处理字符串和字典返回值,确保正确更新缓存 * fix:更新奔曜错误处理报送为物料变更报送,调整日志记录和响应消息 * feat:添加实验报告简化功能,去除冗余信息并保留关键信息 * feat: 添加任务状态事件发布功能,监控并报告任务运行、超时、完成和错误状态 * fix: 修复添加物料时数据格式错误 * Refactor bioyond_dispensing_station and reaction_station_bioyond YAML configurations - Removed redundant action value mappings from bioyond_dispensing_station. - Updated goal properties in bioyond_dispensing_station to use enums for target_stack and other parameters. - Changed data types for end_point and start_point in reaction_station_bioyond to use string enums (Start, End). - Simplified descriptions and updated measurement units from μL to mL where applicable. - Removed unused commands from reaction_station_bioyond to streamline the configuration. * fix:Change the material unit from μL to mL * fix:refresh_material_cache * feat: 动态获取工作流步骤ID,优化工作流配置 * feat: 添加清空服务端所有非核心工作流功能 * fix:修复Bottle类的序列化和反序列化方法 * feat:增强材料缓存更新逻辑,支持处理返回数据中的详细信息 * Add debug log * feat(workstation): update bioyond config migration and coin cell material search logic - Migrate bioyond_cell config to JSON structure and remove global variable dependencies - Implement material search confirmation dialog auto-handling - Add documentation: 20260113_物料搜寻确认弹窗自动处理功能.md and 20260113_配置迁移修改总结.md * Refactor module paths for Bioyond devices in YAML configuration files - Updated the module path for BioyondDispensingStation in bioyond_dispensing_station.yaml to reflect the new directory structure. - Updated the module path for BioyondReactionStation and BioyondReactor in reaction_station_bioyond.yaml to align with the revised organization of the codebase. * fix: WareHouse 的不可哈希类型错误,优化父节点去重逻辑 * refactor: Move config from module to instance initialization * fix: 修正 reaction_station 目录名拼写错误 * feat: Integrate material search logic and cleanup deprecated files - Update coin_cell_assembly.py with material search dialog handling - Update YB_warehouses.py with latest warehouse configurations - Remove outdated documentation and test data files * Refactor: Use instance attributes for action names and workflow step IDs * refactor: Split tipbox storage into left and right warehouses * refactor: Merge tipbox storage left and right into single warehouse --------- Co-authored-by: ZiWei <131428629+ZiWei09@users.noreply.github.com> Co-authored-by: Andy6M <xieqiming1132@qq.com> fix: WareHouse 的不可哈希类型错误,优化父节点去重逻辑 fix parent_uuid fetch when bind_parent_id == node_name 物料更新也是用父节点进行报送 Add None conversion for tube rack etc. Add set_liquid example. Add create_resource and test_resource example. Add restart. Temp allow action message. Add no_update_feedback option. Create session_id by edge. bump version to 0.10.15 temp cancel update req
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
# Bioyond Cell 工作站 - 多订单返回示例
|
||||
|
||||
本文档说明了 `create_orders` 函数如何收集并返回所有订单的完成报文。
|
||||
|
||||
## 问题描述
|
||||
|
||||
之前的实现只会等待并返回第一个订单的完成报文,如果有多个订单(例如从 Excel 解析出 3 个订单),只能得到第一个订单的推送信息。
|
||||
|
||||
## 解决方案
|
||||
|
||||
修改后的 `create_orders` 函数现在会:
|
||||
|
||||
1. **提取所有 orderCode**:从 LIMS 接口返回的 `data` 列表中提取所有订单编号
|
||||
2. **逐个等待完成**:遍历所有 orderCode,调用 `wait_for_order_finish` 等待每个订单完成
|
||||
3. **收集所有报文**:将每个订单的完成报文存入 `all_reports` 列表
|
||||
4. **统一返回**:返回包含所有订单报文的 JSON 格式数据
|
||||
|
||||
## 返回格式
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "all_completed",
|
||||
"total_orders": 3,
|
||||
"reports": [
|
||||
{
|
||||
"token": "",
|
||||
"request_time": "2025-12-24T15:32:09.2148671+08:00",
|
||||
"data": {
|
||||
"orderId": "3a1e614d-a082-c44a-60be-68647a35e6f1",
|
||||
"orderCode": "BSO2025122400024",
|
||||
"orderName": "DP20251224001",
|
||||
"status": "30",
|
||||
"workflowStatus": "completed",
|
||||
"usedMaterials": [...]
|
||||
}
|
||||
},
|
||||
{
|
||||
"token": "",
|
||||
"request_time": "2025-12-24T15:32:09.9999039+08:00",
|
||||
"data": {
|
||||
"orderId": "3a1e614d-a0a2-f7a9-9360-610021c9479d",
|
||||
"orderCode": "BSO2025122400025",
|
||||
"orderName": "DP20251224002",
|
||||
"status": "30",
|
||||
"workflowStatus": "completed",
|
||||
"usedMaterials": [...]
|
||||
}
|
||||
},
|
||||
{
|
||||
"token": "",
|
||||
"request_time": "2025-12-24T15:34:00.4139986+08:00",
|
||||
"data": {
|
||||
"orderId": "3a1e614d-a0cd-81ca-9f7f-2f4e93af01cd",
|
||||
"orderCode": "BSO2025122400026",
|
||||
"orderName": "DP20251224003",
|
||||
"status": "30",
|
||||
"workflowStatus": "completed",
|
||||
"usedMaterials": [...]
|
||||
}
|
||||
}
|
||||
],
|
||||
"original_response": {...}
|
||||
}
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
```python
|
||||
# 调用 create_orders
|
||||
result = workstation.create_orders("20251224.xlsx")
|
||||
|
||||
# 访问返回数据
|
||||
print(f"总订单数: {result['total_orders']}")
|
||||
print(f"状态: {result['status']}")
|
||||
|
||||
# 遍历所有订单的报文
|
||||
for i, report in enumerate(result['reports'], 1):
|
||||
order_data = report.get('data', {})
|
||||
print(f"\n订单 {i}:")
|
||||
print(f" orderCode: {order_data.get('orderCode')}")
|
||||
print(f" orderName: {order_data.get('orderName')}")
|
||||
print(f" status: {order_data.get('status')}")
|
||||
print(f" 使用物料数: {len(order_data.get('usedMaterials', []))}")
|
||||
```
|
||||
|
||||
## 控制台输出示例
|
||||
|
||||
```
|
||||
[create_orders] 即将提交订单数量: 3
|
||||
[create_orders] 接口返回: {...}
|
||||
[create_orders] 等待 3 个订单完成: ['BSO2025122400024', 'BSO2025122400025', 'BSO2025122400026']
|
||||
[create_orders] 正在等待第 1/3 个订单: BSO2025122400024
|
||||
[create_orders] ✓ 订单 BSO2025122400024 完成
|
||||
[create_orders] 正在等待第 2/3 个订单: BSO2025122400025
|
||||
[create_orders] ✓ 订单 BSO2025122400025 完成
|
||||
[create_orders] 正在等待第 3/3 个订单: BSO2025122400026
|
||||
[create_orders] ✓ 订单 BSO2025122400026 完成
|
||||
[create_orders] 所有订单已完成,共收集 3 个报文
|
||||
实验记录本========================create_orders========================
|
||||
返回报文数量: 3
|
||||
报文 1: orderCode=BSO2025122400024, status=30
|
||||
报文 2: orderCode=BSO2025122400025, status=30
|
||||
报文 3: orderCode=BSO2025122400026, status=30
|
||||
========================
|
||||
```
|
||||
|
||||
## 关键改进
|
||||
|
||||
1. ✅ **等待所有订单**:不再只等待第一个订单,而是遍历所有 orderCode
|
||||
2. ✅ **收集完整报文**:每个订单的完整推送报文都被保存在 `reports` 数组中
|
||||
3. ✅ **详细日志**:清晰显示正在等待哪个订单,以及完成情况
|
||||
4. ✅ **错误处理**:即使某个订单失败,也会记录其状态信息
|
||||
5. ✅ **统一格式**:返回的 JSON 格式便于后续处理和分析
|
||||
Binary file not shown.
@@ -0,0 +1,204 @@
|
||||
# BioyondCellWorkstation JSON 配置迁移经验总结
|
||||
|
||||
**日期**: 2026-01-13
|
||||
**目的**: 从 `config.py` 迁移到 JSON 配置文件
|
||||
|
||||
---
|
||||
|
||||
## 问题背景
|
||||
|
||||
原系统通过 `config.py` 管理配置,导致:
|
||||
1. HTTP 服务重复启动(父类 `BioyondWorkstation` 和子类都启动)
|
||||
2. 配置分散在代码中,不便于管理
|
||||
3. 无法通过 JSON 统一配置所有参数
|
||||
|
||||
---
|
||||
|
||||
## 解决方案:嵌套配置结构
|
||||
|
||||
### JSON 结构设计
|
||||
|
||||
**正确示例** (嵌套在 `config` 中):
|
||||
```json
|
||||
{
|
||||
"nodes": [{
|
||||
"id": "bioyond_cell_workstation",
|
||||
"config": {
|
||||
"deck": {...},
|
||||
"protocol_type": [],
|
||||
"bioyond_config": {
|
||||
"api_host": "http://172.16.11.219:44388",
|
||||
"api_key": "8A819E5C",
|
||||
"timeout": 30,
|
||||
"HTTP_host": "172.16.11.206",
|
||||
"HTTP_port": 8080,
|
||||
"debug_mode": false,
|
||||
"material_type_mappings": {...},
|
||||
"warehouse_mapping": {...},
|
||||
"solid_liquid_mappings": {...}
|
||||
}
|
||||
},
|
||||
"data": {}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
**关键点**:
|
||||
- ✅ `bioyond_config` 放在 `config` 中(会传递到 `__init__`)
|
||||
- ❌ **不要**放在 `data` 中(`data` 是运行时状态,不会传递)
|
||||
|
||||
---
|
||||
|
||||
## Python 代码适配
|
||||
|
||||
### 1. 修改 `BioyondCellWorkstation.__init__` 签名
|
||||
|
||||
**文件**: `bioyond_cell_workstation.py`
|
||||
|
||||
```python
|
||||
def __init__(self, bioyond_config: dict = None, deck=None, protocol_type=None, **kwargs):
|
||||
"""
|
||||
Args:
|
||||
bioyond_config: 从 JSON 加载的配置字典
|
||||
deck: Deck 配置
|
||||
protocol_type: 协议类型
|
||||
"""
|
||||
# 验证配置
|
||||
if bioyond_config is None:
|
||||
raise ValueError("需要 bioyond_config 参数")
|
||||
|
||||
# 保存配置
|
||||
self.bioyond_config = bioyond_config
|
||||
|
||||
# 设置 HTTP 服务去重标志
|
||||
self.bioyond_config["_disable_auto_http_service"] = True
|
||||
|
||||
# 调用父类
|
||||
super().__init__(bioyond_config=self.bioyond_config, deck=deck, **kwargs)
|
||||
```
|
||||
|
||||
### 2. 替换全局变量引用
|
||||
|
||||
**修改前**(使用全局变量):
|
||||
```python
|
||||
from config import MATERIAL_TYPE_MAPPINGS, WAREHOUSE_MAPPING
|
||||
|
||||
def create_sample(self, board_type, ...):
|
||||
carrier_type_id = MATERIAL_TYPE_MAPPINGS[board_type][1]
|
||||
location_id = WAREHOUSE_MAPPING[warehouse_name]["site_uuids"][location_code]
|
||||
```
|
||||
|
||||
**修改后**(从配置读取):
|
||||
```python
|
||||
def create_sample(self, board_type, ...):
|
||||
carrier_type_id = self.bioyond_config['material_type_mappings'][board_type][1]
|
||||
location_id = self.bioyond_config['warehouse_mapping'][warehouse_name]["site_uuids"][location_code]
|
||||
```
|
||||
|
||||
### 3. 修复父类配置访问
|
||||
|
||||
在 `station.py` 中安全访问配置默认值:
|
||||
|
||||
```python
|
||||
# 修改前(会 KeyError)
|
||||
self._http_service_config = {
|
||||
"host": bioyond_config.get("http_service_host", HTTP_SERVICE_CONFIG["http_service_host"])
|
||||
}
|
||||
|
||||
# 修改后(安全访问)
|
||||
self._http_service_config = {
|
||||
"host": bioyond_config.get("http_service_host", HTTP_SERVICE_CONFIG.get("http_service_host", ""))
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见陷阱
|
||||
|
||||
### ❌ 错误1:将配置放在 `data` 字段
|
||||
```json
|
||||
"config": {"deck": {...}},
|
||||
"data": {"bioyond_config": {...}} // ❌ 不会传递到 __init__
|
||||
```
|
||||
|
||||
### ❌ 错误2:扁平化配置(已废弃方案)
|
||||
虽然扁平化也能工作,但不推荐:
|
||||
```json
|
||||
"config": {
|
||||
"deck": {...},
|
||||
"api_host": "...", // ❌ 不够清晰
|
||||
"api_key": "...",
|
||||
"HTTP_host": "..."
|
||||
}
|
||||
```
|
||||
|
||||
### ❌ 错误3:忘记替换全局变量引用
|
||||
代码中直接使用 `MATERIAL_TYPE_MAPPINGS` 等全局变量会导致 `NameError`。
|
||||
|
||||
---
|
||||
|
||||
## 云端同步注意事项
|
||||
|
||||
使用 `--upload_registry` 时,云端配置可能覆盖本地配置:
|
||||
- 首次上传时确保 JSON 完整
|
||||
- 或使用新的 `ak/sk` 避免旧配置干扰
|
||||
- 调试时可暂时移除 `--upload_registry` 参数
|
||||
|
||||
---
|
||||
|
||||
## 验证清单
|
||||
|
||||
启动成功后应看到:
|
||||
```
|
||||
✅ 从 JSON 配置加载 bioyond_config 成功
|
||||
API Host: http://...
|
||||
HTTP Service: ...
|
||||
✅ BioyondCellWorkstation 初始化完成
|
||||
Loaded ResourceTreeSet with ... nodes
|
||||
```
|
||||
|
||||
运行时不应出现:
|
||||
- ❌ `NameError: name 'MATERIAL_TYPE_MAPPINGS' is not defined`
|
||||
- ❌ `KeyError: 'http_service_host'`
|
||||
- ❌ `bioyond_config 缺少必需参数`
|
||||
|
||||
---
|
||||
|
||||
## 调试经验
|
||||
|
||||
1. **添加调试日志**查看参数传递链路:
|
||||
- `graphio.py`: JSON 加载后的 config 内容
|
||||
- `initialize_device.py`: `device_config.res_content.config` 的键
|
||||
- `bioyond_cell_workstation.py`: `__init__` 接收到的参数
|
||||
|
||||
2. **config vs data 区别**:
|
||||
- `config`: 初始化参数,传递给 `__init__`
|
||||
- `data`: 运行时状态,不传递给 `__init__`
|
||||
|
||||
3. **参数名必须匹配**:
|
||||
- JSON 中的键名必须与 `__init__` 参数名完全一致
|
||||
|
||||
4. **调试代码清理**:完成后记得删除调试日志(🔍 DEBUG 标记)
|
||||
|
||||
---
|
||||
|
||||
## 修改文件清单
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|----------|
|
||||
| `yibin_electrolyte_config.json` | 创建嵌套 `config.bioyond_config` 结构 |
|
||||
| `bioyond_cell_workstation.py` | 修改 `__init__` 接收 `bioyond_config`,替换所有全局变量引用 |
|
||||
| `station.py` | 安全访问 `HTTP_SERVICE_CONFIG` 默认值 |
|
||||
|
||||
---
|
||||
|
||||
## 参考代码位置
|
||||
|
||||
- JSON 配置示例: `yibin_electrolyte_config.json` L12-L353
|
||||
- `__init__` 实现: `bioyond_cell_workstation.py` L39-L94
|
||||
- 全局变量替换示例: `bioyond_cell_workstation.py` L2005, L1863, L1966
|
||||
- HTTP 服务配置: `station.py` L629-L634
|
||||
|
||||
---
|
||||
|
||||
**总结**: 使用嵌套结构将所有配置放在 `config.bioyond_config` 中,修改 `__init__` 直接接收该参数,并替换所有全局变量引用为 `self.bioyond_config` 访问。
|
||||
@@ -0,0 +1,312 @@
|
||||
# BioyondCell 配置迁移修改总结
|
||||
|
||||
**日期**: 2026-01-13
|
||||
**目标**: 从 `config.py` 完全迁移到 JSON 配置,消除所有全局变量依赖
|
||||
|
||||
---
|
||||
|
||||
## 📋 修改概览
|
||||
|
||||
本次修改完成了 BioyondCell 模块从 Python 配置文件到 JSON 配置的完整迁移,并清理了所有对 `config.py` 全局变量的依赖。
|
||||
|
||||
### 核心成果
|
||||
|
||||
- ✅ 完全移除对 `config.py` 的导入依赖
|
||||
- ✅ 使用嵌套 JSON 结构 `config.bioyond_config`
|
||||
- ✅ 修复 7 处 `bioyond_cell_workstation.py` 中的全局变量引用
|
||||
- ✅ 修复 3 处其他文件中的全局变量引用
|
||||
- ✅ HTTP 服务去重机制完善
|
||||
- ✅ 系统成功启动并正常运行
|
||||
|
||||
---
|
||||
|
||||
## 🔧 修改文件清单
|
||||
|
||||
### 1. JSON 配置文件
|
||||
|
||||
**文件**: `yibin_electrolyte_config.json`
|
||||
|
||||
**修改**:
|
||||
- 采用嵌套结构将所有配置放在 `config.bioyond_config` 中
|
||||
- 包含:`api_host`, `api_key`, `HTTP_host`, `HTTP_port`, `material_type_mappings`, `warehouse_mapping`, `solid_liquid_mappings` 等
|
||||
|
||||
**示例结构**:
|
||||
```json
|
||||
{
|
||||
"nodes": [{
|
||||
"id": "bioyond_cell_workstation",
|
||||
"config": {
|
||||
"deck": {...},
|
||||
"protocol_type": [],
|
||||
"bioyond_config": {
|
||||
"api_host": "http://172.16.11.219:44388",
|
||||
"api_key": "8A819E5C",
|
||||
"HTTP_host": "172.16.11.206",
|
||||
"HTTP_port": 8080,
|
||||
"material_type_mappings": {...},
|
||||
"warehouse_mapping": {...},
|
||||
"solid_liquid_mappings": {...}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. bioyond_cell_workstation.py
|
||||
|
||||
**位置**: `unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py`
|
||||
|
||||
#### 修改 A: `__init__` 方法签名 (L39-99)
|
||||
|
||||
**修改前**:
|
||||
```python
|
||||
def __init__(self, deck=None, protocol_type=None, **kwargs):
|
||||
# 从 kwargs 收集配置字段
|
||||
self.bioyond_config = {}
|
||||
for field in bioyond_field_names:
|
||||
if field in kwargs:
|
||||
self.bioyond_config[field] = kwargs.pop(field)
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```python
|
||||
def __init__(self, bioyond_config: dict = None, deck=None, protocol_type=None, **kwargs):
|
||||
"""直接接收 bioyond_config 参数"""
|
||||
if bioyond_config is None:
|
||||
raise ValueError("需要 bioyond_config 参数")
|
||||
|
||||
self.bioyond_config = bioyond_config
|
||||
|
||||
# 设置 HTTP 服务去重标志
|
||||
self.bioyond_config["_disable_auto_http_service"] = True
|
||||
|
||||
super().__init__(bioyond_config=self.bioyond_config, deck=deck, **kwargs)
|
||||
```
|
||||
|
||||
#### 修改 B: 替换全局变量引用 (7 处)
|
||||
|
||||
| 位置 | 原代码 | 修改后 |
|
||||
|------|--------|--------|
|
||||
| L2005 | `MATERIAL_TYPE_MAPPINGS[board_type][1]` | `self.bioyond_config['material_type_mappings'][board_type][1]` |
|
||||
| L2006 | `MATERIAL_TYPE_MAPPINGS[bottle_type][1]` | `self.bioyond_config['material_type_mappings'][bottle_type][1]` |
|
||||
| L2009 | `WAREHOUSE_MAPPING` | `self.bioyond_config['warehouse_mapping']` |
|
||||
| L2013 | `WAREHOUSE_MAPPING[warehouse_name]` | `self.bioyond_config['warehouse_mapping'][warehouse_name]` |
|
||||
| L2017 | `WAREHOUSE_MAPPING[warehouse_name]["site_uuids"]` | `self.bioyond_config['warehouse_mapping'][warehouse_name]["site_uuids"]` |
|
||||
| L1863 | `SOLID_LIQUID_MAPPINGS.get(material_name)` | `self.bioyond_config.get('solid_liquid_mappings', {}).get(material_name)` |
|
||||
| L1966, L1976 | `MATERIAL_TYPE_MAPPINGS.items()` | `self.bioyond_config['material_type_mappings'].items()` |
|
||||
|
||||
---
|
||||
|
||||
### 3. station.py
|
||||
|
||||
**位置**: `unilabos/devices/workstation/bioyond_studio/station.py`
|
||||
|
||||
#### 修改 A: 删除 config 导入 (L26-28)
|
||||
|
||||
**修改前**:
|
||||
```python
|
||||
from unilabos.devices.workstation.bioyond_studio.config import (
|
||||
API_CONFIG, WORKFLOW_MAPPINGS, MATERIAL_TYPE_MAPPINGS, WAREHOUSE_MAPPING, HTTP_SERVICE_CONFIG
|
||||
)
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```python
|
||||
# 已删除此导入
|
||||
```
|
||||
|
||||
#### 修改 B: `_create_communication_module` 方法 (L691-702)
|
||||
|
||||
**修改前**:
|
||||
```python
|
||||
def _create_communication_module(self, config: Optional[Dict[str, Any]] = None) -> None:
|
||||
default_config = {
|
||||
**API_CONFIG,
|
||||
"workflow_mappings": WORKFLOW_MAPPINGS,
|
||||
"material_type_mappings": MATERIAL_TYPE_MAPPINGS,
|
||||
"warehouse_mapping": WAREHOUSE_MAPPING
|
||||
}
|
||||
if config:
|
||||
self.bioyond_config = {**default_config, **config}
|
||||
else:
|
||||
self.bioyond_config = default_config
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```python
|
||||
def _create_communication_module(self, config: Optional[Dict[str, Any]] = None) -> None:
|
||||
"""创建Bioyond通信模块"""
|
||||
# 使用传入的 config 参数(来自 bioyond_config)
|
||||
# 不再依赖全局变量 API_CONFIG 等
|
||||
if config:
|
||||
self.bioyond_config = config
|
||||
else:
|
||||
# 如果没有传入配置,创建空配置(用于测试或兼容性)
|
||||
self.bioyond_config = {}
|
||||
|
||||
self.hardware_interface = BioyondV1RPC(self.bioyond_config)
|
||||
```
|
||||
|
||||
#### 修改 C: HTTP 服务配置 (L627-632)
|
||||
|
||||
**修改前**:
|
||||
```python
|
||||
self._http_service_config = {
|
||||
"host": bioyond_config.get("http_service_host", HTTP_SERVICE_CONFIG.get("http_service_host", "")),
|
||||
"port": bioyond_config.get("http_service_port", HTTP_SERVICE_CONFIG.get("http_service_port", 0))
|
||||
}
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```python
|
||||
self._http_service_config = {
|
||||
"host": bioyond_config.get("http_service_host", bioyond_config.get("HTTP_host", "")),
|
||||
"port": bioyond_config.get("http_service_port", bioyond_config.get("HTTP_port", 0))
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. bioyond_rpc.py
|
||||
|
||||
**位置**: `unilabos/devices/workstation/bioyond_studio/bioyond_rpc.py`
|
||||
|
||||
#### 修改 A: 删除 config 导入 (L12)
|
||||
|
||||
**修改前**:
|
||||
```python
|
||||
from unilabos.devices.workstation.bioyond_studio.config import LOCATION_MAPPING
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```python
|
||||
# 已删除此导入
|
||||
```
|
||||
|
||||
#### 修改 B: `material_outbound` 方法 (L278-280)
|
||||
|
||||
**修改前**:
|
||||
```python
|
||||
def material_outbound(self, material_id: str, location_name: str, quantity: int) -> dict:
|
||||
"""指定库位出库物料(通过库位名称)"""
|
||||
location_id = LOCATION_MAPPING.get(location_name, location_name)
|
||||
```
|
||||
|
||||
**修改后**:
|
||||
```python
|
||||
def material_outbound(self, material_id: str, location_name: str, quantity: int) -> dict:
|
||||
"""指定库位出库物料(通过库位名称)"""
|
||||
# location_name 参数实际上应该直接是 location_id (UUID)
|
||||
location_id = location_name
|
||||
```
|
||||
|
||||
**说明**: `LOCATION_MAPPING` 在 `config-0113.py` 中本来就是空字典 `{}`,所以直接使用 `location_name` 逻辑等价。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 关键设计决策
|
||||
|
||||
### 1. 嵌套 vs 扁平配置
|
||||
|
||||
**选择**: 嵌套结构 `config.bioyond_config`
|
||||
|
||||
**理由**:
|
||||
- ✅ 语义清晰,配置分组明确
|
||||
- ✅ 参数传递直观,直接对应 `__init__` 参数
|
||||
- ✅ 易于维护,不需要硬编码字段列表
|
||||
- ✅ 符合 UniLab 设计模式
|
||||
|
||||
### 2. HTTP 服务去重
|
||||
|
||||
**实现**: 子类设置 `_disable_auto_http_service` 标志
|
||||
|
||||
```python
|
||||
# bioyond_cell_workstation.py
|
||||
self.bioyond_config["_disable_auto_http_service"] = True
|
||||
|
||||
# station.py (post_init)
|
||||
if self.bioyond_config.get("_disable_auto_http_service"):
|
||||
logger.info("子类已自行管理HTTP服务,跳过自动启动")
|
||||
return
|
||||
```
|
||||
|
||||
### 3. 全局变量替换策略
|
||||
|
||||
**原则**: 所有配置从 `self.bioyond_config` 获取
|
||||
|
||||
**模式**:
|
||||
```python
|
||||
# 修改前
|
||||
from config import MATERIAL_TYPE_MAPPINGS
|
||||
carrier_type_id = MATERIAL_TYPE_MAPPINGS[board_type][1]
|
||||
|
||||
# 修改后
|
||||
carrier_type_id = self.bioyond_config['material_type_mappings'][board_type][1]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 验证结果
|
||||
|
||||
### 启动成功日志
|
||||
```
|
||||
✅ 从 JSON 配置加载 bioyond_config 成功
|
||||
API Host: http://172.16.11.219:44388
|
||||
HTTP Service: 172.16.11.206:8080
|
||||
🔧 已设置 _disable_auto_http_service 标志,防止 HTTP 服务重复启动
|
||||
✅ BioyondCellWorkstation 初始化完成
|
||||
Loaded ResourceTreeSet with 1 trees, 1785 total nodes
|
||||
```
|
||||
|
||||
### 功能验证
|
||||
- ✅ 订单创建 (`create_orders_v2`)
|
||||
- ✅ 质量比计算
|
||||
- ✅ 物料转移 (`transfer_3_to_2_to_1`)
|
||||
- ✅ HTTP 报送接收 (step_finish, sample_finish, order_finish)
|
||||
- ✅ 等待机制 (`wait_for_order_finish`)
|
||||
- ✅ 仓库 UUID 映射
|
||||
- ✅ 物料类型映射
|
||||
|
||||
---
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- **配置迁移经验**: `2026-01-13_JSON配置迁移经验.md`
|
||||
- **任务清单**: `C:\Users\AndyXie\.gemini\antigravity\brain\...\task.md`
|
||||
- **实施计划**: `C:\Users\AndyXie\.gemini\antigravity\brain\...\implementation_plan.md`
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
### 其他工作站模块
|
||||
|
||||
以下文件仍在使用 `config.py` 全局变量(未包含在本次修改中):
|
||||
- `reaction_station.py` - 使用 `API_CONFIG`
|
||||
- `experiment.py` - 使用 `API_CONFIG`, `WORKFLOW_MAPPINGS`, `MATERIAL_TYPE_MAPPINGS`
|
||||
- `dispensing_station.py` - 使用 `API_CONFIG`, `WAREHOUSE_MAPPING`
|
||||
- `station.py` L176, L177, L529, L530 - 动态导入 `WAREHOUSE_MAPPING`
|
||||
|
||||
**建议**: 后续可以统一迁移这些模块到 JSON 配置。
|
||||
|
||||
### config.py 文件
|
||||
|
||||
`config.py` 文件已恢复但**不再被 bioyond_cell 使用**。可以:
|
||||
- 保留作为其他模块的参考
|
||||
- 或者完全删除(如果其他模块也迁移完成)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 下一步建议
|
||||
|
||||
1. **清理调试代码** ✅ (已完成)
|
||||
2. **提交代码到 Git**
|
||||
3. **迁移其他工作站模块** (可选)
|
||||
4. **更新文档和启动脚本**
|
||||
|
||||
---
|
||||
|
||||
**修改完成日期**: 2026-01-13
|
||||
**系统状态**: ✅ 稳定运行
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,157 @@
|
||||
# 批量出库 Excel 模板使用说明
|
||||
|
||||
**文件**: `outbound_template.xlsx`
|
||||
**用途**: 配合 `auto_batch_outbound_from_xlsx()` 方法进行批量出库操作
|
||||
**API 端点**: `/api/lims/storage/auto-batch-out-bound`
|
||||
|
||||
---
|
||||
|
||||
## 📋 Excel 列说明
|
||||
|
||||
| 列名 | 说明 | 示例 | 必填 |
|
||||
|------|------|------|------|
|
||||
| `locationId` | **库位 ID(UUID)** | `3a19da43-57b5-294f-d663-154a1cc32270` | ✅ 是 |
|
||||
| `warehouseId` | **仓库 ID 或名称** | `配液站内试剂仓库` | ✅ 是 |
|
||||
| `quantity` | **出库数量** | `1.0`, `2.0` | ✅ 是 |
|
||||
| `x` | **X 坐标(库位横向位置)** | `1`, `2`, `3` | ✅ 是 |
|
||||
| `y` | **Y 坐标(库位纵向位置)** | `1`, `2`, `3` | ✅ 是 |
|
||||
| `z` | **Z 坐标(库位层数/高度)** | `1`, `2`, `3` | ✅ 是 |
|
||||
| `备注说明` | 可选备注信息 | `配液站内试剂仓库-A01` | ❌ 否 |
|
||||
|
||||
### 📐 坐标说明
|
||||
|
||||
**x, y, z** 是库位在仓库内的**三维坐标**:
|
||||
|
||||
```
|
||||
仓库(例如 WH4)
|
||||
├── Z=1(第1层/加样头面)
|
||||
│ ├── X=1, Y=1(位置 A)
|
||||
│ ├── X=2, Y=1(位置 B)
|
||||
│ ├── X=3, Y=1(位置 C)
|
||||
│ └── ...
|
||||
│
|
||||
└── Z=2(第2层/原液瓶面)
|
||||
├── X=1, Y=1(位置 A)
|
||||
├── X=2, Y=1(位置 B)
|
||||
└── ...
|
||||
```
|
||||
|
||||
- **warehouseId**: 指定哪个仓库(WH3, WH4, 配液站等)
|
||||
- **x, y, z**: 在该仓库内的三维坐标
|
||||
- **locationId**: 该坐标位置的唯一 UUID
|
||||
|
||||
### 🎯 起点与终点
|
||||
|
||||
**重要说明**:批量出库模板**只规定了出库的"起点"**(从哪里取物料),**没有指定"终点"**(放到哪里)。
|
||||
|
||||
```
|
||||
出库流程:
|
||||
起点(Excel 指定) → ?终点(LIMS/工作流决定)
|
||||
↓
|
||||
locationId, x, y, z → 由 LIMS 系统或当前工作流自动分配
|
||||
```
|
||||
|
||||
**终点由以下方式确定:**
|
||||
- **LIMS 系统自动分配**:根据当前任务自动规划目标位置
|
||||
- **工作流预定义**:在创建出库任务时已绑定目标位置
|
||||
- **暂存区**:默认放到出库暂存区,等待下一步操作
|
||||
|
||||
💡 **对比**:上料操作(`auto_feeding4to3`)则有 `targetWH` 参数可以指定目标仓库
|
||||
|
||||
---
|
||||
|
||||
## 🔍 如何获取 UUID?
|
||||
|
||||
### 方法 1:从配置文件获取
|
||||
|
||||
参考 `yibin_electrolyte_config.json` 中的 `warehouse_mapping`:
|
||||
|
||||
```json
|
||||
{
|
||||
"warehouse_mapping": {
|
||||
"配液站内试剂仓库": {
|
||||
"site_uuids": {
|
||||
"A01": "3a19da43-57b5-294f-d663-154a1cc32270",
|
||||
"B01": "3a19da43-57b5-7394-5f49-54efe2c9bef2",
|
||||
"C01": "3a19da43-57b5-5e75-552f-8dbd0ad1075f"
|
||||
}
|
||||
},
|
||||
"手动堆栈": {
|
||||
"site_uuids": {
|
||||
"A01": "3a19deae-2c7a-36f5-5e41-02c5b66feaea",
|
||||
"A02": "3a19deae-2c7a-dc6d-c41e-ef285d946cfe"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 方法 2:通过 API 查询
|
||||
|
||||
```python
|
||||
material_info = hardware_interface.material_id_query(workflow_id)
|
||||
locations = material_info.get("locations", [])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 填写示例
|
||||
|
||||
### 示例 1:从配液站内试剂仓库出库
|
||||
|
||||
| locationId | warehouseId | quantity | x | y | z | 备注说明 |
|
||||
|------------|-------------|----------|---|---|---|----------|
|
||||
| `3a19da43-57b5-294f-d663-154a1cc32270` | 配液站内试剂仓库 | 1 | 1 | 1 | 1 | A01 位置 |
|
||||
| `3a19da43-57b5-7394-5f49-54efe2c9bef2` | 配液站内试剂仓库 | 2 | 2 | 1 | 1 | B01 位置 |
|
||||
|
||||
### 示例 2:从手动堆栈出库
|
||||
|
||||
| locationId | warehouseId | quantity | x | y | z | 备注说明 |
|
||||
|------------|-------------|----------|---|---|---|----------|
|
||||
| `3a19deae-2c7a-36f5-5e41-02c5b66feaea` | 手动堆栈 | 1 | 1 | 1 | 1 | A01 |
|
||||
| `3a19deae-2c7a-dc6d-c41e-ef285d946cfe` | 手动堆栈 | 1 | 1 | 2 | 1 | A02 |
|
||||
|
||||
---
|
||||
|
||||
## 💻 使用方法
|
||||
|
||||
```python
|
||||
from bioyond_cell_workstation import BioyondCellWorkstation
|
||||
|
||||
# 初始化工作站
|
||||
workstation = BioyondCellWorkstation(config=config, deck=deck)
|
||||
|
||||
# 调用批量出库方法
|
||||
result = workstation.auto_batch_outbound_from_xlsx(
|
||||
xlsx_path="outbound_template.xlsx"
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **locationId 必须是有效的 UUID**,不能使用库位名称
|
||||
2. **x, y, z 坐标必须与 locationId 对应**,表示该库位在仓库内的位置
|
||||
3. **quantity 必须是数字**,可以是整数或浮点数
|
||||
4. Excel 文件必须包含表头行
|
||||
5. 空行会被自动跳过
|
||||
6. 确保 UUID 与实际库位对应,否则 API 会报错
|
||||
|
||||
---
|
||||
|
||||
## 📚 相关文件
|
||||
|
||||
- **配置文件**: `yibin_electrolyte_config.json`
|
||||
- **Python 代码**: `bioyond_cell_workstation.py` (L630-695)
|
||||
- **生成脚本**: `create_outbound_template.py`
|
||||
- **上料模板**: `material_template.xlsx`
|
||||
|
||||
---
|
||||
|
||||
## 🔄 重新生成模板
|
||||
|
||||
```bash
|
||||
conda activate newunilab
|
||||
python create_outbound_template.py
|
||||
```
|
||||
Reference in New Issue
Block a user