From 1de35281a699b8d2ca90777f63c7e032c3c9dc3d Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期一, 12 十月 2026 13:34:34 +0800
Subject: [PATCH] 对接第 6 台新威上位机(7.6 客户端,走库路线),并修两处对接中暴露的问题
---
battery-device-bts/src/main/java/com/battery/device/bts/NewareBtsAdapter.java | 67 ++++++++++++++++++++++++++++++++-
1 files changed, 64 insertions(+), 3 deletions(-)
diff --git a/battery-device-bts/src/main/java/com/battery/device/bts/NewareBtsAdapter.java b/battery-device-bts/src/main/java/com/battery/device/bts/NewareBtsAdapter.java
index 5ec2f15..d85470e 100644
--- a/battery-device-bts/src/main/java/com/battery/device/bts/NewareBtsAdapter.java
+++ b/battery-device-bts/src/main/java/com/battery/device/bts/NewareBtsAdapter.java
@@ -62,6 +62,11 @@
private final AdapterCapabilities capabilities;
/** 每通道最近一次工步层读取;见 {@link #stepLayer}。 */
private final Map<String, StepLayer> stepLayers = new ConcurrentHashMap<>();
+ /**
+ * 该客户端有没有数据文件命令({@code inquiredf} / {@code download} / {@code downloadStepLayer})。
+ * 未知为 null;探测一次后固定下来——见 {@link #supportsDataFileCommands}。
+ */
+ private volatile Boolean dataFileCommandsSupported;
public NewareBtsAdapter(String adapterCode, BtsTransport transport, BtsXmlCodec codec)
{
@@ -191,6 +196,12 @@
}
catch (BtsProtocolException unsupported)
{
+ // 客户端不提供 inquiredf(实测 7.6.0.1475):本来源不按设备数据行接收,逐点回落到轮询槽位。
+ return null;
+ }
+ catch (BtsTransportException unanswered)
+ {
+ // 探测说支持、发出去却不作答(已登记不再试):同样回落到轮询槽位,不把来源不可达说成"不按行接收"。
return null;
}
if (state.count() < 1) return new SampleWatermark(null, 0L);
@@ -256,9 +267,19 @@
private StepLayer fetchStepLayer(ChannelIdentity channel)
{
long fetchedAtNanos = System.nanoTime();
+ // 客户端没有这条命令时一条都不发:见 supportsDataFileCommands。
+ if (!supportsDataFileCommands(channel)) return new StepLayer(List.of(), null, fetchedAtNanos);
Instant receivedAt = Instant.now();
- List<StepRecord> layers = codec.parseStepLayer(
- transport.exchange(codec.downloadStepLayerRequest(channel)), receivedAt);
+ List<StepRecord> layers;
+ try
+ {
+ layers = codec.parseStepLayer(transport.exchange(codec.downloadStepLayerRequest(channel)), receivedAt);
+ }
+ catch (BtsTransportException unanswered)
+ {
+ rememberUnanswered(unanswered);
+ return new StepLayer(List.of(), null, fetchedAtNanos);
+ }
if (layers.isEmpty()) return new StepLayer(List.of(), null, fetchedAtNanos);
// 通道仍在动(运行、暂停、保护中)时最后一步没结束:它和它所在的循环都先按住。
if (!isStillRunning(channel)) return new StepLayer(layers, null, fetchedAtNanos);
@@ -343,7 +364,18 @@
private BtsXmlCodec.DataFileState dataFileState(ChannelIdentity channel)
{
- return codec.parseDataFileState(transport.exchange(codec.inquiredfRequest(channel)));
+ if (!supportsDataFileCommands(channel))
+ throw new BtsProtocolException(BtsProtocolException.Reason.MISSING_FIELD,
+ "该客户端不提供 inquiredf");
+ try
+ {
+ return codec.parseDataFileState(transport.exchange(codec.inquiredfRequest(channel)));
+ }
+ catch (BtsTransportException unanswered)
+ {
+ rememberUnanswered(unanswered);
+ throw unanswered;
+ }
}
private List<CabinetRealtime> download(ChannelIdentity channel, long testId, long startPosition, int count)
@@ -352,6 +384,35 @@
Instant.now());
}
+ /**
+ * 这台客户端有没有数据文件命令({@code inquiredf}/{@code download}/{@code downloadStepLayer})。
+ *
+ * <p>为什么必须先问一句再发:**对不支持这些命令的客户端发出去,代价不只是超时**。2026-10-12 实测
+ * (客户端 7.6.0.1475):发一条 {@code inquiredf} 之后,该接口的 {@code inquire} 连续 8 分钟无应答
+ * ({@code getdevinfo} 仍正常)——那等于干扰了那台上位机的对外接口。所以不支持的客户端
+ * **一条都不发**,逐点回落到轮询槽位、工步层为空。
+ *
+ * <p>探测依据是 {@code inquire} 应答的字段:7.6 的应答不带 {@code cycle_id},8.0 的带;
+ * 实测三个构建(7.6.0.1475 / 8.0.0.484 / 8.0.0.530)里"有没有 {@code cycle_id}"与
+ * "有没有这三条数据文件命令"同向。探测本身读不到应答时**抛出**(不吞):那说明来源不可达,
+ * 按契约要抛异常,不能被当成"该来源不按数据行接收"。
+ */
+ private boolean supportsDataFileCommands(ChannelIdentity channel)
+ {
+ Boolean known = dataFileCommandsSupported;
+ if (known != null) return known;
+ RealtimeSnapshot snapshot = inquire(Set.of(channel)).get(channel);
+ boolean supported = snapshot != null && snapshot.cycleNo() != null;
+ dataFileCommandsSupported = supported;
+ return supported;
+ }
+
+ /** 探测说支持、真发出去却不作答:记下来不再反复试——反复发一条无应答的命令会持续干扰那台接口。 */
+ private void rememberUnanswered(BtsTransportException failure)
+ {
+ if (failure.reason() == BtsTransportException.Reason.TIMEOUT) dataFileCommandsSupported = false;
+ }
+
/** 行的序号比水位大就是要的行;序号反而更小说明换了测试,此时按设备时间判定。 */
private static boolean isAfter(SampleWatermark watermark, CabinetRealtime row)
{
--
Gitblit v1.7.1