vince
2023-12-26 9a139b15be65dcd83ae187bb384627097c6a811a
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
package com.fzzy.protocol.youxian0.analysis;
 
import com.alibaba.fastjson.JSONObject;
import com.fzzy.api.data.GatewayDeviceType;
import com.fzzy.api.utils.BytesUtil;
import com.fzzy.api.utils.NumberUtil;
import com.fzzy.gateway.GatewayUtils;
import com.fzzy.gateway.api.GatewayDeviceReportService;
import com.fzzy.gateway.api.GatewayRemoteManager;
import com.fzzy.gateway.data.BaseReqData;
import com.fzzy.gateway.data.WeatherWebDto;
import com.fzzy.gateway.entity.GatewayDevice;
import com.fzzy.gateway.hx2023.ScConstant;
import com.fzzy.gateway.hx2023.data.*;
import com.fzzy.protocol.ProtocolUtils;
import com.fzzy.protocol.bhzn.cmd.ReMessageBuilder;
import com.fzzy.protocol.data.THDto;
import com.fzzy.protocol.youxian0.ServiceUtils;
import com.fzzy.protocol.youxian0.data.GrainRoot;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
 
import javax.annotation.Resource;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 游仙主库,返回报文解析
 */
@Slf4j
@Component(AnalysisService.BEAN_ID)
public class AnalysisService {
 
    public static final String BEAN_ID = "youxian0.analysisService";
 
    @Resource
    private GatewayRemoteManager gatewayRemoteManager;
 
    private static Map<String, GrainRoot> contextGrainRoot = new HashMap<>();
 
    /**
     * 用于存放返回的仓温仓湿信息
     */
    public static Map<String, THDto> contextMapTH = new HashMap<>();
 
 
    /**
     * 协议解析
     * <p>
     * 7E 00 02 02 00 77 00 00 A0 FF FF 66 FF 04 BE 01 64 6A 6B 6A 68 CE 02 A4 BB BA BA B4 CE 03 E4 32 3D 32 3D CE 04 44 BC B3 BC B3 20 47 7E
     *
     * @param address
     * @param port
     * @param strMsg
     */
    public void analysis(InetAddress address, int port, String strMsg) {
 
        //分机ID
        int start = 2 * 2;
        String deviceSn = strMsg.substring(start, start + 2);
        deviceSn = BytesUtil.hexToInt(deviceSn) + "";
 
 
        //命令ID
        start = 5 * 2;
        String msgIdHex = strMsg.substring(start, start + 2);
        int msgId = BytesUtil.hexToInt(msgIdHex);
 
        //命令类型
        start = 11 * 2;
        String funId = strMsg.substring(start, start + 2);
 
 
        GatewayDevice device = GatewayUtils.getCacheByDeviceSn(deviceSn);
 
        //粮情返回
        if (ServiceUtils.FUNCTION_66.equalsIgnoreCase(funId)) {
 
            log.info("---------开始解析粮情信息---------");
            try{
                this.analysisGrainStep1(device, msgId, strMsg);
            }catch (Exception e){
                log.error(e.getMessage(),e);
            }
 
            log.info("---------解析粮情信息结束---------");
        }
 
        //温湿度返回
        if (ServiceUtils.FUNCTION_68.equalsIgnoreCase(funId)) {
            log.info("---------开始解析仓温湿度信息---------");
            try{
                this.analysisGrainTh(device, strMsg);
            }catch (Exception e){
                log.error(e.getMessage(),e);
            }
 
        }
 
    }
 
    private void analysisGrainTh(GatewayDevice device, String strMsg) {
        try{
            THDto th = new THDto();
 
            //TODO----->>> 待解析调整,先用外部气象信息
            //7E 00 01 01 00 06 00 00 A0 FF FF 68 1A 05 CC 16 3A 62 36 7E
            //系统气象站信息
//        WeatherWebDto weather = WeatherWebDto.contextMap.get("default");
//        th.setTempIn(Double.valueOf(weather.getTem()) - 2);
//        th.setHumidityIn(Double.valueOf(weather.getHumidity()) - 10);
            double t,h;
            String temp = strMsg.substring(30,32);
            t =  BytesUtil.hexToInt(temp)/2;
            log.info("温度:{}",t);
            temp = strMsg.substring(32,34);
            h = BytesUtil.hexToInt(temp);
            log.info("湿度:{}",h);
            th.setTempIn(t);
            th.setHumidityIn(h);
            this.add2ThMap(device.getDepotIdSys(), th);
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }
 
    }
 
 
    /**
     * 粮情解析
     * <p>
     * 7E 00 02 02 00 77 00 00 A0 FF FF 66 FF 04 BE 01 64 6A 6B 6A 68 CE
     * 02 A4 BB BA BA B4 CE 03 E4 32 3D 32 3D CE 04 44 BC B3 BC B3 20 47 7E
     *
     * @param device
     * @param msgId  命令ID
     */
    private void analysisGrainStep1(GatewayDevice device, int msgId, String strMsg) {
        String[] attCable = device.getCableRule().split("-");
        int cableZ = Integer.valueOf(attCable[0]);
        int cableY = Integer.valueOf(attCable[1]);
        int cableX = Integer.valueOf(attCable[2]);
        log.info("z={},x={},y={}",cableZ,cableX,cableY);
        //获取请求信息
        BaseReqData reqData = ProtocolUtils.getSyncReq(device.getDepotIdSys());
        if (null == reqData) {
            log.error("---------没有获取到请求信息,不执行解析------{}", device.getDeviceName());
            return;
        }
        //只保留粮情信息
        int start = 15 * 2;
        strMsg = strMsg.substring(start);
 
        GrainRoot grainRoot = new GrainRoot();
        grainRoot.setKey(buildGrainRootKey(device.getDeviceSn(), msgId));
        grainRoot.setNum(msgId);
 
        String tempStr = "";
        for (int j = 0;j<cableY;j++){
            tempStr = strMsg.substring(12 * j,12 * j +12);
            //密钥和点数 02 A4 BB BA BA B4
            String kyeNumHex = tempStr.substring(2, 4);
            String kyeNumBin = BytesUtil.toBinary8String(BytesUtil.hexToInt(kyeNumHex));
 
            String key = "00000" + kyeNumBin.substring(0, 3);
            int keyValue = BytesUtil.hexToInt(BytesUtil.bin2Hex(key));
            key = "0000" + kyeNumBin.substring(4);
            int numValue = BytesUtil.hexToInt(BytesUtil.bin2Hex(key));
 
            //02 A4 BB BA BA B4
            start = 2 * 2;
            String tempHex;
 
            double point = 0;
            for (int i = 0; i < numValue; i++) {
                start = start + i * 2;
                tempHex = tempStr.substring(start, start + 2);
                //实际温度=密钥*密钥*37(溢出为无符号字节)再异或加密后的温度/2。
                point = this.getGrainTemp(keyValue, tempHex);
                log.info("--------解析后的温度点----{}---{}", tempHex, point);
                grainRoot.getPoints().add(point);
                start = 2 * 2;
            }
        }
 
        this.add2GrainMap(grainRoot);
 
        //判断是不是最后一包数据,如果是最后一包执行解析
 
        if (grainRoot.getNum() == cableX) {
            analysisGrainStep2(reqData, cableZ, cableY, cableX);
        }
    }
 
    /**
     * 封装粮情点位
     *
     * @param reqData
     * @param cableZ
     * @param cableY
     * @param cableX
     */
    private void analysisGrainStep2(BaseReqData reqData, int cableZ, int cableY, int cableX) {
 
        List<Double> points = new ArrayList<>();
        GrainRoot root;
        for (int i = 1; i <= cableX; i++) {
            root = this.getGrainRoot(buildGrainRootKey(reqData.getDevice().getDeviceSn(), i));
 
            if (null == root || null == root.getPoints()) {
                log.error("-----------解析获取所有粮情检测点失败,取消执行---------{}---{}", reqData.getDevice().getDeviceName(),i);
                return;
            }
            points.addAll(root.getPoints());
        }
 
        //执行封装解析
        analysisGrainStep3(reqData, cableZ, cableY, cableX, points);
    }
 
    private void analysisGrainStep3(BaseReqData reqData, int cableZ, int cableY, int cableX, List<Double> points) {
 
        GatewayDevice device = reqData.getDevice();
        //数据封装
        GrainData grain = new GrainData();
        grain.setMessageId(ScConstant.getMessageId());
        grain.setDeviceId(device.getDeviceId());
        grain.setTimestamp(System.currentTimeMillis() + "");
 
        ClientHeaders headers = new ClientHeaders();
        headers.setDeviceName(device.getDeviceName());
        headers.setProductId(device.getProductId());
        headers.setOrgId(device.getOrgId());
        headers.setMsgId(reqData.getMessageId());
        grain.setHeaders(headers);
 
 
        GrainOutPut outPut = new GrainOutPut();
 
 
        double max = ReMessageBuilder.MAX_TEMP, min = ReMessageBuilder.MIN_TEMP, sumT = 0.0, sumNum = cableX * cableY * cableZ;
 
        List<GrainTemp> temperature = new ArrayList<>();
        //根号
        int cableNum = 1, position = 0;
 
        double curTemp;
        int x = 0, y = 0, z = 0;
        for (int i = 0; i < points.size(); i++) {
            curTemp = points.get(i);
            position = i;
            z = i % cableZ + 1;
            x = i / (cableZ * cableY);
            y = x * (cableZ * cableY);
            y = (i - y) / cableZ;
            //根号
            cableNum = (i / cableZ) + 1;
 
            temperature.add(new GrainTemp(cableNum + "", z + "", curTemp + "", position + ""));
 
            sumT += curTemp;
            if (curTemp > max) {
                max = curTemp;
            }
            if (curTemp < min) {
                min = curTemp;
            }
        }
 
        if (sumNum == 0) {
            sumNum = 1;
            log.warn("---当前粮情采集异常--");
        }
        //过滤比较用的最大最小值
        if (max == ReMessageBuilder.MAX_TEMP) {
            max = 0.0;
        }
        if (min == ReMessageBuilder.MIN_TEMP) {
            min = 0.0;
        }
 
        outPut.setTemperature(temperature);
        outPut.setAvgTemperature(NumberUtil.keepPrecision((sumT / sumNum), 1) + "");
        outPut.setMinTemperature(min + "");
        outPut.setMaxTemperature(min + "");
        List<GrainTH> ths = new ArrayList<>();
 
 
        //获取温湿度
        THDto thDto = this.getGrainTh(device.getDepotIdSys());
 
        ths.add(new GrainTH(thDto.getTempIn() != null ? thDto.getTempIn() + "" : "", thDto.getHumidityIn() != null ? thDto.getHumidityIn() + "" : "", "1"));
        outPut.setTemperatureAndhumidity(ths);
        grain.setOutput(JSONObject.toJSONString(outPut));
 
        GatewayDevice gatewayDeviceWeather = GatewayUtils.getCacheByDeviceTypeOne(GatewayDeviceType.TYPE_09.getCode());
 
        //系统气象站信息
        WeatherWebDto weather = WeatherWebDto.contextMap.get("default");
 
        //气象信息
        GrainWeather weatherStation = new GrainWeather();
        weatherStation.setMessageId(ScConstant.getMessageId());
        weatherStation.setMessgeId(weatherStation.getMessageId());
 
        if (null != gatewayDeviceWeather) {
            weatherStation.setId(gatewayDeviceWeather.getDeviceId());
        } else {
            weatherStation.setId(device.getDeviceId());
        }
        weatherStation.setAirPressure(weather.getPressure());
        weatherStation.setHumidity(weather.getHumidity());
        weatherStation.setPm(weather.getAir_pm25());
        weatherStation.setRadiation("0");
        weatherStation.setRainfallAmount(weather.getWea());
        weatherStation.setTemperature(weather.getTem());
        weatherStation.setWindDirection(weather.getWin());
        weatherStation.setWindPower(weather.getWin_meter());
        weatherStation.setWindSpeed(weather.getWin_speed());
 
        grain.setWeatherStation(JSONObject.toJSONString(weatherStation));
 
        //封装好的数据
        log.info("---粮情信息封装完成-开始执行推送");
 
        reqData.setData(JSONObject.toJSONString(grain));
 
        doPushGrain(reqData);
    }
 
    private void doPushGrain(BaseReqData reqData) {
 
        GatewayDeviceReportService reportService = gatewayRemoteManager.getDeviceReportService(reqData.getDevice().getPushProtocol());
        if (null == reportService) {
            log.error("------------粮情推送失败,系统不存在当前协议执行类----{}", reqData.getDevice().getDeviceName());
            return;
        }
 
        reportService.reportGrainData(reqData);
    }
 
    private void add2GrainMap(GrainRoot grainRoot) {
        contextGrainRoot.put(grainRoot.getKey(), grainRoot);
    }
 
    private GrainRoot getGrainRoot(String key) {
        return contextGrainRoot.get(key);
    }
 
    private String buildGrainRootKey(String deviceSn, int num) {
        return deviceSn + "_" + num;
    }
 
    /**
     * 计算粮情温度
     * 实际温度=密钥*密钥*37(溢出为无符号字节)再异或加密后的温度/2。
     * 举例说明:第三个字节BB实际温度是5*5*37=039D取9D^(0xBB)=38/2=19;
     *
     * @param keyValue
     * @param tempHex
     * @return
     */
    private double getGrainTemp(int keyValue, String tempHex) {
        int value = keyValue * keyValue * 37;
        String valueHex = BytesUtil.intToHexStr(value);
 
        valueHex = valueHex.substring(2);
 
        int num1 = BytesUtil.hexToInt(valueHex);
        int num2 = BytesUtil.hexToInt(tempHex);
 
        return (num1 ^ num2) / 2.0;
    }
 
    private void add2ThMap(String depotIdSys, THDto th) {
        String key = "TH_" + depotIdSys;
        contextMapTH.put(key, th);
    }
 
    private THDto getGrainTh(String depotIdSys) {
        String key = "TH_" + depotIdSys;
        return contextMapTH.get(key);
    }
}