Skip to content

Commit 8670d1e

Browse files
committed
fix:修复IEC61850客户端无法解析服务端主动报告的bug
1 parent 05b76aa commit 8670d1e

2 files changed

Lines changed: 60 additions & 12 deletions

File tree

src/proto/iec61850/plugins/reports/__init__.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -494,14 +494,43 @@ def _enable_report(
494494
# 回调不会被触发, 导致报告数据缓存为空。
495495
rpt_id = ""
496496
data_set_ref = ""
497+
498+
# 优先通过 getRCBValues 直接读取 RptId(比 get_rcb_detail 更直接可靠)
497499
try:
498-
detail = self.get_rcb_detail(rcb_ref)
499-
if detail:
500-
rpt_id = str(detail.get("rpt_id", "") or "")
501-
data_set_ref = str(detail.get("data_set_ref", "") or "")
502-
log.info(f"_enable_report: 读取 RptId: {rcb_ref}, rpt_id={rpt_id!r}")
500+
if rcb_type == "BRCB":
501+
rcb_info = BrcbHandler.get_rcb_values(self._connection, rcb_ref)
502+
else:
503+
rcb_info = UrcbHandler.get_rcb_values(self._connection, rcb_ref)
504+
if rcb_info and hasattr(rcb_info, "rpt_id") and rcb_info.rpt_id:
505+
rpt_id = str(rcb_info.rpt_id)
506+
data_set_ref = str(rcb_info.data_set_ref or "")
507+
log.info(f"_enable_report: 直接读取 RptId 成功: {rcb_ref}, rpt_id={rpt_id!r}")
508+
elif rcb_info:
509+
data_set_ref = str(rcb_info.data_set_ref or "")
510+
log.info(f"_enable_report: 直接读取 RptId 为空: {rcb_ref}, data_set_ref={data_set_ref!r}")
503511
except Exception as e:
504-
log.warning(f"_enable_report: 读取 RptId 失败: {rcb_ref}, {e}")
512+
log.warning(f"_enable_report: 直接读取 RptId 失败: {rcb_ref}, {e}, 尝试从缓存读取")
513+
514+
# 备用:从缓存中读取
515+
if not rpt_id:
516+
try:
517+
detail = self.get_rcb_detail(rcb_ref)
518+
if detail:
519+
rpt_id = str(detail.get("rpt_id", "") or "")
520+
if not data_set_ref:
521+
data_set_ref = str(detail.get("data_set_ref", "") or "")
522+
log.info(f"_enable_report: 从缓存读取 RptId: {rcb_ref}, rpt_id={rpt_id!r}")
523+
except Exception as e:
524+
log.warning(f"_enable_report: 从缓存读取 RptId 失败: {rcb_ref}, {e}")
525+
526+
# 如果 RptId 仍为空,记录严重警告
527+
if not rpt_id:
528+
log.warning(
529+
f"_enable_report: RptId 为空!"
530+
f"部分 libIEC61850 版本中空 RptId 会导致报告回调无法被触发。"
531+
f"请检查 IED 的 RCB ({rcb_ref}) 是否配置了 RptId。"
532+
f"rcb_type={rcb_type}"
533+
)
505534

506535
# 查询数据集成员引用列表,用于报告数据解析时将 data[i] 映射为具体引用
507536
dataset_members: list[str] = []

src/proto/iec61850/plugins/reports/callback.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,21 +235,40 @@ def install(
235235

236236
try:
237237
nref = _normalize_ref(rcb_ref, rcb_type)
238+
log.info(f"安装报告回调: rcb_ref={rcb_ref}, mms_ref={nref}, rpt_id={rpt_id!r}, rcb_type={rcb_type}")
239+
240+
# 警告:RptId 为空时,部分版本的 libIEC61850 RCBSubscriber
241+
# 无法匹配服务器推送的报告,导致 RCBHandler.trigger 永远不会被调用
242+
effective_rpt_id = rpt_id or ""
243+
if not effective_rpt_id:
244+
log.warning(
245+
f"RptId 为空,报告回调可能无法匹配服务器推送的报告!"
246+
f"请检查 IED 的 RCB 配置中是否设置了 RptId。rcb_ref={rcb_ref}"
247+
)
248+
238249
handler = _PyRCBHandler(rcb_ref)
239250
subscriber = iec61850.RCBSubscriber()
240251
subscriber.setIedConnection(conn)
241252
subscriber.setRcbReference(nref)
242-
subscriber.setRcbRptId(rpt_id or "")
253+
subscriber.setRcbRptId(effective_rpt_id)
243254
subscriber.setEventHandler(handler)
244-
if not subscriber.subscribe():
245-
log.warning(f"订阅报告失败: ref={nref}")
255+
256+
log.debug(f"RCBSubscriber.subscribe() 调用: ref={nref}, rpt_id={effective_rpt_id!r}")
257+
subscribe_ok = subscriber.subscribe()
258+
if not subscribe_ok:
259+
log.warning(
260+
f"RCBSubscriber.subscribe() 返回失败: ref={nref}, rpt_id={effective_rpt_id!r}, "
261+
f"rcb_ref={rcb_ref}"
262+
)
246263
with contextlib.suppress(Exception):
247264
subscriber.deleteEventHandler()
248265
if hasattr(handler, "thisown"):
249266
with contextlib.suppress(Exception):
250267
handler.thisown = 0
251268
return False
252269

270+
log.info(f"RCBSubscriber.subscribe() 成功: ref={nref}, rpt_id={effective_rpt_id!r}")
271+
253272
_CALLBACK_REGISTRY[rcb_ref] = _CallbackInfo(
254273
rcb_ref=rcb_ref,
255274
handler=handler,
@@ -258,13 +277,13 @@ def install(
258277
max_cache=max_cache,
259278
enabled_at=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
260279
mms_ref=nref,
261-
rpt_id=rpt_id or "",
280+
rpt_id=effective_rpt_id,
262281
dataset_members=dataset_members or [],
263282
)
264-
log.info(f"报告回调已安装: {rcb_ref} (mms_ref={nref})")
283+
log.info(f"报告回调已安装: {rcb_ref} (mms_ref={nref}, rpt_id={effective_rpt_id!r})")
265284
return True
266285
except Exception as e:
267-
log.error(f"安装报告回调异常: {rcb_ref}, {e}")
286+
log.error(f"安装报告回调异常: {rcb_ref}, {e}", exc_info=True)
268287
return False
269288

270289
@staticmethod

0 commit comments

Comments
 (0)