业务调整

This commit is contained in:
andy 2025-12-29 14:17:59 +08:00
parent c422c4435e
commit 6e3449a3bc
36 changed files with 1497 additions and 281 deletions

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -4,7 +4,35 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="ec76006e-5a88-4766-9722-bc8eda172857" name="Changes" comment="" />
<list default="true" id="ec76006e-5a88-4766-9722-bc8eda172857" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttConfigOld.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/mongodb/src/main/java/com/evotech/hd/config/ElectricityMeterBoxProperties.java" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/mongodb/src/main/java/com/evotech/hd/config/ElectricityMeterBoxProperties.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/mongodb/src/main/resources/application-mongo.yml" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/mongodb/src/main/resources/application-mongo.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/commoms/mongodb/src/main/resources/application-mongoDev.yml" beforeDir="false" afterPath="$PROJECT_DIR$/commoms/mongodb/src/main/resources/application-mongoDev.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/WebServerApplication.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/WebServerApplication.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MessageTopic.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttConfig.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttMessageCallback.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttMessageCallback.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttProperties.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttProperties.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttPublishMessage.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/config/mqtt/MqttPublishMessage.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/ManualOperationController.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/ManualOperationController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/TestController.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/controller/TestController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/BaseJob.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/BaseJob.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/CheckAlarmJob.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/CheckAlarmJob.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/charging/ChargingFullOfJob.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/job/charging/ChargingFullOfJob.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/service/ExecutionBatterySwapService.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/job/service/ExecutionBatterySwapService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MessageTopic.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MessageTopic.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MessageUtilService.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MessageUtilService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MqttMessageHeader.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/mqtt/MqttMessageHeader.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/OrderChargingService.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/OrderChargingService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/OrderChargingServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/service/impl/OrderChargingServiceImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/ParamUtils.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/ParamUtils.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/instruction/InstructionReadUtils.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/instruction/InstructionReadUtils.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/instruction/InstructionWriteUtils.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/instruction/InstructionWriteUtils.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/sendCloud/CloudSendInfoUtils.java" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/java/com/evotech/hd/webserver/utils/sendCloud/CloudSendInfoUtils.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/resources/application-dev.yml" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/resources/application-dev.yml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/web-server/src/main/resources/application-pro.yml" beforeDir="false" afterPath="$PROJECT_DIR$/web-server/src/main/resources/application-pro.yml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@ -21,6 +49,9 @@
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MavenImportPreferences">
<option name="generalSettings">
<MavenGeneralSettings>
@ -42,7 +73,7 @@
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;Application.CloudSendInfoUtils.executor&quot;: &quot;Debug&quot;,
&quot;Application.CloudSendInfoUtils.executor&quot;: &quot;Run&quot;,
&quot;Application.DataUtils.executor&quot;: &quot;Debug&quot;,
&quot;Application.Group.executor&quot;: &quot;Run&quot;,
&quot;Application.InstructionSendInfoUtils.executor&quot;: &quot;Run&quot;,
@ -61,6 +92,7 @@
&quot;Maven.station_control [install].executor&quot;: &quot;Run&quot;,
&quot;Maven.station_control [package].executor&quot;: &quot;Run&quot;,
&quot;Maven.station_control [tree].executor&quot;: &quot;Run&quot;,
&quot;Maven.station_control [validate].executor&quot;: &quot;Run&quot;,
&quot;Maven.web-server [clean,install,-U].executor&quot;: &quot;Run&quot;,
&quot;Maven.web-server [clean].executor&quot;: &quot;Run&quot;,
&quot;Maven.web-server [compile].executor&quot;: &quot;Run&quot;,
@ -71,9 +103,11 @@
&quot;RequestMappingsPanelWidth0&quot;: &quot;75&quot;,
&quot;RequestMappingsPanelWidth1&quot;: &quot;75&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
&quot;Spring Boot.WebServerApplication.executor&quot;: &quot;Debug&quot;,
&quot;git-widget-placeholder&quot;: &quot;master&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;D:/andy/ideaWorker/my/station-control/web-server/src/main/resources&quot;,
&quot;last_opened_file_path&quot;: &quot;D:/andy/ideaWorker/andy/blc/download/应用端/backend&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
@ -91,21 +125,21 @@
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="D:\andy\ideaWorker\station-control\commoms\mongodb\src\main\java\com\evotech\hd\config" />
<recent name="D:\andy\ideaWorker\my\station-control\web-server\src\main\resources" />
<recent name="D:\andy\ideaWorker\my\station-control\web-server\src\main\resources\mapper" />
<recent name="D:\andy\ideaWorker\my\station-control\commoms\mongodb\src\main\resources" />
<recent name="D:\andy\ideaWorker\my\station-control\web-server\src\main\java\com\evotech\hd\webserver\config\swagger" />
<recent name="D:\andy\ideaWorker\my\station-control\web-server\src\main\java\com\evotech\hd\webserver" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="D:\andy\ideaWorker\my\station-control\web-server\src\main\resources" />
</key>
<key name="CopyClassDialog.RECENTS_KEY">
<recent name="com.evotech.hd.entity" />
<recent name="com.evotech.hd.core.dtos.mqtt" />
<recent name="com.evotech.hd.webserver.mqtt" />
<recent name="com.evotech.hd.webserver.config.mqtt" />
<recent name="com.evotech.hd.webserver.job.service" />
<recent name="com.evotech.hd.exception" />
<recent name="com.evotech.hd.webserver.config.handler" />
<recent name="com.evotech.hd.core.dtos.system" />
</key>
</component>
<component name="RunAnythingCache">
@ -209,8 +243,8 @@
</list>
<recent_temporary>
<list>
<item itemvalue="Application.TestController" />
<item itemvalue="Application.CloudSendInfoUtils" />
<item itemvalue="Application.TestController" />
<item itemvalue="Application.XmlRpcHttpDirectCall" />
<item itemvalue="Application.test111" />
<item itemvalue="Application.DataUtils" />
@ -350,6 +384,14 @@
<workItem from="1764895045816" duration="8587000" />
<workItem from="1764981749573" duration="15080000" />
<workItem from="1765154508002" duration="107521000" />
<workItem from="1765521412936" duration="4420000" />
<workItem from="1765587705019" duration="15301000" />
<workItem from="1765615071525" duration="16015000" />
<workItem from="1765776702387" duration="36665000" />
<workItem from="1765939118169" duration="98526000" />
<workItem from="1766623919531" duration="18086000" />
<workItem from="1766800226399" duration="599000" />
<workItem from="1766810719772" duration="1371000" />
</task>
<servers />
</component>

View File

@ -0,0 +1,30 @@
package com.evotech.hd.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
/**
*
*
* @ClassName:BatteryInfoProperties
* @date: 2025年04月29日 16:32
* @author: andy.shi
* @contact: 17330188597
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Configuration
@ConfigurationProperties(prefix = "yt.zk-battery-box", ignoreInvalidFields = true)
public class BatteryBoxProperties extends AbstractMongoDbConfig {
@Bean("mongoTemplateZkBatteryBox")
@Override
public MongoTemplate getMongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
}

View File

@ -0,0 +1,30 @@
package com.evotech.hd.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.core.MongoTemplate;
/**
*
*
* @ClassName:BatteryInfoProperties
* @date: 2025年04月29日 16:32
* @author: andy.shi
* @contact: 17330188597
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Configuration
@ConfigurationProperties(prefix = "yt.zk-battery-info", ignoreInvalidFields = true)
public class BatteryInfoProperties extends AbstractMongoDbConfig {
@Primary
@Bean("mongoTemplateZkBatteryInfo")
@Override
public MongoTemplate getMongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
}

View File

@ -20,7 +20,7 @@ import org.springframework.data.mongodb.core.MongoTemplate;
@ConfigurationProperties(prefix = "yt.electricity-meter-box", ignoreInvalidFields = true)
public class ElectricityMeterBoxProperties extends AbstractMongoDbConfig {
@Bean("mongoTemplateBatteryBox")
@Bean("mongoTemplateElectricityMeterBox")
@Override
public MongoTemplate getMongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());

View File

@ -0,0 +1,29 @@
package com.evotech.hd.entity;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
/**
*
*
* @ClassName:BaseDocumentEntity
* @date: 2025年05月05日 13:38
* @author: andy.shi
* @contact: 17330188597
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Data
@Document
public class BaseDocumentEntity {
/***
* 时间戳做id
*/
@Id
String id;
String stationCode;
String value;
}

View File

@ -0,0 +1,195 @@
package com.evotech.hd.entity;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
import java.util.List;
/**
* 电池实时信息
* @ClassName:BatData
* @date: 2025年04月30日 9:13
* @author: andy.shi
* @contact: 17330188597
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Data
@Document
public class BatData extends BaseDocumentEntity{
/**
* 电池包追溯码
*/
private String batID;
/**
* 电池编号
*/
private String batCode;
/**
* 充电机编号
*/
private String chgID;
/**
* 仓位序号
*/
private Long cabinetNo;
/**
* 枪编号
*/
private Long gunNo;
/**
* 电池包个数
*/
private Long batPackCnt;
/**
* 单体电压总个数
*/
private Long batCellVoltCnt;
/**
* 单体电压
*/
private List<Float> batCellVoltList;
/**
* 单体电压采样时间
*/
private Date voltSampleTime;
/**
* 探针温度总个数
*/
private Long probeTempCnt;
/**
* 探针温度
*/
private List<Float> probeTempList;
/**
* 探针温度采样时间
*/
private Date tempSampleTime;
/**
* 电池包SOH
*/
private Long soh;
/**
* 电池包总电流充电为负值放电为正值单位-A
*/
private Float batTotalCurr;
/**
* 电池包允许最大 回充电电流值 (脉冲)单位-A
*/
private Float batAvailMaxChgCurr;
/**
* 电池包允许最大 放电电流值( )单位-A
*/
private Float batAvailMaxDischgCurr;
/**
* 电池包正极绝缘值单位-kohm
*/
private Float batPosiinsu;
/**
* 电池包负极绝缘值单位-kohm
*/
private Float batNegainsu;
/**
* 电池端高压(主继电器内侧)单位-V
*/
private Float batHighVoltInner;
/**
* 母线端高压(主继电器外侧) 单位-V
*/
private Float batHighVoltOuter;
/**
* TMS工作状态 0 关机;1 制冷;2 制热;3 自循环;
*/
private Long tmsState;
/**
* TMS高压继电器状态0 断开;1 闭合;2~3 无效;
*/
private Long tmsRelayState;
/**
* 出水温度(机组到电池)单位-°C
*/
private Long outletWaterTemp;
/**
* 回水温度(电池到机组)单位-°C
*/
private Long inletWaterTemp;
/**
* TMS需求功率单位-kW
*/
private Float tmsDemandPower;
/**
* TMS故障码0 无故障;
*/
private Long tmsFaultCode;
/**
* TMS故障码等级1 1 级故障; 2 2 级故障; 3 3 级故障; 0 无效;
*/
private Long tmsFaultLevel;
/***
* value 内容参考
* 仓位序号 cabinetNo int 仓位序号
* 单体电压总个数 batCellVoltCnt int32
* 单体电压 batCellVoltList list<float> 单位-V (每个型号的电池单体单体个数不定)
* 单体电压采样时间 voltSampleTime string 格式:yyyy-MM-dd HH:mm:ss (需要架载机支持)
* 探针温度总个数 probeTempCnt int32
* 探针温度 probeTempList list<int32> 单位-°C (个数不定)
* 探针温度采样时 tempSampleTime string 格式:yyyy-MM-dd HH:mm:ss (需要架载机支持)
* 电池包 SOH soh float %
* 电池包总电流充电为负值放电为正值 batTotalCurr float 单位-A
* 电池包允许最大 回充电电流值 (脉冲) batAvailMaxChgCu rr float 单位-A
* 电池包允许最大 放电电流值( ) batAvailMaxDisch gCurr float 单位-A
* 电池包正极绝缘 batPosiInsu float 单位-kohm
* 电池包负极绝缘 batNegaInsu float 单位-kohm
* 电池端高压( 继电器内侧) batHighVoltInner float 单位-V
* 母线端高压( 继电器外侧) batHighVoltOuter float 单位-V
* TMS 工作状态 tmsState int 0 关机;
* 1 制冷;
* 2 制热;
* 3 自循环;
* TMS 高压继电器 状态 tmsRelayState int 0 断开;1 闭合;2~3 无效;
* 出水温度(机组 到电池) outletWaterTemp int 单位-°C
* 回水温度(电池 到机组) inletWaterTemp int 单位-°C
* TMS 需求功率 tmsDemandPower float 单位-kW
* TMS 故障码 tmsFaultCode int 0 无故障;
* 出现 1 种以上循环发送
* TMS 故障码等级 tmsFaultLevel int 1 1 级故障; 2 2 级故障; 3 3 级故障; 0 无效;
* 电池ID batCode string 唯一识别码
*/
public BatData() {
}
public BatData(String batCode, Long cabinetNo) {
this.batCode = batCode;
this.cabinetNo = cabinetNo;
}
}

View File

@ -0,0 +1,160 @@
package com.evotech.hd.entity;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
/**
* 充电过程实时信息.ChargingData
*
* @author andy.shi
* @ClassName:ChargingData
* @date: 2025年12月13日 14:16
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Data
@Document
public class ChargingData extends BaseDocumentEntity{
/***
* value 内容参考
* 充电机编号 chgID string 充电机编号采用 16 位数字编码
* 枪编号 gunNo int 1 开始比如:1-A 2-B ... (充电切换旋钮为连接器 态时只发 A )
* 充电开始时间 startTime string 格式-yyyy-MM-dd hh:mm:ss
* 充电机输出电压 chgOutputVolt float 单位-V小数点后一位
* 充电机输出电流 chgOutputCurr float 单位-A小数点后一位
* 充电电量 chgQty float 单位-kWh小数点后一位
* 电池ID batCode string 电池唯一识别码
* SOC soc float 当前电池电量0-100%
* 电池箱所在仓位 cabinetNo int 仓位序号
* 最高单体电压 batMaxVolt float 单位-V
* 最高单体电压组 batMaxVoltNo int
* 最低单体电压 batMinVolt float 单位-V
* 最低单体电压组 batMinVoltNo int
* 最高单体温度 batMaxTemp int 单位-°C
* 最高单体温度组 batMaxTempNo int
* 最低单体温度 batMinTemp int 单位-°C
* 最低单体温度组 batMinTempNo int
* 电池电压需求 voltDemand float 单位-V小数点后一位
* 电池电流需求 currDemand float 单位-A小数点后一位
* 充电模式 chgMode int 1恒压充电 2恒流充电 3恒功率充电
* 剩余充电时长 remainderChgTi me int 单位-min BMS 获取
* 直流电表电量 dcMeterElect float 单位-kWh小数点后一位
* 充电流水号 chgSn string
*/
//充电机编号
String chgID;
/***
* 枪编号
*/
Long gunNo;
/***
* 充电开始时间
* 格式-yyyy-MM-dd hh:mm:ss
*/
Date startTime;
/***
* 充电机输出电压
* 单位-V小数点后一位
*/
Float chgOutputVolt;
/***
* 充电机输出电流
* 单位-A小数点后一位
*/
Float chgOutputCurr;
/***
* 充电电量
* 单位-kWh小数点后一位
*/
Float chgQty;
/***
* 电池ID
* 电池唯一识别码
*/
String batCode;
/***
* SOC
* 当前电池电量0-100%
*/
Long soc;
/***
* 电池箱所在仓位
* 仓位序号
*/
Long cabinetNo;
/***
* 最高单体电压
* 单位-V
*/
Float batMaxVolt;
/***
* 最高单体电压组
* 单位-V
*/
Long batMaxVoltNo;
/***
* 最低单体电压
* 单位-V
*/
Float batMinVolt;
/***
* 最低单体电压组
*/
Long batMinVoltNo;
/***
* 最高单体温度
* 单位-°C
*/
Float batMaxTemp;
/***
* 最低单体温度
* 单位-°C
*/
Float batMinTemp;
/***
* 最低单体温度组
* 单位-°C
*/
Long batMinTempNo;
/***
* 电池电压需求
* 单位-V小数点后一位
*/
Float voltDemand;
/***
* 电池电流需求
* 单位-V小数点后一位
*/
Float currDemand;
/***
* 充电模式
* 1恒压充电 2恒流充电 3恒功率充电
*/
Long chgMode;
/***
* 剩余充电时长
* 单位-min
*/
Long remainderChgTime;
/***
* 直流电表电量
* 单位-kWh小数点后一位
*/
Float dcMeterElect;
/***
* 充电流水号
* 电池唯一识别码
*/
String chgSn;
public ChargingData() {
}
}

View File

@ -9,3 +9,9 @@ yt:
electricity-meter-box:
#//数据存储的库
data_base: electricity_meter_box
zk-battery-box:
#//数据存储的库
data_base: zk_battery_box
zk-battery-info:
#//数据存储的库
data_base: zk_battery_info

View File

@ -9,3 +9,9 @@ yt:
electricity-meter-box:
#//数据存储的库
data_base: electricity_meter_box
zk-battery-box:
#//数据存储的库
data_base: zk_battery_box
zk-battery-info:
#//数据存储的库
data_base: zk_battery_info

View File

@ -8,6 +8,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
@ -15,6 +16,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@ComponentScan("com.evotech.hd.**.**")
@MapperScan({"com.evotech.hd.**.**.mapper.**.**"})
@EnableCaching
@EnableAsync
public class WebServerApplication {
public static void main(String[] args) {

View File

@ -1,36 +0,0 @@
package com.evotech.hd.webserver.config.mqtt;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
@Data
public class MessageTopic implements Serializable {
private static final long serialVersionUID = 7238663818955151985L;
private String businessType = "YTHD";
private String stationCode;
private String dataDirection = "S2M";
private String messageType;
public MessageTopic() {
}
public MessageTopic(String stationCode, String messageType) {
this.stationCode = stationCode;
this.messageType = messageType;
}
@Override
public String toString() {
return businessType + "/" + stationCode + "/" + dataDirection + "/" + messageType;
}
}

View File

@ -1,94 +0,0 @@
package com.evotech.hd.webserver.config.mqtt;
/**
*
*
* @ClassName:MqttConfig
* @date: 2025年08月25日 15:28
* @author: andy.shi
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.concurrent.ConcurrentHashMap;
@Configuration
@Component
@Slf4j
public class MqttConfig implements ApplicationRunner {
@Resource
MqttProperties mqttProperties;
static ConcurrentHashMap<String, MqttClient> mqttClientMap = new ConcurrentHashMap<>();
/**
* 配置MQTT连接选项不含客户端ID
*/
@Bean
public MqttConnectOptions mqttConnectOptions() {
MqttConnectOptions options = new MqttConnectOptions();
// 设置服务器地址支持多个用数组
options.setServerURIs(new String[]{mqttProperties.getBroker()});
// 配置认证信息如果有
if (StringUtils.isNotEmpty(mqttProperties.getUsername())) {
options.setUserName(mqttProperties.getUsername());
}
if (StringUtils.isNotEmpty(mqttProperties.getPassword())) {
options.setPassword(mqttProperties.getPassword().toCharArray());
}
// 其他连接参数
options.setKeepAliveInterval(mqttProperties.getKeepAlive()); // 心跳间隔
options.setAutomaticReconnect(true); // 自动重连
options.setCleanSession(true); // 断开后清除会话
return options;
}
/**
* 创建MQTT客户端客户端ID在这里指定
*/
@Bean // 初始化时自动连接
public MqttClient mqttClient(MqttConnectOptions options) throws MqttException {
// 客户端ID在创建MqttClient时传入而非通过MqttConnectOptions设置
MqttClient client = new MqttClient(mqttProperties.getBroker(), mqttProperties.getClientId(), new MemoryPersistence());
// 设置回调处理器
client.setCallback(new MqttMessageCallback());
client.connect(options);
mqttClientMap.put("cloudClient", client);
return client;
}
@PreDestroy
public void PreDestroyComplete() {
log.info("===>>>程序要关闭了...");
MqttClient cloudClient = mqttClientMap.get("cloudClient");
try {
cloudClient.disconnect();
cloudClient.close();
log.info("=====>>>关闭了MQTT");
} catch (MqttException e) {
e.printStackTrace();
}
}
@Override
public void run(ApplicationArguments args) throws Exception {
}
}

View File

@ -0,0 +1,94 @@
//package com.evotech.hd.webserver.config.mqtt;
//
///**
// *
// *
// * @ClassName:MqttConfig
// * @date: 2025年08月25日 15:28
// * @author: andy.shi
// * @remark: 开发人员联系方式 1042025947@qq.com/微信同步
// */
//
//import lombok.extern.slf4j.Slf4j;
//import org.apache.commons.lang3.StringUtils;
//import org.eclipse.paho.client.mqttv3.MqttClient;
//import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
//import org.eclipse.paho.client.mqttv3.MqttException;
//import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.boot.ApplicationArguments;
//import org.springframework.boot.ApplicationRunner;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.stereotype.Component;
//
//import javax.annotation.PreDestroy;
//import javax.annotation.Resource;
//import java.util.concurrent.ConcurrentHashMap;
//
//@Configuration
//@Component
//@Slf4j
//public class MqttConfig implements ApplicationRunner {
//
// @Resource
// MqttProperties mqttProperties;
//
//
// static ConcurrentHashMap<String, MqttClient> mqttClientMap = new ConcurrentHashMap<>();
//
// /**
// * 配置MQTT连接选项不含客户端ID
// */
// @Bean
// public MqttConnectOptions mqttConnectOptions() {
// MqttConnectOptions options = new MqttConnectOptions();
// // 设置服务器地址支持多个用数组
// options.setServerURIs(new String[]{mqttProperties.getBroker()});
// // 配置认证信息如果有
// if (StringUtils.isNotEmpty(mqttProperties.getUsername())) {
// options.setUserName(mqttProperties.getUsername());
// }
// if (StringUtils.isNotEmpty(mqttProperties.getPassword())) {
// options.setPassword(mqttProperties.getPassword().toCharArray());
// }
// // 其他连接参数
// options.setKeepAliveInterval(mqttProperties.getKeepAlive()); // 心跳间隔
// options.setAutomaticReconnect(true); // 自动重连
// options.setCleanSession(true); // 断开后清除会话
// return options;
// }
//
// /**
// * 创建MQTT客户端客户端ID在这里指定
// */
// @Bean // 初始化时自动连接
// public MqttClient mqttClient(MqttConnectOptions options) throws MqttException {
// // 客户端ID在创建MqttClient时传入而非通过MqttConnectOptions设置
// MqttClient client = new MqttClient(mqttProperties.getBroker(), mqttProperties.getClientId(), new MemoryPersistence());
// // 设置回调处理器
// client.setCallback(new MqttMessageCallback());
// client.connect(options);
// mqttClientMap.put("cloudClient", client);
// return client;
// }
//
// @PreDestroy
// public void PreDestroyComplete() {
// log.info("===>>>程序要关闭了...");
// MqttClient cloudClient = mqttClientMap.get("cloudClient");
// try {
// cloudClient.disconnect();
// cloudClient.close();
// log.info("=====>>>关闭了MQTT");
// } catch (MqttException e) {
// e.printStackTrace();
// }
//
// }
//
// @Override
// public void run(ApplicationArguments args) throws Exception {
//
// }
//}

View File

@ -96,10 +96,48 @@ public class MqttMessageCallback implements MqttCallbackExtended, ApplicationCo
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// 消息成功发布后的回调可选处理
// try {
// logger.info("消息已成功发布到主题:{}", token.getMessageId());
// } catch (Exception e) {
// logger.error("消息发布确认失败", e);
// }
try {
logger.info("消息已成功发布到主题:{}", token.getTopics()[0]);
// 核心安全获取主题优先用自定义 token 的主题兼容原生 token
String publishTopic = "未知主题";
// 兼容原生 token判空后获取第一个主题
String[] topics = token.getTopics();
if (topics != null && topics.length > 0) {
publishTopic = topics[0];
}
// 解析其他信息和之前一致增加空指针防护
Integer messageId = token.getMessageId();
String messageContent = "";
int qos = 0;
boolean isRetained = false;
MqttMessage message = token.getMessage();
if (message != null) {
messageContent = new String(message.getPayload(), "UTF-8");
qos = message.getQos();
isRetained = message.isRetained();
}
String clientId = token.getClient() != null ? token.getClient().getClientId() : "未知客户端";
// 打印完整信息
logger.info("===== 消息发布确认 =====");
logger.info("客户端ID{}", clientId);
logger.info("消息ID{}", messageId);
logger.info("发布主题:{}", publishTopic); // 此时主题不会为 null
logger.info("消息内容:{}", messageContent);
logger.info("QoS等级{}", qos);
logger.info("是否保留消息:{}", isRetained);
logger.info("=======================");
} catch (Exception e) {
logger.error("消息发布确认失败", e);
logger.error("解析消息发布确认token失败", e);
}
}

View File

@ -36,4 +36,10 @@ public class MqttProperties {
// 心跳间隔
// @Value("${mqtt.keep-alive:60}")
private int keepAlive;
//重连间隔时间
private int retryInterval;
//最大重试次数
private int maxRetry;
}

View File

@ -1,11 +1,25 @@
package com.evotech.hd.webserver.config.mqtt;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.evotech.hd.webserver.mqtt.MessageTopic;
import com.evotech.hd.webserver.mqtt.MessageUtilService;
import com.evotech.hd.webserver.mqtt.MqttMessageHeader;
import com.evotech.hd.webserver.mqtt.MyMqttMessage;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@Slf4j
public class MqttPublishMessage {
@Resource
MessageUtilService messageUtilService;
public MqttMessage publish(String message, String topic) {
MqttClient cloudClient = MqttConfig.mqttClientMap.get("cloudClient");
MqttMessage mqttMessage = new MqttMessage();
@ -36,4 +50,77 @@ public class MqttPublishMessage {
return mqttMessage;
}
/**
* 发送 AES 加密消息
* @param topic
* @param header
* @param dataBody
*/
public void publishAESMessage(MessageTopic topic, MqttMessageHeader header, JSONObject dataBody) {
log.info("MQTT->>>>>>>>>>>>>请求发送mqtt消息: topic:{}; header:{}, data:{}", JSONUtil.toJsonStr(topic),JSONUtil.toJsonStr(header),JSONUtil.toJsonStr(dataBody));
// 1. 获取AES
SymmetricCrypto aes = messageUtilService.getAes(topic.getStationCode());
// 2. 数据
MyMqttMessage message = new MyMqttMessage();
message.setHeader(header);
message.setDataBody(dataBody);
String encrypt = aes.encryptBase64(JSONUtil.toJsonStr(message));
// 3. 发送MQTT消息
try {
MqttMessage mqttMessage = publish(encrypt, topic.toString());
try {
//dataBody.set("header", JSONUtil.toJsonStr(header));
// addMqttMessage(topic, mqttMessage.getId()+"", mqttMessage.getQos(), JSONUtil.parseObj(message));
} catch (Exception e) {
log.error("MQTT->>>>>>>>>>>>>记录mqtt消息出现了错误{},topic:{}; header:{}, data:{}; message:{}",e.getMessage(),JSONUtil.toJsonStr(topic),JSONUtil.toJsonStr(header),JSONUtil.toJsonStr(dataBody), JSONUtil.toJsonStr(mqttMessage));
throw new RuntimeException("记录mqtt消息出现了错误"+e.getMessage());
}
} catch (Exception e) {
log.error("MQTT->>>>>>>>>>>>>发送站端mqtt消息出现异常{},topic:{}; header:{}, data:{}",e.getMessage(),JSONUtil.toJsonStr(topic),JSONUtil.toJsonStr(header),JSONUtil.toJsonStr(dataBody));
}
}
// public SymmetricCrypto getAes(String stationCode) {
// JSONObject aesJo = getAESKey(stationCode);
// String aesSecretKey = aesJo.getStr("encryptKey");
// String aesIv = aesJo.getStr("encryptVector");
// SymmetricCrypto aes = new AES(Mode.CBC, Padding.PKCS5Padding, Base64.getDecoder().decode(aesSecretKey), aesIv.getBytes());
// return aes;
// }
// public JSONObject getAESKey(String stationCode) {
// JSONObject jo = new JSONObject();
// Object o1 = null;
// try {
// o1 = redisUtil.get(HDConstant.HD_STATION_SECRET_KEY_AES_PREFIX + stationCode + ":key");
// } catch (Exception e) {
// e.printStackTrace();
// }
// Object o2 = null;
// try {
// o2 = redisUtil.get(HDConstant.HD_STATION_SECRET_KEY_AES_PREFIX + stationCode + ":iv");
// } catch (Exception e) {
// e.printStackTrace();
// }
// if (!ObjectUtil.isEmpty(o1) && !ObjectUtil.isEmpty(o2)) {
//// jo.set("aesSecretKey", o1.toString());
//// jo.set("aesIv", o2.toString());
// jo.set("encryptKey", o1.toString());
// jo.set("encryptVector", o2.toString());
// return jo;
// }
// BatteryStationSecretKey bssk = batteryStationSecretKeyDao.selectOne(new QueryWrapper<BatteryStationSecretKey>().eq("type", 2).eq("station_code", stationCode));
// if (bssk == null) {
// throw new RuntimeException("AES秘钥未获取到请站端重新登陆");
//// return setAesKey(stationCode);
// }
// redisUtil.set(HDConstant.HD_STATION_SECRET_KEY_AES_PREFIX + stationCode + ":key", bssk.getPublicKey());
// redisUtil.set(HDConstant.HD_STATION_SECRET_KEY_AES_PREFIX + stationCode + ":iv", bssk.getPrivateKey());
//// jo.set("aesSecretKey", o1.toString());
//// jo.set("aesIv", o2.toString());
// jo.set("encryptKey", o1.toString());
// jo.set("encryptVector", o2.toString());
// return jo;
// }
}

View File

@ -102,14 +102,15 @@ public class ManualOperationController {
@ApiLog(value = "换电机构:停止", type = LogTypeEnum.OPERATION)
public Result<Boolean> rgvUrgentStopMove(){
try {
Map<String, List<Integer>> map = ParamUtils.getBatteryCompartmentPosition();
map.keySet().forEach(rgvNo ->{
try {
InstructionWriteUtils.emergencyStop(rgvNo);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
InstructionWriteUtils.emergencyStop();
// Map<String, List<Integer>> map = ParamUtils.getBatteryCompartmentPosition();
// map.keySet().forEach(rgvNo ->{
// try {
// InstructionWriteUtils.emergencyStop(rgvNo);
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
// });
return Result.getInstance().build(Boolean.class).success(true);
} catch (Exception e) {

View File

@ -1,13 +1,22 @@
package com.evotech.hd.webserver.controller;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.evotech.hd.core.dtos.Result;
import com.evotech.hd.core.dtos.business.AccessStrategyDTO;
import com.evotech.hd.core.entity.business.OrderCharging;
import com.evotech.hd.core.enums.SwapBatteryStepEnum;
import com.evotech.hd.entity.BatData;
import com.evotech.hd.entity.ChargingData;
import com.evotech.hd.exception.InstructionException;
import com.evotech.hd.service.MongoDBService;
import com.evotech.hd.utils.Collections;
import com.evotech.hd.utils.DateUtils;
import com.evotech.hd.webserver.job.service.ExecutionBatterySwapService;
import com.evotech.hd.webserver.logging.annotation.ApiLog;
import com.evotech.hd.webserver.logging.enums.LogTypeEnum;
import com.evotech.hd.webserver.mqtt.MqttPublishUtils;
import com.evotech.hd.webserver.utils.AccessStrategyUtil;
import com.evotech.hd.webserver.utils.ParamUtils;
import com.evotech.hd.webserver.utils.instruction.InstructionReadUtils;
@ -16,12 +25,21 @@ import com.evotech.hd.webserver.utils.sendCloud.CloudSendInfoUtils;
import com.evotech.hd.webserver.websocket.controller.WebSocketUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.spring.web.scanners.ApiDescriptionLookup;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@ -30,6 +48,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
* TestController
@ -42,6 +61,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
@RestController
@RequestMapping("/test/rgv")
@Api(tags = "循环测试")
@Slf4j
public class TestController {
private static final Map<String, CompletableFuture<Void>> taskRgvMap = new ConcurrentHashMap<>();
@ -54,11 +74,113 @@ public class TestController {
@Resource
ExecutionBatterySwapService executionBatterySwapService;
@Resource
MongoDBService mongoDBService;
@PostMapping("/test")
public void test() throws Exception {
InstructionWriteUtils.openRolling(ParamUtils.getDoorParams("入口"));
// InstructionWriteUtils.emergencyStop();
sendCloud();
}
public void sendCloud() throws InstructionException {
// JSONObject batDataInfo1 = InstructionReadUtils.queryBattery(id);
// JSONObject batDataInfo2 = InstructionReadUtils.queryBatDataInfo2(id);
// JSONObject powModInfo = InstructionReadUtils.queryPowModInfo(id);
// JSONObject batChgInfoInfo = InstructionReadUtils.queryBSLBatChgInfo(id);
// JSONObject batCellPeakInfo = InstructionReadUtils.queryBatCellPeak(id);
try {
ChargingData chargingData = new ChargingData();
//当前电池电量0-100%
chargingData.setBatCode("0PDDB00A160JFAD9K1100006");
if(StringUtils.isNotEmpty("200")){
chargingData.setSoc(new BigDecimal("200").divide(new BigDecimal(10), 2, RoundingMode.DOWN).longValue());
}
//充电电量
chargingData.setChgQty(35f);
//电池箱所在仓位
chargingData.setCabinetNo(11l);
//充电模式
chargingData.setChgMode(1l);
//充电机输出电流
chargingData.setChgOutputCurr(20f);
//充电机输出电压
chargingData.setChgOutputVolt(20f);
//电池电压需求 or 电池请求电压
chargingData.setVoltDemand(20f);
//电池电流需求 or 电池请求电流
chargingData.setCurrDemand(25f);
//剩余充电时长
chargingData.setRemainderChgTime(200l);
//最高单体电压
chargingData.setBatMaxVolt(20f);
//最低单体电压
chargingData.setBatMinVolt(15f);
//最高单体温度
chargingData.setBatMaxTemp(65f);
//最低单体温度
chargingData.setBatMinTemp(30f);
//流水号
chargingData.setChgSn("12323213213");
//充电开始时间
chargingData.setStartTime(new Date());
chargingData.setId(String.valueOf(System.currentTimeMillis()));
chargingData.setStationCode(ParamUtils.findStationCode());
mongoDBService.save("zk_battery_info", chargingData.getBatCode(), chargingData);
//推送云平台mq
MqttPublishUtils.sendState("chargingData", JSONUtil.parseObj(chargingData));
// //充电机编号
// String chgID;
// * 枪编号
// Integer gunNo;
// * 最高单体电压组 单位-V
// Integer batMaxVoltNo;
// * 最低单体电压组
// Integer batMinVoltNo;
// * 最低单体温度组 单位-°C
// Integer batMinTempNo;
// * 直流电表电量 单位-kWh小数点后一位
// Float dcMeterElect;
} catch (Exception e) {
e.printStackTrace();
}
BatData batData =new BatData();
//电池ID batCode string 唯一识别码
batData.setBatCode("0PDDB00A160JFAD9K1100006");
//仓位号
batData.setCabinetNo(11l);
//数量信息
batData.setBatCellVoltCnt(120l);
//单体电压
batData.setBatCellVoltList(Collections.asList(12f,12f,12f,12f,12f,12f,12f,12f));
//单体电压采样时间
batData.setVoltSampleTime(new Date());
//探针温度总个数
batData.setProbeTempCnt(14l);
//探针温度
batData.setProbeTempList(Collections.asList(12f,12f,12f,12f,12f,12f,12f,12f));
//探针温度采样时间
batData.setTempSampleTime(new Date());
//电池包SOH
batData.setSoh(99l);
//电池包总电流
batData.setBatTotalCurr(45f);
//电池包正极绝缘值
batData.setBatPosiinsu(40f);
//电池包负极绝缘值
batData.setBatNegainsu(35f);
mongoDBService.save("zk_battery_box", batData.getBatCode(), batData);
//推送云平台mq
MqttPublishUtils.sendState("batData", JSONUtil.parseObj(batData));
}
@ApiOperation("开始")
@ -390,7 +512,7 @@ public class TestController {
Map<String, Object> error = executionBatterySwapService.executionErrorResult(rgvNo);
if(Collections.isNotEmpty(error)){
String message = JSONObject.toJSONString(error);
stopRgv(rgvNo, rgvNo);
stopRgv(rgvNo, rgvNo, String.valueOf(error.get("errorMsg")));
throw new RuntimeException(String.format("RRG:[%s] 出现异常; 机构区间为:{%s}; 执行类型为:{%s}; 执行次数为:{%s}; 异常信息为:{%s}",rgvNo, category, "取存", (runNun+1), message));
}
@ -512,7 +634,7 @@ public class TestController {
return Result.getInstance().success();
}
public void stopRgv(String taskKey, String rgvNo) {
public void stopRgv(String taskKey, String rgvNo, String errorMsg) {
if(taskRgvMap.containsKey(taskKey) && closeRunMap.containsKey(taskKey) && categoryRunMap.containsKey(taskKey)){
if(executionBatterySwapService == null){
executionBatterySwapService = SpringUtil.getBean(ExecutionBatterySwapService.class);
@ -523,8 +645,25 @@ public class TestController {
closeRunMap.put(taskKey, new AtomicBoolean(true));
String category = categoryRunMap.get(taskKey);
categoryRunMap.remove(taskKey);
log.error("触发急停操作, 触发异常为=====>"+errorMsg);
CloudSendInfoUtils.sendAlarmWx(Collections.asMap("area","红旗换电站", "message", errorMsg));
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("执行时间[%s]; RGV[%s]>>>>>下发急停操作命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), rgvNo))));
InstructionWriteUtils.emergencyStop(rgvNo);
InstructionWriteUtils.rgvStopMove(rgvNo);
try {
AccessStrategyDTO accessStrategyDTO = AccessStrategyUtil.getValidAccessStrategyDTO();
if(StringUtils.isNotEmpty(accessStrategyDTO.getEffectiveRgvNo())) {
String[] rgvArrays = accessStrategyDTO.getEffectiveRgvNo().split(",");
for (String rgvNo1 : rgvArrays) {
if(rgvNo != rgvNo1){
InstructionWriteUtils.rgvStopMove(rgvNo1);
}
}
}
} catch (Exception e) {
log.error("发送全站急停失败===>{}", e.getMessage());
throw new RuntimeException(e);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
@ -539,7 +678,8 @@ public class TestController {
Map<String, Object> error = executionBatterySwapService.executionErrorResult(rgvNo);
if(Collections.isNotEmpty(error)){
String message = JSONObject.toJSONString(error);
stopRgv(taskKey, rgvNo);
System.out.println("错误信息为=======>" +message);
stopRgv(taskKey, rgvNo, String.valueOf(error.get("errorMsg")));
throw new RuntimeException(String.format("RRG:[%s] 出现异常; 机构区间为:{%s}; 执行类型为:{%s}; 执行次数为:{%s}; 异常信息为:{%s}",rgvNo, category, "取存", (runNun+1), message));
}
@ -573,26 +713,10 @@ public class TestController {
CompletableFuture<Void> future = CompletableFuture.runAsync(() ->{
//执行开门
CompletableFuture<Boolean> openFuture = CompletableFuture.supplyAsync(()->{
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format(" 执行时间:[%s]; 下发打开开合门命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
InstructionWriteUtils.openCenDoor();
Boolean result = false;
do{
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
if(result = InstructionReadUtils.getCenRbDoorOpenStatus()){
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format(" 执行时间:[%s]; 开合门已打开", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
return true;
}
}while (!result);
} catch (Exception e) {
throw new RuntimeException("打开开合门出现异常:",e);
}
return false;
});
if(openFuture.join()) {
if(true) {
// Boolean isError = true;
//如果是拆装
for (int runNun = 0; runNun < maxNum; runNun++) {
//检查是否停止循环
@ -616,44 +740,106 @@ public class TestController {
int finalRunNun = runNun + 1;
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; 拆存rgv[%s], 取装rgv[%s], 存仓[%s], 取仓[%s]>>>>>>", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), splitStorageRgv, loadingRgv, putCwNo, takeCwNo))));
String finalSplitStorageRgv = splitStorageRgv;
//根据开门结果, 执行拆除
CompletableFuture<Boolean> splitFuture = CompletableFuture.supplyAsync(() -> {
//开始执行拆除
//启动对中机构
CompletableFuture<Boolean> correctFuture = CompletableFuture.supplyAsync(()->{
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s]>>>>>下发拆电池命令", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalSplitStorageRgv))));
InstructionWriteUtils.splitOldBattery(finalSplitStorageRgv);
Boolean oResult = false;
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format(" 执行时间:[%s]; 下发启动对中机构命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
InstructionWriteUtils.startCorrectInstitution();
Boolean openResult = false;
do {
errorCheck(rgv, finalSplitStorageRgv, category, finalRunNun);
if (checkJt(rgv, category, finalRunNun)) {
return false;
}
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
//跳开查询
if (oResult = executionBatterySwapService.checkOpenExecutionResult(finalSplitStorageRgv)) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s]>>>>>执行拆电池操作", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalSplitStorageRgv))));
//检查是否存在异常
if (openResult = executionBatterySwapService.checkCenOpenExecutionResult()) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format(" 执行时间:[%s]; 对中机构正在执行", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
Boolean result = false;
do {
errorCheck(rgv, finalSplitStorageRgv, category, finalRunNun);
if (checkJt(rgv, category, finalRunNun)) {
return false;
}
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
if (result = executionBatterySwapService.executionResult(finalSplitStorageRgv)) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s]>>>>>拆电执行完成", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalSplitStorageRgv))));
if(result = executionBatterySwapService.checkCenExecutionResult()){
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format(" 执行时间:[%s]; 对中机构已锁定", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
// 推送云端, 并查询是否存在异常 没有异常, 开始启动换电
return true;
}
}while (!result);
//如果为true,则证明执行结束
}
}while (!openResult);
} catch (Exception e) {
throw new RuntimeException("启动对中机构出现异常:",e);
}
return false;
});
//检查是否停止循环
if (checkJt(rgv, category, runNun)) {
return;
}
//执行开门
CompletableFuture<Boolean> openFuture = correctFuture.thenApplyAsync((correctResult)->{
if(correctResult){
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format(" 执行时间:[%s]; 下发打开开合门命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
InstructionWriteUtils.openCenDoor();
Boolean result = false;
do{
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
if(result = InstructionReadUtils.getCenRbDoorOpenStatus()){
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format(" 执行时间:[%s]; 开合门已打开", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
return true;
}
}while (!result);
} catch (Exception e) {
throw new RuntimeException("打开开合门出现异常:",e);
}
}
return false;
});
//检查是否停止循环
if (checkJt(rgv, category, runNun)) {
return;
}
//根据开门结果, 执行拆除
CompletableFuture<Boolean> splitFuture = openFuture.thenApplyAsync((openResult) -> {
if(openResult){
//开始执行拆除
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s]>>>>>下发拆电池命令", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalSplitStorageRgv))));
InstructionWriteUtils.splitOldBattery(finalSplitStorageRgv);
Boolean oResult = false;
do {
errorCheck(rgv, finalSplitStorageRgv, category, finalRunNun);
if (checkJt(rgv, category, finalRunNun)) {
return false;
}
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
//跳开查询
if (oResult = executionBatterySwapService.checkOpenExecutionResult(finalSplitStorageRgv)) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s]>>>>>执行拆电池操作", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalSplitStorageRgv))));
Boolean result = false;
do {
errorCheck(rgv, finalSplitStorageRgv, category, finalRunNun);
if (checkJt(rgv, category, finalRunNun)) {
return false;
}
return true;
}
} while (!result);
}
} while (!oResult);
} catch (Exception e) {
stopRgv(rgv, finalSplitStorageRgv);
return false;
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
if (result = executionBatterySwapService.executionResult(finalSplitStorageRgv)) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s]>>>>>拆电执行完成", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalSplitStorageRgv))));
errorCheck(rgv, finalSplitStorageRgv, category, finalRunNun);
if (checkJt(rgv, category, finalRunNun)) {
return false;
}
return true;
}
} while (!result);
}
} while (!oResult);
} catch (Exception e) {
log.error("急停异常");
e.printStackTrace();
stopRgv(rgv, finalSplitStorageRgv, e.getMessage());
return false;
}
}
return false;
});
@ -698,7 +884,9 @@ public class TestController {
}
} while (!openResult);
} catch (Exception e) {
stopRgv(rgv, finalSplitStorageRgv);
log.error("急停异常");
e.printStackTrace();
stopRgv(rgv, finalSplitStorageRgv, e.getMessage());
return false;
}
}
@ -712,45 +900,49 @@ public class TestController {
//
String finalLoadingRgv = loadingRgv;
CompletableFuture<Boolean> takeFuture = CompletableFuture.supplyAsync(() -> {
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s], 电池仓位[%s]>>>>>下发取出命令", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalLoadingRgv, takeCwNo))));
InstructionWriteUtils.takeNewBattery(finalLoadingRgv, Integer.valueOf(takeCwNo));
Boolean openResult = false;
do {
errorCheck(rgv, finalLoadingRgv, category, finalRunNun);
if (checkJt(rgv, category, finalRunNun)) {
return false;
}
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
//跳开查询
if (openResult = executionBatterySwapService.checkOpenExecutionResult(finalLoadingRgv)) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s], 电池仓位[%s]>>>>>执行取出操作", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalLoadingRgv, takeCwNo))));
Boolean endResult = false;
do {
errorCheck(rgv, finalLoadingRgv, category, finalRunNun);
if (checkJt(rgv, category, finalRunNun)) {
return false;
}
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
//执行结束查询
if (endResult = executionBatterySwapService.executionResult(finalLoadingRgv)) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s], 电池仓位[%s]>>>>>执行取出完成", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalLoadingRgv, takeCwNo))));
CompletableFuture<Boolean> takeFuture = openFuture.thenApplyAsync((openDoorResult) -> {
if(openDoorResult){
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s], 电池仓位[%s]>>>>>下发取出命令", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalLoadingRgv, takeCwNo))));
InstructionWriteUtils.takeNewBattery(finalLoadingRgv, Integer.valueOf(takeCwNo));
Boolean openResult = false;
do {
errorCheck(rgv, finalLoadingRgv, category, finalRunNun);
if (checkJt(rgv, category, finalRunNun)) {
return false;
}
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
//跳开查询
if (openResult = executionBatterySwapService.checkOpenExecutionResult(finalLoadingRgv)) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s], 电池仓位[%s]>>>>>执行取出操作", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalLoadingRgv, takeCwNo))));
Boolean endResult = false;
do {
errorCheck(rgv, finalLoadingRgv, category, finalRunNun);
if (checkJt(rgv, category, finalRunNun)) {
return false;
}
return true;
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
//执行结束查询
if (endResult = executionBatterySwapService.executionResult(finalLoadingRgv)) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s], 电池仓位[%s]>>>>>执行取出完成", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalLoadingRgv, takeCwNo))));
errorCheck(rgv, finalLoadingRgv, category, finalRunNun);
if (checkJt(rgv, category, finalRunNun)) {
return false;
}
return true;
}
} while (!endResult);
}
} while (!openResult);
} catch (Exception e) {
e.printStackTrace();
stopRgv(rgv, finalLoadingRgv);
return false;
}
} while (!endResult);
}
} while (!openResult);
} catch (Exception e) {
log.error("急停异常");
e.printStackTrace();
stopRgv(rgv, finalLoadingRgv, e.getMessage());
return false;
}
}
return false;
});
@ -799,12 +991,14 @@ public class TestController {
} else {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; RRG:[%s]>>>>>进行安装失败", finalRunNun, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), finalLoadingRgv))));
stopRgv(rgv, finalLoadingRgv);
log.error("安装失败");
stopRgv(rgv, finalLoadingRgv, "安装失败");
return false;
}
} catch (Exception e) {
log.error("急停异常");
e.printStackTrace();
stopRgv(rgv, finalLoadingRgv);
stopRgv(rgv, finalLoadingRgv, e.getMessage());
return false;
}
return false;
@ -814,37 +1008,103 @@ public class TestController {
if (checkJt(rgv, category, runNun)) {
return;
}
if (splitFuture.join() && put.join() && takeFuture.join() && loading.join()) {
//执行关门
CompletableFuture<Boolean> closeFuture =loading.thenApplyAsync((loadingResult) ->{
if(loadingResult){
//开始执行拆除
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data", String.format("%s 下发关闭开合门命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
InstructionWriteUtils.closeCenDoor();
Boolean result = false;
do{
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
if(result = InstructionReadUtils.getCenRbDoorCloseStatus()){
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format("%s 开合门已关闭", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
return true;
}
}while (!result);
//开门完成
} catch (Exception e) {
throw new RuntimeException("关闭开合门出现异常:", e);
}
}
return false;
});
//检查是否停止循环
if (checkJt(rgv, category, runNun)) {
return;
}
//释放对中机构
CompletableFuture<Boolean> closeCorrectFuture = closeFuture.thenApplyAsync((closeDoorFuture)->{
if(closeDoorFuture){
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format(" 执行时间:[%s]; 下发释放对中机构命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
InstructionWriteUtils.closeCorrectInstitution();
Boolean openResult = false;
do {
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
//检查是否存在异常
if (openResult = executionBatterySwapService.checkCenOpenExecutionResult()) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format(" 执行时间:[%s]; 对中机构正在执行", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
Boolean result = false;
do {
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
if(result = executionBatterySwapService.checkCenExecutionResult()){
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format(" 执行时间:[%s]; 对中机构已释放", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
// 推送云端, 并查询是否存在异常 没有异常, 开始启动换电
return true;
}
}while (!result);
//如果为true,则证明执行结束
}
}while (!openResult);
} catch (Exception e) {
throw new RuntimeException("释放对中机构出现异常:",e);
}
}
return false;
});
//只需要检查存电完成, 对中机构释放就可以执行下一次循环
if (put.join() && closeCorrectFuture.join()) {
//关门完成. 执行下次换电
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; >>>>>全部执行完成, 准备执行下一次循环任务>>>>>>>>>>>>>>>>>>>>>", (runNun + 1), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
//如果当前为最后一次循环, 调整异常为false
// if(maxNum-1 == runNun){
// isError = false;
// }
}
}
//等待装完, 关门
CompletableFuture<Boolean> closeFuture =CompletableFuture.supplyAsync(() ->{
//开门完成
//开始执行拆除
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data", String.format("%s 下发关闭开合门命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
InstructionWriteUtils.closeCenDoor();
Boolean result = false;
do{
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
if(result = InstructionReadUtils.getCenRbDoorCloseStatus()){
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format("%s 开合门已关闭", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
return true;
}
}while (!result);
} catch (Exception e) {
throw new RuntimeException("关闭开合门出现异常:", e);
}
return false;
});
// Boolean finalIsError = isError;
// CompletableFuture<Boolean> closeFuture =CompletableFuture.supplyAsync(() ->{
// //开始执行拆除
// try {
// if(!finalIsError){
// WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data", String.format("%s 下发关闭开合门命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
// InstructionWriteUtils.closeCenDoor();
// Boolean result = false;
// do{
// Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
// if(result = InstructionReadUtils.getCenRbDoorCloseStatus()){
// WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format("%s 开合门已关闭", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
// return true;
// }
// }while (!result);
// }
// //开门完成
// } catch (Exception e) {
// throw new RuntimeException("关闭开合门出现异常:", e);
// }
// return false;
// });
if(closeFuture.join()){
// if(closeFuture.join()){
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",String.format("%s 执行次数{%s}全部完成", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()), maxNum))));
}
// }
}
},
@ -1248,6 +1508,9 @@ public class TestController {
@ApiOperation("全量结束")
@PostMapping("/stop/all/{category}")
@ApiLog(value = "全量结束", type = LogTypeEnum.OPERATION)
@ -1382,4 +1645,137 @@ public class TestController {
@ApiOperation("开合门测试开始")
@PostMapping("/start/door/{category}")
@ApiLog(value = "开合门测试开始", type = LogTypeEnum.OPERATION)
public Result startDoor(@PathVariable("category") final String category,
@RequestParam("maxNum") final Integer maxNum) throws InstructionException, InterruptedException {
Boolean startRun = true;
// for (String rgv : AccessStrategyUtil.getEffectiveRgvNoList()){
// if(executionBatterySwapService.executionResult(rgv)){
// Thread.sleep(1000);
// if(executionBatterySwapService.executionResult(rgv)){
// startRun = true;
// }else{
// startRun = false;
// }
// }else{
// startRun = false;
// }
// }
//检查RGV是否运作
if(startRun){
closeRunMap.put("door", new AtomicBoolean(false));
categoryRunMap.put("door",category);
CompletableFuture<Void> future = CompletableFuture.runAsync(() ->{
for (int runNun = 0; runNun < maxNum; runNun++) {
if(checkJt("door", category, runNun)){
return;
}
//执行开门
CompletableFuture<Boolean> openFuture = CompletableFuture.supplyAsync(() -> {
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format(" 执行时间:[%s]; 下发打开开合门命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
InstructionWriteUtils.openCenDoor();
Boolean result = false;
do {
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
if (result = InstructionReadUtils.getCenRbDoorOpenStatus()) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format(" 执行时间:[%s]; 开合门已打开", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
return true;
}
} while (!result);
} catch (Exception e) {
throw new RuntimeException("打开开合门出现异常:", e);
}
return false;
});
if(checkJt("door", category, runNun)){
return;
}
CompletableFuture<Boolean> closeFuture = openFuture.thenApplyAsync(openResult -> {
if (openResult) {
try {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("%s 下发关闭开合门命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
InstructionWriteUtils.closeCenDoor();
Boolean result = false;
do {
Thread.sleep(ParamUtils.getInstructionIntervalRequestMilliseconds());
if (result = InstructionReadUtils.getCenRbDoorCloseStatus()) {
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("%s 开合门已关闭", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
return true;
}
} while (!result);
//开门完成
} catch (Exception e) {
throw new RuntimeException("关闭开合门出现异常:", e);
}
return false;
}
return false;
});
if(checkJt("door", category, runNun)){
return;
}
if (closeFuture.join() && openFuture.join()) {
//关门完成. 执行下次换电
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("第[%s]次执行: 执行时间:[%s]; >>>>>全部执行完成, 准备执行下一次循环任务>>>>>>>>>>>>>>>>>>>>>", (runNun + 1), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
}
}
},
// 延迟执行器延迟 3
CompletableFuture.delayedExecutor(3, TimeUnit.SECONDS)
);
// 可选监听任务状态
future.whenComplete((unused, throwable) -> {
if (throwable instanceof java.util.concurrent.CancellationException) {
System.out.println("开始---->任务已被取消");
} else if (throwable != null) {
String message = throwable.getMessage();
if(StringUtils.isNotEmpty(message)){
message = message.replace("java.lang.RuntimeException: ","");
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data",message)));
String[] mesArray = message.split(";");
// RRG:[1] 出现异常; 机构区间为:{1}; 执行类型为:{取存}; 执行次数为:{1}; 异常信息为:{/ by zero}
CloudSendInfoUtils.sendAlarmWx(Collections.asMap("area","红旗换电站", "message", mesArray[4].replace("异常信息为:{","").replace("}","")));
}
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method","testRgv"+category,"data","时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())+ "异常信息"+throwable.getMessage())));
} else {
System.out.println("开始---->任务正常完成");
taskRgvMap.remove("door");
}
});
try {
taskRgvMap.put("door", future);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return Result.getInstance().success();
}else{
return Result.getInstance().error("当前RGV正在运行");
}
}
@ApiOperation("开合门结束")
@PostMapping("/stop/door/{category}")
@ApiLog(value = "开合门结束", type = LogTypeEnum.OPERATION)
public Result stopDoor(@PathVariable("category") final String category) throws Exception {
//检查RGV是否运作
CompletableFuture<Void> future = taskRgvMap.get("door");
if(future == null){
return Result.getInstance().success("当前任务已停止");
}
future.cancel(true);
closeRunMap.put("door", new AtomicBoolean(true));
WebSocketUtils.broadCastMessage(JSONObject.toJSONString(Collections.asMap("method", "testRgv" + category, "data", String.format("执行时间[%s]; >>>>>下发停止操作命令", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())))));
return Result.getInstance().success();
}
}

View File

@ -88,7 +88,7 @@ public interface BaseJob {
Map<String, Object> error = getExecutionBatterySwapService().executionErrorResult(rgvNo);
if(Collections.isNotEmpty(error)){
String message = JSONObject.toJSONString(error);
InstructionWriteUtils.emergencyStop(rgvNo);
InstructionWriteUtils.emergencyStop();
Result<OrderSwapDTO> running = getOrderSwapService().runningOrder();
getExecutionBatterySwapService().executionResultPush(running.getData(), swapBatteryStep, Collections.isNotEmpty(error),error);
CloudSendInfoUtils.sendAlarmWx(Collections.asMap("area", ParamUtils.findStationName(), "message", message));

View File

@ -64,8 +64,7 @@ public class CheckAlarmJob implements BaseJob{
Map<String, Object> result = getExecutionBatterySwapService().executionErrorResult(rgvNo);
if(Collections.isNotEmpty(result)){
alarmMessage.put(paramsDTO.getName().replace(":num", rgvNo), String.valueOf(result.get("errorMsg")));
TestController.getInstance().stopRgv(rgvNo, rgvNo);
CloudSendInfoUtils.sendAlarmWx(Collections.asMap("area","红旗换电站", "message", String.valueOf(result.get("errorMsg"))));
TestController.getInstance().stopRgv(rgvNo, rgvNo, String.valueOf(result.get("errorMsg")));
}
}
}else{

View File

@ -1,24 +1,41 @@
package com.evotech.hd.webserver.job.job.charging;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.evotech.hd.core.dtos.business.AccessStrategyDTO;
import com.evotech.hd.core.dtos.business.BatteryCompartmentDTO;
import com.evotech.hd.core.dtos.business.BatteryDTO;
import com.evotech.hd.core.entity.business.BatteryCompartment;
import com.evotech.hd.core.entity.business.OrderCharging;
import com.evotech.hd.entity.BatData;
import com.evotech.hd.entity.ChargingData;
import com.evotech.hd.exception.InstructionException;
import com.evotech.hd.service.MongoDBService;
import com.evotech.hd.utils.Collections;
import com.evotech.hd.utils.DateUtils;
import com.evotech.hd.webserver.job.job.BaseJob;
import com.evotech.hd.webserver.mqtt.MqttMessageHeader;
import com.evotech.hd.webserver.mqtt.MqttPublishUtils;
import com.evotech.hd.webserver.service.BatteryCompartmentService;
import com.evotech.hd.webserver.service.BatteryService;
import com.evotech.hd.webserver.service.OrderChargingService;
import com.evotech.hd.webserver.utils.AccessStrategyUtil;
import com.evotech.hd.webserver.utils.ParamUtils;
import com.evotech.hd.webserver.utils.instruction.InstructionReadUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 充电充满扫描 ChargingFullOfJob
@ -35,6 +52,7 @@ public class ChargingFullOfJob implements BaseJob {
BatteryCompartmentService batteryCompartmentService;
BatteryService batteryService;
OrderChargingService orderChargingService;
MongoDBService mongoDBService;
@PostConstruct
public void init(){
if(batteryCompartmentService == null){
@ -46,6 +64,9 @@ public class ChargingFullOfJob implements BaseJob {
if(orderChargingService == null){
orderChargingService = SpringUtil.getBean(OrderChargingService.class);
}
if(mongoDBService == null){
mongoDBService = SpringUtil.getBean(MongoDBService.class);
}
}
@ -81,5 +102,109 @@ public class ChargingFullOfJob implements BaseJob {
}
}
}
//推送云端
public void sendCloud(Integer id) throws InstructionException {
JSONObject batDataInfo1 = InstructionReadUtils.queryBattery(id);
JSONObject batDataInfo2 = InstructionReadUtils.queryBatDataInfo2(id);
JSONObject batChgInfoInfo = InstructionReadUtils.queryBSLBatChgInfo(id);
JSONObject batCellPeakInfo = InstructionReadUtils.queryBatCellPeak(id);
//查询订单
OrderCharging orderCharging = orderChargingService.getOrderChargingByBatteryCode(batDataInfo1.getString("sBatSN"));
try {
ChargingData chargingData = new ChargingData();
//当前电池电量0-100%
chargingData.setBatCode(batDataInfo1.getString("sBatSN"));
if(StringUtils.isNotEmpty(batDataInfo2.getString("BatSOC"))){
chargingData.setSoc(new BigDecimal(batDataInfo2.getString("BatSOC")).divide(new BigDecimal(10), 2, RoundingMode.DOWN).longValue());
}
//充电电量
chargingData.setChgQty(batDataInfo1.getFloat("BatResEq"));
//电池箱所在仓位
chargingData.setCabinetNo(Long.valueOf(id));
//充电模式
chargingData.setChgMode(batChgInfoInfo.getLong("ChgMode"));
//充电机输出电流
chargingData.setChgOutputCurr(batChgInfoInfo.getFloat("ChgOpCur"));
//充电机输出电压
chargingData.setChgOutputVolt(batChgInfoInfo.getFloat("ChgOpVol"));
//电池电压需求 or 电池请求电压
chargingData.setVoltDemand(batChgInfoInfo.getFloat("BatReqVol"));
//电池电流需求 or 电池请求电流
chargingData.setCurrDemand(batChgInfoInfo.getFloat("BatReqCur"));
//剩余充电时长
chargingData.setRemainderChgTime(batChgInfoInfo.getLong("RemChgTm"));
//最高单体电压
chargingData.setBatMaxVolt(batCellPeakInfo.getFloat("MaxCellVol"));
//最低单体电压
chargingData.setBatMinVolt(batCellPeakInfo.getFloat("MinCellVol"));
//最高单体温度
chargingData.setBatMaxTemp(batCellPeakInfo.getFloat("MaxTemp"));
//最低单体温度
chargingData.setBatMinTemp(batCellPeakInfo.getFloat("MinTemp"));
//流水号
chargingData.setChgSn(orderCharging.getChargingNo());
//充电开始时间
chargingData.setStartTime(orderCharging.getBeginTime());
//最高单体电压组号
chargingData.setBatMaxVoltNo(batDataInfo1.getLong("HgtCellVolGrpNum"));
chargingData.setId(String.valueOf(System.currentTimeMillis()));
chargingData.setStationCode(ParamUtils.findStationCode());
mongoDBService.save("battery_info", chargingData.getBatCode(), chargingData);
//推送云平台mq
MqttPublishUtils.sendState("chargingData", JSONUtil.parseObj(chargingData));
} catch (Exception e) {
log.error("推送云端的充电过程实时信息出现错误: {}", e.getMessage(), e);
}
JSONObject batCellVolInfo = InstructionReadUtils.queryBatCellVol(id);
JSONObject batProbeTempInfo = InstructionReadUtils.queryBatProbeTemp(id);
BatData batData =new BatData();
//电池ID batCode string 唯一识别码
batData.setBatCode(batDataInfo1.getString("sBatSN"));
//仓位号
batData.setCabinetNo(Long.valueOf(id));
//数量信息
batData.setBatCellVoltCnt(batDataInfo2.getLong("BatCellNo"));
//单体电压
batData.setBatCellVoltList(batCellVolInfo.getJSONArray("batCellVolInfo").stream().map(data->{
return Float.valueOf(String.valueOf(data));
}).collect(Collectors.toList()));
//单体电压采样时间
batData.setVoltSampleTime(new Date());
//探针温度总个数
batData.setProbeTempCnt(batDataInfo2.getLong("TempProNo"));
//探针温度
batData.setProbeTempList(batProbeTempInfo.getJSONArray("BatProbeTemp").stream().map(data->{
return Float.valueOf(String.valueOf(data));
}).collect(Collectors.toList()));
//探针温度采样时间
batData.setTempSampleTime(new Date());
//电池包SOH
batData.setSoh(batDataInfo2.getLong("BatSOH"));
//电池包总电流
batData.setBatTotalCurr(batDataInfo2.getFloat("BatTtlCur"));
//电池包正极绝缘值
batData.setBatPosiinsu(batDataInfo2.getFloat("PosInsRes"));
//电池包负极绝缘值
batData.setBatNegainsu(batDataInfo2.getFloat("NegInsRes"));
mongoDBService.save("battery_box", batData.getBatCode(), batData);
//推送云平台mq
MqttPublishUtils.sendState("batData", JSONUtil.parseObj(batData));
}
}

View File

@ -705,7 +705,7 @@ public class ExecutionBatterySwapService {
Map<String, Object> error = executionErrorResult(rgvNo);
if(Collections.isNotEmpty(error)){
String message = JSONObject.toJSONString(error);
InstructionWriteUtils.emergencyStop(rgvNo);
InstructionWriteUtils.rgvStopMove(rgvNo);
Result<OrderSwapDTO> running = orderSwapService.runningOrder();
executionResultPush(running.getData(), swapBatteryStep, Collections.isNotEmpty(error),error);
CloudSendInfoUtils.sendAlarmWx(Collections.asMap("area", ParamUtils.findStationName(), "message", message));
@ -731,6 +731,7 @@ public class ExecutionBatterySwapService {
String val = InstructionUtils.getValue(error);
//记录换电步骤, 默认成功
if(!val.equals(errorCode.getExpectedResults())){
System.out.println("错误代码为=======>" +val);
//出现异常, 记录错误信息
ParamsDTO errorInfo = ParamUtils.getParamsDTO(val);
errorInfoMap.put("errorMsg", errorInfo.getName());

View File

@ -1,5 +1,6 @@
package com.evotech.hd.webserver.mqtt;
import com.evotech.hd.webserver.utils.ParamUtils;
import lombok.Getter;
import lombok.Setter;
@ -13,7 +14,7 @@ public class MessageTopic implements Serializable {
private String businessType = "YTHD";
private String stationCode;
private String stationCode = ParamUtils.findStationCode();
private String dataDirection = "S2M";

View File

@ -46,7 +46,6 @@ public class MessageUtilService {
/**
* 获取AES秘钥和IV
* @param stationCode
* @return
*/
public JSONObject getAESKey() {

View File

@ -4,18 +4,19 @@ import lombok.Data;
@Data
public class MqttMessageHeader {
//协议版本
private String version;
//yyyy-MM-dd hh:mm:ss
private String timeStamp;
//消息Idconfirmreponse回复类报文为对应的请求或事件报文的 index
private String index;
//数据类型
private String function;
private String userId;
private String pwd;
//状态类信息上送原因:1-变化上送;2-周期上送;3-召唤上送
private int reason;
}

View File

@ -0,0 +1,37 @@
package com.evotech.hd.webserver.mqtt;
import cn.hutool.json.JSONObject;
import com.evotech.hd.webserver.config.mqtt.MqttPublishMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* MqttPublishUtils
*
* @author andy.shi
* @ClassName:MqttPublishUtils
* @date: 2025年12月13日 10:46
* @remark: 开发人员联系方式 1042025947@qq.com/微信同步
*/
@Service
public class MqttPublishUtils {
private static MqttPublishMessage mqttPublishMessage;
@Autowired
public MqttPublishUtils(MqttPublishMessage mqttPublishMessage) {
this.mqttPublishMessage = mqttPublishMessage;
}
public static void sendState(String messageType, JSONObject dataBody){
MessageTopic topic = new MessageTopic();
topic.setMessageType("state");
MqttMessageHeader header = new MqttMessageHeader();
header.setTimeStamp(String.valueOf(System.currentTimeMillis()));
header.setIndex("1");
header.setFunction(messageType);
mqttPublishMessage.publishAESMessage(topic,header, dataBody);
}
}

View File

@ -0,0 +1,21 @@
package com.evotech.hd.webserver.mqtt;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.Data;
@Data
//MQTT消息
public class MyMqttMessage {
//MQTT消息头
private MqttMessageHeader header;
//MQTT消息体
private JSONObject dataBody;
@Override
public String toString() {
return JSONUtil.toJsonStr(this);
}
}

View File

@ -35,4 +35,6 @@ public interface OrderChargingService extends IService<OrderCharging> {
OrderCharging addOrderChargingByBatteryCompartment(BatteryCompartment batteryCompartment, String strategyInfo);
Boolean OrderChargingCompleted(BatteryCompartmentDTO batteryCompartmentDTO);
OrderCharging getOrderChargingByBatteryCode(String batteryCode);
}

View File

@ -1,5 +1,6 @@
package com.evotech.hd.webserver.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -78,4 +79,9 @@ public class OrderChargingServiceImpl extends ServiceImpl<OrderChargingMapper, O
saveOrUpdate(orderCharging);
return true;
}
@Override
public OrderCharging getOrderChargingByBatteryCode(String batteryCode) {
return getOne(new LambdaQueryWrapper<OrderCharging>().eq(OrderCharging::getBatteryCode, batteryCode), false);
}
}

View File

@ -368,6 +368,13 @@ public class ParamUtils {
public static ParamsDTO getBatCellVol(){
return getParamsDTO("BSL_BatCellVol");
}
/***
* 获取电池单体极值
* @return
*/
public static ParamsDTO getBatCellPeak(){
return getParamsDTO("BSL_BatCellPeak");
}
/***
* 获取电池数据信息2
* @return

View File

@ -98,6 +98,14 @@ public class InstructionReadUtils {
ParamsDTO paramsDTO = ParamUtils.getBatCellVol();
return InstructionUtils.getJson(execution(paramsDTO, String.valueOf(batteryCompartmentNo)));
}
/** 电池单体极值
* @param batteryCompartmentNo
* @return
*/
public static JSONObject queryBatCellPeak(Integer batteryCompartmentNo) throws InstructionException {
ParamsDTO paramsDTO = ParamUtils.getBatCellPeak();
return InstructionUtils.getJson(execution(paramsDTO, String.valueOf(batteryCompartmentNo)));
}
/*** 检查电池仓是否存在电池
* @param: batteryCompartmentNo
@ -405,19 +413,25 @@ public class InstructionReadUtils {
return InstructionUtils.getBoolean(paramsDTO, executionInteger(paramsDTO, batteryCompartmentNo));
}
/***查询当前RGV是否在互斥区
/***检查节拍执行结果
*/
public static Boolean getCenRbDoorOpenStatus() throws InstructionException {
ParamsDTO paramsDTO = ParamUtils.getParamsDTO(ParamSysConstants.CEN_RB_DOOR_OPEN_STATUS);
public static Boolean getCenOpenExecutionResult() throws InstructionException {
ParamsDTO paramsDTO = ParamUtils.getCenActMoving();
return InstructionUtils.getBoolean(paramsDTO, executionInteger(paramsDTO, null));
}
/***查询当前RGV是否在互斥区
/***检查当前开合门打开状态
*/
public static Boolean getCenRbDoorOpenStatus() throws InstructionException {
ParamsDTO paramsDTO = ParamUtils.getParamsDTO(ParamSysConstants.CEN_RB_DOOR_OPEN_STATUS);
return InstructionUtils.getBoolean(paramsDTO, executionInteger(paramsDTO, null)) && getCenOpenExecutionResult();
}
/***检查当前开合门关闭状态
*/
public static Boolean getCenRbDoorCloseStatus() throws InstructionException {
ParamsDTO paramsDTO = ParamUtils.getParamsDTO(ParamSysConstants.CEN_RB_DOOR_CLOSE_STATUS);
return InstructionUtils.getBoolean(paramsDTO, executionInteger(paramsDTO, null));
return InstructionUtils.getBoolean(paramsDTO, executionInteger(paramsDTO, null)) && getCenOpenExecutionResult();
}

View File

@ -117,8 +117,8 @@ public class InstructionWriteUtils {
}
/** 急停
*/
public static void emergencyStop(String rgvNo) throws Exception {
executeInstructions(runningInstructionsDetailService.findDictDetailDTOByTypeCode(InstructionConstants.EMERGENCY_BIN), rgvNo, null, false);
public static void emergencyStop() throws Exception {
executeInstructions(runningInstructionsDetailService.findDictDetailDTOByTypeCode(InstructionConstants.EMERGENCY_BIN), null, null, false);
}
/** 消防动作

View File

@ -208,6 +208,7 @@ public class CloudSendInfoUtils {
post.setHeader(key, headersMap.get(key));
}
String result = EntityUtils.toString(client.execute(post).getEntity(), "UTF-8");
log.info("doPost请求== 请求接口 ===={}, 请求参数 ===={}, 请求headers ===={}, 请求结果====={}", url, json, JSON.toJSONString(headersMap), result);
jsonObject = JSONObject.parseObject(result);
} catch (Exception e) {
e.printStackTrace();

View File

@ -20,6 +20,8 @@ mqtt:
broker: tcp://192.168.16.128:1883 # MQTT服务器地址如Mosquitto默认端口1883
client-id: springboot-mqtt-${random.value} # 客户端ID添加随机数确保唯一
username: admin # 可选MQTT服务器认证用户名
password: hbyt123456 # 可选MQTT服务器认证密码
password: hbyt12345 # 可选MQTT服务器认证密码
keep-alive: 60 # 心跳间隔(秒)
connection-timeout: 30 # 连接超时(秒)
connection-timeout: 30 # 连接超时(秒)
retry-interval: 10 # 重试间隔默认10秒
max-retry: 5 # 最大重试次数

View File

@ -22,4 +22,6 @@ mqtt:
username: admin # 可选MQTT服务器认证用户名
password: hbyt!123 # 可选MQTT服务器认证密码
keep-alive: 60 # 心跳间隔(秒)
connection-timeout: 30 # 连接超时(秒)
connection-timeout: 30 # 连接超时(秒)
retry-interval: 10 # 重试间隔默认10秒
max-retry: 5 # 最大重试次数