From bd50f1b756c1da2dbf92f6541407ad40f455e24a Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 05 九月 2026 00:17:52 +0800
Subject: [PATCH] 建立厂商无关设备观测接缝

---
 battery-device-simulator/src/main/java/com/battery/device/simulator/BtsDevelopmentSimulator.java |   91 +++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 87 insertions(+), 4 deletions(-)

diff --git a/battery-device-simulator/src/main/java/com/battery/device/simulator/BtsDevelopmentSimulator.java b/battery-device-simulator/src/main/java/com/battery/device/simulator/BtsDevelopmentSimulator.java
index 8151eb4..0067285 100644
--- a/battery-device-simulator/src/main/java/com/battery/device/simulator/BtsDevelopmentSimulator.java
+++ b/battery-device-simulator/src/main/java/com/battery/device/simulator/BtsDevelopmentSimulator.java
@@ -12,6 +12,14 @@
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamReader;
 import com.battery.device.model.DeviceWorkStatus;
+import com.battery.device.model.DeviceConnectionStatus;
+import com.battery.device.model.DeviceIdentity;
+import com.battery.device.model.DeviceObservation;
+import com.battery.device.model.DetectedChannel;
+import com.battery.device.model.DetectedDeviceMetadata;
+import com.battery.device.model.ChannelIdentity;
+import com.battery.device.model.AdapterCapabilities;
+import com.battery.device.api.DeviceObservationAdapter;
 import com.battery.device.simulator.BtsSimulatorStateStore;
 import com.battery.device.simulator.BtsSimulatorStateStore.ChannelState;
 import com.battery.device.simulator.BtsSimulatorStateStore.ChannelTombstone;
@@ -35,7 +43,7 @@
 import com.battery.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
 
 /** 提供由开发后端托管的临时只读 BTS 模拟端点。 */
-public final class BtsDevelopmentSimulator implements AutoCloseable
+public final class BtsDevelopmentSimulator implements DeviceObservationAdapter
 {
     public static final String HOST = "127.0.0.1";
     public static final int DEFAULT_PORT = 15020;
@@ -58,6 +66,71 @@
     private static final long SIMULATED_RECORD_INTERVAL_SECONDS = 60L;
     private static final DateTimeFormatter BTS_HISTORY_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH.mm.ss")
             .withZone(ZoneId.of("Asia/Hong_Kong"));
+
+    @Override
+    public String adapterCode()
+    {
+        return ADAPTER_CODE;
+    }
+
+    @Override
+    public AdapterCapabilities capabilities()
+    {
+        return AdapterCapabilities.observeOnly();
+    }
+
+    /** 直接提供模拟器当前拓扑,供不需要 TCP/XML 的契约测试使用。 */
+    @Override
+    public synchronized List<DetectedChannel> discoverChannels()
+    {
+        List<DetectedChannel> result = new ArrayList<>();
+        for (DeviceState device : state.devices())
+        {
+            BtsDeviceProfile profile = profileFor(device);
+            for (ChannelState channel : device.channels())
+            {
+                ChannelIdentity identity = new ChannelIdentity(ADAPTER_CODE, profile.devtype(), device.deviceId(),
+                        profile.subDeviceId(), channel.channelId());
+                result.add(new DetectedChannel(identity, device.ip(), device.online() && channel.online(),
+                        new DetectedDeviceMetadata(profile.name(), profile.manufacturer(), profile.model(),
+                                simulatorMac(profile.devtype(), device.deviceId()))));
+            }
+        }
+        return List.copyOf(result);
+    }
+
+    /** 直接提供模拟器观测;离线通道不保留上一次测量或工步事实。 */
+    @Override
+    public synchronized java.util.Map<ChannelIdentity, DeviceObservation> observe(
+            java.util.Set<ChannelIdentity> channels)
+    {
+        if (channels == null || channels.isEmpty()) return java.util.Map.of();
+        java.util.Map<ChannelIdentity, DeviceObservation> result = new java.util.LinkedHashMap<>();
+        for (ChannelIdentity requested : channels)
+        {
+            DeviceState device = state.devices().stream().filter(item -> item.deviceId() == requested.devid())
+                    .findFirst().orElse(null);
+            ChannelState channel = device == null ? null : device.channels().stream()
+                    .filter(item -> item.channelId() == requested.chlid()).findFirst().orElse(null);
+            if (device == null || channel == null || !ADAPTER_CODE.equals(requested.adapterCode())
+                    || !device.online() || !channel.online())
+            {
+                result.put(requested, DeviceObservation.offline(requested, "OFFLINE"));
+                continue;
+            }
+            BtsDeviceProfile profile = profileFor(device);
+            if (requested.devtype() != profile.devtype() || requested.subdevid() != profile.subDeviceId())
+            {
+                result.put(requested, DeviceObservation.offline(requested, "OFFLINE"));
+                continue;
+            }
+            result.put(requested, new DeviceObservation(
+                    new DeviceIdentity(ADAPTER_CODE, profile.devtype(), device.deviceId(), profile.subDeviceId()),
+                    requested, DeviceConnectionStatus.ONLINE, channel.workStatus(), List.of(), null,
+                    java.util.Map.of(), null));
+        }
+        return java.util.Map.copyOf(result);
+    }
 
     /** 启动仅监听 IPv4 本机回环地址的开发模拟器;传入 0 时由系统分配测试端口。 */
     public BtsDevelopmentSimulator(int port) throws IOException
@@ -721,7 +794,10 @@
                     .append(decimal(voltage)).append("\" capacity=\"").append(decimal(capacity))
                     .append("\" energy=\"").append(decimal(energy)).append("\" totaltime=\"")
                     .append(working ? tick : 0).append("\" relativetime=\"").append(working ? tick : 0)
-                    .append("\" open_or_close=\"0\" log_code=\"0\"/>");
+                    .append("\" open_or_close=\"0\" log_code=\"0\">")
+                    // 模拟器返回当前设备方案,供统一观测模型展示;不代表真实 BTS 的完整方案字段。
+                    .append("<plan><step step_no=\"").append(stepNo).append("\" step_type=\"")
+                    .append(stepType).append("\" name=\"").append(stepType).append("\"/></plan></inquire>");
         }
         return response.append("</list></bts>").toString();
     }
@@ -1203,10 +1279,17 @@
     }
 
     @Override
-    public synchronized void close() throws Exception
+    public synchronized void close()
     {
         running = false;
-        simulator.close();
+        try
+        {
+            simulator.close();
+        }
+        catch (Exception exception)
+        {
+            throw new IllegalStateException("关闭开发模拟器失败", exception);
+        }
     }
 
     private record ObservedChannel(int deviceId, ChannelState channel) { }

--
Gitblit v1.7.1