yeg
2026-09-29 b78295e8da96c3e5e76befeef9582ce5273dbb74
battery-device-simulator/src/main/java/com/battery/device/simulator/BtsDevelopmentSimulator.java
@@ -7,10 +7,14 @@
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.api.model.DeviceWorkStatus;
import com.battery.device.api.model.DeviceConnectionStatus;
import com.battery.device.api.model.DeviceIdentity;
@@ -19,6 +23,7 @@
import com.battery.device.api.model.DetectedDeviceMetadata;
import com.battery.device.api.model.ChannelIdentity;
import com.battery.device.api.model.AdapterCapabilities;
import com.battery.device.api.model.RealtimeSnapshot;
import com.battery.device.api.DeviceObservationAdapter;
import com.battery.device.api.TestDataObservationAdapter;
import com.battery.device.simulator.BtsSimulatorStateStore;
@@ -37,8 +42,12 @@
import com.battery.device.simulator.DevelopmentCollectorSimulation;
import com.battery.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
/** 提供由开发后端托管的临时只读 BTS 模拟端点。 */
public final class BtsDevelopmentSimulator implements TestDataObservationAdapter
/**
 * 提供由开发后端托管的临时只读 BTS 模拟端点。
 * 同时实现发现与测试数据观测契约:模拟器直接暴露自身状态,因此发现与取数按同一实例解析,
 * 不再需要单独注入一个扩展观测 Bean。TCP 端点仍保留给协议层测试使用。
 */
public final class BtsDevelopmentSimulator implements DeviceAdapter, TestDataObservationAdapter
{
    public static final String HOST = "127.0.0.1";
    public static final int DEFAULT_PORT = 15020;
@@ -59,12 +68,14 @@
    private static final ZoneId DEVICE_ZONE = ZoneId.of("Asia/Hong_Kong");
    private static final DateTimeFormatter DEVICE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    /** 返回固定的适配器实例代码,用于把模拟观测归属到 dev-sim 这一实例。 */
    @Override
    public String adapterCode()
    {
        return ADAPTER_CODE;
    }
    /** 返回只观测能力:支持发现与实时观测,不支持历史下载,也不支持向设备下发控制命令。 */
    @Override
    public AdapterCapabilities capabilities()
    {
@@ -104,6 +115,34 @@
        return java.util.Map.copyOf(result);
    }
    /** 直接提供模拟器实时快照;不可观测通道不出现在结果里,与 BTS 协议解析后的语义一致。 */
    @Override
    public synchronized Map<ChannelIdentity, RealtimeSnapshot> inquire(Set<ChannelIdentity> channels)
    {
        if (channels == null || channels.isEmpty()) return Map.of();
        Map<ChannelIdentity, RealtimeSnapshot> result = new LinkedHashMap<>();
        for (ChannelIdentity requested : channels)
        {
            if (!canObserve(requested)) continue;
            CabinetRealtime measurement = cabinetMeasurement(requested);
            if (measurement == null) continue;
            DeviceObservation observed = observation(requested);
            result.put(requested, new RealtimeSnapshot(requested, observed.workStatus(), measurement.cycleNo(),
                    measurement.stepNo(), measurement.stepType(), null, BigDecimal.valueOf(measurement.currentA()),
                    BigDecimal.valueOf(measurement.voltageV()), BigDecimal.valueOf(measurement.capacityAh()),
                    BigDecimal.valueOf(measurement.energyWh()), totalTimeSeconds(requested),
                    measurement.relativeTimeSeconds(), null, measurement.serverReceivedAt(), Map.of(),
                    DeviceConnectionStatus.ONLINE, measurement.deviceTime(), List.of(), null));
        }
        recordRequest("inquire", channels.toString(), result.toString());
        return Map.copyOf(result);
    }
    private long totalTimeSeconds(ChannelIdentity identity)
    {
        return requireDevice(identity.devid()).channels().get(identity.chlid() - 1).configuration().totalTimeSeconds();
    }
    private DeviceObservation observation(ChannelIdentity requested)
    {
        DeviceState device = state.devices().stream().filter(item -> item.deviceId() == requested.devid())
@@ -135,6 +174,7 @@
        simulator = ScriptedBtsTcpSimulator.responding(port, this::respond);
    }
    /** 返回模拟器 TCP 端点实际监听的端口。 */
    public int port()
    {
        return simulator.port();
@@ -368,7 +408,7 @@
    /** 请求采集器当前配置值;软件不可访问或设备离线时返回空测量。 */
    @Override
    public synchronized CollectorRealtime latestCollector(String collectorCode)
    public synchronized CollectorRealtime latestCollector(String adapterCode, String collectorCode)
    {
        CollectorState collector = state.collectors().stream().filter(item -> item.deviceCode().equals(collectorCode))
                .findFirst().orElse(null);
@@ -853,6 +893,7 @@
            throw new IllegalStateException("Invalid BTS simulator numbering or tombstone state in Redis");
    }
    /** 停止模拟器:标记为不再运行并释放 TCP 端点;释放失败时以运行时异常报告。 */
    @Override
    public synchronized void close()
    {