package com.qianwen.mdc.collect.service; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneOffset; import java.util.Collections; import java.util.Map; import java.util.Set; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; import com.google.common.collect.Sets; import com.qianwen.mdc.collect.cache.TimeSliceCache; import com.qianwen.mdc.collect.constants.CommonConstant; import com.qianwen.mdc.collect.dto.CacheBuildDTO; import com.qianwen.mdc.collect.dto.CalendarShiftTimeSlicesDTO; import com.qianwen.mdc.collect.mapper.iotdb.DeviceStateMapper; import com.qianwen.mdc.collect.utils.LocalDateTimeUtils; import com.xxl.job.core.log.XxlJobLogger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.qianwen.mdc.collect.cache.WorkstationCache; import com.qianwen.mdc.collect.dto.WorkstationDTO; import com.qianwen.mdc.collect.entity.iotdb.DeviceState; import com.qianwen.mdc.collect.entity.iotdb.ProcessParam; import com.qianwen.mdc.collect.mapper.iotdb.ProcessParamMapper; import cn.hutool.core.util.ObjectUtil; /** * 设备离线处理服务,超过一定时间无采集数据判定为离线,插入离线状态数据 */ @Service public class DeviceOfflineCheckService{ private static final Logger log = LoggerFactory.getLogger(DeviceOfflineCheckService.class); /** * 离线判定时长,默认5分钟 */ @Value("${offlineConfigDuration:300000}") private long offlineConfigDuration; public static final String OFFLINE_VALUE = "4";//离线状态值 @Autowired private ProcessParamService paramService; @Autowired private WorkstationCache workstationCache; @Autowired private ProcessParamMapper processParamMapper; @Autowired private DeviceStateService deviceStateService; @Autowired private TimeSliceCache timeSliceCache; @Autowired private DeviceStateMapper deviceStateMapper; /** * 保存状态固定点数据(state_{workstationId}) */ public void checkOffline() { //将数据按照工位id分组 Map workstationsMap = workstationCache.getWorkstations(); if (ObjectUtil.isEmpty(workstationsMap)) { log.info("缓存无设备数据,退出"); return; } Set workstationIds = workstationsMap.keySet(); log.info("离线检查工位总数:{}",workstationsMap.size()); for(String workstationId :workstationIds) { log.info("开始检查工位{}的离线状态",workstationId); Long wid = Long.parseLong(workstationId); handleWorkstationOffline(wid); } } /** * 检查一个工位是否离线,离线则填充离线状态数据 * @param workstationId 工位id */ public void handleWorkstationOffline(long workstationId) { long nowMills = System.currentTimeMillis(); long lastOnlineTime = nowMills - offlineConfigDuration; /* ProcessParam lastParam = processParamMapper.lastParamByWorkstationId(workstationId); if(lastParam != null && lastParam.getTime()> onlineRange) { //有数据,且在判定时间内-》在线 return; }*/ DeviceState lastState = deviceStateMapper.lastNoFixedState(workstationId); if(lastState != null && lastState.getTime() > lastOnlineTime) { //有数据,且在判定时间内-》在线 return; } //TODO 这里一直离线是什么数据 XxlJobLogger.log("离线"+workstationId); //时间段内无参数,说明设备没采集数据判定为离线,插入状态,然后发送realTime消息给mdc //作为实时数据发送 ProcessParam statusParam = new ProcessParam(); statusParam.setTime(nowMills); statusParam.setN("DeviceStatus"); statusParam.setV(OFFLINE_VALUE); statusParam.setWorkstationId(workstationId); //if(lastState == null || !lastParam.getN().equals("DeviceStatus")) { if(lastState == null || lastState.getTime() <= lastOnlineTime) { //之前无任何采集的数据(或者上一条不是状态数据),新加一条离线状态数据 //paramService.insertProcessParam(statusParam); //插入状态表 DeviceState offLineState = new DeviceState(); offLineState.setTime(nowMills); String calendarCode = workstationCache.getWorkstationCalendarCodeForDate(workstationId, DateUtil.formatDate(DateUtil.date(nowMills))); offLineState.setCalendarCode(calendarCode);//111 this.fillCalendar(offLineState); offLineState.setValueCollect(Integer.parseInt(OFFLINE_VALUE)); offLineState.setWcs(offLineState.getValueCollect()); offLineState.setWorkstationId(workstationId); offLineState.setIsFixPoint(false); offLineState.setIsDeleted(false); offLineState.setIsSync(false); deviceStateService.saveDeviceStates(Collections.singletonList(offLineState)); XxlJobLogger.log("保存离线状态"+workstationId); } //通知mdc更新实时状态 paramService.sendRealtimeDataMsg(statusParam); } /** * 填充数据日历 * @param state 状态对象 */ void fillCalendar(DeviceState state){ if (ObjectUtil.isEmpty(state.getCalendarCode())) { state.setCalendarCode(CommonConstant.DEFAULT_CODE); } java.util.Date collectTime = new java.util.Date(state.getTime()); boolean isDefaultCalendar = true; if (!CommonConstant.DEFAULT_CODE.equals(state.getCalendarCode())) { CalendarShiftTimeSlicesDTO calendarShiftTimeSlicesDTO = timeSliceCache.getTimeSliceShift(state.getCalendarCode(), collectTime);//从redis中获得日历的时间切片 if (ObjectUtil.isEmpty(calendarShiftTimeSlicesDTO)) { LocalDate targetDate = Instant.ofEpochMilli(state.getTime()).atZone(ZoneOffset.systemDefault()).toLocalDate(); CacheBuildDTO cacheBuildDTO = CacheBuildDTO.builder().tenantIds(Sets.newHashSet(new String[]{"000000"})).calendarCode(state.getCalendarCode()).targetDate(targetDate).build(); timeSliceCache.build(cacheBuildDTO); calendarShiftTimeSlicesDTO = timeSliceCache.getTimeSliceShift(state.getCalendarCode(), collectTime); } if (ObjectUtil.isNotEmpty(calendarShiftTimeSlicesDTO)) { state.setShiftIndex(calendarShiftTimeSlicesDTO.getShiftIndex()); state.setShiftTimeType(Integer.valueOf(calendarShiftTimeSlicesDTO.getShiftTimeType())); state.setFactoryDate(Integer.valueOf(calendarShiftTimeSlicesDTO.getFactoryDate().replaceAll("-", ""))); state.setFactoryWeek(calendarShiftTimeSlicesDTO.getFactoryWeek()); state.setFactoryMonth(calendarShiftTimeSlicesDTO.getFactoryMonth()); state.setFactoryYear(calendarShiftTimeSlicesDTO.getFactoryYear()); isDefaultCalendar = false; } } //无日历切片,使用采集时间填充factoryYear,month,date,week几个属性 if (isDefaultCalendar) { log.info("离线检查无日历切片"); LocalDate localDate = Instant.ofEpochMilli(state.getTime()).atZone(ZoneOffset.systemDefault()).toLocalDate(); state.setFactoryDate(Integer.valueOf(DatePattern.PURE_DATE_FORMAT.format(collectTime))); state.setFactoryYear(DateUtil.year(collectTime)); state.setFactoryWeek(LocalDateTimeUtils.getWeek(localDate)); state.setFactoryMonth(DateUtil.month(collectTime) + 1); state.setShiftIndex(CommonConstant.DEFAULT_SHIFT_INDEX); state.setShiftTimeType(CommonConstant.DEFAULT_SHIFT_TYPE); } } }