mirror of
https://github.com/deepmodeling/Uni-Lab-OS
synced 2026-04-26 20:14:10 +00:00
fix: 物料系统标准化重构 + 多轮运行期 Bug 修复 (2026-03-12)
- MagazineHolder: klasses=None,解耦极片子节点初始化 - Magazine: 重写 serialize/deserialize,截断旧极片脏数据 - bottle_carriers: 移除 YIHUA_Electrolyte_12VialCarrier 初始化填瓶 - decks.py: BIOYOND_YB_Deck→BioyondElectrolyteDeck,移除 setup 参数 - YB_YH_materials.py: CoincellDeck→YihuaCoinCellDeck,新增 electrolyte_buffer 槽位 - resource_tracker.py: Container 状态键预填 + 重复 UUID 自动修复 + 树级名称去重 - itemized_carrier.py: XY 近似坐标匹配,修复 Z 偏移问题 - bioyond_cell_workstation.py: 跨站转运改用真实资源 + 类型映射双模式查找 - station.py: sync_to_external 属性访问路径修复 - coin_cell_assembly.py: 新增 10 个 Modbus 余量属性 - CSV/JSON/YAML 配置同步更新(类名重命名 + 移除 setup) - 新增 changelog_2026-03-12.md
This commit is contained in:
@@ -585,6 +585,31 @@ class ResourceTreeSet(object):
|
||||
d["model"] = res.config.get("model", None)
|
||||
return d
|
||||
|
||||
def _deduplicate_plr_dict(d: dict, _seen: set = None) -> dict:
|
||||
"""递归去除 children 中同名重复节点(全树范围、保留首次出现)。
|
||||
|
||||
根本原因:同一槽位被 sync_from_external(Bioyond 同步)重复写入,
|
||||
导致数据库中同一 WareHouse 下存在多条同名 BottleCarrier 记录(不同 UUID)。
|
||||
PLR 的 _check_naming_conflicts 在全树范围检查名称唯一性,
|
||||
重复名称会在 deserialize 时抛出 ValueError,导致节点启动失败。
|
||||
此函数在 sub_cls.deserialize 前预先清理,保证名称唯一。
|
||||
"""
|
||||
if _seen is None:
|
||||
_seen = set()
|
||||
children = d.get("children", [])
|
||||
deduped = []
|
||||
for child in children:
|
||||
child = _deduplicate_plr_dict(child, _seen)
|
||||
cname = child.get("name")
|
||||
if cname not in _seen:
|
||||
_seen.add(cname)
|
||||
deduped.append(child)
|
||||
else:
|
||||
logger.warning(
|
||||
f"[资源树去重] 发现重复资源名称 '{cname}',跳过重复项(历史脏数据)"
|
||||
)
|
||||
return {**d, "children": deduped}
|
||||
|
||||
plr_resources = []
|
||||
tracker = DeviceNodeResourceTracker()
|
||||
|
||||
@@ -595,6 +620,8 @@ class ResourceTreeSet(object):
|
||||
collect_node_data(tree.root_node, name_to_uuid, all_states, name_to_extra)
|
||||
has_model = tree.root_node.res_content.type != "deck"
|
||||
plr_dict = node_to_plr_dict(tree.root_node, has_model)
|
||||
plr_dict = _deduplicate_plr_dict(plr_dict)
|
||||
|
||||
try:
|
||||
sub_cls = find_subclass(plr_dict["type"], PLRResource)
|
||||
if skip_devices and plr_dict["type"] == "device":
|
||||
@@ -613,6 +640,14 @@ class ResourceTreeSet(object):
|
||||
|
||||
location = cast(Coordinate, deserialize(plr_dict["location"]))
|
||||
plr_resource.location = location
|
||||
|
||||
# 预填 Container 类型资源在新版 PLR 中要求必须存在的键,
|
||||
# 防止旧数据库状态缺失这些键时 load_all_state 抛出 KeyError。
|
||||
for state in all_states.values():
|
||||
if isinstance(state, dict):
|
||||
state.setdefault("liquid_history", [])
|
||||
state.setdefault("pending_liquids", {})
|
||||
|
||||
plr_resource.load_all_state(all_states)
|
||||
# 使用 DeviceNodeResourceTracker 设置 UUID 和 Extra
|
||||
tracker.loop_set_uuid(plr_resource, name_to_uuid)
|
||||
|
||||
Reference in New Issue
Block a user