yeg
2026-09-04 b41d317e9b76b1158a9d21257698e55194bb39f5
建立电池检测模块骨架与运行时装配
1 文件已复制
1个文件已删除
42 文件已重命名
10个文件已添加
32个文件已修改
929 ■■■■■ 已修改文件
.gitignore 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-business/pom.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-business/src/main/java/com/battery/business/BatteryBusinessModule.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-business/src/test/java/com/battery/business/BatteryBusinessModuleTest.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-business/src/test/java/com/battery/business/ModuleDependencyContractTest.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/pom.xml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/api/DeviceAdapter.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/api/DeviceAdapterException.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/api/NoopDeviceAdapter.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/api/NoopDeviceAdapterFactory.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/discovery/DeviceDiscoveryCandidateStore.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/discovery/InMemoryDeviceDiscoveryCandidateStore.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/AdapterCapabilities.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/ChannelIdentity.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/DetectedChannel.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/DetectedDeviceMetadata.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/DeviceControlCommand.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/DeviceWorkStatus.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/HistoryAvailability.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/HistoryPage.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/HistorySample.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/Measurement.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/model/RealtimeSnapshot.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/registry/AdapterInstanceConfig.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/registry/AdapterRegistryException.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/registry/DeviceAdapterFactory.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/main/java/com/battery/device/registry/DeviceAdapterRegistry.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-api/src/test/java/com/battery/device/registry/DeviceAdapterRegistryTest.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/pom.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/main/java/com/battery/device/bts/BtsDeviceAdapter.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/main/java/com/battery/device/bts/BtsDeviceAdapterFactory.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/main/java/com/battery/device/bts/BtsFrameReader.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/main/java/com/battery/device/bts/BtsProtocolException.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/main/java/com/battery/device/bts/BtsTcpTransport.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/main/java/com/battery/device/bts/BtsTransport.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/main/java/com/battery/device/bts/BtsTransportException.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/main/java/com/battery/device/bts/BtsXmlCodec.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/test/java/com/battery/device/bts/BtsDeviceAdapterContractTest.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/test/java/com/battery/device/bts/BtsDeviceAdapterFactoryContractTest.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/test/java/com/battery/device/bts/BtsTcpTransportTest.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/test/java/com/battery/device/bts/BtsXmlCodecTest.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-bts/src/test/java/com/battery/device/bts/ScriptedBtsTcpSimulator.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/pom.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/src/main/java/com/battery/device/simulator/BtsDevelopmentSimulator.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/src/main/java/com/battery/device/simulator/BtsExcelFixture.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/src/main/java/com/battery/device/simulator/BtsSimulatorStateStore.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/src/main/java/com/battery/device/simulator/DevelopmentCollectorSimulation.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/src/main/java/com/battery/device/simulator/InMemoryBtsSimulatorStateStore.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/src/main/java/com/battery/device/simulator/ScriptedBtsTcpSimulator.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/src/test/java/com/battery/device/contract/DiscoveryCandidateStoreContractTest.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/src/test/java/com/battery/device/contract/SimulatorPublicContractTest.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/src/test/java/com/battery/device/simulator/BtsDevelopmentSimulatorHistoryContractTest.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
battery-device-simulator/src/test/java/com/battery/device/simulator/BtsDevelopmentSimulatorRecordStepCycleTest.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/pom.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorDiscoveryService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorSamplingScheduler.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizer.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentSimulatorDiscoveryScheduler.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/config/DeviceAdapterRuntimeConfig.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/config/RedisBtsSimulatorStateStore.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/config/RedisDeviceDiscoveryCandidateStore.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/device/BtsDevelopmentSimulatorController.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizerTest.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/config/DevelopmentSimulatorProfileContractTest.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/config/DeviceAdapterRuntimeConfigTest.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/config/DeviceAdapterRuntimeNoopStartupTest.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/config/RedisStateStoreTest.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/CollectorDiscoveryServiceImplTest.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImplTest.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/DeviceDiscoveryPersistenceServiceTest.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TCollectorServiceImplTest.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TDetectionCabinetServiceImplTest.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestLiveServiceImplTest.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TestDataReceptionServiceImplTest.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/test/java/com/ruoyi/web/controller/device/BtsDevelopmentSimulatorControllerTest.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-device/pom.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/pom.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceAdapterRuntimeCoordinator.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceDiscoveryPersistenceService.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TCollectorServiceImpl.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TDetectionCabinetServiceImpl.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataReceptionServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -1,6 +1,10 @@
/ruoyi-admin/target/
/ruoyi-common/target/
/ruoyi-device/target/
/battery-business/target/
/battery-device-api/target/
/battery-device-bts/target/
/battery-device-simulator/target/
/ruoyi-framework/target/
/ruoyi-generator/target/
/ruoyi-quartz/target/
battery-business/pom.xml
New file
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent><groupId>com.ruoyi</groupId><artifactId>ruoyi</artifactId><version>3.9.2</version></parent>
    <groupId>com.battery</groupId><artifactId>battery-business</artifactId>
    <description>电池检测业务模块</description>
    <dependencies>
        <dependency><groupId>com.battery</groupId><artifactId>battery-device-api</artifactId></dependency>
        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
    </dependencies>
</project>
battery-business/src/main/java/com/battery/business/BatteryBusinessModule.java
New file
@@ -0,0 +1,7 @@
package com.battery.business;
/** 电池检测业务模块入口标记;业务实现按能力继续放在本模块内。 */
public final class BatteryBusinessModule
{
    private BatteryBusinessModule() { }
}
battery-business/src/test/java/com/battery/business/BatteryBusinessModuleTest.java
New file
@@ -0,0 +1,17 @@
package com.battery.business;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
class BatteryBusinessModuleTest
{
    @Test
    void businessModuleExposesOnlyVendorNeutralDeviceContract()
    {
        assertNotNull(BatteryBusinessModule.class);
        assertNotNull(com.battery.device.api.DeviceAdapter.class);
        assertThrows(ClassNotFoundException.class,
                () -> Class.forName("com.battery.device.bts.BtsXmlCodec"));
    }
}
battery-business/src/test/java/com/battery/business/ModuleDependencyContractTest.java
New file
@@ -0,0 +1,21 @@
package com.battery.business;
import static org.junit.jupiter.api.Assertions.assertFalse;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
/** 防止业务模块在骨架阶段意外引入具体设备实现。 */
class ModuleDependencyContractTest
{
    @Test
    void businessPomKeepsVendorImplementationsOutOfItsDependencies() throws Exception
    {
        Path pom = Path.of("pom.xml");
        if (!Files.exists(pom)) pom = Path.of("battery-business", "pom.xml");
        String text = Files.readString(pom);
        assertFalse(text.contains("battery-device-bts"));
        assertFalse(text.contains("battery-device-simulator"));
        assertFalse(text.contains("spring-boot-starter-data-redis"));
    }
}
battery-device-api/pom.xml
New file
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent><groupId>com.ruoyi</groupId><artifactId>ruoyi</artifactId><version>3.9.2</version></parent>
    <groupId>com.battery</groupId><artifactId>battery-device-api</artifactId>
    <description>厂商无关设备观测契约与模型</description>
    <dependencies>
        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
    </dependencies>
</project>
battery-device-api/src/main/java/com/battery/device/api/DeviceAdapter.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/api/DeviceAdapter.java
@@ -1,15 +1,15 @@
package com.ruoyi.device.api;
package com.battery.device.api;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.ruoyi.device.model.AdapterCapabilities;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DetectedChannel;
import com.ruoyi.device.model.DeviceControlCommand;
import com.ruoyi.device.model.HistoryAvailability;
import com.ruoyi.device.model.HistoryPage;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.battery.device.model.AdapterCapabilities;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DetectedChannel;
import com.battery.device.model.DeviceControlCommand;
import com.battery.device.model.HistoryAvailability;
import com.battery.device.model.HistoryPage;
import com.battery.device.model.RealtimeSnapshot;
public interface DeviceAdapter extends AutoCloseable
{
battery-device-api/src/main/java/com/battery/device/api/DeviceAdapterException.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/api/DeviceAdapterException.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.api;
package com.battery.device.api;
public class DeviceAdapterException extends RuntimeException
{
battery-device-api/src/main/java/com/battery/device/api/NoopDeviceAdapter.java
New file
@@ -0,0 +1,47 @@
package com.battery.device.api;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.battery.device.model.AdapterCapabilities;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DetectedChannel;
import com.battery.device.model.HistoryAvailability;
import com.battery.device.model.HistoryPage;
import com.battery.device.model.RealtimeSnapshot;
/** 没有启用具体设备实现时使用的空适配器,不连接外部设备。 */
public final class NoopDeviceAdapter implements DeviceAdapter
{
    private final String adapterCode;
    public NoopDeviceAdapter(String adapterCode)
    {
        this.adapterCode = adapterCode == null || adapterCode.isBlank() ? "noop" : adapterCode;
    }
    @Override public String adapterCode() { return adapterCode; }
    @Override public AdapterCapabilities capabilities()
    {
        return new AdapterCapabilities(true, true, false, false);
    }
    @Override public List<DetectedChannel> discoverChannels() { return List.of(); }
    @Override public Map<ChannelIdentity, RealtimeSnapshot> inquire(Set<ChannelIdentity> channels)
    {
        return Map.of();
    }
    @Override public List<HistoryAvailability> inquireHistory(Set<ChannelIdentity> channels)
    {
        return List.of();
    }
    @Override public HistoryPage downloadHistory(ChannelIdentity channel, String btsTestId,
            long startPosition, int limit)
    {
        return new HistoryPage(channel, btsTestId, startPosition, startPosition, List.of());
    }
}
battery-device-api/src/main/java/com/battery/device/api/NoopDeviceAdapterFactory.java
New file
@@ -0,0 +1,15 @@
package com.battery.device.api;
import com.battery.device.registry.AdapterInstanceConfig;
import com.battery.device.registry.DeviceAdapterFactory;
/** 为默认启动路径提供不产生外部副作用的设备实现。 */
public final class NoopDeviceAdapterFactory implements DeviceAdapterFactory
{
    @Override public String adapterType() { return "NOOP"; }
    @Override public DeviceAdapter create(AdapterInstanceConfig config)
    {
        return new NoopDeviceAdapter(config.adapterCode());
    }
}
battery-device-api/src/main/java/com/battery/device/discovery/DeviceDiscoveryCandidateStore.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/discovery/DeviceDiscoveryCandidateStore.java
@@ -1,11 +1,11 @@
package com.ruoyi.device.discovery;
package com.battery.device.discovery;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.model.RealtimeSnapshot;
/** 保存未登记发现候选和正式设备的实时观测快照。 */
public interface DeviceDiscoveryCandidateStore
battery-device-api/src/main/java/com/battery/device/discovery/InMemoryDeviceDiscoveryCandidateStore.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/discovery/InMemoryDeviceDiscoveryCandidateStore.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.discovery;
package com.battery.device.discovery;
import java.time.Instant;
import java.util.LinkedHashMap;
battery-device-api/src/main/java/com/battery/device/model/AdapterCapabilities.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/AdapterCapabilities.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
public record AdapterCapabilities(
        boolean discovery,
battery-device-api/src/main/java/com/battery/device/model/ChannelIdentity.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/ChannelIdentity.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
import java.util.Objects;
battery-device-api/src/main/java/com/battery/device/model/DetectedChannel.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/DetectedChannel.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
public record DetectedChannel(ChannelIdentity identity, String serverIp, boolean available,
        DetectedDeviceMetadata deviceMetadata)
battery-device-api/src/main/java/com/battery/device/model/DetectedDeviceMetadata.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/DetectedDeviceMetadata.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
/** 设备发现响应可选携带的展示元数据;空值表示协议未提供。 */
public record DetectedDeviceMetadata(String name, String manufacturer, String model, String macAddress)
battery-device-api/src/main/java/com/battery/device/model/DeviceControlCommand.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/DeviceControlCommand.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
public enum DeviceControlCommand
{
battery-device-api/src/main/java/com/battery/device/model/DeviceWorkStatus.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/DeviceWorkStatus.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
import java.util.Locale;
battery-device-api/src/main/java/com/battery/device/model/HistoryAvailability.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/HistoryAvailability.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
import java.util.Objects;
battery-device-api/src/main/java/com/battery/device/model/HistoryPage.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/HistoryPage.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
import java.util.List;
battery-device-api/src/main/java/com/battery/device/model/HistorySample.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/HistorySample.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
import java.math.BigDecimal;
import java.time.Instant;
battery-device-api/src/main/java/com/battery/device/model/Measurement.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/Measurement.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
import java.math.BigDecimal;
battery-device-api/src/main/java/com/battery/device/model/RealtimeSnapshot.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/model/RealtimeSnapshot.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.model;
package com.battery.device.model;
import java.math.BigDecimal;
import java.time.Instant;
battery-device-api/src/main/java/com/battery/device/registry/AdapterInstanceConfig.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/registry/AdapterInstanceConfig.java
@@ -1,9 +1,9 @@
package com.ruoyi.device.registry;
package com.battery.device.registry;
import java.time.ZoneId;
import java.util.Locale;
import java.util.Objects;
import com.ruoyi.device.model.AdapterCapabilities;
import com.battery.device.model.AdapterCapabilities;
/** 设备适配器实例的运行时配置。 */
public record AdapterInstanceConfig(
battery-device-api/src/main/java/com/battery/device/registry/AdapterRegistryException.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/registry/AdapterRegistryException.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.registry;
package com.battery.device.registry;
/** 适配器运行时注册失败。 */
public final class AdapterRegistryException extends RuntimeException
battery-device-api/src/main/java/com/battery/device/registry/DeviceAdapterFactory.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/registry/DeviceAdapterFactory.java
@@ -1,6 +1,6 @@
package com.ruoyi.device.registry;
package com.battery.device.registry;
import com.ruoyi.device.api.DeviceAdapter;
import com.battery.device.api.DeviceAdapter;
/** 按适配器类型构造厂商协议实现。 */
public interface DeviceAdapterFactory
battery-device-api/src/main/java/com/battery/device/registry/DeviceAdapterRegistry.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/registry/DeviceAdapterRegistry.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.registry;
package com.battery.device.registry;
import java.util.HashMap;
import java.util.List;
@@ -7,7 +7,7 @@
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import com.ruoyi.device.api.DeviceAdapter;
import com.battery.device.api.DeviceAdapter;
/** 管理启用设备适配器的运行时实例及其会话生命周期。 */
public final class DeviceAdapterRegistry implements AutoCloseable
battery-device-api/src/test/java/com/battery/device/registry/DeviceAdapterRegistryTest.java
File was renamed from ruoyi-device/src/test/java/com/ruoyi/device/registry/DeviceAdapterRegistryTest.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.registry;
package com.battery.device.registry;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame;
@@ -14,10 +14,10 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.Test;
import com.ruoyi.device.api.DeviceAdapter;
import com.ruoyi.device.model.AdapterCapabilities;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DeviceControlCommand;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.model.AdapterCapabilities;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DeviceControlCommand;
class DeviceAdapterRegistryTest
{
@@ -201,27 +201,27 @@
        }
        @Override
        public List<com.ruoyi.device.model.DetectedChannel> discoverChannels()
        public List<com.battery.device.model.DetectedChannel> discoverChannels()
        {
            return List.of();
        }
        @Override
        public java.util.Map<ChannelIdentity, com.ruoyi.device.model.RealtimeSnapshot> inquire(
        public java.util.Map<ChannelIdentity, com.battery.device.model.RealtimeSnapshot> inquire(
                java.util.Set<ChannelIdentity> channels)
        {
            return java.util.Map.of();
        }
        @Override
        public List<com.ruoyi.device.model.HistoryAvailability> inquireHistory(
        public List<com.battery.device.model.HistoryAvailability> inquireHistory(
                java.util.Set<ChannelIdentity> channels)
        {
            return List.of();
        }
        @Override
        public com.ruoyi.device.model.HistoryPage downloadHistory(ChannelIdentity channel,
        public com.battery.device.model.HistoryPage downloadHistory(ChannelIdentity channel,
                String btsTestId, long startPosition, int limit)
        {
            throw new UnsupportedOperationException();
battery-device-bts/pom.xml
New file
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent><groupId>com.ruoyi</groupId><artifactId>ruoyi</artifactId><version>3.9.2</version></parent>
    <groupId>com.battery</groupId><artifactId>battery-device-bts</artifactId>
    <description>BTS 协议设备实现</description>
    <dependencies>
        <dependency><groupId>com.battery</groupId><artifactId>battery-device-api</artifactId></dependency>
        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
    </dependencies>
</project>
battery-device-bts/src/main/java/com/battery/device/bts/BtsDeviceAdapter.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsDeviceAdapter.java
@@ -1,16 +1,16 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.ruoyi.device.api.DeviceAdapter;
import com.ruoyi.device.model.AdapterCapabilities;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DetectedChannel;
import com.ruoyi.device.model.HistoryAvailability;
import com.ruoyi.device.model.HistoryPage;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.model.AdapterCapabilities;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DetectedChannel;
import com.battery.device.model.HistoryAvailability;
import com.battery.device.model.HistoryPage;
import com.battery.device.model.RealtimeSnapshot;
public final class BtsDeviceAdapter implements DeviceAdapter
{
battery-device-bts/src/main/java/com/battery/device/bts/BtsDeviceAdapterFactory.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsDeviceAdapterFactory.java
@@ -1,10 +1,10 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import java.time.Duration;
import java.time.ZoneId;
import com.ruoyi.device.api.DeviceAdapter;
import com.ruoyi.device.registry.AdapterInstanceConfig;
import com.ruoyi.device.registry.DeviceAdapterFactory;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.registry.AdapterInstanceConfig;
import com.battery.device.registry.DeviceAdapterFactory;
/** 根据数据库配置构造 BTS 只读适配器。 */
public final class BtsDeviceAdapterFactory implements DeviceAdapterFactory
battery-device-bts/src/main/java/com/battery/device/bts/BtsFrameReader.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsFrameReader.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
battery-device-bts/src/main/java/com/battery/device/bts/BtsProtocolException.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsProtocolException.java
@@ -1,6 +1,6 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import com.ruoyi.device.api.DeviceAdapterException;
import com.battery.device.api.DeviceAdapterException;
public class BtsProtocolException extends DeviceAdapterException
{
battery-device-bts/src/main/java/com/battery/device/bts/BtsTcpTransport.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsTcpTransport.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import java.io.EOFException;
import java.io.IOException;
battery-device-bts/src/main/java/com/battery/device/bts/BtsTransport.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsTransport.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
public interface BtsTransport extends AutoCloseable
{
battery-device-bts/src/main/java/com/battery/device/bts/BtsTransportException.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsTransportException.java
@@ -1,6 +1,6 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import com.ruoyi.device.api.DeviceAdapterException;
import com.battery.device.api.DeviceAdapterException;
/**
 * 表示可供调度与恢复逻辑分类处理的 BTS TCP 传输失败。
battery-device-bts/src/main/java/com/battery/device/bts/BtsXmlCodec.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsXmlCodec.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import java.io.StringReader;
import java.math.BigDecimal;
@@ -23,15 +23,15 @@
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DetectedChannel;
import com.ruoyi.device.model.DetectedDeviceMetadata;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.model.HistoryAvailability;
import com.ruoyi.device.model.HistoryPage;
import com.ruoyi.device.model.HistorySample;
import com.ruoyi.device.model.Measurement;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DetectedChannel;
import com.battery.device.model.DetectedDeviceMetadata;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.model.HistoryAvailability;
import com.battery.device.model.HistoryPage;
import com.battery.device.model.HistorySample;
import com.battery.device.model.Measurement;
import com.battery.device.model.RealtimeSnapshot;
public final class BtsXmlCodec
{
battery-device-bts/src/test/java/com/battery/device/bts/BtsDeviceAdapterContractTest.java
File was renamed from ruoyi-device/src/test/java/com/ruoyi/device/bts/BtsDeviceAdapterContractTest.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -8,10 +8,10 @@
import java.time.ZoneId;
import java.util.Set;
import org.junit.jupiter.api.Test;
import com.ruoyi.device.api.DeviceAdapter;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DeviceControlCommand;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DeviceControlCommand;
import com.battery.device.model.DeviceWorkStatus;
class BtsDeviceAdapterContractTest
{
battery-device-bts/src/test/java/com/battery/device/bts/BtsDeviceAdapterFactoryContractTest.java
File was renamed from ruoyi-device/src/test/java/com/ruoyi/device/registry/BtsDeviceAdapterFactoryContractTest.java
@@ -1,13 +1,15 @@
package com.ruoyi.device.registry;
package com.battery.device.bts;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.List;
import org.junit.jupiter.api.Test;
import com.ruoyi.device.bts.BtsDeviceAdapterFactory;
import com.ruoyi.device.bts.ScriptedBtsTcpSimulator;
import com.ruoyi.device.model.AdapterCapabilities;
import com.battery.device.bts.BtsDeviceAdapterFactory;
import com.battery.device.bts.ScriptedBtsTcpSimulator;
import com.battery.device.model.AdapterCapabilities;
import com.battery.device.registry.AdapterInstanceConfig;
import com.battery.device.registry.DeviceAdapterRegistry;
class BtsDeviceAdapterFactoryContractTest
{
battery-device-bts/src/test/java/com/battery/device/bts/BtsTcpTransportTest.java
File was renamed from ruoyi-device/src/test/java/com/ruoyi/device/bts/BtsTcpTransportTest.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
battery-device-bts/src/test/java/com/battery/device/bts/BtsXmlCodecTest.java
File was renamed from ruoyi-device/src/test/java/com/ruoyi/device/bts/BtsXmlCodecTest.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -11,11 +11,11 @@
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.model.HistoryPage;
import com.ruoyi.device.model.HistoryAvailability;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.model.HistoryPage;
import com.battery.device.model.HistoryAvailability;
import com.battery.device.model.RealtimeSnapshot;
class BtsXmlCodecTest
{
battery-device-bts/src/test/java/com/battery/device/bts/ScriptedBtsTcpSimulator.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/ScriptedBtsTcpSimulator.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.bts;
import java.io.IOException;
import java.io.InputStream;
battery-device-simulator/pom.xml
New file
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent><groupId>com.ruoyi</groupId><artifactId>ruoyi</artifactId><version>3.9.2</version></parent>
    <groupId>com.battery</groupId><artifactId>battery-device-simulator</artifactId>
    <description>开发设备模拟器实现</description>
    <dependencies>
        <dependency><groupId>com.battery</groupId><artifactId>battery-device-api</artifactId></dependency>
        <!-- 仅测试复用协议客户端验证模拟器边界,生产依赖方向仍保持单向。 -->
        <dependency><groupId>com.battery</groupId><artifactId>battery-device-bts</artifactId><scope>test</scope></dependency>
        <dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><scope>test</scope></dependency>
        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
    </dependencies>
</project>
battery-device-simulator/src/main/java/com/battery/device/simulator/BtsDevelopmentSimulator.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsDevelopmentSimulator.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.simulator;
import java.io.IOException;
import java.io.StringReader;
@@ -11,28 +11,28 @@
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.simulator.BtsSimulatorStateStore;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.ChannelState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.ChannelTombstone;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorChannelState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorRealtimeMeasurement;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.DeviceState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsDeviceProfile;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsPlaybackState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.RecentRequest;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.SimulatorState;
import com.ruoyi.device.simulator.InMemoryBtsSimulatorStateStore;
import com.ruoyi.device.simulator.DevelopmentCollectorSimulation;
import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorAdvance;
import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorHistoryPage;
import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.simulator.BtsSimulatorStateStore;
import com.battery.device.simulator.BtsSimulatorStateStore.ChannelState;
import com.battery.device.simulator.BtsSimulatorStateStore.ChannelTombstone;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorChannelState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorRealtimeMeasurement;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorState;
import com.battery.device.simulator.BtsSimulatorStateStore.DeviceState;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsDeviceProfile;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsPlaybackState;
import com.battery.device.simulator.BtsSimulatorStateStore.RecentRequest;
import com.battery.device.simulator.BtsSimulatorStateStore.SimulatorState;
import com.battery.device.simulator.InMemoryBtsSimulatorStateStore;
import com.battery.device.simulator.DevelopmentCollectorSimulation;
import com.battery.device.simulator.DevelopmentCollectorSimulation.CollectorAdvance;
import com.battery.device.simulator.DevelopmentCollectorSimulation.CollectorHistoryPage;
import com.battery.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
/** 提供由开发后端托管的临时只读 BTS 模拟端点。 */
public final class BtsDevelopmentSimulator implements AutoCloseable
battery-device-simulator/src/main/java/com/battery/device/simulator/BtsExcelFixture.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsExcelFixture.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.simulator;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
battery-device-simulator/src/main/java/com/battery/device/simulator/BtsSimulatorStateStore.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/simulator/BtsSimulatorStateStore.java
@@ -1,9 +1,9 @@
package com.ruoyi.device.simulator;
package com.battery.device.simulator;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.List;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.battery.device.model.DeviceWorkStatus;
/** 持久化开发模拟器配置;实现必须在返回前确认写入成功。 */
public interface BtsSimulatorStateStore
battery-device-simulator/src/main/java/com/battery/device/simulator/DevelopmentCollectorSimulation.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/simulator/DevelopmentCollectorSimulation.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.simulator;
package com.battery.device.simulator;
import java.math.BigDecimal;
import java.time.Instant;
@@ -12,12 +12,12 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorChannelState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorRealtimeMeasurement;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorChannelState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorRealtimeMeasurement;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorState;
/** 实现第一版开发采集器的独立采样与故障注入合同。 */
public final class DevelopmentCollectorSimulation
battery-device-simulator/src/main/java/com/battery/device/simulator/InMemoryBtsSimulatorStateStore.java
File was renamed from ruoyi-device/src/main/java/com/ruoyi/device/simulator/InMemoryBtsSimulatorStateStore.java
@@ -1,17 +1,17 @@
package com.ruoyi.device.simulator;
package com.battery.device.simulator;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryBatch;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsHistoryBatch;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.RecentRequest;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.SimulatorState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsPlaybackState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryBatch;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsHistoryBatch;
import com.battery.device.simulator.BtsSimulatorStateStore.RecentRequest;
import com.battery.device.simulator.BtsSimulatorStateStore.SimulatorState;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsPlaybackState;
/** 测试和独立协议合同使用的内存状态存储。 */
public final class InMemoryBtsSimulatorStateStore implements BtsSimulatorStateStore
battery-device-simulator/src/main/java/com/battery/device/simulator/ScriptedBtsTcpSimulator.java
copy from ruoyi-device/src/main/java/com/ruoyi/device/bts/ScriptedBtsTcpSimulator.java copy to battery-device-simulator/src/main/java/com/battery/device/simulator/ScriptedBtsTcpSimulator.java
File was copied from ruoyi-device/src/main/java/com/ruoyi/device/bts/ScriptedBtsTcpSimulator.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.bts;
package com.battery.device.simulator;
import java.io.IOException;
import java.io.InputStream;
@@ -134,7 +134,36 @@
    private String readFrame(InputStream input) throws IOException
    {
        return new String(BtsFrameReader.read(input, Integer.MAX_VALUE), StandardCharsets.UTF_8);
        return new String(readFrameBytes(input), StandardCharsets.UTF_8);
    }
    private byte[] readFrameBytes(InputStream input) throws IOException
    {
        java.io.ByteArrayOutputStream bytes = new java.io.ByteArrayOutputStream();
        byte[] delimiter = FRAME_END;
        int matched = 0;
        while (true)
        {
            int current = input.read();
            if (current < 0) throw new java.io.EOFException("BTS frame ended before delimiter");
            if ((byte) current == delimiter[matched])
            {
                matched++;
                if (matched == delimiter.length) return bytes.toByteArray();
                continue;
            }
            if (matched > 0)
            {
                for (int i = 0; i < matched; i++) bytes.write(delimiter[i]);
                matched = 0;
                if ((byte) current == delimiter[0])
                {
                    matched = 1;
                    continue;
                }
            }
            bytes.write(current);
        }
    }
    @Override
battery-device-simulator/src/test/java/com/battery/device/contract/DiscoveryCandidateStoreContractTest.java
File was renamed from ruoyi-device/src/test/java/com/ruoyi/device/contract/DiscoveryCandidateStoreContractTest.java
@@ -1,15 +1,15 @@
package com.ruoyi.device.contract;
package com.battery.device.contract;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.time.Instant;
import java.util.List;
import org.junit.jupiter.api.Test;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
import com.ruoyi.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
import com.battery.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DeviceWorkStatus;
class DiscoveryCandidateStoreContractTest
{
battery-device-simulator/src/test/java/com/battery/device/contract/SimulatorPublicContractTest.java
File was renamed from ruoyi-device/src/test/java/com/ruoyi/device/contract/SimulatorPublicContractTest.java
@@ -1,4 +1,4 @@
package com.ruoyi.device.contract;
package com.battery.device.contract;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
@@ -13,27 +13,27 @@
import java.util.Set;
import org.junit.jupiter.api.Test;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.device.api.DeviceAdapter;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.bts.BtsDeviceAdapter;
import com.ruoyi.device.bts.BtsXmlCodec;
import com.ruoyi.device.bts.BtsTcpTransport;
import com.ruoyi.device.bts.ScriptedBtsTcpSimulator;
import com.ruoyi.device.model.DetectedChannel;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.simulator.BtsSimulatorStateStore;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.ChannelState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorChannelState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryBatch;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.DeviceState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.SimulatorState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.RecentRequest;
import com.ruoyi.device.simulator.InMemoryBtsSimulatorStateStore;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.bts.BtsDeviceAdapter;
import com.battery.device.bts.BtsXmlCodec;
import com.battery.device.bts.BtsTcpTransport;
import com.battery.device.simulator.ScriptedBtsTcpSimulator;
import com.battery.device.model.DetectedChannel;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.simulator.BtsSimulatorStateStore;
import com.battery.device.simulator.BtsSimulatorStateStore.ChannelState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorChannelState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryBatch;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorState;
import com.battery.device.simulator.BtsSimulatorStateStore.DeviceState;
import com.battery.device.simulator.BtsSimulatorStateStore.SimulatorState;
import com.battery.device.simulator.BtsSimulatorStateStore.RecentRequest;
import com.battery.device.simulator.InMemoryBtsSimulatorStateStore;
class SimulatorPublicContractTest
{
@@ -81,7 +81,7 @@
            var first = simulator.collectorHistory(1, 0, 17);
            var second = simulator.collectorHistory(1, first.nextOffset(), 1000);
            List<com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord> records =
            List<com.battery.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord> records =
                    new java.util.ArrayList<>(first.records());
            records.addAll(second.records());
@@ -291,7 +291,7 @@
            assertEquals(1, firstDiscovery.stream().map(channel -> channel.identity().devid()).distinct().count());
            assertEquals(4, firstDiscovery.stream().filter(channel -> channel.available()).count());
            Set<com.ruoyi.device.model.ChannelIdentity> channels = firstDiscovery.stream()
            Set<com.battery.device.model.ChannelIdentity> channels = firstDiscovery.stream()
                    .map(channel -> channel.identity())
                    .collect(java.util.stream.Collectors.toSet());
            var firstObservation = adapter.inquire(channels);
@@ -330,7 +330,7 @@
                    .filter(device -> device.deviceId() == tDevice || device.deviceId() == tnDevice)
                    .mapToInt(device -> device.channels().size()).sum() / 2);
            Set<com.ruoyi.device.model.ChannelIdentity> channel = tChannels.stream()
            Set<com.battery.device.model.ChannelIdentity> channel = tChannels.stream()
                    .map(DetectedChannel::identity).filter(identity -> identity.chlid() == 1)
                    .collect(java.util.stream.Collectors.toSet());
            var first = adapter.inquire(channel).values().iterator().next();
@@ -377,7 +377,7 @@
            simulator.updateChannel(1, 2, false, DeviceWorkStatus.PAUSED);
            var discovered = adapter.discoverChannels();
            Set<com.ruoyi.device.model.ChannelIdentity> available = discovered.stream()
            Set<com.battery.device.model.ChannelIdentity> available = discovered.stream()
                    .filter(channel -> channel.available())
                    .map(channel -> channel.identity())
                    .collect(java.util.stream.Collectors.toSet());
battery-device-simulator/src/test/java/com/battery/device/simulator/BtsDevelopmentSimulatorHistoryContractTest.java
File was renamed from ruoyi-device/src/test/java/com/ruoyi/device/bts/BtsDevelopmentSimulatorHistoryContractTest.java
@@ -1,12 +1,15 @@
package com.ruoyi.device.bts;
package com.battery.device.simulator;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import java.time.Duration;
import java.time.ZoneId;
import org.junit.jupiter.api.Test;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.simulator.InMemoryBtsSimulatorStateStore;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.bts.BtsDeviceAdapter;
import com.battery.device.bts.BtsTcpTransport;
import com.battery.device.bts.BtsXmlCodec;
import com.battery.device.simulator.InMemoryBtsSimulatorStateStore;
/** Ticket13:开发检测柜历史合同与实时快照保持两条独立路径。 */
class BtsDevelopmentSimulatorHistoryContractTest
battery-device-simulator/src/test/java/com/battery/device/simulator/BtsDevelopmentSimulatorRecordStepCycleTest.java
File was renamed from ruoyi-device/src/test/java/com/ruoyi/device/bts/BtsDevelopmentSimulatorRecordStepCycleTest.java
@@ -1,13 +1,16 @@
package com.ruoyi.device.bts;
package com.battery.device.simulator;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.time.Instant;
import org.junit.jupiter.api.Test;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsPlaybackState;
import com.ruoyi.device.simulator.InMemoryBtsSimulatorStateStore;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.bts.BtsDeviceAdapter;
import com.battery.device.bts.BtsTcpTransport;
import com.battery.device.bts.BtsXmlCodec;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsPlaybackState;
import com.battery.device.simulator.InMemoryBtsSimulatorStateStore;
/** Ticket21:检测柜 record、step、cycle 生命周期和播放控制合同。 */
class BtsDevelopmentSimulatorRecordStepCycleTest
pom.xml
@@ -164,10 +164,24 @@
                <version>${ruoyi.version}</version>
            </dependency>
            <!-- 设备适配模块 -->
            <dependency>
                <groupId>com.ruoyi</groupId>
                <artifactId>ruoyi-device</artifactId>
                <groupId>com.battery</groupId>
                <artifactId>battery-business</artifactId>
                <version>${ruoyi.version}</version>
            </dependency>
            <dependency>
                <groupId>com.battery</groupId>
                <artifactId>battery-device-api</artifactId>
                <version>${ruoyi.version}</version>
            </dependency>
            <dependency>
                <groupId>com.battery</groupId>
                <artifactId>battery-device-bts</artifactId>
                <version>${ruoyi.version}</version>
            </dependency>
            <dependency>
                <groupId>com.battery</groupId>
                <artifactId>battery-device-simulator</artifactId>
                <version>${ruoyi.version}</version>
            </dependency>
@@ -185,7 +199,10 @@
        <module>ruoyi-admin</module>
        <module>ruoyi-framework</module>
        <module>ruoyi-system</module>
        <module>ruoyi-device</module>
        <module>battery-business</module>
        <module>battery-device-api</module>
        <module>battery-device-bts</module>
        <module>battery-device-simulator</module>
        <module>ruoyi-quartz</module>
        <module>ruoyi-generator</module>
        <module>ruoyi-common</module>
ruoyi-admin/pom.xml
@@ -61,10 +61,22 @@
            <artifactId>ruoyi-framework</artifactId>
        </dependency>
        <!-- 设备适配模块 -->
        <!-- 自研业务与设备模块 -->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-device</artifactId>
            <groupId>com.battery</groupId>
            <artifactId>battery-business</artifactId>
        </dependency>
        <dependency>
            <groupId>com.battery</groupId>
            <artifactId>battery-device-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.battery</groupId>
            <artifactId>battery-device-bts</artifactId>
        </dependency>
        <dependency>
            <groupId>com.battery</groupId>
            <artifactId>battery-device-simulator</artifactId>
        </dependency>
        <!-- 定时任务-->
ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorDiscoveryService.java
@@ -4,7 +4,7 @@
import java.util.Set;
import java.time.Instant;
import org.springframework.stereotype.Service;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.system.domain.vo.DiscoveredCollectorVo;
import com.ruoyi.system.service.ICollectorDiscoveryService;
import com.ruoyi.system.service.ITCollectorService;
ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorSamplingScheduler.java
@@ -4,7 +4,7 @@
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Profile;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.battery.device.simulator.BtsDevelopmentSimulator;
/** 按各采集器配置频率推进开发模拟测量,不参与正式测试数据持久化。 */
@Component
ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizer.java
@@ -6,13 +6,15 @@
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
import org.springframework.context.annotation.Profile;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
import com.ruoyi.system.mapper.TCollectorMapper;
/** 将模拟采集器的发现写入 Redis,并同步已登记采集器的实时在线事实。 */
@Component
@Profile("dev-simulator")
public class DevelopmentCollectorStatusSynchronizer
{
    private final BtsDevelopmentSimulator simulator;
ruoyi-admin/src/main/java/com/ruoyi/config/DevelopmentSimulatorDiscoveryScheduler.java
@@ -3,8 +3,8 @@
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Profile;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.registry.DeviceAdapterRegistry;
import com.ruoyi.system.service.impl.DeviceDiscoveryPersistenceService;
import com.ruoyi.system.service.impl.DeviceDiscoveryPersistenceService.DiscoverySource;
ruoyi-admin/src/main/java/com/ruoyi/config/DeviceAdapterRuntimeConfig.java
@@ -6,13 +6,15 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.EnableScheduling;
import com.ruoyi.device.bts.BtsDeviceAdapterFactory;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.model.AdapterCapabilities;
import com.ruoyi.device.registry.AdapterInstanceConfig;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
import com.ruoyi.device.simulator.BtsSimulatorStateStore;
import com.battery.device.api.NoopDeviceAdapterFactory;
import com.battery.device.bts.BtsDeviceAdapterFactory;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.model.AdapterCapabilities;
import com.battery.device.registry.AdapterInstanceConfig;
import com.battery.device.registry.DeviceAdapterRegistry;
import com.battery.device.simulator.BtsSimulatorStateStore;
/** 装配单进程设备适配器运行时。 */
@Configuration
@@ -20,12 +22,21 @@
public class DeviceAdapterRuntimeConfig
{
    @Bean(destroyMethod = "close")
    @Profile("!dev-simulator & !bts")
    public DeviceAdapterRegistry noopDeviceAdapterRegistry()
    {
        return new DeviceAdapterRegistry(List.of(new NoopDeviceAdapterFactory()));
    }
    @Bean(destroyMethod = "close")
    @Profile({ "dev-simulator", "bts" })
    public DeviceAdapterRegistry deviceAdapterRegistry()
    {
        return new DeviceAdapterRegistry(List.of(new BtsDeviceAdapterFactory()));
    }
    @Bean(destroyMethod = "close")
    @Profile("dev-simulator")
    public BtsDevelopmentSimulator btsDevelopmentSimulator(BtsSimulatorStateStore stateStore,
            @Value("${battery.dev-simulator.port:15020}") int simulatorPort) throws IOException
    {
@@ -33,6 +44,7 @@
    }
    @Bean
    @Profile("dev-simulator")
    public ApplicationRunner registerDevelopmentSimulatorAdapter(DeviceAdapterRegistry registry,
            @Value("${battery.dev-simulator.port:15020}") int simulatorPort)
    {
ruoyi-admin/src/main/java/com/ruoyi/config/RedisBtsSimulatorStateStore.java
@@ -10,18 +10,20 @@
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Profile;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.device.simulator.BtsSimulatorStateStore;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsDeviceProfile;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsHistoryBatch;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsPlaybackState;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.battery.device.simulator.BtsSimulatorStateStore;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsDeviceProfile;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsHistoryBatch;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsPlaybackState;
import com.battery.device.model.DeviceWorkStatus;
/** 将开发模拟器完整状态写入 Redis,主状态不设置普通 TTL。 */
@Component
@Profile("dev-simulator")
public class RedisBtsSimulatorStateStore implements BtsSimulatorStateStore
{
    static final String STATE_KEY = "dev:bts-simulator:state:v1";
ruoyi-admin/src/main/java/com/ruoyi/config/RedisDeviceDiscoveryCandidateStore.java
@@ -10,10 +10,10 @@
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.model.RealtimeSnapshot;
/** 保存发现候选和实时状态;条目按 expiresAt 逻辑过期,Redis key 本身不设短 TTL。 */
@Component
ruoyi-admin/src/main/java/com/ruoyi/web/controller/device/BtsDevelopmentSimulatorController.java
@@ -16,20 +16,22 @@
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.bts.BtsDevelopmentSimulator.StateSnapshot;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorHistoryPage;
import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
import com.ruoyi.device.bts.BtsDevelopmentSimulator.PlaybackSnapshot;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.simulator.BtsDevelopmentSimulator.StateSnapshot;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
import com.battery.device.simulator.DevelopmentCollectorSimulation.CollectorHistoryPage;
import com.battery.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
import com.battery.device.simulator.BtsDevelopmentSimulator.PlaybackSnapshot;
/** 本机临时 BTS 模拟器控制 API。 */
@Anonymous
@RestController
@Profile("dev-simulator")
public class BtsDevelopmentSimulatorController
{
    private final BtsDevelopmentSimulator simulator;
@@ -275,7 +277,7 @@
    }
    @GetMapping("/dev/bts-simulator/devices/{deviceId}/channels/{channelId}/records")
    public List<com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord> btsRecords(
    public List<com.battery.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord> btsRecords(
            @PathVariable int deviceId, @PathVariable int channelId)
    {
        try { return simulator.btsRecords(deviceId, channelId); }
ruoyi-admin/src/main/resources/application.yml
@@ -60,8 +60,8 @@
    # 国际化资源文件路径
    basename: i18n/messages
  profiles:
    # 仓库默认启动用于本机联调;真实设备部署必须覆盖并移除 dev-simulator。
    active: druid,dev-simulator
    # 默认不连接任何设备;本机演示时显式追加 dev-simulator。
    active: druid
  # 文件上传
  servlet:
    multipart:
ruoyi-admin/src/test/java/com/ruoyi/config/DevelopmentCollectorStatusSynchronizerTest.java
@@ -4,8 +4,8 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.springframework.beans.factory.annotation.Autowired;
import org.junit.jupiter.api.Test;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.ruoyi.system.mapper.TCollectorMapper;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
ruoyi-admin/src/test/java/com/ruoyi/config/DevelopmentSimulatorProfileContractTest.java
@@ -10,11 +10,11 @@
class DevelopmentSimulatorProfileContractTest
{
    @Test
    void enablesSimulatorSchedulingForDefaultDevelopmentStartup() throws Exception
    void usesNoDeviceProfileByDefault() throws Exception
    {
        var sources = new YamlPropertySourceLoader().load("application", new ClassPathResource("application.yml"));
        Object profiles = sources.get(0).getProperty("spring.profiles.active");
        assertEquals(List.of("druid", "dev-simulator"), List.of(String.valueOf(profiles).split(",")));
        assertEquals(List.of("druid"), List.of(String.valueOf(profiles).split(",")));
    }
}
ruoyi-admin/src/test/java/com/ruoyi/config/DeviceAdapterRuntimeConfigTest.java
@@ -6,8 +6,8 @@
import org.junit.jupiter.api.Test;
import org.springframework.boot.DefaultApplicationArguments;
import org.mockito.ArgumentCaptor;
import com.ruoyi.device.registry.AdapterInstanceConfig;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
import com.battery.device.registry.AdapterInstanceConfig;
import com.battery.device.registry.DeviceAdapterRegistry;
class DeviceAdapterRuntimeConfigTest
{
ruoyi-admin/src/test/java/com/ruoyi/config/DeviceAdapterRuntimeNoopStartupTest.java
New file
@@ -0,0 +1,28 @@
package com.ruoyi.config;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertFalse;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.battery.device.api.NoopDeviceAdapter;
import com.battery.device.registry.DeviceAdapterRegistry;
class DeviceAdapterRuntimeNoopStartupTest
{
    @Test
    void startsWithoutDeviceProfileUsingNoopRegistry()
    {
        try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext())
        {
            context.register(DeviceAdapterRuntimeConfig.class);
            context.refresh();
            DeviceAdapterRegistry registry = context.getBean(DeviceAdapterRegistry.class);
            assertFalse(registry.contains("dev-sim"));
            registry.synchronize(new com.battery.device.registry.AdapterInstanceConfig(
                    "noop-check", "NOOP", "127.0.0.1", 1, 1000, "Asia/Hong_Kong",
                    true, new com.battery.device.model.AdapterCapabilities(true, true, false, false)));
            var adapter = registry.execute("noop-check", value -> value);
            assertInstanceOf(NoopDeviceAdapter.class, adapter);
        }
    }
}
ruoyi-admin/src/test/java/com/ruoyi/config/RedisStateStoreTest.java
@@ -23,17 +23,17 @@
import org.springframework.data.redis.core.ValueOperations;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.ChannelState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.ChannelTombstone;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.DeviceState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.SimulatorState;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
import com.ruoyi.device.model.ChannelIdentity;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.simulator.BtsSimulatorStateStore.ChannelState;
import com.battery.device.simulator.BtsSimulatorStateStore.ChannelTombstone;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorState;
import com.battery.device.simulator.BtsSimulatorStateStore.DeviceState;
import com.battery.device.simulator.BtsSimulatorStateStore.SimulatorState;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
import com.battery.device.model.ChannelIdentity;
import com.ruoyi.framework.config.FastJson2JsonRedisSerializer;
class RedisStateStoreTest
@@ -173,13 +173,13 @@
        RedisBtsSimulatorStateStore store = store(stored);
        SimulatorState current = state(1, "127.0.0.2");
        store.loadOrInitialize(current);
        var record = new com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord(
        var record = new com.battery.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord(
                "dev-sim", "dev-sim-collector-1", "S-01", 1L,
                java.time.Instant.parse("2026-08-29T05:00:00Z"), "2026-08-29 13:00:00.000",
                java.time.Instant.parse("2026-08-29T05:00:00Z"), "temperature",
                new java.math.BigDecimal("25.1"), "℃");
        store.save(current, List.of(
                new com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend(
                new com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend(
                        "dev-sim-collector-1", List.of(record))));
        SimulatorState next = state(7, "127.0.0.9");
@@ -198,13 +198,13 @@
        RedisBtsSimulatorStateStore store = new RedisBtsSimulatorStateStore(redis);
        SimulatorState current = state(1, "127.0.0.2");
        store.loadOrInitialize(current);
        var record = new com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord(
        var record = new com.battery.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord(
                "dev-sim", "dev-sim-collector-1", "S-01", 1L,
                java.time.Instant.parse("2026-08-29T05:00:00Z"), "2026-08-29 13:00:00.000",
                java.time.Instant.parse("2026-08-29T05:00:00Z"), "temperature",
                new java.math.BigDecimal("25.1"), "℃");
        store.save(current, List.of(
                new com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend(
                new com.battery.device.simulator.BtsSimulatorStateStore.CollectorHistoryAppend(
                        "dev-sim-collector-1", java.util.Collections.nCopies(1010, record))));
        ListOperations<Object, Object> lists = redis.opsForList();
        clearInvocations(lists);
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/CollectorDiscoveryServiceImplTest.java
@@ -8,8 +8,8 @@
import org.junit.jupiter.api.Test;
import com.ruoyi.config.DevelopmentCollectorDiscoveryService;
import com.ruoyi.config.DevelopmentCollectorStatusSynchronizer;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.ruoyi.system.domain.vo.DiscoveredCollectorVo;
import com.ruoyi.system.mapper.TCollectorMapper;
import com.ruoyi.system.service.ITCollectorService;
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImplTest.java
@@ -25,16 +25,16 @@
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.device.api.DeviceAdapter;
import com.ruoyi.device.api.DeviceAdapterException;
import com.ruoyi.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DetectedChannel;
import com.ruoyi.device.model.DetectedDeviceMetadata;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.api.DeviceAdapterException;
import com.battery.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DetectedChannel;
import com.battery.device.model.DetectedDeviceMetadata;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.model.RealtimeSnapshot;
import com.battery.device.registry.DeviceAdapterRegistry;
import com.ruoyi.system.domain.TDetectionCabinet;
import com.ruoyi.system.domain.TDetectionChannel;
import com.ruoyi.system.domain.TDeviceAdapter;
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/DeviceDiscoveryPersistenceServiceTest.java
@@ -9,11 +9,11 @@
import java.util.function.Function;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import com.ruoyi.device.api.DeviceAdapter;
import com.ruoyi.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DetectedChannel;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DetectedChannel;
import com.battery.device.registry.DeviceAdapterRegistry;
import com.ruoyi.system.mapper.TDetectionCabinetMapper;
import com.ruoyi.system.mapper.TTestMapper;
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TCollectorServiceImplTest.java
@@ -25,8 +25,8 @@
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.domain.TCollector;
import com.ruoyi.system.mapper.TCollectorMapper;
import com.ruoyi.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
import com.battery.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
/**
 * 采集器 Service 单元测试。
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TDetectionCabinetServiceImplTest.java
@@ -28,11 +28,11 @@
import com.ruoyi.system.domain.TDetectionCabinet;
import com.ruoyi.system.domain.vo.DiscoveredCabinetVo;
import com.ruoyi.system.mapper.TDetectionCabinetMapper;
import com.ruoyi.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.battery.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DeviceWorkStatus;
/**
 * 检测柜业务层单元测试,验证字段规范化、状态限制及唯一性校验等关键规则。
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestLiveServiceImplTest.java
@@ -19,11 +19,11 @@
import org.junit.jupiter.api.Test;
import org.springframework.web.context.request.async.AsyncRequestNotUsableException;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.model.RealtimeSnapshot;
import com.ruoyi.system.domain.TTest;
import com.ruoyi.system.domain.TTestBattery;
import com.ruoyi.system.domain.TTestChannelBinding;
ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TestDataReceptionServiceImplTest.java
@@ -16,10 +16,10 @@
import java.util.List;
import java.math.BigDecimal;
import org.junit.jupiter.api.Test;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorRealtimeMeasurement;
import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorRealtimeMeasurement;
import com.battery.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
import com.ruoyi.system.domain.TTestCollectorChannel;
import com.ruoyi.system.domain.TTest;
import com.ruoyi.system.domain.TTestBattery;
ruoyi-admin/src/test/java/com/ruoyi/web/controller/device/BtsDevelopmentSimulatorControllerTest.java
@@ -18,12 +18,12 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.server.ResponseStatusException;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.ruoyi.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.battery.device.discovery.InMemoryDeviceDiscoveryCandidateStore;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DeviceWorkStatus;
import com.ruoyi.web.config.BtsDevelopmentSimulatorWebConfig;
import com.ruoyi.config.DevelopmentCollectorStatusSynchronizer;
ruoyi-device/pom.xml
File was deleted
ruoyi-system/pom.xml
@@ -19,8 +19,12 @@
        <!-- 厂商无关设备适配契约 -->
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-device</artifactId>
            <groupId>com.battery</groupId>
            <artifactId>battery-device-api</artifactId>
        </dependency>
        <dependency>
            <groupId>com.battery</groupId>
            <artifactId>battery-device-simulator</artifactId>
        </dependency>
        <!-- 通用工具-->
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceAdapterRuntimeCoordinator.java
@@ -2,12 +2,14 @@
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.ruoyi.system.service.IDeviceAdapterService;
/** 在单采集进程内恢复启用实例,并按各自周期执行只读发现。 */
@Component
@Profile({ "dev-simulator", "bts" })
public class DeviceAdapterRuntimeCoordinator
{
    private final IDeviceAdapterService service;
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImpl.java
@@ -11,13 +11,13 @@
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.device.api.DeviceAdapterException;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.model.AdapterCapabilities;
import com.ruoyi.device.registry.AdapterInstanceConfig;
import com.ruoyi.device.registry.AdapterRegistryException;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
import com.battery.device.api.DeviceAdapterException;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.model.AdapterCapabilities;
import com.battery.device.registry.AdapterInstanceConfig;
import com.battery.device.registry.AdapterRegistryException;
import com.battery.device.registry.DeviceAdapterRegistry;
import com.ruoyi.system.domain.TDetectionChannel;
import com.ruoyi.system.domain.TDeviceAdapter;
import com.ruoyi.system.domain.vo.AdapterDiscoveryResult;
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceDiscoveryPersistenceService.java
@@ -7,15 +7,15 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DetectedChannel;
import com.ruoyi.device.model.DetectedDeviceMetadata;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DetectedChannel;
import com.battery.device.model.DetectedDeviceMetadata;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.model.RealtimeSnapshot;
import com.battery.device.registry.DeviceAdapterRegistry;
import com.ruoyi.system.domain.TDetectionChannel;
import com.ruoyi.system.domain.vo.AdapterDiscoveryResult;
import com.ruoyi.system.mapper.TDetectionCabinetMapper;
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TCollectorServiceImpl.java
@@ -14,8 +14,8 @@
import com.ruoyi.system.domain.TCollector;
import com.ruoyi.system.mapper.TCollectorMapper;
import com.ruoyi.system.service.ITCollectorService;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CollectorCandidate;
/**
 * 采集器 Service 实现。
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TDetectionCabinetServiceImpl.java
@@ -19,9 +19,9 @@
import com.ruoyi.system.domain.vo.DiscoveredCabinetVo;
import com.ruoyi.system.mapper.TDetectionCabinetMapper;
import com.ruoyi.system.service.ITDetectionCabinetService;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.ruoyi.device.model.DeviceWorkStatus;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.battery.device.model.DeviceWorkStatus;
/**
 * 检测柜 Service 业务层处理
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TTestLiveServiceImpl.java
@@ -14,13 +14,14 @@
import jakarta.annotation.PreDestroy;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.bts.BtsDevelopmentSimulator.CollectorSnapshot;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.ruoyi.device.model.Measurement;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.simulator.BtsDevelopmentSimulator.CollectorSnapshot;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.CabinetCandidate;
import com.battery.device.discovery.DeviceDiscoveryCandidateStore.ChannelCandidate;
import com.battery.device.model.Measurement;
import com.ruoyi.system.domain.TTest;
import com.ruoyi.system.domain.TTestBattery;
import com.ruoyi.system.service.ITestLiveService;
@@ -41,7 +42,7 @@
    @Autowired
    public TTestLiveServiceImpl(ITTestService tests, DeviceDiscoveryCandidateStore candidates,
            BtsDevelopmentSimulator simulator, TTestMapper mapper)
            @Nullable BtsDevelopmentSimulator simulator, TTestMapper mapper)
    { this.tests = tests; this.candidates = candidates; this.simulator = simulator; this.mapper = mapper; }
    public TTestLiveServiceImpl(ITTestService tests, DeviceDiscoveryCandidateStore candidates,
@@ -82,6 +83,7 @@
    private TestPlanSnapshot detectorTestPlan(TTest test)
    {
        if (simulator == null) return null;
        if (test.getBatteries() == null) return null;
        for (TTestBattery battery : test.getBatteries())
        {
@@ -206,6 +208,8 @@
    private LiveSource collectorSource(TTestBattery battery)
    {
        if (simulator == null) return new LiveSource("COLLECTOR", battery.getCollectorId(), battery.getBatteryNo(),
                "OFFLINE", Map.of());
        for (CollectorSnapshot collector : simulator.snapshot().collectors()) if (collector.collectorId() == battery.getCollectorId())
        {
            Map<String, Object> value = new LinkedHashMap<>();
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataReceptionServiceImpl.java
@@ -12,11 +12,12 @@
import com.alibaba.fastjson2.JSON;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorRealtimeMeasurement;
import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
import com.battery.device.simulator.BtsDevelopmentSimulator;
import com.battery.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.battery.device.simulator.BtsSimulatorStateStore.CollectorRealtimeMeasurement;
import com.battery.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
import com.ruoyi.system.domain.TTest;
import com.ruoyi.system.domain.TTestBattery;
import com.ruoyi.system.domain.TTestChannelBinding;
@@ -36,7 +37,7 @@
    private final Map<Long, Instant> lastRawCaptureAt = new java.util.concurrent.ConcurrentHashMap<>();
    @Autowired
    public TestDataReceptionServiceImpl(TTestMapper mapper, ITTestService tests, BtsDevelopmentSimulator simulator,
    public TestDataReceptionServiceImpl(TTestMapper mapper, ITTestService tests, @Nullable BtsDevelopmentSimulator simulator,
            TestWarningExceptionService warningExceptions)
    {
        this.mapper = mapper;
@@ -53,6 +54,7 @@
    @Transactional(rollbackFor = Exception.class)
    public void captureDevelopmentRealtimeSnapshots()
    {
        if (simulator == null) return;
        List<Long> testIds = mapper.selectReceivingTestIds();
        if (testIds == null) return;
        Date now = new Date();
@@ -134,6 +136,7 @@
    @Transactional(rollbackFor = Exception.class)
    public void captureDevelopmentCabinetRecords()
    {
        if (simulator == null) return;
        List<Long> testIds = mapper.selectReceivingTestIds();
        if (testIds == null) return;
        for (Long testId : testIds)
@@ -151,6 +154,7 @@
    @Transactional(rollbackFor = Exception.class)
    public void captureDevelopmentCollectorMeasurements()
    {
        if (simulator == null) return;
        List<Long> testIds = mapper.selectReceivingTestIds();
        if (testIds == null) return;
        for (Long testId : testIds)