yangys
2025-11-24 11d4be720620abf502d35000e2ed40d30c4023bf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
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<String, WorkstationDTO> workstationsMap = workstationCache.getWorkstations();
        if (ObjectUtil.isEmpty(workstationsMap)) {
            log.info("缓存无设备数据,退出");
            return;
        }
            
        Set<String> 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);
        }
    }
 
    
}