From f522c9ffa487e3710d691e8b98df8c4f0cfafd43 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 05 九月 2026 20:07:26 +0800
Subject: [PATCH] 支持模拟器逐通道参数与工步方案配置
---
battery-device-simulator/src/main/java/com/battery/device/simulator/BtsDevelopmentSimulator.java | 72 +++++++++++++++++++++++++-----------
1 files changed, 50 insertions(+), 22 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 f20ee73..d0ba2fb 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
@@ -23,6 +23,7 @@
import com.battery.device.api.TestDataObservationAdapter;
import com.battery.device.simulator.BtsSimulatorStateStore;
import com.battery.device.simulator.BtsSimulatorStateStore.ChannelState;
+import com.battery.device.simulator.BtsSimulatorStateStore.ChannelConfiguration;
import com.battery.device.simulator.BtsSimulatorStateStore.ChannelTombstone;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorChannelState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
@@ -218,10 +219,26 @@
if (channelId < 1 || channelId > device.channels().size())
throw new IllegalArgumentException("channelId must be between 1 and " + device.channels().size());
List<ChannelState> channels = new ArrayList<>(device.channels());
- channels.set(channelId - 1, new ChannelState(channelId, online, workStatus));
+ channels.set(channelId - 1, new ChannelState(channelId, online, workStatus,
+ channels.get(channelId - 1).configuration()));
persist(new SimulatorState(state.version(),
replaceDevice(new DeviceState(deviceId, device.ip(), device.online(), channels, device.profile())), state.collectors(),
state.nextDeviceId(), state.nextCollectorId(), state.tombstones()));
+ }
+
+ /** 保存单通道的当前测量和工步方案,不改写在线或工作状态,不产生观测。 */
+ public synchronized void configureChannel(int deviceId, int channelId, ChannelConfiguration configuration)
+ {
+ if (configuration == null) throw new IllegalArgumentException("通道配置不能为空");
+ DeviceState device = requireDevice(deviceId);
+ if (channelId < 1 || channelId > device.channels().size())
+ throw new IllegalArgumentException("通道不存在");
+ List<ChannelState> channels = new ArrayList<>(device.channels());
+ ChannelState channel = channels.get(channelId - 1);
+ channels.set(channelId - 1, new ChannelState(channelId, channel.online(), channel.workStatus(), configuration));
+ persist(new SimulatorState(state.version(),
+ replaceDevice(new DeviceState(deviceId, device.ip(), device.online(), channels, device.profile())),
+ state.collectors(), state.nextDeviceId(), state.nextCollectorId(), state.tombstones()));
}
/** 新增一台与 BTS 检测柜拓扑隔离的开发采集器。 */
@@ -297,14 +314,29 @@
replaceCollector(DevelopmentCollectorSimulation.configureStatus(requireCollector(collectorId), channelCode, status));
}
- /** 返回固定的开发计划,不推进工步或生成历史。 */
+ /** 返回通道已配置的开发方案及当前工步位置,不自动推进或生成历史。 */
@Override
public synchronized TestPlan testPlan(ChannelIdentity channel)
{
if (!canObserve(channel)) return null;
- return new TestPlan(1, 1, 1, List.of(new PlanRow("STEP", 1, 1, "恒流充电", 60d, 3.7d,
- requireDevice(channel.devid()).channels().get(channel.chlid() - 1).workStatus() == DeviceWorkStatus.FINISHED
- ? "已完成" : "待执行", null, null)));
+ ChannelState source = requireDevice(channel.devid()).channels().get(channel.chlid() - 1);
+ ChannelConfiguration configuration = source.configuration();
+ List<PlanRow> rows = new ArrayList<>();
+ for (int index = 0; index < configuration.steps().size(); index++) {
+ var step = configuration.steps().get(index);
+ String status = index + 1 < configuration.stepNo() ? "已完成" : "待执行";
+ if (index + 1 == configuration.stepNo()) status = switch (source.workStatus()) {
+ case WORKING -> "进行中";
+ case PAUSED -> "暂停";
+ case FINISHED -> "已完成";
+ case PROTECTED -> "异常";
+ default -> "待执行";
+ };
+ // cyclePosition 表示循环内的工步位置,不能使用当前循环号,否则控制台会合并不同工步。
+ rows.add(new PlanRow("STEP", index + 1, index + 1, step.name(), step.durationSeconds(),
+ step.voltageV(), status, null, null));
+ }
+ return new TestPlan(configuration.cycleNo(), configuration.stepNo(), configuration.plannedCycleCount(), rows);
}
/** 请求当前检测柜测量;离线或无法观测时不返回缓存值。 */
@@ -324,14 +356,13 @@
if (channel.workStatus() == DeviceWorkStatus.UNOBSERVABLE) return null;
Instant now = Instant.now().truncatedTo(java.time.temporal.ChronoUnit.MILLIS);
long sequence = nextObservationSequence();
- double wave = Math.sin((sequence + channel.channelId()) * 0.7d);
- BtsDeviceProfile profile = profileFor(device);
- double current = channel.workStatus() == DeviceWorkStatus.WORKING
- ? clamp(profile.currentMaxA().doubleValue() * (0.18d + wave * 0.02d),
- profile.currentMinA().doubleValue(), profile.currentMaxA().doubleValue()) : 0d;
- double voltage = clamp(3.7d + wave * 0.01d, profile.voltageMinV().doubleValue(), profile.voltageMaxV().doubleValue());
- CabinetRealtime result = new CabinetRealtime(sequence, now, current, voltage, 1.2d, 4.44d,
- 1, 1, "恒流充电", "cc", now, DEVICE_TIME.format(now.atZone(DEVICE_ZONE)), DEVICE_ZONE.getId());
+ ChannelConfiguration configuration = channel.configuration();
+ var step = configuration.steps().get(configuration.stepNo() - 1);
+ // 保存值直接成为当前观测;工作状态和设备量程不反向覆盖操作员配置。
+ CabinetRealtime result = new CabinetRealtime(sequence, now, configuration.currentA().doubleValue(),
+ configuration.voltageV().doubleValue(), configuration.capacityAh().doubleValue(), configuration.energyWh().doubleValue(),
+ configuration.cycleNo(), configuration.stepNo(), step.name(), step.stepType(),
+ now, DEVICE_TIME.format(now.atZone(DEVICE_ZONE)), DEVICE_ZONE.getId());
return result;
}
@@ -406,7 +437,7 @@
.map(device -> new DeviceSnapshot(device.deviceId(), device.ip(), device.online(), device.profile(),
device.channels().stream()
.map(channel -> new ChannelSnapshot(channel.channelId(), channel.online(),
- channel.workStatus()))
+ channel.workStatus(), channel.configuration()))
.toList()))
.toList();
List<CollectorSnapshot> collectorSnapshots = state.collectors().stream()
@@ -581,7 +612,8 @@
.append("\" current=\"").append(decimal(current)).append("\" voltage=\"")
.append(decimal(voltage)).append("\" capacity=\"").append(decimal(capacity))
.append("\" energy=\"").append(decimal(energy)).append("\" totaltime=\"")
- .append(0).append("\" relativetime=\"").append(0)
+ .append(channel.configuration().totalTimeSeconds()).append("\" relativetime=\"")
+ .append(channel.configuration().relativeTimeSeconds())
.append("\" open_or_close=\"0\" log_code=\"0\">")
// 模拟器返回当前设备方案,供统一观测模型展示;不代表真实 BTS 的完整方案字段。
.append("<plan><step step_no=\"").append(stepNo).append("\" step_type=\"")
@@ -662,14 +694,9 @@
throw new IllegalArgumentException("Unsupported Neware simulator model: " + model);
}
- private double clamp(double value, double minimum, double maximum)
- {
- return Math.max(minimum, Math.min(maximum, value));
- }
-
private String decimal(double value)
{
- return String.format(java.util.Locale.ROOT, "%.3f", value);
+ return java.math.BigDecimal.valueOf(value).toPlainString();
}
private String toBtsWorkStatus(DeviceWorkStatus status)
@@ -848,7 +875,8 @@
public record DeviceSnapshot(int deviceId, String ip, boolean online, BtsDeviceProfile profile,
List<ChannelSnapshot> channels) { }
- public record ChannelSnapshot(int channelId, boolean online, DeviceWorkStatus workStatus) { }
+ public record ChannelSnapshot(int channelId, boolean online, DeviceWorkStatus workStatus,
+ ChannelConfiguration configuration) { }
public record CollectorSnapshot(int collectorId, String deviceCode, String ip, String mac, String name,
String manufacturer, String model, int channelCount, boolean online, int sampleIntervalMs,
--
Gitblit v1.7.1