|
@@ -0,0 +1,199 @@
|
|
|
+package com.jjt.utils;
|
|
|
+
|
|
|
+import cn.hutool.json.JSONArray;
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
+import com.jjt.biz.domain.TwinDevice;
|
|
|
+import com.jjt.biz.domain.TwinDeviceYhj;
|
|
|
+import com.jjt.calc.domain.TwinCalcHourYhj;
|
|
|
+import com.jjt.common.utils.DateUtils;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
+import org.springframework.scheduling.annotation.AsyncResult;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.ZoneOffset;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.Future;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 多线程执行任务
|
|
|
+ *
|
|
|
+ * @author wukai
|
|
|
+ * @date 2024/5/4 20:35
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class AsyncYhjService {
|
|
|
+ @Resource
|
|
|
+ private IotService iotService;
|
|
|
+ /**
|
|
|
+ * 字段列表,方便看下标
|
|
|
+ */
|
|
|
+ private final String[] fields = {"Capacity_data_2", "Capacity_data_37", "Capacity_data_38", "Capacity_data_39", "Capacity_data_42",
|
|
|
+ "Capacity_data_43", "Capacity_data_44", "Capacity_data_48", "Formula_data_3", "Formula_data_13",
|
|
|
+ "Capacity_data_36", "Capacity_data_41", "Alarm_unit_1", "Alarm_unit_2", "Alarm_unit_3",
|
|
|
+ "Alarm_unit_4", "Alarm_unit_5", "Alarm_unit_6", "Alarm_unit_7", "Alarm_unit_8",
|
|
|
+ "Alarm_unit_9", "Alarm_unit_10", "Alarm_unit_11", "Alarm_unit_12", "Alarm_unit_13",
|
|
|
+ "Alarm_unit_14", "Alarm_unit_15", "Alarm_unit_16", "Alarm_unit_17", "Alarm_unit_18",
|
|
|
+ "Alarm_unit_19", "Alarm_unit_20", "Alarm_unit_21", "Alarm_unit_22", "Alarm_unit_23",
|
|
|
+ "Alarm_unit_24", "Alarm_unit_25", "Alarm_unit_26", "Alarm_unit_27", "Capacity_data_33",
|
|
|
+ "Capacity_data_15", "Capacity_data_16", "Capacity_data_17", "Capacity_data_18", "Capacity_data_19",
|
|
|
+ "Capacity_data_34", "Formula_data_24", "Formula_data_15", "Capacity_data_1"
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 字段列表,方便查找位置
|
|
|
+ */
|
|
|
+ private final List<String> fieldList = Arrays.stream(fields).collect(Collectors.toList());
|
|
|
+
|
|
|
+ @Async("threadPoolTaskExecutor")
|
|
|
+ public Future<Map<String, Object>> currData(TwinDevice twinDevice) {
|
|
|
+ String table = twinDevice.getDevicePath();
|
|
|
+ String sql = "select last * from " + table;
|
|
|
+ JSONObject jsonObject = iotService.query(sql);
|
|
|
+ JSONObject data = jsonObject.getJSONObject("data");
|
|
|
+ JSONArray values = data.getJSONArray("values");
|
|
|
+ JSONArray timestamps = data.getJSONArray("timestamps");
|
|
|
+ Map<String, Object> dataMap = new HashMap<>();
|
|
|
+ dataMap.put("device", twinDevice);
|
|
|
+ if (timestamps.size() > 0 && (System.currentTimeMillis() - new Date(timestamps.getLong(0)).getTime()) > 5 * 60 * 100) {
|
|
|
+ //如果最后一条记录 超过5分钟,则视为无效记录
|
|
|
+ dataMap.put("total", 0);
|
|
|
+ } else {
|
|
|
+ dataMap.put("total", values.size());
|
|
|
+ dataMap.putAll(Tools.json2Map(values, table));
|
|
|
+ }
|
|
|
+ return new AsyncResult<>(dataMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据设备获取指定时段数据
|
|
|
+ *
|
|
|
+ * @param yhj 印花机设备
|
|
|
+ * @param start 开始时间
|
|
|
+ * @param end 结束时间
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Async("threadPoolTaskExecutor")
|
|
|
+ public Future<TwinCalcHourYhj> process(TwinDeviceYhj yhj, LocalDateTime start, LocalDateTime end) {
|
|
|
+ Long startTime = start.toInstant(ZoneOffset.of("+8")).toEpochMilli();
|
|
|
+ Long endTime = end.toInstant(ZoneOffset.of("+8")).toEpochMilli();
|
|
|
+ TwinCalcHourYhj calcYhj = new TwinCalcHourYhj();
|
|
|
+ String[] fields = {"Formula_data_set_1", "Formula_data_act_5"};
|
|
|
+
|
|
|
+ String sql = "select %s from " + yhj.getDevicePath() + " where time>%s and time <=%s";
|
|
|
+
|
|
|
+ sql = String.format(sql, String.join(",", fields), startTime, endTime);
|
|
|
+ JSONObject jsonObject = iotService.query(sql);
|
|
|
+ JSONObject data = jsonObject.getJSONObject("data");
|
|
|
+ JSONArray columnNames = data.getJSONArray("columnNames");
|
|
|
+ JSONArray values = data.getJSONArray("values");
|
|
|
+ JSONArray timestamps = data.getJSONArray("timestamps");
|
|
|
+ //记录上一次记录的值
|
|
|
+ Integer[] last = new Integer[columnNames.size()];
|
|
|
+ //记录最后一次的值,防中间有数,后面没数
|
|
|
+ Integer[] over = new Integer[columnNames.size()];
|
|
|
+ //当前记录值
|
|
|
+ Integer[] curr = new Integer[columnNames.size()];
|
|
|
+ //记录第一次记录的值,如果清0,则记录清零时刻的值
|
|
|
+ Integer[] first = new Integer[columnNames.size()];
|
|
|
+ //记录统计值
|
|
|
+ Integer[] total = new Integer[columnNames.size()];
|
|
|
+ for (int i = 0; i < values.size(); i++) {
|
|
|
+ JSONArray da = values.getJSONArray(i);
|
|
|
+ da.toList(Integer.class).toArray(curr);
|
|
|
+ if (i == 0) {
|
|
|
+ cloneArray(curr, last);
|
|
|
+ cloneArray(curr, first);
|
|
|
+ cloneArray(curr, over);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ for (int j = 0; j < columnNames.size(); j++) {
|
|
|
+ String name = columnNames.getStr(j);
|
|
|
+ if (name.contains("Formula_data_set_1")) {
|
|
|
+ //如果是版距,则需要记录变化
|
|
|
+ if (curr[j] != null && last[j] != null && curr[j].intValue() != last[j].intValue()) {
|
|
|
+ //这里要用j+1才行
|
|
|
+ calcLength(j + 1, last, first, total);
|
|
|
+ combo(calcYhj, start, yhj, last[j], total[j + 1]);
|
|
|
+ total[j + 1] = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (name.contains("Formula_data_act_5")) {
|
|
|
+ //如果是米长,则需要记录是否清0
|
|
|
+ //如果当前值为小于上一个,且上一个值不为0,则计算
|
|
|
+ //因为会出现数据波动,停机再启动之后的第一个点不为0,为0.00几几几的
|
|
|
+ if (curr[j] != null && last[j] != null && curr[j] < last[j] && last[j] != 0) {
|
|
|
+ calcLength(j, last, first, total);
|
|
|
+ cloneArray(curr, first);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //将本次的值,设为上一条记录了
|
|
|
+ cloneArray(curr, last);
|
|
|
+ cloneArray(curr, over);
|
|
|
+ cloneArrayFirst(curr, first);
|
|
|
+ }
|
|
|
+ for (int j = 0; j < columnNames.size(); j++) {
|
|
|
+ String name = columnNames.getStr(j);
|
|
|
+ if (name.contains("Formula_data_set_1")) {
|
|
|
+ calcLength(j + 1, over, first, total);
|
|
|
+ combo(calcYhj, start, yhj, over[j], total[j + 1]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return new AsyncResult<>(calcYhj);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始值,如果当前值不为空,并且原来值为空
|
|
|
+ */
|
|
|
+ void cloneArrayFirst(Integer[] arr, Integer[] target) {
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ if (arr[i] != null && target[i] == null) {
|
|
|
+ target[i] = arr[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 复制数组,如果当前值不为空
|
|
|
+ */
|
|
|
+ void cloneArray(Integer[] arr, Integer[] target) {
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ if (arr[i] != null) {
|
|
|
+ target[i] = arr[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组合入库数据
|
|
|
+ */
|
|
|
+ void combo(TwinCalcHourYhj calcYhj, LocalDateTime start, TwinDeviceYhj yhj, Integer distance, Integer length) {
|
|
|
+ if (distance != null && length != null) {
|
|
|
+ calcYhj.setDeviceId(yhj.getDeviceId());
|
|
|
+ calcYhj.setDataDate(DateUtils.toDate(start.toLocalDate()));
|
|
|
+ calcYhj.setHour(start.getHour());
|
|
|
+ calcYhj.setDistance(distance);
|
|
|
+ calcYhj.setLength(length);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算米长
|
|
|
+ */
|
|
|
+ void calcLength(int j, Integer[] last, Integer[] first, Integer[] total) {
|
|
|
+ if (last[j] != null && first[j] != null) {
|
|
|
+ if (total[j] == null) {
|
|
|
+ total[j] = 0;
|
|
|
+ }
|
|
|
+ total[j] += (last[j] - first[j]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|