Compare commits

...

30 Commits

Author SHA1 Message Date
7153c00d0c 重构 2026-04-16 23:11:25 +08:00
2b3be8636f 1.单体电池批量新增修改 2026-04-16 19:49:56 +08:00
5eb9b455a5 1.单体电池批量新增修改 2026-04-15 22:47:17 +08:00
4947f085c7 增加业务报表备注功能,可以根据业务设计开发,目前电表报表与收益报表均有备注列可以修改 2026-04-14 16:44:31 +08:00
5460aadf6c 增加业务报表备注功能,可以根据业务设计开发,目前电表报表与收益报表均有备注列可以修改 2026-04-14 16:11:23 +08:00
79a8040446 1.一周充放曲线改为了时间聚合柱状图。
2.PCS最高温度修复bug展示多PCS设备的数据
3.PCS的状态根据状态枚举映射配置的内容显示
4.BMS的总览,增加工作状态、与PCS通讯、与EMS通讯的配置,及关联展示
5.增加批量导入单体电池点位的功能
6.修复计算点可能会出现id与code在一个池子内的问题,再次计算后数据正常
7.计算点增加小数位限制的功能,实时计算与7天历史接口都已经按照配置的小数位进行限制
8.统计报表中的功率曲线改为了按照分钟显示
9.功率曲线出现断点的问题是因为数据计算太密集了导致的,增加了前端连线不断的显示
10.PCS和电池堆的曲线与配置增加了关联设备显示
11.点位映射中的电池温度,增加了多设备
12.收益报表增加升序排列,合并当月所有合计
13.增加业务报表备注功能,可以根据业务设计开发,目前电表报表与收益报表均有备注列可以修改
2026-04-12 15:16:57 +08:00
ed36292c94 Merge pull request 'dev' (#3) from dev into waibao
Reviewed-on: #3
2026-04-09 01:31:05 +00:00
515f440298 重构 2026-03-23 13:47:20 +08:00
e4cfd15cb4 重构 2026-03-18 10:06:42 +08:00
5ab2cb8f90 重构 2026-02-22 18:59:40 +08:00
4e7d387edf 重构 2026-02-17 21:42:59 +08:00
49ed5f218a 重构 2026-02-16 14:46:27 +08:00
8806473080 重构 2026-02-16 13:41:35 +08:00
71d0b0f609 重构 2026-02-15 16:02:06 +08:00
6253fb6b2d 临时修改 2026-02-13 21:41:23 +08:00
21673ecd1e 临时修改 2026-02-12 21:07:41 +08:00
66de6fe77c Merge remote-tracking branch 'origin/dev' into dev
# Conflicts:
#	ems-system/src/main/java/com/xzzn/ems/service/impl/DeviceDataProcessServiceImpl.java
#	ems-system/src/main/java/com/xzzn/ems/service/impl/GeneralQueryServiceImpl.java
2026-02-12 21:06:36 +08:00
63ed2641ee 临时修改 2026-02-12 21:05:11 +08:00
5d5a7137fc Merge pull request 'dev' (#2) from dev into main
Reviewed-on: #2
2026-02-11 01:55:45 +00:00
zq
6545b4f947 修改 2026-01-28 19:26:15 +08:00
zq
8a44009c42 修改设备监控电表类型设备曲线不展示问题 2026-01-28 19:21:30 +08:00
zq
2b22b70baa 新增电表报表、收益报表导出功能 2026-01-28 15:59:30 +08:00
zq
5a86769b40 统计报表-功率曲线按照分钟展示数据 2026-01-27 19:15:55 +08:00
zq
eeccd19f0a 设备监控页面-设备告警铃铛数由查询告警点位数据改为查询设备故障告警 2026-01-27 17:54:11 +08:00
zq
d19f07c4e8 modbus本地设备数据读取失败,告警等级修改为“一般”,读到数据后自恢复 2026-01-27 17:37:42 +08:00
zq
9f2c303047 topic设备数据消息5次没有数据内容则增加告警,告警等级修改为“一般”,读到数据后自恢复 2026-01-27 17:26:11 +08:00
zq
7199677d7b 解决null值转换为字符串 "null"问题 2026-01-27 17:23:32 +08:00
zq
4b58838d5d 解决null值转换为字符串 "null"问题 2026-01-27 16:55:04 +08:00
zq
14904ea6b2 站点首页-设备告警仅存在严重、紧急告警时提醒 2026-01-27 16:49:20 +08:00
zq
5225f03195 站点首页-当日功率曲线按照分钟展示数据 2026-01-27 16:47:48 +08:00
151 changed files with 17152 additions and 3865 deletions

View File

@ -55,4 +55,21 @@ public class EmsAlarmRecordsController extends BaseController
} }
} }
/**
* 关闭告警
*/
@PostMapping("/closeAlarm")
public AjaxResult closeAlarm(@RequestBody EmsAlarmRecords emsAlarmRecords)
{
Long id = emsAlarmRecords.getId();
if (id == null) {
return error("告警id不能为空");
}
String result = iEmsAlarmRecordsService.closeAlarm(id, getUserId());
if ("success".equals(result) || "告警已关闭".equals(result)) {
return AjaxResult.success("操作成功");
}
return error(result);
}
} }

View File

@ -0,0 +1,61 @@
package com.xzzn.web.controller.ems;
import com.xzzn.common.annotation.Log;
import com.xzzn.common.core.controller.BaseController;
import com.xzzn.common.core.domain.AjaxResult;
import com.xzzn.common.core.page.TableDataInfo;
import com.xzzn.common.enums.BusinessType;
import com.xzzn.ems.domain.EmsDailyChargeData;
import com.xzzn.ems.service.IEmsDailyChargeDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 站点管理-充放电修正 Controller
*/
@RestController
@RequestMapping("/ems/dailyChargeData")
public class EmsDailyChargeDataController extends BaseController {
@Autowired
private IEmsDailyChargeDataService emsDailyChargeDataService;
@GetMapping("/list")
public TableDataInfo list(EmsDailyChargeData emsDailyChargeData) {
startPage();
List<EmsDailyChargeData> list = emsDailyChargeDataService.selectEmsDailyChargeDataList(emsDailyChargeData);
return getDataTable(list);
}
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
return success(emsDailyChargeDataService.selectEmsDailyChargeDataById(id));
}
@Log(title = "站点管理-充放电修正", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody EmsDailyChargeData emsDailyChargeData) {
return toAjax(emsDailyChargeDataService.insertEmsDailyChargeData(emsDailyChargeData, getUsername()));
}
@Log(title = "站点管理-充放电修正", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody EmsDailyChargeData emsDailyChargeData) {
return toAjax(emsDailyChargeDataService.updateEmsDailyChargeData(emsDailyChargeData, getUsername()));
}
@Log(title = "站点管理-充放电修正", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(emsDailyChargeDataService.deleteEmsDailyChargeDataByIds(ids));
}
}

View File

@ -0,0 +1,61 @@
package com.xzzn.web.controller.ems;
import com.xzzn.common.annotation.Log;
import com.xzzn.common.core.controller.BaseController;
import com.xzzn.common.core.domain.AjaxResult;
import com.xzzn.common.core.page.TableDataInfo;
import com.xzzn.common.enums.BusinessType;
import com.xzzn.ems.domain.EmsDailyEnergyData;
import com.xzzn.ems.service.IEmsDailyEnergyDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 站点管理-数据修正 Controller
*/
@RestController
@RequestMapping("/ems/dailyEnergyData")
public class EmsDailyEnergyDataController extends BaseController {
@Autowired
private IEmsDailyEnergyDataService emsDailyEnergyDataService;
@GetMapping("/list")
public TableDataInfo list(EmsDailyEnergyData emsDailyEnergyData) {
startPage();
List<EmsDailyEnergyData> list = emsDailyEnergyDataService.selectEmsDailyEnergyDataList(emsDailyEnergyData);
return getDataTable(list);
}
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
return success(emsDailyEnergyDataService.selectEmsDailyEnergyDataById(id));
}
@Log(title = "站点管理-数据修正", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody EmsDailyEnergyData emsDailyEnergyData) {
return toAjax(emsDailyEnergyDataService.insertEmsDailyEnergyData(emsDailyEnergyData, getUsername()));
}
@Log(title = "站点管理-数据修正", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody EmsDailyEnergyData emsDailyEnergyData) {
return toAjax(emsDailyEnergyDataService.updateEmsDailyEnergyData(emsDailyEnergyData, getUsername()));
}
@Log(title = "站点管理-数据修正", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(emsDailyEnergyDataService.deleteEmsDailyEnergyDataByIds(ids));
}
}

View File

@ -0,0 +1,51 @@
package com.xzzn.web.controller.ems;
import com.xzzn.common.annotation.Log;
import com.xzzn.common.core.controller.BaseController;
import com.xzzn.common.core.domain.AjaxResult;
import com.xzzn.common.core.page.TableDataInfo;
import com.xzzn.common.enums.BusinessType;
import com.xzzn.ems.domain.EmsPointCalcConfig;
import com.xzzn.ems.service.IEmsPointCalcConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/ems/pointCalcConfig")
public class EmsPointCalcConfigController extends BaseController {
@Autowired
private IEmsPointCalcConfigService pointCalcConfigService;
@GetMapping("/list")
public TableDataInfo list(EmsPointCalcConfig pointCalcConfig) {
startPage();
List<EmsPointCalcConfig> list = pointCalcConfigService.selectPointCalcConfigList(pointCalcConfig);
return getDataTable(list);
}
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
return success(pointCalcConfigService.selectPointCalcConfigById(id));
}
@Log(title = "计算点配置", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody EmsPointCalcConfig pointCalcConfig) {
return toAjax(pointCalcConfigService.insertPointCalcConfig(pointCalcConfig, getUsername()));
}
@Log(title = "计算点配置", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody EmsPointCalcConfig pointCalcConfig) {
return toAjax(pointCalcConfigService.updatePointCalcConfig(pointCalcConfig, getUsername()));
}
@Log(title = "计算点配置", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(pointCalcConfigService.deletePointCalcConfigByIds(ids));
}
}

View File

@ -0,0 +1,103 @@
package com.xzzn.web.controller.ems;
import com.xzzn.common.annotation.Log;
import com.xzzn.common.core.controller.BaseController;
import com.xzzn.common.core.domain.AjaxResult;
import com.xzzn.common.core.page.TableDataInfo;
import com.xzzn.common.enums.BusinessType;
import com.xzzn.ems.domain.EmsPointConfig;
import com.xzzn.ems.domain.vo.ImportPointTemplateRequest;
import com.xzzn.ems.domain.vo.PointConfigCurveRequest;
import com.xzzn.ems.domain.vo.PointConfigGenerateRecentRequest;
import com.xzzn.ems.domain.vo.PointConfigLatestValueRequest;
import com.xzzn.ems.service.IEmsPointConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import java.util.List;
@RestController
@RequestMapping("/ems/pointConfig")
public class EmsPointConfigController extends BaseController {
@Autowired
private IEmsPointConfigService pointConfigService;
@GetMapping("/list")
public TableDataInfo list(EmsPointConfig pointConfig) {
startPage();
List<EmsPointConfig> list = pointConfigService.selectPointConfigList(pointConfig);
return getDataTable(list);
}
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) {
return success(pointConfigService.selectPointConfigById(id));
}
@Log(title = "点位配置", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody EmsPointConfig pointConfig) {
return toAjax(pointConfigService.insertPointConfig(pointConfig, getUsername()));
}
@Log(title = "点位配置", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody EmsPointConfig pointConfig) {
return toAjax(pointConfigService.updatePointConfig(pointConfig, getUsername()));
}
@Log(title = "点位配置", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
return toAjax(pointConfigService.deletePointConfigByIds(ids));
}
@Log(title = "点位配置", businessType = BusinessType.IMPORT)
@PostMapping("/importTemplateBySite")
public AjaxResult importTemplateBySite(@Valid @RequestBody ImportPointTemplateRequest request) {
return success(pointConfigService.importTemplateBySite(request, getUsername()));
}
@Log(title = "点位配置", businessType = BusinessType.IMPORT)
@PostMapping("/importCsv")
public AjaxResult importCsv(@RequestParam String siteId,
@RequestParam(required = false) Boolean overwrite,
@RequestParam("file") MultipartFile file) {
return success(pointConfigService.importCsvBySite(siteId, overwrite, file, getUsername()));
}
@GetMapping("/registerAddress")
public AjaxResult getRegisterAddress(@RequestParam String siteId,
@RequestParam String deviceCategory,
@RequestParam String deviceId,
@RequestParam String dataKey) {
return success(pointConfigService.getRegisterAddress(siteId, deviceCategory, deviceId, dataKey));
}
@PostMapping("/latestValues")
public AjaxResult latestValues(@RequestBody PointConfigLatestValueRequest request) {
return success(pointConfigService.getLatestValues(request));
}
@PostMapping("/curve")
public AjaxResult curve(@RequestBody PointConfigCurveRequest request) {
return success(pointConfigService.getCurveData(request));
}
@Log(title = "点位配置", businessType = BusinessType.INSERT)
@PostMapping("/generateRecent7Days")
public AjaxResult generateRecent7Days(@Valid @RequestBody PointConfigGenerateRecentRequest request) {
return success(pointConfigService.generateRecent7DaysData(request));
}
}

View File

@ -7,8 +7,12 @@ import javax.validation.Valid;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.xzzn.common.annotation.Log; import com.xzzn.common.annotation.Log;
@ -19,6 +23,7 @@ import com.xzzn.ems.domain.EmsPointMatch;
import com.xzzn.ems.domain.vo.DevicePointMatchExportVo; import com.xzzn.ems.domain.vo.DevicePointMatchExportVo;
import com.xzzn.ems.domain.vo.DevicePointMatchVo; import com.xzzn.ems.domain.vo.DevicePointMatchVo;
import com.xzzn.ems.domain.vo.ImportPointDataRequest; import com.xzzn.ems.domain.vo.ImportPointDataRequest;
import com.xzzn.ems.domain.vo.ImportPointTemplateRequest;
import com.xzzn.ems.service.IEmsPointMatchService; import com.xzzn.ems.service.IEmsPointMatchService;
import com.xzzn.common.utils.poi.ExcelUtil; import com.xzzn.common.utils.poi.ExcelUtil;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -49,6 +54,58 @@ public class EmsPointMatchController extends BaseController
util.exportExcel(response, list, "点位匹配数据"); util.exportExcel(response, list, "点位匹配数据");
} }
/**
* 查询点位配置列表
*/
@GetMapping("/list")
public com.xzzn.common.core.page.TableDataInfo list(EmsPointMatch emsPointMatch)
{
startPage();
List<EmsPointMatch> list = emsPointMatchService.selectPointMatchConfigList(emsPointMatch);
return getDataTable(list);
}
/**
* 查询点位配置详情
*/
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(emsPointMatchService.selectPointMatchById(id));
}
/**
* 新增点位配置
*/
@Log(title = "点位配置", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody EmsPointMatch emsPointMatch)
{
emsPointMatch.setCreateBy(getUsername());
return toAjax(emsPointMatchService.insertPointMatch(emsPointMatch));
}
/**
* 修改点位配置
*/
@Log(title = "点位配置", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody EmsPointMatch emsPointMatch)
{
emsPointMatch.setUpdateBy(getUsername());
return toAjax(emsPointMatchService.updatePointMatch(emsPointMatch));
}
/**
* 删除点位配置
*/
@Log(title = "点位配置", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(emsPointMatchService.deletePointMatchByIds(ids));
}
/** /**
* 上传点位清单 * 上传点位清单
* @param file * @param file
@ -85,4 +142,18 @@ public class EmsPointMatchController extends BaseController
} }
} }
/**
* 根据站点导入模板点位配置
* @param request 请求参数
* @return 导入结果
*/
@PreAuthorize("@ss.hasPermi('system:user:import')")
@Log(title = "点位配置", businessType = BusinessType.IMPORT)
@PostMapping("/importTemplateBySite")
public AjaxResult importTemplateBySite(@Valid @RequestBody ImportPointTemplateRequest request)
{
String message = emsPointMatchService.importTemplateBySite(request, getUsername());
return success(message);
}
} }

View File

@ -8,19 +8,21 @@ import com.xzzn.common.core.page.TableDataInfo;
import com.xzzn.common.enums.BusinessType; import com.xzzn.common.enums.BusinessType;
import com.xzzn.common.utils.file.FileUploadUtils; import com.xzzn.common.utils.file.FileUploadUtils;
import com.xzzn.common.utils.file.MimeTypeUtils; import com.xzzn.common.utils.file.MimeTypeUtils;
import com.xzzn.common.utils.poi.ExcelUtil;
import com.xzzn.ems.domain.EmsSiteSetting; import com.xzzn.ems.domain.EmsSiteSetting;
import com.xzzn.ems.domain.vo.DeviceUpdateRequest; import com.xzzn.ems.domain.vo.DeviceUpdateRequest;
import com.xzzn.ems.domain.vo.DevicesSettingVo; import com.xzzn.ems.domain.vo.DevicesSettingVo;
import com.xzzn.ems.domain.vo.PointDataRequest; import com.xzzn.ems.domain.vo.PointDataRequest;
import com.xzzn.ems.domain.vo.PointQueryResponse; import com.xzzn.ems.domain.vo.PointQueryResponse;
import com.xzzn.ems.domain.vo.SiteDeviceListVo; import com.xzzn.ems.domain.vo.SiteDeviceListVo;
import com.xzzn.ems.domain.vo.SiteMonitorProjectPointMappingSaveRequest;
import com.xzzn.ems.domain.vo.SingleBatteryConfigInitRequest;
import com.xzzn.ems.domain.vo.SingleBatteryConfigInitResultVo;
import com.xzzn.ems.domain.vo.SingleBatteryMonitorImportResultVo;
import com.xzzn.ems.domain.vo.SingleBatteryMonitorImportRowVo;
import com.xzzn.ems.domain.vo.WorkStatusEnumMappingSaveRequest;
import com.xzzn.ems.service.IEmsDeviceSettingService; import com.xzzn.ems.service.IEmsDeviceSettingService;
import com.xzzn.ems.service.IEmsSiteService; import com.xzzn.ems.service.IEmsSiteService;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
@ -33,14 +35,17 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
/** /**
* * 绔欑偣閰嶇疆
* 站点配置
*
*/ */
@RestController @RestController
@RequestMapping("/ems/siteConfig") @RequestMapping("/ems/siteConfig")
public class EmsSiteConfigController extends BaseController{ public class EmsSiteConfigController extends BaseController {
@Autowired @Autowired
private IEmsSiteService iEmsSiteService; private IEmsSiteService iEmsSiteService;
@ -48,158 +53,169 @@ public class EmsSiteConfigController extends BaseController{
@Autowired @Autowired
private IEmsDeviceSettingService iEmsDeviceSettingService; private IEmsDeviceSettingService iEmsDeviceSettingService;
/**
* 获取站点列表
*/
@GetMapping("/getSiteInfoList") @GetMapping("/getSiteInfoList")
public TableDataInfo getSiteInfoList(@RequestParam String siteName, @RequestParam String startTime, @RequestParam String endTime) public TableDataInfo getSiteInfoList(@RequestParam String siteName, @RequestParam String startTime, @RequestParam String endTime) {
{
startPage(); startPage();
List<EmsSiteSetting> list = iEmsSiteService.getAllSiteInfoList(siteName,startTime,endTime); List<EmsSiteSetting> list = iEmsSiteService.getAllSiteInfoList(siteName, startTime, endTime);
return getDataTable(list); return getDataTable(list);
} }
/** @PostMapping("/addSite")
* 获取设备列表-分页 public AjaxResult addSite(@RequestBody EmsSiteSetting emsSiteSetting) {
*/ emsSiteSetting.setCreateBy(getUsername());
return toAjax(iEmsSiteService.addSite(emsSiteSetting));
}
@PostMapping("/updateSite")
public AjaxResult updateSite(@RequestBody EmsSiteSetting emsSiteSetting) {
emsSiteSetting.setUpdateBy(getUsername());
return toAjax(iEmsSiteService.updateSite(emsSiteSetting));
}
@GetMapping("/getDeviceInfoList") @GetMapping("/getDeviceInfoList")
public TableDataInfo getDeviceInfoList(@RequestParam(value = "siteId", required = false) String siteId, public TableDataInfo getDeviceInfoList(@RequestParam(value = "siteId", required = false) String siteId,
@RequestParam(value = "deviceCategory", required = false) String deviceCategory) @RequestParam(value = "deviceCategory", required = false) String deviceCategory) {
{
startPage(); startPage();
List<SiteDeviceListVo> list = iEmsSiteService.getAllDeviceListNoDisp(siteId, deviceCategory); List<SiteDeviceListVo> list = iEmsSiteService.getAllDeviceListNoDisp(siteId, deviceCategory);
return getDataTable(list); return getDataTable(list);
} }
/**
* 获取设备详细信息
*/
@GetMapping("/getDeviceDetailInfo") @GetMapping("/getDeviceDetailInfo")
public AjaxResult getDeviceDetailInfo(@RequestParam Long id) public AjaxResult getDeviceDetailInfo(@RequestParam Long id) {
{
return success(iEmsDeviceSettingService.getDeviceDetailInfo(id)); return success(iEmsDeviceSettingService.getDeviceDetailInfo(id));
} }
/**
* 获取设备列表-不分页
*/
@GetMapping("/getDeviceList") @GetMapping("/getDeviceList")
public AjaxResult getDeviceInfoList2(@RequestParam String siteId) public AjaxResult getDeviceInfoList2(@RequestParam String siteId) {
{
return success(iEmsSiteService.getAllDeviceList(siteId, null)); return success(iEmsSiteService.getAllDeviceList(siteId, null));
} }
/**
* 获取所有设备类别
*/
@GetMapping("/getDeviceCategory") @GetMapping("/getDeviceCategory")
public AjaxResult getDeviceCategory() public AjaxResult getDeviceCategory() {
{
return success(iEmsDeviceSettingService.getDeviceCategory()); return success(iEmsDeviceSettingService.getDeviceCategory());
} }
/**
* 新增设备
*/
@PostMapping("/addDevice") @PostMapping("/addDevice")
public AjaxResult addDevice(@RequestBody DevicesSettingVo devicesSetting) public AjaxResult addDevice(@RequestBody DevicesSettingVo devicesSetting) {
{
int result = iEmsDeviceSettingService.addDevice(devicesSetting); int result = iEmsDeviceSettingService.addDevice(devicesSetting);
if (result > 0) { if (result > 0) {
return AjaxResult.success(result); return AjaxResult.success(result);
} else {
return AjaxResult.error("该设备已存在");
} }
return AjaxResult.error("璇ヨ澶囧凡瀛樺湪");
} }
/**
* 上传设备图片
*/
@PostMapping("/uploadDeviceImg") @PostMapping("/uploadDeviceImg")
public AjaxResult uploadDeviceImg(@RequestParam("avatarfile") MultipartFile file) throws Exception public AjaxResult uploadDeviceImg(@RequestParam("avatarfile") MultipartFile file) throws Exception {
{
if (!file.isEmpty()) { if (!file.isEmpty()) {
String avatar = FileUploadUtils.upload(RuoYiConfig.getDevicePath(), file, MimeTypeUtils.IMAGE_EXTENSION); String avatar = FileUploadUtils.upload(RuoYiConfig.getDevicePath(), file, MimeTypeUtils.IMAGE_EXTENSION);
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
ajax.put("imgUrl", avatar); ajax.put("imgUrl", avatar);
return ajax; return ajax;
} }
return error("上传图片异常,请联系管理员"); return error("涓婁紶鍥剧墖寮傚父锛岃鑱旂郴绠$悊鍛?");
} }
/**
* 修改Modbus设备配置
*/
@PostMapping("/updateDevice") @PostMapping("/updateDevice")
public AjaxResult updateDevice(@RequestBody DevicesSettingVo emsDevicesSetting) public AjaxResult updateDevice(@RequestBody DevicesSettingVo emsDevicesSetting) {
{
int result = iEmsDeviceSettingService.updateDevice(emsDevicesSetting); int result = iEmsDeviceSettingService.updateDevice(emsDevicesSetting);
if (result > 0) { if (result > 0) {
return AjaxResult.success(result); return AjaxResult.success(result);
} else if (result == -1) { } else if (result == -1) {
return AjaxResult.error("数据不存在"); return AjaxResult.error("鏁版嵁涓嶅瓨鍦?");
} else if (result == -2) { } else if (result == -2) {
return AjaxResult.error("该设备已存在"); return AjaxResult.error("璇ヨ澶囧凡瀛樺湪");
} }
return AjaxResult.success(result); return AjaxResult.success(result);
} }
/**
* 删除Modbus设备配置
*/
@DeleteMapping("/deleteService/{id}") @DeleteMapping("/deleteService/{id}")
public AjaxResult deleteService(@PathVariable Long id) public AjaxResult deleteService(@PathVariable Long id) {
{
return toAjax(iEmsDeviceSettingService.deleteEmsDevicesSettingById(id)); return toAjax(iEmsDeviceSettingService.deleteEmsDevicesSettingById(id));
} }
/**
* 单个站点单个设备点位查询-点位清单
*/
@GetMapping("/getDevicePointList") @GetMapping("/getDevicePointList")
public TableDataInfo getDevicePointList(@Validated PointDataRequest request) public TableDataInfo getDevicePointList(@Validated PointDataRequest request) {
{
List<PointQueryResponse> result = iEmsDeviceSettingService.getSingleSiteDevicePoints(request); List<PointQueryResponse> result = iEmsDeviceSettingService.getSingleSiteDevicePoints(request);
return getDataTable2(result); return getDataTable2(result);
} }
/**
* 获取指定站点下的所有设备类别
*/
@GetMapping("/getSiteAllDeviceCategory") @GetMapping("/getSiteAllDeviceCategory")
public AjaxResult getSiteAllDeviceCategory(String siteId) public AjaxResult getSiteAllDeviceCategory(String siteId) {
{
return success(iEmsDeviceSettingService.getSiteAllDeviceCategory(siteId)); return success(iEmsDeviceSettingService.getSiteAllDeviceCategory(siteId));
} }
/**
* 根据设备类别获取父类的设备id
*/
@GetMapping("/getParentDeviceId") @GetMapping("/getParentDeviceId")
public AjaxResult getParentDeviceId(@RequestParam String siteId, @RequestParam String deviceCategory) public AjaxResult getParentDeviceId(@RequestParam String siteId, @RequestParam String deviceCategory) {
{
return success(iEmsSiteService.getParentCategoryDeviceId(siteId, deviceCategory)); return success(iEmsSiteService.getParentCategoryDeviceId(siteId, deviceCategory));
} }
/**
* 获取指定站点下的指定设备类型的设备
*/
@GetMapping("/getDeviceListBySiteAndCategory") @GetMapping("/getDeviceListBySiteAndCategory")
public AjaxResult getDeviceListBySiteAndCategory(String siteId,String deviceCategory) public AjaxResult getDeviceListBySiteAndCategory(String siteId, String deviceCategory) {
{
return success(iEmsDeviceSettingService.getDeviceListBySiteAndCategory(siteId, deviceCategory)); return success(iEmsDeviceSettingService.getDeviceListBySiteAndCategory(siteId, deviceCategory));
} }
/** @GetMapping("/getSingleMonitorProjectPointMapping")
* PCS设备开关机 public AjaxResult getSingleMonitorProjectPointMapping(@RequestParam String siteId) {
*/ return success(iEmsDeviceSettingService.getSiteMonitorProjectPointMapping(siteId));
}
@PostMapping("/saveSingleMonitorProjectPointMapping")
public AjaxResult saveSingleMonitorProjectPointMapping(@RequestBody SiteMonitorProjectPointMappingSaveRequest request) {
int rows = iEmsDeviceSettingService.saveSiteMonitorProjectPointMapping(request, getUsername());
return AjaxResult.success(rows);
}
@GetMapping("/getSingleMonitorWorkStatusEnumMappings")
public AjaxResult getSingleMonitorWorkStatusEnumMappings(@RequestParam String siteId) {
return success(iEmsDeviceSettingService.getSiteWorkStatusEnumMappings(siteId));
}
@PostMapping("/saveSingleMonitorWorkStatusEnumMappings")
public AjaxResult saveSingleMonitorWorkStatusEnumMappings(@RequestBody WorkStatusEnumMappingSaveRequest request) {
int rows = iEmsDeviceSettingService.saveSiteWorkStatusEnumMappings(request.getSiteId(), request.getMappings(), getUsername());
return AjaxResult.success(rows);
}
@GetMapping("/downloadSingleBatteryMonitorImportTemplate")
public void downloadSingleBatteryMonitorImportTemplate(HttpServletResponse response) {
ExcelUtil<SingleBatteryMonitorImportRowVo> util = new ExcelUtil<>(SingleBatteryMonitorImportRowVo.class);
util.importTemplateExcel(response, "单体电池导入模板", "单体电池导入模板");
}
@PostMapping("/importSingleBatteryMonitorMappings")
public AjaxResult importSingleBatteryMonitorMappings(@RequestParam("siteId") String siteId,
@RequestParam("file") MultipartFile file) throws Exception {
ExcelUtil<SingleBatteryMonitorImportRowVo> util = new ExcelUtil<>(SingleBatteryMonitorImportRowVo.class);
List<SingleBatteryMonitorImportRowVo> rowList = util.importExcel(file.getInputStream(), 1);
if (rowList == null) {
return AjaxResult.error("导入失败:未读取到任何数据,请检查 Excel 文件内容");
}
List<SingleBatteryMonitorImportRowVo> validRowList = new ArrayList<>();
for (int i = 0; i < rowList.size(); i++) {
SingleBatteryMonitorImportRowVo row = rowList.get(i);
if (row == null) {
continue;
}
row.setRowNum(i + 3);
validRowList.add(row);
}
if (validRowList.isEmpty()) {
return AjaxResult.error("导入失败:未识别到有效数据,请使用系统导出的最新模板,并保持表头名称不变");
}
SingleBatteryMonitorImportResultVo result = iEmsDeviceSettingService.importSingleBatteryMonitorMappings(siteId, validRowList, getUsername());
return AjaxResult.success(result);
}
@PostMapping("/initializeSingleBatteryMonitorMappings")
public AjaxResult initializeSingleBatteryMonitorMappings(@RequestBody SingleBatteryConfigInitRequest request) {
SingleBatteryConfigInitResultVo result = iEmsDeviceSettingService.initializeSingleBatteryMonitorMappings(request, getUsername());
return AjaxResult.success(result);
}
// @PreAuthorize("@ss.hasPermi('system:device:onAndOff')") // @PreAuthorize("@ss.hasPermi('system:device:onAndOff')")
@Log(title = "开关机", businessType = BusinessType.UPDATE) @Log(title = "寮€鍏虫満", businessType = BusinessType.UPDATE)
@PostMapping("/updateDeviceStatus") @PostMapping("/updateDeviceStatus")
public AjaxResult updateDeviceStatus(@Valid @RequestBody DeviceUpdateRequest request) public AjaxResult updateDeviceStatus(@Valid @RequestBody DeviceUpdateRequest request) {
{
return success(iEmsDeviceSettingService.updateDeviceStatus(request)); return success(iEmsDeviceSettingService.updateDeviceStatus(request));
} }
} }

View File

@ -9,9 +9,14 @@ import com.xzzn.ems.domain.vo.BatteryDataStatsListVo;
import com.xzzn.ems.domain.vo.DateSearchRequest; import com.xzzn.ems.domain.vo.DateSearchRequest;
import com.xzzn.ems.domain.vo.RunningGraphRequest; import com.xzzn.ems.domain.vo.RunningGraphRequest;
import com.xzzn.ems.domain.vo.SiteBatteryDataList; import com.xzzn.ems.domain.vo.SiteBatteryDataList;
import com.xzzn.ems.domain.vo.SiteMonitorDataSaveRequest;
import com.xzzn.ems.domain.vo.SiteMonitorRuningInfoVo;
import com.xzzn.ems.service.IEmsDeviceSettingService;
import com.xzzn.ems.service.IEmsSiteService; import com.xzzn.ems.service.IEmsSiteService;
import com.xzzn.ems.service.IEmsStatsReportService; import com.xzzn.ems.service.IEmsStatsReportService;
import com.xzzn.ems.service.ISingleSiteService; import com.xzzn.ems.service.ISingleSiteService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -26,6 +31,8 @@ import java.util.List;
@RestController @RestController
@RequestMapping("/ems/siteMonitor") @RequestMapping("/ems/siteMonitor")
public class EmsSiteMonitorController extends BaseController{ public class EmsSiteMonitorController extends BaseController{
private static final Logger log = LoggerFactory.getLogger(EmsSiteMonitorController.class);
private static final String RUNNING_GRAPH_CTRL_DEBUG = "RunningGraphCtrlDebug";
@Autowired @Autowired
private ISingleSiteService iSingleSiteService; private ISingleSiteService iSingleSiteService;
@ -33,6 +40,8 @@ public class EmsSiteMonitorController extends BaseController{
private IEmsSiteService iEmsSiteService; private IEmsSiteService iEmsSiteService;
@Autowired @Autowired
private IEmsStatsReportService iemsStatsReportService; private IEmsStatsReportService iemsStatsReportService;
@Autowired
private IEmsDeviceSettingService iEmsDeviceSettingService;
/** /**
* 获取单站首页数据 * 获取单站首页数据
@ -43,6 +52,15 @@ public class EmsSiteMonitorController extends BaseController{
return success(iSingleSiteService.getSiteMonitorDataVo(siteId)); return success(iSingleSiteService.getSiteMonitorDataVo(siteId));
} }
/**
* 获取单站首页总累计运行数据(基于日表)
*/
@GetMapping("/homeTotalView")
public AjaxResult getSingleSiteHomeTotalView(@RequestParam String siteId)
{
return success(iSingleSiteService.getSiteMonitorTotalDataVo(siteId));
}
/** /**
* 单站监控-设备监控-实时运行头部数据 * 单站监控-设备监控-实时运行头部数据
*/ */
@ -56,27 +74,75 @@ public class EmsSiteMonitorController extends BaseController{
* 单站监控-设备监控-实时运行曲线图数据 * 单站监控-设备监控-实时运行曲线图数据
*/ */
@GetMapping("/runningGraph/storagePower") @GetMapping("/runningGraph/storagePower")
public AjaxResult getRunningGraphStorage(RunningGraphRequest request) public AjaxResult getRunningGraphStorage(RunningGraphRequest request,
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate)
{ {
return success(iSingleSiteService.getRunningGraphStorage(request)); SiteMonitorRuningInfoVo data = iSingleSiteService.getRunningGraphStorage(request);
int deviceCount = data == null || data.getPcsPowerList() == null ? 0 : data.getPcsPowerList().size();
log.info("{} storage, siteId={}, rawStartDate={}, rawEndDate={}, bindStartDate={}, bindEndDate={}, deviceCount={}",
RUNNING_GRAPH_CTRL_DEBUG,
request == null ? null : request.getSiteId(),
startDate,
endDate,
request == null ? null : request.getStartDate(),
request == null ? null : request.getEndDate(),
deviceCount);
return success(data);
} }
@GetMapping("/runningGraph/pcsMaxTemp") @GetMapping("/runningGraph/pcsMaxTemp")
public AjaxResult getRunningGraphPcsMaxTemp(RunningGraphRequest request) public AjaxResult getRunningGraphPcsMaxTemp(RunningGraphRequest request,
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate)
{ {
return success(iSingleSiteService.getRunningGraphPcsMaxTemp(request)); SiteMonitorRuningInfoVo data = iSingleSiteService.getRunningGraphPcsMaxTemp(request);
int deviceCount = data == null || data.getPcsMaxTempList() == null ? 0 : data.getPcsMaxTempList().size();
log.info("{} pcsMaxTemp, siteId={}, rawStartDate={}, rawEndDate={}, bindStartDate={}, bindEndDate={}, deviceCount={}",
RUNNING_GRAPH_CTRL_DEBUG,
request == null ? null : request.getSiteId(),
startDate,
endDate,
request == null ? null : request.getStartDate(),
request == null ? null : request.getEndDate(),
deviceCount);
return success(data);
} }
@GetMapping("/runningGraph/batteryAveSoc") @GetMapping("/runningGraph/batteryAveSoc")
public AjaxResult getRunningGraphBatterySoc(RunningGraphRequest request) public AjaxResult getRunningGraphBatterySoc(RunningGraphRequest request,
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate)
{ {
return success(iSingleSiteService.getRunningGraphBatterySoc(request)); SiteMonitorRuningInfoVo data = iSingleSiteService.getRunningGraphBatterySoc(request);
int pointCount = data == null || data.getBatteryAveSOCList() == null ? 0 : data.getBatteryAveSOCList().size();
log.info("{} batteryAveSoc, siteId={}, rawStartDate={}, rawEndDate={}, bindStartDate={}, bindEndDate={}, pointCount={}",
RUNNING_GRAPH_CTRL_DEBUG,
request == null ? null : request.getSiteId(),
startDate,
endDate,
request == null ? null : request.getStartDate(),
request == null ? null : request.getEndDate(),
pointCount);
return success(data);
} }
@GetMapping("/runningGraph/batteryAveTemp") @GetMapping("/runningGraph/batteryAveTemp")
public AjaxResult getRunningGraphBatteryTemp(RunningGraphRequest request) public AjaxResult getRunningGraphBatteryTemp(RunningGraphRequest request,
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate)
{ {
return success(iSingleSiteService.getRunningGraphBatteryTemp(request)); SiteMonitorRuningInfoVo data = iSingleSiteService.getRunningGraphBatteryTemp(request);
int pointCount = data == null || data.getBatteryAveTempList() == null ? 0 : data.getBatteryAveTempList().size();
log.info("{} batteryAveTemp, siteId={}, rawStartDate={}, rawEndDate={}, bindStartDate={}, bindEndDate={}, pointCount={}",
RUNNING_GRAPH_CTRL_DEBUG,
request == null ? null : request.getSiteId(),
startDate,
endDate,
request == null ? null : request.getStartDate(),
request == null ? null : request.getEndDate(),
pointCount);
return success(data);
} }
/** /**
@ -151,9 +217,7 @@ public class EmsSiteMonitorController extends BaseController{
{ {
startPage(); startPage();
SiteBatteryDataList siteBatteryDataList = new SiteBatteryDataList(); SiteBatteryDataList siteBatteryDataList = new SiteBatteryDataList();
// 簇最大最小单体id数据
List<BMSBatteryDataList> clusterBatteryDataList = iSingleSiteService.getClusterBatteryList(siteId,stackDeviceId,clusterDeviceId);
siteBatteryDataList.setClusterList(clusterBatteryDataList);
// 单体电池数据 // 单体电池数据
List<BatteryDataStatsListVo> List = iSingleSiteService.getClusterDataInfoList(clusterDeviceId,siteId,stackDeviceId,batteryId); List<BatteryDataStatsListVo> List = iSingleSiteService.getClusterDataInfoList(clusterDeviceId,siteId,stackDeviceId,batteryId);
// 对batteryList进行分页处理 // 对batteryList进行分页处理
@ -228,4 +292,31 @@ public class EmsSiteMonitorController extends BaseController{
return error("缺少必传项"); return error("缺少必传项");
} }
} }
/**
* 单站监控项目点位配置查询
*/
@GetMapping("/getProjectPointMapping")
public AjaxResult getProjectPointMapping(@RequestParam String siteId)
{
return success(iEmsDeviceSettingService.getSiteMonitorProjectPointMapping(siteId));
}
/**
* 单站监控项目展示数据查询(配置字段 + 字段值)
*/
@GetMapping("/getProjectDisplayData")
public AjaxResult getProjectDisplayData(@RequestParam String siteId)
{
return success(iEmsDeviceSettingService.getSiteMonitorProjectDisplay(siteId));
}
/**
* 单站监控项目展示数据写入
*/
@PostMapping("/saveProjectDisplayData")
public AjaxResult saveProjectDisplayData(@RequestBody SiteMonitorDataSaveRequest request)
{
return AjaxResult.success(iEmsDeviceSettingService.saveSiteMonitorProjectData(request, getUsername()));
}
} }

View File

@ -1,19 +1,33 @@
package com.xzzn.web.controller.ems; package com.xzzn.web.controller.ems;
import com.xzzn.common.annotation.Log;
import com.xzzn.common.core.controller.BaseController; import com.xzzn.common.core.controller.BaseController;
import com.xzzn.common.core.domain.AjaxResult; import com.xzzn.common.core.domain.AjaxResult;
import com.xzzn.common.core.page.TableDataInfo; import com.xzzn.common.core.page.TableDataInfo;
import com.xzzn.common.enums.BusinessType;
import com.xzzn.common.utils.StringUtils; import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.domain.vo.*; import com.xzzn.ems.domain.vo.AmmeterRevenueStatisListVo;
import com.xzzn.ems.domain.vo.AmmeterStatisListVo;
import com.xzzn.ems.domain.vo.ClusterStatisListVo;
import com.xzzn.ems.domain.vo.DateSearchRequest;
import com.xzzn.ems.domain.vo.StatisAmmeterDateRequest;
import com.xzzn.ems.domain.vo.StatisClusterDateRequest;
import com.xzzn.ems.domain.vo.WeatherSyncResultVo;
import com.xzzn.ems.service.IEmsStatsReportService; import com.xzzn.ems.service.IEmsStatsReportService;
import org.springframework.beans.factory.annotation.Autowired; import com.xzzn.ems.service.IEmsWeatherSyncService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** /**
* 单站监控-统计报表 * 单站监控-统计报表
* *
@ -26,6 +40,8 @@ public class EmsStatisticalReportController extends BaseController
@Autowired @Autowired
private IEmsStatsReportService ieEmsStatsReportService; private IEmsStatsReportService ieEmsStatsReportService;
@Autowired
private IEmsWeatherSyncService iEmsWeatherSyncService;
/** /**
* 概率统计-收益指标查询 * 概率统计-收益指标查询
@ -118,6 +134,39 @@ public class EmsStatisticalReportController extends BaseController
return getDataTable(dataList); return getDataTable(dataList);
} }
/**
* 统计报表-电表报表(直接基于 ems_daily_energy_data
*/
@GetMapping("/getAmmeterDataFromDaily")
public TableDataInfo getAmmeterDataFromDaily(StatisAmmeterDateRequest requestVo)
{
startPage();
List<AmmeterStatisListVo> dataList = ieEmsStatsReportService.getAmmeterDataResult(requestVo);
return getDataTable(dataList);
}
/**
* 导出电表报表
*/
@PreAuthorize("@ss.hasPermi('system:ammeterData:export')")
@Log(title = "电表报表", businessType = BusinessType.EXPORT)
@PostMapping("/exportAmmeterData")
public void exportAmmeterData(HttpServletResponse response, StatisAmmeterDateRequest requestVo)
{
ieEmsStatsReportService.exportAmmeterData(response, requestVo);
}
/**
* 导出电表报表(直接基于 ems_daily_energy_data
*/
@PreAuthorize("@ss.hasPermi('system:ammeterData:export')")
@Log(title = "电表报表", businessType = BusinessType.EXPORT)
@PostMapping("/exportAmmeterDataFromDaily")
public void exportAmmeterDataFromDaily(HttpServletResponse response, StatisAmmeterDateRequest requestVo)
{
ieEmsStatsReportService.exportAmmeterData(response, requestVo);
}
/** /**
* 概率统计-电表收益报表 * 概率统计-电表收益报表
*/ */
@ -129,6 +178,17 @@ public class EmsStatisticalReportController extends BaseController
return getDataTable(dataList); return getDataTable(dataList);
} }
/**
* 导出收益报表
*/
@PreAuthorize("@ss.hasPermi('system:ammeterRevenueData:export')")
@Log(title = "收益报表", businessType = BusinessType.EXPORT)
@PostMapping("/exportAmmeterRevenueData")
public void exportAmmeterRevenueData(HttpServletResponse response, StatisAmmeterDateRequest requestVo)
{
ieEmsStatsReportService.exportAmmeterRevenueData(response, requestVo);
}
/** /**
* 概率统计-功率曲线 * 概率统计-功率曲线
*/ */
@ -142,4 +202,19 @@ public class EmsStatisticalReportController extends BaseController
} }
} }
/**
* 手动触发天气同步
*/
@PostMapping("/syncWeatherByDateRange")
public AjaxResult syncWeatherByDateRange(StatisAmmeterDateRequest requestVo)
{
if (StringUtils.isEmpty(requestVo.getSiteId())
|| StringUtils.isEmpty(requestVo.getStartTime())
|| StringUtils.isEmpty(requestVo.getEndTime())) {
return error("缺少必传项: siteId/startTime/endTime");
}
WeatherSyncResultVo resultVo = iEmsWeatherSyncService.syncWeatherByDateRange(requestVo);
return success(resultVo);
}
} }

View File

@ -0,0 +1,48 @@
package com.xzzn.web.controller.ems;
import com.xzzn.common.core.controller.BaseController;
import com.xzzn.common.core.domain.AjaxResult;
import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.domain.EmsStrategyRuntimeConfig;
import com.xzzn.ems.service.IEmsStrategyRuntimeConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 策略运行参数配置Controller
*/
@RestController
@RequestMapping("/system/strategyRuntimeConfig")
public class EmsStrategyRuntimeConfigController extends BaseController {
@Autowired
private IEmsStrategyRuntimeConfigService runtimeConfigService;
/**
* 按站点ID获取策略运行参数
*/
@GetMapping("/getBySiteId")
public AjaxResult getBySiteId(String siteId) {
if (StringUtils.isEmpty(siteId)) {
return error("缺少必填字段siteId");
}
return success(runtimeConfigService.getBySiteId(siteId));
}
/**
* 保存策略运行参数按siteId新增/更新)
*/
@PostMapping("/save")
public AjaxResult save(@RequestBody EmsStrategyRuntimeConfig config) {
if (config == null || StringUtils.isEmpty(config.getSiteId())) {
return error("缺少必填字段siteId");
}
config.setCreateBy(getUsername());
config.setUpdateBy(getUsername());
return toAjax(runtimeConfigService.saveBySiteId(config));
}
}

View File

@ -6,12 +6,7 @@ import com.xzzn.common.enums.TopicHandleType;
import com.xzzn.common.utils.StringUtils; import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.domain.EmsMqttTopicConfig; import com.xzzn.ems.domain.EmsMqttTopicConfig;
import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper; import com.xzzn.ems.mapper.EmsMqttTopicConfigMapper;
import com.xzzn.ems.service.IDDSDataProcessService;
import com.xzzn.ems.service.IDeviceDataProcessService; import com.xzzn.ems.service.IDeviceDataProcessService;
import com.xzzn.ems.service.IEmsMqttMessageService;
import com.xzzn.ems.service.IEmsStrategyService;
import com.xzzn.ems.service.IFXXAlarmDataProcessService;
import com.xzzn.ems.service.IFXXDataProcessService;
import com.xzzn.ems.service.IMqttSyncLogService; import com.xzzn.ems.service.IMqttSyncLogService;
import com.xzzn.framework.manager.MqttLifecycleManager; import com.xzzn.framework.manager.MqttLifecycleManager;
import com.xzzn.framework.web.service.MqttPublisher; import com.xzzn.framework.web.service.MqttPublisher;
@ -27,6 +22,7 @@ import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -38,29 +34,19 @@ public class MqttMessageController implements MqttPublisher, MqttSubscriber {
private final MqttLifecycleManager mqttLifecycleManager; private final MqttLifecycleManager mqttLifecycleManager;
@Autowired
private IEmsMqttMessageService emsMqttMessageService;
@Autowired
private IFXXDataProcessService fXXDataProcessService;
@Autowired
private IDDSDataProcessService dDSDataProcessService;
@Autowired @Autowired
private IDeviceDataProcessService deviceDataProcessService; private IDeviceDataProcessService deviceDataProcessService;
@Autowired
private IFXXAlarmDataProcessService fXXAlarmDataProcessService;
@Autowired @Autowired
private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper; private EmsMqttTopicConfigMapper emsMqttTopicConfigMapper;
@Autowired @Autowired
private IEmsStrategyService emsStrategyService;
@Autowired
private IMqttSyncLogService iMqttSyncLogService; private IMqttSyncLogService iMqttSyncLogService;
@Autowired @Autowired
private RedisCache redisCache; private RedisCache redisCache;
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Autowired @Autowired
public MqttMessageController(MqttLifecycleManager mqttLifecycleManager) { public MqttMessageController(MqttLifecycleManager mqttLifecycleManager) {
@ -136,51 +122,32 @@ public class MqttMessageController implements MqttPublisher, MqttSubscriber {
private void handleSystemStatus(String topic, MqttMessage message) { private void handleSystemStatus(String topic, MqttMessage message) {
String payload = new String(message.getPayload()); String payload = new String(message.getPayload());
System.out.println("[SYSTEM] Status update: " + payload); System.out.println("[SYSTEM] Status update: " + payload);
try {
emsMqttMessageService.insertMqttOriginalMessage(topic,payload);
} catch (Exception e) {
log.error("Failed to process system status message: " + e.getMessage(), e);
}
} }
// 处理设备数据 // 处理设备数据
private void handleDeviceData(String topic, MqttMessage message) { private void handleDeviceData(String topic, MqttMessage message) {
String payload = new String(message.getPayload()); String payload = new String(message.getPayload());
log.error("[DEVICE] data: " + payload); threadPoolTaskExecutor.execute(() -> {
try { log.debug("[DEVICE] data: {}", payload);
// 业务处理逻辑 try {
// if (topic.startsWith("021_DDS")) { deviceDataProcessService.handleDeviceData(payload, getSiteIdByTopic(topic));
// dDSDataProcessService.handleDdsData(payload); } catch (Exception e) {
// } else if (topic.startsWith("021_FXX")) { log.error("Failed to process device data message: {}", e.getMessage(), e);
// fXXDataProcessService.handleFxData(payload); }
// } });
deviceDataProcessService.handleDeviceData(payload, getSiteIdByTopic(topic));
emsMqttMessageService.insertMqttOriginalMessage(topic, payload);
} catch (Exception e) {
log.error("Failed to process device data message: " + e.getMessage(), e);
}
} }
// 处理告警数据 // 处理告警数据
private void handleAlarmData(String topic, MqttMessage message) { private void handleAlarmData(String topic, MqttMessage message) {
String payload = new String(message.getPayload()); String payload = new String(message.getPayload());
System.out.println("[DEVICE] data: " + payload); threadPoolTaskExecutor.execute(() -> {
try { try {
// 业务处理逻辑 deviceDataProcessService.handleAlarmData(payload, getSiteIdByTopic(topic));
// if (topic.startsWith("021_FXX")) { } catch (Exception e) {
// fXXAlarmDataProcessService.handleFxAlarmData(payload); log.error("Failed to process device alarm data message: {}", e.getMessage(), e);
// } }
deviceDataProcessService.handleAlarmData(payload, getSiteIdByTopic(topic)); });
emsMqttMessageService.insertMqttOriginalMessage(topic, payload);
} catch (Exception e) {
e.printStackTrace();
log.error("Failed to process device alarm data message: " + e.getMessage(), e);
}
} }
@ -191,78 +158,67 @@ public class MqttMessageController implements MqttPublisher, MqttSubscriber {
siteId = topicConfig.getSiteId(); siteId = topicConfig.getSiteId();
redisCache.setCacheObject(RedisKeyConstants.SITE_ID + topic, siteId); redisCache.setCacheObject(RedisKeyConstants.SITE_ID + topic, siteId);
} }
log.info("当前处理数据站点:" + siteId + ",topic: " + topic);
return siteId; return siteId;
} }
// 处理运行策略数据:云端-本地 // 处理运行策略数据:云端-本地
private void handleStrategyData(String topic, MqttMessage message) { private void handleStrategyData(String topic, MqttMessage message) {
String payload = new String(message.getPayload()); String payload = new String(message.getPayload());
System.out.println("[处理运行策略数据] data: " + payload); threadPoolTaskExecutor.execute(() -> {
try { try {
// 业务处理逻辑 iMqttSyncLogService.handleMqttStrategyData(payload);
iMqttSyncLogService.handleMqttStrategyData(payload); } catch (Exception e) {
log.error("Failed to process strategy data message: {}", e.getMessage(), e);
emsMqttMessageService.insertMqttOriginalMessage(topic,payload); }
} catch (Exception e) { });
log.error("Failed to process strategy data message: " + e.getMessage(), e);
}
} }
// 处理设备保护告警策略数据:云端-本地 // 处理设备保护告警策略数据:云端-本地
private void handleFaultProtPlanData(String topic, MqttMessage message) { private void handleFaultProtPlanData(String topic, MqttMessage message) {
String payload = new String(message.getPayload()); String payload = new String(message.getPayload());
System.out.println("[处理设备保护告警策略数据] data: " + payload); threadPoolTaskExecutor.execute(() -> {
try { try {
// 业务处理逻辑 iMqttSyncLogService.handleMqttPlanData(payload);
iMqttSyncLogService.handleMqttPlanData(payload); } catch (Exception e) {
log.error("Failed to process fault plan data message: {}", e.getMessage(), e);
emsMqttMessageService.insertMqttOriginalMessage(topic,payload); }
} catch (Exception e) { });
log.error("Failed to process fault plan data message: " + e.getMessage(), e);
}
} }
// 处理保护策略告警信息:本地-云端 // 处理保护策略告警信息:本地-云端
private void handleFaultAlarmData(String topic, MqttMessage message) { private void handleFaultAlarmData(String topic, MqttMessage message) {
String payload = new String(message.getPayload()); String payload = new String(message.getPayload());
System.out.println("[处理本地保护策略告警信息到云端] data: " + payload); threadPoolTaskExecutor.execute(() -> {
try { try {
// 业务处理逻辑 iMqttSyncLogService.handleFaultAlarmData(payload);
iMqttSyncLogService.handleFaultAlarmData(payload); } catch (Exception e) {
log.error("Failed to process fault plan alarm data message: {}", e.getMessage(), e);
emsMqttMessageService.insertMqttOriginalMessage(topic,payload); }
} catch (Exception e) { });
log.error("Failed to process fault plan alarm data message: " + e.getMessage(), e);
}
} }
// 处理保护策略下发日志:本地-云端 // 处理保护策略下发日志:本地-云端
private void handleFaultPlanIssueData(String topic, MqttMessage message) { private void handleFaultPlanIssueData(String topic, MqttMessage message) {
String payload = new String(message.getPayload()); String payload = new String(message.getPayload());
System.out.println("[处理本地保护策略下发日志到云端] data: " + payload); threadPoolTaskExecutor.execute(() -> {
try { try {
// 业务处理逻辑 iMqttSyncLogService.handleFaultPlanIssueData(payload);
iMqttSyncLogService.handleFaultPlanIssueData(payload); } catch (Exception e) {
log.error("Failed to process fault plan issue log message: {}", e.getMessage(), e);
emsMqttMessageService.insertMqttOriginalMessage(topic,payload); }
} catch (Exception e) { });
log.error("Failed to process fault plan issue log message: " + e.getMessage(), e);
}
} }
// 处理设备状态变更日志:本地-云端 // 处理设备状态变更日志:本地-云端
private void handleDeviceChangeLogData(String topic, MqttMessage message) { private void handleDeviceChangeLogData(String topic, MqttMessage message) {
String payload = new String(message.getPayload()); String payload = new String(message.getPayload());
System.out.println("[处理本地的保护策略告警信息到云端] data: " + payload); threadPoolTaskExecutor.execute(() -> {
try { try {
// 业务处理逻辑 iMqttSyncLogService.handleDeviceChangeLogData(payload);
iMqttSyncLogService.handleDeviceChangeLogData(payload); } catch (Exception e) {
log.error("Failed to process device change log message: {}", e.getMessage(), e);
emsMqttMessageService.insertMqttOriginalMessage(topic,payload); }
} catch (Exception e) { });
log.error("Failed to process device change log message: " + e.getMessage(), e);
}
} }
@Override @Override
@ -292,4 +248,4 @@ public class MqttMessageController implements MqttPublisher, MqttSubscriber {
} }
} }
} }

View File

@ -0,0 +1,32 @@
package com.xzzn.web.controller.system;
import com.xzzn.common.core.controller.BaseController;
import com.xzzn.common.core.domain.AjaxResult;
import com.xzzn.ems.domain.vo.BizRemarkBatchGetRequest;
import com.xzzn.ems.domain.vo.BizRemarkSaveRequest;
import com.xzzn.ems.service.ISysBizRemarkService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/system/bizRemark")
public class SysBizRemarkController extends BaseController
{
@Autowired
private ISysBizRemarkService sysBizRemarkService;
@PostMapping("/batchGet")
public AjaxResult batchGet(@RequestBody BizRemarkBatchGetRequest request)
{
return success(sysBizRemarkService.getRemarkMap(request.getBizType(), request.getBizKey1(), request.getBizKey2List()));
}
@PostMapping("/save")
public AjaxResult save(@RequestBody BizRemarkSaveRequest request)
{
return toAjax(sysBizRemarkService.saveRemark(request, getUsername()));
}
}

View File

@ -205,3 +205,10 @@ modbus:
poll: poll:
interval: "0 */5 * * * *" # 5分钟间隔 interval: "0 */5 * * * *" # 5分钟间隔
timeout: 30000 # 30秒超时 timeout: 30000 # 30秒超时
weather:
api:
enabled: true
base-url: https://archive-api.open-meteo.com/v1/archive
api-key:
timezone: Asia/Shanghai

View File

@ -205,3 +205,24 @@ modbus:
poll: poll:
interval: "0 */5 * * * *" # 5分钟间隔 interval: "0 */5 * * * *" # 5分钟间隔
timeout: 30000 # 30秒超时 timeout: 30000 # 30秒超时
weather:
api:
enabled: true
base-url: https://archive-api.open-meteo.com/v1/archive
api-key:
timezone: Asia/Shanghai
influxdb:
enabled: true
url: http://172.17.0.7:8086/
api-token: B_1HvHbUhubQQhLdI0XtNVw7maWS1aIjVZQ1a3PGD6b-VNg3_JUo_jHgZmjeBKYXnGATNdIqfpl-FAVbJ4UIPg==
write-method: POST
read-method: GET
write-path: /api/v2/write
query-path: /query
org: ems
bucket: point_data
database: ems_point_data
retention-policy: autogen
measurement: mqtt_point_data

View File

@ -199,6 +199,20 @@ mqtt:
topic: topic:
siteId: siteId:
influxdb:
enabled: true
url: http://122.51.194.184:8086/
api-token: F2XcmBzZsWcz90ikU2_t7UXY2fzWuf2ruVp1BkusNkIS_gwrQZuiaIjl33XQMQajm7vSI6TQSRnpPSx5CXThlA==
write-method: POST
read-method: GET
write-path: /api/v2/write
query-path: /query
org: ems
bucket: point_data
database: ems_point_data
retention-policy: autogen
measurement: mqtt_point_data
modbus: modbus:
pool: pool:
max-total: 20 max-total: 20
@ -207,3 +221,10 @@ modbus:
poll: poll:
interval: "0 */5 * * * *" # 5分钟间隔 interval: "0 */5 * * * *" # 5分钟间隔
timeout: 30000 # 30秒超时 timeout: 30000 # 30秒超时
weather:
api:
enabled: true
base-url: https://archive-api.open-meteo.com/v1/archive
api-key:
timezone: Asia/Shanghai

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration> <configuration>
<!-- 日志存放路径 --> <!-- 日志存放路径 -->
<property name="log.path" value="/etc/xzzn/logs" /> <property name="log.path" value="logs" />
<!-- 日志输出格式 --> <!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
@ -90,4 +90,4 @@
<logger name="sys-user" level="info"> <logger name="sys-user" level="info">
<appender-ref ref="sys-user"/> <appender-ref ref="sys-user"/>
</logger> </logger>
</configuration> </configuration>

View File

@ -103,6 +103,9 @@ public class RedisKeyConstants
/** 设备信息初始化 */ /** 设备信息初始化 */
public static final String INIT_DEVICE_INFO = "init_device_info"; public static final String INIT_DEVICE_INFO = "init_device_info";
/** 设备配置缓存(按站点+设备) */
public static final String DEVICE_SETTING = "DEVICE_SETTING_";
/** 告警匹配信息 */ /** 告警匹配信息 */
public static final String ALARM_MATCH_INFO = "alarm_message_info"; public static final String ALARM_MATCH_INFO = "alarm_message_info";
@ -122,4 +125,19 @@ public class RedisKeyConstants
/** 每个设备最新数据-设置失效时间-判断是否正常同步数据 */ /** 每个设备最新数据-设置失效时间-判断是否正常同步数据 */
public static final String SYNC_DATA_ALARM = "SYNC_DATA_ALARM_"; public static final String SYNC_DATA_ALARM = "SYNC_DATA_ALARM_";
/** 点位配置缓存(按站点+设备) */
public static final String POINT_CONFIG_DEVICE = "POINT_CONFIG_DEVICE_";
/** 点位配置缓存(按站点+pointId */
public static final String POINT_CONFIG_POINT = "POINT_CONFIG_POINT_";
/** 单站监控最新数据(按站点+模块) */
public static final String SITE_MONITOR_LATEST = "SITE_MONITOR_LATEST_";
/** 单站监控点位映射(按站点) */
public static final String SITE_MONITOR_POINT_MATCH = "SITE_MONITOR_POINT_MATCH_";
/** 站点保护约束(按站点) */
public static final String PROTECTION_CONSTRAINT = "PROTECTION_CONSTRAINT_";
} }

View File

@ -1,5 +1,8 @@
package com.xzzn.common.utils; package com.xzzn.common.utils;
import com.xzzn.common.constant.Constants;
import com.xzzn.common.core.text.StrFormatter;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -7,9 +10,8 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.springframework.util.AntPathMatcher; import org.springframework.util.AntPathMatcher;
import com.xzzn.common.constant.Constants;
import com.xzzn.common.core.text.StrFormatter;
/** /**
* 字符串工具类 * 字符串工具类
@ -743,6 +745,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
} }
public static String getString(Object s){ public static String getString(Object s){
if (s == null) return null;
String result; String result;
try { try {
result = String.valueOf(s); result = String.valueOf(s);

View File

@ -3,21 +3,37 @@ package com.xzzn.framework.manager;
import com.xzzn.ems.service.IEmsAlarmRecordsService; import com.xzzn.ems.service.IEmsAlarmRecordsService;
import org.eclipse.paho.client.mqttv3.*; import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
import org.springframework.context.SmartLifecycle; import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@Component @Component
public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle, MqttCallback { public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle, MqttCallbackExtended {
private static final Logger log = LoggerFactory.getLogger(MqttLifecycleManager.class);
private static final long RECONNECT_DELAY_SECONDS = 5;
private final MqttConnectOptions connectOptions; private final MqttConnectOptions connectOptions;
private final IEmsAlarmRecordsService iEmsAlarmRecordsService; private final IEmsAlarmRecordsService iEmsAlarmRecordsService;
private final ScheduledExecutorService reconnectExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
Thread thread = new Thread(r);
thread.setName("mqtt-reconnect");
thread.setDaemon(true);
return thread;
});
private final AtomicBoolean reconnectScheduled = new AtomicBoolean(false);
private volatile ScheduledFuture<?> reconnectFuture;
private MqttClient mqttClient; private MqttClient mqttClient;
private volatile boolean running = false; private volatile boolean running = false;
@ -41,7 +57,9 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
if (running) return; if (running) return;
try { try {
String clientId = connectOptions.getUserName() + "-" + System.currentTimeMillis(); String prefix = connectOptions.getUserName() == null || connectOptions.getUserName().isEmpty()
? "mqtt-client" : connectOptions.getUserName();
String clientId = prefix + "-" + System.currentTimeMillis();
mqttClient = new MqttClient( mqttClient = new MqttClient(
connectOptions.getServerURIs()[0], connectOptions.getServerURIs()[0],
clientId, clientId,
@ -51,27 +69,28 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
mqttClient.setCallback(this); mqttClient.setCallback(this);
mqttClient.connect(connectOptions); mqttClient.connect(connectOptions);
// 重连后自动重新订阅
resubscribeAll(); resubscribeAll();
running = true; running = true;
System.out.println("MQTT client connected to: " + connectOptions.getServerURIs()[0]); log.info("MQTT client connected to: {}", connectOptions.getServerURIs()[0]);
} catch (MqttException e) { } catch (MqttException e) {
System.err.println("MQTT connection failed: " + e.getMessage()); running = false;
// 添加重试逻辑 log.error("MQTT connection failed: {}", e.getMessage(), e);
scheduleReconnect();
} }
} }
@Override @Override
public void stop() { public void stop() {
cancelReconnectTask();
if (mqttClient != null && mqttClient.isConnected()) { if (mqttClient != null && mqttClient.isConnected()) {
try { try {
mqttClient.disconnect(); mqttClient.disconnect();
mqttClient.close(); mqttClient.close();
} catch (MqttException e) { } catch (MqttException e) {
System.err.println("Error disconnecting MQTT client: " + e.getMessage()); log.warn("Error disconnecting MQTT client: {}", e.getMessage(), e);
} }
} }
reconnectExecutor.shutdownNow();
running = false; running = false;
} }
@ -83,9 +102,17 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
// MQTT 回调方法 // MQTT 回调方法
@Override @Override
public void connectionLost(Throwable cause) { public void connectionLost(Throwable cause) {
System.err.println("MQTT connection lost: " + cause.getMessage()); log.warn("MQTT connection lost: {}", cause == null ? "unknown" : cause.getMessage(), cause);
running = false; running = false;
// 自动重连由 MqttConnectOptions 处理 scheduleReconnect();
}
@Override
public void connectComplete(boolean reconnect, String serverURI) {
running = true;
cancelReconnectTask();
log.info("MQTT connection complete, reconnect: {}, serverURI: {}", reconnect, serverURI);
resubscribeAll();
} }
@Override @Override
@ -106,14 +133,16 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
try { try {
if (mqttClient != null && mqttClient.isConnected()) { if (mqttClient != null && mqttClient.isConnected()) {
mqttClient.subscribe(topic, qos); mqttClient.subscribe(topic, qos);
log.info("MQTT subscribe success, topic: {}, qos: {}", topic, qos);
} else {
log.warn("MQTT subscribe deferred, client not connected, topic: {}", topic);
} }
subscriptions.put(topic, new SubscriptionInfo(listener, qos)); subscriptions.put(topic, new SubscriptionInfo(listener, qos));
} catch (MqttException e) { } catch (MqttException e) {
System.err.println("Subscribe failed: " + e.getMessage()); log.error("Subscribe failed, topic: {}, err: {}", topic, e.getMessage(), e);
// 订阅失败-增加告警
iEmsAlarmRecordsService.addSubFailedAlarmRecord(topic); iEmsAlarmRecordsService.addSubFailedAlarmRecord(topic);
scheduleReconnect();
} }
// 订阅成功了-校验是否存在未处理或者处理中的订阅失败信息
iEmsAlarmRecordsService.checkFailedRecord(topic); iEmsAlarmRecordsService.checkFailedRecord(topic);
} }
@ -135,12 +164,52 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
subscriptions.forEach((topic, info) -> { subscriptions.forEach((topic, info) -> {
try { try {
mqttClient.subscribe(topic, info.getQos()); mqttClient.subscribe(topic, info.getQos());
log.info("MQTT resubscribe success, topic: {}, qos: {}", topic, info.getQos());
} catch (MqttException e) { } catch (MqttException e) {
System.err.println("Resubscribe failed for topic: " + topic); log.error("Resubscribe failed for topic: {}, err: {}", topic, e.getMessage(), e);
} }
}); });
} }
private void scheduleReconnect() {
if (mqttClient == null || reconnectExecutor.isShutdown()) {
return;
}
if (!reconnectScheduled.compareAndSet(false, true)) {
return;
}
reconnectFuture = reconnectExecutor.scheduleWithFixedDelay(() -> {
if (mqttClient == null) {
cancelReconnectTask();
return;
}
if (mqttClient.isConnected()) {
cancelReconnectTask();
return;
}
try {
log.info("MQTT reconnecting...");
mqttClient.connect(connectOptions);
running = true;
cancelReconnectTask();
resubscribeAll();
log.info("MQTT reconnect success.");
} catch (MqttException e) {
running = false;
log.warn("MQTT reconnect failed: {}", e.getMessage());
}
}, RECONNECT_DELAY_SECONDS, RECONNECT_DELAY_SECONDS, TimeUnit.SECONDS);
}
private void cancelReconnectTask() {
reconnectScheduled.set(false);
ScheduledFuture<?> future = reconnectFuture;
if (future != null && !future.isCancelled()) {
future.cancel(false);
}
}
// 订阅信息内部类 // 订阅信息内部类
private static class SubscriptionInfo { private static class SubscriptionInfo {
private final IMqttMessageListener listener; private final IMqttMessageListener listener;
@ -159,4 +228,4 @@ public class MqttLifecycleManager implements ApplicationRunner, SmartLifecycle,
return qos; return qos;
} }
} }
} }

View File

@ -1,7 +1,6 @@
package com.xzzn.generator.controller; package com.xzzn.generator.controller;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -18,10 +17,6 @@ import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
import com.xzzn.common.annotation.Log; import com.xzzn.common.annotation.Log;
import com.xzzn.common.core.controller.BaseController; import com.xzzn.common.core.controller.BaseController;
import com.xzzn.common.core.domain.AjaxResult; import com.xzzn.common.core.domain.AjaxResult;
@ -29,7 +24,6 @@ import com.xzzn.common.core.page.TableDataInfo;
import com.xzzn.common.core.text.Convert; import com.xzzn.common.core.text.Convert;
import com.xzzn.common.enums.BusinessType; import com.xzzn.common.enums.BusinessType;
import com.xzzn.common.utils.SecurityUtils; import com.xzzn.common.utils.SecurityUtils;
import com.xzzn.common.utils.sql.SqlUtil;
import com.xzzn.generator.config.GenConfig; import com.xzzn.generator.config.GenConfig;
import com.xzzn.generator.domain.GenTable; import com.xzzn.generator.domain.GenTable;
import com.xzzn.generator.domain.GenTableColumn; import com.xzzn.generator.domain.GenTableColumn;
@ -121,43 +115,6 @@ public class GenController extends BaseController
return success(); return success();
} }
/**
* 创建表结构(保存)
*/
@PreAuthorize("@ss.hasRole('admin')")
@Log(title = "创建表", businessType = BusinessType.OTHER)
@PostMapping("/createTable")
public AjaxResult createTableSave(String sql)
{
try
{
SqlUtil.filterKeyword(sql);
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);
List<String> tableNames = new ArrayList<>();
for (SQLStatement sqlStatement : sqlStatements)
{
if (sqlStatement instanceof MySqlCreateTableStatement)
{
MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement;
if (genTableService.createTable(createTableStatement.toString()))
{
String tableName = createTableStatement.getTableName().replaceAll("`", "");
tableNames.add(tableName);
}
}
}
List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()]));
String operName = SecurityUtils.getUsername();
genTableService.importGenTable(tableList, operName);
return AjaxResult.success();
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
return AjaxResult.error("创建表结构异常");
}
}
/** /**
* 修改保存代码生成业务 * 修改保存代码生成业务
*/ */
@ -260,4 +217,4 @@ public class GenController extends BaseController
response.setContentType("application/octet-stream; charset=UTF-8"); response.setContentType("application/octet-stream; charset=UTF-8");
IOUtils.write(data, response.getOutputStream()); IOUtils.write(data, response.getOutputStream());
} }
} }

View File

@ -81,11 +81,4 @@ public interface GenTableMapper
*/ */
public int deleteGenTableByIds(Long[] ids); public int deleteGenTableByIds(Long[] ids);
/**
* 创建表
*
* @param sql 表结构
* @return 结果
*/
public int createTable(String sql);
} }

View File

@ -149,18 +149,6 @@ public class GenTableServiceImpl implements IGenTableService
genTableColumnMapper.deleteGenTableColumnByIds(tableIds); genTableColumnMapper.deleteGenTableColumnByIds(tableIds);
} }
/**
* 创建表
*
* @param sql 创建表语句
* @return 结果
*/
@Override
public boolean createTable(String sql)
{
return genTableMapper.createTable(sql) == 0;
}
/** /**
* 导入表结构 * 导入表结构
* *
@ -528,4 +516,4 @@ public class GenTableServiceImpl implements IGenTableService
} }
return genPath + File.separator + VelocityUtils.getFileName(template, table); return genPath + File.separator + VelocityUtils.getFileName(template, table);
} }
} }

View File

@ -66,14 +66,6 @@ public interface IGenTableService
*/ */
public void deleteGenTableByIds(Long[] tableIds); public void deleteGenTableByIds(Long[] tableIds);
/**
* 创建表
*
* @param sql 创建表语句
* @return 结果
*/
public boolean createTable(String sql);
/** /**
* 导入表结构 * 导入表结构
* *

View File

@ -171,10 +171,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
) )
</insert> </insert>
<update id="createTable">
${sql}
</update>
<update id="updateGenTable" parameterType="GenTable"> <update id="updateGenTable" parameterType="GenTable">
update gen_table update gen_table
<set> <set>
@ -207,4 +203,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach> </foreach>
</delete> </delete>
</mapper> </mapper>

View File

@ -0,0 +1,35 @@
package com.xzzn.quartz.task;
import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.service.impl.DeviceDataProcessServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("calcPointTask")
public class CalcPointTask {
private static final Logger log = LoggerFactory.getLogger(CalcPointTask.class);
@Autowired
private DeviceDataProcessServiceImpl deviceDataProcessService;
public void syncAllSites() {
log.info("开始执行计算点轮询任务-全站点");
deviceDataProcessService.syncCalcPointDataFromInfluxByQuartz();
log.info("结束执行计算点轮询任务-全站点");
}
public void syncBySite(String siteId) {
if (StringUtils.isBlank(siteId)) {
log.warn("计算点轮询任务参数为空,转为全站点执行");
syncAllSites();
return;
}
String normalizedSiteId = siteId.trim();
log.info("开始执行计算点轮询任务-单站点, siteId: {}", normalizedSiteId);
deviceDataProcessService.syncCalcPointDataFromInfluxByQuartz(normalizedSiteId);
log.info("结束执行计算点轮询任务-单站点, siteId: {}", normalizedSiteId);
}
}

View File

@ -0,0 +1,35 @@
package com.xzzn.quartz.task;
import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.service.impl.DeviceDataProcessServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("dailyChargeDataTask")
public class DailyChargeDataTask {
private static final Logger log = LoggerFactory.getLogger(DailyChargeDataTask.class);
@Autowired
private DeviceDataProcessServiceImpl deviceDataProcessService;
public void syncAllSites() {
log.info("开始执行每日充放电数据轮询任务-全站点");
deviceDataProcessService.syncDailyChargeDataFromInfluxByQuartz();
log.info("结束执行每日充放电数据轮询任务-全站点");
}
public void syncBySite(String siteId) {
if (StringUtils.isBlank(siteId)) {
log.warn("每日充放电数据轮询任务参数为空,转为全站点执行");
syncAllSites();
return;
}
String normalizedSiteId = siteId.trim();
log.info("开始执行每日充放电数据轮询任务-单站点, siteId: {}", normalizedSiteId);
deviceDataProcessService.syncDailyChargeDataFromInfluxByQuartz(normalizedSiteId);
log.info("结束执行每日充放电数据轮询任务-单站点, siteId: {}", normalizedSiteId);
}
}

View File

@ -2,31 +2,25 @@ package com.xzzn.quartz.task;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.ModbusMaster;
import com.xzzn.common.constant.RedisKeyConstants; import com.xzzn.common.constant.RedisKeyConstants;
import com.xzzn.common.core.modbus.ModbusProcessor; import com.xzzn.common.core.modbus.ModbusProcessor;
import com.xzzn.common.core.modbus.domain.DeviceConfig; import com.xzzn.common.core.modbus.domain.DeviceConfig;
import com.xzzn.common.core.modbus.domain.TagConfig;
import com.xzzn.common.core.redis.RedisCache; import com.xzzn.common.core.redis.RedisCache;
import com.xzzn.common.enums.DeviceRunningStatus; import com.xzzn.common.enums.DeviceRunningStatus;
import com.xzzn.common.utils.DateUtils; import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.domain.EmsDevicesSetting; import com.xzzn.ems.domain.EmsDevicesSetting;
import com.xzzn.ems.domain.EmsPointConfig;
import com.xzzn.ems.mapper.EmsDevicesSettingMapper; import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
import com.xzzn.ems.mapper.EmsPointConfigMapper;
import com.xzzn.ems.service.IEmsAlarmRecordsService; import com.xzzn.ems.service.IEmsAlarmRecordsService;
import com.xzzn.ems.service.impl.DeviceDataProcessServiceImpl; import com.xzzn.ems.service.impl.DeviceDataProcessServiceImpl;
import com.xzzn.framework.manager.MqttLifecycleManager;
import com.xzzn.framework.web.service.MqttPublisher; import com.xzzn.framework.web.service.MqttPublisher;
import com.xzzn.quartz.config.ScheduledTask;
import com.xzzn.quartz.domain.SysJob;
import com.xzzn.quartz.service.ISysJobService;
import com.xzzn.quartz.util.CronUtils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -36,9 +30,9 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.stream.Collectors;
import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttException;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -54,10 +48,8 @@ import org.springframework.util.CollectionUtils;
@Component("modbusPoller") @Component("modbusPoller")
public class ModbusPoller { public class ModbusPoller {
private static final Logger log = LoggerFactory.getLogger(ModbusPoller.class); private static final Logger log = LoggerFactory.getLogger(ModbusPoller.class);
private static final int SITE_DEVICE_OFFLINE_THRESHOLD = 6;
private final MqttLifecycleManager mqttLifecycleManager;
private final ScheduledTask scheduledTask;
private final ObjectMapper objectMapper = new ObjectMapper();
private final Map<String, Integer> deviceFailureCounts = new ConcurrentHashMap<>(); private final Map<String, Integer> deviceFailureCounts = new ConcurrentHashMap<>();
private final AtomicBoolean polling = new AtomicBoolean(false); private final AtomicBoolean polling = new AtomicBoolean(false);
@ -69,77 +61,46 @@ public class ModbusPoller {
@Autowired @Autowired
private IEmsAlarmRecordsService iEmsAlarmRecordsService; private IEmsAlarmRecordsService iEmsAlarmRecordsService;
@Autowired
private ISysJobService iSysJobService;
@Autowired @Autowired
private DeviceDataProcessServiceImpl deviceDataProcessServiceImpl; private DeviceDataProcessServiceImpl deviceDataProcessServiceImpl;
@Autowired @Autowired
private EmsDevicesSettingMapper emsDevicesSettingMapper; private EmsDevicesSettingMapper emsDevicesSettingMapper;
@Autowired @Autowired
private EmsPointConfigMapper emsPointConfigMapper;
@Autowired
private RedisCache redisCache; private RedisCache redisCache;
@Autowired @Autowired
private MqttPublisher mqttPublisher; private MqttPublisher mqttPublisher;
@Value("${mqtt.topic}") @Value("${mqtt.topic}")
private String topic; private String topic;
@Value("${mqtt.siteId}")
private String siteId;
@Autowired
public ModbusPoller(MqttLifecycleManager mqttLifecycleManager, ScheduledTask scheduledTask) {
this.mqttLifecycleManager = mqttLifecycleManager;
this.scheduledTask = scheduledTask;
}
public void pollAllDevices() { public void pollAllDevices() {
if (!polling.compareAndSet(false, true)) { if (!polling.compareAndSet(false, true)) {
log.warn("上一次轮询尚未完成,本次轮询跳过"); log.warn("上一次轮询尚未完成,本次轮询跳过");
return; return;
} }
Path devicesDir = Paths.get(System.getProperty("user.dir"), "devices"); List<PollingTask> pollingTasks = buildPollingTasks();
if (!Files.exists(devicesDir)) { if (CollectionUtils.isEmpty(pollingTasks)) {
log.error("Devices目录不存在: {}", devicesDir); log.warn("未查询到可用的Modbus采集点位配置跳过本轮轮询");
polling.set(false); polling.set(false);
return; return;
} }
List<Path> jsonFiles = null; // 按主机IP分组同一网关串行访问避免连接抖动
try { Map<String, List<PollingTask>> groupedByHost = pollingTasks.stream()
jsonFiles = Files.list(devicesDir) .collect(Collectors.groupingBy(
.filter(path -> path.toString().endsWith(".json")) task -> task.getDeviceConfig().getHost(),
.collect(Collectors.toList()); HashMap::new,
} catch (IOException e) { Collectors.toList()));
log.error("modbusPoller.loadConfigs 获取设备配置文件失败: {}", devicesDir, e);
polling.set(false);
return;
}
// 按主机IP分组同一网关的不同端口也归为一组避免并发访问导致Connection Reset
Map<String, List<DeviceConfig>> groupedByHost = new HashMap<>();
for (Path filePath : jsonFiles) {
DeviceConfig config = null;
try {
config = objectMapper.readValue(filePath.toFile(), DeviceConfig.class);
} catch (IOException e) {
log.error("modbusPoller.loadConfigs 解析设备配置文件失败: {}", filePath, e);
continue;
}
if (config.isEnabled()) {
// 只按主机IP分组确保同一网关的所有端口串行访问
String hostKey = config.getHost();
groupedByHost.computeIfAbsent(hostKey, k -> new ArrayList<>()).add(config);
}
}
// 使用单线程 executor 串行执行所有主机的 Modbus 操作
// 将所有主机的设备按顺序串行处理,避免任何并发访问
Future<?> future = modbusExecutor.submit(() -> { Future<?> future = modbusExecutor.submit(() -> {
for (Map.Entry<String, List<DeviceConfig>> entry : groupedByHost.entrySet()) { for (Map.Entry<String, List<PollingTask>> entry : groupedByHost.entrySet()) {
String hostKey = entry.getKey(); String hostKey = entry.getKey();
List<DeviceConfig> configs = entry.getValue(); List<PollingTask> tasks = entry.getValue();
for (DeviceConfig config : configs) { for (PollingTask task : tasks) {
try { try {
scheduledStart(config); scheduledStart(task.getSiteId(), task.getDeviceConfig());
// 每次读取后等待200ms给Modbus网关足够的处理时间 // 每次读取后等待200ms给Modbus网关足够的处理时间
Thread.sleep(200); Thread.sleep(200);
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
@ -147,7 +108,8 @@ public class ModbusPoller {
log.warn("Modbus轮询被中断"); log.warn("Modbus轮询被中断");
return; return;
} catch (Exception e) { } catch (Exception e) {
log.error("采集设备数据异常: {}", config.getDeviceName(), e); log.error("采集设备数据异常: siteId={}, deviceId={}",
task.getSiteId(), task.getDeviceConfig().getDeviceNumber(), e);
} }
} }
log.info("采集设备数据{}轮询任务执行完成", hostKey); log.info("采集设备数据{}轮询任务执行完成", hostKey);
@ -165,7 +127,139 @@ public class ModbusPoller {
} }
} }
public void scheduledStart(DeviceConfig config) { private List<PollingTask> buildPollingTasks() {
List<EmsPointConfig> pointConfigs = emsPointConfigMapper.selectModbusCollectPointConfigs(null);
if (CollectionUtils.isEmpty(pointConfigs)) {
return Collections.emptyList();
}
List<EmsDevicesSetting> allDevices = emsDevicesSettingMapper.selectEmsDevicesSettingList(null);
Map<String, EmsDevicesSetting> deviceMap = allDevices.stream()
.filter(Objects::nonNull)
.filter(device -> StringUtils.isNoneBlank(device.getSiteId(), device.getDeviceId()))
.collect(Collectors.toMap(
this::buildSiteDeviceKey,
device -> device,
(left, right) -> left));
Map<String, List<EmsPointConfig>> pointsByDevice = pointConfigs.stream()
.filter(Objects::nonNull)
.filter(point -> StringUtils.isNoneBlank(point.getSiteId(), point.getDeviceId()))
.collect(Collectors.groupingBy(
point -> point.getSiteId() + "_" + point.getDeviceId(),
HashMap::new,
Collectors.toList()));
List<PollingTask> tasks = new ArrayList<>();
for (Map.Entry<String, List<EmsPointConfig>> entry : pointsByDevice.entrySet()) {
String siteDeviceKey = entry.getKey();
EmsDevicesSetting device = deviceMap.get(siteDeviceKey);
if (device == null) {
log.warn("未找到设备连接配置,跳过采集: key={}", siteDeviceKey);
continue;
}
DeviceConfig deviceConfig = buildDeviceConfig(device, entry.getValue());
if (deviceConfig == null) {
continue;
}
tasks.add(new PollingTask(device.getSiteId(), deviceConfig));
}
return tasks;
}
private DeviceConfig buildDeviceConfig(EmsDevicesSetting device, List<EmsPointConfig> pointConfigs) {
if (device == null || CollectionUtils.isEmpty(pointConfigs)) {
return null;
}
if (StringUtils.isBlank(device.getIpAddress()) || device.getIpPort() == null || device.getSlaveId() == null) {
log.warn("设备连接参数不完整,跳过采集: siteId={}, deviceId={}", device.getSiteId(), device.getDeviceId());
return null;
}
List<TagConfig> tags = pointConfigs.stream()
.sorted(Comparator.comparing(point -> point.getModbusReadOrder() == null ? 0 : point.getModbusReadOrder()))
.map(this::toTagConfig)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(tags)) {
log.warn("设备无有效Modbus点位配置跳过采集: siteId={}, deviceId={}", device.getSiteId(), device.getDeviceId());
return null;
}
DeviceConfig deviceConfig = new DeviceConfig();
deviceConfig.setEnabled(true);
deviceConfig.setDeviceName(device.getDeviceName());
deviceConfig.setDeviceNumber(device.getDeviceId());
deviceConfig.setHost(device.getIpAddress());
deviceConfig.setPort(device.getIpPort().intValue());
deviceConfig.setSlaveId(device.getSlaveId().intValue());
deviceConfig.setTags(tags);
return deviceConfig;
}
private TagConfig toTagConfig(EmsPointConfig pointConfig) {
if (pointConfig == null) {
return null;
}
if (StringUtils.isBlank(pointConfig.getDataKey())) {
return null;
}
String address = normalizeAddress(pointConfig.getRegisterAddress(), pointConfig.getModbusRegisterType());
if (StringUtils.isBlank(address)) {
return null;
}
if (StringUtils.isBlank(pointConfig.getModbusDataType())) {
return null;
}
TagConfig tag = new TagConfig();
tag.setKey(pointConfig.getDataKey().trim());
tag.setAddress(address);
tag.setDataType(pointConfig.getModbusDataType().trim());
tag.setA(pointConfig.getDataA() == null ? 0F : pointConfig.getDataA().floatValue());
tag.setK(pointConfig.getDataK() == null ? 1F : pointConfig.getDataK().floatValue());
tag.setB(pointConfig.getDataB() == null ? 0F : pointConfig.getDataB().floatValue());
tag.setBit(pointConfig.getDataBit());
return tag;
}
private String normalizeAddress(String registerAddress, String registerType) {
if (StringUtils.isBlank(registerAddress)) {
return null;
}
String normalizedAddress = registerAddress.trim();
if (!normalizedAddress.chars().allMatch(Character::isDigit)) {
log.warn("寄存器地址必须为数字,当前值: {}", normalizedAddress);
return null;
}
if (normalizedAddress.length() > 1) {
char first = normalizedAddress.charAt(0);
if (first >= '0' && first <= '4') {
return normalizedAddress;
}
}
return getRegisterPrefix(registerType) + normalizedAddress;
}
private String getRegisterPrefix(String registerType) {
String normalized = StringUtils.defaultString(registerType).trim().toUpperCase();
switch (normalized) {
case "COIL":
return "0";
case "DISCRETE_INPUT":
return "1";
case "INPUT_REGISTER":
return "3";
case "HOLDING_REGISTER":
default:
return "4";
}
}
private String buildSiteDeviceKey(EmsDevicesSetting device) {
return device.getSiteId() + "_" + device.getDeviceId();
}
public void scheduledStart(String siteId, DeviceConfig config) {
if (config.isEnabled()) { if (config.isEnabled()) {
log.info("Reading data from devices: {}", config.getDeviceName()); log.info("Reading data from devices: {}", config.getDeviceName());
@ -205,7 +299,7 @@ public class ModbusPoller {
log.info("Data from {}: {}", config.getDeviceName(), data); log.info("Data from {}: {}", config.getDeviceName(), data);
String deviceNumber = config.getDeviceNumber(); String deviceNumber = config.getDeviceNumber();
//处理数据并发送MQTT消息、保存Redis数据和数据入库 //处理数据并发送MQTT消息、保存Redis数据和数据入库
processingData(data, deviceNumber); processingData(siteId, data, deviceNumber);
} }
} }
@ -254,25 +348,27 @@ public class ModbusPoller {
return data; return data;
} }
private void processingData(Map<String, Object> data, String deviceNumber) { private void processingData(String siteId, Map<String, Object> data, String deviceNumber) {
String siteDeviceKey = siteId + "_" + deviceNumber;
if (CollectionUtils.isEmpty(data)) { if (CollectionUtils.isEmpty(data)) {
// 增加失败计数 // 增加失败计数
int failureCount = deviceFailureCounts.getOrDefault(deviceNumber, 0) + 1; int failureCount = deviceFailureCounts.getOrDefault(siteDeviceKey, 0) + 1;
deviceFailureCounts.put(deviceNumber, failureCount); deviceFailureCounts.put(siteDeviceKey, failureCount);
log.warn("设备 {} 数据读取失败,当前连续失败次数: {}", deviceNumber, failureCount); log.warn("设备 {} 数据读取失败,当前连续失败次数: {}", siteDeviceKey, failureCount);
// 连续6次失败触发报警 // 连续6次失败触发报警
if (failureCount >= 6) { if (failureCount >= SITE_DEVICE_OFFLINE_THRESHOLD) {
addDeviceOfflineRecord(siteId, deviceNumber); addDeviceOfflineRecord(siteId, deviceNumber);
log.error("设备 {} 连续 {} 次未读取到数据,触发报警", deviceNumber, failureCount); log.error("设备 {} 连续 {} 次未读取到数据,触发报警", siteDeviceKey, failureCount);
} }
return; return;
} }
// 数据读取成功,重置计数器 // 数据读取成功,重置计数器
deviceFailureCounts.remove(deviceNumber); deviceFailureCounts.remove(siteDeviceKey);
updateDeviceStatus(siteId, deviceNumber, DeviceRunningStatus.ONLINE.getCode()); // 读取到数据后告警自恢复
deleteDeviceOfflineRecord(siteId, deviceNumber);
// 发送MQTT消息、保存Redis数据和数据入库 // 发送MQTT消息、保存Redis数据和数据入库
Long timestamp = System.currentTimeMillis(); Long timestamp = System.currentTimeMillis();
@ -280,9 +376,42 @@ public class ModbusPoller {
json.put("Data", data); json.put("Data", data);
json.put("timestamp", timestamp); json.put("timestamp", timestamp);
json.put("Device", deviceNumber); json.put("Device", deviceNumber);
sendMqttMsg(json); if (shouldSendMqttOnChange(siteId, deviceNumber, data)) {
saveRedisData(json, deviceNumber); sendMqttMsg(json);
saveDataToDatabase(data, deviceNumber, timestamp); } else {
sendMqttHeartbeat(deviceNumber, timestamp);
log.info("设备 {} 数据无变化已发送心跳MQTT", siteDeviceKey);
}
saveRedisData(siteId, json, deviceNumber);
saveDataToDatabase(siteId, data, deviceNumber, timestamp);
}
/**
* 逢变上送仅当Data发生变化时才发送MQTT
*/
private boolean shouldSendMqttOnChange(String siteId, String deviceNumber, Map<String, Object> currentData) {
JSONObject lastPayload = redisCache.getCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceNumber);
if (lastPayload == null) {
return true;
}
Object lastDataObj = lastPayload.get("Data");
if (lastDataObj == null) {
return true;
}
JSONObject lastData = JSON.parseObject(JSON.toJSONString(lastDataObj));
JSONObject currentDataJson = JSON.parseObject(JSON.toJSONString(currentData));
return !Objects.equals(lastData, currentDataJson);
}
private void sendMqttHeartbeat(String deviceNumber, Long timestamp) {
JSONObject heartbeat = new JSONObject();
heartbeat.put("Device", deviceNumber);
heartbeat.put("timestamp", timestamp);
heartbeat.put("Heartbeat", 1);
heartbeat.put("Data", new JSONObject());
sendMqttMsg(heartbeat);
} }
public void sendMqttMsg(JSONObject json) { public void sendMqttMsg(JSONObject json) {
@ -295,7 +424,7 @@ public class ModbusPoller {
} }
public void saveRedisData(JSONObject obj, String deviceNumber) { public void saveRedisData(String siteId, JSONObject obj, String deviceNumber) {
try { try {
// 存放mqtt原始每个设备最晚一次数据便于后面点位获取数据 // 存放mqtt原始每个设备最晚一次数据便于后面点位获取数据
redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceNumber, obj); redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA + siteId + "_" + deviceNumber, obj);
@ -307,8 +436,12 @@ public class ModbusPoller {
} }
} }
private void saveDataToDatabase(Map<String, Object> data, String deviceNumber, Long timestamp) { private void saveDataToDatabase(String siteId, Map<String, Object> data, String deviceNumber, Long timestamp) {
deviceDataProcessServiceImpl.processingDeviceData(siteId, deviceNumber, JSON.toJSONString(data), DateUtils.convertUpdateTime(timestamp)); JSONObject payload = new JSONObject();
payload.put("Device", deviceNumber);
payload.put("Data", JSON.toJSONString(data));
payload.put("timestamp", timestamp);
deviceDataProcessServiceImpl.handleDeviceData(Collections.singletonList(payload).toString(), siteId);
} }
//处理设备连接失败的情况,更新设备状态为离线,添加报警记录 //处理设备连接失败的情况,更新设备状态为离线,添加报警记录
@ -317,6 +450,12 @@ public class ModbusPoller {
iEmsAlarmRecordsService.addDeviceOfflineRecord(siteId, deviceNumber); iEmsAlarmRecordsService.addDeviceOfflineRecord(siteId, deviceNumber);
} }
//处理设备读取到数据的情况,更新设备状态为在线,报警记录自恢复
private void deleteDeviceOfflineRecord(String siteId, String deviceNumber) {
updateDeviceStatus(siteId, deviceNumber, DeviceRunningStatus.ONLINE.getCode());
iEmsAlarmRecordsService.deleteDeviceOfflineRecord(siteId, deviceNumber);
}
// 更新设备状态为在线或离线 // 更新设备状态为在线或离线
private void updateDeviceStatus(String siteId, String deviceNumber, String deviceStatus) { private void updateDeviceStatus(String siteId, String deviceNumber, String deviceStatus) {
EmsDevicesSetting emsDevicesSetting = emsDevicesSettingMapper.getDeviceBySiteAndDeviceId(deviceNumber, siteId); EmsDevicesSetting emsDevicesSetting = emsDevicesSettingMapper.getDeviceBySiteAndDeviceId(deviceNumber, siteId);
@ -326,11 +465,22 @@ public class ModbusPoller {
} }
} }
private int getScheduledTaskInterval() { private static class PollingTask {
SysJob query = new SysJob(); private final String siteId;
query.setInvokeTarget("modbusPoller.pollAllDevices"); private final DeviceConfig deviceConfig;
List<SysJob> sysJobs = iSysJobService.selectJobList(query);
return Math.toIntExact(CronUtils.getNextExecutionIntervalMillis(sysJobs.get(0).getCronExpression())); private PollingTask(String siteId, DeviceConfig deviceConfig) {
this.siteId = siteId;
this.deviceConfig = deviceConfig;
}
public String getSiteId() {
return siteId;
}
public DeviceConfig getDeviceConfig() {
return deviceConfig;
}
} }
} }

View File

@ -10,40 +10,16 @@ import com.xzzn.common.core.redis.RedisCache;
import com.xzzn.common.enums.AlarmLevelStatus; import com.xzzn.common.enums.AlarmLevelStatus;
import com.xzzn.common.enums.AlarmStatus; import com.xzzn.common.enums.AlarmStatus;
import com.xzzn.common.enums.ProtPlanStatus; import com.xzzn.common.enums.ProtPlanStatus;
import com.xzzn.common.enums.StrategyStatus;
import com.xzzn.common.utils.StringUtils; import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.domain.EmsAlarmRecords; import com.xzzn.ems.domain.EmsAlarmRecords;
import com.xzzn.ems.domain.EmsDevicesSetting;
import com.xzzn.ems.domain.EmsFaultIssueLog;
import com.xzzn.ems.domain.EmsFaultProtectionPlan; import com.xzzn.ems.domain.EmsFaultProtectionPlan;
import com.xzzn.ems.domain.EmsStrategyRunning; import com.xzzn.ems.domain.vo.ProtectionConstraintVo;
import com.xzzn.ems.domain.vo.ProtectionPlanVo; import com.xzzn.ems.domain.vo.ProtectionPlanVo;
import com.xzzn.ems.domain.vo.ProtectionSettingVo; import com.xzzn.ems.domain.vo.ProtectionSettingVo;
import com.xzzn.ems.domain.vo.ProtectionSettingsGroupVo;
import com.xzzn.ems.mapper.EmsAlarmRecordsMapper; import com.xzzn.ems.mapper.EmsAlarmRecordsMapper;
import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
import com.xzzn.ems.mapper.EmsFaultIssueLogMapper;
import com.xzzn.ems.mapper.EmsFaultProtectionPlanMapper; import com.xzzn.ems.mapper.EmsFaultProtectionPlanMapper;
import com.xzzn.ems.mapper.EmsStrategyRunningMapper;
import com.xzzn.ems.service.IEmsFaultProtectionPlanService; import com.xzzn.ems.service.IEmsFaultProtectionPlanService;
import com.xzzn.common.core.modbus.ModbusProcessor;
import com.xzzn.common.core.modbus.domain.DeviceConfig;
import com.xzzn.common.core.modbus.domain.WriteTagConfig;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -51,14 +27,29 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* 告警保护方案轮询 * 告警保护方案轮询
*
* @author xzzn
*/ */
@Component("protectionPlanTask") @Component("protectionPlanTask")
public class ProtectionPlanTask { public class ProtectionPlanTask {
private static final Logger logger = LoggerFactory.getLogger(ProtectionPlanTask.class); private static final Logger logger = LoggerFactory.getLogger(ProtectionPlanTask.class);
private static final BigDecimal DEFAULT_L1_POWER_RATIO = new BigDecimal("0.5");
private static final int CONSTRAINT_TTL_SECONDS = 120;
@Resource(name = "scheduledExecutorService") @Resource(name = "scheduledExecutorService")
private ScheduledExecutorService scheduledExecutorService; private ScheduledExecutorService scheduledExecutorService;
@Autowired @Autowired
@ -66,18 +57,11 @@ public class ProtectionPlanTask {
@Autowired @Autowired
private EmsAlarmRecordsMapper emsAlarmRecordsMapper; private EmsAlarmRecordsMapper emsAlarmRecordsMapper;
@Autowired @Autowired
private EmsStrategyRunningMapper emsStrategyRunningMapper;
@Autowired
private EmsFaultProtectionPlanMapper emsFaultProtectionPlanMapper; private EmsFaultProtectionPlanMapper emsFaultProtectionPlanMapper;
@Autowired @Autowired
private RedisCache redisCache; private RedisCache redisCache;
private static final ObjectMapper objectMapper = new ObjectMapper(); private static final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private EmsDevicesSettingMapper emsDevicesSettingMapper;
@Autowired
private ModbusProcessor modbusProcessor;
@Autowired
private EmsFaultIssueLogMapper emsFaultIssueLogMapper;
public ProtectionPlanTask(IEmsFaultProtectionPlanService iEmsFaultProtectionPlanService) { public ProtectionPlanTask(IEmsFaultProtectionPlanService iEmsFaultProtectionPlanService) {
this.iEmsFaultProtectionPlanService = iEmsFaultProtectionPlanService; this.iEmsFaultProtectionPlanService = iEmsFaultProtectionPlanService;
@ -86,303 +70,456 @@ public class ProtectionPlanTask {
public void pollPlanList() { public void pollPlanList() {
Long planId = 0L; Long planId = 0L;
try { try {
// 获取所有方案,轮询
List<EmsFaultProtectionPlan> planList = iEmsFaultProtectionPlanService.selectEmsFaultProtectionPlanList(null); List<EmsFaultProtectionPlan> planList = iEmsFaultProtectionPlanService.selectEmsFaultProtectionPlanList(null);
for (EmsFaultProtectionPlan plan : planList) { for (EmsFaultProtectionPlan plan : planList) {
planId = plan.getId(); planId = plan.getId();
String siteId = plan.getSiteId(); String siteId = plan.getSiteId();
if (StringUtils.isEmpty(siteId)) { if (StringUtils.isEmpty(siteId)) {
return; continue;
} }
// 保护前提 ProtectionSettingsGroupVo settingGroup = parseProtectionSettings(plan.getProtectionSettings());
String protectionSettings = plan.getProtectionSettings(); if (CollectionUtils.isEmpty(settingGroup.getFaultSettings())
final List<ProtectionSettingVo> protSettings = objectMapper.readValue( && CollectionUtils.isEmpty(settingGroup.getReleaseSettings())) {
protectionSettings, continue;
new TypeReference<List<ProtectionSettingVo>>() {}
);
if (protSettings == null) {
return;
}
// 处理告警保护方案
boolean isHighLevel = dealWithProtectionPlan(plan, protSettings);
if (isHighLevel) {
// 触发最高故障等级-结束循环
return;
} }
dealWithProtectionPlan(plan, settingGroup);
} }
refreshProtectionConstraintCache(planList);
} catch (Exception e) { } catch (Exception e) {
logger.error("轮询失败,方案id为{}", planId, e); logger.error("轮询失败,方案id为{}", planId, e);
} }
} }
// 处理告警保护方案-返回触发下发方案时是否最高等级
// 需要同步云端
@SyncAfterInsert @SyncAfterInsert
private boolean dealWithProtectionPlan(EmsFaultProtectionPlan plan, List<ProtectionSettingVo> protSettings) { private void dealWithProtectionPlan(EmsFaultProtectionPlan plan, ProtectionSettingsGroupVo settingGroup) {
logger.info("<轮询保护方案> 站点:{}方案ID:{}", plan.getSiteId(), plan.getId()); logger.info("<轮询保护方案> 站点:{}方案ID:{}", plan.getSiteId(), plan.getId());
boolean isHighLevel = false;
String siteId = plan.getSiteId(); String siteId = plan.getSiteId();
final Integer isAlertAlarm = plan.getIsAlert(); Integer isAlertAlarm = plan.getIsAlert();
final Long status = plan.getStatus(); List<ProtectionSettingVo> faultSettings = settingGroup.getFaultSettings();
// 看方案是否启用,走不同判断 List<ProtectionSettingVo> releaseSettings = settingGroup.getReleaseSettings();
Long status = plan.getStatus();
if (status == null) {
status = ProtPlanStatus.STOP.getCode();
}
if (Objects.equals(status, ProtPlanStatus.STOP.getCode())) { if (Objects.equals(status, ProtPlanStatus.STOP.getCode())) {
logger.info("<方案未启用> 站点:{}方案ID:{}", siteId, plan.getId()); if (checkIsNeedIssuedPlan(faultSettings, siteId)) {
// 未启用,获取方案的故障值与最新数据判断是否需要下发方案 int faultDelay = safeDelaySeconds(plan.getFaultDelaySeconds(), 0);
if(checkIsNeedIssuedPlan(protSettings, siteId)){ scheduledExecutorService.schedule(() -> {
if("3".equals(plan.getFaultLevel())){ if (!checkIsNeedIssuedPlan(faultSettings, siteId)) {
isHighLevel = true;//最高故障等级 return;
}
// 延时
final int faultDelay = plan.getFaultDelaySeconds().intValue();
ScheduledFuture<?> delayTask = scheduledExecutorService.schedule(() -> {
// 延时后再次确认是否仍满足触发条件(防止期间状态变化)
if (checkIsNeedIssuedPlan(protSettings, siteId)) {
// 判断是否需要生成告警
if (isAlertAlarm == 1) {
logger.info("<生成告警> 方案ID:{},站点:{}", plan.getId(), siteId);
EmsAlarmRecords alarmRecords = addAlarmRecord(siteId,plan.getFaultName(),
getAlarmLevel(plan.getFaultLevel()));
emsAlarmRecordsMapper.insertEmsAlarmRecords(alarmRecords);
}
// 是否有保护方案有则通过modbus连接设备下发方案
String protPlanJson = plan.getProtectionPlan();
if (protPlanJson != null && !protPlanJson.isEmpty() && !"[]".equals(protPlanJson)) {
logger.info("<下发保护方案> 方案内容:{}", protPlanJson);
executeProtectionActions(protPlanJson,siteId,plan.getId(),plan.getFaultLevel()); // 执行Modbus指令
}
// 更新方案状态为“已启用”
logger.info("<方案已启用> 方案ID:{}", plan.getId());
plan.setStatus(ProtPlanStatus.RUNNING.getCode());
emsFaultProtectionPlanMapper.updateEmsFaultProtectionPlan(plan);
// 更新该站点策略为暂停状态
updateStrategyRunningStatus(siteId, StrategyStatus.SUSPENDED.getCode());
} }
}, faultDelay, TimeUnit.SECONDS); if (Integer.valueOf(1).equals(isAlertAlarm)) {
} EmsAlarmRecords alarmRecords = addAlarmRecord(siteId, plan.getFaultName(), getAlarmLevel(plan.getFaultLevel()));
} else { emsAlarmRecordsMapper.insertEmsAlarmRecords(alarmRecords);
logger.info("<方案已启用> 站点:{}方案ID:{}", siteId, plan.getId());
// 已启用,则获取方案的释放值与最新数据判断是否需要取消方案
if(checkIsNeedCancelPlan(protSettings, siteId)){
// 延时,
int releaseDelay = plan.getReleaseDelaySeconds().intValue();
ScheduledFuture<?> delayTask = scheduledExecutorService.schedule(() -> {
// 判断是否已存在未处理告警,有着取消
if(isAlertAlarm == 1){
logger.info("<取消告警>");
EmsAlarmRecords emsAlarmRecords = emsAlarmRecordsMapper.getFailedRecord(siteId,
plan.getFaultName(),getAlarmLevel(plan.getFaultLevel()));
if(emsAlarmRecords != null){
emsAlarmRecords.setStatus(AlarmStatus.DONE.getCode());
emsAlarmRecordsMapper.updateEmsAlarmRecords(emsAlarmRecords);
}
} }
// 更新方案状态为“未启用” plan.setStatus(ProtPlanStatus.RUNNING.getCode());
logger.info("<方案变更为未启用> 方案ID:{}", plan.getId());
plan.setStatus(ProtPlanStatus.STOP.getCode());
plan.setUpdateBy("system"); plan.setUpdateBy("system");
emsFaultProtectionPlanMapper.updateEmsFaultProtectionPlan(plan); emsFaultProtectionPlanMapper.updateEmsFaultProtectionPlan(plan);
// 更新该站点策略为启用状态 refreshSiteProtectionConstraint(siteId);
updateStrategyRunningStatus(siteId, StrategyStatus.RUNNING.getCode()); }, faultDelay, TimeUnit.SECONDS);
}, releaseDelay, TimeUnit.SECONDS);
} }
}
return isHighLevel;
}
// 下发保护方案
private void executeProtectionActions(String protPlanJson, String siteId, Long planId, Integer faultLevel){
final List<ProtectionPlanVo> protPlanList;
try {
protPlanList = objectMapper.readValue(
protPlanJson,
new TypeReference<List<ProtectionPlanVo>>() {}
);
if (protPlanList == null) {
return;
}
// 遍历保护方案
for (ProtectionPlanVo plan : protPlanList) {
if (StringUtils.isEmpty(plan.getDeviceId()) || StringUtils.isEmpty(plan.getPoint())) {
return;
}
// 给设备发送指令记录日志,并同步云端
EmsFaultIssueLog faultIssueLog = createLogEntity(plan,siteId);
faultIssueLog.setLogLevel(faultLevel);
emsFaultIssueLogMapper.insertEmsFaultIssueLog(faultIssueLog);
// 通过modbus连接设备发送数据
executeSinglePlan(plan,siteId);
}
} catch (Exception e) {
logger.error("下发保护方案失败,方案id为", planId, e);
}
}
private EmsFaultIssueLog createLogEntity(ProtectionPlanVo plan,String siteId) {
EmsFaultIssueLog faultIssueLog = new EmsFaultIssueLog();
faultIssueLog.setLogId(UUID.randomUUID().toString());
faultIssueLog.setLogTime(new Date());
faultIssueLog.setSiteId(siteId);
faultIssueLog.setDeviceId(plan.getDeviceId());
faultIssueLog.setPoint(plan.getPoint());
faultIssueLog.setValue(plan.getValue());
faultIssueLog.setCreateBy("sys");
faultIssueLog.setCreateTime(new Date());
return faultIssueLog;
}
private void executeSinglePlan(ProtectionPlanVo plan, String siteId) throws Exception {
String deviceId = plan.getDeviceId();
// 获取设备地址信息
EmsDevicesSetting device = emsDevicesSettingMapper.getDeviceBySiteAndDeviceId(deviceId, siteId);
if (device == null || StringUtils.isEmpty(device.getIpAddress()) || device.getIpPort()==null) {
logger.warn("设备信息不完整deviceId:{}", deviceId);
return; return;
} }
// 构建设备配置 if (checkIsNeedCancelPlan(releaseSettings, siteId)) {
DeviceConfig config = new DeviceConfig(); int releaseDelay = safeDelaySeconds(plan.getReleaseDelaySeconds(), 0);
config.setHost(device.getIpAddress()); scheduledExecutorService.schedule(() -> {
config.setPort(device.getIpPort().intValue()); if (Integer.valueOf(1).equals(isAlertAlarm)) {
config.setSlaveId(device.getSlaveId().intValue()); EmsAlarmRecords emsAlarmRecords = emsAlarmRecordsMapper.getFailedRecord(
config.setDeviceName(device.getDeviceName()); siteId,
config.setDeviceNumber(device.getDeviceId()); plan.getFaultName(),
getAlarmLevel(plan.getFaultLevel())
// 构建写入标签配置 );
WriteTagConfig writeTag = new WriteTagConfig(); if (emsAlarmRecords != null) {
writeTag.setAddress(plan.getPoint()); emsAlarmRecords.setStatus(AlarmStatus.DONE.getCode());
writeTag.setValue(plan.getValue()); emsAlarmRecordsMapper.updateEmsAlarmRecords(emsAlarmRecords);
}
List<WriteTagConfig> writeTags = new ArrayList<>(); }
writeTags.add(writeTag); plan.setStatus(ProtPlanStatus.STOP.getCode());
config.setWriteTags(writeTags); plan.setUpdateBy("system");
emsFaultProtectionPlanMapper.updateEmsFaultProtectionPlan(plan);
// 写入数据到设备 refreshSiteProtectionConstraint(siteId);
boolean success = modbusProcessor.writeDataToDeviceWithRetry(config); }, releaseDelay, TimeUnit.SECONDS);
if (!success) {
logger.error("写入失败,设备地址:{}", device.getIpAddress());
} }
} }
// 校验释放值是否取消方案 private int safeDelaySeconds(Long delay, int defaultSeconds) {
private boolean checkIsNeedCancelPlan(List<ProtectionSettingVo> protSettings, String siteId) { if (delay == null || delay < 0) {
BigDecimal releaseValue = BigDecimal.ZERO; return defaultSeconds;
}
return delay.intValue();
}
private ProtectionSettingsGroupVo parseProtectionSettings(String settingsJson) {
if (StringUtils.isEmpty(settingsJson)) {
return ProtectionSettingsGroupVo.empty();
}
try {
if (settingsJson.trim().startsWith("[")) {
List<ProtectionSettingVo> legacy = objectMapper.readValue(
settingsJson,
new TypeReference<List<ProtectionSettingVo>>() {}
);
ProtectionSettingsGroupVo groupVo = ProtectionSettingsGroupVo.empty();
groupVo.setFaultSettings(legacy);
groupVo.setReleaseSettings(legacy);
return groupVo;
}
ProtectionSettingsGroupVo groupVo = objectMapper.readValue(settingsJson, ProtectionSettingsGroupVo.class);
if (groupVo == null) {
return ProtectionSettingsGroupVo.empty();
}
if (groupVo.getFaultSettings() == null) {
groupVo.setFaultSettings(new ArrayList<>());
}
if (groupVo.getReleaseSettings() == null) {
groupVo.setReleaseSettings(new ArrayList<>());
}
return groupVo;
} catch (Exception e) {
logger.error("解析保护前提失败json:{}", settingsJson, e);
return ProtectionSettingsGroupVo.empty();
}
}
private List<ProtectionPlanVo> parseProtectionPlan(String planJson) {
if (StringUtils.isEmpty(planJson)) {
return new ArrayList<>();
}
try {
if (planJson.trim().startsWith("[")) {
List<ProtectionPlanVo> plans = objectMapper.readValue(
planJson,
new TypeReference<List<ProtectionPlanVo>>() {}
);
return plans == null ? new ArrayList<>() : plans;
}
ProtectionPlanVo plan = objectMapper.readValue(planJson, ProtectionPlanVo.class);
List<ProtectionPlanVo> plans = new ArrayList<>();
if (plan != null) {
plans.add(plan);
}
return plans;
} catch (Exception e) {
logger.error("解析执行保护失败json:{}", planJson, e);
return new ArrayList<>();
}
}
private void refreshProtectionConstraintCache(List<EmsFaultProtectionPlan> allPlans) {
Map<String, List<EmsFaultProtectionPlan>> planBySite = new HashMap<>();
for (EmsFaultProtectionPlan plan : allPlans) {
if (StringUtils.isEmpty(plan.getSiteId())) {
continue;
}
planBySite.computeIfAbsent(plan.getSiteId(), k -> new ArrayList<>()).add(plan);
}
for (Map.Entry<String, List<EmsFaultProtectionPlan>> entry : planBySite.entrySet()) {
writeSiteProtectionConstraint(entry.getKey(), entry.getValue());
}
}
private void refreshSiteProtectionConstraint(String siteId) {
if (StringUtils.isEmpty(siteId)) {
return;
}
EmsFaultProtectionPlan query = new EmsFaultProtectionPlan();
query.setSiteId(siteId);
List<EmsFaultProtectionPlan> sitePlans = iEmsFaultProtectionPlanService.selectEmsFaultProtectionPlanList(query);
writeSiteProtectionConstraint(siteId, sitePlans);
}
private void writeSiteProtectionConstraint(String siteId, List<EmsFaultProtectionPlan> sitePlans) {
List<EmsFaultProtectionPlan> runningPlans = new ArrayList<>();
for (EmsFaultProtectionPlan plan : sitePlans) {
if (Objects.equals(plan.getStatus(), ProtPlanStatus.RUNNING.getCode())) {
runningPlans.add(plan);
}
}
String key = RedisKeyConstants.PROTECTION_CONSTRAINT + siteId;
if (runningPlans.isEmpty()) {
redisCache.deleteObject(key);
return;
}
ProtectionConstraintVo merged = ProtectionConstraintVo.empty();
for (EmsFaultProtectionPlan runningPlan : runningPlans) {
ProtectionConstraintVo single = buildConstraintFromPlan(runningPlan);
mergeConstraint(merged, single);
}
merged.setUpdateAt(System.currentTimeMillis());
redisCache.setCacheObject(key, merged, CONSTRAINT_TTL_SECONDS, TimeUnit.SECONDS);
}
private ProtectionConstraintVo buildConstraintFromPlan(EmsFaultProtectionPlan plan) {
ProtectionConstraintVo vo = ProtectionConstraintVo.empty();
int level = plan.getFaultLevel() == null ? 0 : plan.getFaultLevel();
vo.setLevel(level);
vo.setSourcePlanIds(new ArrayList<>());
vo.getSourcePlanIds().add(plan.getId());
if (level == 1) {
vo.setPowerLimitRatio(DEFAULT_L1_POWER_RATIO);
} else if (level >= 3) {
vo.setForceStop(true);
vo.setForceStandby(true);
vo.setAllowCharge(false);
vo.setAllowDischarge(false);
vo.setPowerLimitRatio(BigDecimal.ZERO);
}
String description = StringUtils.isEmpty(plan.getDescription()) ? "" : plan.getDescription();
BigDecimal ratioByDesc = parseDerateRatio(description);
if (ratioByDesc != null) {
vo.setPowerLimitRatio(minRatio(vo.getPowerLimitRatio(), ratioByDesc));
}
if (description.contains("禁止充放电")) {
vo.setAllowCharge(false);
vo.setAllowDischarge(false);
} else {
if (description.contains("禁止充电")) {
vo.setAllowCharge(false);
}
if (description.contains("禁止放电")) {
vo.setAllowDischarge(false);
}
if (description.contains("允许充电")) {
vo.setAllowCharge(true);
}
if (description.contains("允许放电")) {
vo.setAllowDischarge(true);
}
}
if (description.contains("待机")) {
vo.setForceStandby(true);
}
if (description.contains("停机") || description.contains("切断") || level >= 3) {
vo.setForceStop(true);
vo.setForceStandby(true);
vo.setAllowCharge(false);
vo.setAllowDischarge(false);
vo.setPowerLimitRatio(BigDecimal.ZERO);
}
// 执行保护配置优先于描述文本配置
List<ProtectionPlanVo> protectionPlans = parseProtectionPlan(plan.getProtectionPlan());
applyCapabilityByProtectionPlan(vo, protectionPlans);
return vo;
}
private void applyCapabilityByProtectionPlan(ProtectionConstraintVo vo, List<ProtectionPlanVo> protectionPlans) {
if (CollectionUtils.isEmpty(protectionPlans)) {
return;
}
for (ProtectionPlanVo item : protectionPlans) {
if (item == null) {
continue;
}
String marker = ((item.getPointName() == null ? "" : item.getPointName()) + " "
+ (item.getPoint() == null ? "" : item.getPoint())).toLowerCase();
if (StringUtils.isEmpty(marker)) {
continue;
}
if (containsAny(marker, "降功率", "derate", "power_limit", "powerlimit")) {
BigDecimal ratio = parseDerateRatioByPlan(item);
if (ratio != null) {
vo.setPowerLimitRatio(minRatio(vo.getPowerLimitRatio(), ratio));
}
}
if (!isCapabilityEnabled(item.getValue())) {
continue;
}
if (containsAny(marker, "禁止充放电", "forbid_charge_discharge", "disable_charge_discharge")) {
vo.setAllowCharge(false);
vo.setAllowDischarge(false);
continue;
}
if (containsAny(marker, "禁止充电", "forbid_charge", "disable_charge")) {
vo.setAllowCharge(false);
}
if (containsAny(marker, "禁止放电", "forbid_discharge", "disable_discharge")) {
vo.setAllowDischarge(false);
}
if (containsAny(marker, "允许充电", "allow_charge")) {
vo.setAllowCharge(true);
}
if (containsAny(marker, "允许放电", "allow_discharge")) {
vo.setAllowDischarge(true);
}
if (containsAny(marker, "待机", "standby")) {
vo.setForceStandby(true);
}
if (containsAny(marker, "关机", "停机", "切断", "shutdown", "stop")) {
vo.setForceStop(true);
vo.setForceStandby(true);
vo.setAllowCharge(false);
vo.setAllowDischarge(false);
vo.setPowerLimitRatio(BigDecimal.ZERO);
}
}
}
private BigDecimal parseDerateRatioByPlan(ProtectionPlanVo planVo) {
BigDecimal value = planVo.getValue();
if (value == null || value.compareTo(BigDecimal.ZERO) < 0) {
return null;
}
if (value.compareTo(BigDecimal.ONE) <= 0) {
return value;
}
if (value.compareTo(new BigDecimal("100")) <= 0) {
return value.divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP);
}
return null;
}
private boolean isCapabilityEnabled(BigDecimal value) {
return value == null || value.compareTo(BigDecimal.ZERO) != 0;
}
private boolean containsAny(String text, String... markers) {
if (StringUtils.isEmpty(text) || markers == null) {
return false;
}
for (String marker : markers) {
if (!StringUtils.isEmpty(marker) && text.contains(marker)) {
return true;
}
}
return false;
}
private BigDecimal parseDerateRatio(String text) {
if (StringUtils.isEmpty(text)) {
return null;
}
Matcher m = Pattern.compile("降功率\\s*(\\d+(?:\\.\\d+)?)%")
.matcher(text);
if (!m.find()) {
return null;
}
BigDecimal percent = new BigDecimal(m.group(1));
if (percent.compareTo(BigDecimal.ZERO) < 0) {
return null;
}
return percent.divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP);
}
private void mergeConstraint(ProtectionConstraintVo merged, ProtectionConstraintVo incoming) {
if (incoming == null) {
return;
}
merged.setLevel(Math.max(nullSafeInt(merged.getLevel()), nullSafeInt(incoming.getLevel())));
merged.setAllowCharge(boolAnd(merged.getAllowCharge(), incoming.getAllowCharge()));
merged.setAllowDischarge(boolAnd(merged.getAllowDischarge(), incoming.getAllowDischarge()));
merged.setForceStandby(boolOr(merged.getForceStandby(), incoming.getForceStandby()));
merged.setForceStop(boolOr(merged.getForceStop(), incoming.getForceStop()));
merged.setPowerLimitRatio(minRatio(merged.getPowerLimitRatio(), incoming.getPowerLimitRatio()));
if (incoming.getSourcePlanIds() != null && !incoming.getSourcePlanIds().isEmpty()) {
if (merged.getSourcePlanIds() == null) {
merged.setSourcePlanIds(new ArrayList<>());
}
merged.getSourcePlanIds().addAll(incoming.getSourcePlanIds());
}
}
private BigDecimal minRatio(BigDecimal a, BigDecimal b) {
BigDecimal left = a == null ? BigDecimal.ONE : a;
BigDecimal right = b == null ? BigDecimal.ONE : b;
return left.min(right);
}
private int nullSafeInt(Integer value) {
return value == null ? 0 : value;
}
private Boolean boolAnd(Boolean a, Boolean b) {
boolean left = a == null || a;
boolean right = b == null || b;
return left && right;
}
private Boolean boolOr(Boolean a, Boolean b) {
boolean left = a != null && a;
boolean right = b != null && b;
return left || right;
}
private boolean checkIsNeedCancelPlan(List<ProtectionSettingVo> protSettings, String siteId) {
StringBuilder conditionSb = new StringBuilder(); StringBuilder conditionSb = new StringBuilder();
for (int i = 0; i < protSettings.size(); i++) { for (int i = 0; i < protSettings.size(); i++) {
ProtectionSettingVo vo = protSettings.get(i); ProtectionSettingVo vo = protSettings.get(i);
String deviceId = vo.getDeviceId(); String deviceId = vo.getDeviceId();
String point = vo.getPoint(); String point = vo.getPoint();
releaseValue = vo.getFaultValue(); BigDecimal releaseValue = vo.getReleaseValue();
if(StringUtils.isEmpty(deviceId) || StringUtils.isEmpty(point) || releaseValue == null if (StringUtils.isEmpty(deviceId)
|| StringUtils.isEmpty(vo.getReleaseOperator())){ || StringUtils.isEmpty(point)
|| releaseValue == null
|| StringUtils.isEmpty(vo.getReleaseOperator())) {
return false; return false;
} }
// 获取点位最新值
BigDecimal lastPointValue = getPointLastValue(deviceId, point, siteId); BigDecimal lastPointValue = getPointLastValue(deviceId, point, siteId);
logger.info("checkIsNeedCancelPlan 点位:{},最新值:{},比较方式:{},释放值:{}", point, lastPointValue, vo.getReleaseOperator(), releaseValue); if (lastPointValue == null) {
if(lastPointValue == null){
return false; return false;
} }
// 拼接校验语句-最新值+比较方式+故障值+与下一点位关系(最后一个条件后不加关系)
conditionSb.append(lastPointValue).append(vo.getReleaseOperator()).append(releaseValue); conditionSb.append(lastPointValue).append(vo.getReleaseOperator()).append(releaseValue);
if (i < protSettings.size() - 1) { if (i < protSettings.size() - 1) {
String relation = vo.getRelationNext(); conditionSb.append(" ").append(vo.getRelationNext()).append(" ");
conditionSb.append(" ").append(relation).append(" ");
} }
} }
// 执行比较语句
return executeWithParser(conditionSb.toString()); return executeWithParser(conditionSb.toString());
} }
// 校验故障值是否需要下发方案
private boolean checkIsNeedIssuedPlan(List<ProtectionSettingVo> protSettings, String siteId) { private boolean checkIsNeedIssuedPlan(List<ProtectionSettingVo> protSettings, String siteId) {
BigDecimal faultValue = BigDecimal.ZERO;
StringBuilder conditionSb = new StringBuilder(); StringBuilder conditionSb = new StringBuilder();
for (int i = 0; i < protSettings.size(); i++) { for (int i = 0; i < protSettings.size(); i++) {
ProtectionSettingVo vo = protSettings.get(i); ProtectionSettingVo vo = protSettings.get(i);
String deviceId = vo.getDeviceId(); String deviceId = vo.getDeviceId();
String point = vo.getPoint(); String point = vo.getPoint();
faultValue = vo.getFaultValue(); BigDecimal faultValue = vo.getFaultValue();
if(StringUtils.isEmpty(deviceId) || StringUtils.isEmpty(point) || faultValue == null if (StringUtils.isEmpty(deviceId)
|| StringUtils.isEmpty(vo.getFaultOperator())){ || StringUtils.isEmpty(point)
|| faultValue == null
|| StringUtils.isEmpty(vo.getFaultOperator())) {
return false; return false;
} }
// 获取点位最新值
BigDecimal lastPointValue = getPointLastValue(deviceId, point, siteId); BigDecimal lastPointValue = getPointLastValue(deviceId, point, siteId);
logger.info("checkIsNeedIssuedPlan 点位:{},最新值:{},比较方式:{},故障值:{}", point, lastPointValue, vo.getFaultOperator(), faultValue); if (lastPointValue == null) {
if(lastPointValue == null){
return false; return false;
} }
// 拼接校验语句-最新值+比较方式+故障值+与下一点位关系(最后一个条件后不加关系)
conditionSb.append(lastPointValue).append(vo.getFaultOperator()).append(faultValue); conditionSb.append(lastPointValue).append(vo.getFaultOperator()).append(faultValue);
if (i < protSettings.size() - 1) { if (i < protSettings.size() - 1) {
String relation = vo.getRelationNext(); conditionSb.append(" ").append(vo.getRelationNext()).append(" ");
conditionSb.append(" ").append(relation).append(" ");
} }
} }
// 执行比较语句
return executeWithParser(conditionSb.toString()); return executeWithParser(conditionSb.toString());
} }
private BigDecimal getPointLastValue(String deviceId, String point, String siteId) { private BigDecimal getPointLastValue(String deviceId, String point, String siteId) {
JSONObject mqttJson = redisCache.getCacheObject(RedisKeyConstants.SYNC_DATA + siteId + "_" + deviceId); JSONObject mqttJson = redisCache.getCacheObject(RedisKeyConstants.SYNC_DATA + siteId + "_" + deviceId);
if(mqttJson == null){ if (mqttJson == null) {
return null; return null;
} }
String jsonData = mqttJson.get("Data").toString(); String jsonData = mqttJson.get("Data").toString();
if(StringUtils.isEmpty(jsonData)){ if (StringUtils.isEmpty(jsonData)) {
return null; return null;
} }
Map<String, Object> obj = JSON.parseObject(jsonData, new com.alibaba.fastjson2.TypeReference<Map<String, Object>>() {}); Map<String, Object> obj = JSON.parseObject(jsonData, new com.alibaba.fastjson2.TypeReference<Map<String, Object>>() {});
return StringUtils.getBigDecimal(obj.get(point)); return StringUtils.getBigDecimal(obj.get(point));
} }
// 更新站点策略为启用 private EmsAlarmRecords addAlarmRecord(String siteId, String content, String level) {
private void updateStrategyRunningStatus(String siteId, String status) {
// 获取是否有正在运行的策略,如果有则不更改
EmsStrategyRunning query = new EmsStrategyRunning();
query.setSiteId(siteId);
query.setStatus(StrategyStatus.RUNNING.getCode().equals(status) ? StrategyStatus.SUSPENDED.getCode() : StrategyStatus.RUNNING.getCode());
List<EmsStrategyRunning> strategyRunningList = emsStrategyRunningMapper.selectEmsStrategyRunningList(query);
if (CollectionUtils.isNotEmpty(strategyRunningList)) {
// 获取已存在并且状态为:未启用和已暂停的最晚一条策略,更新为已启用
strategyRunningList.forEach(emsStrategyRunning -> {
emsStrategyRunning.setStatus(status);
emsStrategyRunningMapper.updateEmsStrategyRunning(emsStrategyRunning);
});
}
}
// 更新站点策略为启用
private void updateStrategyRunning(String siteId) {
// 获取是否有正在运行的策略,如果有则不更改
EmsStrategyRunning emsStrategyRunning = emsStrategyRunningMapper.getRunningStrategy(siteId);
if (emsStrategyRunning == null) {
// 获取已存在并且状态为:未启用和已暂停的最晚一条策略,更新为已启用
emsStrategyRunning = emsStrategyRunningMapper.getPendingStrategy(siteId);
emsStrategyRunning.setStatus(StrategyStatus.RUNNING.getCode());
emsStrategyRunningMapper.updateEmsStrategyRunning(emsStrategyRunning);
}
}
private EmsAlarmRecords addAlarmRecord(String siteId, String content,String level) {
EmsAlarmRecords emsAlarmRecords = new EmsAlarmRecords(); EmsAlarmRecords emsAlarmRecords = new EmsAlarmRecords();
emsAlarmRecords.setSiteId(siteId); emsAlarmRecords.setSiteId(siteId);
emsAlarmRecords.setAlarmContent(content); emsAlarmRecords.setAlarmContent(content);
@ -395,29 +532,31 @@ public class ProtectionPlanTask {
return emsAlarmRecords; return emsAlarmRecords;
} }
// 故障等级-告警等级匹配
private String getAlarmLevel(Integer faultLevel) { private String getAlarmLevel(Integer faultLevel) {
if (ObjectUtils.isEmpty(faultLevel) || faultLevel < 1 || faultLevel > 3) { if (ObjectUtils.isEmpty(faultLevel) || faultLevel < 1 || faultLevel > 3) {
logger.warn("非法故障等级:{},默认返回普通告警", faultLevel); logger.warn("非法故障等级:{},默认返回紧急告警", faultLevel);
return AlarmLevelStatus.EMERGENCY.getCode(); return AlarmLevelStatus.EMERGENCY.getCode();
} }
switch (faultLevel) { switch (faultLevel) {
case 1: return AlarmLevelStatus.GENERAL.getCode(); case 1:
case 2: return AlarmLevelStatus.SERIOUS.getCode(); return AlarmLevelStatus.GENERAL.getCode();
case 3: return AlarmLevelStatus.EMERGENCY.getCode(); case 2:
return AlarmLevelStatus.SERIOUS.getCode();
case 3:
return AlarmLevelStatus.EMERGENCY.getCode();
default: default:
logger.error("未匹配的故障等级:{}", faultLevel);
return AlarmLevelStatus.EMERGENCY.getCode(); return AlarmLevelStatus.EMERGENCY.getCode();
} }
} }
// 自定义表达式解析器(仅支持简单运算符和逻辑关系) /**
* 自定义表达式解析器(仅支持简单运算符和逻辑关系)
*/
public boolean executeWithParser(String conditionStr) { public boolean executeWithParser(String conditionStr) {
if (conditionStr == null || conditionStr.isEmpty()) { if (conditionStr == null || conditionStr.isEmpty()) {
return false; return false;
} }
// 1. 拆分逻辑关系(提取 && 或 ||
List<String> logicRelations = new ArrayList<>(); List<String> logicRelations = new ArrayList<>();
Pattern logicPattern = Pattern.compile("(&&|\\|\\|)"); Pattern logicPattern = Pattern.compile("(&&|\\|\\|)");
Matcher logicMatcher = logicPattern.matcher(conditionStr); Matcher logicMatcher = logicPattern.matcher(conditionStr);
@ -425,10 +564,7 @@ public class ProtectionPlanTask {
logicRelations.add(logicMatcher.group()); logicRelations.add(logicMatcher.group());
} }
// 2. 拆分原子条件(如 "3.55>3.52"
String[] atomicConditions = logicPattern.split(conditionStr); String[] atomicConditions = logicPattern.split(conditionStr);
// 3. 解析每个原子条件并计算结果
List<Boolean> atomicResults = new ArrayList<>(); List<Boolean> atomicResults = new ArrayList<>();
Pattern conditionPattern = Pattern.compile("(\\d+\\.?\\d*)\\s*([><]=?|==)\\s*(\\d+\\.?\\d*)"); Pattern conditionPattern = Pattern.compile("(\\d+\\.?\\d*)\\s*([><]=?|==)\\s*(\\d+\\.?\\d*)");
for (String atomic : atomicConditions) { for (String atomic : atomicConditions) {
@ -437,11 +573,10 @@ public class ProtectionPlanTask {
logger.error("无效的原子条件:{}", atomic); logger.error("无效的原子条件:{}", atomic);
return false; return false;
} }
double left = Double.parseDouble(matcher.group(1)); // 左值(最新值) double left = Double.parseDouble(matcher.group(1));
String operator = matcher.group(2); // 运算符 String operator = matcher.group(2);
double right = Double.parseDouble(matcher.group(3)); // 右值(故障值) double right = Double.parseDouble(matcher.group(3));
// 执行比较
boolean result; boolean result;
switch (operator) { switch (operator) {
case ">": case ">":
@ -466,11 +601,10 @@ public class ProtectionPlanTask {
atomicResults.add(result); atomicResults.add(result);
} }
// 4. 组合原子结果(根据逻辑关系)
boolean finalResult = atomicResults.get(0); boolean finalResult = atomicResults.get(0);
for (int i = 0; i < logicRelations.size(); i++) { for (int i = 0; i < logicRelations.size(); i++) {
String relation = logicRelations.get(i); String relation = logicRelations.get(i);
boolean nextResult = atomicResults.get(i+1); boolean nextResult = atomicResults.get(i + 1);
if ("&&".equals(relation)) { if ("&&".equals(relation)) {
finalResult = finalResult && nextResult; finalResult = finalResult && nextResult;
} else if ("||".equals(relation)) { } else if ("||".equals(relation)) {

View File

@ -2,11 +2,16 @@ package com.xzzn.quartz.task;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONArray;
import com.xzzn.common.constant.RedisKeyConstants;
import com.xzzn.common.core.modbus.ModbusProcessor; import com.xzzn.common.core.modbus.ModbusProcessor;
import com.xzzn.common.core.modbus.domain.DeviceConfig; import com.xzzn.common.core.modbus.domain.DeviceConfig;
import com.xzzn.common.core.modbus.domain.WriteTagConfig; import com.xzzn.common.core.modbus.domain.WriteTagConfig;
import com.xzzn.common.core.redis.RedisCache;
import com.xzzn.common.enums.BusinessStatus;
import com.xzzn.common.enums.BusinessType;
import com.xzzn.common.enums.ChargeStatus; import com.xzzn.common.enums.ChargeStatus;
import com.xzzn.common.enums.DeviceCategory; import com.xzzn.common.enums.DeviceCategory;
import com.xzzn.common.enums.OperatorType;
import com.xzzn.common.enums.SiteDevice; import com.xzzn.common.enums.SiteDevice;
import com.xzzn.common.enums.SocLimit; import com.xzzn.common.enums.SocLimit;
import com.xzzn.common.enums.WorkStatus; import com.xzzn.common.enums.WorkStatus;
@ -16,26 +21,33 @@ import com.xzzn.ems.domain.EmsAmmeterData;
import com.xzzn.ems.domain.EmsBatteryStack; import com.xzzn.ems.domain.EmsBatteryStack;
import com.xzzn.ems.domain.EmsDevicesSetting; import com.xzzn.ems.domain.EmsDevicesSetting;
import com.xzzn.ems.domain.EmsPcsSetting; import com.xzzn.ems.domain.EmsPcsSetting;
import com.xzzn.ems.domain.EmsStrategyRuntimeConfig;
import com.xzzn.ems.domain.EmsStrategyLog; import com.xzzn.ems.domain.EmsStrategyLog;
import com.xzzn.ems.domain.EmsStrategyTemp; import com.xzzn.ems.domain.EmsStrategyTemp;
import com.xzzn.ems.domain.EmsStrategyTimeConfig; import com.xzzn.ems.domain.EmsStrategyTimeConfig;
import com.xzzn.ems.domain.vo.ProtectionConstraintVo;
import com.xzzn.ems.domain.vo.StrategyRunningVo; import com.xzzn.ems.domain.vo.StrategyRunningVo;
import com.xzzn.ems.mapper.EmsAmmeterDataMapper; import com.xzzn.ems.mapper.EmsAmmeterDataMapper;
import com.xzzn.ems.mapper.EmsBatteryStackMapper; import com.xzzn.ems.mapper.EmsBatteryStackMapper;
import com.xzzn.ems.mapper.EmsDevicesSettingMapper; import com.xzzn.ems.mapper.EmsDevicesSettingMapper;
import com.xzzn.ems.mapper.EmsPcsSettingMapper; import com.xzzn.ems.mapper.EmsPcsSettingMapper;
import com.xzzn.ems.mapper.EmsStrategyLogMapper; import com.xzzn.ems.mapper.EmsStrategyLogMapper;
import com.xzzn.ems.mapper.EmsStrategyRuntimeConfigMapper;
import com.xzzn.ems.mapper.EmsStrategyRunningMapper; import com.xzzn.ems.mapper.EmsStrategyRunningMapper;
import com.xzzn.ems.mapper.EmsStrategyTempMapper; import com.xzzn.ems.mapper.EmsStrategyTempMapper;
import com.xzzn.ems.mapper.EmsStrategyTimeConfigMapper; import com.xzzn.ems.mapper.EmsStrategyTimeConfigMapper;
import com.xzzn.system.domain.SysOperLog;
import com.xzzn.system.service.ISysOperLogService;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -57,16 +69,34 @@ public class StrategyPoller {
private static final ConcurrentHashMap<Long, Boolean> strategyLocks = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<Long, Boolean> strategyLocks = new ConcurrentHashMap<>();
// SOC 上下限值默认为0%-100% // SOC 上下限值默认为0%-100%
private static final BigDecimal SOC_DOWN = new BigDecimal(0); private static final BigDecimal DEFAULT_SOC_DOWN = BigDecimal.ZERO;
private static final BigDecimal SOC_UP = new BigDecimal(100); private static final BigDecimal DEFAULT_SOC_UP = new BigDecimal(100);
// 逆变器功率下限值默认为30kW // 逆变器功率下限值默认为30kW
private static final BigDecimal ANTI_REVERSE_THRESHOLD = new BigDecimal(30); private static final BigDecimal DEFAULT_ANTI_REVERSE_THRESHOLD = new BigDecimal(30);
// 逆变器下限值范围默认为20% // 逆变器下限值范围默认为20%
private static final BigDecimal ANTI_REVERSE_RANGE_PERCENT = new BigDecimal(20); private static final BigDecimal DEFAULT_ANTI_REVERSE_RANGE_PERCENT = new BigDecimal(20);
// 逆变器功率上限值默认为100kW // 逆变器功率上限值默认为100kW
private static final BigDecimal ANTI_REVERSE_UP = new BigDecimal(100); private static final BigDecimal DEFAULT_ANTI_REVERSE_UP = new BigDecimal(100);
// PCS功率降幅默认为10% // PCS功率降幅默认为10%
private static final BigDecimal ANTI_REVERSE_POWER_DOWN_PERCENT = new BigDecimal(10); private static final BigDecimal DEFAULT_ANTI_REVERSE_POWER_DOWN_PERCENT = new BigDecimal(10);
// 电网有功功率低于20kW时强制待机
private static final BigDecimal DEFAULT_ANTI_REVERSE_HARD_STOP_THRESHOLD = new BigDecimal(20);
// 设定功率倍率默认10
private static final BigDecimal DEFAULT_POWER_SET_MULTIPLIER = new BigDecimal(10);
// 保护介入默认开启
private static final Integer DEFAULT_PROTECT_INTERVENE_ENABLE = 1;
// 一级保护默认降额50%
private static final BigDecimal DEFAULT_PROTECT_L1_DERATE_PERCENT = new BigDecimal("50");
// 保护约束失效保护时长(秒)
private static final Integer DEFAULT_PROTECT_RECOVERY_STABLE_SECONDS = 5;
// 三级保护默认锁存开启
private static final Integer DEFAULT_PROTECT_L3_LATCH_ENABLE = 1;
// 保护冲突策略默认值
private static final String DEFAULT_PROTECT_CONFLICT_POLICY = "MAX_LEVEL_WIN";
// 保护约束默认功率比例
private static final BigDecimal DEFAULT_PROTECTION_RATIO = BigDecimal.ONE;
// 除法精度避免BigDecimal除不尽异常
private static final int POWER_SCALE = 4;
@Autowired @Autowired
private EmsStrategyRunningMapper emsStrategyRunningMapper; private EmsStrategyRunningMapper emsStrategyRunningMapper;
@ -85,7 +115,13 @@ public class StrategyPoller {
@Autowired @Autowired
private EmsStrategyLogMapper emsStrategyLogMapper; private EmsStrategyLogMapper emsStrategyLogMapper;
@Autowired @Autowired
private EmsStrategyRuntimeConfigMapper runtimeConfigMapper;
@Autowired
private RedisCache redisCache;
@Autowired
private ModbusProcessor modbusProcessor; private ModbusProcessor modbusProcessor;
@Autowired
private ISysOperLogService operLogService;
@Resource(name = "modbusExecutor") @Resource(name = "modbusExecutor")
private ExecutorService modbusExecutor; private ExecutorService modbusExecutor;
@ -132,6 +168,7 @@ public class StrategyPoller {
} }
private void dealStrategyCurveData(Long strategyId, String siteId) { private void dealStrategyCurveData(Long strategyId, String siteId) {
EmsStrategyRuntimeConfig runtimeConfig = getRuntimeConfig(siteId);
// 1.获取当前策略的所有模板 // 1.获取当前策略的所有模板
List<Map<String, String>> temps = emsStrategyTempMapper.getTempNameList(strategyId, siteId); List<Map<String, String>> temps = emsStrategyTempMapper.getTempNameList(strategyId, siteId);
if (CollectionUtils.isEmpty(temps)) { if (CollectionUtils.isEmpty(temps)) {
@ -174,24 +211,53 @@ public class StrategyPoller {
continue; continue;
} }
// 判断SOC上下限 // 判断SOC上下限
if (isSocInRange(emsStrategyTemp)) { if (isSocInRange(emsStrategyTemp, runtimeConfig)) {
BigDecimal avgChargeDischargePower = emsStrategyTemp.getChargeDischargePower().divide(new BigDecimal(pcsDeviceList.size())); ProtectionConstraintVo protectionConstraint = getProtectionConstraint(siteId);
Map<Long, EmsPcsSetting> pcsSettingCache = new HashMap<>();
BigDecimal avgChargeDischargePower = emsStrategyTemp.getChargeDischargePower()
.divide(new BigDecimal(pcsDeviceList.size()), POWER_SCALE, RoundingMode.HALF_UP);
BigDecimal totalActivePower = null;
if (ChargeStatus.DISCHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
// 同一站点同一轮执行只读取一次电网电表,降低重复查库和数据抖动
EmsAmmeterData emsAmmeterData = emsAmmeterDataMapper.getLastData(emsStrategyTemp.getSiteId(), SiteDevice.LOAD.name());
if (emsAmmeterData != null) {
totalActivePower = emsAmmeterData.getTotalActivePower();
}
}
for (EmsDevicesSetting pcsDevice : pcsDeviceList) { for (EmsDevicesSetting pcsDevice : pcsDeviceList) {
EmsPcsSetting pcsSetting = emsPcsSettingMapper.selectEmsPcsSettingByDeviceId(pcsDevice.getId()); EmsPcsSetting pcsSetting = pcsSettingCache.computeIfAbsent(
pcsDevice.getId(),
id -> emsPcsSettingMapper.selectEmsPcsSettingByDeviceId(id)
);
if (pcsSetting == null || pcsSetting.getClusterNum() < 1) { if (pcsSetting == null || pcsSetting.getClusterNum() < 1) {
logger.info("当前站点: {}, PCS设备: {} 未获取电池簇数量", siteId, pcsDevice.getDeviceId()); logger.info("当前站点: {}, PCS设备: {} 未获取电池簇数量", siteId, pcsDevice.getDeviceId());
continue; continue;
} }
// 功率默认放大10倍平均功率值根据电池簇数量进行平均分配 // 平均功率值根据倍率放大后,再按电池簇数量平均分配
avgChargeDischargePower = avgChargeDischargePower.multiply(new BigDecimal(10)).divide(new BigDecimal(pcsSetting.getClusterNum())); BigDecimal strategyPower = avgChargeDischargePower.multiply(runtimeConfig.getPowerSetMultiplier())
.divide(new BigDecimal(pcsSetting.getClusterNum()), POWER_SCALE, RoundingMode.HALF_UP);
// 根据充电状态,处理数据 // 根据充电状态,处理数据
if (ChargeStatus.CHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) { if (ChargeStatus.CHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
StrategyCommandDecision decision = applyProtectionConstraint(
strategyPower,
ChargeStatus.CHARGING,
runtimeConfig,
protectionConstraint
);
// 发送Modbus命令控制设备-充电 // 发送Modbus命令控制设备-充电
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.CHARGING, avgChargeDischargePower, emsStrategyTemp, false, null); sendModbusCommand(
Collections.singletonList(pcsDevice),
pcsSetting,
decision.getChargeStatus(),
decision.getPower(),
emsStrategyTemp,
false,
null
);
} else if (ChargeStatus.DISCHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) { } else if (ChargeStatus.DISCHARGING.getCode().equals(emsStrategyTemp.getChargeStatus())) {
boolean needAntiReverseFlow = false; boolean needAntiReverseFlow = false;
Integer powerDownType = null; Integer powerDownType = null;
BigDecimal chargeDischargePower = avgChargeDischargePower; BigDecimal chargeDischargePower = strategyPower;
// 查询策略运行日志 // 查询策略运行日志
EmsStrategyLog lastStrategyLog = getLastStrategyLog(pcsDevice.getDeviceId(), emsStrategyTemp); EmsStrategyLog lastStrategyLog = getLastStrategyLog(pcsDevice.getDeviceId(), emsStrategyTemp);
if (lastStrategyLog != null) { if (lastStrategyLog != null) {
@ -204,39 +270,69 @@ public class StrategyPoller {
} }
// 查询电网电表的正向有功功率,36kW-50kW范围内稳定运行低于36kW降功率高于50kW增加功率 // 查询电网电表的正向有功功率,36kW-50kW范围内稳定运行低于36kW降功率高于50kW增加功率
EmsAmmeterData emsAmmeterData = emsAmmeterDataMapper.getLastData(emsStrategyTemp.getSiteId(), SiteDevice.LOAD.name()); if (totalActivePower == null) {
if (emsAmmeterData == null || emsAmmeterData.getTotalActivePower() == null) { logger.warn("当前站点: {}, 未获取到最新电表数据,执行保守策略并切换待机", emsStrategyTemp.getSiteId());
logger.info("当前站点: {}, 未获取到最新电表数据", emsStrategyTemp.getSiteId()); sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, true, 0);
continue;
} else { } else {
// 电网功率过低,直接待机,不再放电
if (totalActivePower.compareTo(runtimeConfig.getAntiReverseHardStopThreshold()) < 0) {
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, true, 0);
continue;
}
// 放电开始先按差值限幅:差值=电网功率-防逆流阈值
BigDecimal diffPower = totalActivePower.subtract(runtimeConfig.getAntiReverseThreshold());
BigDecimal targetPower = diffPower.compareTo(BigDecimal.ZERO) > 0 ? diffPower : BigDecimal.ZERO;
if (targetPower.compareTo(strategyPower) > 0) {
targetPower = strategyPower;
}
if (chargeDischargePower.compareTo(targetPower) > 0) {
chargeDischargePower = targetPower;
}
// 判断是否需要防逆流 // 判断是否需要防逆流
needAntiReverseFlow = isNeedAntiReverseFlow(emsAmmeterData.getTotalActivePower()); needAntiReverseFlow = isNeedAntiReverseFlow(totalActivePower, runtimeConfig);
BigDecimal power = avgChargeDischargePower.multiply(ANTI_REVERSE_POWER_DOWN_PERCENT).divide(new BigDecimal(100)); BigDecimal power = strategyPower.multiply(runtimeConfig.getAntiReversePowerDownPercent())
.divide(new BigDecimal(100), POWER_SCALE, RoundingMode.HALF_UP);
if (needAntiReverseFlow) { if (needAntiReverseFlow) {
// 降功率 // 降功率
chargeDischargePower = chargeDischargePower.subtract(power); chargeDischargePower = chargeDischargePower.subtract(power);
powerDownType = 0; powerDownType = 0;
} else { } else {
// 判断是否需要增加功率, // 判断是否需要增加功率,
if (powerDownType != null && emsAmmeterData.getTotalActivePower().compareTo(ANTI_REVERSE_UP) > 0) { if (powerDownType != null && totalActivePower.compareTo(runtimeConfig.getAntiReverseUp()) > 0) {
if (chargeDischargePower.compareTo(avgChargeDischargePower) == 0) { if (chargeDischargePower.compareTo(targetPower) >= 0) {
// 功率增加到平均值则停止 // 功率增加到限幅值则停止
continue; continue;
} }
// 增加功率 // 增加功率
chargeDischargePower = chargeDischargePower.add(power); chargeDischargePower = chargeDischargePower.add(power);
if (chargeDischargePower.compareTo(targetPower) > 0) {
chargeDischargePower = targetPower;
}
powerDownType = 1; powerDownType = 1;
needAntiReverseFlow = true; needAntiReverseFlow = true;
} }
} }
} }
if (BigDecimal.ZERO.compareTo(chargeDischargePower) == 0) { if (chargeDischargePower.compareTo(BigDecimal.ZERO) < 0) {
chargeDischargePower = BigDecimal.ZERO;
}
StrategyCommandDecision decision = applyProtectionConstraint(
chargeDischargePower,
ChargeStatus.DISCHARGING,
runtimeConfig,
protectionConstraint
);
ChargeStatus finalStatus = decision.getChargeStatus();
BigDecimal finalPower = decision.getPower();
if (ChargeStatus.STANDBY.equals(finalStatus) || BigDecimal.ZERO.compareTo(finalPower) == 0) {
// 如果已经降功率到0则设备直接待机 // 如果已经降功率到0则设备直接待机
// 发送Modbus命令控制设备-待机 // 发送Modbus命令控制设备-待机
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, needAntiReverseFlow, powerDownType); sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.STANDBY, BigDecimal.ZERO, emsStrategyTemp, needAntiReverseFlow, powerDownType);
} else { } else {
// 发送Modbus命令控制设备-放电 // 发送Modbus命令控制设备-放电
sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, ChargeStatus.DISCHARGING, chargeDischargePower, emsStrategyTemp, needAntiReverseFlow, powerDownType); sendModbusCommand(Collections.singletonList(pcsDevice), pcsSetting, finalStatus, finalPower, emsStrategyTemp, needAntiReverseFlow, powerDownType);
} }
} else { } else {
// 发送Modbus命令控制设备-待机 // 发送Modbus命令控制设备-待机
@ -297,11 +393,11 @@ public class StrategyPoller {
return emsStrategyLogMapper.getLastStrategyLog(query); return emsStrategyLogMapper.getLastStrategyLog(query);
} }
private boolean isNeedAntiReverseFlow(BigDecimal totalActivePower) { private boolean isNeedAntiReverseFlow(BigDecimal totalActivePower, EmsStrategyRuntimeConfig runtimeConfig) {
// 获取当前设定的防逆流阈值(30kW) // 获取当前设定的防逆流阈值(30kW)
BigDecimal threshold = ANTI_REVERSE_THRESHOLD; BigDecimal threshold = runtimeConfig.getAntiReverseThreshold();
// 计算20%范围的上限(36kW) // 计算20%范围的上限(36kW)
BigDecimal upperLimit = threshold.multiply(ANTI_REVERSE_RANGE_PERCENT).divide(new BigDecimal(100)).add(threshold); BigDecimal upperLimit = threshold.multiply(runtimeConfig.getAntiReverseRangePercent()).divide(new BigDecimal(100)).add(threshold);
// 判断电网电表正向有功功率是否小于36kW(接近30kW的20%范围) // 判断电网电表正向有功功率是否小于36kW(接近30kW的20%范围)
return totalActivePower.compareTo(upperLimit) < 0; return totalActivePower.compareTo(upperLimit) < 0;
@ -409,8 +505,9 @@ public class StrategyPoller {
continue; continue;
} else { } else {
// 充、放电,则先开机设备 // 充、放电,则先开机设备
switchDevice(pcsDevice, pcsSetting, WorkStatus.NORMAL); if (!switchDevice(pcsDevice, pcsSetting, WorkStatus.NORMAL)) {
continue; continue;
}
} }
} }
@ -421,8 +518,10 @@ public class StrategyPoller {
boolean result = modbusProcessor.writeDataToDeviceWithRetry(deviceConfig); boolean result = modbusProcessor.writeDataToDeviceWithRetry(deviceConfig);
if (!result) { if (!result) {
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, chargeStatus.getInfo()); logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, chargeStatus.getInfo());
recordDeviceOperationLog(siteId, deviceId, "写功率", chargeDischargePower, false, chargeStatus.getInfo() + "功率下发失败");
continue; continue;
} else { } else {
recordDeviceOperationLog(siteId, deviceId, "写功率", chargeDischargePower, true, null);
if (ChargeStatus.STANDBY.equals(chargeStatus)) { if (ChargeStatus.STANDBY.equals(chargeStatus)) {
// 待机,先写功率值,再关机 // 待机,先写功率值,再关机
if (!switchDevice(pcsDevice, pcsSetting, WorkStatus.STOP)) { if (!switchDevice(pcsDevice, pcsSetting, WorkStatus.STOP)) {
@ -440,18 +539,147 @@ public class StrategyPoller {
private boolean switchDevice(EmsDevicesSetting pcsDevice, EmsPcsSetting pcsSetting, WorkStatus workStatus) { private boolean switchDevice(EmsDevicesSetting pcsDevice, EmsPcsSetting pcsSetting, WorkStatus workStatus) {
String siteId = pcsDevice.getSiteId(); String siteId = pcsDevice.getSiteId();
String deviceId = pcsDevice.getDeviceId(); String deviceId = pcsDevice.getDeviceId();
String originalWorkStatus = pcsDevice.getWorkStatus();
pcsDevice.setWorkStatus(workStatus.getCode()); pcsDevice.setWorkStatus(workStatus.getCode());
DeviceConfig deviceConfig = getDeviceConfig(siteId, deviceId, pcsDevice, pcsSetting , null, 1); DeviceConfig deviceConfig = getDeviceConfig(siteId, deviceId, pcsDevice, pcsSetting , null, 1);
if (deviceConfig == null) { if (deviceConfig == null) {
pcsDevice.setWorkStatus(originalWorkStatus);
return false; return false;
} }
boolean result = modbusProcessor.writeDataToDeviceWithRetry(deviceConfig); boolean result = modbusProcessor.writeDataToDeviceWithRetry(deviceConfig);
if (!result) { if (!result) {
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceConfig, workStatus.getInfo()); pcsDevice.setWorkStatus(originalWorkStatus);
logger.info("当前站点: {}, PCS设备: {} modbus控制设备{}指令发送失败", siteId, deviceId, workStatus.getInfo());
recordDeviceOperationLog(siteId, deviceId, "开关机", workStatus.getInfo(), false, workStatus.getInfo() + "指令发送失败");
} else {
recordDeviceOperationLog(siteId, deviceId, "开关机", workStatus.getInfo(), true, null);
} }
return result; return result;
} }
private void recordDeviceOperationLog(String siteId, String deviceId, String action, Object param, boolean success, String errorMsg) {
try {
SysOperLog operLog = new SysOperLog();
operLog.setTitle("策略设备控制-" + action);
operLog.setBusinessType(BusinessType.UPDATE.ordinal());
operLog.setMethod(this.getClass().getName() + "." + action);
operLog.setRequestMethod("SCHEDULE");
operLog.setOperatorType(OperatorType.OTHER.ordinal());
operLog.setOperName("system");
operLog.setOperIp("127.0.0.1");
operLog.setOperUrl("/quartz/strategyPoller");
operLog.setOperTime(DateUtils.getNowDate());
Map<String, Object> operParam = new HashMap<>();
operParam.put("siteId", siteId);
operParam.put("deviceId", deviceId);
operParam.put("action", action);
operParam.put("param", param);
operLog.setOperParam(StringUtils.substring(JSON.toJSONString(operParam), 0, 2000));
operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(Collections.singletonMap("success", success)), 0, 2000));
operLog.setStatus(success ? BusinessStatus.SUCCESS.ordinal() : BusinessStatus.FAIL.ordinal());
if (!success) {
operLog.setErrorMsg(StringUtils.substring(errorMsg, 0, 2000));
}
operLogService.insertOperlog(operLog);
} catch (Exception e) {
logger.error("记录sys_oper_log失败, siteId={}, deviceId={}, action={}", siteId, deviceId, action, e);
}
}
private ProtectionConstraintVo getProtectionConstraint(String siteId) {
ProtectionConstraintVo constraint = redisCache.getCacheObject(RedisKeyConstants.PROTECTION_CONSTRAINT + siteId);
if (constraint == null) {
return ProtectionConstraintVo.empty();
}
if (constraint.getPowerLimitRatio() == null) {
constraint.setPowerLimitRatio(DEFAULT_PROTECTION_RATIO);
}
if (constraint.getAllowCharge() == null) {
constraint.setAllowCharge(true);
}
if (constraint.getAllowDischarge() == null) {
constraint.setAllowDischarge(true);
}
if (constraint.getForceStandby() == null) {
constraint.setForceStandby(false);
}
if (constraint.getForceStop() == null) {
constraint.setForceStop(false);
}
if (constraint.getLevel() == null) {
constraint.setLevel(0);
}
return constraint;
}
private StrategyCommandDecision applyProtectionConstraint(BigDecimal targetPower,
ChargeStatus targetStatus,
EmsStrategyRuntimeConfig runtimeConfig,
ProtectionConstraintVo constraint) {
if (constraint == null || nullSafeInt(constraint.getLevel()) <= 0) {
return new StrategyCommandDecision(targetStatus, safePower(targetPower));
}
if (Boolean.TRUE.equals(constraint.getForceStop()) || Boolean.TRUE.equals(constraint.getForceStandby())) {
return new StrategyCommandDecision(ChargeStatus.STANDBY, BigDecimal.ZERO);
}
if (ChargeStatus.CHARGING.equals(targetStatus) && Boolean.FALSE.equals(constraint.getAllowCharge())) {
return new StrategyCommandDecision(ChargeStatus.STANDBY, BigDecimal.ZERO);
}
if (ChargeStatus.DISCHARGING.equals(targetStatus) && Boolean.FALSE.equals(constraint.getAllowDischarge())) {
return new StrategyCommandDecision(ChargeStatus.STANDBY, BigDecimal.ZERO);
}
BigDecimal ratio = getPowerLimitRatio(constraint, runtimeConfig);
BigDecimal finalPower = safePower(targetPower).multiply(ratio).setScale(POWER_SCALE, RoundingMode.HALF_UP);
if (finalPower.compareTo(BigDecimal.ZERO) <= 0) {
return new StrategyCommandDecision(ChargeStatus.STANDBY, BigDecimal.ZERO);
}
return new StrategyCommandDecision(targetStatus, finalPower);
}
private BigDecimal getPowerLimitRatio(ProtectionConstraintVo constraint, EmsStrategyRuntimeConfig runtimeConfig) {
BigDecimal ratio = constraint.getPowerLimitRatio();
if (ratio == null || ratio.compareTo(BigDecimal.ZERO) < 0 || ratio.compareTo(BigDecimal.ONE) > 0) {
ratio = DEFAULT_PROTECTION_RATIO;
}
if (nullSafeInt(constraint.getLevel()) == 1 && DEFAULT_PROTECTION_RATIO.compareTo(ratio) == 0) {
BigDecimal deratePercent = runtimeConfig.getProtectL1DeratePercent();
if (deratePercent == null || deratePercent.compareTo(BigDecimal.ZERO) < 0 || deratePercent.compareTo(new BigDecimal("100")) > 0) {
deratePercent = DEFAULT_PROTECT_L1_DERATE_PERCENT;
}
ratio = deratePercent.divide(new BigDecimal("100"), POWER_SCALE, RoundingMode.HALF_UP);
}
return ratio;
}
private BigDecimal safePower(BigDecimal power) {
if (power == null || power.compareTo(BigDecimal.ZERO) < 0) {
return BigDecimal.ZERO;
}
return power;
}
private int nullSafeInt(Integer value) {
return value == null ? 0 : value;
}
private static class StrategyCommandDecision {
private final ChargeStatus chargeStatus;
private final BigDecimal power;
private StrategyCommandDecision(ChargeStatus chargeStatus, BigDecimal power) {
this.chargeStatus = chargeStatus;
this.power = power;
}
public ChargeStatus getChargeStatus() {
return chargeStatus;
}
public BigDecimal getPower() {
return power;
}
}
// 判断当前时间是否在时间范围内 // 判断当前时间是否在时间范围内
private static boolean isTimeInRange(LocalTime now, Date startTime, Date endTime) { private static boolean isTimeInRange(LocalTime now, Date startTime, Date endTime) {
ZoneId zoneId = ZoneId.of("Asia/Shanghai"); ZoneId zoneId = ZoneId.of("Asia/Shanghai");
@ -461,13 +689,17 @@ public class StrategyPoller {
LocalTime endLocalTime = endTime.toInstant() LocalTime endLocalTime = endTime.toInstant()
.atZone(zoneId) .atZone(zoneId)
.toLocalTime(); .toLocalTime();
return now.equals(startLocalTime) || (now.isAfter(startLocalTime) && now.isBefore(endLocalTime)); // 支持跨天时段如23:00-01:00边界采用闭区间
if (!startLocalTime.isAfter(endLocalTime)) {
return !now.isBefore(startLocalTime) && !now.isAfter(endLocalTime);
}
return !now.isBefore(startLocalTime) || !now.isAfter(endLocalTime);
} }
// 判断SOC上限和下限 // 判断SOC上限和下限
private boolean isSocInRange(EmsStrategyTemp emsStrategyTemp) { private boolean isSocInRange(EmsStrategyTemp emsStrategyTemp, EmsStrategyRuntimeConfig runtimeConfig) {
BigDecimal socDown = SOC_DOWN; BigDecimal socDown = runtimeConfig.getSocDown();
BigDecimal socUp = SOC_UP; BigDecimal socUp = runtimeConfig.getSocUp();
if (SocLimit.ON.getCode().equals(emsStrategyTemp.getSdcLimit())) { if (SocLimit.ON.getCode().equals(emsStrategyTemp.getSdcLimit())) {
socDown = emsStrategyTemp.getSdcDown(); socDown = emsStrategyTemp.getSdcDown();
socUp = emsStrategyTemp.getSdcUp(); socUp = emsStrategyTemp.getSdcUp();
@ -491,4 +723,54 @@ public class StrategyPoller {
return true; return true;
} }
private EmsStrategyRuntimeConfig getRuntimeConfig(String siteId) {
EmsStrategyRuntimeConfig config = runtimeConfigMapper.selectBySiteId(siteId);
if (config == null) {
config = new EmsStrategyRuntimeConfig();
config.setSiteId(siteId);
}
if (config.getSocDown() == null) {
config.setSocDown(DEFAULT_SOC_DOWN);
}
if (config.getSocUp() == null) {
config.setSocUp(DEFAULT_SOC_UP);
}
if (config.getAntiReverseThreshold() == null) {
config.setAntiReverseThreshold(DEFAULT_ANTI_REVERSE_THRESHOLD);
}
if (config.getAntiReverseRangePercent() == null) {
config.setAntiReverseRangePercent(DEFAULT_ANTI_REVERSE_RANGE_PERCENT);
}
if (config.getAntiReverseUp() == null) {
config.setAntiReverseUp(DEFAULT_ANTI_REVERSE_UP);
}
if (config.getAntiReversePowerDownPercent() == null) {
config.setAntiReversePowerDownPercent(DEFAULT_ANTI_REVERSE_POWER_DOWN_PERCENT);
}
if (config.getAntiReverseHardStopThreshold() == null) {
config.setAntiReverseHardStopThreshold(DEFAULT_ANTI_REVERSE_HARD_STOP_THRESHOLD);
}
if (config.getPowerSetMultiplier() == null || config.getPowerSetMultiplier().compareTo(BigDecimal.ZERO) <= 0) {
config.setPowerSetMultiplier(DEFAULT_POWER_SET_MULTIPLIER);
}
if (config.getProtectInterveneEnable() == null) {
config.setProtectInterveneEnable(DEFAULT_PROTECT_INTERVENE_ENABLE);
}
if (config.getProtectL1DeratePercent() == null
|| config.getProtectL1DeratePercent().compareTo(BigDecimal.ZERO) < 0
|| config.getProtectL1DeratePercent().compareTo(new BigDecimal("100")) > 0) {
config.setProtectL1DeratePercent(DEFAULT_PROTECT_L1_DERATE_PERCENT);
}
if (config.getProtectRecoveryStableSeconds() == null || config.getProtectRecoveryStableSeconds() < 0) {
config.setProtectRecoveryStableSeconds(DEFAULT_PROTECT_RECOVERY_STABLE_SECONDS);
}
if (config.getProtectL3LatchEnable() == null) {
config.setProtectL3LatchEnable(DEFAULT_PROTECT_L3_LATCH_ENABLE);
}
if (StringUtils.isEmpty(config.getProtectConflictPolicy())) {
config.setProtectConflictPolicy(DEFAULT_PROTECT_CONFLICT_POLICY);
}
return config;
}
} }

View File

@ -27,6 +27,12 @@
<artifactId>jaxb-runtime</artifactId> <artifactId>jaxb-runtime</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.influxdb</groupId>
<artifactId>influxdb-java</artifactId>
<version>2.24</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,61 @@
package com.xzzn.ems.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "weather.api")
public class WeatherApiProperties {
/**
* 是否启用天气同步
*/
private boolean enabled = false;
/**
* 天气接口基础地址
*/
private String baseUrl = "https://archive-api.open-meteo.com/v1/archive";
/**
* 可选接口鉴权字段
*/
private String apiKey;
/**
* 时区参数
*/
private String timezone = "Asia/Shanghai";
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
}

View File

@ -25,10 +25,6 @@ public class EmsDailyChargeData extends BaseEntity
@Excel(name = "站点id") @Excel(name = "站点id")
private String siteId; private String siteId;
/** 设备唯一标识符 */
@Excel(name = "设备唯一标识符")
private String deviceId;
/** 数据日期:yyyy-MM-dd */ /** 数据日期:yyyy-MM-dd */
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "数据日期:yyyy-MM-dd", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "数据日期:yyyy-MM-dd", width = 30, dateFormat = "yyyy-MM-dd")
@ -50,6 +46,14 @@ public class EmsDailyChargeData extends BaseEntity
@Excel(name = "当日放电量") @Excel(name = "当日放电量")
private BigDecimal dischargeData; private BigDecimal dischargeData;
/** 总收入 */
@Excel(name = "总收入")
private BigDecimal totalRevenue;
/** 当日实时收入 */
@Excel(name = "当日实时收入")
private BigDecimal dayRevenue;
public void setId(Long id) public void setId(Long id)
{ {
this.id = id; this.id = id;
@ -70,16 +74,6 @@ public class EmsDailyChargeData extends BaseEntity
return siteId; return siteId;
} }
public void setDeviceId(String deviceId)
{
this.deviceId = deviceId;
}
public String getDeviceId()
{
return deviceId;
}
public void setDateTime(Date dateTime) public void setDateTime(Date dateTime)
{ {
this.dateTime = dateTime; this.dateTime = dateTime;
@ -130,17 +124,38 @@ public class EmsDailyChargeData extends BaseEntity
return dischargeData; return dischargeData;
} }
public void setTotalRevenue(BigDecimal totalRevenue)
{
this.totalRevenue = totalRevenue;
}
public BigDecimal getTotalRevenue()
{
return totalRevenue;
}
public void setDayRevenue(BigDecimal dayRevenue)
{
this.dayRevenue = dayRevenue;
}
public BigDecimal getDayRevenue()
{
return dayRevenue;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId()) .append("id", getId())
.append("siteId", getSiteId()) .append("siteId", getSiteId())
.append("deviceId", getDeviceId())
.append("dateTime", getDateTime()) .append("dateTime", getDateTime())
.append("totalChargeData", getTotalChargeData()) .append("totalChargeData", getTotalChargeData())
.append("totalDischargeData", getTotalDischargeData()) .append("totalDischargeData", getTotalDischargeData())
.append("chargeData", getChargeData()) .append("chargeData", getChargeData())
.append("dischargeData", getDischargeData()) .append("dischargeData", getDischargeData())
.append("totalRevenue", getTotalRevenue())
.append("dayRevenue", getDayRevenue())
.append("createBy", getCreateBy()) .append("createBy", getCreateBy())
.append("createTime", getCreateTime()) .append("createTime", getCreateTime())
.append("updateBy", getUpdateBy()) .append("updateBy", getUpdateBy())

View File

@ -30,13 +30,9 @@ public class EmsDailyEnergyData extends BaseEntity
@Excel(name = "数据日期:yyyy-MM-dd", width = 30, dateFormat = "yyyy-MM-dd") @Excel(name = "数据日期:yyyy-MM-dd", width = 30, dateFormat = "yyyy-MM-dd")
private Date dataDate; private Date dataDate;
/** 总收入 */ /** 数据小时(0-23) */
@Excel(name = "总收入") @Excel(name = "数据小时(0-23)")
private BigDecimal totalRevenue; private Integer dataHour;
/** 当日实时收入 */
@Excel(name = "当日实时收入")
private BigDecimal dayRevenue;
/** 尖峰时段充电差值 */ /** 尖峰时段充电差值 */
@Excel(name = "尖峰时段充电差值") @Excel(name = "尖峰时段充电差值")
@ -71,6 +67,7 @@ public class EmsDailyEnergyData extends BaseEntity
private BigDecimal valleyDischargeDiff; private BigDecimal valleyDischargeDiff;
/** 差值计算时间如2025-10-10 23:59:00 */ /** 差值计算时间如2025-10-10 23:59:00 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "差值计算时间", readConverterExp = "如=2025-10-10,2=3:59:00") @Excel(name = "差值计算时间", readConverterExp = "如=2025-10-10,2=3:59:00")
private Date calcTime; private Date calcTime;
@ -104,24 +101,14 @@ public class EmsDailyEnergyData extends BaseEntity
return dataDate; return dataDate;
} }
public void setTotalRevenue(BigDecimal totalRevenue) public void setDataHour(Integer dataHour)
{ {
this.totalRevenue = totalRevenue; this.dataHour = dataHour;
} }
public BigDecimal getTotalRevenue() public Integer getDataHour()
{ {
return totalRevenue; return dataHour;
}
public void setDayRevenue(BigDecimal dayRevenue)
{
this.dayRevenue = dayRevenue;
}
public BigDecimal getDayRevenue()
{
return dayRevenue;
} }
public void setPeakChargeDiff(BigDecimal peakChargeDiff) public void setPeakChargeDiff(BigDecimal peakChargeDiff)
@ -220,8 +207,7 @@ public class EmsDailyEnergyData extends BaseEntity
.append("id", getId()) .append("id", getId())
.append("siteId", getSiteId()) .append("siteId", getSiteId())
.append("dataDate", getDataDate()) .append("dataDate", getDataDate())
.append("totalRevenue", getTotalRevenue()) .append("dataHour", getDataHour())
.append("dayRevenue", getDayRevenue())
.append("peakChargeDiff", getPeakChargeDiff()) .append("peakChargeDiff", getPeakChargeDiff())
.append("peakDischargeDiff", getPeakDischargeDiff()) .append("peakDischargeDiff", getPeakDischargeDiff())
.append("highChargeDiff", getHighChargeDiff()) .append("highChargeDiff", getHighChargeDiff())

View File

@ -49,6 +49,10 @@ public class EmsPcsSetting extends BaseEntity
@Excel(name = "关机目标功率") @Excel(name = "关机目标功率")
private BigDecimal stopPower; private BigDecimal stopPower;
/** 目标功率倍率 */
@Excel(name = "目标功率倍率")
private BigDecimal powerMultiplier;
/** 电池簇数 */ /** 电池簇数 */
@Excel(name = "电池簇数") @Excel(name = "电池簇数")
private Integer clusterNum; private Integer clusterNum;
@ -135,6 +139,16 @@ public class EmsPcsSetting extends BaseEntity
return stopPower; return stopPower;
} }
public BigDecimal getPowerMultiplier()
{
return powerMultiplier;
}
public void setPowerMultiplier(BigDecimal powerMultiplier)
{
this.powerMultiplier = powerMultiplier;
}
public void setClusterNum(Integer clusterNum) public void setClusterNum(Integer clusterNum)
{ {
this.clusterNum = clusterNum; this.clusterNum = clusterNum;
@ -165,6 +179,7 @@ public class EmsPcsSetting extends BaseEntity
.append("stopCommand", getStopCommand()) .append("stopCommand", getStopCommand())
.append("startPower", getStartPower()) .append("startPower", getStartPower())
.append("stopPower", getStopPower()) .append("stopPower", getStopPower())
.append("powerMultiplier", getPowerMultiplier())
.append("clusterNum", getClusterNum()) .append("clusterNum", getClusterNum())
.append("clusterPointAddress", getClusterPointAddress()) .append("clusterPointAddress", getClusterPointAddress())
.append("createBy", getCreateBy()) .append("createBy", getCreateBy())

View File

@ -0,0 +1,128 @@
package com.xzzn.ems.domain;
import com.xzzn.common.annotation.Excel;
import com.xzzn.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class EmsPointCalcConfig extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
@Excel(name = "点位ID")
private String pointId;
@Excel(name = "站点ID")
private String siteId;
@Excel(name = "设备类型")
private String deviceCategory;
@Excel(name = "点位名称")
private String pointName;
@Excel(name = "数据键")
private String dataKey;
@Excel(name = "点位描述")
private String pointDesc;
@Excel(name = "单位")
private String dataUnit;
@Excel(name = "计算表达式")
private String calcExpression;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPointId() {
return pointId;
}
public void setPointId(String pointId) {
this.pointId = pointId;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getPointName() {
return pointName;
}
public void setPointName(String pointName) {
this.pointName = pointName;
}
public String getDeviceCategory() {
return deviceCategory;
}
public void setDeviceCategory(String deviceCategory) {
this.deviceCategory = deviceCategory;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
public String getPointDesc() {
return pointDesc;
}
public void setPointDesc(String pointDesc) {
this.pointDesc = pointDesc;
}
public String getDataUnit() {
return dataUnit;
}
public void setDataUnit(String dataUnit) {
this.dataUnit = dataUnit;
}
public String getCalcExpression() {
return calcExpression;
}
public void setCalcExpression(String calcExpression) {
this.calcExpression = calcExpression;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("pointId", getPointId())
.append("siteId", getSiteId())
.append("deviceCategory", getDeviceCategory())
.append("pointName", getPointName())
.append("dataKey", getDataKey())
.append("pointDesc", getPointDesc())
.append("dataUnit", getDataUnit())
.append("calcExpression", getCalcExpression())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.toString();
}
}

View File

@ -0,0 +1,313 @@
package com.xzzn.ems.domain;
import com.xzzn.common.annotation.Excel;
import com.xzzn.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.math.BigDecimal;
/**
* 点位配置对象 ems_point_config
*/
public class EmsPointConfig extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
@Excel(name = "点位ID")
private String pointId;
@Excel(name = "站点ID")
private String siteId;
@Excel(name = "设备类型")
private String deviceCategory;
@Excel(name = "设备ID")
private String deviceId;
@Excel(name = "点位名称")
private String pointName;
@Excel(name = "数据键")
private String dataKey;
@Excel(name = "点位描述")
private String pointDesc;
@Excel(name = "寄存器地址")
private String registerAddress;
@Excel(name = "单位")
private String dataUnit;
@Excel(name = "A系数")
private BigDecimal dataA;
@Excel(name = "K系数")
private BigDecimal dataK;
@Excel(name = "B系数")
private BigDecimal dataB;
@Excel(name = "位偏移")
private Integer dataBit;
@Excel(name = "是否报警点位", readConverterExp = "0=否,1=是")
private Integer isAlarm;
@Excel(name = "点位类型")
private String pointType;
@Excel(name = "计算表达式")
private String calcExpression;
@Excel(name = "是否启用采集", readConverterExp = "0=否,1=是")
private Integer collectEnabled;
@Excel(name = "采集来源")
private String collectSource;
@Excel(name = "Modbus寄存器类型")
private String modbusRegisterType;
@Excel(name = "Modbus数据类型")
private String modbusDataType;
@Excel(name = "Modbus读取顺序")
private Integer modbusReadOrder;
@Excel(name = "Modbus分组")
private String modbusGroup;
@Excel(name = "小数位数")
private Integer decimalScale;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPointId() {
return pointId;
}
public void setPointId(String pointId) {
this.pointId = pointId;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getDeviceCategory() {
return deviceCategory;
}
public void setDeviceCategory(String deviceCategory) {
this.deviceCategory = deviceCategory;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getPointName() {
return pointName;
}
public void setPointName(String pointName) {
this.pointName = pointName;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
public String getPointDesc() {
return pointDesc;
}
public void setPointDesc(String pointDesc) {
this.pointDesc = pointDesc;
}
public String getRegisterAddress() {
return registerAddress;
}
public void setRegisterAddress(String registerAddress) {
this.registerAddress = registerAddress;
}
public String getDataUnit() {
return dataUnit;
}
public void setDataUnit(String dataUnit) {
this.dataUnit = dataUnit;
}
public BigDecimal getDataA() {
return dataA;
}
public void setDataA(BigDecimal dataA) {
this.dataA = dataA;
}
public BigDecimal getDataK() {
return dataK;
}
public void setDataK(BigDecimal dataK) {
this.dataK = dataK;
}
public BigDecimal getDataB() {
return dataB;
}
public void setDataB(BigDecimal dataB) {
this.dataB = dataB;
}
public Integer getDataBit() {
return dataBit;
}
public void setDataBit(Integer dataBit) {
this.dataBit = dataBit;
}
public Integer getIsAlarm() {
return isAlarm;
}
public void setIsAlarm(Integer isAlarm) {
this.isAlarm = isAlarm;
}
public String getPointType() {
return pointType;
}
public void setPointType(String pointType) {
this.pointType = pointType;
}
public String getCalcExpression() {
return calcExpression;
}
public void setCalcExpression(String calcExpression) {
this.calcExpression = calcExpression;
}
public Integer getCollectEnabled() {
return collectEnabled;
}
public void setCollectEnabled(Integer collectEnabled) {
this.collectEnabled = collectEnabled;
}
public String getCollectSource() {
return collectSource;
}
public void setCollectSource(String collectSource) {
this.collectSource = collectSource;
}
public String getModbusRegisterType() {
return modbusRegisterType;
}
public void setModbusRegisterType(String modbusRegisterType) {
this.modbusRegisterType = modbusRegisterType;
}
public String getModbusDataType() {
return modbusDataType;
}
public void setModbusDataType(String modbusDataType) {
this.modbusDataType = modbusDataType;
}
public Integer getModbusReadOrder() {
return modbusReadOrder;
}
public void setModbusReadOrder(Integer modbusReadOrder) {
this.modbusReadOrder = modbusReadOrder;
}
public String getModbusGroup() {
return modbusGroup;
}
public void setModbusGroup(String modbusGroup) {
this.modbusGroup = modbusGroup;
}
public Integer getDecimalScale() {
return decimalScale;
}
public void setDecimalScale(Integer decimalScale) {
this.decimalScale = decimalScale;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("pointId", getPointId())
.append("siteId", getSiteId())
.append("deviceCategory", getDeviceCategory())
.append("deviceId", getDeviceId())
.append("pointName", getPointName())
.append("dataKey", getDataKey())
.append("pointDesc", getPointDesc())
.append("registerAddress", getRegisterAddress())
.append("dataUnit", getDataUnit())
.append("dataA", getDataA())
.append("dataK", getDataK())
.append("dataB", getDataB())
.append("dataBit", getDataBit())
.append("isAlarm", getIsAlarm())
.append("pointType", getPointType())
.append("calcExpression", getCalcExpression())
.append("collectEnabled", getCollectEnabled())
.append("collectSource", getCollectSource())
.append("modbusRegisterType", getModbusRegisterType())
.append("modbusDataType", getModbusDataType())
.append("modbusReadOrder", getModbusReadOrder())
.append("modbusGroup", getModbusGroup())
.append("decimalScale", getDecimalScale())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.toString();
}
}

View File

@ -0,0 +1,58 @@
package com.xzzn.ems.domain;
import com.xzzn.common.core.domain.BaseEntity;
import java.util.Date;
/**
* 单站监控展示数据对象(按分组落到 ems_site_monitor_data_home/sbjk/tjbb
*/
public class EmsSiteMonitorData extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private String siteId;
private String fieldCode;
private String fieldValue;
private Date valueTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getFieldCode() {
return fieldCode;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
public Date getValueTime() {
return valueTime;
}
public void setValueTime(Date valueTime) {
this.valueTime = valueTime;
}
}

View File

@ -0,0 +1,101 @@
package com.xzzn.ems.domain;
import com.xzzn.common.core.domain.BaseEntity;
/**
* 单站监控配置项定义对象 ems_site_monitor_item
*/
public class EmsSiteMonitorItem extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private String moduleCode;
private String moduleName;
private String menuCode;
private String menuName;
private String sectionName;
private String fieldCode;
private String fieldName;
private Integer sortNo;
private Integer status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getModuleCode() {
return moduleCode;
}
public void setModuleCode(String moduleCode) {
this.moduleCode = moduleCode;
}
public String getModuleName() {
return moduleName;
}
public void setModuleName(String moduleName) {
this.moduleName = moduleName;
}
public String getMenuCode() {
return menuCode;
}
public void setMenuCode(String menuCode) {
this.menuCode = menuCode;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getSectionName() {
return sectionName;
}
public void setSectionName(String sectionName) {
this.sectionName = sectionName;
}
public String getFieldCode() {
return fieldCode;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public Integer getSortNo() {
return sortNo;
}
public void setSortNo(Integer sortNo) {
this.sortNo = sortNo;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}

View File

@ -0,0 +1,74 @@
package com.xzzn.ems.domain;
import com.xzzn.common.core.domain.BaseEntity;
/**
* 单站监控字段点位映射对象 ems_site_monitor_point_match
*/
public class EmsSiteMonitorPointMatch extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private String siteId;
private String fieldCode;
private String deviceId;
private String dataPoint;
private String fixedDataPoint;
private Integer useFixedDisplay;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getFieldCode() {
return fieldCode;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getDataPoint() {
return dataPoint;
}
public void setDataPoint(String dataPoint) {
this.dataPoint = dataPoint;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getFixedDataPoint() {
return fixedDataPoint;
}
public void setFixedDataPoint(String fixedDataPoint) {
this.fixedDataPoint = fixedDataPoint;
}
public Integer getUseFixedDisplay() {
return useFixedDisplay;
}
public void setUseFixedDisplay(Integer useFixedDisplay) {
this.useFixedDisplay = useFixedDisplay;
}
}

View File

@ -25,6 +25,10 @@ public class EmsSiteSetting extends BaseEntity
@Excel(name = "站点名称") @Excel(name = "站点名称")
private String siteName; private String siteName;
/** 站点简称 */
@Excel(name = "站点简称")
private String siteShortName;
/** 站点地址 */ /** 站点地址 */
@Excel(name = "站点地址") @Excel(name = "站点地址")
private String siteAddress; private String siteAddress;
@ -54,6 +58,9 @@ public class EmsSiteSetting extends BaseEntity
@Excel(name = "站点id") @Excel(name = "站点id")
private String siteId; private String siteId;
/** 授权状态true-已授权false-未授权 */
private Boolean authorized;
public void setId(Long id) public void setId(Long id)
{ {
this.id = id; this.id = id;
@ -74,6 +81,16 @@ public class EmsSiteSetting extends BaseEntity
return siteName; return siteName;
} }
public void setSiteShortName(String siteShortName)
{
this.siteShortName = siteShortName;
}
public String getSiteShortName()
{
return siteShortName;
}
public void setSiteAddress(String siteAddress) public void setSiteAddress(String siteAddress)
{ {
this.siteAddress = siteAddress; this.siteAddress = siteAddress;
@ -144,11 +161,22 @@ public class EmsSiteSetting extends BaseEntity
return siteId; return siteId;
} }
public void setAuthorized(Boolean authorized)
{
this.authorized = authorized;
}
public Boolean getAuthorized()
{
return authorized;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId()) .append("id", getId())
.append("siteName", getSiteName()) .append("siteName", getSiteName())
.append("siteShortName", getSiteShortName())
.append("siteAddress", getSiteAddress()) .append("siteAddress", getSiteAddress())
.append("runningTime", getRunningTime()) .append("runningTime", getRunningTime())
.append("latitude", getLatitude()) .append("latitude", getLatitude())
@ -161,6 +189,7 @@ public class EmsSiteSetting extends BaseEntity
.append("createTime", getCreateTime()) .append("createTime", getCreateTime())
.append("updateTime", getUpdateTime()) .append("updateTime", getUpdateTime())
.append("siteId", getSiteId()) .append("siteId", getSiteId())
.append("authorized", getAuthorized())
.toString(); .toString();
} }
} }

View File

@ -0,0 +1,221 @@
package com.xzzn.ems.domain;
import com.xzzn.common.annotation.Excel;
import com.xzzn.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.math.BigDecimal;
/**
* 策略运行参数配置对象 ems_strategy_runtime_config
*
* @author xzzn
* @date 2026-02-13
*/
public class EmsStrategyRuntimeConfig extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 站点ID */
@Excel(name = "站点ID")
private String siteId;
/** SOC下限(%) */
@Excel(name = "SOC下限(%)")
private BigDecimal socDown;
/** SOC上限(%) */
@Excel(name = "SOC上限(%)")
private BigDecimal socUp;
/** 防逆流阈值(kW) */
@Excel(name = "防逆流阈值(kW)")
private BigDecimal antiReverseThreshold;
/** 防逆流阈值上浮比例(%) */
@Excel(name = "防逆流阈值上浮比例(%)")
private BigDecimal antiReverseRangePercent;
/** 防逆流恢复上限(kW) */
@Excel(name = "防逆流恢复上限(kW)")
private BigDecimal antiReverseUp;
/** 防逆流降功率比例(%) */
@Excel(name = "防逆流降功率比例(%)")
private BigDecimal antiReversePowerDownPercent;
/** 防逆流硬停阈值(kW) */
@Excel(name = "防逆流硬停阈值(kW)")
private BigDecimal antiReverseHardStopThreshold;
/** 设定功率倍率 */
@Excel(name = "设定功率倍率")
private BigDecimal powerSetMultiplier;
/** 保护介入开关1-启用0-禁用) */
@Excel(name = "保护介入开关")
private Integer protectInterveneEnable;
/** 一级保护降额比例(%) */
@Excel(name = "一级保护降额比例(%)")
private BigDecimal protectL1DeratePercent;
/** 保护释放稳定时长(秒) */
@Excel(name = "保护释放稳定时长(秒)")
private Integer protectRecoveryStableSeconds;
/** 三级保护锁存开关1-启用0-禁用) */
@Excel(name = "三级保护锁存开关")
private Integer protectL3LatchEnable;
/** 保护冲突策略 */
@Excel(name = "保护冲突策略")
private String protectConflictPolicy;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public BigDecimal getSocDown() {
return socDown;
}
public void setSocDown(BigDecimal socDown) {
this.socDown = socDown;
}
public BigDecimal getSocUp() {
return socUp;
}
public void setSocUp(BigDecimal socUp) {
this.socUp = socUp;
}
public BigDecimal getAntiReverseThreshold() {
return antiReverseThreshold;
}
public void setAntiReverseThreshold(BigDecimal antiReverseThreshold) {
this.antiReverseThreshold = antiReverseThreshold;
}
public BigDecimal getAntiReverseRangePercent() {
return antiReverseRangePercent;
}
public void setAntiReverseRangePercent(BigDecimal antiReverseRangePercent) {
this.antiReverseRangePercent = antiReverseRangePercent;
}
public BigDecimal getAntiReverseUp() {
return antiReverseUp;
}
public void setAntiReverseUp(BigDecimal antiReverseUp) {
this.antiReverseUp = antiReverseUp;
}
public BigDecimal getAntiReversePowerDownPercent() {
return antiReversePowerDownPercent;
}
public void setAntiReversePowerDownPercent(BigDecimal antiReversePowerDownPercent) {
this.antiReversePowerDownPercent = antiReversePowerDownPercent;
}
public BigDecimal getAntiReverseHardStopThreshold() {
return antiReverseHardStopThreshold;
}
public void setAntiReverseHardStopThreshold(BigDecimal antiReverseHardStopThreshold) {
this.antiReverseHardStopThreshold = antiReverseHardStopThreshold;
}
public BigDecimal getPowerSetMultiplier() {
return powerSetMultiplier;
}
public void setPowerSetMultiplier(BigDecimal powerSetMultiplier) {
this.powerSetMultiplier = powerSetMultiplier;
}
public Integer getProtectInterveneEnable() {
return protectInterveneEnable;
}
public void setProtectInterveneEnable(Integer protectInterveneEnable) {
this.protectInterveneEnable = protectInterveneEnable;
}
public BigDecimal getProtectL1DeratePercent() {
return protectL1DeratePercent;
}
public void setProtectL1DeratePercent(BigDecimal protectL1DeratePercent) {
this.protectL1DeratePercent = protectL1DeratePercent;
}
public Integer getProtectRecoveryStableSeconds() {
return protectRecoveryStableSeconds;
}
public void setProtectRecoveryStableSeconds(Integer protectRecoveryStableSeconds) {
this.protectRecoveryStableSeconds = protectRecoveryStableSeconds;
}
public Integer getProtectL3LatchEnable() {
return protectL3LatchEnable;
}
public void setProtectL3LatchEnable(Integer protectL3LatchEnable) {
this.protectL3LatchEnable = protectL3LatchEnable;
}
public String getProtectConflictPolicy() {
return protectConflictPolicy;
}
public void setProtectConflictPolicy(String protectConflictPolicy) {
this.protectConflictPolicy = protectConflictPolicy;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("siteId", getSiteId())
.append("socDown", getSocDown())
.append("socUp", getSocUp())
.append("antiReverseThreshold", getAntiReverseThreshold())
.append("antiReverseRangePercent", getAntiReverseRangePercent())
.append("antiReverseUp", getAntiReverseUp())
.append("antiReversePowerDownPercent", getAntiReversePowerDownPercent())
.append("antiReverseHardStopThreshold", getAntiReverseHardStopThreshold())
.append("powerSetMultiplier", getPowerSetMultiplier())
.append("protectInterveneEnable", getProtectInterveneEnable())
.append("protectL1DeratePercent", getProtectL1DeratePercent())
.append("protectRecoveryStableSeconds", getProtectRecoveryStableSeconds())
.append("protectL3LatchEnable", getProtectL3LatchEnable())
.append("protectConflictPolicy", getProtectConflictPolicy())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.toString();
}
}

View File

@ -35,6 +35,14 @@ public class EmsStrategyTempTimeConfig extends BaseEntity
@Excel(name = "充放功率 (kW)") @Excel(name = "充放功率 (kW)")
private BigDecimal chargeDischargePower; private BigDecimal chargeDischargePower;
/** SDC下限 (%) */
@Excel(name = "SDC下限 (%)")
private BigDecimal sdcDown;
/** SDC上限 (%) */
@Excel(name = "SDC上限 (%)")
private BigDecimal sdcUp;
/** 充电状态如“1-充电”、“2-待机” */ /** 充电状态如“1-充电”、“2-待机” */
@Excel(name = "充电状态如“1-充电”、“2-待机”") @Excel(name = "充电状态如“1-充电”、“2-待机”")
private String chargeStatus; private String chargeStatus;
@ -83,6 +91,26 @@ public class EmsStrategyTempTimeConfig extends BaseEntity
return chargeDischargePower; return chargeDischargePower;
} }
public void setSdcDown(BigDecimal sdcDown)
{
this.sdcDown = sdcDown;
}
public BigDecimal getSdcDown()
{
return sdcDown;
}
public void setSdcUp(BigDecimal sdcUp)
{
this.sdcUp = sdcUp;
}
public BigDecimal getSdcUp()
{
return sdcUp;
}
public void setChargeStatus(String chargeStatus) public void setChargeStatus(String chargeStatus)
{ {
this.chargeStatus = chargeStatus; this.chargeStatus = chargeStatus;
@ -110,6 +138,8 @@ public class EmsStrategyTempTimeConfig extends BaseEntity
.append("startTime", getStartTime()) .append("startTime", getStartTime())
.append("endTime", getEndTime()) .append("endTime", getEndTime())
.append("chargeDischargePower", getChargeDischargePower()) .append("chargeDischargePower", getChargeDischargePower())
.append("sdcDown", getSdcDown())
.append("sdcUp", getSdcUp())
.append("chargeStatus", getChargeStatus()) .append("chargeStatus", getChargeStatus())
.append("createBy", getCreateBy()) .append("createBy", getCreateBy())
.append("createTime", getCreateTime()) .append("createTime", getCreateTime())

View File

@ -0,0 +1,68 @@
package com.xzzn.ems.domain;
import com.xzzn.common.core.domain.BaseEntity;
public class SysBizRemark extends BaseEntity
{
private static final long serialVersionUID = 1L;
private Long id;
private String bizType;
private String bizKey1;
private String bizKey2;
private String delFlag;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getBizType()
{
return bizType;
}
public void setBizType(String bizType)
{
this.bizType = bizType;
}
public String getBizKey1()
{
return bizKey1;
}
public void setBizKey1(String bizKey1)
{
this.bizKey1 = bizKey1;
}
public String getBizKey2()
{
return bizKey2;
}
public void setBizKey2(String bizKey2)
{
this.bizKey2 = bizKey2;
}
public String getDelFlag()
{
return delFlag;
}
public void setDelFlag(String delFlag)
{
this.delFlag = delFlag;
}
}

View File

@ -11,6 +11,15 @@ public class AmmeterRevenueStatisListVo {
/** 类别 */ /** 类别 */
private String dataTime; private String dataTime;
/** 是否工作日1-工作日 0-节假日 */
private Integer isWorkday;
/** 日期类型 */
private String dayType;
/** 天气情况 */
private String weatherDesc;
/** 组合有功-总 */ /** 组合有功-总 */
private BigDecimal activeTotalPrice = BigDecimal.ZERO; private BigDecimal activeTotalPrice = BigDecimal.ZERO;
@ -44,6 +53,8 @@ public class AmmeterRevenueStatisListVo {
/** 实际收益 */ /** 实际收益 */
private BigDecimal actualRevenue = BigDecimal.ZERO; private BigDecimal actualRevenue = BigDecimal.ZERO;
private String remark;
public String getDataTime() { public String getDataTime() {
return dataTime; return dataTime;
} }
@ -52,6 +63,30 @@ public class AmmeterRevenueStatisListVo {
this.dataTime = dataTime; this.dataTime = dataTime;
} }
public Integer getIsWorkday() {
return isWorkday;
}
public void setIsWorkday(Integer isWorkday) {
this.isWorkday = isWorkday;
}
public String getDayType() {
return dayType;
}
public void setDayType(String dayType) {
this.dayType = dayType;
}
public String getWeatherDesc() {
return weatherDesc;
}
public void setWeatherDesc(String weatherDesc) {
this.weatherDesc = weatherDesc;
}
public BigDecimal getActiveTotalPrice() { public BigDecimal getActiveTotalPrice() {
return activeTotalPrice; return activeTotalPrice;
} }
@ -139,4 +174,12 @@ public class AmmeterRevenueStatisListVo {
public void setActualRevenue(BigDecimal actualRevenue) { public void setActualRevenue(BigDecimal actualRevenue) {
this.actualRevenue = actualRevenue; this.actualRevenue = actualRevenue;
} }
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
} }

View File

@ -46,6 +46,8 @@ public class AmmeterStatisListVo {
/** 效率-有功总/无功总 */ /** 效率-有功总/无功总 */
private BigDecimal effect = BigDecimal.ZERO; private BigDecimal effect = BigDecimal.ZERO;
private String remark;
public String getDataTime() { public String getDataTime() {
return dataTime; return dataTime;
} }
@ -149,4 +151,12 @@ public class AmmeterStatisListVo {
public void setEffect(BigDecimal effect) { public void setEffect(BigDecimal effect) {
this.effect = effect; this.effect = effect;
} }
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
} }

View File

@ -24,6 +24,18 @@ public class BatteryDataStatsListVo {
/** SOH (%) */ /** SOH (%) */
private BigDecimal soh; private BigDecimal soh;
/** 电压映射点位ID */
private String voltagePointId;
/** 温度映射点位ID */
private String temperaturePointId;
/** SOC映射点位ID */
private String socPointId;
/** SOH映射点位ID */
private String sohPointId;
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
private Date dataTimestamp; private Date dataTimestamp;
@ -71,6 +83,38 @@ public class BatteryDataStatsListVo {
this.soh = soh; this.soh = soh;
} }
public String getVoltagePointId() {
return voltagePointId;
}
public void setVoltagePointId(String voltagePointId) {
this.voltagePointId = voltagePointId;
}
public String getTemperaturePointId() {
return temperaturePointId;
}
public void setTemperaturePointId(String temperaturePointId) {
this.temperaturePointId = temperaturePointId;
}
public String getSocPointId() {
return socPointId;
}
public void setSocPointId(String socPointId) {
this.socPointId = socPointId;
}
public String getSohPointId() {
return sohPointId;
}
public void setSohPointId(String sohPointId) {
this.sohPointId = sohPointId;
}
public Date getDataTimestamp() { public Date getDataTimestamp() {
return dataTimestamp; return dataTimestamp;
} }

View File

@ -0,0 +1,42 @@
package com.xzzn.ems.domain.vo;
import java.util.List;
public class BizRemarkBatchGetRequest
{
private String bizType;
private String bizKey1;
private List<String> bizKey2List;
public String getBizType()
{
return bizType;
}
public void setBizType(String bizType)
{
this.bizType = bizType;
}
public String getBizKey1()
{
return bizKey1;
}
public void setBizKey1(String bizKey1)
{
this.bizKey1 = bizKey1;
}
public List<String> getBizKey2List()
{
return bizKey2List;
}
public void setBizKey2List(List<String> bizKey2List)
{
this.bizKey2List = bizKey2List;
}
}

View File

@ -0,0 +1,52 @@
package com.xzzn.ems.domain.vo;
public class BizRemarkSaveRequest
{
private String bizType;
private String bizKey1;
private String bizKey2;
private String remark;
public String getBizType()
{
return bizType;
}
public void setBizType(String bizType)
{
this.bizType = bizType;
}
public String getBizKey1()
{
return bizKey1;
}
public void setBizKey1(String bizKey1)
{
this.bizKey1 = bizKey1;
}
public String getBizKey2()
{
return bizKey2;
}
public void setBizKey2(String bizKey2)
{
this.bizKey2 = bizKey2;
}
public String getRemark()
{
return remark;
}
public void setRemark(String remark)
{
this.remark = remark;
}
}

View File

@ -24,11 +24,25 @@ public class DevicePointDataList
private BigDecimal avgValue; private BigDecimal avgValue;
// 差值max - min // 差值max - min
private BigDecimal diffValue; private BigDecimal diffValue;
// 第一四分位数
private BigDecimal q1;
// 中位数
private BigDecimal median;
// 第三四分位数
private BigDecimal q3;
public DevicePointDataList(String deviceId, List<GeneralQueryDataVo> pointValueList,String parentDeviceId, public DevicePointDataList(String deviceId, List<GeneralQueryDataVo> pointValueList,String parentDeviceId,
BigDecimal maxValue, BigDecimal minValue, BigDecimal maxValue, BigDecimal minValue,
BigDecimal avgValue, BigDecimal diffValue, BigDecimal avgValue, BigDecimal diffValue,
String maxDate, String minDate) { String maxDate, String minDate) {
this(deviceId, pointValueList, parentDeviceId, maxValue, minValue, avgValue, diffValue, maxDate, minDate, null, null, null);
}
public DevicePointDataList(String deviceId, List<GeneralQueryDataVo> pointValueList,String parentDeviceId,
BigDecimal maxValue, BigDecimal minValue,
BigDecimal avgValue, BigDecimal diffValue,
String maxDate, String minDate,
BigDecimal q1, BigDecimal median, BigDecimal q3) {
this.deviceId = deviceId; this.deviceId = deviceId;
this.pointValueList = pointValueList; this.pointValueList = pointValueList;
this.parentDeviceId = parentDeviceId; this.parentDeviceId = parentDeviceId;
@ -38,6 +52,9 @@ public class DevicePointDataList
this.diffValue = diffValue; this.diffValue = diffValue;
this.maxDate = maxDate; this.maxDate = maxDate;
this.minDate = minDate; this.minDate = minDate;
this.q1 = q1;
this.median = median;
this.q3 = q3;
} }
public DevicePointDataList(String deviceId, String parentDeviceId, List<GeneralQueryDataVo> pointValueList) { public DevicePointDataList(String deviceId, String parentDeviceId, List<GeneralQueryDataVo> pointValueList) {
@ -121,4 +138,28 @@ public class DevicePointDataList
public void setDiffValue(BigDecimal diffValue) { public void setDiffValue(BigDecimal diffValue) {
this.diffValue = diffValue; this.diffValue = diffValue;
} }
public BigDecimal getQ1() {
return q1;
}
public void setQ1(BigDecimal q1) {
this.q1 = q1;
}
public BigDecimal getMedian() {
return median;
}
public void setMedian(BigDecimal median) {
this.median = median;
}
public BigDecimal getQ3() {
return q3;
}
public void setQ3(BigDecimal q3) {
this.q3 = q3;
}
} }

View File

@ -0,0 +1,40 @@
package com.xzzn.ems.domain.vo;
public class GeneralQueryPointOptionVo {
private String pointId;
private String pointName;
private String dataKey;
private String pointDesc;
public String getPointId() {
return pointId;
}
public void setPointId(String pointId) {
this.pointId = pointId;
}
public String getPointName() {
return pointName;
}
public void setPointName(String pointName) {
this.pointName = pointName;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
public String getPointDesc() {
return pointDesc;
}
public void setPointDesc(String pointDesc) {
this.pointDesc = pointDesc;
}
}

View File

@ -0,0 +1,32 @@
package com.xzzn.ems.domain.vo;
import javax.validation.constraints.NotBlank;
/**
* 按站点导入点位模板请求参数
*/
public class ImportPointTemplateRequest {
/** 目标站点ID */
@NotBlank(message = "站点ID不能为空")
private String siteId;
/** 是否覆盖目标站点已有点位配置 */
private Boolean overwrite;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public Boolean getOverwrite() {
return overwrite;
}
public void setOverwrite(Boolean overwrite) {
this.overwrite = overwrite;
}
}

View File

@ -0,0 +1,76 @@
package com.xzzn.ems.domain.vo;
public class PointConfigCurveRequest {
private String siteId;
private String deviceId;
private String pointId;
private String dataKey;
private String pointType;
private String rangeType;
private String startTime;
private String endTime;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getPointId() {
return pointId;
}
public void setPointId(String pointId) {
this.pointId = pointId;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
public String getPointType() {
return pointType;
}
public void setPointType(String pointType) {
this.pointType = pointType;
}
public String getRangeType() {
return rangeType;
}
public void setRangeType(String rangeType) {
this.rangeType = rangeType;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
}

View File

@ -0,0 +1,24 @@
package com.xzzn.ems.domain.vo;
import java.util.Date;
public class PointConfigCurveValueVo {
private Date dataTime;
private Object pointValue;
public Date getDataTime() {
return dataTime;
}
public void setDataTime(Date dataTime) {
this.dataTime = dataTime;
}
public Object getPointValue() {
return pointValue;
}
public void setPointValue(Object pointValue) {
this.pointValue = pointValue;
}
}

View File

@ -0,0 +1,38 @@
package com.xzzn.ems.domain.vo;
import javax.validation.constraints.NotBlank;
public class PointConfigGenerateRecentRequest {
@NotBlank(message = "站点ID不能为空")
private String siteId;
@NotBlank(message = "点位ID不能为空")
private String pointId;
private String deviceId;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getPointId() {
return pointId;
}
public void setPointId(String pointId) {
this.pointId = pointId;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
}

View File

@ -0,0 +1,40 @@
package com.xzzn.ems.domain.vo;
public class PointConfigLatestValueItemVo {
private String siteId;
private String pointId;
private String deviceId;
private String dataKey;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getPointId() {
return pointId;
}
public void setPointId(String pointId) {
this.pointId = pointId;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
}

View File

@ -0,0 +1,15 @@
package com.xzzn.ems.domain.vo;
import java.util.List;
public class PointConfigLatestValueRequest {
private List<PointConfigLatestValueItemVo> points;
public List<PointConfigLatestValueItemVo> getPoints() {
return points;
}
public void setPoints(List<PointConfigLatestValueItemVo> points) {
this.points = points;
}
}

View File

@ -0,0 +1,60 @@
package com.xzzn.ems.domain.vo;
import java.util.Date;
public class PointConfigLatestValueVo {
private String siteId;
private String pointId;
private String deviceId;
private String dataKey;
private Object pointValue;
private Date dataTime;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getPointId() {
return pointId;
}
public void setPointId(String pointId) {
this.pointId = pointId;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
public Object getPointValue() {
return pointValue;
}
public void setPointValue(Object pointValue) {
this.pointValue = pointValue;
}
public Date getDataTime() {
return dataTime;
}
public void setDataTime(Date dataTime) {
this.dataTime = dataTime;
}
}

View File

@ -1,9 +1,10 @@
package com.xzzn.ems.domain.vo; package com.xzzn.ems.domain.vo;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal; import java.math.BigDecimal;
import javax.validation.constraints.NotBlank;
/** /**
* 设备列表-点位详情-入参 * 设备列表-点位详情-入参
* *
@ -24,6 +25,8 @@ public class PointDataRequest {
private String dataPointName; private String dataPointName;
/** 点位-模糊查询 */ /** 点位-模糊查询 */
private String dataPoint; private String dataPoint;
/** 点位匹配字段 */
private String matchField;
/** 点位数据-范围上下限 */ /** 点位数据-范围上下限 */
private BigDecimal lower; private BigDecimal lower;
private BigDecimal upper; private BigDecimal upper;
@ -126,6 +129,14 @@ public class PointDataRequest {
this.dataPoint = dataPoint; this.dataPoint = dataPoint;
} }
public String getMatchField() {
return matchField;
}
public void setMatchField(String matchField) {
this.matchField = matchField;
}
public BigDecimal getLower() { public BigDecimal getLower() {
return lower; return lower;
} }

View File

@ -14,6 +14,9 @@ public class PointNameRequest {
private String deviceCategory; private String deviceCategory;
private String pointName; private String pointName;
private List<String> pointNames;
private String pointId;
private List<String> pointIds;
/** 数据分组 1-分钟 2-小时 3-天 */ /** 数据分组 1-分钟 2-小时 3-天 */
private int dataUnit; private int dataUnit;
@ -50,6 +53,30 @@ public class PointNameRequest {
this.pointName = pointName; this.pointName = pointName;
} }
public List<String> getPointNames() {
return pointNames;
}
public void setPointNames(List<String> pointNames) {
this.pointNames = pointNames;
}
public String getPointId() {
return pointId;
}
public void setPointId(String pointId) {
this.pointId = pointId;
}
public List<String> getPointIds() {
return pointIds;
}
public void setPointIds(List<String> pointIds) {
this.pointIds = pointIds;
}
public int getDataUnit() { public int getDataUnit() {
return dataUnit; return dataUnit;
} }

View File

@ -14,6 +14,10 @@ public class PointQueryResponse
@Excel(name = "点位名称") @Excel(name = "点位名称")
private String pointName; private String pointName;
/** 点位匹配字段 */
@Excel(name = "点位匹配字段")
private String matchField;
/** 数据点位 */ /** 数据点位 */
@Excel(name = "数据点位") @Excel(name = "数据点位")
private String dataPoint; private String dataPoint;
@ -110,6 +114,14 @@ public class PointQueryResponse
this.pointName = pointName; this.pointName = pointName;
} }
public String getMatchField() {
return matchField;
}
public void setMatchField(String matchField) {
this.matchField = matchField;
}
public String getDataUnit() { public String getDataUnit() {
return dataUnit; return dataUnit;
} }

View File

@ -31,6 +31,8 @@ public class PowerStatisListVo {
*/ */
private BigDecimal pvPower; private BigDecimal pvPower;
public PowerStatisListVo() {}
public PowerStatisListVo(String statisDate, BigDecimal gridPower, BigDecimal storagePower, BigDecimal pvPower) { public PowerStatisListVo(String statisDate, BigDecimal gridPower, BigDecimal storagePower, BigDecimal pvPower) {
this.statisDate = statisDate; this.statisDate = statisDate;
this.gridPower = gridPower; this.gridPower = gridPower;

View File

@ -0,0 +1,114 @@
package com.xzzn.ems.domain.vo;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* 站点保护约束(供策略轮询仲裁)
*/
public class ProtectionConstraintVo implements Serializable {
private static final long serialVersionUID = 1L;
/** 最高保护等级0-无保护1/2/3 对应故障等级 */
private Integer level;
/** 是否允许充电 */
private Boolean allowCharge;
/** 是否允许放电 */
private Boolean allowDischarge;
/** 功率上限比例0~1 */
private BigDecimal powerLimitRatio;
/** 是否强制待机 */
private Boolean forceStandby;
/** 是否强制停机 */
private Boolean forceStop;
/** 生效的方案ID列表 */
private List<Long> sourcePlanIds;
/** 更新时间戳(毫秒) */
private Long updateAt;
public Integer getLevel() {
return level;
}
public void setLevel(Integer level) {
this.level = level;
}
public Boolean getAllowCharge() {
return allowCharge;
}
public void setAllowCharge(Boolean allowCharge) {
this.allowCharge = allowCharge;
}
public Boolean getAllowDischarge() {
return allowDischarge;
}
public void setAllowDischarge(Boolean allowDischarge) {
this.allowDischarge = allowDischarge;
}
public BigDecimal getPowerLimitRatio() {
return powerLimitRatio;
}
public void setPowerLimitRatio(BigDecimal powerLimitRatio) {
this.powerLimitRatio = powerLimitRatio;
}
public Boolean getForceStandby() {
return forceStandby;
}
public void setForceStandby(Boolean forceStandby) {
this.forceStandby = forceStandby;
}
public Boolean getForceStop() {
return forceStop;
}
public void setForceStop(Boolean forceStop) {
this.forceStop = forceStop;
}
public List<Long> getSourcePlanIds() {
return sourcePlanIds;
}
public void setSourcePlanIds(List<Long> sourcePlanIds) {
this.sourcePlanIds = sourcePlanIds;
}
public Long getUpdateAt() {
return updateAt;
}
public void setUpdateAt(Long updateAt) {
this.updateAt = updateAt;
}
public static ProtectionConstraintVo empty() {
ProtectionConstraintVo vo = new ProtectionConstraintVo();
vo.setLevel(0);
vo.setAllowCharge(true);
vo.setAllowDischarge(true);
vo.setPowerLimitRatio(BigDecimal.ONE);
vo.setForceStandby(false);
vo.setForceStop(false);
vo.setSourcePlanIds(new ArrayList<>());
vo.setUpdateAt(System.currentTimeMillis());
return vo;
}
}

View File

@ -0,0 +1,38 @@
package com.xzzn.ems.domain.vo;
import java.util.ArrayList;
import java.util.List;
/**
* 告警保护方案-保护前提分组
*/
public class ProtectionSettingsGroupVo {
/** 故障保护前提 */
private List<ProtectionSettingVo> faultSettings;
/** 释放保护前提 */
private List<ProtectionSettingVo> releaseSettings;
public static ProtectionSettingsGroupVo empty() {
ProtectionSettingsGroupVo vo = new ProtectionSettingsGroupVo();
vo.setFaultSettings(new ArrayList<>());
vo.setReleaseSettings(new ArrayList<>());
return vo;
}
public List<ProtectionSettingVo> getFaultSettings() {
return faultSettings;
}
public void setFaultSettings(List<ProtectionSettingVo> faultSettings) {
this.faultSettings = faultSettings;
}
public List<ProtectionSettingVo> getReleaseSettings() {
return releaseSettings;
}
public void setReleaseSettings(List<ProtectionSettingVo> releaseSettings) {
this.releaseSettings = releaseSettings;
}
}

View File

@ -1,6 +1,7 @@
package com.xzzn.ems.domain.vo; package com.xzzn.ems.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date; import java.util.Date;
@ -10,10 +11,12 @@ import java.util.Date;
public class RunningGraphRequest { public class RunningGraphRequest {
/** 开始时间 */ /** 开始时间 */
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
private Date startDate; private Date startDate;
/** 结束时间 */ /** 结束时间 */
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd")
private Date endDate; private Date endDate;

View File

@ -0,0 +1,41 @@
package com.xzzn.ems.domain.vo;
public class SingleBatteryConfigInitRequest {
private String siteId;
private String scopeType;
private String scopeDeviceId;
private Integer targetCount;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getScopeType() {
return scopeType;
}
public void setScopeType(String scopeType) {
this.scopeType = scopeType;
}
public String getScopeDeviceId() {
return scopeDeviceId;
}
public void setScopeDeviceId(String scopeDeviceId) {
this.scopeDeviceId = scopeDeviceId;
}
public Integer getTargetCount() {
return targetCount;
}
public void setTargetCount(Integer targetCount) {
this.targetCount = targetCount;
}
}

View File

@ -0,0 +1,122 @@
package com.xzzn.ems.domain.vo;
public class SingleBatteryConfigInitResultVo {
private Boolean committed;
private String siteId;
private String scopeType;
private String scopeDeviceId;
private Integer targetCount;
private Integer existingBatteryCount;
private Integer initializedBatteryCount;
private Integer insertedBatteryCount;
private Integer pointHitCount;
private Integer fixedValueFallbackCount;
private Integer insertedMappingCount;
private Integer updatedMappingCount;
private String message;
public Boolean getCommitted() {
return committed;
}
public void setCommitted(Boolean committed) {
this.committed = committed;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getScopeType() {
return scopeType;
}
public void setScopeType(String scopeType) {
this.scopeType = scopeType;
}
public String getScopeDeviceId() {
return scopeDeviceId;
}
public void setScopeDeviceId(String scopeDeviceId) {
this.scopeDeviceId = scopeDeviceId;
}
public Integer getTargetCount() {
return targetCount;
}
public void setTargetCount(Integer targetCount) {
this.targetCount = targetCount;
}
public Integer getExistingBatteryCount() {
return existingBatteryCount;
}
public void setExistingBatteryCount(Integer existingBatteryCount) {
this.existingBatteryCount = existingBatteryCount;
}
public Integer getInitializedBatteryCount() {
return initializedBatteryCount;
}
public void setInitializedBatteryCount(Integer initializedBatteryCount) {
this.initializedBatteryCount = initializedBatteryCount;
}
public Integer getInsertedBatteryCount() {
return insertedBatteryCount;
}
public void setInsertedBatteryCount(Integer insertedBatteryCount) {
this.insertedBatteryCount = insertedBatteryCount;
}
public Integer getPointHitCount() {
return pointHitCount;
}
public void setPointHitCount(Integer pointHitCount) {
this.pointHitCount = pointHitCount;
}
public Integer getFixedValueFallbackCount() {
return fixedValueFallbackCount;
}
public void setFixedValueFallbackCount(Integer fixedValueFallbackCount) {
this.fixedValueFallbackCount = fixedValueFallbackCount;
}
public Integer getInsertedMappingCount() {
return insertedMappingCount;
}
public void setInsertedMappingCount(Integer insertedMappingCount) {
this.insertedMappingCount = insertedMappingCount;
}
public Integer getUpdatedMappingCount() {
return updatedMappingCount;
}
public void setUpdatedMappingCount(Integer updatedMappingCount) {
this.updatedMappingCount = updatedMappingCount;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -0,0 +1,59 @@
package com.xzzn.ems.domain.vo;
public class SingleBatteryMonitorImportFailureVo {
private Integer rowNum;
private String siteId;
private String stackDeviceId;
private String clusterDeviceId;
private String batteryDeviceId;
private String errorMessage;
public Integer getRowNum() {
return rowNum;
}
public void setRowNum(Integer rowNum) {
this.rowNum = rowNum;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getStackDeviceId() {
return stackDeviceId;
}
public void setStackDeviceId(String stackDeviceId) {
this.stackDeviceId = stackDeviceId;
}
public String getClusterDeviceId() {
return clusterDeviceId;
}
public void setClusterDeviceId(String clusterDeviceId) {
this.clusterDeviceId = clusterDeviceId;
}
public String getBatteryDeviceId() {
return batteryDeviceId;
}
public void setBatteryDeviceId(String batteryDeviceId) {
this.batteryDeviceId = batteryDeviceId;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}

View File

@ -0,0 +1,98 @@
package com.xzzn.ems.domain.vo;
import java.util.ArrayList;
import java.util.List;
public class SingleBatteryMonitorImportResultVo {
private Boolean committed;
private Integer totalRows;
private Integer successRows;
private Integer failureRows;
private Integer insertedBatteryCount;
private Integer updatedBatteryCount;
private Integer insertedMappingCount;
private Integer updatedMappingCount;
private String message;
private List<SingleBatteryMonitorImportFailureVo> failureDetails = new ArrayList<>();
public Boolean getCommitted() {
return committed;
}
public void setCommitted(Boolean committed) {
this.committed = committed;
}
public Integer getTotalRows() {
return totalRows;
}
public void setTotalRows(Integer totalRows) {
this.totalRows = totalRows;
}
public Integer getSuccessRows() {
return successRows;
}
public void setSuccessRows(Integer successRows) {
this.successRows = successRows;
}
public Integer getFailureRows() {
return failureRows;
}
public void setFailureRows(Integer failureRows) {
this.failureRows = failureRows;
}
public Integer getInsertedBatteryCount() {
return insertedBatteryCount;
}
public void setInsertedBatteryCount(Integer insertedBatteryCount) {
this.insertedBatteryCount = insertedBatteryCount;
}
public Integer getUpdatedBatteryCount() {
return updatedBatteryCount;
}
public void setUpdatedBatteryCount(Integer updatedBatteryCount) {
this.updatedBatteryCount = updatedBatteryCount;
}
public Integer getInsertedMappingCount() {
return insertedMappingCount;
}
public void setInsertedMappingCount(Integer insertedMappingCount) {
this.insertedMappingCount = insertedMappingCount;
}
public Integer getUpdatedMappingCount() {
return updatedMappingCount;
}
public void setUpdatedMappingCount(Integer updatedMappingCount) {
this.updatedMappingCount = updatedMappingCount;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<SingleBatteryMonitorImportFailureVo> getFailureDetails() {
return failureDetails;
}
public void setFailureDetails(List<SingleBatteryMonitorImportFailureVo> failureDetails) {
this.failureDetails = failureDetails;
}
}

View File

@ -0,0 +1,115 @@
package com.xzzn.ems.domain.vo;
import com.xzzn.common.annotation.Excel;
public class SingleBatteryMonitorImportRowVo {
private Integer rowNum;
@Excel(name = "站点ID")
private String siteId;
@Excel(name = "电池堆编号")
private String stackDeviceId;
@Excel(name = "电池簇编号")
private String clusterDeviceId;
@Excel(name = "单体编号")
private String batteryDeviceId;
@Excel(name = "单体名称")
private String batteryDeviceName;
@Excel(name = "电压点位ID")
private String voltagePointId;
@Excel(name = "温度点位ID")
private String temperaturePointId;
@Excel(name = "SOC点位ID")
private String socPointId;
@Excel(name = "SOH点位ID")
private String sohPointId;
public Integer getRowNum() {
return rowNum;
}
public void setRowNum(Integer rowNum) {
this.rowNum = rowNum;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getStackDeviceId() {
return stackDeviceId;
}
public void setStackDeviceId(String stackDeviceId) {
this.stackDeviceId = stackDeviceId;
}
public String getClusterDeviceId() {
return clusterDeviceId;
}
public void setClusterDeviceId(String clusterDeviceId) {
this.clusterDeviceId = clusterDeviceId;
}
public String getBatteryDeviceId() {
return batteryDeviceId;
}
public void setBatteryDeviceId(String batteryDeviceId) {
this.batteryDeviceId = batteryDeviceId;
}
public String getBatteryDeviceName() {
return batteryDeviceName;
}
public void setBatteryDeviceName(String batteryDeviceName) {
this.batteryDeviceName = batteryDeviceName;
}
public String getVoltagePointId() {
return voltagePointId;
}
public void setVoltagePointId(String voltagePointId) {
this.voltagePointId = voltagePointId;
}
public String getTemperaturePointId() {
return temperaturePointId;
}
public void setTemperaturePointId(String temperaturePointId) {
this.temperaturePointId = temperaturePointId;
}
public String getSocPointId() {
return socPointId;
}
public void setSocPointId(String socPointId) {
this.socPointId = socPointId;
}
public String getSohPointId() {
return sohPointId;
}
public void setSohPointId(String sohPointId) {
this.sohPointId = sohPointId;
}
}

View File

@ -0,0 +1,33 @@
package com.xzzn.ems.domain.vo;
import java.util.Date;
public class SiteMonitorDataSaveItemVo {
private String fieldCode;
private String fieldValue;
private Date valueTime;
public String getFieldCode() {
return fieldCode;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
public Date getValueTime() {
return valueTime;
}
public void setValueTime(Date valueTime) {
this.valueTime = valueTime;
}
}

View File

@ -0,0 +1,24 @@
package com.xzzn.ems.domain.vo;
import java.util.List;
public class SiteMonitorDataSaveRequest {
private String siteId;
private List<SiteMonitorDataSaveItemVo> items;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public List<SiteMonitorDataSaveItemVo> getItems() {
return items;
}
public void setItems(List<SiteMonitorDataSaveItemVo> items) {
this.items = items;
}
}

View File

@ -0,0 +1,27 @@
package com.xzzn.ems.domain.vo;
import java.util.Date;
/**
* 单站监控展示数据(配置项 + 当前值)
*/
public class SiteMonitorProjectDisplayVo extends SiteMonitorProjectPointMappingVo {
private String fieldValue;
private Date valueTime;
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
public Date getValueTime() {
return valueTime;
}
public void setValueTime(Date valueTime) {
this.valueTime = valueTime;
}
}

View File

@ -0,0 +1,36 @@
package com.xzzn.ems.domain.vo;
import java.util.List;
public class SiteMonitorProjectPointMappingSaveRequest {
private String siteId;
private List<SiteMonitorProjectPointMappingVo> mappings;
private List<String> deletedFieldCodes;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public List<SiteMonitorProjectPointMappingVo> getMappings() {
return mappings;
}
public void setMappings(List<SiteMonitorProjectPointMappingVo> mappings) {
this.mappings = mappings;
}
public List<String> getDeletedFieldCodes() {
return deletedFieldCodes;
}
public void setDeletedFieldCodes(List<String> deletedFieldCodes) {
this.deletedFieldCodes = deletedFieldCodes;
}
}

View File

@ -0,0 +1,124 @@
package com.xzzn.ems.domain.vo;
public class SiteMonitorProjectPointMappingVo {
private String moduleCode;
private String moduleName;
private String menuCode;
private String menuName;
private String sectionName;
private String fieldCode;
private String fieldName;
private String deviceId;
private String deviceName;
private String dataPoint;
private String fixedDataPoint;
private Integer useFixedDisplay;
public String getModuleCode() {
return moduleCode;
}
public void setModuleCode(String moduleCode) {
this.moduleCode = moduleCode;
}
public String getModuleName() {
return moduleName;
}
public void setModuleName(String moduleName) {
this.moduleName = moduleName;
}
public String getFieldCode() {
return fieldCode;
}
public String getMenuCode() {
return menuCode;
}
public void setMenuCode(String menuCode) {
this.menuCode = menuCode;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getSectionName() {
return sectionName;
}
public void setSectionName(String sectionName) {
this.sectionName = sectionName;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getDataPoint() {
return dataPoint;
}
public void setDataPoint(String dataPoint) {
this.dataPoint = dataPoint;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public String getFixedDataPoint() {
return fixedDataPoint;
}
public void setFixedDataPoint(String fixedDataPoint) {
this.fixedDataPoint = fixedDataPoint;
}
public Integer getUseFixedDisplay() {
return useFixedDisplay;
}
public void setUseFixedDisplay(Integer useFixedDisplay) {
this.useFixedDisplay = useFixedDisplay;
}
}

View File

@ -6,6 +6,7 @@ import java.math.BigDecimal;
* 单站监控-首页-电池堆点位数据 * 单站监控-首页-电池堆点位数据
*/ */
public class StackPointVo{ public class StackPointVo{
private String statisDate; private String statisDate;
/** SOC */ /** SOC */
private BigDecimal avgSoc; private BigDecimal avgSoc;

View File

@ -0,0 +1,76 @@
package com.xzzn.ems.domain.vo;
public class WeatherSyncResultVo {
private String siteId;
private String startTime;
private String endTime;
private int totalDays;
private int successDays;
private int insertedDays;
private int updatedDays;
private String message;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
public int getTotalDays() {
return totalDays;
}
public void setTotalDays(int totalDays) {
this.totalDays = totalDays;
}
public int getSuccessDays() {
return successDays;
}
public void setSuccessDays(int successDays) {
this.successDays = successDays;
}
public int getInsertedDays() {
return insertedDays;
}
public void setInsertedDays(int insertedDays) {
this.insertedDays = insertedDays;
}
public int getUpdatedDays() {
return updatedDays;
}
public void setUpdatedDays(int updatedDays) {
this.updatedDays = updatedDays;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -0,0 +1,26 @@
package com.xzzn.ems.domain.vo;
import java.util.List;
public class WorkStatusEnumMappingSaveRequest {
private String siteId;
private List<WorkStatusEnumMappingVo> mappings;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public List<WorkStatusEnumMappingVo> getMappings() {
return mappings;
}
public void setMappings(List<WorkStatusEnumMappingVo> mappings) {
this.mappings = mappings;
}
}

View File

@ -0,0 +1,74 @@
package com.xzzn.ems.domain.vo;
public class WorkStatusEnumMappingVo {
private String deviceCategory;
private String matchField;
private String matchFieldName;
private String enumCode;
private String enumName;
private String enumDesc;
private String dataEnumCode;
public String getEnumCode() {
return enumCode;
}
public void setEnumCode(String enumCode) {
this.enumCode = enumCode;
}
public String getEnumName() {
return enumName;
}
public void setEnumName(String enumName) {
this.enumName = enumName;
}
public String getEnumDesc() {
return enumDesc;
}
public void setEnumDesc(String enumDesc) {
this.enumDesc = enumDesc;
}
public String getDataEnumCode() {
return dataEnumCode;
}
public void setDataEnumCode(String dataEnumCode) {
this.dataEnumCode = dataEnumCode;
}
public String getDeviceCategory() {
return deviceCategory;
}
public void setDeviceCategory(String deviceCategory) {
this.deviceCategory = deviceCategory;
}
public String getMatchField() {
return matchField;
}
public void setMatchField(String matchField) {
this.matchField = matchField;
}
public String getMatchFieldName() {
return matchFieldName;
}
public void setMatchFieldName(String matchFieldName) {
this.matchFieldName = matchFieldName;
}
}

View File

@ -1,9 +1,18 @@
package com.xzzn.ems.mapper; package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsAmmeterData;
import com.xzzn.ems.domain.vo.AmmeterStatisListVo;
import com.xzzn.ems.domain.vo.DateSearchRequest;
import com.xzzn.ems.domain.vo.MonthlyTimeRange;
import com.xzzn.ems.domain.vo.PowerStatisListVo;
import com.xzzn.ems.domain.vo.SiteMonitorDataVo;
import com.xzzn.ems.domain.vo.StatisAmmeterDateRequest;
import com.xzzn.ems.domain.vo.TimePointQuery;
import com.xzzn.ems.domain.vo.TimePointValue;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import com.xzzn.ems.domain.EmsAmmeterData;
import com.xzzn.ems.domain.vo.*;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
/** /**
@ -99,4 +108,6 @@ public interface EmsAmmeterDataMapper
List<AmmeterStatisListVo> selectDailyAmmeterData(@Param("siteId") String siteId, List<AmmeterStatisListVo> selectDailyAmmeterData(@Param("siteId") String siteId,
@Param("startTime") String startTime, @Param("startTime") String startTime,
@Param("endTime") String endTime); @Param("endTime") String endTime);
List<PowerStatisListVo> getPowerDataByMinute(DateSearchRequest requestVo);
} }

View File

@ -1,12 +1,17 @@
package com.xzzn.ems.mapper; package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsBatteryCluster;
import com.xzzn.ems.domain.vo.BMSBatteryDataList;
import com.xzzn.ems.domain.vo.BatteryAveTempVo;
import com.xzzn.ems.domain.vo.ClusterStatisListVo;
import com.xzzn.ems.domain.vo.DateSearchRequest;
import com.xzzn.ems.domain.vo.StatisClusterDateRequest;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.xzzn.ems.domain.EmsBatteryCluster;
import com.xzzn.ems.domain.vo.*;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
/** /**
@ -83,4 +88,6 @@ public interface EmsBatteryClusterMapper
public List<Map<String, BigDecimal>> getAvgTempByHour(DateSearchRequest requestVo); public List<Map<String, BigDecimal>> getAvgTempByHour(DateSearchRequest requestVo);
public List<Map<String, BigDecimal>> getAvgTempByDay(DateSearchRequest requestVo); public List<Map<String, BigDecimal>> getAvgTempByDay(DateSearchRequest requestVo);
public List<Map<String, BigDecimal>> getAvgTempByMonth(DateSearchRequest requestVo); public List<Map<String, BigDecimal>> getAvgTempByMonth(DateSearchRequest requestVo);
List<Map<String, BigDecimal>> getAvgTempByMinute(DateSearchRequest requestVo);
} }

View File

@ -1,9 +1,15 @@
package com.xzzn.ems.mapper; package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsBatteryStack;
import com.xzzn.ems.domain.vo.BatteryAveSOCVo;
import com.xzzn.ems.domain.vo.BatteryAveTempVo;
import com.xzzn.ems.domain.vo.DateSearchRequest;
import com.xzzn.ems.domain.vo.StackPointVo;
import com.xzzn.ems.domain.vo.StackStatisListVo;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import com.xzzn.ems.domain.EmsBatteryStack;
import com.xzzn.ems.domain.vo.*;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
/** /**
@ -85,4 +91,8 @@ public interface EmsBatteryStackMapper
public List<BatteryAveSOCVo> getAveSocList(@Param("siteId") String siteId, @Param("startDate") Date startDate, @Param("endDate") Date endDate); public List<BatteryAveSOCVo> getAveSocList(@Param("siteId") String siteId, @Param("startDate") Date startDate, @Param("endDate") Date endDate);
// 实时运行-DDS平均温度 // 实时运行-DDS平均温度
public List<BatteryAveTempVo> getBatteryAveTempList(@Param("siteId")String siteId, @Param("startDate")Date yesterday, @Param("endDate") Date today); public List<BatteryAveTempVo> getBatteryAveTempList(@Param("siteId")String siteId, @Param("startDate")Date yesterday, @Param("endDate") Date today);
List<StackPointVo> getStackPointByMinute(DateSearchRequest requestVo);
List<StackStatisListVo> getStackDataByMinute(DateSearchRequest requestVo);
} }

View File

@ -69,6 +69,17 @@ public interface EmsDailyChargeDataMapper
// 插入或更新站点每日充放电数据 // 插入或更新站点每日充放电数据
public void insertOrUpdateData(EmsDailyChargeData emsDailyChargeData); public void insertOrUpdateData(EmsDailyChargeData emsDailyChargeData);
// 按站点+日期(天)查询当日已存在记录
public EmsDailyChargeData selectBySiteIdAndDateTime(@Param("siteId") String siteId,
@Param("dateTime") Date dateTime);
// 按站点+日期(天)更新收入字段
public int updateRevenueBySiteAndDate(@Param("siteId") String siteId,
@Param("dateTime") Date dateTime,
@Param("totalRevenue") BigDecimal totalRevenue,
@Param("dayRevenue") BigDecimal dayRevenue,
@Param("updateBy") String updateBy);
// 获取所有站点总充总放 // 获取所有站点总充总放
public Map<String, BigDecimal> getAllSiteChargeData(@Param("nowData")String nowData, @Param("siteId")String siteId); public Map<String, BigDecimal> getAllSiteChargeData(@Param("nowData")String nowData, @Param("siteId")String siteId);

View File

@ -68,6 +68,12 @@ public interface EmsDailyEnergyDataMapper
// 获取站点某日电表数据 // 获取站点某日电表数据
public EmsDailyEnergyData getDataByDate(@Param("siteId")String siteId,@Param("today") String today); public EmsDailyEnergyData getDataByDate(@Param("siteId")String siteId,@Param("today") String today);
// 按站点+日期+小时查询当小时已存在记录
public EmsDailyEnergyData selectBySiteIdAndDateHour(@Param("siteId") String siteId,
@Param("dataDate") java.util.Date dataDate,
@Param("dataHour") Integer dataHour);
// 插入或更新每日尖峰平谷差值 // 插入或更新每日尖峰平谷差值
public void insertOrUpdateData(EmsDailyEnergyData energyData); public void insertOrUpdateData(EmsDailyEnergyData energyData);
// 电表报表 // 电表报表

View File

@ -136,6 +136,8 @@ public interface EmsPcsDataMapper
public List<PcsStatisListVo> getPcsActivePowerByMonth(DateSearchRequest requestVo); public List<PcsStatisListVo> getPcsActivePowerByMonth(DateSearchRequest requestVo);
public List<PcsStatisListVo> getPcsActivePowerByMinutes(DateSearchRequest requestVo);
// 实时运行-fx-pcs最高温度 // 实时运行-fx-pcs最高温度
public List<PcsMaxTempVo> getFXMaxTemp(@Param("siteId")String siteId, @Param("startDate")Date startDate, @Param("endDate")Date endDate); public List<PcsMaxTempVo> getFXMaxTemp(@Param("siteId")String siteId, @Param("startDate")Date startDate, @Param("endDate")Date endDate);
// 实时运行-dds-pcs最高温度 // 实时运行-dds-pcs最高温度

View File

@ -0,0 +1,24 @@
package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsPointCalcConfig;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface EmsPointCalcConfigMapper {
EmsPointCalcConfig selectEmsPointCalcConfigById(Long id);
List<EmsPointCalcConfig> selectEmsPointCalcConfigList(EmsPointCalcConfig emsPointCalcConfig);
int insertEmsPointCalcConfig(EmsPointCalcConfig emsPointCalcConfig);
int updateEmsPointCalcConfig(EmsPointCalcConfig emsPointCalcConfig);
int deleteEmsPointCalcConfigById(Long id);
int deleteEmsPointCalcConfigByIds(Long[] ids);
int countBySiteId(@Param("siteId") String siteId);
int deleteBySiteId(@Param("siteId") String siteId);
}

View File

@ -0,0 +1,54 @@
package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsPointConfig;
import com.xzzn.ems.domain.vo.GeneralQueryPointOptionVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface EmsPointConfigMapper {
EmsPointConfig selectEmsPointConfigById(Long id);
List<EmsPointConfig> selectEmsPointConfigList(EmsPointConfig emsPointConfig);
int insertEmsPointConfig(EmsPointConfig emsPointConfig);
int insertBatchEmsPointConfig(@Param("list") List<EmsPointConfig> list);
int updateEmsPointConfig(EmsPointConfig emsPointConfig);
int updateEmsPointConfigForImport(EmsPointConfig emsPointConfig);
int deleteEmsPointConfigById(Long id);
int deleteEmsPointConfigByIds(Long[] ids);
int countBySiteId(@Param("siteId") String siteId);
int deleteBySiteId(@Param("siteId") String siteId);
int copyTemplateToSite(@Param("templateSiteId") String templateSiteId,
@Param("targetSiteId") String targetSiteId,
@Param("operName") String operName);
String getRegisterAddress(@Param("siteId") String siteId,
@Param("deviceCategory") String deviceCategory,
@Param("deviceId") String deviceId,
@Param("dataKey") String dataKey);
List<GeneralQueryPointOptionVo> getPointNameList(@Param("siteIds") List<String> siteIds,
@Param("deviceCategory") String deviceCategory,
@Param("deviceId") String deviceId,
@Param("pointName") String pointName);
List<EmsPointConfig> getConfigListForGeneralQuery(@Param("siteIds") List<String> siteIds,
@Param("deviceCategory") String deviceCategory,
@Param("pointIds") List<String> pointIds,
@Param("pointNames") List<String> pointNames,
@Param("deviceIds") List<String> deviceIds);
List<EmsPointConfig> selectBySiteIdAndPointIds(@Param("siteId") String siteId,
@Param("pointIds") List<String> pointIds);
List<EmsPointConfig> selectModbusCollectPointConfigs(@Param("siteId") String siteId);
}

View File

@ -67,4 +67,16 @@ public interface EmsPointEnumMatchMapper
public List<EmsPointEnumMatch> selectList(@Param("siteId") String siteId, public List<EmsPointEnumMatch> selectList(@Param("siteId") String siteId,
@Param("deviceCategory") String deviceCategory, @Param("deviceCategory") String deviceCategory,
@Param("matchField") String matchField); @Param("matchField") String matchField);
int countBySiteId(@Param("siteId") String siteId);
int deleteBySiteId(@Param("siteId") String siteId);
int copyTemplateToSite(@Param("templateSiteId") String templateSiteId,
@Param("targetSiteId") String targetSiteId,
@Param("operName") String operName);
int deleteByScope(@Param("siteId") String siteId,
@Param("deviceCategory") String deviceCategory,
@Param("matchField") String matchField);
} }

View File

@ -75,7 +75,8 @@ public interface EmsPointMatchMapper
// 获取匹配信息 // 获取匹配信息
public List<EmsPointMatch> getMatchInfo(@Param("siteIds") List<String> siteIds, public List<EmsPointMatch> getMatchInfo(@Param("siteIds") List<String> siteIds,
@Param("deviceCategory")String deviceCategory, @Param("deviceId") String deviceId,
@Param("deviceCategory") String deviceCategory,
@Param("pointName") String pointName); @Param("pointName") String pointName);
// 根据条件查询数据-按分钟-单体电池特殊处理 // 根据条件查询数据-按分钟-单体电池特殊处理
public List<GeneralQueryDataVo> getBatteryPointDataByMinutes(@Param("siteIds")List<String> siteIds, public List<GeneralQueryDataVo> getBatteryPointDataByMinutes(@Param("siteIds")List<String> siteIds,
@ -172,4 +173,14 @@ public interface EmsPointMatchMapper
int getDevicePointAlarmNum(@Param("siteId") String siteId, @Param("deviceId") String deviceId, @Param("deviceCategory") String deviceCategory); int getDevicePointAlarmNum(@Param("siteId") String siteId, @Param("deviceId") String deviceId, @Param("deviceCategory") String deviceCategory);
List<EmsPointMatch> selectDeviceStatusPoint(@Param("request") DeviceUpdateRequest request); List<EmsPointMatch> selectDeviceStatusPoint(@Param("request") DeviceUpdateRequest request);
int countBySiteId(@Param("siteId") String siteId);
int deleteBySiteId(@Param("siteId") String siteId);
int copyTemplateToSite(@Param("templateSiteId") String templateSiteId,
@Param("targetSiteId") String targetSiteId,
@Param("operName") String operName);
List<EmsPointMatch> selectBySiteId(@Param("siteId") String siteId);
} }

View File

@ -0,0 +1,23 @@
package com.xzzn.ems.mapper;
import org.apache.ibatis.annotations.Param;
/**
* 单站监控展示数据 Mapper
*/
public interface EmsSiteMonitorDataMapper {
String selectHistoryJsonByMinute(@Param("tableName") String tableName,
@Param("siteId") String siteId,
@Param("statisMinute") java.util.Date statisMinute);
int upsertHistoryJsonByMinute(@Param("tableName") String tableName,
@Param("siteId") String siteId,
@Param("statisMinute") java.util.Date statisMinute,
@Param("dataJson") String dataJson,
@Param("hotSoc") String hotSoc,
@Param("hotTotalActivePower") String hotTotalActivePower,
@Param("hotTotalReactivePower") String hotTotalReactivePower,
@Param("hotDayChargedCap") String hotDayChargedCap,
@Param("hotDayDisChargedCap") String hotDayDisChargedCap,
@Param("operName") String operName);
}

View File

@ -0,0 +1,12 @@
package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsSiteMonitorItem;
import java.util.List;
/**
* 单站监控配置项定义 Mapper
*/
public interface EmsSiteMonitorItemMapper {
List<EmsSiteMonitorItem> selectEnabledList();
}

View File

@ -0,0 +1,23 @@
package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsSiteMonitorPointMatch;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 单站监控字段点位映射 Mapper
*/
public interface EmsSiteMonitorPointMatchMapper {
List<String> selectDistinctSiteIds();
List<EmsSiteMonitorPointMatch> selectBySiteId(@Param("siteId") String siteId);
int deleteBySiteId(@Param("siteId") String siteId);
int deleteBySiteIdAndDeviceId(@Param("siteId") String siteId, @Param("deviceId") String deviceId);
int insertBatch(@Param("list") List<EmsSiteMonitorPointMatch> list);
int updateEmsSiteMonitorPointMatch(EmsSiteMonitorPointMatch pointMatch);
}

View File

@ -0,0 +1,19 @@
package com.xzzn.ems.mapper;
import org.apache.ibatis.annotations.Param;
public interface EmsSiteWeatherDayMapper {
int updateWeatherDesc(@Param("siteId") String siteId,
@Param("calendarDate") String calendarDate,
@Param("weatherDesc") String weatherDesc,
@Param("weatherCode") Integer weatherCode);
int selectCountBySiteAndDate(@Param("siteId") String siteId, @Param("calendarDate") String calendarDate);
int insertSiteWeatherDay(@Param("siteId") String siteId,
@Param("calendarDate") String calendarDate,
@Param("weatherDesc") String weatherDesc,
@Param("weatherCode") Integer weatherCode,
@Param("source") String source);
}

View File

@ -0,0 +1,36 @@
package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsStrategyRuntimeConfig;
/**
* 策略运行参数配置Mapper接口
*
* @author xzzn
* @date 2026-02-13
*/
public interface EmsStrategyRuntimeConfigMapper {
/**
* 根据站点ID查询参数配置
*
* @param siteId 站点ID
* @return 参数配置
*/
EmsStrategyRuntimeConfig selectBySiteId(String siteId);
/**
* 新增参数配置
*
* @param config 参数配置
* @return 结果
*/
int insert(EmsStrategyRuntimeConfig config);
/**
* 按站点ID更新参数配置
*
* @param config 参数配置
* @return 结果
*/
int updateBySiteId(EmsStrategyRuntimeConfig config);
}

View File

@ -0,0 +1,21 @@
package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.SysBizRemark;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface SysBizRemarkMapper
{
SysBizRemark selectByBizKeys(@Param("bizType") String bizType,
@Param("bizKey1") String bizKey1,
@Param("bizKey2") String bizKey2);
List<SysBizRemark> selectByBizKey2List(@Param("bizType") String bizType,
@Param("bizKey1") String bizKey1,
@Param("bizKey2List") List<String> bizKey2List);
int insertSysBizRemark(SysBizRemark bizRemark);
int updateSysBizRemark(SysBizRemark bizRemark);
}

View File

@ -1,7 +0,0 @@
package com.xzzn.ems.service;
public interface IDDSDataProcessService {
public void handleDdsData(String message);
}

View File

@ -77,6 +77,15 @@ public interface IEmsAlarmRecordsService
* @return * @return
*/ */
public String createTicketNo(Long id, Long userId); public String createTicketNo(Long id, Long userId);
/**
* 关闭告警并设置为已处理
*
* @param id 告警ID
* @param userId 用户ID
* @return 处理结果
*/
public String closeAlarm(Long id, Long userId);
// 订阅失败-增加告警 // 订阅失败-增加告警
public void addSubFailedAlarmRecord(String topic); public void addSubFailedAlarmRecord(String topic);
// 订阅成功-处理告警 // 订阅成功-处理告警
@ -85,6 +94,8 @@ public interface IEmsAlarmRecordsService
// topic 内没有数据,按照设备维度告警 // topic 内没有数据,按照设备维度告警
public void addEmptyDataAlarmRecord(String siteId, String deviceId); public void addEmptyDataAlarmRecord(String siteId, String deviceId);
public void deleteEmptyDataAlarmRecord(String siteId, String deviceId);
// 告警字段和告警信息 // 告警字段和告警信息
public void initAlarmMatchInfo(); public void initAlarmMatchInfo();
@ -101,4 +112,6 @@ public interface IEmsAlarmRecordsService
public void dealSyncData(String content, String operateType); public void dealSyncData(String content, String operateType);
public void addDeviceOfflineRecord(String siteId, String deviceNumber); public void addDeviceOfflineRecord(String siteId, String deviceNumber);
public void deleteDeviceOfflineRecord(String siteId, String deviceNumber);
} }

View File

@ -0,0 +1,21 @@
package com.xzzn.ems.service;
import com.xzzn.ems.domain.EmsDailyChargeData;
import java.util.List;
/**
* 站点每日充放电数据Service接口
*/
public interface IEmsDailyChargeDataService {
List<EmsDailyChargeData> selectEmsDailyChargeDataList(EmsDailyChargeData emsDailyChargeData);
EmsDailyChargeData selectEmsDailyChargeDataById(Long id);
int insertEmsDailyChargeData(EmsDailyChargeData emsDailyChargeData, String operName);
int updateEmsDailyChargeData(EmsDailyChargeData emsDailyChargeData, String operName);
int deleteEmsDailyChargeDataByIds(Long[] ids);
}

View File

@ -0,0 +1,21 @@
package com.xzzn.ems.service;
import com.xzzn.ems.domain.EmsDailyEnergyData;
import java.util.List;
/**
* 站点每日收益数据Service接口
*/
public interface IEmsDailyEnergyDataService {
List<EmsDailyEnergyData> selectEmsDailyEnergyDataList(EmsDailyEnergyData emsDailyEnergyData);
EmsDailyEnergyData selectEmsDailyEnergyDataById(Long id);
int insertEmsDailyEnergyData(EmsDailyEnergyData emsDailyEnergyData, String operName);
int updateEmsDailyEnergyData(EmsDailyEnergyData emsDailyEnergyData, String operName);
int deleteEmsDailyEnergyDataByIds(Long[] ids);
}

View File

@ -6,7 +6,17 @@ import com.xzzn.ems.domain.vo.DeviceUpdateRequest;
import com.xzzn.ems.domain.vo.DevicesSettingVo; import com.xzzn.ems.domain.vo.DevicesSettingVo;
import com.xzzn.ems.domain.vo.PointDataRequest; import com.xzzn.ems.domain.vo.PointDataRequest;
import com.xzzn.ems.domain.vo.PointQueryResponse; import com.xzzn.ems.domain.vo.PointQueryResponse;
import com.xzzn.ems.domain.vo.SiteMonitorDataSaveRequest;
import com.xzzn.ems.domain.vo.SiteMonitorProjectDisplayVo;
import com.xzzn.ems.domain.vo.SiteMonitorProjectPointMappingSaveRequest;
import com.xzzn.ems.domain.vo.SiteMonitorProjectPointMappingVo;
import com.xzzn.ems.domain.vo.SingleBatteryConfigInitRequest;
import com.xzzn.ems.domain.vo.SingleBatteryConfigInitResultVo;
import com.xzzn.ems.domain.vo.SingleBatteryMonitorImportResultVo;
import com.xzzn.ems.domain.vo.SingleBatteryMonitorImportRowVo;
import com.xzzn.ems.domain.vo.WorkStatusEnumMappingVo;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -36,4 +46,22 @@ public interface IEmsDeviceSettingService
public List<Map<String, Object>> getDeviceListBySiteAndCategory(String siteId, String deviceCategory); public List<Map<String, Object>> getDeviceListBySiteAndCategory(String siteId, String deviceCategory);
public boolean updateDeviceStatus(DeviceUpdateRequest request); public boolean updateDeviceStatus(DeviceUpdateRequest request);
public List<SiteMonitorProjectPointMappingVo> getSiteMonitorProjectPointMapping(String siteId);
public int saveSiteMonitorProjectPointMapping(SiteMonitorProjectPointMappingSaveRequest request, String operName);
public List<WorkStatusEnumMappingVo> getSiteWorkStatusEnumMappings(String siteId);
public int saveSiteWorkStatusEnumMappings(String siteId, List<WorkStatusEnumMappingVo> mappings, String operName);
public List<SiteMonitorProjectDisplayVo> getSiteMonitorProjectDisplay(String siteId);
public int saveSiteMonitorProjectData(SiteMonitorDataSaveRequest request, String operName);
public int syncSiteMonitorDataByMqtt(String siteId, String deviceId, String jsonData, Date valueTime);
public SingleBatteryMonitorImportResultVo importSingleBatteryMonitorMappings(String siteId, List<SingleBatteryMonitorImportRowVo> rows, String operName);
public SingleBatteryConfigInitResultVo initializeSingleBatteryMonitorMappings(SingleBatteryConfigInitRequest request, String operName);
} }

View File

@ -0,0 +1,19 @@
package com.xzzn.ems.service;
import com.xzzn.ems.domain.EmsPointCalcConfig;
import java.util.List;
public interface IEmsPointCalcConfigService {
List<EmsPointCalcConfig> selectPointCalcConfigList(EmsPointCalcConfig pointCalcConfig);
EmsPointCalcConfig selectPointCalcConfigById(Long id);
int insertPointCalcConfig(EmsPointCalcConfig pointCalcConfig, String operName);
int updatePointCalcConfig(EmsPointCalcConfig pointCalcConfig, String operName);
int deletePointCalcConfigByIds(Long[] ids);
int deleteBySiteId(String siteId);
}

Some files were not shown because too many files have changed in this diff Show More