瀏覽代碼

Merge branch 'master' of http://git.jiayuepowertech.com:9022/xusl/focus

wanghc 3 年之前
父節點
當前提交
61b94647db
共有 14 個文件被更改,包括 1177 次插入3 次删除
  1. 35 0
      ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/entity/PowerLimitPlanSign.java
  2. 1 1
      ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/repository/OverhaulPlanRepository.java
  3. 18 0
      ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/repository/PowerLimitPlanSignRepository.java
  4. 1 0
      ipfcst-console/src/main/java/com/jiayue/ipfcst/ConsoleApplication.java
  5. 12 0
      ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/OverHaulPlanService.java
  6. 600 0
      ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/PowerStationDataPacker.java
  7. 50 0
      ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/PowerStationDataPackerContainer.java
  8. 0 2
      ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/WindTurbineInfoService.java
  9. 91 0
      ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/powerofreference/BasePowerOfReferenceCalculator.java
  10. 156 0
      ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/powerofreference/iml/PowerOfReferenceCalculator1.java
  11. 65 0
      ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/powerofreference/iml/PowerOfReferenceCalculator2.java
  12. 5 0
      ipfcst-console/src/main/java/com/jiayue/ipfcst/console/util/RedisUtils.java
  13. 87 0
      ipfcst-console/src/test/java/com/jiayue/ipfcst/console/service/PowerStationDataTest.java
  14. 56 0
      ipfcst-console/velocity.log

+ 35 - 0
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/entity/PowerLimitPlanSign.java

@@ -0,0 +1,35 @@
+package com.jiayue.ipfcst.common.data.entity;
+
+import lombok.Data;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * 限电计划标识
+ *
+ * @author xls
+ * @version 3.0
+ */
+@Data
+@Entity
+public class PowerLimitPlanSign implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO, generator = "myid")
+    @GenericGenerator(name = "myid", strategy = "com.jiayue.ipfcst.common.data.entity.id.CustomIDGenerator")
+    @Column
+    private Integer id;
+
+    /*是否限电 1.限电 0.不限电*/
+    @Column
+    private Integer sign;
+
+    @Column
+    private  String stationCode;
+}

+ 1 - 1
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/repository/OverhaulPlanRepository.java

@@ -23,7 +23,7 @@ public interface OverhaulPlanRepository extends BaseRepository<OverhaulPlan, Int
 
     List<OverhaulPlan> findByEndTimeGreaterThanEqualAndStartTimeLessThanEqualAndStatusAndStationCode(Long stTime, Long eTime, Integer status, String stationCode);
 
-    List<OverhaulPlan> findByStartTimeLessThanAndEndTimeGreaterThanAndStatus(Long startTime, Long endTime, Integer status);
+    List<OverhaulPlan> findByStartTimeLessThanAndEndTimeGreaterThanAndStatusAndStationCode(Long startTime, Long endTime, Integer status,String stationCode);
 
     List<OverhaulPlan> findByEndTimeAfterAndStatus(Long time, Integer status);
 

+ 18 - 0
ipfcst-common/ipfcst-common-data/src/main/java/com/jiayue/ipfcst/common/data/repository/PowerLimitPlanSignRepository.java

@@ -0,0 +1,18 @@
+package com.jiayue.ipfcst.common.data.repository;
+
+
+import com.jiayue.ipfcst.common.data.entity.PowerLimitPlanSign;
+
+import java.util.List;
+
+/**
+ * 限电标识设置仓储
+ *
+ * @author xsl
+ * @version 3.0
+ */
+public interface PowerLimitPlanSignRepository extends BaseRepository<PowerLimitPlanSign, Integer> {
+
+
+     List<PowerLimitPlanSign> findAllByStationCode(String stationCode);
+}

+ 1 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/ConsoleApplication.java

@@ -51,6 +51,7 @@ public class ConsoleApplication {
       ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);
         //变更配置文件读取位置启动
         new SpringApplicationBuilder(ConsoleApplication.class).run(args);
+
     }
 
     /**

+ 12 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/OverHaulPlanService.java

@@ -10,6 +10,7 @@ import org.springframework.data.domain.*;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
@@ -102,6 +103,17 @@ public class OverHaulPlanService {
 
   }
 
+
+  public BigDecimal getOverhaulCapacityByStationCode(String stationCode){
+      BigDecimal overhaulCapacity = new BigDecimal(0);
+      long time = System.currentTimeMillis();
+      List<OverhaulPlan> overhaulPlans = overhaulPlanRepository.findByStartTimeLessThanAndEndTimeGreaterThanAndStatusAndStationCode(time, time, 1,stationCode);
+      if(overhaulPlans.size()>0){
+        overhaulCapacity = overhaulPlans.get(0).getOverhaulCapactity();
+      }
+      return overhaulCapacity;
+  }
+
   /**
    * 查询检修计划信息
    */

+ 600 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/PowerStationDataPacker.java

@@ -0,0 +1,600 @@
+package com.jiayue.ipfcst.console.service;
+
+import com.googlecode.aviator.AviatorEvaluator;
+import com.googlecode.aviator.Expression;
+import com.googlecode.aviator.Options;
+import com.googlecode.aviator.exception.ExpressionSyntaxErrorException;
+import com.jiayue.ipfcst.common.core.util.DateMomentUtil;
+import com.jiayue.ipfcst.common.core.util.SpringContextHolder;
+import com.jiayue.ipfcst.common.core.util.SunRiseSet;
+import com.jiayue.ipfcst.common.data.abst.equipmentstatus.AbstractEquipmentStatusData;
+import com.jiayue.ipfcst.common.data.constant.enums.ElectricFieldTypeEnum;
+import com.jiayue.ipfcst.common.data.entity.*;
+import com.jiayue.ipfcst.console.service.powerofreference.BasePowerOfReferenceCalculator;
+import com.jiayue.ipfcst.console.service.powerofreference.iml.PowerOfReferenceCalculator1;
+import com.jiayue.ipfcst.console.service.powerofreference.iml.PowerOfReferenceCalculator2;
+import com.jiayue.ipfcst.console.util.RedisUtils;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.joda.time.DateTime;
+import org.joda.time.LocalTime;
+
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+
+/**
+ * 有关功率的审计和计算类
+ * <p>
+ * 用于计算功率是否合理 返回合理值
+ * <p>
+ * 计算理论功率和可用功率
+ * <p>
+ * 非主动计算 需被动调用  计算
+ *
+ * @author 修唯xiuwei
+ * @version 3.0
+ */
+@Slf4j
+public class PowerStationDataPacker {
+
+  public PowerStationDataPacker(ElectricField electricField) {
+    this.electricField = electricField;
+  }
+
+  /**
+   * 参照功率的计算方式标识
+   * 理论功率计算方式
+   */
+  private static final String LGJSFS = "lgjsfs";
+
+
+  /**
+   * 判断是否限电的容量倍率 标识
+   * 处在 容量*该倍率之下的实际功率 不统计是否限电
+   */
+  private static final String SFPDXD = "sfpdxd";
+
+
+  /**
+   * 限电系数 标识
+   * 如果  参照功率 - 实际功率 > 实际功率*该系数  则判断为限电
+   */
+  private static final String XDXS = "xdxs";
+
+
+  /**
+   * 短期和超短期平均数计算可用功率所乘 系数最小值
+   */
+  private static final String KYGLJSMIN = "kygljsMIN";
+
+
+  /**
+   * 短期和超短期平均数计算可用功率所乘 系数最大值
+   */
+  private static final String KYGLJSMAX = "kygljsMAX";
+
+  /**
+   * 样板机计算方式 标识
+   */
+  private static final String YBJSF = "ybjsf";
+
+
+  /**
+   * 理论功率公式
+   */
+  private static final String LLGLGS = "kyglgs";
+
+
+  /**
+   * 随机数生成器
+   */
+  private static final Random random = new Random();
+
+
+  /**
+   * 样板机计算参照功率
+   */
+  BasePowerOfReferenceCalculator powerOfReferenceCalculatorBySample;
+
+  /**
+   * 场站状态数据实体域
+   */
+  List<Field> fields = new ArrayList<>();
+  @Setter
+  @Getter
+  private PowerStationStatusData t = new PowerStationStatusData();
+  /**
+   * 场站信息
+   */
+  private final ElectricField electricField;
+  /**
+   * 测风/光法 的公式计算器
+   */
+  private CalculatorOfMeasuring calculatorOfMeasuring;
+
+  /**
+   * 实际功率是否需要审核的标志 默认不审核
+   */
+  private static final Boolean AUDIT_REAL_POWER = false;
+
+
+  /**
+   * 日升时刻
+   */
+  private DateTime sunUpTime;
+  /**
+   * 日落时刻
+   */
+  private DateTime sunDownTime;
+
+  /**
+   * 系统配置变量获取类
+   */
+  SysParameterService sysParameterService = SpringContextHolder.getBean(SysParameterService.class);
+
+  /**
+   * 查询检修信息
+   */
+  OverHaulPlanService overHaulPlanService = SpringContextHolder.getBean(OverHaulPlanService.class);
+
+  /**
+   * 获取短期
+   */
+  ForecastPowerShortTermService forecastPowerShortTermService = SpringContextHolder.getBean(ForecastPowerShortTermService.class);
+  /**
+   * 获取超短期
+   */
+
+  ForecastPowerUltraShortTermService forecastPowerUltraShortTermService = SpringContextHolder.getBean(ForecastPowerUltraShortTermService.class);
+
+
+  /**
+   * redis 工具
+   */
+  private final RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class);
+
+
+  /**
+   * 对实际功率合理性进行审核 查看实际功率的合理性
+   *
+   * @param power 功率
+   * @return 更改后的值 double
+   */
+  public BigDecimal realPowerRationalityAuditor(BigDecimal power) {
+    DateTime time = DateTime.now();
+    if (electricField != null && electricField.getCapacity() != null && power.compareTo(electricField.getCapacity()) > 0) {
+      //当实际功率超过场站的容量时  返回容量
+      power = electricField.getCapacity();
+      if (power.compareTo(BigDecimal.ZERO) < 0) {
+        power = BigDecimal.ZERO;
+      }
+    }
+    //对日升和日落各宽恕30min  如果在日升前30min到 日落后30min 之间
+    //如果时间处于日出前30分钟    日落后30分钟   则判定功率为0
+    if (electricField != null && ElectricFieldTypeEnum.E1.equals(electricField.getElectricFieldTypeEnum())) {
+      if (time.isBefore(getSunUpTime().minusMillis(30)) || time.isAfter(getSunDownTime().plusMillis(30))) {
+        power = BigDecimal.ZERO;
+      }
+    }
+    return power;
+  }
+
+
+  /**
+   * 获取参照功率
+   * lgjsfs  理论功率计算方式
+   *
+   * @return 参照功率的计算结果
+   */
+  private BigDecimal getPowerOfReference(PowerStationStatusData powerStationStatusData) {
+    String lgjsfs = sysParameterService.getSysParameter(LGJSFS, "0", electricField.getStationCode());
+    switch (lgjsfs) {
+      case "1":
+        log.info("使用样板机方式计算参考值");
+        if (powerStationStatusData.getReferencePowerBySample() != null) {
+          return powerStationStatusData.getReferencePowerBySample().multiply(getOpenRatio());
+        } else {
+          log.info("样板机方式计算参考值为空返回倍率计算方式");
+        }
+      case "2":
+        log.info("使用测风/光法方式计算参考值");
+        if (powerStationStatusData.getReferencePowerByMeasuring() != null) {
+          return powerStationStatusData.getReferencePowerByMeasuring().multiply(getOpenRatio());
+        } else {
+          log.info("测风/光法方式计算参考值为空返回倍率计算方式");
+        }
+      default:
+    }
+    log.info("不判断限电,直接判断不限电");
+    return BigDecimal.valueOf(-99);
+  }
+
+
+  /**
+   * 根据实际功率是否需要审核  返回实际功率
+   *
+   * @return 实际功率数值
+   */
+  @SneakyThrows
+  public BigDecimal getRealPowerVal(BigDecimal realPower) {
+    if (realPower == null) {
+      return BigDecimal.valueOf(-99D);
+    }
+    if (AUDIT_REAL_POWER) {
+      return realPowerRationalityAuditor(realPower);
+    } else {
+      BigDecimal power = realPower;
+      if (power.compareTo(BigDecimal.ZERO) < 0) {
+        power = BigDecimal.ZERO;
+      }
+      return power;
+    }
+
+  }
+
+
+  /**
+   * 初始化
+   * 初始化计算器
+   * 1.确定场站类别
+   * 2.初始化各种map等
+   *
+   * @return 工具包装器本身
+   */
+  public PowerStationDataPacker init() {
+    //初始化实体域集合
+    initEntityFields();
+    //初始化测风光法计算器
+    initCalculatorOfMeasuring();
+    //初始化样板机法计算公式
+    initReferenceCalculator();
+    return this;
+  }
+
+  /**
+   * 初始化实体域集合
+   */
+  private void initEntityFields() {
+    fields.addAll(Arrays.asList(t.getClass().getDeclaredFields()));
+    fields.addAll(Arrays.asList(AbstractEquipmentStatusData.class.getDeclaredFields()));
+    for (Field f : fields) {
+      f.setAccessible(true);
+    }
+  }
+
+  /**
+   * 初始化样板机功率系数计算器
+   */
+  private void initReferenceCalculator() {
+    if ("1".equals(sysParameterService.getSysParameter(YBJSF, "1", electricField.getStationCode()))) {
+      this.powerOfReferenceCalculatorBySample = new PowerOfReferenceCalculator1(electricField).init();
+    } else {
+      this.powerOfReferenceCalculatorBySample = new PowerOfReferenceCalculator2(electricField).init();
+    }
+  }
+
+
+  /**
+   * 判断是否限电
+   *
+   * @param powerStationStatusData 场站状态数据
+   * @return 限电?  true: 限电 ; false :不限电
+   */
+  public boolean judgeIsRationing(PowerStationStatusData powerStationStatusData) {
+    //底线功率
+    BigDecimal baseLinePower = electricField.getCapacity().multiply(new BigDecimal(sysParameterService.getSysParameter(SFPDXD, "1", electricField.getStationCode())));
+    BigDecimal coefficient = new BigDecimal(sysParameterService.getSysParameter(XDXS, "0.2", electricField.getStationCode())).add(BigDecimal.valueOf(1));
+    BigDecimal referencePower = this.getPowerOfReference(powerStationStatusData);
+    if (powerStationStatusData.getRealValue().compareTo(baseLinePower) < 0) {
+      //实际功率 小于容量的 n%  不统计是否限电  全部视为不限电
+      return false;
+    } else {
+      //参照功率 - 实际功率 > 实际功率 * 限电系数  ??  大于就限电 小于就不限电
+      return referencePower.compareTo(powerStationStatusData.getRealValue().multiply(coefficient)) > 0;
+    }
+  }
+
+
+  /**
+   * 初始化测风光法计算器
+   */
+  private void initCalculatorOfMeasuring() {
+    this.calculatorOfMeasuring = null;
+  }
+
+  /**
+   * 获取当下时间段的 短期功率和超短期功率的平均数
+   *
+   * @return 平均数
+   */
+  @SneakyThrows
+  private BigDecimal getForecastPowerAvg() {
+    long nowQuarterTime = DateMomentUtil.getMomentTime(System.currentTimeMillis(), 1, 900000L);
+    BigDecimal dq = BigDecimal.valueOf(0);
+    BigDecimal cdq = BigDecimal.valueOf(0);
+    BigDecimal val;
+    //获取当前的短期
+    List<ForecastPowerShortTermHis> forecastPowerShortTermHisList = forecastPowerShortTermService.getForecastPowerShortTerm(nowQuarterTime, nowQuarterTime, electricField.getStationCode());
+    if (null != forecastPowerShortTermHisList && forecastPowerShortTermHisList.size() > 0) {
+      dq = forecastPowerShortTermHisList.get(0).getAbleValue();
+    }
+    //获取当前时刻超短期
+    List<ForecastPowerUltraShortTermHis> forecastPowerUltraShortTermHisList = forecastPowerUltraShortTermService.getForecastPowerUltraShortTerm(nowQuarterTime, nowQuarterTime, electricField.getStationCode());
+    if (null != forecastPowerUltraShortTermHisList && forecastPowerUltraShortTermHisList.size() > 0) {
+      cdq = forecastPowerUltraShortTermHisList.get(0).getAbleValue();
+    }
+    val = (dq.add(cdq)).divide(new BigDecimal(2), 2, RoundingMode.HALF_DOWN);
+    return val;
+  }
+
+  /**
+   * 组装场站数据实体
+   *
+   * @param realPower 实际功率
+   * @return {@link PowerStationStatusData}
+   */
+  public PowerStationStatusData packageData(BigDecimal realPower) {
+    PowerStationStatusData powerStationStatusData = new PowerStationStatusData();
+    try {
+      //设定时间
+      powerStationStatusData.setTime(DateTime.now().withMillisOfSecond(0).withSecondOfMinute(0).toDate());
+      //设定容量
+      powerStationStatusData.setCapacity(electricField.getCapacity());
+      //设定并网设备数
+      powerStationStatusData.setOnGridNum(electricField.getGridCE());
+      //设定开机容量为装机容量
+      powerStationStatusData.setOpenCapacity(electricField.getCapacity().subtract(overHaulPlanService.getOverhaulCapacityByStationCode(electricField.getStationCode())));
+      //设定场站状态
+      powerStationStatusData.setStatus(electricField.getElectricFieldTypeEnum().getCode());
+      //设定实际功率
+      powerStationStatusData.setRealValue(getRealPowerVal(realPower));
+      //设定 样板机参照功率
+      powerStationStatusData.setReferencePowerBySample(powerOfReferenceCalculatorBySample.getEstimatePower());
+      if (powerStationStatusData.getReferencePowerBySample() == null || powerStationStatusData.getReferencePowerBySample().compareTo(powerStationStatusData.getRealValue()) < 0) {
+        log.warn("样板机法计算值小于实际功率异常,值为:" + powerStationStatusData.getReferencePowerBySample());
+        powerStationStatusData.setAbnormalOfSample(powerStationStatusData.getReferencePowerBySample());
+        powerStationStatusData.setReferencePowerBySample(((electricField.getCapacity().subtract(powerStationStatusData.getRealValue())).multiply(BigDecimal.valueOf(random.nextFloat())).multiply(BigDecimal.valueOf(0.001))).add(powerStationStatusData.getRealValue()).setScale(2, RoundingMode.HALF_UP));
+      } else if (powerStationStatusData.getReferencePowerBySample().compareTo(powerStationStatusData.getCapacity()) > 0) {
+        log.warn("样板机法计算值超装机容量异常,值为:" + powerStationStatusData.getReferencePowerBySample());
+        powerStationStatusData.setAbnormalOfSample(powerStationStatusData.getReferencePowerBySample());
+        powerStationStatusData.setReferencePowerBySample(powerStationStatusData.getCapacity());
+      }
+      powerStationStatusData.setAblePowerBySample(powerOfReferenceCalculatorBySample.getEstimatePower().multiply(getOpenRatio()).setScale(2, RoundingMode.HALF_UP));
+      if (powerStationStatusData.getAblePowerBySample().compareTo(powerStationStatusData.getRealValue()) < 0) {
+        powerStationStatusData.setAblePowerBySample(powerStationStatusData.getReferencePowerBySample());
+      }
+      //设定 测风光法参照功率
+      if (this.calculatorOfMeasuring != null) {
+        powerStationStatusData.setReferencePowerByMeasuring(this.calculatorOfMeasuring.getData().setScale(2, RoundingMode.HALF_UP));
+      }
+      if (powerStationStatusData.getReferencePowerByMeasuring() == null || powerStationStatusData.getReferencePowerByMeasuring().compareTo(powerStationStatusData.getRealValue()) < 0) {
+        log.warn("测风光法计算值小于实际功率异常,值为:" + powerStationStatusData.getReferencePowerByMeasuring());
+        powerStationStatusData.setAbnormalOfMeasuring(powerStationStatusData.getReferencePowerByMeasuring());
+        powerStationStatusData.setReferencePowerByMeasuring(((electricField.getCapacity().subtract(powerStationStatusData.getRealValue())).multiply(BigDecimal.valueOf(random.nextFloat())).multiply(BigDecimal.valueOf(0.001))).add(powerStationStatusData.getRealValue()).setScale(2, RoundingMode.HALF_UP));
+      } else if (powerStationStatusData.getReferencePowerByMeasuring().compareTo(powerStationStatusData.getCapacity()) > 0) {
+        log.warn("测风光法计算值超装机容量异常,值为:" + powerStationStatusData.getReferencePowerByMeasuring());
+        powerStationStatusData.setAbnormalOfMeasuring(powerStationStatusData.getReferencePowerByMeasuring());
+        powerStationStatusData.setReferencePowerByMeasuring(powerStationStatusData.getCapacity());
+      }
+      powerStationStatusData.setAblePowerByMeasuring(powerStationStatusData.getReferencePowerByMeasuring().multiply(getOpenRatio()).setScale(2, RoundingMode.HALF_UP));
+      if (powerStationStatusData.getAblePowerByMeasuring().compareTo(powerStationStatusData.getRealValue()) < 0) {
+        powerStationStatusData.setAblePowerByMeasuring(powerStationStatusData.getReferencePowerByMeasuring());
+      }
+      boolean isRationing = judgeIsRationing(powerStationStatusData);
+      //设定是否限电
+      powerStationStatusData.setIsRationingByAutoControl(isRationing);
+
+      //设定理论和可用
+      if (isRationing) {
+        //限电情况下  平均功率和实际功率取大者 乘倍率
+        switch (sysParameterService.getSysParameter("kyglqz", "1", electricField.getStationCode())) {
+          case "2":
+            powerStationStatusData.setAbleValue(powerStationStatusData.getReferencePowerBySample().multiply(getOpenRatio()).setScale(2, RoundingMode.HALF_DOWN));
+            break;
+          case "3":
+            powerStationStatusData.setAbleValue(powerStationStatusData.getReferencePowerByMeasuring().multiply(getOpenRatio()).setScale(2, RoundingMode.HALF_DOWN));
+            break;
+          default: {
+            BigDecimal avgPower = getForecastPowerAvg();
+            BigDecimal randomNum = getRandomNum(new BigDecimal(sysParameterService.getSysParameter(KYGLJSMIN, "1", electricField.getStationCode())), new BigDecimal(sysParameterService.getSysParameter(KYGLJSMAX, "1.02", electricField.getStationCode())));
+            if (avgPower.compareTo(powerStationStatusData.getRealValue()) > 0) {
+              powerStationStatusData.setAbleValue(avgPower.multiply(randomNum).setScale(2, RoundingMode.HALF_UP));
+            } else {
+              powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue().multiply(randomNum).setScale(2, RoundingMode.HALF_UP));
+            }
+          }
+        }
+      } else {
+        //不限电 实际功率,理论功率,可用功率  理论=k*可用=k*实际
+        powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue().multiply(BigDecimal.ONE.add(getMagnificationK())).setScale(2, RoundingMode.HALF_DOWN));
+      }
+
+      if (powerStationStatusData.getOpenCapacity().compareTo(new BigDecimal(0)) != 0) {
+        //设置理论功率
+        powerStationStatusData.setTheoryValue(powerStationStatusData.getAbleValue().multiply(BigDecimal.ONE.add(getMagnificationK())).add(overHaulPlanService.getOverhaulCapacityByStationCode(electricField.getStationCode()).multiply(powerStationStatusData.getRealValue().divide(powerStationStatusData.getOpenCapacity(), RoundingMode.CEILING))).setScale(2, RoundingMode.HALF_DOWN));
+      } else {
+        powerStationStatusData.setTheoryValue(new BigDecimal(0));
+      }
+      //设置站内受阻
+      powerStationStatusData.setOnSiteObstructed(powerStationStatusData.getTheoryValue().subtract(powerStationStatusData.getAbleValue()));
+      //设置站外受阻
+      powerStationStatusData.setOffSiteObstructed(powerStationStatusData.getAbleValue().subtract(powerStationStatusData.getRealValue()));
+    } catch (Exception e) {
+      log.error("组装场站状态数据时发生异常", e);
+      throw new RuntimeException("组装场站状态数据时发生异常");
+    }
+
+    if (powerStationStatusData.getAbleValue().compareTo(BigDecimal.valueOf(-99)) == 0) {
+      powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue());
+      powerStationStatusData.setTheoryValue(powerStationStatusData.getAbleValue());
+    } else {
+      if (powerStationStatusData.getAbleValue().compareTo(powerStationStatusData.getRealValue()) < 0) {
+        powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue().multiply(getMagnificationK().add(BigDecimal.ONE)).setScale(2, RoundingMode.HALF_DOWN));
+      }
+      if (powerStationStatusData.getTheoryValue().compareTo(powerStationStatusData.getAbleValue()) < 0) {
+        powerStationStatusData.setTheoryValue(powerStationStatusData.getAbleValue().multiply(getMagnificationK().add(BigDecimal.ONE)).setScale(2, RoundingMode.HALF_DOWN));
+      }
+    }
+    return powerStationStatusData;
+  }
+
+
+  /**
+   * 得到随机num
+   *
+   * @param min 最小值
+   * @param max 最大值
+   * @return {@link BigDecimal}
+   */
+  public BigDecimal getRandomNum(BigDecimal min, BigDecimal max) {
+    return BigDecimal.valueOf(random.nextDouble()).multiply(max.subtract(min)).add(min).setScale(2, RoundingMode.HALF_DOWN);
+  }
+
+
+  /**
+   * 获取当前时间开机容量比 即开机容量和装机容量的比值
+   */
+  public BigDecimal getOpenRatio() {
+    return BigDecimal.ONE.subtract(overHaulPlanService.getOverhaulCapacityByStationCode(electricField.getStationCode()).divide(electricField.getCapacity(), 2, RoundingMode.HALF_DOWN));
+  }
+
+  /**
+   * 获取0.015 - 0.02 的随机数
+   *
+   * @return {@link BigDecimal}
+   */
+  public BigDecimal getMagnificationK() {
+    return getRandomNum(BigDecimal.valueOf(0.015), BigDecimal.valueOf(0.02));
+  }
+
+
+  public DateTime getSunUpTime() {
+    updateTodaySunRiseSetTime();
+    return this.sunUpTime;
+  }
+
+  public DateTime getSunDownTime() {
+    updateTodaySunRiseSetTime();
+    return this.sunDownTime;
+  }
+
+  /**
+   * 刷新今天日出日落时间
+   * 由于日升日落 要求精度不是很高 而且预测的数据也比较准确
+   */
+  public void updateTodaySunRiseSetTime() {
+    if (sunUpTime == null || sunUpTime.isBefore(DateTime.now().withMillisOfDay(0))) {
+      Date date = DateTime.now().toDate();
+      String sunRiseTimeString = SunRiseSet.getSunrise(electricField.getLongitude(), electricField.getLatitude(), date);
+      String sunSetTimeString = SunRiseSet.getSunset(electricField.getLongitude(), electricField.getLatitude(), date);
+      if (StringUtils.isNotEmpty(sunRiseTimeString)) {
+        try {
+          sunUpTime = LocalTime.parse(sunRiseTimeString).toDateTimeToday();
+        } catch (Exception e) {
+          sunUpTime = null;
+        }
+      }
+      if (StringUtils.isNotEmpty(sunSetTimeString)) {
+        try {
+          this.sunDownTime = LocalTime.parse(sunSetTimeString).toDateTimeToday();
+        } catch (Exception e) {
+          this.sunDownTime = null;
+        }
+      }
+    }
+  }
+
+
+  class CalculatorOfMeasuring {
+
+    /**
+     * 正式的
+     */
+    public String formula;
+
+
+    /**
+     * 用于替换公式的值
+     */
+    public Map<String, Object> dataMap = new HashMap<>();
+
+    /**
+     * 原始数据池
+     */
+    Map<String, String> oDataMap = new HashMap<>();
+
+
+    /**
+     * 气象站或测风塔的编号
+     */
+    public Integer equipmentNo;
+
+
+    /**
+     * 计算表达式
+     */
+    Expression compiledExp;
+
+    /**
+     * 初始化
+     *//* 光伏组件效率*(1-0.003*(光伏组件温度-25))*math.pow(0.992,3)*总辐射*光伏组件总面积/1000000*0.79*/
+    public void init() throws Exception {
+      AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, true);
+      this.formula = sysParameterService.getSysParameter(LLGLGS, "", electricField.getStationCode());
+      try {
+        this.compiledExp = AviatorEvaluator.compile(formula);
+      } catch (ExpressionSyntaxErrorException e) {
+        log.error("公式解析失败,公式不可用", e);
+        throw new RuntimeException("公式解析失败,公式不可用");
+      }
+      if (electricField.getElectricFieldTypeEnum() == ElectricFieldTypeEnum.E1) {
+        WeatherStationInfoService weatherStationInfoService = SpringContextHolder.getBean(WeatherStationInfoService.class);
+        List<WeatherStationInfo> l = weatherStationInfoService.getAll();
+        if (l.size() >= 1) {
+          this.equipmentNo = l.get(0).getId();
+        } else {
+          throw new Exception("系统缺少气象站信息");
+        }
+      } else {
+        WindTowerInfoService windTowerInfoService = SpringContextHolder.getBean(WindTowerInfoService.class);
+        List<WindTowerInfo> l = windTowerInfoService.getAll();
+        if (l.size() >= 1) {
+          this.equipmentNo = l.get(0).getId();
+        } else {
+          throw new Exception("系统缺少测风塔信息");
+        }
+      }
+    }
+
+    public void updateDates() {
+      if (electricField.getElectricFieldTypeEnum() == ElectricFieldTypeEnum.E1) {
+        //光伏
+        oDataMap = redisUtils.hgetall("qxz-" + electricField.getStationCode() + "-" + equipmentNo);
+        if (oDataMap.containsKey("cellT")) {
+          dataMap.put("光伏组件温度", new BigDecimal(oDataMap.get("cellT")));
+        }
+        if (oDataMap.containsKey("globalR")) {
+          dataMap.put("总辐射", new BigDecimal(oDataMap.get("globalR")));
+        }
+      } else {
+        oDataMap = redisUtils.hgetall("cft-" + electricField.getStationCode() + "-" + equipmentNo);
+        if (oDataMap.containsKey("wsInstHubHeight")) {
+          dataMap.put("轮毂风速", new BigDecimal(oDataMap.get("wsInstHubHeight")));
+        }
+      }
+    }
+
+
+    BigDecimal getData() {
+      return new BigDecimal(compiledExp.execute(dataMap) + "");
+    }
+  }
+}
+
+
+

+ 50 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/PowerStationDataPackerContainer.java

@@ -0,0 +1,50 @@
+package com.jiayue.ipfcst.console.service;
+
+import com.jiayue.ipfcst.common.data.entity.ElectricField;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 注入样板机法的配置类
+ *
+ * @author 修唯xiuwei
+ *
+ */
+@DependsOn("springContextHolder")
+@Service
+public class PowerStationDataPackerContainer {
+
+  @Autowired
+  protected ElectricFieldService electricFieldService;
+
+
+
+  /**
+   * 查询场站信息
+   */
+  Map<String, PowerStationDataPacker> powerStationDataPackerMap = new HashMap<>();
+
+
+  /**
+   * 初始化
+   */
+  @PostConstruct
+  public void init() {
+    List<ElectricField> l = electricFieldService.getAll();
+    for (ElectricField e : l) {
+      powerStationDataPackerMap.put(e.getStationCode(), new PowerStationDataPacker(e).init());
+    }
+  }
+
+  public PowerStationDataPacker getDataPacker(String stationCode) {
+    return this.powerStationDataPackerMap.getOrDefault(stationCode, null);
+  }
+
+
+}

+ 0 - 2
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/WindTurbineInfoService.java

@@ -1,8 +1,6 @@
 package com.jiayue.ipfcst.console.service;
 
 import com.jiayue.ipfcst.common.core.exception.BusinessException;
-import com.jiayue.ipfcst.common.data.entity.InverterInfo;
-import com.jiayue.ipfcst.common.data.entity.WindTowerInfo;
 import com.jiayue.ipfcst.common.data.entity.WindTurbineInfo;
 import com.jiayue.ipfcst.common.data.repository.WindTurbineInfoRepository;
 import com.jiayue.ipfcst.common.data.service.BaseService;

+ 91 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/powerofreference/BasePowerOfReferenceCalculator.java

@@ -0,0 +1,91 @@
+package com.jiayue.ipfcst.console.service.powerofreference;
+
+
+import com.jiayue.ipfcst.common.core.util.SpringContextHolder;
+import com.jiayue.ipfcst.common.data.constant.enums.ElectricFieldTypeEnum;
+import com.jiayue.ipfcst.common.data.entity.ElectricField;
+import com.jiayue.ipfcst.console.service.ElectricFieldService;
+import com.jiayue.ipfcst.console.service.InverterInfoService;
+import com.jiayue.ipfcst.console.service.WindTurbineInfoService;
+import com.jiayue.ipfcst.console.util.RedisUtils;
+import org.springframework.stereotype.Component;
+import java.math.BigDecimal;
+
+/**
+ * 样板机的发电比例法计算 判断参照功率
+ *
+ * @author: xiuwei
+ * @version: 3.0
+ */
+public abstract class BasePowerOfReferenceCalculator {
+
+
+  /**
+   * 风机
+   */
+  private static final  String FJ="FJ";
+  /**
+   * 逆变器
+   */
+  private static final  String NBQ="NBQ";
+
+
+  /**
+   * 风机信息的查询 方便推算样板机数据
+   */
+  protected WindTurbineInfoService windTurbineInfoService = SpringContextHolder.getBean(WindTurbineInfoService.class);
+
+  /**
+   * 逆变器信息查询
+   */
+  protected InverterInfoService inverterInfoService = SpringContextHolder.getBean(InverterInfoService.class);
+
+  /**
+   * Redis 操作
+   */
+  protected RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class);
+
+  /**
+   * 查询场站信息
+   */
+  protected ElectricField electricField;
+
+
+
+  /**
+   * 场站类型
+   */
+  protected ElectricFieldTypeEnum electricFieldType;
+
+  public BasePowerOfReferenceCalculator(ElectricField electricField) {
+    this.electricField = electricField;
+  }
+
+  /**
+   * 获取预计理论的发电功率
+   *
+   * @return 预计的功率
+   */
+  public abstract BigDecimal getEstimatePower();
+
+  /**
+   * 初始化 或者重新初始化该类
+   *
+   * @return 预计的功率
+   */
+  public abstract BasePowerOfReferenceCalculator init();
+
+
+  protected BigDecimal getPowerOfEquipment(Integer equipmentId){
+    String e;
+    if(electricField.getElectricFieldTypeEnum()==ElectricFieldTypeEnum.E2){
+      e=FJ;
+    }else{
+      e=NBQ;
+    }
+    e=redisUtils.hget(e+"-"+electricField.getStationCode()+"-"+equipmentId,"activePower");
+    return new BigDecimal(e);
+  }
+
+}
+

+ 156 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/powerofreference/iml/PowerOfReferenceCalculator1.java

@@ -0,0 +1,156 @@
+package com.jiayue.ipfcst.console.service.powerofreference.iml;
+
+
+import com.jiayue.ipfcst.common.data.constant.enums.ElectricFieldTypeEnum;
+import com.jiayue.ipfcst.common.data.entity.ElectricField;
+import com.jiayue.ipfcst.common.data.entity.InverterInfo;
+import com.jiayue.ipfcst.common.data.entity.WindTurbineInfo;
+import com.jiayue.ipfcst.console.service.InverterInfoService;
+import com.jiayue.ipfcst.console.service.WindTurbineInfoService;
+import com.jiayue.ipfcst.console.service.powerofreference.BasePowerOfReferenceCalculator;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 样板机的发电比例法计算     判断参照功率
+ *
+ *
+ * @author: xiuwei
+ * @version: 3.0
+ */
+@Setter
+@Slf4j
+public class PowerOfReferenceCalculator1 extends BasePowerOfReferenceCalculator {
+
+
+  /**
+   * 场站的总运行容量
+   */
+  BigDecimal stationTotalCapacity;
+
+
+  /**
+   * 样板机信息
+   */
+  List<SampleEquipment> samples = new ArrayList<>();
+
+  public PowerOfReferenceCalculator1( ElectricField electricField) {
+    super( electricField);
+  }
+
+
+  /**
+   * 获取预计的发电功率
+   *
+   * @return 预计的功率
+   */
+  @Override
+  public BigDecimal getEstimatePower() {
+    BigDecimal avgRatio = BigDecimal.ZERO;
+    BigDecimal ratio;
+    try {
+
+      if (stationTotalCapacity != null && stationTotalCapacity.compareTo(BigDecimal.ZERO) != 0) {
+        for (SampleEquipment e : samples) {
+          ratio=e.updatePower().getSamplePowerGenerationRatio();
+          if(ratio.compareTo(BigDecimal.ONE)>0){
+            log.warn("样板机"+e.equipmentId+"发电量超装");
+          }
+          if(ratio.compareTo(BigDecimal.ZERO)>0){
+            avgRatio = avgRatio.add(ratio);
+          }
+        }
+      }
+      if (samples.size() == 0) {
+        return BigDecimal.ZERO;
+      }
+      avgRatio = avgRatio.divide(BigDecimal.valueOf(samples.size()), 10, RoundingMode.HALF_UP).multiply(stationTotalCapacity).setScale(2, RoundingMode.HALF_UP);
+
+    } catch (Exception e) {
+      log.error("计算样板机法理论功率数据时发生了异常" + e);
+    }
+    return avgRatio;
+  }
+
+  @SneakyThrows
+  @Override
+  public BasePowerOfReferenceCalculator init() {
+    this.electricFieldType = electricField.getElectricFieldTypeEnum();
+    this.stationTotalCapacity = electricField.getCapacity();
+    if (ElectricFieldTypeEnum.E1.equals(this.electricFieldType)) {
+      List<InverterInfo> inverterInfos = inverterInfoService.getAllSample();
+      for (InverterInfo i : inverterInfos) {
+        this.samples.add(new SampleEquipment(i.getId(),i.getCapacity()));
+      }
+    } else if (ElectricFieldTypeEnum.E2.equals(this.electricFieldType)) {
+      List<WindTurbineInfo> windTurbineInfos = windTurbineInfoService.getAllSample();
+      for (WindTurbineInfo i : windTurbineInfos) {
+        this.samples.add(new SampleEquipment(i.getId(),BigDecimal.valueOf(i.getMaxPower())));
+      }
+    }
+    return this;
+  }
+
+  /**
+   * 样板机信息
+   */
+  @Setter
+  @NoArgsConstructor
+  class SampleEquipment {
+    /**
+     * 设备ID
+     */
+    int equipmentId;
+    /**
+     * 设备实际功率
+     */
+    BigDecimal realPower;
+
+    /**
+     * 设备容量
+     */
+    BigDecimal capacity;
+
+
+    /**
+     * 样板机设备信息
+     *
+     * @param equipmentId 设备id
+     * @param capacity    容量
+     */
+    public SampleEquipment(int equipmentId,  BigDecimal capacity) {
+      this.equipmentId = equipmentId;
+      this.capacity = capacity;
+    }
+
+    /**
+     * 获取发电比例
+     *
+     * @return 发电比例
+     */
+    protected BigDecimal getSamplePowerGenerationRatio() {
+      return realPower.divide(capacity,2,BigDecimal.ROUND_HALF_UP);
+    }
+
+    /**
+     * 更新实际功率数据
+     *
+     * @return 实例本身
+     */
+    public SampleEquipment updatePower() {
+      this.realPower = getPowerOfEquipment(this.equipmentId);
+      return this;
+    }
+  }
+
+
+}
+
+

+ 65 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/service/powerofreference/iml/PowerOfReferenceCalculator2.java

@@ -0,0 +1,65 @@
+package com.jiayue.ipfcst.console.service.powerofreference.iml;
+
+import com.jiayue.ipfcst.common.data.constant.enums.ElectricFieldTypeEnum;
+import com.jiayue.ipfcst.common.data.entity.ElectricField;
+import com.jiayue.ipfcst.common.data.entity.InverterInfo;
+import com.jiayue.ipfcst.common.data.entity.WindTurbineInfo;
+import com.jiayue.ipfcst.console.service.InverterInfoService;
+import com.jiayue.ipfcst.console.service.WindTurbineInfoService;
+import com.jiayue.ipfcst.console.service.powerofreference.BasePowerOfReferenceCalculator;
+import lombok.SneakyThrows;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 每个样板机的平均功率*  风机或逆变器个数
+ *
+ * @author: xiuwei
+ * @version:
+ */
+public class PowerOfReferenceCalculator2 extends BasePowerOfReferenceCalculator {
+
+
+  Set<Integer> samples = new HashSet<>();
+
+
+  public PowerOfReferenceCalculator2( ElectricField electricField) {
+    super( electricField);
+  }
+
+
+  @SneakyThrows
+  @Override
+  public BigDecimal getEstimatePower() {
+    BigDecimal total = BigDecimal.valueOf(0);
+    if (samples.size() == 0) {
+      return total;
+    }
+    for (Integer i : samples) {
+      total = total.add(getPowerOfEquipment(i));
+    }
+    return total.divide(BigDecimal.valueOf(samples.size()),2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(electricField.getGridCE()));
+  }
+
+  @SneakyThrows
+  @Override
+  public BasePowerOfReferenceCalculator init() {
+    this.electricFieldType = electricField.getElectricFieldTypeEnum();
+    if (ElectricFieldTypeEnum.E1.equals(this.electricFieldType)) {
+      List<InverterInfo> inverterInfos = inverterInfoService.getAllSample();
+      for (InverterInfo i : inverterInfos) {
+        this.samples.add(i.getId());
+      }
+    } else if (ElectricFieldTypeEnum.E2.equals(this.electricFieldType)) {
+      List<WindTurbineInfo> windTurbineInfos = windTurbineInfoService.getAllSample();
+      for (WindTurbineInfo i : windTurbineInfos) {
+        this.samples.add(i.getId());
+      }
+    }
+    return this;
+  }
+}

+ 5 - 0
ipfcst-console/src/main/java/com/jiayue/ipfcst/console/util/RedisUtils.java

@@ -1,5 +1,6 @@
 package com.jiayue.ipfcst.console.util;
 
+import com.jiayue.ipfcst.common.data.abst.equipmentstatus.AbstractEquipmentStatusData;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import redis.clients.jedis.Jedis;
@@ -7,6 +8,8 @@ import redis.clients.jedis.JedisPool;
 import redis.clients.jedis.Pipeline;
 import redis.clients.jedis.Tuple;
 
+import java.lang.reflect.Field;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -16,6 +19,7 @@ import java.util.Set;
  */
 @Component
 public class RedisUtils {
+
   @Autowired
   private JedisPool jedisPool;
     /*
@@ -641,6 +645,7 @@ public class RedisUtils {
         }
     }
 
+
     /**
      * 取出某个hash表中任意多个key对应的value的集合
      *

+ 87 - 0
ipfcst-console/src/test/java/com/jiayue/ipfcst/console/service/PowerStationDataTest.java

@@ -0,0 +1,87 @@
+package com.jiayue.ipfcst.console.service;
+
+import com.alibaba.fastjson.JSON;
+import com.jiayue.ipfcst.BaseTest;
+import com.jiayue.ipfcst.common.data.abst.equipmentstatus.AbstractEquipmentStatusData;
+import com.jiayue.ipfcst.common.data.entity.PowerStationStatusData;
+import com.jiayue.ipfcst.common.data.entity.WindTurbineStatusData;
+import com.jiayue.ipfcst.console.util.RedisUtils;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.util.*;
+
+public class PowerStationDataTest extends BaseTest {
+
+
+  @Autowired
+  PowerStationDataPackerContainer powerStationDataPackerContainer;
+
+  @Autowired
+  RedisUtils redisUtils;
+
+
+  private final Random random = new Random();
+
+  @Test
+  public void packages() throws Exception {
+    for (; ; ) {
+      PowerStationStatusData a = powerStationDataPackerContainer.getDataPacker("J00001").packageData(BigDecimal.valueOf(20));
+      System.out.println(JSON.toJSONString(a));
+      Thread.sleep(20000L);
+    }
+  }
+
+  @Test
+  public void save() throws Exception {
+    WindTurbineStatusData data = new WindTurbineStatusData();
+    data.setStationCode("J00001");
+    data.setId(1);
+    data.setActivePower(BigDecimal.valueOf(random.nextFloat()).multiply(BigDecimal.valueOf(1000)));
+    saveEquipmentStatusData("FJ-" + data.getStationCode() + "-" + data.getId(), data);
+    data.setId(2);
+    data.setActivePower(BigDecimal.valueOf(random.nextFloat()).multiply(BigDecimal.valueOf(1000)));
+    saveEquipmentStatusData("FJ-" + data.getStationCode() + "-" + data.getId(), data);
+    data.setId(3);
+    data.setActivePower(BigDecimal.valueOf(random.nextFloat()).multiply(BigDecimal.valueOf(1000)));
+    saveEquipmentStatusData("FJ-" + data.getStationCode() + "-" + data.getId(), data);
+    data.setId(5);
+    data.setActivePower(BigDecimal.valueOf(random.nextFloat()).multiply(BigDecimal.valueOf(1000)));
+    saveEquipmentStatusData("FJ-" + data.getStationCode() + "-" + data.getId(), data);
+    data.setId(7);
+    data.setActivePower(BigDecimal.valueOf(random.nextFloat()).multiply(BigDecimal.valueOf(1000)));
+    saveEquipmentStatusData("FJ-" + data.getStationCode() + "-" + data.getId(), data);
+    data.setId(12);
+    data.setActivePower(BigDecimal.valueOf(random.nextFloat()).multiply(BigDecimal.valueOf(1000)));
+    saveEquipmentStatusData("FJ-" + data.getStationCode() + "-" + data.getId(), data);
+    data.setId(14);
+    data.setActivePower(BigDecimal.valueOf(random.nextFloat()).multiply(BigDecimal.valueOf(1000)));
+    saveEquipmentStatusData("FJ-" + data.getStationCode() + "-" + data.getId(), data);
+    data.setId(16);
+    data.setActivePower(BigDecimal.valueOf(random.nextFloat()).multiply(BigDecimal.valueOf(1000)));
+    saveEquipmentStatusData("FJ-" + data.getStationCode() + "-" + data.getId(), data);
+    data.setId(17);
+    data.setActivePower(BigDecimal.valueOf(random.nextFloat()).multiply(BigDecimal.valueOf(1000)));
+    saveEquipmentStatusData("FJ-" + data.getStationCode() + "-" + data.getId(), data);
+
+
+  }
+
+
+  public void saveEquipmentStatusData(String key, AbstractEquipmentStatusData equipmentStatusData) throws IllegalAccessException {
+    Field[] f1 = equipmentStatusData.getClass().getDeclaredFields();
+    Field[] f2 = AbstractEquipmentStatusData.class.getDeclaredFields();
+    List<Field> l = Arrays.asList(f1);
+    l.addAll(Arrays.asList(f2));
+    Map<String, String> m = new HashMap<>();
+    Object o;
+    for (Field f : l) {
+      f.setAccessible(true);
+      o = f.get(equipmentStatusData);
+      m.put(f.getName(), o.toString());
+    }
+    redisUtils.hmset(key, m);
+  }
+}

+ 56 - 0
ipfcst-console/velocity.log

@@ -127,3 +127,59 @@
 2021-08-31 22:13:08,399 - Null reference [template 'start-console.vm', line 25, column 19] : $app_path cannot be resolved.
 2021-08-31 22:13:08,399 - Null reference [template 'start-console.vm', line 25, column 49] : $start_app_log cannot be resolved.
 2021-08-31 22:13:08,399 - Null reference [template 'start-console.vm', line 28, column 44] : $app_path cannot be resolved.
+2021-10-13 11:31:53,047 - Log4JLogChute initialized using file 'velocity.log'
+2021-10-13 11:31:53,048 - Initializing Velocity, Calling init()...
+2021-10-13 11:31:53,048 - Starting Apache Velocity v1.7 (compiled: 2010-11-19 12:14:37)
+2021-10-13 11:31:53,048 - Default Properties File: org\apache\velocity\runtime\defaults\velocity.properties
+2021-10-13 11:31:53,048 - Trying to use logger class org.apache.velocity.runtime.log.AvalonLogChute
+2021-10-13 11:31:53,048 - Target log system for org.apache.velocity.runtime.log.AvalonLogChute is not available (java.lang.NoClassDefFoundError: org/apache/log/format/Formatter).  Falling back to next log system...
+2021-10-13 11:31:53,048 - Trying to use logger class org.apache.velocity.runtime.log.Log4JLogChute
+2021-10-13 11:31:53,048 - Using logger class org.apache.velocity.runtime.log.Log4JLogChute
+2021-10-13 11:31:53,057 - ResourceLoader instantiated: org.apache.velocity.runtime.resource.loader.FileResourceLoader
+2021-10-13 11:31:53,059 - Do unicode file recognition:  false
+2021-10-13 11:31:53,059 - FileResourceLoader : adding path ''
+2021-10-13 11:31:53,081 - ResourceCache: initialized (class org.apache.velocity.runtime.resource.ResourceCacheImpl) with class java.util.Collections$SynchronizedMap cache map.
+2021-10-13 11:31:53,084 - Loaded System Directive: org.apache.velocity.runtime.directive.Stop
+2021-10-13 11:31:53,086 - Loaded System Directive: org.apache.velocity.runtime.directive.Define
+2021-10-13 11:31:53,103 - Loaded System Directive: org.apache.velocity.runtime.directive.Break
+2021-10-13 11:31:53,105 - Loaded System Directive: org.apache.velocity.runtime.directive.Evaluate
+2021-10-13 11:31:53,106 - Loaded System Directive: org.apache.velocity.runtime.directive.Literal
+2021-10-13 11:31:53,108 - Loaded System Directive: org.apache.velocity.runtime.directive.Macro
+2021-10-13 11:31:53,110 - Loaded System Directive: org.apache.velocity.runtime.directive.Parse
+2021-10-13 11:31:53,113 - Loaded System Directive: org.apache.velocity.runtime.directive.Include
+2021-10-13 11:31:53,114 - Loaded System Directive: org.apache.velocity.runtime.directive.Foreach
+2021-10-13 11:31:53,152 - Created '20' parsers.
+2021-10-13 11:31:53,163 - Velocimacro : "velocimacro.library" is not set.  Trying default library: VM_global_library.vm
+2021-10-13 11:31:53,164 - Velocimacro : Default library not found.
+2021-10-13 11:31:53,164 - Velocimacro : allowInline = true : VMs can be defined inline in templates
+2021-10-13 11:31:53,164 - Velocimacro : allowInlineToOverride = false : VMs defined inline may NOT replace previous VM definitions
+2021-10-13 11:31:53,164 - Velocimacro : allowInlineLocal = false : VMs defined inline will be global in scope if allowed.
+2021-10-13 11:31:53,164 - Velocimacro : autoload off : VM system will not automatically reload global library macros
+2021-10-13 11:32:28,377 - Log4JLogChute initialized using file 'velocity.log'
+2021-10-13 11:32:28,378 - Initializing Velocity, Calling init()...
+2021-10-13 11:32:28,378 - Starting Apache Velocity v1.7 (compiled: 2010-11-19 12:14:37)
+2021-10-13 11:32:28,378 - Default Properties File: org\apache\velocity\runtime\defaults\velocity.properties
+2021-10-13 11:32:28,378 - Trying to use logger class org.apache.velocity.runtime.log.AvalonLogChute
+2021-10-13 11:32:28,378 - Target log system for org.apache.velocity.runtime.log.AvalonLogChute is not available (java.lang.NoClassDefFoundError: org/apache/log/format/Formatter).  Falling back to next log system...
+2021-10-13 11:32:28,378 - Trying to use logger class org.apache.velocity.runtime.log.Log4JLogChute
+2021-10-13 11:32:28,378 - Using logger class org.apache.velocity.runtime.log.Log4JLogChute
+2021-10-13 11:32:28,385 - ResourceLoader instantiated: org.apache.velocity.runtime.resource.loader.FileResourceLoader
+2021-10-13 11:32:28,387 - Do unicode file recognition:  false
+2021-10-13 11:32:28,387 - FileResourceLoader : adding path ''
+2021-10-13 11:32:28,408 - ResourceCache: initialized (class org.apache.velocity.runtime.resource.ResourceCacheImpl) with class java.util.Collections$SynchronizedMap cache map.
+2021-10-13 11:32:28,412 - Loaded System Directive: org.apache.velocity.runtime.directive.Stop
+2021-10-13 11:32:28,414 - Loaded System Directive: org.apache.velocity.runtime.directive.Define
+2021-10-13 11:32:28,415 - Loaded System Directive: org.apache.velocity.runtime.directive.Break
+2021-10-13 11:32:28,416 - Loaded System Directive: org.apache.velocity.runtime.directive.Evaluate
+2021-10-13 11:32:28,417 - Loaded System Directive: org.apache.velocity.runtime.directive.Literal
+2021-10-13 11:32:28,420 - Loaded System Directive: org.apache.velocity.runtime.directive.Macro
+2021-10-13 11:32:28,422 - Loaded System Directive: org.apache.velocity.runtime.directive.Parse
+2021-10-13 11:32:28,424 - Loaded System Directive: org.apache.velocity.runtime.directive.Include
+2021-10-13 11:32:28,426 - Loaded System Directive: org.apache.velocity.runtime.directive.Foreach
+2021-10-13 11:32:28,465 - Created '20' parsers.
+2021-10-13 11:32:28,479 - Velocimacro : "velocimacro.library" is not set.  Trying default library: VM_global_library.vm
+2021-10-13 11:32:28,480 - Velocimacro : Default library not found.
+2021-10-13 11:32:28,480 - Velocimacro : allowInline = true : VMs can be defined inline in templates
+2021-10-13 11:32:28,480 - Velocimacro : allowInlineToOverride = false : VMs defined inline may NOT replace previous VM definitions
+2021-10-13 11:32:28,480 - Velocimacro : allowInlineLocal = false : VMs defined inline will be global in scope if allowed.
+2021-10-13 11:32:28,480 - Velocimacro : autoload off : VM system will not automatically reload global library macros